openzwave-1.6.1914/0000777000175200017520000000000014032143202010773 500000000000000openzwave-1.6.1914/INSTALL0000644000175200017520000000505514032142454011755 00000000000000Minimal Install Guide for OpenZWave! For Unix's (including Mac, bsd's etc) ================= execute Make in the Top Level Directory make Libraries to link to (Static and Dynamic) will be in top level directory as well (but you can change that as detailed below with LIBDIR) To Install: make install Some Options you can set: "BUILD=(release|debug)" - Build a Release or Debug Version of the Library (Release is default) "PREFIX=(path)" - Prefix to install the shared library into - Defaults to /usr/local "LIBDIR=/tmp" - Path to place the libraries into after complication. A poor mans "make install" for simple Applications. To use the options, specify them on the commandline when executing make eg: "BUILD=debug PREFIX=/opt/local make" What Gets installed: When make install is called the following happens: * Documentation: if you have DoxyGen, API documentation is installed into (PREFIX)/share/doc/openzwave-(version)/ * Shared Libary (libopenzwave.so.*): The Shared Library is installed into either (prefix)/lib64 (on 64 bit platforms) or (prefix)/lib/ on 32 bit platforms) * Header Files: Installed into (prefix)/include/openzwave/ * pkg-config file: Installed into (prefix)/lib(64)/pkgconfig/libopenzwave.pc * Config files and Device Databases (manufacturer_specific.xml et al) Installed into (prefix)/etc/openzwave/ * MinOZW example program: Installed into (prefix)/bin/ directory The Static Version of the library is never installed, but will be created in top build directory after a successfull make. Windows Versions ================ Visual Studio Solution Files and Mingw32 Makefiles are present in cpp/build/windows/. Select the correct Visual Studio or Mingw32 directory depending on the versions you have. (Note, if building DLL's on Windows (currently a option in the vs2010 solution) - You have to ensure you application is compiled with exactly the same compiler options and versions as OpenZWave - Otherwise strange things might happen) For the .NET dll, the solution files exist in the dotnet/build/ directory Sample Programs =============== For all platforms, there is a simple example program that will print out events as they happen on your ZWave network. This sample is called MinOZW and you can find the source in the cpp/examples directory. By default, these examples are built during the Make Install Stage. If you want compile them separately, you can use the "make examples" target. For the .NET wrapper, there is a OZWForm application in dotnet/examples/OZWForm/. Please read the README file in that directory for further instructions openzwave-1.6.1914/distfiles.mk0000644000175200017520000020131014032142455013234 00000000000000# This File is automatically generated by make dist-update # Any Edits on this file will be lost next time dist-update is run DISTFILES = .gitignore \ BSDmakefile \ INSTALL \ LICENSE \ Makefile \ README.md \ config/2gig/ct100.xml \ config/2gig/ct101.xml \ config/2gig/ct200.xml \ config/2gig/ct30.xml \ config/2gig/ct32.xml \ config/2gig/ct50e.xml \ config/2gig/ct80.xml \ config/BeNext/1poleswitch.xml \ config/BeNext/2poleswitch.xml \ config/BeNext/AlarmSound.xml \ config/BeNext/BuiltinDimmer.xml \ config/BeNext/DoorSensor.xml \ config/BeNext/EnergySwitch.xml \ config/BeNext/HeatingControl.xml \ config/BeNext/Molite.xml \ config/BeNext/P1dongle.xml \ config/BeNext/PanicButton.xml \ config/BeNext/PanicWatch.xml \ config/BeNext/PluginDimmer.xml \ config/BeNext/SceneController.xml \ config/BeNext/TagReader.xml \ config/BeNext/TagReader500.xml \ config/BeNext/mydisplay.xml \ config/BeNext/mygate.xml \ config/Localization.xml \ config/Localization.xsd \ config/NotificationCCTypes.xml \ config/NotificationCCTypes.xsd \ config/SensorMultiLevelCCTypes.xml \ config/SensorMultiLevelCCTypes.xsd \ config/abus/SHRM10000.xml \ config/act/lfm20.xml \ config/act/zdm230.xml \ config/act/zdp100.xml \ config/act/zdw103.xml \ config/act/zdw232.xml \ config/act/zir010.xml \ config/act/zrm230.xml \ config/act/zrp100.xml \ config/act/zrp110.xml \ config/act/zrw103.xml \ config/act/zrw230.xml \ config/aeotec/dsa03202.xml \ config/aeotec/dsa22.xml \ config/aeotec/dsa38.xml \ config/aeotec/dsb04100.xml \ config/aeotec/dsb05.xml \ config/aeotec/dsb09104.xml \ config/aeotec/dsb28-zweu.xml \ config/aeotec/dsb28.xml \ config/aeotec/dsb29.xml \ config/aeotec/dsb45.xml \ config/aeotec/dsb54.xml \ config/aeotec/dsc06106.xml \ config/aeotec/dsc08101.xml \ config/aeotec/dsc10.xml \ config/aeotec/dsc11.xml \ config/aeotec/dsc12104.xml \ config/aeotec/dsc13104.xml \ config/aeotec/dsc14104.xml \ config/aeotec/dsc18103.xml \ config/aeotec/dsc19103.xml \ config/aeotec/dsc24.xml \ config/aeotec/dsc26103.xml \ config/aeotec/dsc27103.xml \ config/aeotec/dsc35103.xml \ config/aeotec/dsd37.xml \ config/aeotec/zw056.xml \ config/aeotec/zw062.xml \ config/aeotec/zw074.xml \ config/aeotec/zw075.xml \ config/aeotec/zw078.xml \ config/aeotec/zw080.xml \ config/aeotec/zw088.xml \ config/aeotec/zw089.xml \ config/aeotec/zw090.xml \ config/aeotec/zw095.xml \ config/aeotec/zw096.xml \ config/aeotec/zw097.xml \ config/aeotec/zw098.xml \ config/aeotec/zw099.xml \ config/aeotec/zw100.xml \ config/aeotec/zw111.xml \ config/aeotec/zw112.xml \ config/aeotec/zw116.xml \ config/aeotec/zw117.xml \ config/aeotec/zw120.xml \ config/aeotec/zw121.xml \ config/aeotec/zw122.xml \ config/aeotec/zw129.xml \ config/aeotec/zw130.xml \ config/aeotec/zw132.xml \ config/aeotec/zw139.xml \ config/aeotec/zw140.xml \ config/aeotec/zw141.xml \ config/aeotec/zw162.xml \ config/aeotec/zw164.xml \ config/aeotec/zw175.xml \ config/aeotec/zw187.xml \ config/aeotec/zw189.xml \ config/aeotec/zwa001.xml \ config/aeotec/zwa002.xml \ config/aeotec/zwa003.xml \ config/aeotec/zwa004.xml \ config/aeotec/zwa005.xml \ config/aeotec/zwa006.xml \ config/aeotec/zwa008.xml \ config/aeotec/zwa009.xml \ config/aeotec/zwa012.xml \ config/aeotec/zwa019.xml \ config/aeotec/zwa021.xml \ config/airlinemechanical/zds-ud10.xml \ config/alfred/DB2.xml \ config/assa_abloy/ConexisL1.xml \ config/assa_abloy/KeyfreeConnected-plus.xml \ config/assa_abloy/KeyfreeConnected.xml \ config/assa_abloy/ProSLKey-FreeDeadbolt.xml \ config/assa_abloy/PushButtonDeadbolt.xml \ config/assa_abloy/PushButtonLever.xml \ config/assa_abloy/TouchDeadbolt.xml \ config/assa_abloy/TouchLever.xml \ config/assa_abloy/nexTouch.xml \ config/assa_abloy/yrd1x0.xml \ config/assa_abloy/yrm276.xml \ config/august/asl-03.xml \ config/buffalo/hw-100v15a-zw.xml \ config/building36/b36-t10.xml \ config/comfort/ucm.xml \ config/config-template.xml \ config/connecthome/ch-201.xml \ config/cooper/RF9501.xml \ config/cooper/RF9505-T.xml \ config/cooper/RF9505-T.xml.zip \ config/cooper/RF9517.xml \ config/cooper/RF9540-N.xml \ config/cooper/RF9542-Z.xml \ config/cooper/RF9601.xml \ config/cooper/RFWC5.xml \ config/cooper/rf9534.xml \ config/danfoss/living.xml \ config/danfoss/rsroom.xml \ config/danfoss/z.xml \ config/device_classes.xml \ config/device_classes.xsd \ config/device_configuration.xsd \ config/devolo/connectz.xml \ config/devolo/mt02648.xml \ config/devolo/mt02755.xml \ config/devolo/mt02758.xml \ config/devolo/mt02792.xml \ config/devolo/mt2646.xml \ config/devolo/mt2647.xml \ config/devolo/mt2651.xml \ config/devolo/mt2652.xml \ config/devolo/mt2653.xml \ config/devolo/mt2756.xml \ config/devolo/mt2759.xml \ config/devolo/mt2760.xml \ config/devolo/mt2761.xml \ config/devolo/rs014G0159.xml \ config/diehlcontrols/766366.xml \ config/dlink/dch-z110.xml \ config/dlink/dch-z120.xml \ config/dlink/dch-z210.xml \ config/dlink/dch-z510.xml \ config/dome/0002.xml \ config/dome/0083.xml \ config/dome/0085.xml \ config/dome/0086.xml \ config/dome/0087.xml \ config/dome/0088.xml \ config/dome/0101.xml \ config/dome/0104.xml \ config/dome/0201.xml \ config/dome/dmex1.xml \ config/domitech/zb22uk.xml \ config/domitech/ze27eu.xml \ config/domux/DX1CA-Z.xml \ config/domux/DX1CG-Z.xml \ config/domux/DX1DS-Z.xml \ config/domux/DX1HT-Z.xml \ config/domux/DX1MS-Z.xml \ config/domux/DX1SA-Z.xml \ config/domux/DX1WL-Z.xml \ config/domux/DX2SK-Z.xml \ config/dragontech/wd-100.xml \ config/duco/DucoBox.xml \ config/duco/Ducotronic_CO-RH_sensor.xml \ config/duwi/05458.xml \ config/duwi/ZWES1000.xml \ config/duwi/ZWESJ300.xml \ config/duwi/zw-edan-300.xml \ config/duwi/zw-zdan-300.xml \ config/duwi/zwfb.xml \ config/duwi/zwws.xml \ config/ecodim/0.7.xml \ config/ecolink/doorwindow.xml \ config/ecolink/firefighter.xml \ config/ecolink/floodfreeze.xml \ config/ecolink/motion.xml \ config/ecolink/sensor.xml \ config/ecolink/tiltsensor.xml \ config/econet/ezw1204.xml \ config/electronicsolutions/dbmz.xml \ config/enblink/ss201-us-w_1308.xml \ config/enerwave/zw15rmplus.xml \ config/enerwave/zw15s.xml \ config/enerwave/zw20r.xml \ config/enerwave/zw20rm.xml \ config/enerwave/zw500d.xml \ config/enerwave/zwn-bpc.xml \ config/enerwave/zwn-sc7.xml \ config/enerwave/zwnrsm1plus.xml \ config/enerwave/zwnrsm2plus.xml \ config/eurotronic/eur_airquality.xml \ config/eurotronic/eur_cometz.xml \ config/eurotronic/eur_spiritz.xml \ config/eurotronic/eur_stellaz.xml \ config/eurotronic/eur_temphumin.xml \ config/everspring/ad146.xml \ config/everspring/ad147.xml \ config/everspring/an145.xml \ config/everspring/an157.xml \ config/everspring/an158.xml \ config/everspring/an163.xml \ config/everspring/an179.xml \ config/everspring/an180.xml \ config/everspring/an181.xml \ config/everspring/hac01.xml \ config/everspring/han01.xml \ config/everspring/han02-1.xml \ config/everspring/hsp02.xml \ config/everspring/lptdm1u.xml \ config/everspring/se812.xml \ config/everspring/sf812.xml \ config/everspring/sm103.xml \ config/everspring/sp103.xml \ config/everspring/sp814.xml \ config/everspring/sp815.xml \ config/everspring/sp816.xml \ config/everspring/st812.xml \ config/everspring/st814.xml \ config/everspring/st815.xml \ config/everspring/tse03.xml \ config/everspringct/hsm02.xml \ config/evolve/lfm-20.xml \ config/evolve/lrm-as.xml \ config/evolve/lsm-15.xml \ config/evolve/ltm-5.xml \ config/evolve/t-100.xml \ config/fakro/arz.xml \ config/fakro/arzsolar.xml \ config/fakro/zrh12.xml \ config/fakro/zwp10.xml \ config/fakro/zwrs.xml \ config/fakro/zws12.xml \ config/fakro/zws230.xml \ config/fibaro/fgbs001.xml \ config/fibaro/fgbs222.xml \ config/fibaro/fgcd001.xml \ config/fibaro/fgd211.xml \ config/fibaro/fgd212.xml \ config/fibaro/fgdw2.xml \ config/fibaro/fgfs101.xml \ config/fibaro/fgfs101zw5.xml \ config/fibaro/fggc001.xml \ config/fibaro/fgk001.xml \ config/fibaro/fgk10x.xml \ config/fibaro/fgkf601.xml \ config/fibaro/fgms.xml \ config/fibaro/fgmszw5.xml \ config/fibaro/fgpb101.xml \ config/fibaro/fgr221.xml \ config/fibaro/fgr223.xml \ config/fibaro/fgrgbw442.xml \ config/fibaro/fgrgbwm441.xml \ config/fibaro/fgrm222.xml \ config/fibaro/fgs211.xml \ config/fibaro/fgs212.xml \ config/fibaro/fgs213.xml \ config/fibaro/fgs214.xml \ config/fibaro/fgs221.xml \ config/fibaro/fgs222.xml \ config/fibaro/fgs223.xml \ config/fibaro/fgs224.xml \ config/fibaro/fgsd002.xml \ config/fibaro/fgss101.xml \ config/fibaro/fgt001.xml \ config/fibaro/fgwd111.xml \ config/fibaro/fgwds221.xml \ config/fibaro/fgwds221ss.xml \ config/fibaro/fgwoe.xml \ config/fibaro/fgwpb121.xml \ config/fibaro/fgwpe.xml \ config/fibaro/fgwpfzw5.xml \ config/fibaro/fgwpg111.xml \ config/fibaro/fgwr111.xml \ config/firstalert/zcombo-g.xml \ config/firstalert/zcombo.xml \ config/firstalert/zsmoke.xml \ config/followgood/swz-1002.xml \ config/forest/fs2z5232000002.xml \ config/fortrezz/fmi.xml \ config/fortrezz/fts05p.xml \ config/fortrezz/gdc1_fortrezz_1501.xml \ config/fortrezz/mimo2plus.xml \ config/fortrezz/mimolite.xml \ config/fortrezz/ssa2.xml \ config/fortrezz/ssa3.xml \ config/fortrezz/wv01.xml \ config/fortrezz/wwa-01aa.xml \ config/fortrezz/wwa02.xml \ config/frostdale/fdn2311.xml \ config/frostdale/fdn2nxx.xml \ config/ge/12719-plugin-switch.xml \ config/ge/12720.xml \ config/ge/12724-dimmer.xml \ config/ge/12727.xml \ config/ge/14280-plugin-dimmer.xml \ config/ge/14282-plugin-switch.xml \ config/ge/14284.xml \ config/ge/14285.xml \ config/ge/14288-outlet.xml \ config/ge/14291-switch.xml \ config/ge/14292-toggle-switch.xml \ config/ge/14294-dimmer.xml \ config/ge/14295-dimmer-toggle.xml \ config/ge/14298.xml \ config/ge/14322-dimmer-toggle.xml \ config/ge/26931-motion-switch.xml \ config/ge/26932-motion-dimmer.xml \ config/ge/26933-motion-dimmer.xml \ config/ge/28167-plugin-dimmer.xml \ config/ge/28169-plugin-switch.xml \ config/ge/45604.xml \ config/ge/46201-switch.xml \ config/ge/46202-switch.xml \ config/ge/46203-dimmer.xml \ config/ge/46204-dimmer-toggle.xml \ config/ge/dimmer.xml \ config/ge/dimmer_module.xml \ config/ge/hinge-pin.xml \ config/ge/receptacle.xml \ config/ge/relay.xml \ config/ge/ze26i.xml \ config/ge/zw4001-switch.xml \ config/ge/zw6302.xml \ config/gocontrol/GC-TBZ48L.xml \ config/goodway/td14010.xml \ config/gr/gr-302n.xml \ config/gr/gr105.xml \ config/gr/gr105n.xml \ config/gr/grb3.xml \ config/graber/brz1.xml \ config/graber/csz1.xml \ config/graber/mcz1.xml \ config/graber/rsz1.xml \ config/graber/vcz1.xml \ config/greenwave/gs1110-1-gr-1.xml \ config/greenwave/powernode1.xml \ config/greenwave/powernode6.xml \ config/guardtec/gkw2000d.xml \ config/hab/iblindsV2.xml \ config/hab/iblindsV3.xml \ config/hank/hkzw-dws01.xml \ config/hank/hkzw-fld01.xml \ config/hank/hkzw-ms01.xml \ config/hank/hkzw-ms02-200.xml \ config/hank/hkzw-ms02-300.xml \ config/hank/hkzw-rgb01.xml \ config/hank/hkzw-so01-smartplug.xml \ config/hank/hkzw-so03.xml \ config/hank/hkzw-so05-smartplug.xml \ config/hank/scenecontroller1.xml \ config/hank/scenecontroller4.xml \ config/heiman/HS1CA-Z.xml \ config/heiman/HS1CG-Z.xml \ config/heiman/HS1DS-Z.xml \ config/heiman/HS1HT-Z.xml \ config/heiman/HS1MS-Z.xml \ config/heiman/HS1SA-Z.xml \ config/heiman/HS1WL-Z.xml \ config/heiman/HS2SK-Z.xml \ config/heiman/HS2WD-Z.xml \ config/heltun/he-ft01.xml \ config/heltun/he-ht01.xml \ config/heltun/he-zw-sw-5a-1.xml \ config/heltun/he-zw-therm-fc1.xml \ config/heltun/he-zw-therm-fl2.xml \ config/homeseer/ezmotionplus.xml \ config/homeseer/hs-ds100plus.xml \ config/homeseer/hs-fc200plus.xml \ config/homeseer/hs-fls100plus.xml \ config/homeseer/hs-fs100plus.xml \ config/homeseer/hs-ls100plus.xml \ config/homeseer/hs-ms100plus.xml \ config/homeseer/hs-wd100plus.xml \ config/homeseer/hs-wd200plus.xml \ config/homeseer/hs-ws100plus.xml \ config/homeseer/hs-ws200plus.xml \ config/homeseer/hsm100.xml \ config/homeseer/hsm200.xml \ config/homeseer/ztroller.xml \ config/honeywell/2681-plugin-dimmer.xml \ config/honeywell/3830-zw3107.xml \ config/honeywell/39348-ZW4005.xml \ config/honeywell/39348-zw4008.xml \ config/honeywell/39349-ZW1002.xml \ config/honeywell/39351-ZW3005.xml \ config/honeywell/39351-ZW3010.xml \ config/honeywell/39357-ZW3004.xml \ config/honeywell/39358-ZW4002.xml \ config/honeywell/39449-ZW4106.xml \ config/honeywell/lynx-touch-l5100.xml \ config/honeywell/th6320zw2003.xml \ config/honeywell/th8320zw1000.xml \ config/horstmann/asrzw.xml \ config/horstmann/hrt4zw.xml \ config/horstmann/scsc17.xml \ config/horstmann/ses301.xml \ config/horstmann/ses302.xml \ config/horstmann/ses303.xml \ config/horstmann/sir321.xml \ config/horstmann/srt321.xml \ config/horstmann/srt323.xml \ config/horstmann/ssr302.xml \ config/horstmann/ssr303.xml \ config/icare/zw-66.xml \ config/idlock/idlock101.xml \ config/idlock/idlock150.xml \ config/images/2gig/ct100.png \ config/images/2gig/ct200.png \ config/images/2gig/ct32.png \ config/images/BeNext/AlarmSound.png \ config/images/BeNext/DoorSensor.png \ config/images/BeNext/Molite.png \ config/images/BeNext/P1dongle.png \ config/images/BeNext/TagReader.png \ config/images/BeNext/TagReader500.png \ config/images/BeNext/mydisplay.png \ config/images/BeNext/mygate.png \ config/images/DefaultProductImage.png \ config/images/abus/SHRM10000.jpg \ config/images/act/lfm20.png \ config/images/act/zdm230.png \ config/images/act/zdp100.png \ config/images/act/zir010.png \ config/images/act/zrm230.png \ config/images/act/zrp100.png \ config/images/act/zrw103.png \ config/images/act/zrw230.png \ config/images/aeotec/dsa03202.png \ config/images/aeotec/dsa38.png \ config/images/aeotec/dsb04100.png \ config/images/aeotec/dsb05.png \ config/images/aeotec/dsb09104.png \ config/images/aeotec/dsb28-zweu.png \ config/images/aeotec/dsb28.png \ config/images/aeotec/dsb29.png \ config/images/aeotec/dsc06106.png \ config/images/aeotec/dsc10.png \ config/images/aeotec/dsc11.png \ config/images/aeotec/dsc14104.png \ config/images/aeotec/dsc18103.png \ config/images/aeotec/dsc19103.png \ config/images/aeotec/dsc24.png \ config/images/aeotec/dsc26103.png \ config/images/aeotec/dsc27103.png \ config/images/aeotec/dsc35103.png \ config/images/aeotec/dsd37.png \ config/images/aeotec/zw056.png \ config/images/aeotec/zw062.png \ config/images/aeotec/zw074.png \ config/images/aeotec/zw075.png \ config/images/aeotec/zw078.png \ config/images/aeotec/zw080.png \ config/images/aeotec/zw088.png \ config/images/aeotec/zw089.png \ config/images/aeotec/zw090.png \ config/images/aeotec/zw095.png \ config/images/aeotec/zw096.png \ config/images/aeotec/zw097.png \ config/images/aeotec/zw098.png \ config/images/aeotec/zw099.png \ config/images/aeotec/zw100.png \ config/images/aeotec/zw111.png \ config/images/aeotec/zw112.png \ config/images/aeotec/zw116.png \ config/images/aeotec/zw117.png \ config/images/aeotec/zw120.png \ config/images/aeotec/zw121.png \ config/images/aeotec/zw122.png \ config/images/aeotec/zw129.png \ config/images/aeotec/zw130.png \ config/images/aeotec/zw132.png \ config/images/aeotec/zw139.png \ config/images/aeotec/zw140.png \ config/images/aeotec/zw141.png \ config/images/aeotec/zw162.png \ config/images/aeotec/zw164.png \ config/images/aeotec/zw187.png \ config/images/aeotec/zw189.png \ config/images/aeotec/zw195.png \ config/images/aeotec/zwa001.png \ config/images/aeotec/zwa002.png \ config/images/aeotec/zwa003.png \ config/images/aeotec/zwa004.png \ config/images/aeotec/zwa005.png \ config/images/aeotec/zwa006.png \ config/images/aeotec/zwa009.png \ config/images/aeotec/zwa012.png \ config/images/aeotec/zwa019.png \ config/images/aeotec/zwa021.png \ config/images/airlinemechanical/zds-ud10.png \ config/images/alfred/DB2.png \ config/images/assa_abloy/ConexisL1.png \ config/images/assa_abloy/KeyfreeConnected-plus.png \ config/images/assa_abloy/KeyfreeConnected.png \ config/images/assa_abloy/ProSLKey-FreeDeadbolt.png \ config/images/assa_abloy/PushButtonDeadbolt.png \ config/images/assa_abloy/TouchDeadbolt.png \ config/images/assa_abloy/TouchLever.png \ config/images/assa_abloy/nexTouch.png \ config/images/assa_abloy/yrd1x0.png \ config/images/assa_abloy/yrm276.png \ config/images/august/asl-03.png \ config/images/buffalo/hw-100v15a-zw.png \ config/images/building36/b36-t10.png \ config/images/comfort/ucm.png \ config/images/connecthome/CH_201.png \ config/images/cooper/RF9501.png \ config/images/cooper/RF9505-T.png \ config/images/cooper/RF9517.png \ config/images/cooper/RF9540-N.png \ config/images/cooper/RF9542-Z.png \ config/images/cooper/RF9601.png \ config/images/cooper/rf9534.png \ config/images/danfoss/living.png \ config/images/danfoss/rsroom.png \ config/images/danfoss/z.png \ config/images/devolo/mt02648.png \ config/images/devolo/mt02755.png \ config/images/devolo/mt02758.png \ config/images/devolo/mt2646.png \ config/images/devolo/mt2647.png \ config/images/devolo/mt2652.png \ config/images/devolo/mt2756.png \ config/images/devolo/mt2759.png \ config/images/devolo/mt2760.png \ config/images/devolo/mt2761.png \ config/images/diehlcontrols/766366.png \ config/images/dlink/dch-z110.png \ config/images/dlink/dch-z120.png \ config/images/dlink/dch-z210.png \ config/images/dlink/dch-z510.png \ config/images/dome/0002.png \ config/images/dome/0085.png \ config/images/dome/0086.png \ config/images/dome/0088.png \ config/images/dome/0201.png \ config/images/dome/dmex1.png \ config/images/domitech/zb22uk.png \ config/images/domitech/ze27eu.png \ config/images/dragontech/wd-100.png \ config/images/duwi/ZWES1000.png \ config/images/duwi/zw-edan-300.png \ config/images/duwi/zw-zdan-300.png \ config/images/duwi/zwws.png \ config/images/ecodim/0.7.jpg \ config/images/ecolink/doorwindow.png \ config/images/ecolink/firefighter.png \ config/images/ecolink/floodfreeze.png \ config/images/ecolink/motion.png \ config/images/ecolink/sensor.png \ config/images/ecolink/tiltsensor.png \ config/images/econet/ezw1204.png \ config/images/electronicsolutions/dbmz.png \ config/images/enblink/ss201-us-w_1308.png \ config/images/enerwave/zw15rmplus.png \ config/images/enerwave/zw20r.png \ config/images/enerwave/zw20rm.png \ config/images/enerwave/zwn-bpc.png \ config/images/enerwave/zwnrsm1plus.png \ config/images/enerwave/zwnrsm2plus.png \ config/images/eurotronic/eur_airquality.png \ config/images/eurotronic/eur_cometz.png \ config/images/eurotronic/eur_spiritz.png \ config/images/eurotronic/eur_stellaz.png \ config/images/eurotronic/eur_temphumid.png \ config/images/everspring/ad146.png \ config/images/everspring/ad147.png \ config/images/everspring/an157.png \ config/images/everspring/an158.png \ config/images/everspring/an163.png \ config/images/everspring/an179.png \ config/images/everspring/an180.png \ config/images/everspring/an181.png \ config/images/everspring/hac01.png \ config/images/everspring/han01.png \ config/images/everspring/han02-1.png \ config/images/everspring/hsm02.png \ config/images/everspring/hsp02.png \ config/images/everspring/lptdm1u.png \ config/images/everspring/se812.png \ config/images/everspring/sf812.png \ config/images/everspring/sm103.png \ config/images/everspring/sp103.png \ config/images/everspring/sp814.png \ config/images/everspring/sp815.png \ config/images/everspring/sp816.png \ config/images/everspring/st812.png \ config/images/everspring/st814.png \ config/images/everspring/st815.png \ config/images/everspring/tse03.png \ config/images/evolve/lfm-20.png \ config/images/evolve/ltm-5.png \ config/images/evolve/t-100.png \ config/images/fakro/arz.png \ config/images/fakro/zws12.png \ config/images/fibaro/fgbs222.png \ config/images/fibaro/fgcd001.png \ config/images/fibaro/fgd212.png \ config/images/fibaro/fgdw2.png \ config/images/fibaro/fgfs101.png \ config/images/fibaro/fgfs101zw5.png \ config/images/fibaro/fggc001.png \ config/images/fibaro/fgk001.png \ config/images/fibaro/fgk10x.png \ config/images/fibaro/fgkf601.png \ config/images/fibaro/fgms.png \ config/images/fibaro/fgmszw5.png \ config/images/fibaro/fgpb101.png \ config/images/fibaro/fgr223.png \ config/images/fibaro/fgrgbw442.png \ config/images/fibaro/fgrgbwm441.png \ config/images/fibaro/fgrm222.png \ config/images/fibaro/fgs213.png \ config/images/fibaro/fgs222.png \ config/images/fibaro/fgs223.png \ config/images/fibaro/fgs224.png \ config/images/fibaro/fgsd002.png \ config/images/fibaro/fgt001.png \ config/images/fibaro/fgwd111.png \ config/images/fibaro/fgwds221.png \ config/images/fibaro/fgwoe.png \ config/images/fibaro/fgwpb121.png \ config/images/fibaro/fgwpe.png \ config/images/fibaro/fgwpfzw5.png \ config/images/fibaro/fgwpg111.png \ config/images/fibaro/fgwr111.png \ config/images/firstalert/zcombo-g.png \ config/images/firstalert/zcombo.png \ config/images/firstalert/zsmoke.png \ config/images/followgood/swz-1002.png \ config/images/forest/fs2z5232000002.png \ config/images/fortrezz/fmi.png \ config/images/fortrezz/fts05p.png \ config/images/fortrezz/gdc1_fortrezz_1501.png \ config/images/fortrezz/mimo2plus.png \ config/images/fortrezz/mimolite.png \ config/images/fortrezz/ssa2.png \ config/images/fortrezz/ssa3.png \ config/images/fortrezz/wv01.png \ config/images/fortrezz/wwa-01aa.png \ config/images/fortrezz/wwa02.png \ config/images/frostdale/fdn2311.png \ config/images/ge/12719-plugin-switch.png \ config/images/ge/12724-dimmer.png \ config/images/ge/12727.png \ config/images/ge/14280-plugin-dimmer.png \ config/images/ge/14282-plugin-switch.png \ config/images/ge/14284.png \ config/images/ge/14285.png \ config/images/ge/14288-outlet.png \ config/images/ge/14291-switch.png \ config/images/ge/14292-toggle-switch.png \ config/images/ge/14294-dimmer.png \ config/images/ge/14295-dimmer-toggle.png \ config/images/ge/14298.png \ config/images/ge/14322-dimmer-toggle.png \ config/images/ge/26931-motion-switch.png \ config/images/ge/26933-motion-dimmer.png \ config/images/ge/28167-plugin-dimmer.png \ config/images/ge/28169-plugin-switch.png \ config/images/ge/45604.png \ config/images/ge/46201-switch.png \ config/images/ge/46202-switch.png \ config/images/ge/46203-dimmer.png \ config/images/ge/46204-dimmer-toggle.png \ config/images/ge/dimmer.png \ config/images/ge/dimmer_module.png \ config/images/ge/hinge-pin.png \ config/images/ge/receptacle.png \ config/images/ge/relay.png \ config/images/ge/ze26i.png \ config/images/ge/zw6302.png \ config/images/goodway/td14010.png \ config/images/gr/gr-302n.png \ config/images/gr/gr105.png \ config/images/gr/gr105n.png \ config/images/graber/brz1.png \ config/images/graber/csz1.png \ config/images/graber/mcz1.png \ config/images/graber/rsz1.png \ config/images/graber/vcz1.png \ config/images/greenwave/gs1110-1-gr-1.png \ config/images/greenwave/powernode1.png \ config/images/greenwave/powernode6.png \ config/images/guardtec/gkw2000d.png \ config/images/hab/iblinds.png \ config/images/hab/iblindsV3.png \ config/images/hank/hkzw-dws01.png \ config/images/hank/hkzw-fld01.png \ config/images/hank/hkzw-ms01.png \ config/images/hank/hkzw-ms02-200.png \ config/images/hank/hkzw-rgb01.png \ config/images/hank/hkzw-so01-smartplug.png \ config/images/hank/hkzw-so03.png \ config/images/hank/hkzw-so05-smartplug.png \ config/images/hank/scenecontroller1.png \ config/images/hank/scenecontroller4.png \ config/images/heiman/HS1CA-Z.png \ config/images/heiman/HS1CG-Z.png \ config/images/heiman/HS1DS-Z.png \ config/images/heiman/HS1HT-Z.png \ config/images/heiman/HS1MS-Z.png \ config/images/heiman/HS1SA-Z.png \ config/images/heiman/HS1WL-Z.png \ config/images/heiman/HS2SK-Z.png \ config/images/heltun/he-ft01.png \ config/images/heltun/he-ht01.png \ config/images/homeseer/hs-ds100plus.png \ config/images/homeseer/hs-fc200plus.png \ config/images/homeseer/hs-fls100plus.png \ config/images/homeseer/hs-fs100plus.png \ config/images/homeseer/hs-ls100plus.png \ config/images/homeseer/hs-ms100plus.png \ config/images/homeseer/hs-wd100plus.png \ config/images/homeseer/hs-wd200plus.png \ config/images/homeseer/hs-ws100plus.png \ config/images/homeseer/hs-ws200plus.png \ config/images/homeseer/hsm200.png \ config/images/honeywell/2681-plugin-dimmer.png \ config/images/honeywell/3830-zw3107.png \ config/images/honeywell/39348-ZW4005.png \ config/images/honeywell/39348-ZW4008.png \ config/images/honeywell/39349-ZW1002.png \ config/images/honeywell/39351-ZW3005.png \ config/images/honeywell/39357-ZW3004.png \ config/images/honeywell/39358-ZW4002.png \ config/images/honeywell/39449-ZW4106.png \ config/images/honeywell/lynx-touch-l5100.png \ config/images/honeywell/th6320zw2003.png \ config/images/honeywell/th8320zw1000.png \ config/images/horstmann/asrzw.png \ config/images/horstmann/hrt4zw.png \ config/images/horstmann/scsc17.png \ config/images/horstmann/ses301.png \ config/images/horstmann/ses302.png \ config/images/horstmann/ses303.png \ config/images/horstmann/sir321.png \ config/images/horstmann/srt321.png \ config/images/horstmann/srt323.png \ config/images/horstmann/ssr302.png \ config/images/horstmann/ssr303.png \ config/images/icare/zw-66.png \ config/images/idlock/idlock101.png \ config/images/idlock/idlock150.png \ config/images/ingersoll/dwzwave1.png \ config/images/inovelli/lzw30-sn.png \ config/images/inovelli/lzw30.png \ config/images/inovelli/lzw31-sn.png \ config/images/inovelli/lzw31.png \ config/images/inovelli/lzw36.png \ config/images/inovelli/lzw40.png \ config/images/inovelli/lzw41.png \ config/images/inovelli/lzw42.png \ config/images/inovelli/lzw60.png \ config/images/inovelli/nzw30.png \ config/images/inovelli/simple_module.png \ config/images/iwatsu/ne-4ct-2p.png \ config/images/iwatsu/ne-4ct.png \ config/images/jasco/45601.png \ config/images/kaipule/im20.png \ config/images/kwikset/888.png \ config/images/kwikset/914c.png \ config/images/kwikset/916.jpg \ config/images/kwikset/smartcode.png \ config/images/leviton/dz15s.png \ config/images/leviton/dz6hd.png \ config/images/leviton/dzpa1.png \ config/images/leviton/dzpd3.png \ config/images/leviton/vrcs2.png \ config/images/leviton/vrf01.png \ config/images/leviton/vri10.png \ config/images/leviton/vrpa1.png \ config/images/leviton/vrpd3.png \ config/images/leviton/vrs15.png \ config/images/leviton/zw15r.png \ config/images/leviton/zw4sf.png \ config/images/linear/LB60Z-1.png \ config/images/linear/WD500Z5-1.png \ config/images/linear/WT00Z5-1.png \ config/images/linear/gd00z-7.png \ config/images/linear/ngd00z.png \ config/images/logicsoft/ZDB5100.png \ config/images/logicsoft/ZHC5010.png \ config/images/mcohome/015f_5102_d411.png \ config/images/mcohome/mh7h.png \ config/images/mcohome/mh8fceu0803.png \ config/images/mcohome/mhp220.png \ config/images/mcohome/mhp511.png \ config/images/mcohome/mhs513.png \ config/images/merten/5044xx.png \ config/images/merten/5046xx.png \ config/images/merten/506004.png \ config/images/merten/508244.png \ config/images/miyakawaelectric/me-d101.png \ config/images/namron/1402756.png \ config/images/namron/4512710.png \ config/images/namron/4512712.jpg \ config/images/namron/4512714.jpg \ config/images/namron/4512715.png \ config/images/namron/4512720.jpg \ config/images/namron/4512724.png \ config/images/nexia/db100z.png \ config/images/nexia/th100nx.png \ config/images/nodon/asp3100SmartPlug.png \ config/images/nodon/crc3100OctanRemote.png \ config/images/nodon/crc360xSofremote.png \ config/images/nodon/cws3101wallswitch.png \ config/images/nodon/msp31xxMicroSmartPlug.png \ config/images/northq/nq92021.png \ config/images/oomi/ft100.png \ config/images/oomi/ft111.png \ config/images/oomi/ft112.png \ config/images/oomi/ft118.png \ config/images/permundo/psc132zw.png \ config/images/permundo/psc234zw.png \ config/images/philio/pad02.png \ config/images/philio/pan04.png \ config/images/philio/pan05.png \ config/images/philio/pan06.png \ config/images/philio/pan08.png \ config/images/philio/pan11-1.png \ config/images/philio/pan11.png \ config/images/philio/pan16.png \ config/images/philio/phpab01.png \ config/images/philio/phpat02.png \ config/images/philio/phpsg01.png \ config/images/philio/pse02.png \ config/images/philio/psm02.png \ config/images/philio/psp05.png \ config/images/philio/psr03-1b.png \ config/images/philio/psr04.png \ config/images/philio/pst02-1c.png \ config/images/philio/pst02-b.png \ config/images/philio/pst02.png \ config/images/polycontrol/doorlock.png \ config/images/polycontrol/doorlockv3.png \ config/images/popp/004407.png \ config/images/popp/009303.png \ config/images/popp/009402.png \ config/images/popp/012501.png \ config/images/popp/700045.png \ config/images/popp/700168.png \ config/images/popp/700397.png \ config/images/popp/701202.png \ config/images/popp/dwt.png \ config/images/popp/smoke-detector.png \ config/images/popp/solar-siren.png \ config/images/popp/zweather.png \ config/images/prowell/zw-702.png \ config/images/q-light/q-light_puck.png \ config/images/q-light/q-light_zerodim.png \ config/images/q-light/q-light_zerodim_2pol.png \ config/images/qees/reto-dimmer-plus.png \ config/images/qees/reto-plugin-switch.png \ config/images/qolsys/qz2140-840.png \ config/images/qubino/ZMNHADx.png \ config/images/qubino/ZMNHBDx.png \ config/images/qubino/ZMNHCDx.png \ config/images/qubino/ZMNHDA2.png \ config/images/qubino/ZMNHDDx.png \ config/images/qubino/ZMNHIDx.png \ config/images/qubino/ZMNHNDx.png \ config/images/qubino/ZMNHODx.png \ config/images/qubino/ZMNHQDx.png \ config/images/qubino/ZMNHSDx.png \ config/images/qubino/ZMNHTDx.png \ config/images/qubino/ZMNHVDx.png \ config/images/qubino/ZMNHWD1.png \ config/images/qubino/ZMNHYDx.png \ config/images/qubino/ZMNKADx.png \ config/images/qubino/zmnhxdx.png \ config/images/quby/qb2.png \ config/images/rcs/em52-zw.png \ config/images/rcs/therm0009.png \ config/images/remotec/bw8120eu.png \ config/images/remotec/zfm-80.png \ config/images/remotec/zrc-100eu.png \ config/images/remotec/zrc-90.png \ config/images/remotec/zts-110.png \ config/images/remotec/zts-500.png \ config/images/remotec/zurc.png \ config/images/remotec/zxt-120.png \ config/images/remotec/zxt-310.png \ config/images/remotec/zxt-600.png \ config/images/ring/PIR-SS.png \ config/images/ring/contact-sensor-v2.png \ config/images/ring/motion-detector-v2.png \ config/images/schlage/BE468ZP.png \ config/images/schlage/BE469.png \ config/images/schlage/BE469ZP.png \ config/images/schlage/fe599.png \ config/images/schlagelink/41.png \ config/images/sensative/strips.png \ config/images/sensative/stripscomfort.png \ config/images/sercomm/sw-clp01-eu.png \ config/images/shenzen_neo/ls03ch.jpg \ config/images/shenzen_neo/nas-ab01z.png \ config/images/shenzen_neo/nas-cs01z.jpg \ config/images/shenzen_neo/nas-ds01z.png \ config/images/shenzen_neo/nas-pd01z.png \ config/images/shenzen_neo/nas-pd02z.png \ config/images/shenzen_neo/nas-sc03ze.jpg \ config/images/shenzen_neo/nas-wr01z.png \ config/images/shenzen_neo/nas-wr01ze.png \ config/images/shenzen_neo/nas-ws02z.png \ config/images/shenzen_saykey/SK-3007-05.png \ config/images/shenzhen-neo/eu-1.png \ config/images/shenzhen-neo/eu-2.png \ config/images/shenzhen-neo/eu-3.png \ config/images/simon/10002020-13X.png \ config/images/simon/10002034-13X.png \ config/images/simon/10002080-13X.png \ config/images/smartthings/pgc401m.png \ config/images/smartthings/sth-eth200.png \ config/images/steinel/is140-2.png \ config/images/steinel/l810-led-ihf.png \ config/images/steinel/rs-led-d2.png \ config/images/steinel/xled-home-2.png \ config/images/stelpro/stzw402.png \ config/images/sunricher/srzv9001k12dimz4.png \ config/images/sunricher/srzv9001k12dimz5.png \ config/images/sunricher/srzv9001k2dim.png \ config/images/sunricher/srzv9001k4dim.png \ config/images/sunricher/srzv9001k4dimg2.png \ config/images/sunricher/srzv9001k8.png \ config/images/sunricher/srzv9001t4dimeu.png \ config/images/sunricher/srzv9001tccteu.png \ config/images/sunricher/srzv9003t4rgbweu.png \ config/images/sunricher/srzv9101facct.png \ config/images/sunricher/srzv9101sachpeu.png \ config/images/sunricher/srzv9101sachpswitch.png \ config/images/sunricher/zv2835rac.png \ config/images/sunricher/zv9100a.png \ config/images/sunricher/zv9101.png \ config/images/swiid/swiidinter.png \ config/images/technisat/03009496.png \ config/images/technisat/03009497.png \ config/images/technisat/03009499.png \ config/images/telldus/tzdw100.png \ config/images/telldus/tzwp100.png \ config/images/telldus/tzwp102.png \ config/images/there/800z.png \ config/images/thermofloor/Heatit-Z-Push-button-8-white.png \ config/images/thermofloor/heatit0204.png \ config/images/thermofloor/heatit021.png \ config/images/thermofloor/heatit056.png \ config/images/thermofloor/heatit058.png \ config/images/thermofloor/heatit20a.png \ config/images/thermofloor/heatit_zdim.png \ config/images/trane/TZEMT400AB32MAA.png \ config/images/trane/TZEMT400BB32MAA.png \ config/images/trane/TZEMT524AA21MA.png \ config/images/vera/vera2.png \ config/images/vision/1701.png \ config/images/vision/brg1-433.png \ config/images/vision/zd2102.png \ config/images/vision/zd2105us5.png \ config/images/vision/zd2201.png \ config/images/vision/zd2301.png \ config/images/vision/zl7101us.png \ config/images/vision/zl7201us.png \ config/images/vision/zl7431.png \ config/images/vision/zl7432us.png \ config/images/vision/zm1601eu.png \ config/images/vision/zm1601eu5.png \ config/images/vision/zm1602eu5.png \ config/images/vision/zm1701.png \ config/images/vision/zp3102.png \ config/images/vision/zp3111.png \ config/images/vision/zr1202us.png \ config/images/vision/zs610eu.png \ config/images/vision/zu1401jp.png \ config/images/vitrum/vitrumI-Dimmer.png \ config/images/vitrum/vitrumI-Switch.png \ config/images/vitrum/vitrumII-Blind.png \ config/images/vitrum/vitrumII-Dimmer.png \ config/images/vitrum/vitrumII-Switch.png \ config/images/wenzhou/tsp01.png \ config/images/wenzhou/tz55.png \ config/images/wenzhou/tz56.png \ config/images/wenzhou/tz65d.png \ config/images/wenzhou/tz66d.png \ config/images/wenzhou/tz67.png \ config/images/wenzhou/tz68.png \ config/images/wenzhou/tz69.png \ config/images/wenzhou/tz77.png \ config/images/wenzhou/tz78.png \ config/images/wenzhou/tz88.png \ config/images/wenzhou/tze96.png \ config/images/widom/DRY.png \ config/images/widom/UBS104.png \ config/images/widom/UME304C_S.png \ config/images/widom/UMS2.png \ config/images/widom/WDS.png \ config/images/widom/WDS2.png \ config/images/widom/WSP.png \ config/images/widom/WTED.png \ config/images/wink/wnk-mot1.png \ config/images/wink/wnk-sir1p.png \ config/images/zipato/HS1CA-Z.png \ config/images/zipato/HS1CG-Z.png \ config/images/zipato/HS1SA-Z.png \ config/images/zipato/HS1WL-Z.png \ config/images/zipato/RGBBulb.png \ config/images/zipato/ne-nas-ab01z.png \ config/images/zipato/pan04.png \ config/images/zipato/phpab01.png \ config/images/zipato/pse02.png \ config/images/zipato/pst02.png \ config/images/zipato/vszd2102.png \ config/images/zipato/zd2301.png \ config/images/zipato/zp3102.png \ config/images/zooz/zen06.png \ config/images/zooz/zen15.png \ config/images/zooz/zen16.png \ config/images/zooz/zen20.png \ config/images/zooz/zen20v2.png \ config/images/zooz/zen21.png \ config/images/zooz/zen21v3.png \ config/images/zooz/zen22.png \ config/images/zooz/zen23v3.png \ config/images/zooz/zen24v2.png \ config/images/zooz/zen26.png \ config/images/zooz/zen27.png \ config/images/zooz/zen30.png \ config/images/zooz/zen31.png \ config/images/zooz/zen34.png \ config/images/zooz/zen71.png \ config/images/zooz/zen72.png \ config/images/zooz/zen76.png \ config/images/zooz/zen77.png \ config/images/zooz/zse09.png \ config/images/zooz/zse19.png \ config/images/zooz/zse29.png \ config/images/zooz/zse30.png \ config/images/zooz/zse33.png \ config/images/zooz/zse40.png \ config/images/zwave.me/004001.png \ config/images/zwave.me/ZME_05431.png \ config/images/zwave.me/ZME_06433.png \ config/images/zwave.me/ZME_06436.png \ config/images/zwave.me/ZUno.png \ config/images/zwave.me/kfob.png \ config/images/zwave.me/popp_kfob-c.png \ config/images/zwave.me/razberry.png \ config/images/zwave.me/zme_raz5.png \ config/images/zwave.me/zme_wallc_s.png \ config/images/zwave.me/zweather.png \ config/images/zwp/PA-100.png \ config/images/zwp/WD-100.png \ config/ingersoll/dwzwave1.xml \ config/inovelli/lzw30-sn.xml \ config/inovelli/lzw30.xml \ config/inovelli/lzw31-sn.xml \ config/inovelli/lzw31.xml \ config/inovelli/lzw36.xml \ config/inovelli/lzw40.xml \ config/inovelli/lzw41.xml \ config/inovelli/lzw42.xml \ config/inovelli/lzw45.xml \ config/inovelli/lzw60.xml \ config/inovelli/nzw1201.xml \ config/inovelli/nzw30.xml \ config/inovelli/nzw31.xml \ config/inovelli/nzw36.xml \ config/inovelli/nzw37.xml \ config/inovelli/nzw39.xml \ config/inovelli/nzw96.xml \ config/inovelli/nzw97.xml \ config/inovelli/simple_module.xml \ config/intermatic/ca8900.xml \ config/iris/rangeextender.xml \ config/iwatsu/ne-4ct-2p.xml \ config/iwatsu/ne-4ct.xml \ config/jasco/45601.xml \ config/kaipule/im20.xml \ config/kaipule/ix32.xml \ config/kwikset/888.xml \ config/kwikset/910.xml \ config/kwikset/914c.xml \ config/kwikset/916.xml \ config/kwikset/smartcode.xml \ config/leviton/dz15s.xml \ config/leviton/dz6hd.xml \ config/leviton/dzpa1.xml \ config/leviton/dzpd3.xml \ config/leviton/rzi10.xml \ config/leviton/vrcpg.xml \ config/leviton/vrcs2.xml \ config/leviton/vrcz4.xml \ config/leviton/vre06.xml \ config/leviton/vrf01.xml \ config/leviton/vri06.xml \ config/leviton/vri10.xml \ config/leviton/vrpa1.xml \ config/leviton/vrpd3.xml \ config/leviton/vrs15.xml \ config/leviton/zw15r.xml \ config/leviton/zw4sf.xml \ config/linear/GC-TBZ48.xml \ config/linear/LB60Z-1.xml \ config/linear/PD300Z-2.xml \ config/linear/WA00Z-1.xml \ config/linear/WA105DBZ-1.xml \ config/linear/WADWAZ-1.xml \ config/linear/WAPIRZ-1.xml \ config/linear/WD500Z-1.xml \ config/linear/WD500Z5-1.xml \ config/linear/WS15Z-1.xml \ config/linear/WT00Z-1.xml \ config/linear/WT00Z5-1.xml \ config/linear/gd00z-7.xml \ config/linear/ngd00z.xml \ config/logicsoft/ZDB5100.xml \ config/logicsoft/ZHC5002.xml \ config/logicsoft/ZHC5010.xml \ config/manufacturer_specific.xml \ config/manufacturer_specific.xsd \ config/mcohome/a8-9.xml \ config/mcohome/mh10pm25wd.xml \ config/mcohome/mh7h.xml \ config/mcohome/mh8fceu.xml \ config/mcohome/mh8fceu0803.xml \ config/mcohome/mh9co2.xml \ config/mcohome/mhdt411.xml \ config/mcohome/mhp210.xml \ config/mcohome/mhp220.xml \ config/mcohome/mhp511.xml \ config/mcohome/mhs220.xml \ config/mcohome/mhs311.xml \ config/mcohome/mhs312.xml \ config/mcohome/mhs314.xml \ config/mcohome/mhs411.xml \ config/mcohome/mhs412.xml \ config/mcohome/mhs513.xml \ config/merten/5044xx.xml \ config/merten/5046xx.xml \ config/merten/506004.xml \ config/merten/507801.xml \ config/merten/508244.xml \ config/merten/50x5xx.xml \ config/miyakawaelectric/me-d101.xml \ config/namron/1402756.xml \ config/namron/4512710.xml \ config/namron/4512712.xml \ config/namron/4512714.xml \ config/namron/4512715.xml \ config/namron/4512720.xml \ config/namron/4512724.xml \ config/nei/ms11z.xml \ config/nexia/db100z.xml \ config/nexia/th100nx.xml \ config/nodon/asp3100SmartPlug.xml \ config/nodon/crc3100OctanRemote.xml \ config/nodon/crc360xSofremote.xml \ config/nodon/cws3101wallswitch.xml \ config/nodon/msp31xxMicroSmartPlug.xml \ config/northq/nq9021.xml \ config/northq/nq9121.xml \ config/northq/nq92021.xml \ config/oomi/ft100.xml \ config/oomi/ft111.xml \ config/oomi/ft112.xml \ config/oomi/ft118.xml \ config/options.xml \ config/options.xsd \ config/permundo/psc132zw.xml \ config/permundo/psc234zw.xml \ config/philio/pad02.xml \ config/philio/pan03.xml \ config/philio/pan04.xml \ config/philio/pan05.xml \ config/philio/pan06.xml \ config/philio/pan07.xml \ config/philio/pan08.xml \ config/philio/pan11-1.xml \ config/philio/pan11.xml \ config/philio/pan16.xml \ config/philio/phpab01.xml \ config/philio/phpat02.xml \ config/philio/phpsg01.xml \ config/philio/pse02.xml \ config/philio/psm02.xml \ config/philio/psp05.xml \ config/philio/psr03-1b.xml \ config/philio/psr04.xml \ config/philio/pst02-1c.xml \ config/philio/pst02-b.xml \ config/philio/pst02.xml \ config/polycontrol/doorlock.xml \ config/polycontrol/doorlockv3.xml \ config/polycontrol/keypad.xml \ config/polycontrol/polylock.xml \ config/popp/004407.xml \ config/popp/009105.xml \ config/popp/009303.xml \ config/popp/009402.xml \ config/popp/009501.xml \ config/popp/012501.xml \ config/popp/123580.xml \ config/popp/123601.xml \ config/popp/123658.xml \ config/popp/700045.xml \ config/popp/700168.xml \ config/popp/700342.xml \ config/popp/700397.xml \ config/popp/700793.xml \ config/popp/701202.xml \ config/popp/dwt.xml \ config/popp/smoke-detector.xml \ config/popp/solar-siren.xml \ config/popp/zweather.xml \ config/prowell/zw-702.xml \ config/q-light/q-light_puck.xml \ config/q-light/q-light_zerodim.xml \ config/q-light/q-light_zerodim_2pol.xml \ config/qees/reto-dimmer-plus.xml \ config/qees/reto-plugin-switch.xml \ config/qolsys/qz2140-840.xml \ config/qubino/ZMNHAA2.xml \ config/qubino/ZMNHADx.xml \ config/qubino/ZMNHBA2.xml \ config/qubino/ZMNHBDx.xml \ config/qubino/ZMNHCA2.xml \ config/qubino/ZMNHCDx.xml \ config/qubino/ZMNHDA2.xml \ config/qubino/ZMNHDDx.xml \ config/qubino/ZMNHHDx.xml \ config/qubino/ZMNHIA2.xml \ config/qubino/ZMNHIDxS1.xml \ config/qubino/ZMNHIDxS2.xml \ config/qubino/ZMNHJA2.xml \ config/qubino/ZMNHJD1.xml \ config/qubino/ZMNHKDx.xml \ config/qubino/ZMNHLAx.xml \ config/qubino/ZMNHLDx.xml \ config/qubino/ZMNHNDx.xml \ config/qubino/ZMNHODx.xml \ config/qubino/ZMNHQDx.xml \ config/qubino/ZMNHSDx.xml \ config/qubino/ZMNHTDx.xml \ config/qubino/ZMNHTDxS3.xml \ config/qubino/ZMNHUD1.xml \ config/qubino/ZMNHVDx.xml \ config/qubino/ZMNHWD1.xml \ config/qubino/ZMNHXDx.xml \ config/qubino/ZMNHYDx.xml \ config/qubino/ZMNHZDx.xml \ config/qubino/ZMNKADx.xml \ config/qubino/ZMNKIDx.xml \ config/quby/qb2.xml \ config/rcs/em52-zw.xml \ config/rcs/pm12-zw.xml \ config/rcs/therm0005.xml \ config/rcs/therm0007.xml \ config/rcs/therm0009.xml \ config/remotec/bw8120eu.xml \ config/remotec/zfm-80.xml \ config/remotec/zrc-100eu.xml \ config/remotec/zrc-90.xml \ config/remotec/zts-110.xml \ config/remotec/zts-500.xml \ config/remotec/zurc.xml \ config/remotec/zxt-120.xml \ config/remotec/zxt-310.xml \ config/remotec/zxt-600.xml \ config/ring/PIR-SS.xml \ config/ring/contact-sensor-v2.xml \ config/ring/motion-detector-v2.xml \ config/schlage/BE468.xml \ config/schlage/BE468ZP.xml \ config/schlage/BE469.xml \ config/schlage/BE469ZP.xml \ config/schlage/fe599.xml \ config/schlagelink/41.xml \ config/schlagelink/itemp.xml \ config/schlagelink/minikeypad.xml \ config/sensative/strips.xml \ config/sensative/stripscomfort.xml \ config/sercomm/sw-clp01-eu.xml \ config/shenzen_neo/ls01ch.xml \ config/shenzen_neo/ls02ch.xml \ config/shenzen_neo/ls03ch.xml \ config/shenzen_neo/nas-ab01z.xml \ config/shenzen_neo/nas-cs01z.xml \ config/shenzen_neo/nas-ds01z.xml \ config/shenzen_neo/nas-pd01z.xml \ config/shenzen_neo/nas-pd02z.xml \ config/shenzen_neo/nas-pd03z.xml \ config/shenzen_neo/nas-rc01z.xml \ config/shenzen_neo/nas-sc03ze.xml \ config/shenzen_neo/nas-wr01z.xml \ config/shenzen_neo/nas-wr01ze.xml \ config/shenzen_neo/nas-ws02z.xml \ config/shenzen_saykey/sk-3007-05.xml \ config/simon/10002020-13X.xml \ config/simon/10002034-13X.xml \ config/simon/10002041-13X.xml \ config/simon/10002080-13X.xml \ config/smartthings/pgc401m.xml \ config/smartthings/sth-eth200.xml \ config/somfy/1811265_ZRTSI.xml \ config/steinel/is140-2.xml \ config/steinel/l810-led-ihf.xml \ config/steinel/rs-led-d2.xml \ config/steinel/xled-home-2.xml \ config/stelpro/stzw402.xml \ config/sunricher/srzv9001k12dimz4.xml \ config/sunricher/srzv9001k12dimz5.xml \ config/sunricher/srzv9001k2dim.xml \ config/sunricher/srzv9001k4dim.xml \ config/sunricher/srzv9001k4dimg2.xml \ config/sunricher/srzv9001k8.xml \ config/sunricher/srzv9001t4dimeu.xml \ config/sunricher/srzv9001tccteu.xml \ config/sunricher/srzv9003t4rgbweu.xml \ config/sunricher/srzv9100aa.xml \ config/sunricher/srzv9101sachpeu.xml \ config/sunricher/srzv9101sachpswitch.xml \ config/sunricher/zv2835rac.xml \ config/sunricher/zv9101.xml \ config/sunricher/zv9101fa.xml \ config/swiid/swiidinter.xml \ config/swiid/swiidplug.xml \ config/technisat/03009496.xml \ config/technisat/03009497.xml \ config/technisat/03009499.xml \ config/telldus/tzdw100.xml \ config/telldus/tzwp100.xml \ config/telldus/tzwp102.xml \ config/there/800z.xml \ config/thermofloor/heatit-zdim.xml \ config/thermofloor/heatit021-v1.92.xml \ config/thermofloor/heatit021.xml \ config/thermofloor/heatit056.xml \ config/thermofloor/heatit058.xml \ config/thermofloor/heatit204.xml \ config/thermofloor/heatit20a.xml \ config/thermofloor/heatitz4.xml \ config/thermofloor/heatitz8.xml \ config/trane/TZEMT400AB32MAA.xml \ config/trane/TZEMT400BB32MAA.xml \ config/trane/TZEMT524AA21MA.xml \ config/vera/vera2.xml \ config/vision/1701.xml \ config/vision/brg1-433.xml \ config/vision/zd2102.xml \ config/vision/zd2105us5.xml \ config/vision/zd2201.xml \ config/vision/zd2301.xml \ config/vision/zf5201.xml \ config/vision/zg8101.xml \ config/vision/zl7101us.xml \ config/vision/zl7201us.xml \ config/vision/zl7261.xml \ config/vision/zl7431.xml \ config/vision/zl7432us.xml \ config/vision/zm1601eu.xml \ config/vision/zm1601eu5.xml \ config/vision/zm1602eu.xml \ config/vision/zm1602eu5.xml \ config/vision/zp3102.xml \ config/vision/zp3111.xml \ config/vision/zr1202us.xml \ config/vision/zs5101eu.xml \ config/vision/zs610eu.xml \ config/vision/zu1401jp.xml \ config/vitrum/vitrumI-Dimmer.xml \ config/vitrum/vitrumI-Switch.xml \ config/vitrum/vitrumII-Dimmer.xml \ config/vitrum/vitrumII-RollerBlind.xml \ config/vitrum/vitrumII-Switch.xml \ config/vitrum/vitrumIII-Dimmer.xml \ config/vitrum/vitrumIII-Switch.xml \ config/vitrum/vitrumIV-Switch.xml \ config/vitrum/vitrumVI-Switch.xml \ config/waynedalton/WDTC-20.xml \ config/wenzhou/sm103.xml \ config/wenzhou/tsp01.xml \ config/wenzhou/tz55.xml \ config/wenzhou/tz56.xml \ config/wenzhou/tz56s.xml \ config/wenzhou/tz57.xml \ config/wenzhou/tz65d.xml \ config/wenzhou/tz66d.xml \ config/wenzhou/tz67.xml \ config/wenzhou/tz68.xml \ config/wenzhou/tz69.xml \ config/wenzhou/tz74.xml \ config/wenzhou/tz77.xml \ config/wenzhou/tz78.xml \ config/wenzhou/tz79.xml \ config/wenzhou/tz88.xml \ config/wenzhou/tze96.xml \ config/widom/DRY.xml \ config/widom/UBS104.xml \ config/widom/UME304C_S.xml \ config/widom/UMS2.xml \ config/widom/WDS.xml \ config/widom/WDS2.xml \ config/widom/WSP.xml \ config/widom/WTED.xml \ config/wink/wnk-mot1.xml \ config/wink/wnk-sir1p.xml \ config/zipato/MiniKeypad.xml \ config/zipato/RGBBulb.xml \ config/zipato/RGBBulb2.xml \ config/zipato/ne-nas-ab02z.xml \ config/zipato/pan04.xml \ config/zipato/vszd2102.xml \ config/zipato/zp3102.xml \ config/zooz/zen06.xml \ config/zooz/zen07.xml \ config/zooz/zen15.xml \ config/zooz/zen16.xml \ config/zooz/zen20.xml \ config/zooz/zen20v2.xml \ config/zooz/zen21.xml \ config/zooz/zen21v3.xml \ config/zooz/zen22.xml \ config/zooz/zen22v2.xml \ config/zooz/zen23.xml \ config/zooz/zen23v3.xml \ config/zooz/zen24.xml \ config/zooz/zen24v2.xml \ config/zooz/zen25.xml \ config/zooz/zen26.xml \ config/zooz/zen27.xml \ config/zooz/zen30.xml \ config/zooz/zen31.xml \ config/zooz/zen34.xml \ config/zooz/zen71.xml \ config/zooz/zen72.xml \ config/zooz/zen76.xml \ config/zooz/zen77.xml \ config/zooz/zse08.xml \ config/zooz/zse09.xml \ config/zooz/zse18.xml \ config/zooz/zse19.xml \ config/zooz/zse29.xml \ config/zooz/zse30.xml \ config/zooz/zse33.xml \ config/zooz/zse40.xml \ config/zwave.me/004001.xml \ config/zwave.me/ZME_05431.xml \ config/zwave.me/ZME_05461.xml \ config/zwave.me/ZME_06433.xml \ config/zwave.me/ZME_06436.xml \ config/zwave.me/ZME_064381.xml \ config/zwave.me/ZME_064435.xml \ config/zwave.me/ZME_KFOB-S.xml \ config/zwave.me/ZME_RC2.xml \ config/zwave.me/ZME_WALLC-S.xml \ config/zwave.me/ZME_WCD2.xml \ config/zwave.me/ZUno.xml \ config/zwave.me/iTemp.xml \ config/zwave.me/kfob.xml \ config/zwave.me/popp_kfob-c.xml \ config/zwave.me/razberry.xml \ config/zwave.me/zme_raz5.xml \ config/zwave.me/zweather.xml \ config/zwcfg.xsd \ config/zwp/PA-100.xml \ config/zwp/WD-100.xml \ config/zwscene.xsd \ cpp/build/LeakSanitizer-Suppressions.txt \ cpp/build/Makefile \ cpp/build/OZW_RunTests.sh \ cpp/build/libopenzwave.pc.in \ cpp/build/ozw_config.in \ cpp/build/sh2ju.sh \ cpp/build/support.mk \ cpp/build/testconfig.pl \ cpp/build/testconfigsuppressions.cfg \ cpp/build/testconfigversions.cfg \ cpp/build/winRT/vs2015/OpenZWave.sln \ cpp/build/winRT/vs2015/OpenZWave.vcxproj \ cpp/build/winRT/vs2015/OpenZWave.vcxproj.filters \ cpp/build/windows/GIT-VS-VERSION-GEN.bat \ cpp/build/windows/installer/buildall.bat \ cpp/build/windows/installer/openzwave.nsi \ cpp/build/windows/mingw-w64/Makefile \ cpp/build/windows/mingw32/Makefile \ cpp/build/windows/vs2010/OpenZWave.sln \ cpp/build/windows/vs2010/OpenZWave.vcxproj \ cpp/build/windows/vs2010/OpenZWave.vcxproj.filters \ cpp/build/windows/winversion.tmpl \ cpp/examples/MinOZW/Main.cpp \ cpp/examples/MinOZW/Makefile \ cpp/examples/MinOZW/MinOZW.in \ cpp/examples/windows/MinOZW/Main.cpp \ cpp/examples/windows/MinOZW/vs2010/MinOZW.sln \ cpp/examples/windows/MinOZW/vs2010/MinOZW.vcxproj \ cpp/examples/windows/MinOZW/vs2010/MinOZW.vcxproj.filters \ cpp/hidapi/AUTHORS.txt \ cpp/hidapi/HACKING.txt \ cpp/hidapi/LICENSE-bsd.txt \ cpp/hidapi/LICENSE-gpl3.txt \ cpp/hidapi/LICENSE-orig.txt \ cpp/hidapi/LICENSE.txt \ cpp/hidapi/Makefile.am \ cpp/hidapi/README.txt \ cpp/hidapi/bootstrap \ cpp/hidapi/configure.ac \ cpp/hidapi/doxygen/Doxyfile \ cpp/hidapi/hidapi/hidapi.h \ cpp/hidapi/libusb/Makefile-manual \ cpp/hidapi/libusb/Makefile.am \ cpp/hidapi/libusb/Makefile.freebsd \ cpp/hidapi/libusb/Makefile.linux \ cpp/hidapi/libusb/hid.c \ cpp/hidapi/linux/.gitignore \ cpp/hidapi/linux/Makefile-manual \ cpp/hidapi/linux/Makefile.am \ cpp/hidapi/linux/README.txt \ cpp/hidapi/linux/hid.c \ cpp/hidapi/m4/ax_pthread.m4 \ cpp/hidapi/m4/pkg.m4 \ cpp/hidapi/mac/.gitignore \ cpp/hidapi/mac/Makefile-manual \ cpp/hidapi/mac/Makefile.am \ cpp/hidapi/mac/hid.c \ cpp/hidapi/pc/hidapi-hidraw.pc.in \ cpp/hidapi/pc/hidapi-libusb.pc.in \ cpp/hidapi/pc/hidapi.pc.in \ cpp/hidapi/udev/99-hid.rules \ cpp/hidapi/windows/.gitignore \ cpp/hidapi/windows/Makefile-manual \ cpp/hidapi/windows/Makefile.am \ cpp/hidapi/windows/Makefile.mingw \ cpp/hidapi/windows/ddk_build/.gitignore \ cpp/hidapi/windows/ddk_build/hidapi.def \ cpp/hidapi/windows/ddk_build/makefile \ cpp/hidapi/windows/ddk_build/sources \ cpp/hidapi/windows/hid.cpp \ cpp/hidapi/windows/hidapi.sln \ cpp/hidapi/windows/hidapi.vcproj \ cpp/hidapi/windows/hidtest.vcproj \ cpp/src/Bitfield.cpp \ cpp/src/Bitfield.h \ cpp/src/CompatOptionManager.cpp \ cpp/src/CompatOptionManager.h \ cpp/src/DNSThread.cpp \ cpp/src/DNSThread.h \ cpp/src/Defs.h \ cpp/src/DoxygenMain.h \ cpp/src/Driver.cpp \ cpp/src/Driver.h \ cpp/src/Group.cpp \ cpp/src/Group.h \ cpp/src/Http.cpp \ cpp/src/Http.h \ cpp/src/Localization.cpp \ cpp/src/Localization.h \ cpp/src/Manager.cpp \ cpp/src/Manager.h \ cpp/src/ManufacturerSpecificDB.cpp \ cpp/src/ManufacturerSpecificDB.h \ cpp/src/Msg.cpp \ cpp/src/Msg.h \ cpp/src/Node.cpp \ cpp/src/Node.h \ cpp/src/Notification.cpp \ cpp/src/Notification.h \ cpp/src/NotificationCCTypes.cpp \ cpp/src/NotificationCCTypes.h \ cpp/src/OZWException.h \ cpp/src/Options.cpp \ cpp/src/Options.h \ cpp/src/Scene.cpp \ cpp/src/Scene.h \ cpp/src/SensorMultiLevelCCTypes.cpp \ cpp/src/SensorMultiLevelCCTypes.h \ cpp/src/TimerThread.cpp \ cpp/src/TimerThread.h \ cpp/src/Utils.cpp \ cpp/src/Utils.h \ cpp/src/ValueIDIndexes.h \ cpp/src/ValueIDIndexesDefines.def \ cpp/src/ValueIDIndexesDefines.h \ cpp/src/ZWSecurity.cpp \ cpp/src/ZWSecurity.h \ cpp/src/aes/aes.h \ cpp/src/aes/aes.txt \ cpp/src/aes/aes_modes.c \ cpp/src/aes/aescpp.h \ cpp/src/aes/aescrypt.c \ cpp/src/aes/aeskey.c \ cpp/src/aes/aesopt.h \ cpp/src/aes/aestab.c \ cpp/src/aes/aestab.h \ cpp/src/aes/brg_endian.h \ cpp/src/aes/brg_types.h \ cpp/src/command_classes/Alarm.cpp \ cpp/src/command_classes/Alarm.h \ cpp/src/command_classes/ApplicationStatus.cpp \ cpp/src/command_classes/ApplicationStatus.h \ cpp/src/command_classes/Association.cpp \ cpp/src/command_classes/Association.h \ cpp/src/command_classes/AssociationCommandConfiguration.cpp \ cpp/src/command_classes/AssociationCommandConfiguration.h \ cpp/src/command_classes/BarrierOperator.cpp \ cpp/src/command_classes/BarrierOperator.h \ cpp/src/command_classes/Basic.cpp \ cpp/src/command_classes/Basic.h \ cpp/src/command_classes/BasicWindowCovering.cpp \ cpp/src/command_classes/BasicWindowCovering.h \ cpp/src/command_classes/Battery.cpp \ cpp/src/command_classes/Battery.h \ cpp/src/command_classes/CRC16Encap.cpp \ cpp/src/command_classes/CRC16Encap.h \ cpp/src/command_classes/CentralScene.cpp \ cpp/src/command_classes/CentralScene.h \ cpp/src/command_classes/ClimateControlSchedule.cpp \ cpp/src/command_classes/ClimateControlSchedule.h \ cpp/src/command_classes/Clock.cpp \ cpp/src/command_classes/Clock.h \ cpp/src/command_classes/Color.cpp \ cpp/src/command_classes/Color.h \ cpp/src/command_classes/CommandClass.cpp \ cpp/src/command_classes/CommandClass.h \ cpp/src/command_classes/CommandClasses.cpp \ cpp/src/command_classes/CommandClasses.h \ cpp/src/command_classes/Configuration.cpp \ cpp/src/command_classes/Configuration.h \ cpp/src/command_classes/ControllerReplication.cpp \ cpp/src/command_classes/ControllerReplication.h \ cpp/src/command_classes/DeviceResetLocally.cpp \ cpp/src/command_classes/DeviceResetLocally.h \ cpp/src/command_classes/DoorLock.cpp \ cpp/src/command_classes/DoorLock.h \ cpp/src/command_classes/DoorLockLogging.cpp \ cpp/src/command_classes/DoorLockLogging.h \ cpp/src/command_classes/EnergyProduction.cpp \ cpp/src/command_classes/EnergyProduction.h \ cpp/src/command_classes/Hail.cpp \ cpp/src/command_classes/Hail.h \ cpp/src/command_classes/Indicator.cpp \ cpp/src/command_classes/Indicator.h \ cpp/src/command_classes/Language.cpp \ cpp/src/command_classes/Language.h \ cpp/src/command_classes/Lock.cpp \ cpp/src/command_classes/Lock.h \ cpp/src/command_classes/ManufacturerProprietary.cpp \ cpp/src/command_classes/ManufacturerProprietary.h \ cpp/src/command_classes/ManufacturerSpecific.cpp \ cpp/src/command_classes/ManufacturerSpecific.h \ cpp/src/command_classes/Meter.cpp \ cpp/src/command_classes/Meter.h \ cpp/src/command_classes/MeterPulse.cpp \ cpp/src/command_classes/MeterPulse.h \ cpp/src/command_classes/MultiChannelAssociation.cpp \ cpp/src/command_classes/MultiChannelAssociation.h \ cpp/src/command_classes/MultiCmd.cpp \ cpp/src/command_classes/MultiCmd.h \ cpp/src/command_classes/MultiInstance.cpp \ cpp/src/command_classes/MultiInstance.h \ cpp/src/command_classes/NoOperation.cpp \ cpp/src/command_classes/NoOperation.h \ cpp/src/command_classes/NodeNaming.cpp \ cpp/src/command_classes/NodeNaming.h \ cpp/src/command_classes/Powerlevel.cpp \ cpp/src/command_classes/Powerlevel.h \ cpp/src/command_classes/Proprietary.cpp \ cpp/src/command_classes/Proprietary.h \ cpp/src/command_classes/Protection.cpp \ cpp/src/command_classes/Protection.h \ cpp/src/command_classes/SceneActivation.cpp \ cpp/src/command_classes/SceneActivation.h \ cpp/src/command_classes/Security.cpp \ cpp/src/command_classes/Security.h \ cpp/src/command_classes/SensorAlarm.cpp \ cpp/src/command_classes/SensorAlarm.h \ cpp/src/command_classes/SensorBinary.cpp \ cpp/src/command_classes/SensorBinary.h \ cpp/src/command_classes/SensorMultilevel.cpp \ cpp/src/command_classes/SensorMultilevel.h \ cpp/src/command_classes/SimpleAV.cpp \ cpp/src/command_classes/SimpleAV.h \ cpp/src/command_classes/SimpleAVCommandItem.cpp \ cpp/src/command_classes/SimpleAVCommandItem.h \ cpp/src/command_classes/SoundSwitch.cpp \ cpp/src/command_classes/SoundSwitch.h \ cpp/src/command_classes/SwitchAll.cpp \ cpp/src/command_classes/SwitchAll.h \ cpp/src/command_classes/SwitchBinary.cpp \ cpp/src/command_classes/SwitchBinary.h \ cpp/src/command_classes/SwitchMultilevel.cpp \ cpp/src/command_classes/SwitchMultilevel.h \ cpp/src/command_classes/SwitchToggleBinary.cpp \ cpp/src/command_classes/SwitchToggleBinary.h \ cpp/src/command_classes/SwitchToggleMultilevel.cpp \ cpp/src/command_classes/SwitchToggleMultilevel.h \ cpp/src/command_classes/ThermostatFanMode.cpp \ cpp/src/command_classes/ThermostatFanMode.h \ cpp/src/command_classes/ThermostatFanState.cpp \ cpp/src/command_classes/ThermostatFanState.h \ cpp/src/command_classes/ThermostatMode.cpp \ cpp/src/command_classes/ThermostatMode.h \ cpp/src/command_classes/ThermostatOperatingState.cpp \ cpp/src/command_classes/ThermostatOperatingState.h \ cpp/src/command_classes/ThermostatSetpoint.cpp \ cpp/src/command_classes/ThermostatSetpoint.h \ cpp/src/command_classes/TimeParameters.cpp \ cpp/src/command_classes/TimeParameters.h \ cpp/src/command_classes/UserCode.cpp \ cpp/src/command_classes/UserCode.h \ cpp/src/command_classes/Version.cpp \ cpp/src/command_classes/Version.h \ cpp/src/command_classes/WakeUp.cpp \ cpp/src/command_classes/WakeUp.h \ cpp/src/command_classes/ZWavePlusInfo.cpp \ cpp/src/command_classes/ZWavePlusInfo.h \ cpp/src/platform/Controller.cpp \ cpp/src/platform/Controller.h \ cpp/src/platform/DNS.cpp \ cpp/src/platform/DNS.h \ cpp/src/platform/Event.cpp \ cpp/src/platform/Event.h \ cpp/src/platform/FileOps.cpp \ cpp/src/platform/FileOps.h \ cpp/src/platform/HidController.cpp \ cpp/src/platform/HidController.h \ cpp/src/platform/HttpClient.cpp \ cpp/src/platform/HttpClient.h \ cpp/src/platform/Log.cpp \ cpp/src/platform/Log.h \ cpp/src/platform/Mutex.cpp \ cpp/src/platform/Mutex.h \ cpp/src/platform/Ref.h \ cpp/src/platform/SerialController.cpp \ cpp/src/platform/SerialController.h \ cpp/src/platform/Stream.cpp \ cpp/src/platform/Stream.h \ cpp/src/platform/Thread.cpp \ cpp/src/platform/Thread.h \ cpp/src/platform/TimeStamp.cpp \ cpp/src/platform/TimeStamp.h \ cpp/src/platform/Wait.cpp \ cpp/src/platform/Wait.h \ cpp/src/platform/unix/DNSImpl.cpp \ cpp/src/platform/unix/DNSImpl.h \ cpp/src/platform/unix/EventImpl.cpp \ cpp/src/platform/unix/EventImpl.h \ cpp/src/platform/unix/FileOpsImpl.cpp \ cpp/src/platform/unix/FileOpsImpl.h \ cpp/src/platform/unix/LogImpl.cpp \ cpp/src/platform/unix/LogImpl.h \ cpp/src/platform/unix/MutexImpl.cpp \ cpp/src/platform/unix/MutexImpl.h \ cpp/src/platform/unix/SerialControllerImpl.cpp \ cpp/src/platform/unix/SerialControllerImpl.h \ cpp/src/platform/unix/ThreadImpl.cpp \ cpp/src/platform/unix/ThreadImpl.h \ cpp/src/platform/unix/TimeStampImpl.cpp \ cpp/src/platform/unix/TimeStampImpl.h \ cpp/src/platform/unix/WaitImpl.cpp \ cpp/src/platform/unix/WaitImpl.h \ cpp/src/platform/unix/android.h \ cpp/src/platform/winRT/DNSImpl.cpp \ cpp/src/platform/winRT/DNSImpl.h \ cpp/src/platform/winRT/EventImpl.cpp \ cpp/src/platform/winRT/EventImpl.h \ cpp/src/platform/winRT/FileOpsImpl.cpp \ cpp/src/platform/winRT/FileOpsImpl.h \ cpp/src/platform/winRT/HidControllerWinRT.cpp \ cpp/src/platform/winRT/HidControllerWinRT.h \ cpp/src/platform/winRT/LogImpl.cpp \ cpp/src/platform/winRT/LogImpl.h \ cpp/src/platform/winRT/MutexImpl.cpp \ cpp/src/platform/winRT/MutexImpl.h \ cpp/src/platform/winRT/SerialControllerImpl.cpp \ cpp/src/platform/winRT/SerialControllerImpl.h \ cpp/src/platform/winRT/ThreadImpl.cpp \ cpp/src/platform/winRT/ThreadImpl.h \ cpp/src/platform/winRT/TimeStampImpl.cpp \ cpp/src/platform/winRT/TimeStampImpl.h \ cpp/src/platform/winRT/WaitImpl.cpp \ cpp/src/platform/winRT/WaitImpl.h \ cpp/src/platform/windows/DNSImpl.cpp \ cpp/src/platform/windows/DNSImpl.h \ cpp/src/platform/windows/EventImpl.cpp \ cpp/src/platform/windows/EventImpl.h \ cpp/src/platform/windows/FileOpsImpl.cpp \ cpp/src/platform/windows/FileOpsImpl.h \ cpp/src/platform/windows/LogImpl.cpp \ cpp/src/platform/windows/LogImpl.h \ cpp/src/platform/windows/MutexImpl.cpp \ cpp/src/platform/windows/MutexImpl.h \ cpp/src/platform/windows/SerialControllerImpl.cpp \ cpp/src/platform/windows/SerialControllerImpl.h \ cpp/src/platform/windows/ThreadImpl.cpp \ cpp/src/platform/windows/ThreadImpl.h \ cpp/src/platform/windows/TimeStampImpl.cpp \ cpp/src/platform/windows/TimeStampImpl.h \ cpp/src/platform/windows/WaitImpl.cpp \ cpp/src/platform/windows/WaitImpl.h \ cpp/src/value_classes/Value.cpp \ cpp/src/value_classes/Value.h \ cpp/src/value_classes/ValueBitSet.cpp \ cpp/src/value_classes/ValueBitSet.h \ cpp/src/value_classes/ValueBool.cpp \ cpp/src/value_classes/ValueBool.h \ cpp/src/value_classes/ValueButton.cpp \ cpp/src/value_classes/ValueButton.h \ cpp/src/value_classes/ValueByte.cpp \ cpp/src/value_classes/ValueByte.h \ cpp/src/value_classes/ValueDecimal.cpp \ cpp/src/value_classes/ValueDecimal.h \ cpp/src/value_classes/ValueID.cpp \ cpp/src/value_classes/ValueID.h \ cpp/src/value_classes/ValueInt.cpp \ cpp/src/value_classes/ValueInt.h \ cpp/src/value_classes/ValueList.cpp \ cpp/src/value_classes/ValueList.h \ cpp/src/value_classes/ValueRaw.cpp \ cpp/src/value_classes/ValueRaw.h \ cpp/src/value_classes/ValueSchedule.cpp \ cpp/src/value_classes/ValueSchedule.h \ cpp/src/value_classes/ValueShort.cpp \ cpp/src/value_classes/ValueShort.h \ cpp/src/value_classes/ValueStore.cpp \ cpp/src/value_classes/ValueStore.h \ cpp/src/value_classes/ValueString.cpp \ cpp/src/value_classes/ValueString.h \ cpp/test/Makefile \ cpp/test/ValueID_test.cpp \ cpp/test/include/gtest/gtest-death-test.h \ cpp/test/include/gtest/gtest-matchers.h \ cpp/test/include/gtest/gtest-message.h \ cpp/test/include/gtest/gtest-param-test.h \ cpp/test/include/gtest/gtest-printers.h \ cpp/test/include/gtest/gtest-spi.h \ cpp/test/include/gtest/gtest-test-part.h \ cpp/test/include/gtest/gtest-typed-test.h \ cpp/test/include/gtest/gtest.h \ cpp/test/include/gtest/gtest_pred_impl.h \ cpp/test/include/gtest/gtest_prod.h \ cpp/test/include/gtest/internal/custom/README.md \ cpp/test/include/gtest/internal/custom/gtest-port.h \ cpp/test/include/gtest/internal/custom/gtest-printers.h \ cpp/test/include/gtest/internal/custom/gtest.h \ cpp/test/include/gtest/internal/gtest-death-test-internal.h \ cpp/test/include/gtest/internal/gtest-filepath.h \ cpp/test/include/gtest/internal/gtest-internal.h \ cpp/test/include/gtest/internal/gtest-param-util.h \ cpp/test/include/gtest/internal/gtest-port-arch.h \ cpp/test/include/gtest/internal/gtest-port.h \ cpp/test/include/gtest/internal/gtest-string.h \ cpp/test/include/gtest/internal/gtest-type-util.h \ cpp/test/src/gtest-death-test.cc \ cpp/test/src/gtest-filepath.cc \ cpp/test/src/gtest-internal-inl.h \ cpp/test/src/gtest-matchers.cc \ cpp/test/src/gtest-port.cc \ cpp/test/src/gtest-printers.cc \ cpp/test/src/gtest-test-part.cc \ cpp/test/src/gtest-typed-test.cc \ cpp/test/src/gtest.cc \ cpp/test/src/gtest_main.cc \ cpp/tinyxml/Makefile \ cpp/tinyxml/tinystr.cpp \ cpp/tinyxml/tinystr.h \ cpp/tinyxml/tinyxml.cpp \ cpp/tinyxml/tinyxml.h \ cpp/tinyxml/tinyxmlerror.cpp \ cpp/tinyxml/tinyxmlparser.cpp \ debian/MinOZW.1 \ debian/changelog \ debian/compat \ debian/control \ debian/copyright \ debian/format \ debian/libopenzwave-doc.doc-base \ debian/libopenzwave-doc.install \ debian/libopenzwave-doc.lintian-overrides-not-needed \ debian/libopenzwave1.6-dev.install \ debian/libopenzwave1.6.install \ debian/libopenzwave1.6.lintian-overrides \ debian/libopenzwave1.6.postinst \ debian/openzwave.dsc \ debian/openzwave.install \ debian/openzwave.manpages \ debian/patches/hardening.patch \ debian/patches/series \ debian/patches/spelling.patch \ debian/rules \ debian/shlibs.libopenzwave1.6 \ debian/source/format \ debian/version-increment.sh \ debian/watch \ dist.mk \ dist/libopenzwave.changes \ dist/openzwave.spec \ dist/openzwave.spec.in \ distfiles.mk \ docs/ChangeLog.old \ docs/Doxyfile.in \ docs/default.htm \ docs/general/DoxygenStepByStep.html \ docs/general/GettingHelp.html \ docs/general/Index.htm \ docs/general/MakingDocumentation.html \ docs/general/Notifications.html \ docs/images+css/Doxywizard1.JPG \ docs/images+css/Doxywizard2.JPG \ docs/images+css/Doxywizard3.JPG \ docs/images+css/Doxywizard4.JPG \ docs/images+css/Doxywizard5.JPG \ docs/images+css/OpenZWave.css \ docs/images+css/image003.gif \ docs/images+css/zwalliance_250x100.jpg \ licenses/Apache-License-2.0.txt \ licenses/gpl.txt \ licenses/lgpl.txt \ licenses/license.txt \ makedist \ tools/imagedownload.pl \ cpp/src/vers.cpp openzwave-1.6.1914/dist/0000777000175200017520000000000014032143201011735 500000000000000openzwave-1.6.1914/dist/openzwave.spec.in0000644000175200017520000001262114032142455015164 00000000000000%if 0%{?is_opensuse} %define __global_ldflags %{nil} %endif Name: openzwave Version: @VERSION@ Release: 1.0%{?dist} Summary: Sample Executables for OpenZWave URL: http://www.openzwave.net %if 0%{?suse_version} > 0 License: LGPL-3.0+ %else License: LGPLv3+ %endif Source0: http://old.openzwave.com/downloads/openzwave-%{version}.tar.gz BuildRequires: gcc-c++ BuildRequires: doxygen BuildRequires: graphviz BuildRequires: tinyxml-devel %if 0%{?fedora} BuildRequires: systemd-devel pkgconfig %endif %if 0%{?is_opensuse} BuildRequires: systemd-devel pkg-config %endif %description OpenZWave is an open-source, cross-platform library designed to enable anyone to add support for Z-Wave home-automation devices to their applications, without requiring any in depth knowledge of the Z-Wave protocol. %package -n libopenzwave Summary: Library to access Z-Wave interfaces %if 0%{?is_opensuse} Requires(pre): shadow %else Requires(pre): shadow-utils %endif %description -n libopenzwave OpenZWave is an open-source, cross-platform library designed to enable anyone to add support for Z-Wave home-automation devices to their applications, without requiring any in depth knowledge of the Z-Wave protocol. %package -n libopenzwave-devel Summary: Open-ZWave header files Requires: libopenzwave%{?_isa} = %{version}-%{release} %description -n libopenzwave-devel Header files needed when you want to compile your own applications using openzwave %package -n libopenzwave-devel-doc Summary: Open-ZWave API documentation files Requires: libopenzwave-devel%{?_isa} = %{version}-%{release} %description -n libopenzwave-devel-doc API documentation files needed when you want to compile your own applications using openzwave %prep %setup -q -n openzwave-%{version} %build major_ver=$(echo %{version} | awk -F \. {'print $1'}) minor_ver=$(echo %{version} | awk -F \. {'print $2'}) revision=$(echo %{version} | awk -F \. {'print $3'}) CPPFLAGS="%{optflags} -Wformat" LDFLAGS="%{__global_ldflags}" USE_HID=0 USE_BI_TXML=0 VERSION_MAJ=$major_ver VERSION_MIN=$minor_ver VERSION_REV=$revision PREFIX=/usr sysconfdir=%{_sysconfdir}/openzwave/ includedir=%{_includedir} docdir=%{_defaultdocdir}/openzwave-%{version} instlibdir=%{_libdir} make %{?_smp_mflags} %install rm -rf %{buildroot}/* major_ver=$(echo %{version} | awk -F \. {'print $1'}) minor_ver=$(echo %{version} | awk -F \. {'print $2'}) revision=$(echo %{version} | awk -F \. {'print $3'}) mkdir -p %{buildroot}/%{_bindir} mkdir -p %{buildroot}/%{_libdir} mkdir -p %{buildroot}/%{_defaultdocdir}/openzwave-%{version}/ mkdir -p %{buildroot}/%{_sysconfdir}/ mkdir -p %{buildroot}/%{_includedir}/openzwave/ DESTDIR=%{buildroot} USE_HID=0 USE_BI_TXML=0 VERSION_MAJ=$major_ver VERSION_MIN=$minor_ver VERSION_REV=$revision PREFIX=/usr sysconfdir=%{_sysconfdir}/openzwave/ includedir=%{_includedir}/openzwave/ docdir=%{_defaultdocdir}/openzwave-%{version} instlibdir=%{_libdir} make install rm %{buildroot}%{_defaultdocdir}/openzwave-%{version}/Doxyfile.in rm -rf %{buildroot}%{_defaultdocdir}/openzwave-%{version}/ChangeLog.old rm -rf %{buildroot}%{_defaultdocdir}/openzwave-%{version}/html/ rm -rf %{buildroot}%{_defaultdocdir}/openzwave-%{version}/default.htm rm -rf %{buildroot}%{_defaultdocdir}/openzwave-%{version}/general/ rm -rf %{buildroot}%{_defaultdocdir}/openzwave-%{version}/images+css/ rm -rf %{buildroot}%{_defaultdocdir}/openzwave-%{version}/api/ %files %{_bindir}/MinOZW %files -n libopenzwave %license LICENSE %doc docs/default.htm docs/general/ docs/images+css/ %{_libdir}/libopenzwave.so.* %defattr(664, root, zwave, 775) %dir %{_sysconfdir}/openzwave/ %config(noreplace) %{_sysconfdir}/openzwave/* %files -n libopenzwave-devel %{_bindir}/ozw_config %{_includedir}/openzwave/ %{_libdir}/libopenzwave.so %{_libdir}/pkgconfig/libopenzwave.pc %files -n libopenzwave-devel-doc %doc docs/api/ %post -n libopenzwave /sbin/ldconfig %post -n libopenzwave-devel /sbin/ldconfig %postun -n libopenzwave /sbin/ldconfig %pre -n libopenzwave getent group zwave >/dev/null || groupadd -f -r zwave %changelog * Wed May 08 2019 Justin Hammond - @VERSION@ - Update to new release of OpenZwave - 1.6 * Fri Feb 01 2019 Fedora Release Engineering - 1.5.0-0.20180624git1e36dcc.0 - Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild * Wed Jul 18 2018 Michael Cronenworth - 1.5.0-0.20180623git1e36dcc.0 - Update to 20180623 git checkout to fix FTBFS - Drop patches that revert BARRIER_OPERATOR support and use newer version * Fri Jul 13 2018 Fedora Release Engineering - 1.5.0-0.20171212gitc3b0e31.0 - Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild * Mon Feb 26 2018 Michael Cronenworth - 1.5.0-0.20171211gitc3b0e31.0 - Update to 20171211 git checkout - Revert new BARRIER_OPERATOR support and use older version * Thu Feb 08 2018 Fedora Release Engineering - 1.5.0-0.20170725gitde1c0e6 - Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild * Mon Jul 31 2017 Michael Cronenworth - 1.5.0-0.20170724gitde1c0e6 - Update to a git checkout, execeptions patch is upstream - Fixes crashing issues with domoticz * Thu Jul 27 2017 Fedora Release Engineering - 1.4.164-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild * Wed Jul 12 2017 Michael Cronenworth - 1.4.164-1 - Initial spec openzwave-1.6.1914/dist/openzwave.spec0000644000175200017520000001261714032142711014557 00000000000000%if 0%{?is_opensuse} %define __global_ldflags %{nil} %endif Name: openzwave Version: 1.6.1914 Release: 1.0%{?dist} Summary: Sample Executables for OpenZWave URL: http://www.openzwave.net %if 0%{?suse_version} > 0 License: LGPL-3.0+ %else License: LGPLv3+ %endif Source0: http://old.openzwave.com/downloads/openzwave-%{version}.tar.gz BuildRequires: gcc-c++ BuildRequires: doxygen BuildRequires: graphviz BuildRequires: tinyxml-devel %if 0%{?fedora} BuildRequires: systemd-devel pkgconfig %endif %if 0%{?is_opensuse} BuildRequires: systemd-devel pkg-config %endif %description OpenZWave is an open-source, cross-platform library designed to enable anyone to add support for Z-Wave home-automation devices to their applications, without requiring any in depth knowledge of the Z-Wave protocol. %package -n libopenzwave Summary: Library to access Z-Wave interfaces %if 0%{?is_opensuse} Requires(pre): shadow %else Requires(pre): shadow-utils %endif %description -n libopenzwave OpenZWave is an open-source, cross-platform library designed to enable anyone to add support for Z-Wave home-automation devices to their applications, without requiring any in depth knowledge of the Z-Wave protocol. %package -n libopenzwave-devel Summary: Open-ZWave header files Requires: libopenzwave%{?_isa} = %{version}-%{release} %description -n libopenzwave-devel Header files needed when you want to compile your own applications using openzwave %package -n libopenzwave-devel-doc Summary: Open-ZWave API documentation files Requires: libopenzwave-devel%{?_isa} = %{version}-%{release} %description -n libopenzwave-devel-doc API documentation files needed when you want to compile your own applications using openzwave %prep %setup -q -n openzwave-%{version} %build major_ver=$(echo %{version} | awk -F \. {'print $1'}) minor_ver=$(echo %{version} | awk -F \. {'print $2'}) revision=$(echo %{version} | awk -F \. {'print $3'}) CPPFLAGS="%{optflags} -Wformat" LDFLAGS="%{__global_ldflags}" USE_HID=0 USE_BI_TXML=0 VERSION_MAJ=$major_ver VERSION_MIN=$minor_ver VERSION_REV=$revision PREFIX=/usr sysconfdir=%{_sysconfdir}/openzwave/ includedir=%{_includedir} docdir=%{_defaultdocdir}/openzwave-%{version} instlibdir=%{_libdir} make %{?_smp_mflags} %install rm -rf %{buildroot}/* major_ver=$(echo %{version} | awk -F \. {'print $1'}) minor_ver=$(echo %{version} | awk -F \. {'print $2'}) revision=$(echo %{version} | awk -F \. {'print $3'}) mkdir -p %{buildroot}/%{_bindir} mkdir -p %{buildroot}/%{_libdir} mkdir -p %{buildroot}/%{_defaultdocdir}/openzwave-%{version}/ mkdir -p %{buildroot}/%{_sysconfdir}/ mkdir -p %{buildroot}/%{_includedir}/openzwave/ DESTDIR=%{buildroot} USE_HID=0 USE_BI_TXML=0 VERSION_MAJ=$major_ver VERSION_MIN=$minor_ver VERSION_REV=$revision PREFIX=/usr sysconfdir=%{_sysconfdir}/openzwave/ includedir=%{_includedir}/openzwave/ docdir=%{_defaultdocdir}/openzwave-%{version} instlibdir=%{_libdir} make install rm %{buildroot}%{_defaultdocdir}/openzwave-%{version}/Doxyfile.in rm -rf %{buildroot}%{_defaultdocdir}/openzwave-%{version}/ChangeLog.old rm -rf %{buildroot}%{_defaultdocdir}/openzwave-%{version}/html/ rm -rf %{buildroot}%{_defaultdocdir}/openzwave-%{version}/default.htm rm -rf %{buildroot}%{_defaultdocdir}/openzwave-%{version}/general/ rm -rf %{buildroot}%{_defaultdocdir}/openzwave-%{version}/images+css/ rm -rf %{buildroot}%{_defaultdocdir}/openzwave-%{version}/api/ %files %{_bindir}/MinOZW %files -n libopenzwave %license LICENSE %doc docs/default.htm docs/general/ docs/images+css/ %{_libdir}/libopenzwave.so.* %defattr(664, root, zwave, 775) %dir %{_sysconfdir}/openzwave/ %config(noreplace) %{_sysconfdir}/openzwave/* %files -n libopenzwave-devel %{_bindir}/ozw_config %{_includedir}/openzwave/ %{_libdir}/libopenzwave.so %{_libdir}/pkgconfig/libopenzwave.pc %files -n libopenzwave-devel-doc %doc docs/api/ %post -n libopenzwave /sbin/ldconfig %post -n libopenzwave-devel /sbin/ldconfig %postun -n libopenzwave /sbin/ldconfig %pre -n libopenzwave getent group zwave >/dev/null || groupadd -f -r zwave %changelog * Wed May 08 2019 Justin Hammond - 1.6.1914 - Update to new release of OpenZwave - 1.6 * Fri Feb 01 2019 Fedora Release Engineering - 1.5.0-0.20180624git1e36dcc.0 - Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild * Wed Jul 18 2018 Michael Cronenworth - 1.5.0-0.20180623git1e36dcc.0 - Update to 20180623 git checkout to fix FTBFS - Drop patches that revert BARRIER_OPERATOR support and use newer version * Fri Jul 13 2018 Fedora Release Engineering - 1.5.0-0.20171212gitc3b0e31.0 - Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild * Mon Feb 26 2018 Michael Cronenworth - 1.5.0-0.20171211gitc3b0e31.0 - Update to 20171211 git checkout - Revert new BARRIER_OPERATOR support and use older version * Thu Feb 08 2018 Fedora Release Engineering - 1.5.0-0.20170725gitde1c0e6 - Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild * Mon Jul 31 2017 Michael Cronenworth - 1.5.0-0.20170724gitde1c0e6 - Update to a git checkout, execeptions patch is upstream - Fixes crashing issues with domoticz * Thu Jul 27 2017 Fedora Release Engineering - 1.4.164-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild * Wed Jul 12 2017 Michael Cronenworth - 1.4.164-1 - Initial spec openzwave-1.6.1914/dist/libopenzwave.changes0000644000175200017520000000105014032142455015716 00000000000000------------------------------------------------------------------- Fri Jun 21 11:16:35 UTC 2013 - justin@dynam.ac Add MultiInstance.patch to handle buggy devices such as Vitrum that send wrong commands ------------------------------------------------------------------- Fri Jun 21 08:02:24 UTC 2013 - justin@dynam.ac Remove debug output from RPM installation commands- ------------------------------------------------------------------- Fri Jun 21 06:46:23 UTC 2013 - justin@dynam.ac Initial RPM Packages that should work for all Platforms - openzwave-1.6.1914/BSDmakefile0000644000175200017520000000010714032142454012746 00000000000000all: .DEFAULT .DEFAULT: gmake ${.MAKEFLAGS} ${.TARGETS} .PHONY: all openzwave-1.6.1914/dist.mk0000644000175200017520000001056414032142455012222 00000000000000# dist.mk - make dist # Lots of this is taken directly from Automake. # User can override this. # Valid values are gzip bzip2 zip # Automake supplies compress and shar as well, but I suspect those are # obsolete and I have left them out. #DIST_FORMATS ?= bzip2 # Fun uses of wildcard. Some of these are probably bogus. # install-sh -- should be legacy, probably, but configure looks for it. # FIXME: common files, quagmire files, texinfo ... anything else? # DISTFILES = $(quagmire/dist_sources) $(quagmire/dist-files) $(EXTRA_DIST) distdir = openzwave-$(VERSION).$(VERSION_REV) #$(if $(PACKAGE_TARNAME),$(if $(PACKAGE_VERSION),$(PACKAGE_TARNAME)-$(PACKAGE_VERSION),$(error PACKAGE_VERSION not defined)),$(error PACKAGE_TARNAME not defined)) am__remove_distdir = \ { test ! -d $(distdir) \ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -fr $(distdir); }; } # FIXME: gnits-like NEWS checking distdir: cpp/src/vers.cpp $(am__remove_distdir) mkdir -p $(distdir) @list='$(DISTFILES)'; for file in $$list; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ mkdir -p `dirname $(distdir)/$$file`; \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r $(distdir) .PHONY: distdir GZIP_ENV = --best # FIXME: gnu tar dependency dist-gzip: distdir tar chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz .PHONY: dist-gzip # FIXME: gnu tar dependency dist-bzip2: distdir tar chof - $(distdir) | bzip2 -9 -c >$(distdir).tar.bz2 .PHONY: dist-bzip2 dist-zip: distdir rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) .PHONY: dist-zip dist: $(addprefix dist-,$(DIST_FORMATS)) $(if $(DIST_FORMATS),,$(error DIST_FORMATS is empty)) $(am__remove_distdir) .PHONY: dist distcheck-hook: echo $(BUILDDIR) mkdir -p ../$(BUILDDIR)/cpp/build/ mkdir -p ../$(BUILDDIR)/cpp/examples/MinOZW/ cp Makefile ../$(BUILDDIR) cp cpp/build/support.mk ../$(BUILDDIR)/cpp/build/ cp cpp/build/Makefile ../$(BUILDDIR)/cpp/build/ cp dist.mk ../$(BUILDDIR) cp distfiles.mk ../$(BUILDDIR) cp cpp/examples/MinOZW/Makefile ../$(BUILDDIR)/cpp/examples/MinOZW/ .PHONY: distcheck-hook DISTCHECK_CONFIGURE_FLAGS ?= # FIXME: should 'make dvi' in the check. should copy over commentary # from automake. # FIXME: support DIST_ARCHIVES stuff from automake as well distcheck: $(MAKE) DIST_FORMATS=bzip2 dist bunzip2 -c $(distdir).tar.bz2 | tar xf - chmod -R a-w $(distdir); chmod a+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) dc_install_base=`cd $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && $(MAKE) distcheck-hook \ && cd $(distdir)/_build \ && $(MAKE) -C ../ \ && chmod -R a-w "$$dc_install_base" \ && rm -rf "$$dc_destdir" \ && $(MAKE) DIST_FORMATS=bzip2 dist \ && rm -rf $(distdir).tar.bz2 \ && $(MAKE) distcleancheck $(am__remove_distdir) @(echo "$(distdir).tar.bz2 archive ready for distribution" .PHONY: distcheck distuninstallcheck_listfiles = find . -type f -print distuninstallcheck: @cd $(distuninstallcheck_dir) \ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 .PHONY: distuninstallcheck distcleancheck_listfiles = find . -type f -print distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 .PHONY: distcleancheck openzwave-1.6.1914/cpp/0000777000175200017520000000000014032143201011554 500000000000000openzwave-1.6.1914/cpp/build/0000777000175200017520000000000014032143177012667 500000000000000openzwave-1.6.1914/cpp/build/testconfigversions.cfg0000644000175200017520000110205514032143170017217 00000000000000%versiondb = ( 'config/2gig/ct100.xml' => { 'Revision' => 6, 'md5' => '4fe343964064e151aac9e1b2ce76574da4b2d1ba9e9cb86b7986a27e611ab5d88a7df0005f4d04b43c39aa64e08c299ac077f9f6c85cfe5af5b46c4f3c622e77' }, 'config/2gig/ct101.xml' => { 'Revision' => 2, 'md5' => 'b2c96148fd6c97c1e7a0d07126d2a7a497b49b56105e00d311dcf885d204f44bbd0673a15b0041c894098cca56b8ccfdcb072946557bbd64877552beeb0e21c0' }, 'config/2gig/ct200.xml' => { 'Revision' => 1, 'md5' => '7822e83cf1aa215d3ccad4d0103cc72a7a81c9a4501a068572bc65d3e7dd3631c3801dc3d554a4677d6b8b57758e42946b9cd2a5c614318c085f4ef6ade6d947' }, 'config/2gig/ct30.xml' => { 'Revision' => 4, 'md5' => '783218e85cb8eadbb47fd3dfd1d9dc60ccd7f1bf63fd585d8fd1701cab9f3460b78afd48c30ff88bd1e6754e0f215a1f607e6a8d838b92b25fe8dad5c106ea9f' }, 'config/2gig/ct32.xml' => { 'Revision' => 6, 'md5' => '3fc0dc93e116998e2d5d3e33d26dc182611a8c0c0ca031503b66fa45e88d39a6be0d53bdc0d7efcb6f371338ae70c393d5378f1e06dc58ec8b1ebf3fe17d44e2' }, 'config/2gig/ct50e.xml' => { 'Revision' => 2, 'md5' => '9c53edcf0c9718202fb57582c4f292dbd8d754b90c3bb06680aa4a03f7d981be96636035134c680f33d99ab5b3341698a05f8f70652e2489715606287f8ca221' }, 'config/2gig/ct80.xml' => { 'Revision' => 2, 'md5' => '8d38a290a107a1777a2b4d319ae9a393ed0e2b44ec2720e9ff778088a1bc9a417d3a128ef557b9ad568246754bcdd41c19c90c3cb6775a48e16544f787ed54b7' }, 'config/BeNext/1poleswitch.xml' => { 'Revision' => 2, 'md5' => '3b76f4656bc5d544507eec34e0fff51472a363b55d07b10ec06208d46be9bb8ced3f4baed01cd4ed97fd5f9187048eef62963c95c03134b2104f158b09592cdb' }, 'config/BeNext/2poleswitch.xml' => { 'Revision' => 2, 'md5' => '85a950d189684ef3797d9b043572e82f9661a29af90dff49a62a6e8e0672952442b13f113e6b9dfe69ac19141addd097e6664e8f02006f553960cc9a3add3860' }, 'config/BeNext/AlarmSound.xml' => { 'Revision' => 4, 'md5' => '8aa7047af5db54a1a47792a5a5cc63148f83a6b7dbe9e592a8a99bf5ebac4313528ec089346aea61438ff7ecb420273838f11ecd7fed7b97092b5f5eef97463b' }, 'config/BeNext/BuiltinDimmer.xml' => { 'Revision' => 2, 'md5' => '748984dd23e65d0e9ba5e3a392cc3d85ad892d2ba1d19cfa7dcf73097dcf03aa0cc64b5a424619d0a04c6533a448698d81e3c6b0ace5fe1ced9e0deb08542da2' }, 'config/BeNext/DoorSensor.xml' => { 'Revision' => 4, 'md5' => '8ebfe57d88e12b732d66a18dd5c1bdfe31eda56ba4a174f09a7ccfae12eae2e378c74c4050d3b59b3a3323e312c7286fa80ef25406c721d0bace170c30c6ee9d' }, 'config/BeNext/EnergySwitch.xml' => { 'Revision' => 2, 'md5' => '5f21579b7171abadad0c495552ac171378e4530f0d54ec0c1440e1b019288234e6ebde6c210a132f355435959c3082ead05a559c8277b1dd7e01513c60b0c970' }, 'config/BeNext/HeatingControl.xml' => { 'Revision' => 4, 'md5' => 'd1f4f2efc1544b406b40cd4a8d7d45ab2f15cacbb1f35b484a4b3dffd2d18beae46abf14970993d246799fb2df26109893b6f824304fede8ac38d2fb2c51fc16' }, 'config/BeNext/Molite.xml' => { 'Revision' => 6, 'md5' => '45ba6a2c4525a2609e843cf21e186762f30f9d4c0e1d3ce57da5685c55127df5a66987ea00c44364a543be57a30025c3d125e091bb03ea06e1528adf54325611' }, 'config/BeNext/P1dongle.xml' => { 'Revision' => 4, 'md5' => '8c0e0f218bb6fcece9001601875ec97de1db64456c1c1126c539499dbf73539afdb8fe7549ebfbc186158f4c246a30e523a9905962eb195cc2ad7a7605acf095' }, 'config/BeNext/PanicButton.xml' => { 'Revision' => 3, 'md5' => 'a28d1e807284459bc308026d21eb66b83b5f010ad8d155d1c729a1c1106389ee9f591ba7b633097f495d33bed8559e79aa8db822ac0ccb7f09ee4fd9705716a2' }, 'config/BeNext/PanicWatch.xml' => { 'Revision' => 2, 'md5' => 'ac6e5f893d44d59a9d583ac9cdd8d3ea8a96a9f27b3ad288cc87a9634c00e68339bfeac1e855cba5a94b2b6e0f1b39fe38240d0911e78d9d8374f2368b260ee5' }, 'config/BeNext/PluginDimmer.xml' => { 'Revision' => 2, 'md5' => '3f2f85b719e0ca2f87f0e95eb3bf1968de6416a369fb3eded5ee92f97ad8935ba4a76585b163c41778707ae1af73e6919230c93614c4e7d049e388d864773157' }, 'config/BeNext/SceneController.xml' => { 'Revision' => 2, 'md5' => 'f8a6cd6c2b4a7dcca25543b18a26301f0fb717671a779e937988428da8d40bb957af81c8e3011adef397ed3416a89c8d910f6c374b9ecc0e1968e88a3f0a3723' }, 'config/BeNext/TagReader.xml' => { 'Revision' => 5, 'md5' => '86e9af8a741a2a97cef4a2fbe8b46b558fd9903fa845cc6a09f3002b6e8d8593fbf1d89b9bd899a4cf5749411af35141ebb1fe7ddaad965eb4b8dbe49172bf42' }, 'config/BeNext/TagReader500.xml' => { 'Revision' => 5, 'md5' => 'e67743d1ac01fe4c07366f15806a7209a2ad458411b7a4c3dbfe0dc2e350c87b39dd72bcd7d676656d85b4fc13771aba34cf7690fc8eec0bbde116e19ca90a0e' }, 'config/BeNext/mydisplay.xml' => { 'Revision' => 1, 'md5' => '5930fbe8cce26fd6dd82e44ab57aec2db4cc1d0e2d2715af28cad9f35ca3b022fd94c5e3d2c1ab14b127a75886da4f295fb16ff4cfe5f5f5b985a02eefc4f009' }, 'config/BeNext/mygate.xml' => { 'Revision' => 1, 'md5' => 'eb39290e2085eb7493a88fba0f53782a588539d81810442fd1575d5065263e24b23e4711a2fd5df0bf7cae7ff380c605d785399e87aa658cac3f155a1d2ae667' }, 'config/Localization.xml' => { 'Revision' => 12, 'md5' => '3947ce48694ec51a18c15b5ffe9b02906df9929c44fd5ba2c4d3a860ea1f125e3255b7cf85f8a1be7334a5335b8f3615429a1a0a3fdef78157c00935eaa98a5b' }, 'config/NotificationCCTypes.xml' => { 'Revision' => 11, 'md5' => '219e944370bea857e14dc25789bca29dde4a65f72b9d9b39a9ab187437cf80c70a876b399a45fd89f90b4da27f2ce3359f61f90d5605c4d53a14effb3ca28343' }, 'config/SensorMultiLevelCCTypes.xml' => { 'Revision' => 4, 'md5' => '36aee27cf7888627f6d7a35604f782976d043aceda82cf1c90a830e19e297fae5ad7ac36de480a4c36af71c5ad94a5c7db52b2817cfc84cb760fcbb83bcba6f8' }, 'config/abus/SHRM10000.xml' => { 'Revision' => 1, 'md5' => '65df614d199c1b62a17a141801d6723803af54ecb5fd0fd591a731ef8a80695f61532a484469dad55c100373d188816bb1642cb48f5dda8e1e9e81c40edfa66f' }, 'config/act/lfm20.xml' => { 'Revision' => 2, 'md5' => 'f4c1366e3f7ee171137d2688de970a6e4ae2d4939c22267eda205405ce5e397c731cda516bd76225bab830e0c4cb998a4da44e249d468e88593a0151c41157eb' }, 'config/act/zdm230.xml' => { 'Revision' => 3, 'md5' => '32b87c4f243f83783ca721429e0722ec0b8e502996dd8cba17afccab11a6d73c4b5b4b4e6fbf11146e6998d1ed714565a6ec3461ad6b0a9ca05e28e65645cb06' }, 'config/act/zdp100.xml' => { 'Revision' => 1, 'md5' => '326fce3252167b44133df2be23528b4aca1586c30fc4c028abda4eb8725d0a1f8705f5a17369ad3303de4684b713c638b1b7e50b0aa2d4e8867d6d0c8027068a' }, 'config/act/zdw103.xml' => { 'Revision' => 2, 'md5' => 'd62d1c261b6d4b002cf4897f486c11959c877c46b7f8e40b5d3d36161e394eb9a88a45ca04b6726fae366adef1a30cd508dd2c9c58da282caf48e29762798591' }, 'config/act/zdw232.xml' => { 'Revision' => 3, 'md5' => '11bce1049e1a2d8e6404d7bed073cb7621ed522d24f4cb5418399ed2f33b614d928cab6eb856722de1cc4a251d7ec0fe78b3a3cf3076c4b074dc344dee8a3da7' }, 'config/act/zir010.xml' => { 'Revision' => 5, 'md5' => 'baa9da225651ef1a50f889aed86ac6f136b1fc54bbed8c43326559eaf65521b4b098e51c4f870c41c2da057b482a86969095daac30aad0667225b10b5498721d' }, 'config/act/zrm230.xml' => { 'Revision' => 1, 'md5' => '91e81981210fcc70fb877270b991ca31fce51b9c7b6b572b7db02b28ad033f30173803e9aead08998dd5adbe90a94af6fae55bad09b50850d71f133615223c69' }, 'config/act/zrp100.xml' => { 'Revision' => 3, 'md5' => '9ea2450a9c6bb7f1b871d020a04abf8c8c1907884b93bb2c8433226d5ee3fc5915022b9229c040c65e9ec34387f1ceb6590f6299d08d5ca76e6a4f6b94d0508e' }, 'config/act/zrp110.xml' => { 'Revision' => 1, 'md5' => '53777acb25cebd3379f8d7a06057d6fe0b52354e71679e105e2a4ff66aa046a8b4a9cd853c3ea7249a87d3dfec36d015cf18a75a0a416a5c60e1dc14ef81464d' }, 'config/act/zrw103.xml' => { 'Revision' => 3, 'md5' => '56be44ee933cb0e4fcd59758fb49af06aadf0536c7a372ba665037092b628c5888783b45411aa4c1cd92ac99ba450b0130955598f8846b534598864f333d1db7' }, 'config/act/zrw230.xml' => { 'Revision' => 1, 'md5' => '8396a52fa0dda4e5d29b7a8a218f2fc07c8fdf734c43d916e9db558216450d435660aa7a3f0a432801108541095634dfb193720ac2fe005d895e602734dc121a' }, 'config/aeotec/dsa03202.xml' => { 'Revision' => 5, 'md5' => '0979e94319ead0dac6c7a9cdd7907b40202785de948535b5bb73ae2cd46c4d29ad97fd5d363dca65a6b080c0a9ede2390d015db935faaffeec84987f9e4eedfa' }, 'config/aeotec/dsa22.xml' => { 'Revision' => 1, 'md5' => '3ddb4ae3f695f1952b10592611eb98cc4c261ef4224cd681344d462283bb4732bc46bf103048708cbc43cd5fd5d9668148aa60d242dc35664973b555f14520d3' }, 'config/aeotec/dsa38.xml' => { 'Revision' => 4, 'md5' => 'f174aec88220486aa47af5d8fead4efbdf26c1ccdd8f5a6d6bc18609350d859589fdced0cfb1a07a949c3a227fbc2807ccd6328e74ee2d3368cf6d7e87ceed8d' }, 'config/aeotec/dsb04100.xml' => { 'Revision' => 3, 'md5' => '20fd36afaf508a5224785de53c4a5fbd252cd07b37ebc12fea5393c90fb3a3191bc60f2ef712d2e32a3236e2b435b5e2e38c10ed4172eb2970fa88f9da96caeb' }, 'config/aeotec/dsb05.xml' => { 'Revision' => 5, 'md5' => '7937693b67248dd6edfb79483fb99d1bc6dfedac63c4b143ecbb775435ef2bdf4676c885a5f4796e0ff0a7af8124b21c6bdf4015d2fdb9db9ab7699d4b7023be' }, 'config/aeotec/dsb09104.xml' => { 'Revision' => 4, 'md5' => 'fb7263fd5cfd5c64567cd8740930ae30a0f2529f24c851c2f98c851ab8f1e643f187a3ed345567300ce4dcc7f6137f9c6894ee07aa58959c0aed5401771451c6' }, 'config/aeotec/dsb28-zweu.xml' => { 'Revision' => 3, 'md5' => '378e85fb9fd12363865dc1fea1be23ea2d3699896e178c4a9ed32a0346c5aacec4ea25eda557365bd93373734bd389dc9278bbcfdceed4b1fdc0c518998c446a' }, 'config/aeotec/dsb28.xml' => { 'Revision' => 2, 'md5' => 'cf1a42993bccbece425f82a4c38b2ea9afc25c815c20e9d6910616007135e15df7e542dc3ec025d040273f2c0056709d20819d6171ea72dab452b38ff94c4837' }, 'config/aeotec/dsb29.xml' => { 'Revision' => 5, 'md5' => '8cf1f981a5cf9607e560d3b3f3b23ee9145a16361fb97dbad6d32fb3428167bf73d76562942092eaab26f6970d6ec943e2779d434ed188d8a3d7531a445e089b' }, 'config/aeotec/dsb45.xml' => { 'Revision' => 2, 'md5' => '16f6b34bcf084cd4febdae147093a2456f65bb5a999c98eb19006664a1e2d30dbb6c76f785d340da40bb1abace3161243f53669e109102b80c30b92f311839b6' }, 'config/aeotec/dsb54.xml' => { 'Revision' => 2, 'md5' => 'f7be82de3668551d30335226875e9f899b80c2f9ace847f8391586b77856828f1737992b711fea1dfcdf198acc32468c695ef00a7e37f1a308ef6fb6950e57ac' }, 'config/aeotec/dsc06106.xml' => { 'Revision' => 2, 'md5' => '052dee67375c3d6a155197019da3dee753ccd485d419e85e4071ee5bd43cde8f79e397df4c3b951a19c5f13059a2ff3091f8ae82dfe82b406a6ab88f3d0fa5c8' }, 'config/aeotec/dsc08101.xml' => { 'Revision' => 1, 'md5' => '09e3b194689ed0e6299999897f6abf295ec66ec3c63bc58cc04745ef0c0bb64c378cbcd828609741241aa3fb822baec07435a3dcd5efb7575e390be780e010c9' }, 'config/aeotec/dsc10.xml' => { 'Revision' => 2, 'md5' => 'a408eb0f1de9aefebd3b47fbb18ac37d6cdecb279379d33a009f8625eb398eeb15dcaa70135ea32e6097ec08e796b5e47a40552ccba49b73fac9948fc3caca5b' }, 'config/aeotec/dsc11.xml' => { 'Revision' => 2, 'md5' => '442bf8b1c4eb469d23faf31cf4f7615b97bc3f809f96e888ffbe2a058cede252fa47703493ea1628f21d12df606528cb3e4b2f28562c9b1960b29c35fcfc66cf' }, 'config/aeotec/dsc12104.xml' => { 'Revision' => 1, 'md5' => 'b87f4a6edcaacab02edf19bfd695ef33639634b5bdaed27e6627ac2125999825ee722e7b621aa25da10523676f958cf2665c66970656bc3a41449ffe5f242614' }, 'config/aeotec/dsc13104.xml' => { 'Revision' => 1, 'md5' => 'ef5dd72ffeeff633a1c3e4f800b030d15d08aee39f8d986b38b1b62dec3be5b86239d86c9bd68900b415181b3f80dcd39359719229d31e4def3025a21c61a9a4' }, 'config/aeotec/dsc14104.xml' => { 'Revision' => 4, 'md5' => '17a2282e85a8c55c9594ebcabf655e639e05c6ff9c5fc34d735212d107cd5bb2f02de79a9d9208116a8233ee93283e5e06e56a582e225162be1745560e2ebdfd' }, 'config/aeotec/dsc18103.xml' => { 'Revision' => 4, 'md5' => '32d7bfcef911dbd9809a4acd2edc9ee0d024467b2f976f43e7c48ced7fbe00091ce325cbd31a09229e210e0ecc0723120e9781ec4ca8f29cebe80c1cb1b41d5f' }, 'config/aeotec/dsc19103.xml' => { 'Revision' => 5, 'md5' => '7515c93b6868543dffcae100ead92a9e6d9f9627a6673bb69c57099ceece2f3e8c8c93afa5031e8b7fb1b3f29c33cb4d6573913ee59efa2336fad2f86420a100' }, 'config/aeotec/dsc24.xml' => { 'Revision' => 4, 'md5' => '341394bce4e1c61175b6acf0fd8f9b299661db2c40f93d4138e897084b3afc3ad04798cd074d8bfa910e35a2b7629acff05479577c9c3cf7f764833233f4fcf5' }, 'config/aeotec/dsc26103.xml' => { 'Revision' => 4, 'md5' => '9adb08a2bc7b6d2b24d9e120c78e77a6d686bd6191dfb41b80fdd2da2a2d151a48c3b63c9f43cb09ce25b2acd9853b89d980570fbed3b5f2d8663773388cf3d4' }, 'config/aeotec/dsc27103.xml' => { 'Revision' => 4, 'md5' => '7dbc08625869c04da00c72444804e053bae36ee28f3207413fcc40591929001a69e59dfeed59eb80482c5fa5ef55d490efcf945dfd339fcf911700ec5f2a1f92' }, 'config/aeotec/dsc35103.xml' => { 'Revision' => 2, 'md5' => 'f5d464374a3466fc7bbf7a53858afc26224007de129cdc115171ddbf609a12282bae1fcac01f33554d9029918ba37a63b89d84f935160214e5d84b178b4715af' }, 'config/aeotec/dsd37.xml' => { 'Revision' => 5, 'md5' => '85d86525fac9158fc4fa41da95217e52dbb19eafe45a5fc02ae36f63e6ab0b7e1d7967441de798ab36f223b41f672395d6012e53ddecf25f06b7a6ff9225c256' }, 'config/aeotec/zw056.xml' => { 'Revision' => 5, 'md5' => 'd84b9d33348e972fbc0e9d7afcccf8a9baf3ab216600a93461ba27276a16d93f2749b909640942ab4e9b9c5e6aca977df9d73a84851d25055c08973560b3b70c' }, 'config/aeotec/zw062.xml' => { 'Revision' => 7, 'md5' => '216ceb7f2224557a2c6cfd8b7e35a14c42777eaf9aa14e266c3ccdf3791c2020c3038bd4d9198bbf56d309f537004c6a9380511de115474efc371652c55193af' }, 'config/aeotec/zw074.xml' => { 'Revision' => 5, 'md5' => 'cc2f4eaea28d3c4eca92e8d354890f4dabc5f2b6bc93f92e82237a7ea243bba0e0bdfe1aa154f6b0775f846a14c0e8fe86ec9e634c1e8339c357eea80b150a60' }, 'config/aeotec/zw075.xml' => { 'Revision' => 4, 'md5' => '437c6d307461be670fce0b2f16f0e1634890cdbf4f5ccd43f34ff237bd68410b1bf6cf8e6a6eb029e2deb3af565a6d5c61dea6543920b20845a84dc9b8229de6' }, 'config/aeotec/zw078.xml' => { 'Revision' => 5, 'md5' => '09020a57df80e03f421bf3df6603ec5fa6e0fd50242faa53e2e8f9b3ac8e966e5735eeebad82106b458ed21a3bf8e40263cf8e6469d3c452f62a55e0a6e021f0' }, 'config/aeotec/zw080.xml' => { 'Revision' => 6, 'md5' => '78618600d24ec5b5079f23575d0559b863626162259177a93e31ff1f78540764f54ff9d4e38e84195de1709798d4a44f3efcd5c4e6cae7aff564e1c26255dfd0' }, 'config/aeotec/zw088.xml' => { 'Revision' => 4, 'md5' => '76a90cace1499ce28ec2cb7334fe3a4e1baf890732f2b272c60b5b0627c15c89ec72bf3e86ba1394aab8e0ebe6eb39e86677540af28579016430c85baeb3d311' }, 'config/aeotec/zw089.xml' => { 'Revision' => 6, 'md5' => 'e7839e6376516c3a932c2f8d32ad64d60df5a890cd5e669cacb10fb75ae0621947e3d9cb00e00de7b4bb026f8c7e4be1cc25b59336568fa1d23dd1885126b1e5' }, 'config/aeotec/zw090.xml' => { 'Revision' => 6, 'md5' => 'eda5882a0b1e3f78c95e51496307d1867a1b3dc756a0b24f705155a3a1996659e67b6af65e60bd4b800548b4b1b6bb57ff591140f2062027545612efbf2a3cfa' }, 'config/aeotec/zw095.xml' => { 'Revision' => 6, 'md5' => '2e61f67c818ce40e29881dfc21ac53d6fc51b650d8394a615c02221664d47d53882a967581943faf9fd1b67f9c64ead25d0dee1d50ffc4893876c328ef449f35' }, 'config/aeotec/zw096.xml' => { 'Revision' => 8, 'md5' => '6d1e18b9e7a418ff6eefd323b2928fc1320f034cbf93d5c10be66a2794f99f57941c67364ee5e7d0b8a15491fe5bcbc856e859be16735ec6781899f1fc1d22d7' }, 'config/aeotec/zw097.xml' => { 'Revision' => 3, 'md5' => 'f9cdfc4713dd0352b3e5069a21cf8a6a6d36014611b3ba482fe059195016111c6ec43d9ed99d1874381424970e5939e0fff6796bf8412e8c06bf9c16add43919' }, 'config/aeotec/zw098.xml' => { 'Revision' => 10, 'md5' => 'adf310294cf46f0d5e1a833017eea6039c841b500479bc57176648e13dc27e4525591d226b60ad2ff6461483b7168229fea7885bf0d84e8c3a5169e17668dd7c' }, 'config/aeotec/zw099.xml' => { 'Revision' => 5, 'md5' => 'c4775cc1e44d3580cf6cadede3c1dca34dc94d9cb573888775ded7da5f224035853690d715ce8c7de0031d1e5df637d0da1ff7c1c86957755f09b65bcd4677f5' }, 'config/aeotec/zw100.xml' => { 'Revision' => 24, 'md5' => 'd7844707b29f8fe526d94aca4b1a47a26a3639e8d4a681199bb2775024d2f273c7be634cba65062d1ba2000803491af6aa654bcf33969e7ab870ffc80ce6f673' }, 'config/aeotec/zw111.xml' => { 'Revision' => 8, 'md5' => 'bdada4079cb3fe4bcc7bca5d831abc450e27f9ee4e38e36709df5e5b7adbb814846b7e660686fefd81f0b5524c382e1efb1ff43f0df77ca1374bbedacd1207c9' }, 'config/aeotec/zw112.xml' => { 'Revision' => 6, 'md5' => '5e832838a7292144bee049fa0cff287a4de781c55c1afa5a5471d98a00a22c6a796eef7b80bcb6ad6ca15b0e72a78e90ac6d82943aeeccdd8fc78befc3b2358d' }, 'config/aeotec/zw116.xml' => { 'Revision' => 8, 'md5' => 'acddde85a083a0bdba9a27da88fae9c7605d35cc8ef1109a1a4c8d91abaafd81c8510144cd6ae239a52290403bf73dfe46357e8ba3656ccbb761e7f3f56228d2' }, 'config/aeotec/zw117.xml' => { 'Revision' => 5, 'md5' => 'f06c4a37004d923c5131b5d81da83a3b035f8c4869cf7460e00d709cdf132ca98cda8b6d6c8efe3e123b1abae40ba2b21edb6c43e4d355c8ab0c9a893488d073' }, 'config/aeotec/zw120.xml' => { 'Revision' => 5, 'md5' => 'dc9b411f14b53925f973925c79fe180d7627f605cee4f45dd53c09030b3a4e234d83b2402bf4ed348b522f69b60a02bbc318031013a489853cc2569fbc55c245' }, 'config/aeotec/zw121.xml' => { 'Revision' => 4, 'md5' => '32a745da8b1a4ad35c19526739550747d4c243b93360ee64045435ad04e45e2e4148e12ed2c4f08c11efd076d39e4831395eda05651efe160fee24457b957bd5' }, 'config/aeotec/zw122.xml' => { 'Revision' => 10, 'md5' => '4c874a1d73359dd30743161b0665edfd3c7b9b16d5e4781ab13a84b5554ba2d03f9fb9480345f5192637abdde80867c4862388a10b2527c8207041999a4b4626' }, 'config/aeotec/zw129.xml' => { 'Revision' => 6, 'md5' => '372fa89d8aacf685983efe977fdafeb25715d5397d44922ae8075b5fd2fa69e74fb4afe45ca365fd0c464aea1bd0651a93e5f0518c25a6bab98d86edf21f3861' }, 'config/aeotec/zw130.xml' => { 'Revision' => 7, 'md5' => '9e98b12590da0c343fc75ebc18b1343e4df9120f292d46700666ba53e41ee99e6a6b196a2cf4e3b5a567a844499264e015381638c418d1d9adeda9e7117e599b' }, 'config/aeotec/zw132.xml' => { 'Revision' => 7, 'md5' => 'db49147ea64a88bc8106c1e88975523edf85c2e7e0b5ccccafb53ab438466f6a9cb6af75c4c17b7f5bf5cf10e6155cfa6f662d9b0b23726549d38f6d7c8e51a3' }, 'config/aeotec/zw139.xml' => { 'Revision' => 5, 'md5' => '971cf4eb4f6323c3f983c171b744af227d2f59a13665303b1cd3b76f62111cf5cb179bb196b0fdc33d90d608716490106cc9d75946a715c35140400f628f64b6' }, 'config/aeotec/zw140.xml' => { 'Revision' => 5, 'md5' => 'b64f170b079ae1340bd4a74ef3a88f0cdf66281fa28d656b46f408b183d04c8e6a67f584f90dd6f8b2aa1fc2b2039e32b936f6f947394d28002b3d3a2a47cadb' }, 'config/aeotec/zw141.xml' => { 'Revision' => 7, 'md5' => '3707dc66d31c2b7b68d3067021825beb48e00aaf04802a8b5f69dbccb2e1228cb0fa10ea71e3fe1f4ce2f1ac92958504fe3200552f8daca10024da401d9bb7ea' }, 'config/aeotec/zw162.xml' => { 'Revision' => 8, 'md5' => 'e64095e89500ff3b42d49c0cd92dae23d278091eb4eaf536d593d0cf1d887eb28f39c90963775341a7a72599de22b20ed96da31a29b328bb1328f13f69c425fe' }, 'config/aeotec/zw164.xml' => { 'Revision' => 2, 'md5' => 'ccfd9832b957c32bcdfeee2ad8802dc577e621df4d71ebfcdc3f166d67a5af5da9b789ffc53163fa2f62183ac463b29a8845fb7a8c3e7845d264bb8f7f6c2828' }, 'config/aeotec/zw175.xml' => { 'Revision' => 3, 'md5' => '1ea7de2ad02c49d24bb0c5d86ddf91cb09d37e3d9b3f64d9802f33f6d5626cd8cf33a18c1d0775f5622f075979415c461a846630ad40212d41998e8a4a970b8d' }, 'config/aeotec/zw187.xml' => { 'Revision' => 2, 'md5' => '154d350bd8009ee6af5e6a28515bf9e2255e9f91a61c2c69108af544307d2291164ee819e333ea7f1064ae21507037c99a0550dbc2540c1106e973c204367ce0' }, 'config/aeotec/zw189.xml' => { 'Revision' => 1, 'md5' => '9fce017a9280d9419cdb71e47867fb849ae88873930e5edd6eedeadd317e6cd71953c3db3e1944c90ecd298ae1c19164e688412e7a163611375848b8625d664f' }, 'config/aeotec/zwa001.xml' => { 'Revision' => 3, 'md5' => 'e63fd65924332e173ce34701ba86502affcfe1e5088cac0aeaa5755a0c1e73e335727b5bdc4730784c407f8022766fc0c220e8f07e36df8e6a44ca636abf67a8' }, 'config/aeotec/zwa002.xml' => { 'Revision' => 4, 'md5' => 'c32dbf9c909ee50b3d38f14594f163cb2e5b49873cf1cd551c3d1a0fdbfb7223466c2e70d14d1b95de5467797f6fc2141b0e8859fe6c3e2fe3231abd0aae1dce' }, 'config/aeotec/zwa003.xml' => { 'Revision' => 4, 'md5' => 'a02624ebe5092fa4bb9514c85ceb1b0e43dbc91203ab48c0608d13f3276bd48f331fed785d8b5ef2cae1a2af2ce40fb3d258b9c1aa9d36eb808b584e2383ecb2' }, 'config/aeotec/zwa004.xml' => { 'Revision' => 3, 'md5' => '0626cc10287e159e0a8b597dc07e7f092d1ae9af4c1b8ce796ddc12370981ba4c71589d04b4549936c58f690ee8b614619208bf3268f915f32602d1e2d6aaf9b' }, 'config/aeotec/zwa005.xml' => { 'Revision' => 6, 'md5' => '3c3441f59134243043aaefc4f01d1e8478580e03ac82a6a532f721c4d8320e5f8bf5404c93c25bcb853198b590353fb53deb364c39444fe9ca7fe36b64c218fc' }, 'config/aeotec/zwa006.xml' => { 'Revision' => 2, 'md5' => '08a55ab00eea7eb0fae63af644359667467bf0e31b22720bd21abb770c3b45cf0c3320039a67c8c6a33b740b8455beb1a67c9d4fa2f440cdc5056fee50f07a01' }, 'config/aeotec/zwa008.xml' => { 'Revision' => 1, 'md5' => '12234e354ac9b5378c93c1f5c32d642d29ff45ed6ae907c13d2a51c385f4340a1196a59b3419dd7901b48c592cb1693956e9d6e687b173d9d7a492221bec4a82' }, 'config/aeotec/zwa009.xml' => { 'Revision' => 1, 'md5' => 'dea1ef33d8f6ee2abbe83a0aabd9c9e22e4a9d86e0715f1ee90c8851ed135ff27521ddd6cc308cd09648e2aca4a498903054fd5ee66f3338098f9ce81fcef2f3' }, 'config/aeotec/zwa012.xml' => { 'Revision' => 1, 'md5' => 'bcfcf5d1a552ab8a8ac6ab7586f3de4cd7189d72a11e60bbad6b0038eb33f1d4acba164b625e7d8343b712aa27752fbe9f17f5ee9294ce82599e7abdf6c675f9' }, 'config/aeotec/zwa019.xml' => { 'Revision' => 1, 'md5' => '5238b4e34afaa58b71c9b6c6e857b5b1a63e4645322cf0324cdc3556202dfc5d08979f5cdecc7989b851eb7db9aae6c2308bf7c3e7f56adb264c1f395d05e4cf' }, 'config/aeotec/zwa021.xml' => { 'Revision' => 2, 'md5' => '1337565d4bb52206d7c29f16a04957d09e9f800da716907a5190841f6b69901f5fde754d7e9713d0ac97f2ef6ab7b563edb3f3fda6981e58757e5f2202ab50e0' }, 'config/airlinemechanical/zds-ud10.xml' => { 'Revision' => 1, 'md5' => '028c79db0efa85f50283cb57a22462dac7d2e7024851b5d715ddb7f715d0012b8f993829ad542639294ab266b3017fb31a62ed8fec929dde8f401dd276dde67f' }, 'config/alfred/DB2.xml' => { 'Revision' => 1, 'md5' => '3277bc3318fabba8c77c47592c791a2679fb4e96a0f1e9b21c38561d2fb624452d9397b89ce9a51c3eb6d39d20444a3cc8af06cf46cbca218a52c2c7d82dc8da' }, 'config/assa_abloy/ConexisL1.xml' => { 'Revision' => 3, 'md5' => '87fb792063b7985b730a185e5be07e8f98d3662069b8055cd4cdd1a5f7623edd9d18f25ef5ca9c45c5489d48a91f97da914026b845ba9ed57bdd99752d985ff9' }, 'config/assa_abloy/KeyfreeConnected-plus.xml' => { 'Revision' => 4, 'md5' => '800ecddc35ebfbd336d3bcf8880b769d4c1bf5e333085d24a38ed64fe372bd128c2bac8ad3fe6cc7929e2531c8a0d0672b2c02276e57b547c70599810ca73ef9' }, 'config/assa_abloy/KeyfreeConnected.xml' => { 'Revision' => 2, 'md5' => '4252c298eacb7e31a79c7c8fcee5e2d40b56d9bf865c8eeed53e3a29e8695508d38ffb83f558a41871e13af346c65cbdbc8a7de6caf7c5a1a67af59b5fb384b3' }, 'config/assa_abloy/ProSLKey-FreeDeadbolt.xml' => { 'Revision' => 2, 'md5' => '7a6771adb77b2bbcb11fa6e74733ff064b87311b1530dbfb048bb167d03e5a1b3880ad2d5fa59977080cc3c3b37f3624f457095ebc5770d97d4cf258d68cf0fd' }, 'config/assa_abloy/PushButtonDeadbolt.xml' => { 'Revision' => 7, 'md5' => 'a39dc67ada1bb3ea32c5be977f635cb4e5758e5006d54b84ef8cb9c8bb91a830718e94758b5701d07af4c17ec3c83a68af34069aaded0e9096f70311e15ae2c5' }, 'config/assa_abloy/PushButtonLever.xml' => { 'Revision' => 1, 'md5' => '20533ba6551380cfb41ec7ef2e1dcec8c1b2d5e23b5ffcd87285c5a0945556989200c7bf25031cf8bdd3b39ae2c6a514565698acb3443c6bd6a3ed7ba583dbf6' }, 'config/assa_abloy/TouchDeadbolt.xml' => { 'Revision' => 13, 'md5' => 'c29a547f859db492054de260d6d575cedfcaecd00aa612974e848e317cfe498eea5e95723e0e01f90ac8ddd8179144b83fe744b248cf54d2e19fc97a52cbfc68' }, 'config/assa_abloy/TouchLever.xml' => { 'Revision' => 3, 'md5' => 'f8ce232d1d46aadcc867c736a54218bd1cd15b54d2f2f819d190315cde7302e887ce23f0d111c4478bed6c3b0af9df91eabd9973313e9399e0516ca3cb66dbe9' }, 'config/assa_abloy/nexTouch.xml' => { 'Revision' => 5, 'md5' => '56cacadad65e06642795966771dc7ab7058c34207ca34acd340e593156db7c10de265fbadb75c0f31574b696ebc74e4329d661f98e8e246ab16c91a55ab38e0e' }, 'config/assa_abloy/yrd1x0.xml' => { 'Revision' => 14, 'md5' => '72b0c1a02e59692b581f0f242a36b9c0c96f97d94217e7f391d219130f73df398abdc8370dcdffd74462d41b9aa1bf69498d0d04c3c147ed89a093970d25fef7' }, 'config/assa_abloy/yrm276.xml' => { 'Revision' => 1, 'md5' => '85f0bb84ad6fc350a6e916a4931d91adc77427366f8394bf07de3c9ca1394bf5a5dce576d6a4dd107097017454e4397f800ac597bec7fee8047a69a1709b2d12' }, 'config/august/asl-03.xml' => { 'Revision' => 2, 'md5' => 'c20731a4c1ed5261983c163c619c36085cab448344caa87203a45f89938678cd755708bf67bb0bc997bc61120051ae0355e4465f7e50a83420f4fc12e9752ac0' }, 'config/buffalo/hw-100v15a-zw.xml' => { 'Revision' => 1, 'md5' => '700da33bf896ed7250ae6e75b8f06885935c0398a3b60fcb96c28f0e8b61aec82bb83811a458893679da00db0864dea000f831b9128ff17a911e020bc93bf3ac' }, 'config/building36/b36-t10.xml' => { 'Revision' => 2, 'md5' => 'af740c48ea2d7fbd46bbcb97ae6605dcf3f16bfcb8c8f785339a9baf3c4c41206310d309d85c9df803fee06bf1d958110cbb3a90d7088d945de39d46d430c852' }, 'config/comfort/ucm.xml' => { 'Revision' => 1, 'md5' => '343e23824152ce111beb412a9b5ce0b40f90e12cad4fdc3b9e91267143e7dfa48f3b5901513401eb1b55bd986188c36d121c2fdd058f6ff91fcbb2c19f6fbfaf' }, 'config/connecthome/ch-201.xml' => { 'Revision' => 2, 'md5' => 'a0ca60110b50b83dd53ed869fbe3cfafef1bbb1aa22c5cf96a85208370c55554d7af20b5a24eab3f2c81e333b9dea81a1134596def6254d9067a6f7de45d2e99' }, 'config/cooper/RF9501.xml' => { 'Revision' => 3, 'md5' => '3607a09ae6cfb895c99875d96250165cc78a6072c12bc381ffa206792599f0a646e835ef535084c128e528453e4a23430d2ac0a6797aab7e6f1c56b0103ae28b' }, 'config/cooper/RF9505-T.xml' => { 'Revision' => 4, 'md5' => 'e66799ca1eb28d18fdde9ece6bdab8a00b583fed2f921e652dd6ac4e2f27f80c71ce1ba14316057314ae79a2bc6b4e31ff4e012242d996e905134f1c59123598' }, 'config/cooper/RF9517.xml' => { 'Revision' => 2, 'md5' => '79e0f21a4292d455896bdb3b87401bfd6f405a6a2a795c8b77a4a01513aefeb17b72ed4595f3f84c2463f17b386bd1ecea67ebbe547e5f39472abeb3d831b805' }, 'config/cooper/RF9540-N.xml' => { 'Revision' => 5, 'md5' => 'ee02b6f5fdaac0c1eabb44e093fa59d4962443a5d0c1f151ee4f00e9bc219d4224dc93e423f7fb6ff7a1342717644f71a689b301cbf29aec4eef49879f5a51c1' }, 'config/cooper/RF9542-Z.xml' => { 'Revision' => 3, 'md5' => '9b2bcec41e4a46a2a2558960b03f5a3e66db60d40832542bffa053f49c0f08c70e64151d2619f1328df23089028a83ed70dc17af9125b2299443e237957ebbee' }, 'config/cooper/RF9601.xml' => { 'Revision' => 1, 'md5' => '086da7deb18b8df7738a637822279549d2fe9618ebe7965c1d190fc83e0120e8050e1a2f9ec082b0b36bd5ee5589ce2d93e54d04c768238c5be40d88dd3dbd5e' }, 'config/cooper/RFWC5.xml' => { 'Revision' => 2, 'md5' => '5e94896a472f7be22fe176de80f784d333bbf9a1afdcbed80094ecc1ae89c0b5cfcf47dc57731aa5312a87120b4d04934060ac3bf78aa39133118c6f1dc6d3a7' }, 'config/cooper/rf9534.xml' => { 'Revision' => 2, 'md5' => '3a127a530e1704602f95b10301cad6ec6fb7aa5eebeabae85610b3435d97242bc011435d8e0e603e3a4856f7b91ea29a6365593bb789fcf880efdffced4b1a28' }, 'config/danfoss/living.xml' => { 'Revision' => 3, 'md5' => 'e896b83443f6776d1a9e9ad52ccbd4294c0905d2c61f1f1029c0d51316e33278efa0586fabde67562e2ed1db7dd5f98b12580b43575d8ba167041b9b80dfb605' }, 'config/danfoss/rsroom.xml' => { 'Revision' => 9, 'md5' => '8670ab88a1a580c94bd5cba9bdfe217ba8cf980ceb15ec2fe28f8def9e6bb53131e019b4029b4cf193622775a68cbe63e147c83ccd39d1da981e550870448ad3' }, 'config/danfoss/z.xml' => { 'Revision' => 10, 'md5' => '67829f0390c36d3ce36ab30b108b1c470a3e233c81bc982758f8707c0872e27cc926ed27c2587fd65656c22b551a3c0421dbe4dacca16be6bc4f8079f176572b' }, 'config/devolo/connectz.xml' => { 'Revision' => 2, 'md5' => '61e265fb8396c5b7ca94019ec7c9912fb26d975f30a8bdc286f2d2b7eb63d75be28a9f2266d06d2a7d1fc222430b74e25a330246614141ddac617145ba08af00' }, 'config/devolo/mt02648.xml' => { 'Revision' => 4, 'md5' => '90a9dd3e7ad3fba28b73ac65425ca48640ffa0962c7bcb87e3a6b56661dd5fda87a89ca9e0c3fdf09bfc96f8319b8793e9cb8089932b0c8dc65c26e7131a8c99' }, 'config/devolo/mt02755.xml' => { 'Revision' => 3, 'md5' => '8b039195599ad62f4f511f07643743f7bde06359acadbc29790328483fab0ab0d5601156735849e1542e1b2f08fa5c90a241d1a7c366d773ec86f7c9756bd711' }, 'config/devolo/mt02758.xml' => { 'Revision' => 4, 'md5' => '14ff0b2c38401d34c8ee73b3070264d9dc5f7a8e2e0433df136b84e9590a718840b2aa4b18726eec7e40598b8f1bddb7a9f125ca17ffe1ed8f5eb3cc20661257' }, 'config/devolo/mt02792.xml' => { 'Revision' => 1, 'md5' => 'd61db8b2dd5102245fb5e73208c40af5431512b7e60e6d3cff8b98b35b4a1d1744542f5beda0eb8a4b15606e4004f111454504e6fe4dec070ac4a8ccfe07d113' }, 'config/devolo/mt2646.xml' => { 'Revision' => 4, 'md5' => 'f8715a93ad04fc6fca58e8f98d7d6d4608f62692cd825a61fbdc0bcf238e78845818fa848f33788f8d5ad3c031d969e403f96c49fa134921ed695cef73685940' }, 'config/devolo/mt2647.xml' => { 'Revision' => 4, 'md5' => 'c8591779bcb81c1861d4b1009450cd600b7c21dc11ba0660efb16ef725686dbccf2f5dda3a78abf66c0d84ed834280e99d29b0cbfd229b3741e1a5ce4f585ca2' }, 'config/devolo/mt2651.xml' => { 'Revision' => 2, 'md5' => 'bf1c18dbad944110d0b9cd6d4d796c77c7baaca3e51b7650f11ba84e981dc6e8de2d8a4be54e148592aeef2cb66b6751b39db4f11db5c31009de4804b51e6d05' }, 'config/devolo/mt2652.xml' => { 'Revision' => 2, 'md5' => 'a8f15a647bc553fe25af1f6dd85a43915880514e90991e3ca1dad164801b86aa2ec738f78de7e20967eac39851d34decb3e437ba083a22ca102da399bc8b6e3e' }, 'config/devolo/mt2653.xml' => { 'Revision' => 2, 'md5' => '54999716088a16dfb9e197b14af98c726c1f2e709cb4fb15aa29dbaf6bfd9247e236fb0e389398c25d4e74c87a488c2dbe29c0f19a8fadcf3998a7e890e9d053' }, 'config/devolo/mt2756.xml' => { 'Revision' => 3, 'md5' => '2907005d8044e82669ec68cedefc5b7bfa93e688221a55c8b1d3b41e387579aaf90126c60ee2fe2253a8b0ee014a8e0fb4ebe325653dce4f2a3759079570337b' }, 'config/devolo/mt2759.xml' => { 'Revision' => 1, 'md5' => '5c8c1066314553f11e30aaa335e19d366c1d222def7a6cd6487a0e634dbac718d0e2d86de21906a0c24dd077a6e847295a55243683e45f1a5f2dacdf22cb71ee' }, 'config/devolo/mt2760.xml' => { 'Revision' => 1, 'md5' => '1dbd17cf896b8241471c094ec0d450792a36af2e0f23d92cb82d2875253beb05e5bd909a43ee29c6c386b5b60a0e604c830e38a5d6828045224064138369e7d0' }, 'config/devolo/mt2761.xml' => { 'Revision' => 1, 'md5' => 'f5ec076e52b23e4ac0c0c9132f92d3315f20c752c024e60de4a05d1fc6caed280fa285b4f8f332f3d17c90124e1e84f3d42f50808419e0c2ebb8d38a7e356351' }, 'config/devolo/rs014G0159.xml' => { 'Revision' => 2, 'md5' => '5a998e36359d0db43cf66cfbd59ef3b41281d12f535cb7aa57d704abd77e4e771cea236e82c8eead4ba9fb74962b536cd4431c7f6b5482f8900ba58496cfb9d9' }, 'config/diehlcontrols/766366.xml' => { 'Revision' => 2, 'md5' => '19811a36d8b2b054f026486178497b34b6c6e7819533aea8e865a57fea7bea01a39731cae1c407a7d983199ea8dae2eae7cd5ead407662ac79d35e25977c57e1' }, 'config/dlink/dch-z110.xml' => { 'Revision' => 3, 'md5' => '573c19c68df079fae58fcb4a318be9e269dfa618c38357a65ff80365a47840b9fb0f703370bd3c6d5a7409d1155472564291720169824c6e3bacfecadce05294' }, 'config/dlink/dch-z120.xml' => { 'Revision' => 3, 'md5' => '057ea9034b5751fe492a27bf4deef6c5b73fd53406649552f8817fee341be6001bb776cb5012ae6f7d8f319ada161faa29243d32c8efef9d508b18ed80cf41f8' }, 'config/dlink/dch-z210.xml' => { 'Revision' => 2, 'md5' => '738b1bfcaa5f34d23eece8c2d95284c113abb0807197638d881f33afc49fe169036e68a702989bba4d64c49bdb038f6a764ff76e241884c25c339d251c4201c0' }, 'config/dlink/dch-z510.xml' => { 'Revision' => 3, 'md5' => '0168efb962c2470418b5fb8ff1f274b5619054523605eb79341ac32e8e1e09ca817cee00c4a30fd0df2e0caa74de7740469cc32514ed0f2e3266e0dbc499789c' }, 'config/dome/0002.xml' => { 'Revision' => 2, 'md5' => '67ed823369ab3c2446449ecd98206ac0f1c427ac66ac86b471866e3a879460f373ef33d7629a7a9bb045793894140b585c1b3079b6e8661f85ce55865151edc2' }, 'config/dome/0083.xml' => { 'Revision' => 1, 'md5' => 'df800a068d84b8f3615b232fafe6190ef9bea776c5c41f801ed127d1d76ee2decd5254b98966a2ea2b0b560a489d6279a61eafe1bfe7cc87b3e6335206fea102' }, 'config/dome/0085.xml' => { 'Revision' => 2, 'md5' => 'f02b0adcd4abb200640525a406f1eba3e246a5e8db82bdfd3f9f80531fa2cdec0e42d0a6ce140c3876a8e038d56f3a1e51ef9d1f5b4ae4cbec0160c958e5eaec' }, 'config/dome/0086.xml' => { 'Revision' => 3, 'md5' => '0f86f2e63e4c1695f4cd159ada100514fcd979a5d06f3e6c9b0095ba5716a2de68d5f4dcf20bc82383d9da30050e3254251a3005fb7b14c8c1e324b329a5fb6c' }, 'config/dome/0087.xml' => { 'Revision' => 1, 'md5' => '8cbb65b02e93448094240c732e1807d0a701372d94690a90fa410f75b0b9f8eec748d7e1f190f3250d271d972de4353eb507f30221678b597141caf4134326c7' }, 'config/dome/0088.xml' => { 'Revision' => 2, 'md5' => 'cd876175a0f5f4fad952b2bc97abdb39e82ef1b606f9f7f7303124295ee375dab7957e73535a750f9e6551479e4f48a8d55845b79a889dbed8d28e0218acd705' }, 'config/dome/0101.xml' => { 'Revision' => 1, 'md5' => '5ccce24dbb0b56cc6e5e5bbebc24e05da07750a24f64dd66a6a5cd5aec7d79a0ae59f854af5f4b40cc60806706f54cc007bb1c844346db0f91ac10c8e3b49a7e' }, 'config/dome/0104.xml' => { 'Revision' => 3, 'md5' => 'e4121145912464763ef4ece86fb7f2ff8edc0c547329b1dc7d36e81717202be5b0b84ed5214bcaa31d8a2f5882b9f762d0892402dfb421f3bd80b8f81b4577e6' }, 'config/dome/0201.xml' => { 'Revision' => 4, 'md5' => 'fee61cf3301b50c77758714649fa35f6d3bc3f1614124608577e3b47b897fc546fefb1a31520307f853c28726c5758cc3656d3ebe290b6ad858b43d4e99d7a64' }, 'config/dome/dmex1.xml' => { 'Revision' => 1, 'md5' => '70b90962ec3fc43b50b827f6ac2fd8b9d112b8c979e6e42588dd5fa19eaa909fb4a9f66da21f3f9200358f4343785c41d6d561f6d1933a0a6587403421380627' }, 'config/domitech/zb22uk.xml' => { 'Revision' => 2, 'md5' => '90c85ebfbaf16201c99bd09c957a408b944034a3626a5a5c2eced093e27e6e0a8afca3d8516d7f6ace2e3889b57e5fbe585219c74ecf7c8a127d3b860970c425' }, 'config/domitech/ze27eu.xml' => { 'Revision' => 3, 'md5' => 'b198727272486c632dbaf5b9c4df7dac0fb4c8c743d63f223980b764c75b747078d2754959d2a15281de83972275b0062cf6fad1ab2b83dc1a7788b2d74e0e74' }, 'config/domux/DX1CA-Z.xml' => { 'Revision' => 1, 'md5' => '7bc16a7dbe5ba0591fd65015e168075a191131d6ed80882d4e986dac2f0db163988f8b7dea228dd9b1cbbec994ae78eb60f7ee302f716ab3647d3e304357656c' }, 'config/domux/DX1CG-Z.xml' => { 'Revision' => 2, 'md5' => '431f30aa51b7c02581e67d94ff80f901e03436759cca0d1ebd4312445fbebc4904f3003298994d3b31fb7271edb78b0de5eab1c612898925549b702a150cbaf7' }, 'config/domux/DX1DS-Z.xml' => { 'Revision' => 2, 'md5' => 'a23fbfbb8197142d739590d81e1efc2e6540d6a3b0d061d7aeb33e2186e2fc544f6f9e8287b56fc9e33fee74b542fbc7cdb2c859c869d8043ba5ad8da45e3173' }, 'config/domux/DX1HT-Z.xml' => { 'Revision' => 2, 'md5' => '8a2954363a09e06ff6dbe2688482a16987af0794aff080fe25229786387efe805ad42e46dd8a5b2a59c205f4e9b9eef2dbe5e30f015dffc348b22f73f08d28d4' }, 'config/domux/DX1MS-Z.xml' => { 'Revision' => 2, 'md5' => 'afd42f05719619ee61728d7707cfb7f5ae0a26317c3c2b91a06d6c8f6d9ca66709e21f5dfe05825ed24e1adbb3597f9785d4395ea1419ab1a1ec25780bf7f5e2' }, 'config/domux/DX1SA-Z.xml' => { 'Revision' => 2, 'md5' => '4c57c0102cfae7a0a3d99c4a876c010ea600ff68267d8f3af9d6d93c4b23eba3eb6022edd26f0c3ed901ee69e83938c0dfc913ceb2e2e50f1d55ac015243b6bf' }, 'config/domux/DX1WL-Z.xml' => { 'Revision' => 2, 'md5' => '5e533a29c1e3da4b6c739cb95c4e8ecbbfb269280c45c3c826a5429c8ed0ed0b50d142914354a1e9c660d825b144e2d595621126b34f4d29acf885bd1ced5204' }, 'config/domux/DX2SK-Z.xml' => { 'Revision' => 2, 'md5' => 'db469a75eb48481db6cc3ffcfb6590a58e531b1090cb215b3db12b8492bedd270d6068d1d716b5eec26a0fcb201694d269c106bd22095dc4190e50c8f30f016c' }, 'config/dragontech/wd-100.xml' => { 'Revision' => 5, 'md5' => '4d7a77c213b0dea753512dcd30e3f6723f7d751d13801af9a0584a04f4182043275e3e47f268299ab44f91958356119c571a34d1022b70bf8bafc08fd717c67e' }, 'config/duco/DucoBox.xml' => { 'Revision' => 2, 'md5' => '7911f42a45b59bf2081ccf0dde356696d7586388f69e660e80ef72ef17516888ef9d74bff4deea0f03d721e27e43c2ac31ccea40bcdbe178a2a8163ce5bdbc3b' }, 'config/duco/Ducotronic_CO-RH_sensor.xml' => { 'Revision' => 2, 'md5' => '506b64e578667ead9c2ad64c896c0e44fe30efb228e6daa0144995f7ddaee1f0b7692e1447ddccb16d55bd9a2589a57afdfe164ca04873e7faf8db9cc598fcb7' }, 'config/duwi/05458.xml' => { 'Revision' => 2, 'md5' => 'aae2fb7ecd70a8670daf1f9a74a78e4a337da5e4477480607909a727385572371e7708e4cfcba1962c31231f23960db30dc182a74143f291366ddf9317b51e22' }, 'config/duwi/ZWES1000.xml' => { 'Revision' => 3, 'md5' => 'a2068646341b2563717c6a9ed279b56010de4ad2b8420105d2318020fd4ab35f97975ffbdfa69fb7167855287ad2f54cb402705ea30437ba86b6f3598ce25b52' }, 'config/duwi/ZWESJ300.xml' => { 'Revision' => 1, 'md5' => '180a94924d5a26af131b684cd2a55a9b529563a852d22be1b1d4e67fbf89b9052113789ced43d8d1ec2980fb6c03a135e6ae384c66dcc49128cd0d494ea9cfd0' }, 'config/duwi/zw-edan-300.xml' => { 'Revision' => 1, 'md5' => '558abcae454f44ba9d0de9f04903672e77492bb1f2a67b9d399755c93ef71a6326ff261fbbf42f887ea2db0336d578220de8bf36028b3337f970d6d3313b1bf6' }, 'config/duwi/zw-zdan-300.xml' => { 'Revision' => 1, 'md5' => '4a87e60d6056dc202812887a8c896b089bd439e259924b724abc2ceb4cd9afbd2c72226320ef4130a55bc79c6d1c5946fc6feca04e0a71b52f4bc50a698d0a7d' }, 'config/duwi/zwfb.xml' => { 'Revision' => 1, 'md5' => 'aba223dd3409990a731e8773259e6a68a893b862adcd3a99e008214c57771416120d42845bbbc5a99d4044819aac3121fc81c6610f0e48053676ff2c9888d91e' }, 'config/duwi/zwws.xml' => { 'Revision' => 2, 'md5' => '29a2b8e9eadf09ee7af8441cdf46d97ab8df6271d2f1cc981acc73a9f4bd7dbf1f53449c6f71d052fa130fed9c1347a5b611b81adc46f305d704943472f54b87' }, 'config/ecodim/0.7.xml' => { 'Revision' => 2, 'md5' => 'e334fccc67d01e2b271314e4749dfbfef299dee1dac04af6bfbc253b9fd676e43c0711322226c936ef6fdc026cca4c291ecf943fa7a6419fec816d5533e0abbe' }, 'config/ecolink/doorwindow.xml' => { 'Revision' => 8, 'md5' => 'f328fc950eaa4b3055fff82625da805bcdc8708115a79f926b623432ac30d3482fd933e0e8a252086a61b3f48fd27cdd850aaa828f74f5a774e7e6b2ee272bfe' }, 'config/ecolink/firefighter.xml' => { 'Revision' => 3, 'md5' => 'bb3c0c3231ab9eb0a0a015140702edde90edd4f0a16794efbc10a9feb286d9573642c5411ebbf5cf917ef2ecc7eda16725b95e9106032bf2ddc885e4c478ac4e' }, 'config/ecolink/floodfreeze.xml' => { 'Revision' => 1, 'md5' => 'affa47443b792317e413a8bc124477f533173a259ef9bb9e820ee9977db7cc75ec58d21332f912d65f015b46b4ed5ca0df8ea157ca03f91b483f07b6d0d4649d' }, 'config/ecolink/motion.xml' => { 'Revision' => 4, 'md5' => 'abde9dec922634817550f559909091b5806e1f0d42f7aa400292ed8c9e6cf6ca0aaed1bb6bab30327053643ec7883333010783b2c3e7263e45421da8dbbe31bf' }, 'config/ecolink/sensor.xml' => { 'Revision' => 3, 'md5' => 'd1897bb925a8c3c1f94ee31c3ad8cb8532be3690331fcc477444035e16c9a4b6496be1fd621f1c6c7be7575d72e55229c77234eedd956c9cb9817139ef317c51' }, 'config/ecolink/tiltsensor.xml' => { 'Revision' => 4, 'md5' => '59094a94ac42598b888a8a6edc2d87f08b0d47b174246fd4d22f46a71ebc1951edde9ae30a094d5502916e8381bfecb1d67d86fb9d54c9bbf91968585cf6ff3d' }, 'config/econet/ezw1204.xml' => { 'Revision' => 1, 'md5' => 'fcbf2492b919363361339a98d7a9bdfd67618b9655cbf1795d8688924abf331ccb31ccc9169d05d5a541baf40e73e753f5d9a5e30a8cfd7f7149d69484038aee' }, 'config/electronicsolutions/dbmz.xml' => { 'Revision' => 4, 'md5' => 'a73eed69c4692edfa8c192c3ff82849c84585689ff73f07d7497d1abbb5c8dc77a249c4e090f366d0ec8cbb8da63a4727758685e3c0012821f0918fe78b8ac5a' }, 'config/enblink/ss201-us-w_1308.xml' => { 'Revision' => 2, 'md5' => '461fae3791a15189acc997f64255566573dcd51612028cb8d0bb9d189a249182d86336f977b62e434bfc26e0c89f15ef839ea0786ceda7d6cb32d8b452a05071' }, 'config/enerwave/zw15rmplus.xml' => { 'Revision' => 3, 'md5' => '0089cbf9a8c7f27a9ed4b7af8e84e594d6be66a70e1c92f0b0d85fd222355f8b8c7a03b5c584f22e99ee7c65776122a92dc74a50bd156be616327774602ae805' }, 'config/enerwave/zw15s.xml' => { 'Revision' => 2, 'md5' => '1300de4b8f914d8b1d2098cfb6cde5c5ba4f8ddfbb60d3a303b4301d7971001b7f088ee05aed4dd31b7138374fc14f07f322ea8b9b18889bf692e5891e944cf3' }, 'config/enerwave/zw20r.xml' => { 'Revision' => 2, 'md5' => '649faf0c076c9d76140c6d8e029addea7b2a82a0570b45780925d6ef435ff6478d0b86bad01078e1acb4761c71bae0ef85fbff28a8e1e1f18a587069ff7111bb' }, 'config/enerwave/zw20rm.xml' => { 'Revision' => 2, 'md5' => 'd1d8e3db4d73e61674548aaaad10ff1543cd19339b5888fe2a9885e932d3a2f09a88f9d93ff62f0ba036e8a5cc191102683af39ea665f10de43ab1f31e56f2f3' }, 'config/enerwave/zw500d.xml' => { 'Revision' => 1, 'md5' => '7d6d24d8557afcfed2d1fb8620772546730f5ec5d6dac0115f5461d3565d6890403783455e5e7d8010e326098b5cb7eb03b816df9d6557f46b6447e893c075a1' }, 'config/enerwave/zwn-bpc.xml' => { 'Revision' => 3, 'md5' => '39b03cf30d1e29f45854d2328f661abf76754e635e4b1f6279d90ace3b4b5c57fb8d883384520617a70e499b79390bbbb3bac3d53260da19eefda686baf0bab5' }, 'config/enerwave/zwn-sc7.xml' => { 'Revision' => 1, 'md5' => '96404c642f3741b36f865b0486bf7ca0dbebdea208da28cace87d10181be77c14d69b455aa0cecdd2a3864d9b0b741c999da786f1b5daf75e2c906da568084b8' }, 'config/enerwave/zwnrsm1plus.xml' => { 'Revision' => 3, 'md5' => '6725ee78062fb147fca3f41f1868bb520abf637684dee1a2cf39c2257fde1d98d90eaa6a2a35f54f768e013557889552b2458e72f37b81079e39b84053b39182' }, 'config/enerwave/zwnrsm2plus.xml' => { 'Revision' => 2, 'md5' => 'f89f47cf55c773b388c2694738955d138ae819b3962a6a2fab1c1a41039bdce7d474a7fac4503a42f4ca3b35040ae0c7795cb790379ba963b188272a4d2225e1' }, 'config/eurotronic/eur_airquality.xml' => { 'Revision' => 2, 'md5' => 'b5f0d3da21fb410fa81dd9f6863746cdb62037fdb750b0a8e0e6f1f73637581ad6ad330ceb6f7a4d4f774a5fd1602f55e410df66242e1e87245ee029b84ee5a3' }, 'config/eurotronic/eur_cometz.xml' => { 'Revision' => 6, 'md5' => 'fecc7214a3cb7334806e38686fa9e4635caefff7a7bac8cf98af1b1a6dedefaa33a7a943f6435d5ae8d2286d39a69c08b3fab173ed29fd367de5fba6b321886b' }, 'config/eurotronic/eur_spiritz.xml' => { 'Revision' => 6, 'md5' => '0dd6650679d4f3fb99fd10c0d3e125fd2c3320edf88c3a808a6fdc0c5e3301034335c9469c2b278e1858dbef381c885a442e816b3a2d40aae119ac1bcadfebcc' }, 'config/eurotronic/eur_stellaz.xml' => { 'Revision' => 4, 'md5' => 'c0756aa51169958ecfd63418b44423f557f31c1399f8cc5933dd487012272b8c9c92a8fb5a27fe87d78675b8a115c2ad00ad76dbbdd362c8f1da39050b4a4ed0' }, 'config/eurotronic/eur_temphumin.xml' => { 'Revision' => 2, 'md5' => '53ac26d6eec78e7886ac95a6481bbd1d14f7fed6ad060a1aa2c5a6977a374ab2c395b592bef9ae4eac3fbe7e4af934dc31c45ba45fe39a19e94816f06e3db9a7' }, 'config/everspring/ad146.xml' => { 'Revision' => 2, 'md5' => 'aadcf1eadebff5fa7d508e5970dbdb043632d9b9f1c106ae4d872b11127e8bbd67755114c016f52aa4961ca92069eafcb42c099ad8f919578b334015bcedb6d6' }, 'config/everspring/ad147.xml' => { 'Revision' => 4, 'md5' => 'c48e9fa3f0a31c8f082ed9fb16a08787251621b3902f15a13c78c7e319ff254c8001b4883f3721ee44bd0b5584679e2a98a68d7ec005562b08623ad5c7f1630e' }, 'config/everspring/an145.xml' => { 'Revision' => 2, 'md5' => '30235407eb3b18cf27ff7e105c0d87341dec592d5c05e217b6d4deec470066afc37e95f773c021ab9f6f85874da9b349bcada1f9be56f9377923b9767753fe62' }, 'config/everspring/an157.xml' => { 'Revision' => 8, 'md5' => 'f7afa8e9d7fbf522812deba0c11a1b5b15479e2896f7bb55df1099f83a4c1aabc64e08cb84b40849b0cb673c239501af20eff0672e63216794baf6eb3ad22740' }, 'config/everspring/an158.xml' => { 'Revision' => 5, 'md5' => 'beffd93d68274c31d2583838aa4fc014fdc1bf980bce07f98b8bf7fa6d8fef44bae85d1a06f24c5362f26e67a82022d842f545346d2e8c9fc3d7885d26d1dfc6' }, 'config/everspring/an163.xml' => { 'Revision' => 2, 'md5' => '36f97e69383ccb3b6428b9d0935d5feee86598483267e35bd1b0b9a54ecf4f112a92f35ef01cf5be79abdd81b0a401fecbe09ea2f639adbaf0e1a78d7afdc0d3' }, 'config/everspring/an179.xml' => { 'Revision' => 4, 'md5' => 'e39532bf66154389eb31e6f1f6da5915c40cd8dbb682152eaaf60931dd8ea4992be1a11a1b9ac58fadf40f965e3ea7de03e9deb34b7b1ba63bad9485dab53877' }, 'config/everspring/an180.xml' => { 'Revision' => 5, 'md5' => 'c1118724c848e37cb666af3cc4338314075f9013e1fb47caa2f8eef00420e80fe808c0335828154bda037891e0dc7b9769236c28dbea8e73240fd6d2daf9139e' }, 'config/everspring/an181.xml' => { 'Revision' => 4, 'md5' => '29ccf218506eefa4204ff5293d190a32026e9cd57e083a85131b29d575f1ff89a8991b4dd7eb79136abd58d42107fab32093f9b610f2b158b2e0a1aee3be92b0' }, 'config/everspring/hac01.xml' => { 'Revision' => 3, 'md5' => '83858d1a26350a75ee01bc46c2ba6bd0cd6ff281d549a22fdd9784f88a7bc8e60467e235e638fec024222252414ca151f0a5a3c0a0d1efa05f02a851cef5025d' }, 'config/everspring/han01.xml' => { 'Revision' => 1, 'md5' => '41d5fcf2548e675012a7d5510c5edd0489accd9429f7c4710dcec46678e95bd3ecae692242bb9da11618baf2fbbf1fb5e3373fc2ee5ca065be954a9ced07060d' }, 'config/everspring/han02-1.xml' => { 'Revision' => 1, 'md5' => '3ac5a3938d6536d9b99a260cc4c1fe9587290ea6e6aa38e93158df05c22d17d9a41ab3f5db639a653e1b57e6c701c234784ba366f79ec1d81ea1f9bb42280184' }, 'config/everspring/hsp02.xml' => { 'Revision' => 7, 'md5' => '6579098c7dbeb3ba683016cfe27ef08805ee7dee2d9cc5e3b94e4df010d8672e0811d61fa70533061c822d766a849daf3fb66b1f18e87e90ad02862ed76ef8a0' }, 'config/everspring/lptdm1u.xml' => { 'Revision' => 9, 'md5' => '8cbffa88913207a3a149123dadfb6f9db9686886795862237723dd73cf75ca28f0e85eb57aa66ceffc21974ca40fe06f0a877605096cd5aa65e351a797af9d23' }, 'config/everspring/se812.xml' => { 'Revision' => 6, 'md5' => 'ddbdd0af88bc20428667e30ba0e423e963d0d53c5fb741a5d9f0e2a962c7e833586ec3f19bbfb6571ce9475b26041c865a7818ec45fdbb25fb1b5021a6e5b7c1' }, 'config/everspring/sf812.xml' => { 'Revision' => 4, 'md5' => 'ae3e1c1ea273b60314aaf34a828efd3d7cc4e1c1c9c2144353f1d7340af646a12651d18689a48e96a3e3045dd5eb3591e053df56ead016077d50b284e305bab3' }, 'config/everspring/sm103.xml' => { 'Revision' => 5, 'md5' => 'b4db68039d5c8b96246750b126efd8f526bc8ed1a502fee3b0f5bc299076165cc26a727ffad606c3c5913900196e8a4119903b56052e8ffd9f98f64338519eb2' }, 'config/everspring/sp103.xml' => { 'Revision' => 4, 'md5' => 'b7005e1785178e4def11ba6d4148b7c3ecdf82cf3205f6c7752d8ca5e5ba46e2efe1dac837cd99f21963837e95a396bf2698640eb71f086745c3655348940355' }, 'config/everspring/sp814.xml' => { 'Revision' => 8, 'md5' => '1eb7a9708bd399b1d76a9b91b48e82367b141fdba05c99200038ecc3a425bc459c320bdce5ebbe8ac9496e1eddb5d9faac0119ff5cbe4046ae4553ac8ef397aa' }, 'config/everspring/sp815.xml' => { 'Revision' => 3, 'md5' => 'e8ca9d3c02c9b238f2a8198eb349389cc8b83fe9c95639abd361672a27b32fd901690c03ebdfffa6baf3f9dbbe76d8090fc7ff6baeb955d5775211f0e84a27da' }, 'config/everspring/sp816.xml' => { 'Revision' => 5, 'md5' => '2a6bb41379abd9b55599ad5bdc59c756c24ec41136f5fb797f8c69f35d32b04f81c1e79acae22567d58e2eb5cfd79678b13185b9762217733e41b04ba453bb09' }, 'config/everspring/st812.xml' => { 'Revision' => 5, 'md5' => '1c44712463c9a810bf6bf9dc55eb4427d76fd0370148bca22798bcc19a10939ab6e4ad04204a300a800d40c9e72a4df1dd5326497a78517324e22b7a5b8c7201' }, 'config/everspring/st814.xml' => { 'Revision' => 8, 'md5' => '92bdd7c1bfd0febe8e67fc4f0e156456ed98fd12a3e118346416527536faa79a77ce207bfdd056e809e76218a65483f6b227ed2b3748a7090605fdcd1ed30036' }, 'config/everspring/st815.xml' => { 'Revision' => 5, 'md5' => '1dd35980d8278ca67d8d81d9501d299dee9c3362797f4cd0614b9570ca39264e7d6ab20ab0823ad130449d361249b57c31e0c99d6e9ad6dc1a8f57f8df4f74ed' }, 'config/everspring/tse03.xml' => { 'Revision' => 3, 'md5' => 'ffe2ea7bb8e42515f36eae34c2911ce3a7130c07065088559a1766895eb95bf3e324a3cea09f3009c490d5a6b09a960581244700a662b37942d7a0389162bb06' }, 'config/everspringct/hsm02.xml' => { 'Revision' => 6, 'md5' => 'e131dbb42620861a8f91b6a2146b83ab32d0f721f733529bf11bf4d4961251c7d11fd2df79e288145cd2a5ba92dc761fe9b98c6c9b76e0f8beac4bfc7053fc68' }, 'config/evolve/lfm-20.xml' => { 'Revision' => 1, 'md5' => 'e0e7192e0013c6280d2dc866cc5db6e4f4746fcc2457e13cf2f0fdc7d454e3924c790b5e832876015a11ca3fca6bf25dc979bd49d99e68575f9c17f442c498c3' }, 'config/evolve/lrm-as.xml' => { 'Revision' => 1, 'md5' => '648bb59f6ccc9fe8d61207f67a46898eb22315463b138c410ab5e20bf3a23c48154e50039d23cdc106bb1226ada35875072988e84227c767d1c475dda329d35c' }, 'config/evolve/lsm-15.xml' => { 'Revision' => 1, 'md5' => '375c317a73b812f1766db89385ea6810cef5eb5374ae5e68c01a00dd5f9ed6954b33150a55dd1950ee2c547d95cf0cb3eeeb5f1400c08cbfe399cdf58adb0dde' }, 'config/evolve/ltm-5.xml' => { 'Revision' => 3, 'md5' => 'c0dc3a85b7da4e3bd36a877f968ebe8f4315376349793d6d0f7e0d9b8bbbe1a888473c0261ba67dbbf6ada1f65459ef273e29e48643a30696a4ed0e2c0a674f8' }, 'config/evolve/t-100.xml' => { 'Revision' => 1, 'md5' => '7f807187a53ec217bab2de7a8401670593d02226802cc5ef897fc7f7e5db58925deaa2c3ce12353305c8029b67aca240c0f03c55673f0c39265359b7f2f8e3ed' }, 'config/fakro/arz.xml' => { 'Revision' => 1, 'md5' => '5983b72ce936031edbf95af40b9a1141b1a4b902d85387d1c93878a227cb850eba1616606f4acf2bb71d77d6d53943b43312ef960dd98586f6fa54c6765ecb0e' }, 'config/fakro/arzsolar.xml' => { 'Revision' => 1, 'md5' => '45ea7e674b111811160d58f2677a643e67e1c0e95baceb3f05b6256f4621f5efdf22740644e347689fddfbdefe9c024bc1fae47ce4411c194af79598e8ea2688' }, 'config/fakro/zrh12.xml' => { 'Revision' => 1, 'md5' => '27769984df864ecddd0076acd107085bf13267952adb28bd00c1b33b3a00556f935eb740adaedbcc2d74a20bb34af26e68390788e29012befc9485c08744c5f0' }, 'config/fakro/zwp10.xml' => { 'Revision' => 1, 'md5' => 'c841afafac7b5636e538cf14bcc2c6ae28e30ee68aa865887559cc46a94a628d091fdeab1af02fe2b6068baddfc64c9689c70948a604985515d96efaca5c7d71' }, 'config/fakro/zwrs.xml' => { 'Revision' => 1, 'md5' => '08b86b5d4ec15f2f1eb34441beea264589f7503a88213db36e02619cac3b191ce77dab68ea21c683fd6a6caae25cd5886c49b1b85452663c6dd2bc2c757a1843' }, 'config/fakro/zws12.xml' => { 'Revision' => 4, 'md5' => '2244930ec5075941e48029016e4d03f4003ed2c4f354dbe14422b067fcb09d2d083716e1ed583b5bec8851758cdd2f7c634c926280dcf4c97521a3983f19469b' }, 'config/fakro/zws230.xml' => { 'Revision' => 3, 'md5' => '38d4216b7e3fef3900f637ee4e173c241ccc734de5e1ae85fd5eed95e4ff8d2aef08ec5229aaeb3712905e81ce5fd725b45ddd8a8b959bea21d756cf72b9b5f0' }, 'config/fibaro/fgbs001.xml' => { 'Revision' => 4, 'md5' => 'addfa55daf406a745a852792ea34a1a6e83995d7ed3755789a7f29081833e1c12b5599b537dbf3cd36dd2d0d41d145f6174fda43fcc22b02361fd6dda7e1d425' }, 'config/fibaro/fgbs222.xml' => { 'Revision' => 4, 'md5' => '9e7a4798a3f538dd041de9528ae8d948b6852131b8f73f7b9db0443a3eea9eba5b3fa16ad3282b23a4d817f44c470258938282c402f2c079a0853d2a18052231' }, 'config/fibaro/fgcd001.xml' => { 'Revision' => 5, 'md5' => '94e7567c5a4c746afb36a90bd8f5879df6d8f95f6e2241d3fd50accd32b3c363aa2cc6454e51facfa5b17469385e9774622f7605566577692c02f40ec3eca2d5' }, 'config/fibaro/fgd211.xml' => { 'Revision' => 3, 'md5' => 'e579604d1d754bab281b4f701ca02b7f08a4b89692f4122defcd1bed87acabd1d73aa00d1f76986c6d4bd01ad2646a1369f305e793ddbcbc9e212cbe920de42a' }, 'config/fibaro/fgd212.xml' => { 'Revision' => 14, 'md5' => '21d87779df4aaf0c9619b9d3260b2e1500cda54534f89ebf272f154afdfb1fe2163107968376d9de8f43203e4a9ca45f0ffd1f5226d4690c443ca87edee630bb' }, 'config/fibaro/fgdw2.xml' => { 'Revision' => 5, 'md5' => 'bf766ffd85bf105faf0aa1e391d5d747d9fae52479fd52a3bb43dea64e5634113c730066ba200bd03e28922b7a1e04933edd53dc9c84d7f17164cbc378694597' }, 'config/fibaro/fgfs101.xml' => { 'Revision' => 4, 'md5' => 'e5e06eb03490aeeb0e25703fe67cb02cfca4046b8ac618012f3019c5b3468c74aab0daec6017b0265eb75ed637d229d9d1849aae8fa4b95b1b5f9c6c7b9b6f43' }, 'config/fibaro/fgfs101zw5.xml' => { 'Revision' => 8, 'md5' => '28385ab08db45cb56171e3f9130f275fa3e68fae413150a8fe274e45988092e4316e8a727e208a9a75523719d66a187ba8387c1567ccd5e19fe7fe72a5ee7882' }, 'config/fibaro/fggc001.xml' => { 'Revision' => 3, 'md5' => '050a8006717af518041d68f2055eb5adcc759c077a0ff55ec66218b7f049151189d0e7896b66e1bd72ce6e6bd42eb7a071f300096e02a3e92feda34a7ac588d4' }, 'config/fibaro/fgk001.xml' => { 'Revision' => 6, 'md5' => '675408571e8f8fc679fa60b304c79a103c12b4dd4880d896e45829387998ceed01379216c916bddea2eb7d9d5d1d4fa4cc0315e979a8275e6fce25b179535c26' }, 'config/fibaro/fgk10x.xml' => { 'Revision' => 4, 'md5' => '15b64a691b43a5c3a24753849d6721aa3241ccbcb6a6d8e5d43d2222ada1dc1fa0b08f5bdded9efc5de56391825be228435aacd6f7859b419ebfb4f317f0cf56' }, 'config/fibaro/fgkf601.xml' => { 'Revision' => 5, 'md5' => 'b477def6a8d30e0399f8b4917b6c8317fcb2658b24f702bf8c1591b54b8a3d0ff4bbeb9e9790227d1edf2341efa9e123669644e9ee39cda91e869d42f5f14642' }, 'config/fibaro/fgms.xml' => { 'Revision' => 6, 'md5' => '76242fb913189103b1a368f5a5e4329cd443136b0b38e67286867e4170cc75527549130b1683015b93fbce90a7c9f7a95b3a22d3913c322e4730f44078b1e1f9' }, 'config/fibaro/fgmszw5.xml' => { 'Revision' => 11, 'md5' => '0adefffe86619a91a05a0904132abd3e24c6d367986f082cd08ef0738d340814d209b631c32d1eab4752263f86086c2e0d4110020d1d1be456f12f4abe887ca8' }, 'config/fibaro/fgpb101.xml' => { 'Revision' => 6, 'md5' => '4a688fdca007e02f3ae2e13e11745ab591c4dd4e58dcc9f9034c2de91e694a506cdcc99c4059d94b1f154dde6fbef84d6f800c6189a0e11e75429a3e413c9923' }, 'config/fibaro/fgr221.xml' => { 'Revision' => 2, 'md5' => 'b1ac55805cb99bfd01a6f7a553fe9893e83f4bc1a4f299c0dac1a29e931c41c119a0a81522351e8639881c92225e05170134dab379836e40c36c7f3724377622' }, 'config/fibaro/fgr223.xml' => { 'Revision' => 4, 'md5' => '10d3acdcfb6738324afa2f6c4c0547f29bf04634fbe774bedeb5c160c547168d5ffa1dbfc8740aa4c12c5b928ff2e9d8ca1ca99c5f7f2a366b6e037371a32e69' }, 'config/fibaro/fgrgbw442.xml' => { 'Revision' => 1, 'md5' => '7e75383774d35228492d543a94cbcd4a9652e8cb6b934bab92dc6b1d5b634d518b70370c61cabe52c1ddcc55b741600e90dbdc0bc7982232b5ab641f2b914093' }, 'config/fibaro/fgrgbwm441.xml' => { 'Revision' => 5, 'md5' => '302c58370d2f92b94036178c3c7e09e2506c3cb31ad92b6989a3599de87f80b51d0f33ebabff3a9ce2ae81512be294287265a21c48d0176e5db80eaafd541fd2' }, 'config/fibaro/fgrm222.xml' => { 'Revision' => 6, 'md5' => 'ce4f42d47c38e5743e77a783d0c1fe86ea66b97e5165b922cbb14d4cb66c5b77b6b28289a5bdbc49e1e4ea4fd1634d9afc57d0be660ac1e0d03e6abce02c049e' }, 'config/fibaro/fgs211.xml' => { 'Revision' => 3, 'md5' => '801ee579a73bf981bd3c4b5000642dfdceef3fb0f4bc1f659dadad7dd2f42f3b234ead1d681bf2d0ab18339dbb6ea683ce65d91aedde49f04f836257e3f13fd2' }, 'config/fibaro/fgs212.xml' => { 'Revision' => 4, 'md5' => '6b9c4b6b47544b2acdb0820ae6e914b6f25b322e88b99e48392e6968d0e57203a051870bb87c3345132385e48d18597f829c4790d21e2b270babe9b92d9faea4' }, 'config/fibaro/fgs213.xml' => { 'Revision' => 11, 'md5' => 'e41844de98b9d3c13bdce42661f3126dd742e92e834255ba4926a69a305a9d6e0f629ff16ad7018b1b299e03294b21a7b2250e68278c3f2e2f8134c46ffa3119' }, 'config/fibaro/fgs214.xml' => { 'Revision' => 1, 'md5' => '6c14728668387d7e7a905dc8c360966afe1155006a187fdaf27b639980d223d1e351f87a13cc1e1a8b00be318a73b74d4467b695aa40ef5f14b6ddec0e99f3f4' }, 'config/fibaro/fgs221.xml' => { 'Revision' => 4, 'md5' => 'e0260bbc99a7eab473a1f80f9398602f6316c00f3f2177ea76bbaf240dbb831cfe7f2ce9caddec53a05655ac6e73b5c36db55f1218f8a0d2c2bd0a4c062c8f4b' }, 'config/fibaro/fgs222.xml' => { 'Revision' => 6, 'md5' => '1d4895013a2282e732c1bcb84c75157043064d95298f1469c54c133f504668ca818f1aa4ae2abada77a0712b7a62abed883f53d9ac81617f2c8e6cc7b6b07067' }, 'config/fibaro/fgs223.xml' => { 'Revision' => 14, 'md5' => 'a20bca0d2a4fbc249391a9e21197c4481e7d650d90cf6f52a9c10f6783b576b083a7979178ecff6e64e17a6266e197f155105a8b57c5346e404e99db3de395ed' }, 'config/fibaro/fgs224.xml' => { 'Revision' => 2, 'md5' => '5b877ff52fef4c7db0dc43daf33b157d2a9c17caf310b9631465371d80f81bf73434aa5de944e3ce45349f52b4a4edab88461551ca39c6502f03e9255d0fe416' }, 'config/fibaro/fgsd002.xml' => { 'Revision' => 7, 'md5' => 'caf23b9d5714c41757a472148801faff4face27a0b9963b74363bd2fc78827d2073f47f9e0f89745713d19234b48ea80ecdfe3e1c100a156962468403f7dfd6c' }, 'config/fibaro/fgss101.xml' => { 'Revision' => 4, 'md5' => 'b3ddc92e51ee5a0ac5eba30f3cdba72f8c8aa114b2b474f3d7096d0092ccf9ae8ce6042e8f6182f4a07129a891e6dc83517be0d5d67bda91893ec0bb210f0f45' }, 'config/fibaro/fgt001.xml' => { 'Revision' => 6, 'md5' => 'dcf003e4bbe58bc3e0e706801a0734095db4ecf5a40c73ce5dd03a2a3ae9cc6e6033c87ae08b6d7c8575de5ee8fb56541496c584d676c6203ca29a98546b98cb' }, 'config/fibaro/fgwd111.xml' => { 'Revision' => 2, 'md5' => 'bf6d95da83aad31068f0f62fb3abf1d03481f63dcaa347f8fe6a38cc8d4a2bd9a3031722f9a4e73cd6823dc151fdf30772c4c3b5d4f06bdc6df3120389091057' }, 'config/fibaro/fgwds221.xml' => { 'Revision' => 4, 'md5' => '9641565fe4eca688bb3f0b73acf0a425b1f301f68c67e5ec8af0255457e9ded311aa311c15152700e3fdf51363ea8c04ce397e79426b2c01d75ab8193d2aae16' }, 'config/fibaro/fgwds221ss.xml' => { 'Revision' => 1, 'md5' => '044ec0227f23e478e9d8315100cd9a4bb6886f94e5b7dd8077133159ce99a042abb6075ccdd6a03639e2e4681f5a21cf0bc3a6005d143195de829c5b799bff78' }, 'config/fibaro/fgwoe.xml' => { 'Revision' => 1, 'md5' => '117d888dee07fa6b24bf1a69a144e631921c7f06ebdb0e90632560ecf45872eabdc82e2821d734f260585c660dfd47737c5948a44c9ed21674e13b8e1533824f' }, 'config/fibaro/fgwpb121.xml' => { 'Revision' => 1, 'md5' => 'efc9063c630e257e314ab3676517cac800807248d605b92be342b98fcf4562c9cb7a872c71970fa4953950466a29c5b6dfefbc11077a7dd4fb209a99a4d267c6' }, 'config/fibaro/fgwpe.xml' => { 'Revision' => 6, 'md5' => 'f099c34442fb3d67723c59cbec6b31d2d383686b583ac013607848e3d8dce2a9628dd96a10751a027cf8d18c4714b0272dab073dda20302b1dc5820f18273643' }, 'config/fibaro/fgwpfzw5.xml' => { 'Revision' => 5, 'md5' => '61fc9df991d5a091c0a05a92ea37c4f76d18e52d9cc9252418b5525a32f48cc8cb9815a42b05de2fa8cff62665db88094eb4b99114d5c157671337e12a8230af' }, 'config/fibaro/fgwpg111.xml' => { 'Revision' => 4, 'md5' => 'ff622cfe98037421901a2087f85d5d7272f3fc0e1c77c5b357708588cee4f4f47e61141c833c9b7af4734f2ae109dcf2e1e3d44bc6f6d4a39450ec5de8de5ab1' }, 'config/fibaro/fgwr111.xml' => { 'Revision' => 1, 'md5' => '14e1efc7dd30097da9adb3b5c69ea5c114ea63806004f553c701cf7833aeea730b4fc1cc30913b1cedcf1e2e88aa2f7785cef3384663df68a879a0a3a5b184e7' }, 'config/firstalert/zcombo-g.xml' => { 'Revision' => 1, 'md5' => '3aafd7c7283dde9c093a55c0c6e0cc0c8f221e9b06f647cc151b97a4bd4296c2715e89d9c62886d275f213376e2e3052a23ce05ed027a181f054459fdef0e3cb' }, 'config/firstalert/zcombo.xml' => { 'Revision' => 2, 'md5' => '6550cacd482668a1c7561434bf094255cabe30b5beda26c406e2f9f5a772fb19176f2c0b28824f9015ee64b0d4f737f5f9b35ad2c133852f7286160ee337844d' }, 'config/firstalert/zsmoke.xml' => { 'Revision' => 1, 'md5' => '419d50ff831000b5b2ad8dccc3841dd89cd1145186c7180d98d3b5071b02dd4b94ce8c12c1471ba7cfa4243a3e46c63779f5e31d1559e95f571f471dcf32c2d2' }, 'config/followgood/swz-1002.xml' => { 'Revision' => 1, 'md5' => '3142c3cc8cd97d218a3f3a31d841d308ab0a51291fa2a57a3c13c3cc45cad79350d958463bd1667d596a99206c5759877a7423692e714437e922f9aba5bee6ee' }, 'config/forest/fs2z5232000002.xml' => { 'Revision' => 5, 'md5' => '5d023a7e60f4becae275c45eca40de4772fa5650f13158727dede39a8011ba03000e5ad3941542279978f6348d3f85bfd45ad6b02a0185e612b1662f6a4bb25d' }, 'config/fortrezz/fmi.xml' => { 'Revision' => 2, 'md5' => '8f7ad8fcf6fdf93c1228bde5f5ad12cdd4f6681ea96e2fba2e59da2b84b9a9ce5fbd288a1f3a859ccc640ad77c362191b3ded331a15c0cd15ba1007c4ca8d4c6' }, 'config/fortrezz/fts05p.xml' => { 'Revision' => 1, 'md5' => 'bd74c940439b0e3c77c83b9bd2a0d4af6744833f3e4dc4ac2726f0b319bec7b12b9ecd19373bf0b0cb8c094f039604e429826e46038043a11cc81023fe78c1fb' }, 'config/fortrezz/gdc1_fortrezz_1501.xml' => { 'Revision' => 1, 'md5' => '48bfe2a8c75fd3c17a87bb4405908dc9c835c131d7e8625760b93a8c8d4f3d6895cc8fd8483913bfad697d12811f42c82b9ee41168baf068ef2616d4bec65800' }, 'config/fortrezz/mimo2plus.xml' => { 'Revision' => 2, 'md5' => '6016f3d62b2d67fc6c21749852db2bf0f158534a6aedeb5414e2e23b073ec505b86653725ee4ca69b61b0d2577b6c2cbbc09a390e00babc6d813052cd7c6ff84' }, 'config/fortrezz/mimolite.xml' => { 'Revision' => 5, 'md5' => 'f8643c66c280f96588067d67f33ae3aee81243fe1ea5677ca8f8b3e0f21282cc968b98af61fe5a1772a6ac02f00ad44d9c130caf15552e49d40879419cb703fe' }, 'config/fortrezz/ssa2.xml' => { 'Revision' => 2, 'md5' => '8b5fb147acc63d0dd5fbbb34acf4efbc4a2fafa63d1ee8970da52a216c912d75b35fee0c624eb97d64e8c8e4fa08998aa193a7b9f2beec6a354a2902309f72d1' }, 'config/fortrezz/ssa3.xml' => { 'Revision' => 2, 'md5' => '96196cd391eaf93e6b87da39636f574a4613c0581987f2a680f592b8d4493f967068995df52eb54b33930052392725b563b1c9de2c4acbdfa26895cad24c8f16' }, 'config/fortrezz/wv01.xml' => { 'Revision' => 4, 'md5' => 'e7ef958f3c88e40d69704871967293baa75c03b1118b80cc046c4ac3710b1cd1503a465bd1c9f475caede7a926062c2b72d811f4e26864e45b479983631fb59c' }, 'config/fortrezz/wwa-01aa.xml' => { 'Revision' => 1, 'md5' => '822a106d8f7d792f2c1f52252ffc941d2c27a17ea182c403b2fb212ab42d18e7083e079f2b250f45f587509c95b6fbce43ddfe1c02f66734084ba5d07a495c1b' }, 'config/fortrezz/wwa02.xml' => { 'Revision' => 3, 'md5' => '4bab32e79691a880d38d91c7501f0cf98b6e2e60b7a2004ad332602bbd0f33bd8fc4861e4048953e2e9c469d765a6f9e6b65c3c212a0e3f6e9f5e1f4126655cc' }, 'config/frostdale/fdn2311.xml' => { 'Revision' => 1, 'md5' => '79f468d1f50721b8cbc723c77fc9902c727376cfed82099e821901ffb81e402d6e1213486fe9f0c2c6f8e39b3954327c1a87ad21a705036dea8927e84746526c' }, 'config/frostdale/fdn2nxx.xml' => { 'Revision' => 2, 'md5' => '2cfaf444e663bf9f6bcd25d8c08ef14163ea9c938c106556ecb6bba22641bb47b066c323bba6c7db49f4f731ee12eda16648ab9bd8e0b3f1bf949bce8fd9cfeb' }, 'config/ge/12719-plugin-switch.xml' => { 'Revision' => 3, 'md5' => '17ebbde5eba4998fad0e35f252461259606ca8e88d0eaca3437cb3ccabd36797b28671660bb7955349eaff19cf617d86f20318693d0766f7c56a14998d2c43a8' }, 'config/ge/12720.xml' => { 'Revision' => 1, 'md5' => 'dad8cc08440a1f5abde69cb6649d45eff1059ed7a8e58ca297192f20e89941f8fd09d2ab491781ae0ea2fe840123f782a0881a2ae75e3d79f7e0de6f63ab9710' }, 'config/ge/12724-dimmer.xml' => { 'Revision' => 11, 'md5' => '6568fb1fe307b61db6b8a4f9f068124bf6dd7a9fae99a2fbdc008bd25a4a2a629e53b379f0ef1e589bda4c871ffbef5d8e48fc9ee4c8fa35a855d4a3fa6493c5' }, 'config/ge/12727.xml' => { 'Revision' => 1, 'md5' => '2f1fc4587bf2caf5d982f45535996a36bdb93adb7de8f089e9ca8bc042d91e45677bc2f5997d125b3eb1e93f533c00637ef6d7106a9c456878aa8523ac52dc07' }, 'config/ge/14280-plugin-dimmer.xml' => { 'Revision' => 0, 'md5' => '62c479d852b5e22ba57306c3877ca58eb247528829d02022d8796c725a7b4964c5acc4f829ea807fff291182777ae271a29676145933fe78fe80f7873d597e2b' }, 'config/ge/14282-plugin-switch.xml' => { 'Revision' => 4, 'md5' => '72ec968ba6c64f65c48fc8ef9fa33f623717bda452d0685547735dea6240ef4efde6a1da95f683cd5fe1efdfaeea834a13412482a305c05423c21186c7edaa97' }, 'config/ge/14284.xml' => { 'Revision' => 2, 'md5' => 'cd3edde334dc3c489b23b3148590077b6e4f3d2a50fd3530fac2e140a956ae6cc41ed1d435ea47388456d955d7fcccf0a399225d76d1e58796c36e406d42491c' }, 'config/ge/14285.xml' => { 'Revision' => 1, 'md5' => 'f3a27a970ed353ce1eeb8c70a30b9cea0ec86e06fdc2a603291b92139b4ff200ba60af992b156660e7c8237e59b0bc2337ae517e22f821088c3ab1d80e3ee71a' }, 'config/ge/14288-outlet.xml' => { 'Revision' => 3, 'md5' => 'd9fb1de64ede9d3da8730b73e67149d87f383aa45d878cb1fc54fe59cfc4b636577f35c58823484f3d5d830b0080aa69b4c86a934225c521e11a7f81ca07fb93' }, 'config/ge/14291-switch.xml' => { 'Revision' => 6, 'md5' => '26fbb25b684f516c6ea4b2ec40af67ddd8d2d6870a65f18f4db0fd38b38eb508f8512da9dc96a4e0ffab200ae02be8cab9178a4617ea17fabd0ac63ee5bb2188' }, 'config/ge/14292-toggle-switch.xml' => { 'Revision' => 5, 'md5' => 'a0fa7333db77747a5a5cbc70860b04900739c52c015d8b4d6a45b36a275469285672f70719b7be61de3ee06a1845f9d876b89557aba862c8f3776cd9d67c18be' }, 'config/ge/14294-dimmer.xml' => { 'Revision' => 8, 'md5' => '0acd274b8f1f60d0c2a8b1a704977f27854a8f4346c97304fa89b90eb71aa1c4bbaf1c96d64d1b3b5b9b4d707c521555a173859d31ac733e9cd9b7fda28c270a' }, 'config/ge/14295-dimmer-toggle.xml' => { 'Revision' => 2, 'md5' => '936f319de3f6658b448d9c27ee2b6c639a5702fa2669a750ac841e13e2dc5fbfd1c686ae6805cc231b94607c36781d2bd7214ea81fdbdf10f11efd4a7f9c9848' }, 'config/ge/14298.xml' => { 'Revision' => 1, 'md5' => '24da4dcaab326eb2aec592f74c6db3e51d05108773b6613a6f415760a93fdd98be579834488335ed3efd2f987c20f316284b39b1a8c659f67e83895f50021044' }, 'config/ge/14322-dimmer-toggle.xml' => { 'Revision' => 1, 'md5' => '56f3d865b46562564dcf28bafb2449704e0b5df1ed57025d0cc54e0c865d4a7f8b926c03e0c60be4b47f1be0bac25a5e3ff5ab4a8706d0c910b8b710f9ca12a2' }, 'config/ge/26931-motion-switch.xml' => { 'Revision' => 3, 'md5' => 'd29b700b0b98e93829596b71cc1888534dcd18dc13d057a25a6b5daf8792e156f1d1cd39d168cdf5a419ca6c890ce7bdb22fd341e06618a2e1f2456c4fc5426c' }, 'config/ge/26932-motion-dimmer.xml' => { 'Revision' => 3, 'md5' => '536b5e0151fd2c4c31478e8da98ee7cd7e3e75233f45f2563f37e5463884d636521b67da7a2af87abab15590c877c2752192147b776cf85114aa4ffe8c0da23d' }, 'config/ge/26933-motion-dimmer.xml' => { 'Revision' => 4, 'md5' => '0394fce7c7e8b1b3a5181ca36230cf10ccd13c4a34ebaa67f39df0af12316d58ba9bfdace934a02d6bcb4f8d12d86cba5bc113d0660b06fc833c0794c47e9d24' }, 'config/ge/28167-plugin-dimmer.xml' => { 'Revision' => 3, 'md5' => '3ee59078343932afcb5732ec56eb15c259f360f3a4adcaee1f632350f057581372ba65a0c33ed51f6b239096db43231fa64a439a9307c3b9c4c9e23da0ca6995' }, 'config/ge/28169-plugin-switch.xml' => { 'Revision' => 4, 'md5' => '58980d447abb1f8c82167ba043aec5546a8ace8e6ea9f4129c521b363ae3aa3d7c723c64901af5c6bec6695d7f0aa85e4975ca318da9016deeb83cbe6aaf5e59' }, 'config/ge/45604.xml' => { 'Revision' => 2, 'md5' => '1a651b322ebaf4de9f8b5a03c9604cf55e6140cd1a64f45814e6e8818d83dc4e0988f7f8ffcd318ca3d9424f24e78250b742fa87025f682e22560e1774d18df8' }, 'config/ge/46201-switch.xml' => { 'Revision' => 2, 'md5' => '1ecb7e32a13de469936cf4bcb1fe12da5808a7a431caafe2687632755a8c7b031c6a14a8848ac11115fc2589c45ed408f7cb7bb0779133b028c5f66e201fd835' }, 'config/ge/46202-switch.xml' => { 'Revision' => 1, 'md5' => '0b52e54d014cf6ca5f94d2f0ac130236625b2ba575d8edb955a0a682b358a1c30b481f23b598c31349068aaa95a5a02ba76d074f7c0ac1ace38dc3134b584a3e' }, 'config/ge/46203-dimmer.xml' => { 'Revision' => 1, 'md5' => 'e66fa46f950b4533040b0bf24df89bde1fd624c7cd4ce92cd88721e31445e8cd41676f4dd0bc4587dbacd37a462bf9967651cc0bda71f1d7a6c089893c50fd92' }, 'config/ge/46204-dimmer-toggle.xml' => { 'Revision' => 1, 'md5' => '3fc29dc416cf95fa427f0dadb5c5676bc42cdcf148072b0d4a7d37c1034180410c60ba767bfe27fb262a36c276de262e2ebdfd70ab0301fdcf2dd38e655250f0' }, 'config/ge/dimmer.xml' => { 'Revision' => 15, 'md5' => '69d688ae37c8887da28d801b24305f9bd81ee1f9b1cea214c492340ded4144263955f4325a229b33c22d5ac0a7f327b358cd0bf2100e4d096e9772822a0960a1' }, 'config/ge/dimmer_module.xml' => { 'Revision' => 6, 'md5' => 'f917273cfc180539f9dde977978e68e7ec54f30d2ef2378a2795f7c4519f93d52d9af4b860c190ef059363a562bd105899e3d5464b84b07e52af6ae417216112' }, 'config/ge/hinge-pin.xml' => { 'Revision' => 2, 'md5' => '195127b7310facea584641c8c4b0de9f80c787db87f65ac10a0b0f876fd061014828d7cd32e72d2f9f2eb146deb09e3278ec5cfac299ad1a5586325611a3f52e' }, 'config/ge/receptacle.xml' => { 'Revision' => 7, 'md5' => '3d226b9b6330953a94b786a712451067c0df84cd688feee5d156ae43ef847d490890db44629aff06771a4edad590ec0e12983de15ecdcf64400c499c8b956c8e' }, 'config/ge/relay.xml' => { 'Revision' => 10, 'md5' => '2796184b6ac7fe9f8aceb1a09221cc6a1c8c3844a039a484057dfa71f704ddca8c05b038cb6352f1df9d10972b328dcac6277749d8dc2b0197b4548760db213d' }, 'config/ge/ze26i.xml' => { 'Revision' => 3, 'md5' => '48668adae273d804358eb6ed626833f2576e08b25484914c8b3b5704fe2918392ff77467390677596b541f558779e9cc07b56dd1907f866ac4c1f858800b6f4e' }, 'config/ge/zw4001-switch.xml' => { 'Revision' => 1, 'md5' => '56d8b8c8c7c1450298ce238cd73f0e5782812a48a6794e2fb82a65fc32150862c5283294cd90cf9874b0085ca52dbd620710322dd50bf3e38da3d74d70ef0856' }, 'config/ge/zw6302.xml' => { 'Revision' => 4, 'md5' => '6b668bf119e7f0e6aea6c066294bed1be1e7843e67b1223ad2819691cc5c7aac2bf36807eefb29c996eaa4a83ce05abc93abe50873f835b018e563ddc8dc8748' }, 'config/gocontrol/GC-TBZ48L.xml' => { 'Revision' => 2, 'md5' => '15d627a3d9de686ec39e3cf2cda1adcb335cb6b38ae807106007a69416c45622ccbc9fa06f2b7ea4a9fed73646497f8600cf54e27e879ef90d71fda6fa19d452' }, 'config/goodway/td14010.xml' => { 'Revision' => 3, 'md5' => 'eb19987dcaa0c672fda5d4e7b340481176b132332a21b745628fd735597b6f88f6c6e2c8e662ac3380c0195dc42ebb4e29741f3b43801e3b0dcccadbefbf79e9' }, 'config/gr/gr-302n.xml' => { 'Revision' => 1, 'md5' => 'a151aeaebddc3e1b697ea96f455aff329e374662ebb64849067dd74f50caf3a96d32750aeff1005f7df557fdb6a3f75aaf94190ace1566bae5bb25019719b0fd' }, 'config/gr/gr105.xml' => { 'Revision' => 2, 'md5' => '54bfe047e99c0701d98c2220492a0da6c98d80abb22690916c6de4baad6a0fb473a2ec6f5ec3369e7ea31bcce54828300e43fb752ff5efc867d8e99c2f7be6dd' }, 'config/gr/gr105n.xml' => { 'Revision' => 4, 'md5' => 'ed10e4f95c410c9a6e9b539bcba6298f052c35867326105777ddd9e19d6d7677ee5ca9d2bf862a837b420fabd8b74e25483b637c7a71e35c6974dfe30e09dcc5' }, 'config/gr/grb3.xml' => { 'Revision' => 2, 'md5' => 'a03b12da4dc4cd30c564f72efa4ca00dcdac5c7a7dff878dad7ada0a87675fdc271a1408a5187a5f3349eb4809886b1064b2df6f0b4697b068308a57b337e97e' }, 'config/graber/brz1.xml' => { 'Revision' => 2, 'md5' => '20de3c410b7f5e4230670cc72a74a5c0aa055c452538072f17146558addcb823ac1eabe84ed5e3c5b99520a1263f3e2425a53869d1dc5ea714cf323488e88f08' }, 'config/graber/csz1.xml' => { 'Revision' => 1, 'md5' => '536a0b35500ee8ab596c1093763c408e4b7ec61bb808f73495f0c89e25e038522fd4f35d9869fe5dcf54c51109260d35a53bc525c446040110f771a0c4cda308' }, 'config/graber/mcz1.xml' => { 'Revision' => 1, 'md5' => '3aaf4b40388aa6f23f2b0221f1707c02690cb63ae173fd990604c9456999b75fdaf82f4dacac5f98d2f02e6f21d85c76bc8582a3c728b19465c8d73b7a26a5a6' }, 'config/graber/rsz1.xml' => { 'Revision' => 1, 'md5' => '598bdd923d527543430b89d86d2f0260c26a59017a3f44d7eeba00ce809bf01f9a0161041d1b9745a339dbab0f7f0d8f984504a74dad89921921454273e666e9' }, 'config/graber/vcz1.xml' => { 'Revision' => 2, 'md5' => '3b1ed59b630c3e890e80900dac25d798c48661a01e7cab554777f51f7bd3acb1e11d5adb0170011576b302f52611ea2489a082481bcacb00cebaf5eccb24f262' }, 'config/greenwave/gs1110-1-gr-1.xml' => { 'Revision' => 1, 'md5' => '9dd0a66c0191769535bcda4fc90ed9fcd3aa1858016cce795e92c517641a7e72d210946435f88baac53f37178d9283fafbcc94491394f8de6279077963b243d9' }, 'config/greenwave/powernode1.xml' => { 'Revision' => 6, 'md5' => 'c96db0c34ebba8459e59ccbaf488c3876b9201235936bbe2410dd2b8777bf3ef674777e7f2dad9e80067d4e2e93b435fd11573a2a3d4938d7144e99df9cee828' }, 'config/greenwave/powernode6.xml' => { 'Revision' => 6, 'md5' => '1e575738b3a559c2de13dfc9632fceb800dc03c8ac5691ecb0d0629a57b607d1046316d8ddc3a87db9e4fe1dcae57fab20998845f1b6d699953d555af71d179a' }, 'config/guardtec/gkw2000d.xml' => { 'Revision' => 2, 'md5' => '280feec2b7433f743ebbacfe437dd6b1423b38777141a11f22433e29177b9280db33d2f15a26da0a9b0940c93c47d29dd874e7ae7b12565de709dd73ab669a9a' }, 'config/hab/iblindsV2.xml' => { 'Revision' => 2, 'md5' => '1d8c628927d098803b55085eafd213c946af427b6246eefdcdaf74ea576b17cc72c2d76f0ee6c1a238b509eb0b2dbdcd95fd0924997e760503f115ad65a3b6b7' }, 'config/hab/iblindsV3.xml' => { 'Revision' => 1, 'md5' => 'ff25e0ca31e6e7b3a7ef6739e2175eb31b925b1fe663b1697df37710d07a8b7cf5056536b695f4a6c2a874ac2ede66318724d8f3592b8674ddbd2ecd7c0a0878' }, 'config/hank/hkzw-dws01.xml' => { 'Revision' => 5, 'md5' => 'b11d36a38e54d9c4f36fde7224db3847a5e0bb09e5828ff9ef8802ef1c67000846513ad3e91b2cedcf19e91b95734b4d2864a4d44a32c32bab7b16e4a5adf46e' }, 'config/hank/hkzw-fld01.xml' => { 'Revision' => 2, 'md5' => '02bd96bd02e95491700f0c6efd92fcd89e1c306bacd5d58d7f2f364d0df24bfd034ddd150215419537c7af5edbcf18da75eab1e77a5aff3a8140526fe527a58e' }, 'config/hank/hkzw-ms01.xml' => { 'Revision' => 3, 'md5' => '8a04fdaaa929db3866654b4b01329d13e3e32c449f711b6e23d78ab244106238ab73695e9a7002a80e203934bd1db1871dd6e5541dd944ac44ceb72b6c946d2a' }, 'config/hank/hkzw-ms02-200.xml' => { 'Revision' => 3, 'md5' => '5b89e6e05015240d4ffc671f8b880a0c37dcd4e015ba415cb1e73f593bce38af3cf03c629ba543ec797de41a12af504c06f112db7e85716a07605ddf61950d14' }, 'config/hank/hkzw-ms02-300.xml' => { 'Revision' => 3, 'md5' => 'fc42fa3347826206318fe37b5283d667abc1257b4cf36084d41b876e90155b342b2773af6bd836954bbbbe14002e1346e5b42f39e412a1a347169dc5c947a782' }, 'config/hank/hkzw-rgb01.xml' => { 'Revision' => 3, 'md5' => '35476c9eb132e78674d3e0fea1f757dc4508e0c390362b42fac1670fc6398078983b5253de0cafe95c081daacef41896bc760a3c50dd89905f7bf070bb991e01' }, 'config/hank/hkzw-so01-smartplug.xml' => { 'Revision' => 2, 'md5' => '9c1ab32ee4af6cf8b1d7d3437a9d031861d48952c015fa6fbe2e8c54940c45a718fc669975691a32eb53c78f1acef8dd231faaaca643fd1b22158c5655269f8a' }, 'config/hank/hkzw-so03.xml' => { 'Revision' => 2, 'md5' => '3340deb59e1570b2c07fec06e4b13cf1159a9274f6b87fec2c846388ef9f47ca9a3bf3af2d306202d84e0b24adb226969f9ab6f7f0e7c3a5c916252b1583fea7' }, 'config/hank/hkzw-so05-smartplug.xml' => { 'Revision' => 3, 'md5' => '6dc4cc5e720bb5c534f25510f20c134baffb3d4b1f68704d397bab9775b6b14397471dee6469f230ecb81afd79363837589a531be926a7d3e789e82b4c1c5a83' }, 'config/hank/scenecontroller1.xml' => { 'Revision' => 3, 'md5' => 'e748ff7ae3bb3358e80b863cdea2103275dbf536edbd538963502c7629aaa623c49b562d092cfbf4db17f7fa2f4b191223ad1e9513c86b58b937eb6504145f7c' }, 'config/hank/scenecontroller4.xml' => { 'Revision' => 4, 'md5' => '25e5e4f19385dc44c8d33dd0372837fd2befb1d12b5bab7dc74027a3bc12875e56afdff854c363cb0bdf186aee0f5717af03b6c62f77409bf365176c9e953aed' }, 'config/heiman/HS1CA-Z.xml' => { 'Revision' => 3, 'md5' => '7a20a77d2c2c7633b0a116d68c59325cf1da6cc57f83845d9927212b5864804f0e485775c317ca4728cf901764622507abed325542816aa4ec62b36cdd0db10b' }, 'config/heiman/HS1CG-Z.xml' => { 'Revision' => 3, 'md5' => 'dfadb2f28046d15b412034c106537d03bff4b224c0f4c4808d4af54f5fe045995cc31b1f289c215c34288ea10a82df5a7d9b26a3a20db67859d346a405a55136' }, 'config/heiman/HS1DS-Z.xml' => { 'Revision' => 3, 'md5' => '210a2d51e707e26c6619428919e5e44694c06e15bb2b111a1ef5f499a3f2ad2c4c99fd07482b824ba3dd7d95ab9e2b5219ac1805c1566a52f3ea1a88b6b7fcc2' }, 'config/heiman/HS1HT-Z.xml' => { 'Revision' => 3, 'md5' => '1331770135d4050f99c83dee86a0e55f0dc59bf51430f083f2b7ceaad3ea32851b9a915f821fda1fd4b618041bf82c5afbe9cd7f74c0e5b73d0f5d47450008e8' }, 'config/heiman/HS1MS-Z.xml' => { 'Revision' => 2, 'md5' => '0dac77cd6892ddce000c77485c595ee219aef2f83b3e7cfa641981b37e1476bea55855120e19ca80c302e566c58c328e94148ea03e734f8f4d40f862c6e6d6f4' }, 'config/heiman/HS1SA-Z.xml' => { 'Revision' => 4, 'md5' => '217ed29fff544fc5a36fc5d1b26334b84725ad6ff6181e7080731f7dd5c37ebc8d079e37e70e5cd50ac87a014066b84978ac3b0d7b080dee55d12fdaeb8db019' }, 'config/heiman/HS1WL-Z.xml' => { 'Revision' => 4, 'md5' => '6821d6247218a026a8832f72df5c2b3f76abd2b3b95b18302201c5bf7e0fe1fbc22659078056f5188a42981304d635088e2018c5bea98565c19a45712524cbd5' }, 'config/heiman/HS2SK-Z.xml' => { 'Revision' => 4, 'md5' => '2717377bdd18d9b510f85c815d842930080a10ee319f64a43241b2cebcb8b7a2a81628ae9b4aafa95719c3d0530eb17e75acac1a444446a14bb829148d7d2bef' }, 'config/heiman/HS2WD-Z.xml' => { 'Revision' => 1, 'md5' => 'c2ce7171aec99ffae507edc6bf9aab24ccd539a25e162c93c410cb83404899bc33956bc3b50aadea0adbc75acbc0e1a655f92b4496d0d2b725b784880e7038c5' }, 'config/heltun/he-ft01.xml' => { 'Revision' => 1, 'md5' => '3cc642f60cce237779dc4e824780c1d4ed36ef5ac691e3cf338f7821338f939723210c56fe7ee97719697ea903162d11d79ea95400c374281b9ddbf2421b16d7' }, 'config/heltun/he-ht01.xml' => { 'Revision' => 1, 'md5' => 'b21edd812c1fb609541f0a740e6d80595aa28b17d8ea09b2ae8337c19bab8d8c1377eb435afbe80b6145bb1923b51f700ce77b354baa050075b8091b2847c1f3' }, 'config/heltun/he-zw-sw-5a-1.xml' => { 'Revision' => 3, 'md5' => 'a4f75b095ae18579fda4a9a5d857466ed83fb0d8a3679945aff2ad419c72c5b96960db4aa84168911ff0cfae551151b38e95a4156782854a9ea3a0db5576257d' }, 'config/heltun/he-zw-therm-fc1.xml' => { 'Revision' => 3, 'md5' => 'c819a5f9e0f64ab5bbde2ad1754b7e9825564f6a7b2b1e63f209c711b43dc5445021c59f36f0a06d4970ee315ad8df1899c74a7934f94a373448aa2a3cbf5bc0' }, 'config/heltun/he-zw-therm-fl2.xml' => { 'Revision' => 2, 'md5' => '1eeee37ed56959421b124f96f69dbed1fe93ed0b230c2b6e0a133bcbb1bc34b4da975ee6f5193e793f46da217a1c0ef81d132f7ec0b8571289e284e98e42c186' }, 'config/homeseer/ezmotionplus.xml' => { 'Revision' => 3, 'md5' => '8d4ea274a67cfc24dd3c20205bd4e2fc8133233ed99fbb2596d7162298c0ad4ed07ab327356fb5a07e1424d6634de27227bc03b70c7a9f06754f82360d854537' }, 'config/homeseer/hs-ds100plus.xml' => { 'Revision' => 1, 'md5' => 'bf724e9e2f52776c8837b1a46d465d2b20bdab25733b1775d8665e00329c82f1b9a194a5e6c2539df754abc90e3c83b6044388e1e7019b2820f9ea3c63e64aeb' }, 'config/homeseer/hs-fc200plus.xml' => { 'Revision' => 3, 'md5' => '2c8076f31efdef00d014a58a4acc35db4e256175c57e2e93c3db183c66f52fe7a47feea880c2cd8723883fa860a540b81bb52cfd17c04072b7b9a5a6e06126c8' }, 'config/homeseer/hs-fls100plus.xml' => { 'Revision' => 2, 'md5' => 'cdd48d1045234e40dc257caa0df6eff883426833bb19d55587da53b78e9362eae2699f3cddf4b25f6aefbab24d06c0fe34ded0c7bd12b03853a2c965193a754b' }, 'config/homeseer/hs-fs100plus.xml' => { 'Revision' => 2, 'md5' => 'a749528efc1e275c53dd5d2dcfac7f005798172775756a54676b25c732cd22db548d4c3ff45118904d08c3d34f6c4195a5528fefe74a98b13395d87f93336bdc' }, 'config/homeseer/hs-ls100plus.xml' => { 'Revision' => 2, 'md5' => '05e3aaee1cb368211d1e4867149f1e914bdd7d5da5e558bccfc9bbd60180d212ad0c76b1b95095bebd074e2ad64b52e15e893ef65c73e765873f0e73219d8a25' }, 'config/homeseer/hs-ms100plus.xml' => { 'Revision' => 2, 'md5' => '528e313dab27daf86c92e7ecfbf311077842bdff72f662c308d0554a308691b9a9c5830bc08dab5a4860991053c6a73b05d5c21f1cf115a8c70c873adeb27a5d' }, 'config/homeseer/hs-wd100plus.xml' => { 'Revision' => 8, 'md5' => 'dd1aeca42ff3c3465442a45a0da960632ea52301b5514cceec9e4d58b47a8fc18e7ddbfb1fe06b191ba10f32cb91d6671e125bde7ce8e99e5603703124b29f0b' }, 'config/homeseer/hs-wd200plus.xml' => { 'Revision' => 2, 'md5' => '25187da0fac3b2752ece5aa716e0a883577782ece97e6bfb604faee0c2155690ffd837ac0ed19afc00cffcdf2145b260797b3446620e12f4ddf3dcbc7d34d818' }, 'config/homeseer/hs-ws100plus.xml' => { 'Revision' => 4, 'md5' => '8dc36ef5c448b933464a3541eb156b4f9bf8c99b87f1e117ac1b881056b2cf03ddd53a7a6535a7f88210956a15c51ebce71dd5bf89daa9daac3ef2e27880e727' }, 'config/homeseer/hs-ws200plus.xml' => { 'Revision' => 2, 'md5' => 'a34e0e874f7b7cf55801068535eea231f80ffcb6564c1a6e3ef4fe41c7da677c00340d456f4b79a413e657bce7b8847b6d7f5b293c7a8a0309713f1cd3872214' }, 'config/homeseer/hsm100.xml' => { 'Revision' => 3, 'md5' => 'd3078946530995d9f5cf1fc432617617466d8d100a3a368f619bf4762c62ba852d20a4c0b9c19321805995f4f3b15d4bdf98efe3e4c1fa7addad3aa6cfbcbdb2' }, 'config/homeseer/hsm200.xml' => { 'Revision' => 5, 'md5' => '05846519da65becb8e4d36ef93040bb190fc7e599e11dd1a82619a7abde98fc3393d80f08160d74911b0090925c4fe04d419628cb278feab92c586262bcd7be0' }, 'config/homeseer/ztroller.xml' => { 'Revision' => 1, 'md5' => '46f0c29d16537254242bd4458489767cd57709b2d0c5faf5ea6ba92778d35362c72e998352a92964c67c81b9b819d66cdac55131154028d5928f0842c96f920e' }, 'config/honeywell/2681-plugin-dimmer.xml' => { 'Revision' => 1, 'md5' => '45efb5ee352873cfb38af888b7cf532cd87108438131ed6b0645c2950a87429b560ae6794d48a58ced064ab46a9a32e5cade299a09bc49c30991df77b19e2f3d' }, 'config/honeywell/3830-zw3107.xml' => { 'Revision' => 1, 'md5' => '198e8c84e3e9a1689bc73ba0f35ab36fff0960580f9e78adb75b89af347c834abe53237dce5817a328eb7b7afcb5f4e4ebbf44415e05c2d78749779c04b3d486' }, 'config/honeywell/39348-ZW4005.xml' => { 'Revision' => 2, 'md5' => '4d97e53273d973cc3207b3b9e19900a17cb13363ad8e82cfd055ad990604ee19a08128e933ab41be50016a933f83f1b8e4568d562b84d6fd523d76fa8b477861' }, 'config/honeywell/39348-zw4008.xml' => { 'Revision' => 2, 'md5' => '9770a4da93a9a3f137296f4d82f7267a3e759c65f02c57c2d7f8a77311ba07f50ca738b94dcdb942183ca924b4629e4e6581971329911113df979fc69552d94f' }, 'config/honeywell/39349-ZW1002.xml' => { 'Revision' => 1, 'md5' => 'a2fe0efafeb8f38685cff7e6fe32cbd5e9085c21b3c4901c568e085b56177b555478dc39a5db6668060d4da7bde6c6cfa678f55fa2fdd81e0a1a488d01be662c' }, 'config/honeywell/39351-ZW3005.xml' => { 'Revision' => 2, 'md5' => '9bcbbda3dbd837836905a4d6601aff515eae4bd452f5cde4676c490e04d92eabb04abcde02f5157a3f41fcdc3279ac87ca87b7d73c2b422e5e3432a51f140cf4' }, 'config/honeywell/39351-ZW3010.xml' => { 'Revision' => 1, 'md5' => '630d49e09812d18cc61f9def5003fca12afef551ae845c537482305c4da9c47990d8c8b15a98d235b9c66e857f2aeb849ed1581c3e8884eb8afd34b1a0903e7c' }, 'config/honeywell/39357-ZW3004.xml' => { 'Revision' => 1, 'md5' => '8fbcbc2963a36423b42e7dc2938168c5ae752eee37b35f0205ed4d2162f372e58d646bc8fa794e19221da9d3a0c39659cd4951cb5a30310f9ef7969af1fca9a6' }, 'config/honeywell/39358-ZW4002.xml' => { 'Revision' => 2, 'md5' => 'f5b66553b75341237286f46e2c1d7665785f41ceb276a0caf152012ae06957310ae50b52c6caf955c188bceb18ec1ef4b1dda8a440f25624d4c3a668153aed5c' }, 'config/honeywell/39449-ZW4106.xml' => { 'Revision' => 2, 'md5' => '63bb116001f13ab496d811c8835018afde8421fd5b4856069d1dc00461d0b6b5e5bd254cc6721dffe5c51023829f64bbb1d41d2e1b2047729a508e1a44b37c94' }, 'config/honeywell/lynx-touch-l5100.xml' => { 'Revision' => 2, 'md5' => '530fd1b4c43248f55ab6bcc788e80bda83eeeafa515f8b812e07b1f507399f163145ab3337d8f26d6bd7313de6028ad13502c7ae2d07f9b4ea8b4ca730cab0c0' }, 'config/honeywell/th6320zw2003.xml' => { 'Revision' => 4, 'md5' => 'dfa3a4d3afb7baf806b7c97070e9c654e8a0f022cda21ad9c5755c1d6dc1f36700eb3137a4f77e61ba61a8323cae7c9779ff7a7dde49a84da0d27cb306d76f5b' }, 'config/honeywell/th8320zw1000.xml' => { 'Revision' => 4, 'md5' => '423c31e6fa2354ee987cbe7fa2d8f406ae04162bdeb1852eb8ed4c9f88790cb292fa4429488cc395368ebfa139512e6c4f1d24ad2467ed3adca0313fca5590e9' }, 'config/horstmann/asrzw.xml' => { 'Revision' => 3, 'md5' => '4972230ffc90010107288b9772b20daaa43d45ed5a3d8bd76fa6c29feeae2922e12a428a4069d0c6de3fde2faf09bcddada6240b545f438f5023ef2cb1489292' }, 'config/horstmann/hrt4zw.xml' => { 'Revision' => 4, 'md5' => 'd9f875c619feaf1136bc76eada1cd63a3c7396d6fb8d4b50c2515264eca723c0420d7afb58290a8a0e2c4f7b780c154ffddefc411e64cafeeda941494b3702f2' }, 'config/horstmann/scsc17.xml' => { 'Revision' => 6, 'md5' => '689b01ced1d29a5cb443a11c222de099c2ea19ab4d355d3274c5610f0c8356940bb3d97df684bbde76186483ffc7e25af3b5c3df173ce9bebd207a9c3509fe1c' }, 'config/horstmann/ses301.xml' => { 'Revision' => 1, 'md5' => '36f2fdaff9dbb847944983cdd4d542db17602846822d67541265a3bf5d913cbb82b05c7e9c964948a5298e145223820ba029936d990eaf66fe3c2a124ee854eb' }, 'config/horstmann/ses302.xml' => { 'Revision' => 2, 'md5' => '7b929c04ea087fee4dd1c2ec08385d8587f3c5bc7371c684f1f8cdb5bc42c9140a0fa496cd2742a611301f7231e39780f9f3aa2848d52da5f730eb778926769e' }, 'config/horstmann/ses303.xml' => { 'Revision' => 2, 'md5' => 'e8ba07277647d361613657702f2c181c3092499e561aafb2c612ad106151609487a39763f477a996952daaf8e5ffb3db810280dac73eb77d2f1cc239d7af6bce' }, 'config/horstmann/sir321.xml' => { 'Revision' => 5, 'md5' => 'a3f4c5fe213ca7ceafee96eae84b01c8146f72e3e5715e8a0d9added2bfb6640a868f91c7e743172df177ac6c61d237112c82768419a8ceaee2305efad80776c' }, 'config/horstmann/srt321.xml' => { 'Revision' => 3, 'md5' => '322c5d1195a2aa4de8a792befc4103f048280c914a6bc0d237a7dbec8d14a4ec26cdea4274082011a041d88ec22fc288b0f856719cf59fe343b9b7094861c386' }, 'config/horstmann/srt323.xml' => { 'Revision' => 4, 'md5' => '8585cef3b015848b99920976e699e68bd519bca47fcbd11c6059d04a3629ca99428119965cb060848f1b2eaec49052bd8a4c7a537c083769dd30c132baffdcc4' }, 'config/horstmann/ssr302.xml' => { 'Revision' => 3, 'md5' => 'b244edf548e853864c9698958e440fa7e4436c63806296e39b2f70ddebeb1dc591e7f13456edd002911ccc5f945a8fd14b2ef9f18f4663816371a17a424b5027' }, 'config/horstmann/ssr303.xml' => { 'Revision' => 3, 'md5' => '9375b06248963dddbb3bc64fbff19537cc4ef6e4c4e7fe946ebc8a40280ea32217104d2ce4eacc12449e9ea3f943aa9e38447d18215bf2dd1cfd40c242dc73af' }, 'config/icare/zw-66.xml' => { 'Revision' => 1, 'md5' => 'c35e93e83039a1eb91d700668764769e8117761b626b894f4fe18435db4c12e95934af23cc5983282c49f1cfd55edb397b84ee5ec05fbdbae7805e0df4b42ffb' }, 'config/idlock/idlock101.xml' => { 'Revision' => 2, 'md5' => 'f9fbf4ae903cdd0ee79fd4e11621453ea66777e729e85d437bbe76892984eea29514b93574f11dde87c478c05122c4f125639e44753dca567cc597b0c79d38e0' }, 'config/idlock/idlock150.xml' => { 'Revision' => 4, 'md5' => '4e8b8082701c3a3137ced8f7636c82058dd9b9942f28125b6dd1d3c3147b7c01ff8c15c982f0781e1fcd4089db341506e318dbf1066d7e780caa2b7a0b3fdf40' }, 'config/ingersoll/dwzwave1.xml' => { 'Revision' => 2, 'md5' => '7fe244aa57c478f25638817f015d2d5d9f83a6f971014de80242a25fd94a35c1e98d3bcc0ad26b69a0677df64993614ee58ae7fe60e6c8af1afe713d4a152f71' }, 'config/inovelli/lzw30-sn.xml' => { 'Revision' => 10, 'md5' => '8b68e4082fda4419b715a2c8f7cf7daf97c9b71303ca5cd30ebe42f856e7d40d076eda2525c0c628e4b07797ad3165e87cbf996a73f29a53e9c53a76862d933e' }, 'config/inovelli/lzw30.xml' => { 'Revision' => 8, 'md5' => '0287fced6b4962a11846d14f3dae6005ea4e7a530b61bfcda8769cb81878ea2603a9d1207efb8103771ca10f539d3f1daa103f8ebbe8178d9f138b9937202424' }, 'config/inovelli/lzw31-sn.xml' => { 'Revision' => 5, 'md5' => 'cd2c997d830c5e66cb1f23856e6e60399b811a8489f1ec94a9d3a5edf6f65047d9105d8cf59709db0890c0140562cee4e88f19ba8b6afdf4e2587cf87e5863c4' }, 'config/inovelli/lzw31.xml' => { 'Revision' => 4, 'md5' => '7fa5513084ea2e9c7231c1df9d2e912a6ba0d472115922a1db29f6faae6027b6a4b1ef4aa82eab3f52fc1aa1d49fdb549eb8a2bdfcb40564a9b6ecc6c5798921' }, 'config/inovelli/lzw36.xml' => { 'Revision' => 9, 'md5' => 'fc8d2062384870d955f1711fff7c3a3e4207f444da331210e57bac51147af9177bb7f03c2bc89a4c1f4aaa24fb17611fac637bab760a542b9ffd743e68ffe192' }, 'config/inovelli/lzw40.xml' => { 'Revision' => 1, 'md5' => 'ed5fb8ad83529a9bf8ec71eab474c84c1816b671ee40b3abf7e8d8438b909e808207d888b6401e28fb1e52a08aa244d5c37dbce11fba6b7cbbd3671261b879f6' }, 'config/inovelli/lzw41.xml' => { 'Revision' => 2, 'md5' => 'b21fa3dee3a882e4ff7e95b446fd95f286857da87d83a273cccb03a536fa7df321f37e2f21c51a477b8a900f9e6b7e61a6b1d313315eefe5d8122654b9b315b9' }, 'config/inovelli/lzw42.xml' => { 'Revision' => 2, 'md5' => '8a255b9f1762edab6edf809ac54964910f02427f3c215bb1def2741e8737b5479eb7ae3673be4f222558f3d70af66e3394ba16958dd9cb1dfd3e3b0c57122aa1' }, 'config/inovelli/lzw45.xml' => { 'Revision' => 7, 'md5' => '06c8a460ef78d26a073341a0561641b98f7bb3b1cdd95e56b1f4ad7a28ab34ca3930a232ba023307090017e1fe85d5d83c8d3a0b0fb93dd4050a81c1f48e972c' }, 'config/inovelli/lzw60.xml' => { 'Revision' => 1, 'md5' => 'd279c5b9dee85d2886f21b484af5ebd146c8189e480b6b676da38a0a3545c08194fab6a6c0b6c4de8f3cf145f2906d774af4bc703cb2dab9815f8d53f05c8b01' }, 'config/inovelli/nzw1201.xml' => { 'Revision' => 1, 'md5' => 'f5789891f9adf7716e6dec82b5764c2869b48fc626b54b9d7bc8eb894368b980c6831073858d82a6155297b4349fb415d39fe4e8a9680cf163802d78fa9e6eaa' }, 'config/inovelli/nzw30.xml' => { 'Revision' => 4, 'md5' => '8f9ed256dc1f56fa42124713e38259ad5ec3a332d51ecc51c99013af7e036cc3b217033a2f9344737282dbddee796fe08975dd15e8e680e619ba21205b1d0f27' }, 'config/inovelli/nzw31.xml' => { 'Revision' => 3, 'md5' => '0b7cb44c57753cdb1714aa7c46208531ff22bdca23f6610e2e662f513254936e447ca0e3887be691c31b8f372022a3b76898672267ae1d902131f4b1501611a3' }, 'config/inovelli/nzw36.xml' => { 'Revision' => 1, 'md5' => '4e2139c9e4c8625789aa15d8238e35804afa8673d2f8e48397660967b30779a60607ef77a5c76bb72b28be1ee6360bb6e34e5fe8f6a3a391a6379bd49f0f7209' }, 'config/inovelli/nzw37.xml' => { 'Revision' => 1, 'md5' => '7c78fc3bf2e50059c24b670adaf755477793fad06821c57b69e6ef554b12bec45940976f6d5a7b4c41d34abacdfd99e5dc2df62154f80f2491ce1935886125b9' }, 'config/inovelli/nzw39.xml' => { 'Revision' => 1, 'md5' => '4e2139c9e4c8625789aa15d8238e35804afa8673d2f8e48397660967b30779a60607ef77a5c76bb72b28be1ee6360bb6e34e5fe8f6a3a391a6379bd49f0f7209' }, 'config/inovelli/nzw96.xml' => { 'Revision' => 1, 'md5' => '668e2faf59ea80cfa66fab415a51bdc25116458cd9666c3a1b9cbe4931f0e6a4fc22fe48d0009f7d152e194567718f3577f39e78b9593e54fa7cc74400029dd2' }, 'config/inovelli/nzw97.xml' => { 'Revision' => 3, 'md5' => 'c175f8a9765bd1411d594988c61846d9f77fbd54518f714f94db99ad9214dd4478003dde586a139b59e54011a60a0313967efa0a7bf0736eb5d2dae565a71264' }, 'config/inovelli/simple_module.xml' => { 'Revision' => 7, 'md5' => '2fb8a975ffe9bacac544ef535b9842f50aee91b1228bd18826b864e6f9d585bf7032c2990714b392d20b3013a04c470edb7922e5f4bedea1756603be824b3650' }, 'config/intermatic/ca8900.xml' => { 'Revision' => 2, 'md5' => 'b2c96148fd6c97c1e7a0d07126d2a7a497b49b56105e00d311dcf885d204f44bbd0673a15b0041c894098cca56b8ccfdcb072946557bbd64877552beeb0e21c0' }, 'config/iris/rangeextender.xml' => { 'Revision' => 1, 'md5' => '771dd895b5d6868c5a2369b1d77f5a567afba312662421b8e9b6430774f7573962fa3a89b2395b48acc6fe9512fd2da3957698af39ffe9196870802b10fa1aeb' }, 'config/iwatsu/ne-4ct-2p.xml' => { 'Revision' => 1, 'md5' => '76e62021a25d51d9fb8963ff4a6bb5bbdf2409e858c95944320cf3a8d0b2100ee4960a1cd404c75617c7f75805c0b27901c43b36b4358173ece6695cd0df6d7f' }, 'config/iwatsu/ne-4ct.xml' => { 'Revision' => 1, 'md5' => '81f5f32ba61a8f41ba1770f8859e774d36ffb27d3508989e2ce7db5fd3335c202293881459e87d9fd9e48957bb0c1035045937e33489ca9a1ec9e9cc664ef04b' }, 'config/jasco/45601.xml' => { 'Revision' => 1, 'md5' => '1f93ef3a4b052f0280b54d95d2f91b8845be7e683d32cb5410cd6cf8c9928642c66450fd0f1d10a42523b21a2e114f8be667775c52418108d717b369adce0d08' }, 'config/kaipule/im20.xml' => { 'Revision' => 3, 'md5' => 'a9b5df85ca3414019c366a874650c0dfc9c1f70f85d5ee75be43b07e6d13204239a0be9872be4cefb12cae00b3a209bbe4361cfaa47355f48be4405c1756014d' }, 'config/kaipule/ix32.xml' => { 'Revision' => 1, 'md5' => '6c73035dfad876c339cd6433337ec8b822da99ec5e4cee641f7c0bea712b18118e58243764df11200aa7745e1ef4fbe38b77f3df17b8a81ec7bc1350d379d57b' }, 'config/kwikset/888.xml' => { 'Revision' => 2, 'md5' => '8e5c2437c10c94ecf8fb026f9e028a0cbc4b3709ce15d7df37abf9e777478436c2fb1feee5a935d8a41e98f1e9adc52530a2f702d08a8caaa80e33b5bc486f5b' }, 'config/kwikset/910.xml' => { 'Revision' => 1, 'md5' => 'fc4d9468508bb971bd24eb0e6b658e08760e04b60e23fbda089a1087e3fd167c92e994ee8c344e8317a5485d81821ed0716f3c2d9dfa21e74ae79785a6eb337b' }, 'config/kwikset/914c.xml' => { 'Revision' => 2, 'md5' => '5724dcb1df68c2809fa3136f2fae556df59be5c75af1fe8283b3aec92239a422f36180f55aafe0589333e759e89b5d1d22b02f10fa0caa27d44b8f1b0f5edf18' }, 'config/kwikset/916.xml' => { 'Revision' => 1, 'md5' => '4f011b843c8e07c72cd0af17a0b4ec1fa8764fcf8ea9e9106a283cd3afc7aa99d8c890ec0429bdae05fef29af0a4f9ba0172c8cce9faf203e774837d6d4758a4' }, 'config/kwikset/smartcode.xml' => { 'Revision' => 15, 'md5' => '25b10ac756242e227b2772b31101c9dd64a27dc5250b9923e8eaa3a56880911455af70bfdf8254d3d349ee9ff5b1f0d4e0339ce3dc143b66f602b0f43f568d0f' }, 'config/leviton/dz15s.xml' => { 'Revision' => 5, 'md5' => 'b7a57c24f9a19bc37086084b95a1bc541b8425f1877883e69e19008b41ee08ea0e9dbe854c9a2bb4e72d42f5972eb74eb768513d62a41d5f903e431cdef4bcb8' }, 'config/leviton/dz6hd.xml' => { 'Revision' => 4, 'md5' => '48977e685e55b815ff14870d049d84b7046fb76e55afff21055e6374a612971eb43f9ce51aee02f763b17cb77893b33d37abfe838af55b518d045ac2635ff2f0' }, 'config/leviton/dzpa1.xml' => { 'Revision' => 1, 'md5' => '44eab79bb9fe2c858b333d7e162c4f62258890cfa3ac7751ea5c7256bf2008421faa0bac4651fe03f33cf467fa7f872e3b38c2b5fa97a8dd902451977c793769' }, 'config/leviton/dzpd3.xml' => { 'Revision' => 3, 'md5' => '56d3f1600de0802f82cc66f25306024d84aab6539f74cc12062304bb9975d5b5d605ce6c88e3b4112a68f2673c76a5a525e91f83a8ae0d6ecc487b7bd16f86c3' }, 'config/leviton/rzi10.xml' => { 'Revision' => 2, 'md5' => '2e49f23a2cb4569ac6c8d82cd0d1c1fdd9384c94a9929b4479ed8f2db6fd8c956e96a7d36bf0a32da77957afca5b319b55d5129e973345195b610b21f18a3249' }, 'config/leviton/vrcpg.xml' => { 'Revision' => 2, 'md5' => '2e49f23a2cb4569ac6c8d82cd0d1c1fdd9384c94a9929b4479ed8f2db6fd8c956e96a7d36bf0a32da77957afca5b319b55d5129e973345195b610b21f18a3249' }, 'config/leviton/vrcs2.xml' => { 'Revision' => 3, 'md5' => '6163822e432a74e1bbf1114ca11e810e550c4d90ce454b7b3a924af3db6621d047def018dd3f48ff11a91bdaf0e9586c8de34485c884ba6c7f19db7ea64c5752' }, 'config/leviton/vrcz4.xml' => { 'Revision' => 1, 'md5' => '496680a38f17174dfd6926dc45208c47f76433505227eb1952aef4d52af714a0b3401ab43a5bd9d57acaee399c4db2209229ef78bb8b5884c9cd15e009c8d8b2' }, 'config/leviton/vre06.xml' => { 'Revision' => 2, 'md5' => '2e49f23a2cb4569ac6c8d82cd0d1c1fdd9384c94a9929b4479ed8f2db6fd8c956e96a7d36bf0a32da77957afca5b319b55d5129e973345195b610b21f18a3249' }, 'config/leviton/vrf01.xml' => { 'Revision' => 3, 'md5' => '3a0cab86c66acc518d174cd9d09e4dccc6a7475622fad1b1eb7774840ec4b7e10e3e134c8047a37eab8b2eaaf325f759f18b0f28863a340ed0e3eca82a6f7313' }, 'config/leviton/vri06.xml' => { 'Revision' => 2, 'md5' => '2e49f23a2cb4569ac6c8d82cd0d1c1fdd9384c94a9929b4479ed8f2db6fd8c956e96a7d36bf0a32da77957afca5b319b55d5129e973345195b610b21f18a3249' }, 'config/leviton/vri10.xml' => { 'Revision' => 3, 'md5' => '9fa98d67f20fb67b25548993f0d004319d0c2978465226c1ff359a2dbf6a75919484eeaf45ba1a78c7b8ac72191538e5e3ea36e4f8cfa392eb0e2b8bf8a0e0d5' }, 'config/leviton/vrpa1.xml' => { 'Revision' => 1, 'md5' => '4444a13410fde75516d45b600d68209dcbbb9fcb9f2506a135deac78a9183882768a4511e599282b3a85a0fdb51278053fe1d022332f4d1c84034ba3e8241810' }, 'config/leviton/vrpd3.xml' => { 'Revision' => 1, 'md5' => '366fe2489351c4de06bacb6c212861d56959e4b2d9cb455cce9ce3b2efedf7aa1f52c4c6ef22f29f70cc76558ed6e7b92bd349a19dca045f79ce294ca93728d8' }, 'config/leviton/vrs15.xml' => { 'Revision' => 1, 'md5' => 'd89c5ecc71d6fabce275e8cda97edc9d42ba989269c1d4046ea530280ce5ca5d941956538b1f224030a6f34fb007b25d680c2c7570d6c088dd0e763e04f379f1' }, 'config/leviton/zw15r.xml' => { 'Revision' => 1, 'md5' => 'd0ba74846bbb01a3c552944cc6e5fd2122479779f26a6e94472c1fdf866342d44cb57ea3fca7134979dbd82fdccfb8a27837dd91fa185f7e7ff804a9d4d1cbea' }, 'config/leviton/zw4sf.xml' => { 'Revision' => 1, 'md5' => '4cf229a4bab0b12de915d005488ecf28d388a875266615b94a690442458b98c09967cb8558762065abfb2dd9558e0da294ccb5152b213f7b3958c4593d80ebff' }, 'config/linear/GC-TBZ48.xml' => { 'Revision' => 3, 'md5' => 'bae62218e942cd6e768c236ca9d90864f53afba4f142fb30d2d399dbc5ac864a6b2ec94f371d4a845774db0463d00d45d6faea7c272b593bd04c706ff578a69a' }, 'config/linear/LB60Z-1.xml' => { 'Revision' => 6, 'md5' => '8696980f7aa7f96a1c5b2be399c0093b306309e668d3be229d64891d2fb19dc3c95dc2f084ca6ed45a2c2d9837c2d77dc1a26211bd25249c55b56fc06a163301' }, 'config/linear/PD300Z-2.xml' => { 'Revision' => 1, 'md5' => 'f1b17e79d26ab0ee49b7928b2bf22c2378ec4fad3b8d4ddf3bca7dd7d52ee640a6f40779be218b2dbbe0c1741fe044e1698644eecfe99c421f35cbeec4119eac' }, 'config/linear/WA00Z-1.xml' => { 'Revision' => 2, 'md5' => '3b1d6292b3f7b5a00d0c4f238094abb83e91dc71f0b3c73dcd2e90261598a5aee1912cbb9ec1bc842327278bde870d24c019e0a8a9cbe40ce75ffe7aab22c7c0' }, 'config/linear/WA105DBZ-1.xml' => { 'Revision' => 2, 'md5' => 'fbfc462f83df75cc451fccaaba4e4dd4c3166a6c0cccab7dfda73036bc6a64cdacb48da0964f2e61b1d104685a20b3fd517eee2f35b58661f295ed980a1beb08' }, 'config/linear/WADWAZ-1.xml' => { 'Revision' => 3, 'md5' => '9c79c9f63bd033188724d48990a39e6a972b7549a4b3fb9a9a7e0eb592d00e405e72ecd81562d08ee21bb50a74072b6fe971991e5eb1e348d5175a9e19621499' }, 'config/linear/WAPIRZ-1.xml' => { 'Revision' => 1, 'md5' => 'dc77298b11a62ae28185db44db822bedfe7b23b9c3f59992003f75dcd816df1970140b905ad6f2ca7bca28feb61f9fc7e2ee6f0bff7f6bc86750c6a58f041107' }, 'config/linear/WD500Z-1.xml' => { 'Revision' => 2, 'md5' => 'd2af4d164e011dd302616cdc29244b66d17d94fc75b2c582af63d39dcbf73cb3e288e8e01e87e09eb67c385ae12e3b90ad0e153effa957a9ce3f774e3b2e87d1' }, 'config/linear/WD500Z5-1.xml' => { 'Revision' => 2, 'md5' => 'e11f2016a1ea920b46f0f727b6c3a4205a0b752db14cbfe27f15abfc4a10ba84762dea5d1aa8b1905afd2ae7f71eae7d74ea06bd989f7c778099e2f0cd090333' }, 'config/linear/WS15Z-1.xml' => { 'Revision' => 3, 'md5' => 'e3a8734089a4cd8a592ce7ac844198abe8503f803219ba6c0af1a94fad0fae4264c1bd5114d8d1c7ac5c194ac3e69205d29cf22d2d305dbe7a3b6bd01cd6a6a6' }, 'config/linear/WT00Z-1.xml' => { 'Revision' => 2, 'md5' => '4431cdf404d513158d1f7b9f62644ef45818a5cbce27b27a18ab0bfc631c11884996556a41b82c6242dd5c574f005a80e68b8bafe144659d10bde6304aea0a5c' }, 'config/linear/WT00Z5-1.xml' => { 'Revision' => 1, 'md5' => '378756bb646f7f84f3161a324289670142281a97fb074e7dd0123c7182a0b61963ee01f0f0feed71a0f9fcd11d4f2f458ad671710433187eead121085cb242d7' }, 'config/linear/gd00z-7.xml' => { 'Revision' => 2, 'md5' => '48a5f7d3b0d0cafd025fc035680a298e8afce80831940ff003b46cfbd3a8056e781474e5a6d247bcbbd6cd74ce9d4c04475b7445dee870401ee912c3e6056c9e' }, 'config/linear/ngd00z.xml' => { 'Revision' => 2, 'md5' => '88bf6abcbe1a82e590f415571cb96d9304ef77fedc43eea98b372142c84f79b94d001b87398f5610290d3c19ba79e59d856874f0b3fd3c65d2ffaea750d7e971' }, 'config/logicsoft/ZDB5100.xml' => { 'Revision' => 5, 'md5' => '3145ca4b1a0d82f196c79590e28841826165c6c0c6a018260d7506c743bb16b424265e3ac56e36da8755385442f27222fc9983c5a4ce5974fe5d215927f623cb' }, 'config/logicsoft/ZHC5002.xml' => { 'Revision' => 1, 'md5' => 'cbd53fd7d938a6086861d26e8214c1c56916b0fa2337366c59b4ea5bb35af9727b1fa1d3b447a733ca269c708f5f5385f7ed3661821e9ec29929828459d35a77' }, 'config/logicsoft/ZHC5010.xml' => { 'Revision' => 6, 'md5' => '4d34aeaaea917c229bedbb737e4de1550b2d7db5f9e61566a1c0a39966b6442d381d01f93714e12aae1404797d36854274cc4063dd7424b00d27da238b17a36a' }, 'config/manufacturer_specific.xml' => { 'Revision' => 169, 'md5' => '1141313019f988b909161b307adfbd3ac3c208da7244997052279d6e41e7cc49d8a503878cbc25ef79c0746ccefb37510f00d226e06782badde2e9f8de6a3528' }, 'config/mcohome/a8-9.xml' => { 'Revision' => 1, 'md5' => 'd1809616fec114edc52eab80314654c8644550fecaec881193460099bface47dc976da727f2d2b0ed6b06fdea1560a942ba2bf230752722ec64c210ed8ce95db' }, 'config/mcohome/mh10pm25wd.xml' => { 'Revision' => 0, 'md5' => 'ebef8141b4a35af56a90ca212206de80c39e15825c9f1a1101c24e6432d47644609b5d2d95dc19b7dd656fd3dc103fb487910f56f4bc032870290aba77ad4189' }, 'config/mcohome/mh7h.xml' => { 'Revision' => 3, 'md5' => '03ca338b59a9e520891497741c0c25dd562734b3f6367a4eac65aaa739351a409004c95faab888ae84c523ce1721d9b5842a9f365554dedf6faf6ed9fb6c7cb9' }, 'config/mcohome/mh8fceu.xml' => { 'Revision' => 2, 'md5' => 'adeca64ab2864dedb92249a76413d32feaf0712385a53289c2c8c7778ea4e0b74403a191dc10c6de4aa3bac2a9d5f0b940d214efba597080483d3045ddf2be71' }, 'config/mcohome/mh8fceu0803.xml' => { 'Revision' => 1, 'md5' => '5e41a956638d5e67045b75513486c36b2e439ad3a37e8970125c14009efbb65cc194e5c0e49d78c81b55bd601a8d0739d31d16a8a2a49c26679186485bc3a0e8' }, 'config/mcohome/mh9co2.xml' => { 'Revision' => 2, 'md5' => '663b2cbf6cbf61244da0704e8882d0d39a5c95be197d7b29f1d9a494f139e4c3cd50a7f6571fbd3815cae78378716652dec606a69a40300e286e4df45995dd5c' }, 'config/mcohome/mhdt411.xml' => { 'Revision' => 3, 'md5' => '5358c4702375567b723991acc1f6b126d1264a09712f6828be6294183d799dfee7d0b66a02bb1b200c2a4f9097c64568a6d6fc0ce04dbf8c4f42f255c10d6fcf' }, 'config/mcohome/mhp210.xml' => { 'Revision' => 1, 'md5' => 'ef4a59bae64c999292ce1f3307af32bec1203cd74c1bf69a990d036e670c9e02fe75b441e4e58cc52a7f563a6c5aa854c36479c06da46db4a6962d1f8c8648c6' }, 'config/mcohome/mhp220.xml' => { 'Revision' => 1, 'md5' => 'cdd157b8cf327dfa5f4b86e94708b2b4fbc6f749906c4b50908155b7ed54e0f1276e82aedf256772ddfe6c4f0d976ada08e4bd0f60e330ce4d089075132983e6' }, 'config/mcohome/mhp511.xml' => { 'Revision' => 1, 'md5' => '3cb80a2f92e58623f3c390ceb6dac6a4195a12bfce6726ea417ac28d2c80b337da8b79047436b1a34bee629b34e5cec6df3193e8acaab4c0866dd0e3ba5471dd' }, 'config/mcohome/mhs220.xml' => { 'Revision' => 1, 'md5' => 'c44d7297cce33fe821e92f35dd4e27a164db8a2f8ed3be6dba7bafc5e98629f836d92c2c32509de7cad48d4e56c2b4f095a7626e244e523e5f557317c21cb49c' }, 'config/mcohome/mhs311.xml' => { 'Revision' => 2, 'md5' => '4ce93d5bcf48f3a80f31d8293f4b2501f5541c2d74f1d09b35f1a6db7fee94bb14a375c3b443ab0582c325bddc0e0ad343eda1dce9948e16d356a51688980ba0' }, 'config/mcohome/mhs312.xml' => { 'Revision' => 3, 'md5' => 'e208b5d84f389663806f848bce581d5e20329e5a16efa32ae683ffd99c65078518cee716201f4ede6f3b9034f27f14ae5f6e235efce02f4b6a98fe32eeb39da3' }, 'config/mcohome/mhs314.xml' => { 'Revision' => 3, 'md5' => '31033492060277778c0d0272cea5d2dbe3fd507d526d855f8d39f8f1e2cad6b3e43c3e6358229487e6ee7c9ad14e836438ddbd26ff85eb9cbd68bb273e8c62a0' }, 'config/mcohome/mhs411.xml' => { 'Revision' => 2, 'md5' => '161506bc23625d36fcb5e4156e180885065c042a141177e118b8d4577b660ccbd64bd3c49e783742a0ba4f299b153f0e4e73c76b54cb832e1149e374c39e6843' }, 'config/mcohome/mhs412.xml' => { 'Revision' => 3, 'md5' => '0f893961cd58ae4f3f58e1efadfac230430412427a7fc49d7137cb9fb8d708ed5ad46d74f022db2f651e3490662516366c24666d61545c68e14dd94429ed4bb7' }, 'config/mcohome/mhs513.xml' => { 'Revision' => 4, 'md5' => '05db47a894784963b58626ccbe4f09ca637e2819b26a0bffa0e7255ab058406eb4563e8aa88f45c09a46b9c15963a01b2c87bbe619463341a8fee64a590ccfb9' }, 'config/merten/5044xx.xml' => { 'Revision' => 1, 'md5' => '0210019559c453668d5fd09bda0c3fff573e205820700826e0f7cc2e0326764855958ea1c7883d6fac73a4970777c5e73bc9a68116cc11b4d0a67ee93c701c3e' }, 'config/merten/5046xx.xml' => { 'Revision' => 1, 'md5' => '3526849695799ba35286d08503ac441603c0b662ec2311d867aa3759c60497a436a3d5333ec11f55591158c3ef2e9294b98d7e76a335b19eec99b5ee990a06d3' }, 'config/merten/506004.xml' => { 'Revision' => 1, 'md5' => '59f056e18cb14239c023886f9d7dd8f06a2de6cea986822f36fed7c3527cc0c73318cae6da71529202770e3ce8a53b88a9d1f7b94ee1af75dbefc0059d68b155' }, 'config/merten/507801.xml' => { 'Revision' => 4, 'md5' => '529137173a0a9ce8d2a75e8a19ea81d0367192947ec1fb181777bd7f61c93017d90d6c09841fec15716245ff63ae6545f5c17b477fbbbf469df27fe8f40efad6' }, 'config/merten/508244.xml' => { 'Revision' => 1, 'md5' => 'f2f028a1f81f4d1c3287c230489e9532d82b0013102b57794e19c6b57d2fa210d5ff9cb9aff00e9e3c0b54410d8d10b846e3da4a42d1938097440c7eeab6ee77' }, 'config/merten/50x5xx.xml' => { 'Revision' => 5, 'md5' => 'e4cff66ac2ed17fd5be4359b90046e6959ce38bf84af0366dfab8e7c4fac65086036f6558c5ae816d502d981cd3d1c256a80576acdb1989c019ccd2d68016813' }, 'config/miyakawaelectric/me-d101.xml' => { 'Revision' => 1, 'md5' => '702416a0165005b37d576d5fb029a5cf057406bcac8cd0e26092aebdb728a4ffb98da456fae6e06794275b0421444ec20415292300f988d0c19a808f29b41bcc' }, 'config/namron/1402756.xml' => { 'Revision' => 2, 'md5' => '97ae44eefb3bf39b5ba125efa3124c040934209a3c61f6815212c41b7ff3fca862454dfd2cc3eba0c6c29dc12d3ede6a97d499dc466863ec74c94c64fa32cd4b' }, 'config/namron/4512710.xml' => { 'Revision' => 1, 'md5' => '6bdd47c7a0ba829e89cf2735e720bf2b62020f228a4e80df237c1b454707ea7aa7898e916bcad430ac313d38206e9862b5a51748ec3138368c2b5fb643d93d15' }, 'config/namron/4512712.xml' => { 'Revision' => 2, 'md5' => 'a82b5f87b0be78f05917547ca8ca358d6d2ff484a3aab865597fc8fa8d59dac81498693d0768f4aa8aa7fdf45ce115edf96a6ad17cee09d9ef37941f803a2ade' }, 'config/namron/4512714.xml' => { 'Revision' => 1, 'md5' => '223ddb325b70ed7abe9898aa74521b6ad263a45e6a4be4f6842af04d0093d300451ca1d9b07e392c129195e425f431b8faf5fadcb7c32ecc74096699419a8446' }, 'config/namron/4512715.xml' => { 'Revision' => 1, 'md5' => '601c713a6cef0fa0e5d92bbfe6fa0d6201b60959a5a1d427cf7280d73921d658ee5fdc703b003d42ba2ce3c000848c1cdd507bd9385a435ff93c1888d3fb1ca5' }, 'config/namron/4512720.xml' => { 'Revision' => 2, 'md5' => 'c53b0beebcd8ef019da86791c1e6eebf632ed92c9fda51a6881b52dfeadf1b6e0c9809ef6c4072234ed73ee9b679cee5530866bd04916c27441e7d195a4a5c8d' }, 'config/namron/4512724.xml' => { 'Revision' => 1, 'md5' => '10edb9b98013bac7754fd68151bef8b684dff2ad17d14b71cd6831f386a1e98aef64ff83138cdd28bf6bd1ab6526ca40b87e310beed25e9ed4a857b21e689b3f' }, 'config/nei/ms11z.xml' => { 'Revision' => 1, 'md5' => '798d15de5a67cd238320459d17b73b168fdc269de623ccaf21d84c84d353fdb15efb693c10bf43075e555b7011344200e8111352250bc7bf688f4298d981e8b2' }, 'config/nexia/db100z.xml' => { 'Revision' => 2, 'md5' => 'a85e3b5dd39faff1bd76dc1f73f3b3527eacea0e1e1c70aa6d6e879533219b9e8034fc872b2553a12c7144152781389f3d055927a62565814695db853b87bf8e' }, 'config/nexia/th100nx.xml' => { 'Revision' => 1, 'md5' => 'fc72b207417e4c992ceadb75f0b87a6480a6becde57f7ff9e3e625ad066a5fe75bb0f2ba2b8b9e24f12843b04d66f37a599f84a3551956a723ab4eaeb6934fb2' }, 'config/nodon/asp3100SmartPlug.xml' => { 'Revision' => 4, 'md5' => '7c24be4705939a05a678db1c9d8a569abd97f9d074abff0cac479f92fd7235bc95439f0371d0767e72220ca1281cb1beb526eb4e0f68184d7ca29fc3fe620259' }, 'config/nodon/crc3100OctanRemote.xml' => { 'Revision' => 3, 'md5' => '4c2e1bf3aa0abdda59164b964887b9662a637a852d859baf197f480d9b3959cc796b38fcad3208a63e8592ac533b588cc82943707c1f81acdbf73d8cf08f8cfa' }, 'config/nodon/crc360xSofremote.xml' => { 'Revision' => 4, 'md5' => 'c9224c55596b27daf81dc38f5f8f99797a2002bfa7c513161a94c818fdd1d411ec2beeb48209f531c87eb1c8fbb5ed7d71f14d03076cc403c63adea718e720f9' }, 'config/nodon/cws3101wallswitch.xml' => { 'Revision' => 2, 'md5' => '3488db5887b2336d0a1bf35b8c81692fb6f899d620598b09de648a3c192780d343ba6edd5444fadd750aa426391037cf1074b503387e8d32c7a6749ec3d2b1e1' }, 'config/nodon/msp31xxMicroSmartPlug.xml' => { 'Revision' => 2, 'md5' => '12f715e8f79d0351ded0d6fba4094bd58d0fcbd3ece3eb325ff7ea7e7bf0e47c322e42cb8af4dc89bfc16b657a799768ed21184f2371c2f121cc0febd5fdefaf' }, 'config/northq/nq9021.xml' => { 'Revision' => 4, 'md5' => '865152ea0ebb5adce8ee09f65760f4f43c4010e6059596f346f4b16ca4121cd1cbf810123668009dd4329bb6c93c6c8a39d8d5893454cc03e6c06e555b857fbb' }, 'config/northq/nq9121.xml' => { 'Revision' => 4, 'md5' => '414c7fcf570c29c0ee472a80ac17399b47678028fb5b6c52ee13c7dedb570751708152d20a549cdcc0c9b5b7e5068d9119057641a7659c6ecf91ba8e7c46721e' }, 'config/northq/nq92021.xml' => { 'Revision' => 4, 'md5' => 'c1145f7d6cd67f960109fdf04b12952fe4b6255bf703f3826e62512c54c8f4e4f58ef33554f5cb03eedb1b2fd969e5ebe48b03e296dde88b89b9218fc3a6a2e9' }, 'config/oomi/ft100.xml' => { 'Revision' => 4, 'md5' => '8398a78120575f099e915e4544755bb035a8f9d8dea8caa536d9341baf8140ae82bae017b0556a22f8617dbe5d567422a29c2b8667d6b8a7807fb097ab86dfc6' }, 'config/oomi/ft111.xml' => { 'Revision' => 4, 'md5' => '1495bc054f8821256e12b70cc4aadd76e55b1d5a15ce26912e2df6a9b7246bab73968e723ae994c7e0ef923a293b46f8f72760e8c3ebb8fb32ffed7fa73e8caf' }, 'config/oomi/ft112.xml' => { 'Revision' => 2, 'md5' => '3a44eec10683cc26fcd878e9f02c715173f91b7dd37954803f81f1b93460212f6ad0b113261b4afa1150d39df39691a6f27bd74d8fe11a0c8fb459a1acdad2cf' }, 'config/oomi/ft118.xml' => { 'Revision' => 2, 'md5' => '3e98d700b6909d74f4e753880a4cae27929a324993943c9b3d6d9070805bc18360631450f2c6ac36e4081fdf5147b717c5163b4c29238e7973c037f50ab38782' }, 'config/permundo/psc132zw.xml' => { 'Revision' => 1, 'md5' => 'fdfb1fdc33cbe4dcb02dee460b52941dbf751641a35d80814e50df85a4235f182323a55203948213c7d99d083beb95174ba6acc860f38b41bea65608f227decd' }, 'config/permundo/psc234zw.xml' => { 'Revision' => 1, 'md5' => '32cf262b674384dea494dd38e5cde1393f2f0996c1ea42715ec82597af90f59898bbd75e6d37ff4a1d0b491e914a5f28c9b2946713e432f5b598907dcb052cfc' }, 'config/philio/pad02.xml' => { 'Revision' => 2, 'md5' => '8e1fe2169622ea923aff37663ee762a922dd90d2600fecf6f95808917cd414187d2dcbae6d33a97508b09d5cbfbf91413d3ef0284d875905f2e611e34069e393' }, 'config/philio/pan03.xml' => { 'Revision' => 5, 'md5' => '69ac125e867e1523ba7cd4e7ed1e7e8a4fbce0d48dca53080db404a833c1bd6446ae1014871a60f4756f5fd789dc0f314a2c23ea3467464665e61766778124ff' }, 'config/philio/pan04.xml' => { 'Revision' => 8, 'md5' => '921f304351c137d6d652cd81d9ec757ff689e4ebec2aa65e31538ff069858619b67f33e663c5ef68901ec47d442ae4a8ed81f84fbd218cb76d6d0f956431c58d' }, 'config/philio/pan05.xml' => { 'Revision' => 5, 'md5' => 'e57f208a8b5d5037bf9a1d1a8991a8936e3302944b6572dab297f15f086654e4a24b059171ca9bbc1f7cf835afadd568000cc6b8cc20a0c7e8de452118817193' }, 'config/philio/pan06.xml' => { 'Revision' => 4, 'md5' => 'de37b536016da639ee85bf9e1f782e3b1d7458d2f1cbf71c31d851f62cd0617dcab0e481ff787139f8b5bb7d8f8a3aebec61281950c172665616c9fd32e3a767' }, 'config/philio/pan07.xml' => { 'Revision' => 3, 'md5' => 'd38c538a03cd694dc2c5b55488d947b7e3541c99fb852ca3fd0c2f422aed746626ce34d8387244aaeb353bcbcdfda5087815b8d823839756cfee45c324d7abc0' }, 'config/philio/pan08.xml' => { 'Revision' => 7, 'md5' => '6f40cd915cbf21b17d229218e374e06931c17679066d5a9b66a3be20fb7f1f126034828484ea0b34493a6bd2f690e0ce79886b563dfe73b7d2d92477cdb96f56' }, 'config/philio/pan11-1.xml' => { 'Revision' => 4, 'md5' => 'aa358cc989d2e2d476bc0229750ad7f963fc07edc0ad9acd9b14f0e08fba41a1ed858d5db360195dd77b34799a610a774c2a5210eff0ae29c5de570ce3e560ae' }, 'config/philio/pan11.xml' => { 'Revision' => 4, 'md5' => 'bcb431b0960b2c0731437a8c6f88a43a32586c45dea68c43245bd51f1895d5a8b7ee875d77ee07f2ab510a88487f4f910c38aada574cb27396b70617ff1f8757' }, 'config/philio/pan16.xml' => { 'Revision' => 5, 'md5' => 'a7fefd71f6bc5ede497d62d300ecfb3e5700c0cce1c55068349881fd6ad31ce08c19a0760a935033d42ec6407853b65d1d39f49d5047eeb69a6a0d05cd57094a' }, 'config/philio/phpab01.xml' => { 'Revision' => 5, 'md5' => 'ee5564aa200257d255d4a630e4a329e33fbc0a202f0e0ed64f3e8933f760f8fdb5d248a94bf21ebcf20affd30fa5fadaa652cb01b1470496cd1b18a1d196740e' }, 'config/philio/phpat02.xml' => { 'Revision' => 7, 'md5' => '2934c2c8f14d96e31c6b978a4f0d6514eb40fcbf6bf4cf88b0298661f7aa58a3f552d8d7071bc096f61d2f2d81d7af8e4e3e2a281306c12bfe1957ef210173c0' }, 'config/philio/phpsg01.xml' => { 'Revision' => 5, 'md5' => '2fc5c66f6abdfec254f00814927a5de34ac80a32d433781cdcce2f3756726bbd22c5c52e38af2128c0c5d478ae767256c3e257010170d39fae8cf6e8f17a692b' }, 'config/philio/pse02.xml' => { 'Revision' => 5, 'md5' => '2660f6fafc0f5d1929d6fc4896fe7da6da4d1bc420d8f98d1ced1ce5c492819239c1296d18965314b6119e840cadb226677add587e1cc6eab01d7fa4ec312578' }, 'config/philio/psm02.xml' => { 'Revision' => 8, 'md5' => '61de4f16428eb7b039dc52080318783485c5ef1281f6e8b9b966ba668fa9a34c5155fc94e1a32def1cca869f832c750232608be17c007305386e491177411aaf' }, 'config/philio/psp05.xml' => { 'Revision' => 4, 'md5' => 'c11ff9ff5577b4b78cf5c9501053be6b23c53ccdcdde42b06b5e042001cbb5f898e855e3d8769bb5af6f5aeff7738f2d955d638d3609caa988b28c8beefcec1e' }, 'config/philio/psr03-1b.xml' => { 'Revision' => 2, 'md5' => '47648ede1096a03001221a87b148e05f226dfdc160ab84731c299694b64f5a982503a25c1c5cf2905f0654df08024d05c44010133648ebf5ab4358cbe7e34736' }, 'config/philio/psr04.xml' => { 'Revision' => 5, 'md5' => '02d630345e20cc163797e73a0299c2f1f678854e1bbec6475c694167ba95e38b9dae3933e151a56a0457d7548757bd7ac45b3f4acadde7b671f396f04079f454' }, 'config/philio/pst02-1c.xml' => { 'Revision' => 6, 'md5' => '464c0b4b141a2574032381b026c8e1a188c7f39f196449a3470de246591c0b75b842f1db09261e7ea8fe78d13718d38614ef2c04b311dfafb4f896772833eb5f' }, 'config/philio/pst02-b.xml' => { 'Revision' => 6, 'md5' => '4231162c58f286ebb12b0a6fd65fcfe1cee8d5a41f1a7565648dac2f50f03b327c88bf7932369c76ff17b7b2cabbc3f87e082e2978ee0012b47ba60c0361443a' }, 'config/philio/pst02.xml' => { 'Revision' => 11, 'md5' => '03450ce5dd6f64055d0ade348357cfae39a7bfde49c15fb94298489f56e303faf669dfc19bf51dd4da2e95d72dc7bbe1fe691848074c339d20377f1de337532b' }, 'config/polycontrol/doorlock.xml' => { 'Revision' => 9, 'md5' => '41699e435d7d757d17c930c7b6a255218ce13c9c0ffd7c813eb8d1ad9872fd5e10e08497833a96b1d5c8d6d5e6ac7cb4983e62f179930c2fd4963014748ae50c' }, 'config/polycontrol/doorlockv3.xml' => { 'Revision' => 15, 'md5' => '470dffd2518ef1de4af71fdd29ead1afef79913651964dd328c2068e8e8d3539e61b5ed5c5ef3bbacd47590a6a800e182a0115f1dff6fb29be6b6bf47e302eeb' }, 'config/polycontrol/keypad.xml' => { 'Revision' => 2, 'md5' => '355727d3cae60c0ee5bce2415bfc6f781d3b7ee00caf4b0693d51daac80efae1e5d535f2da189787445a091759d25e01072603476c3645f9e6b78b178d9c9fb4' }, 'config/polycontrol/polylock.xml' => { 'Revision' => 2, 'md5' => 'd568bb68a43925c93fa91ae1e90be02a7bd122a96e45976024451d554e30bbbcd4b1c379eb7b929ca09086d6e2a2c3a50235193627b115358f104bb3f78a5861' }, 'config/popp/004407.xml' => { 'Revision' => 2, 'md5' => '9aef97d5a39d568f37918b440777fd2cd95cb0f094dc1463fc846d3ccfd6a9834b0890409e6ee7c3baf18a058ba90540c03eb04e86b54f30d8ad3183db88daa5' }, 'config/popp/009105.xml' => { 'Revision' => 1, 'md5' => 'f342fff90c90bb58c7b2982fc2ac1c1dbc81a62de8ba5e955714efbacfa2a90950df81bbd5a255771bb43820a5b3e65fa6abf83863ef19787590cb540dba0a99' }, 'config/popp/009303.xml' => { 'Revision' => 2, 'md5' => 'a5d8cc2a490a870b0c4e8bcdaae57d2efc4e2c3cf632da50950a7e16a23cdea02389fe078aab9441eaf29d9312f808d00d6173c78aacaca000693cb88d1a3f28' }, 'config/popp/009402.xml' => { 'Revision' => 4, 'md5' => '76fb11bdec34c53312c01e694e798cfd05516215f82a6756628b47628a832f9f29852adb0d33f6783e3706bc35b132c44b9be7631049d91077a434ae148d5f41' }, 'config/popp/009501.xml' => { 'Revision' => 1, 'md5' => '749c31c6f0a959da709f13b331f01abe31bdd5c9f93a584cdff75ba40ede6051b777056d01bd42fb4e34e4728ec2f5454fcd8d634ded05209afc66450412e013' }, 'config/popp/012501.xml' => { 'Revision' => 2, 'md5' => '44af7415b92881839701d05860bbd9b1a4f3d1e1a249c2bd0dbceaa4f1e4f704009adf51b33242e8b81ab41a7766c2a0fe3c2b27e71a592c21a659d0c74d24ed' }, 'config/popp/123580.xml' => { 'Revision' => 2, 'md5' => 'e6f1179ca889975925b64d57dabe01c7c9a6ed85c2d904765d3e3b076d9271fe88a8e20512a40119d113ff12660361194668773712af6c57de0d9c6e7b26abb4' }, 'config/popp/123601.xml' => { 'Revision' => 1, 'md5' => 'a62805b4ce498ea1010c49d9379f78bad95599a7acc465f2e829b6d6aacc5c72a5eadf12f357ca86ffbbe86bc241d0d787a0cd2b7d90b24c481ca774dd6944ae' }, 'config/popp/123658.xml' => { 'Revision' => 2, 'md5' => '7a156ae6ee0a11a5a22edd0b0be003173c37f8abfa4e93558c0d78c0c15a48be962a83a797423bd75e2fccf1b6133020ec5886da5cf81721a726fdb525ddd11f' }, 'config/popp/700045.xml' => { 'Revision' => 2, 'md5' => '9f5b536c1f6716e9171b9cb6f6778f0f609ef33321bb8b3ecbd890a66d428048fe05d7cc39b4fcce7a1c2e16273ec76fda322af74e87cb7bb02ec951f342b6be' }, 'config/popp/700168.xml' => { 'Revision' => 2, 'md5' => '1edd75ada9a0c8be1e77b48629a4e07f724a5755f32fa80b0471709043dbdac923a028f3698eeadee2ee948b039560c0e99dc500165e26f1bbb67bf5a4788729' }, 'config/popp/700342.xml' => { 'Revision' => 1, 'md5' => '8134576c997489d04fd02f62dc94815f2e9ab24ab0110e0632102d24f7e1e2015180abdb8365346bc1607aa27d5e8216e02a151c3501c7b7bd3fa8b33c961817' }, 'config/popp/700397.xml' => { 'Revision' => 2, 'md5' => '89784ba95b9219c52c8f63826514c480fbbd9fe84910789b0e3c5bd5a10038621fc68c392a8b759ad89a2c43aa34e823af029ff354651b86f65fcc71c098a848' }, 'config/popp/700793.xml' => { 'Revision' => 1, 'md5' => 'caceab22bf95c5e0e3e030befb73d612d94620cb3f11011509a7ac8d85a0b7771d24521385275918054334d7046ab98902f576d8c9d5ea98009e735d0413a331' }, 'config/popp/701202.xml' => { 'Revision' => 1, 'md5' => '737e201dcc7710e70727ad12ec7e93d77cd3b1a53c4f690a1c18aa343f39f791f56ab7543d18bfe77e10773c8899e7115aeb59e03875657b678d72508d7d1af8' }, 'config/popp/dwt.xml' => { 'Revision' => 1, 'md5' => '68638128d2fefdf799548463d04769bf7d911ad2b2d6240ddd4d7a6df7e03875808773e819839c84deb29a5a2fc3474c326e13a9335653f389a5ab211f57f644' }, 'config/popp/smoke-detector.xml' => { 'Revision' => 2, 'md5' => '5a0047adbd73b8bac7bb78d1a01c4e04a8674b2c6afff325d14b2e83710fa1e9008af3c6650368dd7e9c2694dd601b885cc8a64c1127fd1019ad401d12b35996' }, 'config/popp/solar-siren.xml' => { 'Revision' => 2, 'md5' => '010d56d45a25cf13b51b1953554f0ae4dddbf52f18dc03a3c1f85a264ebac8d065d7f226c12e2cffcca5b42d0fbda10208ee3156df78c7930b7c8ba023722be8' }, 'config/popp/zweather.xml' => { 'Revision' => 2, 'md5' => '89c31bb70e56b887ec4559b2d4bc450bdf40490fb9b496f37e337265539e638c0bcdcc128f6914c3940f2d58cf51655deb1ea7876c38d74ccc2e89af7e1240df' }, 'config/prowell/zw-702.xml' => { 'Revision' => 5, 'md5' => '0f18166b3561a3bc65c5f53f8a26fd2776b6adb2d01367a7be5ef11800cf3bb1877ec2e8ba6db6170c6faa9ce4654ece1259e4d9095354da2595b8ff4b100aa0' }, 'config/q-light/q-light_puck.xml' => { 'Revision' => 2, 'md5' => '0e726ac3a95dade8cef628abc82fe71f6a9b22b6331d6844d548e14106e7c70b8100cbc2e6a9e8b99c70614269da30f15f56d0db8d410e092113a3c7bb284453' }, 'config/q-light/q-light_zerodim.xml' => { 'Revision' => 2, 'md5' => '4d7ea7bb60f06aa3a79a1e7327530e5e5ea5cb99213684f09626d8f7204ac5aa03069ec4728b5c8eff44faf7d65dc6a0ce2383e72f386fa0417af1f359141ed3' }, 'config/q-light/q-light_zerodim_2pol.xml' => { 'Revision' => 2, 'md5' => '09b34de566e3854dea8839bab6b7c3d45e4732a3c27fc7ed839fb596dc1dc80331019e83822faab3cb46a8abae18b080ef29c328e77f55dc3796455d48fbbcc2' }, 'config/qees/reto-dimmer-plus.xml' => { 'Revision' => 8, 'md5' => '944ab5c363ba7722f0f870782bf9d20bc75040fa21820db080040b538794f8574140ff0960ca218273810e596df193f76a7ee2fb4412f8ba2b2cce7fa18fb431' }, 'config/qees/reto-plugin-switch.xml' => { 'Revision' => 6, 'md5' => 'd1f4c2dd9454ae4b1edc810c6d732bf042447334700deb17d9fb82d7330544e376d055c7e96a75a88bd2911cced8337c3d76041946ebb6e011b4b68d3d780dcf' }, 'config/qolsys/qz2140-840.xml' => { 'Revision' => 1, 'md5' => 'cda505a60a5855fa591303809c3d6e7bb1d471a274522a014fb42571e7e81c551374f5227b8c4e544553f981b8a44d2176786aab59f872ef62791401ed39a902' }, 'config/qubino/ZMNHAA2.xml' => { 'Revision' => 1, 'md5' => '080174f8dbebe8e5e80bb84601cd153946b7a014450bd04eb52cac0351dcf326b6b5c139385a42c055e1f01a09a41e1baf19586b66fe20e975ab6e7ab5b87e8d' }, 'config/qubino/ZMNHADx.xml' => { 'Revision' => 9, 'md5' => '510f98884bd31bfb09f356abcdefcdcb4456fb1edb54c6d20e673878983744d98a06a0b643880e842678bbe76d9272ddae4469606dfa57ab7546f26531f5d64b' }, 'config/qubino/ZMNHBA2.xml' => { 'Revision' => 2, 'md5' => '35bde84eae9bf56aae8a8ec8710cd96c066d9caf087ec1356c3fda124e82bed5406af2e72b627a45bc45e1e6c91f8f0d9af9368e80fcf5973d9be2ffb5e191cd' }, 'config/qubino/ZMNHBDx.xml' => { 'Revision' => 5, 'md5' => 'e7997e9c51a66d078d37e5501191a2a36bd7faa8b98dc8967043b68e9e97621c5dc5f797640ee4c50a3ae4389d38ed87e6e3a94540911549298f366aa8ac5cd9' }, 'config/qubino/ZMNHCA2.xml' => { 'Revision' => 2, 'md5' => '94f11e408312da4a3104d120112bb697bf53a9c5877f3eb73128e480f23e217aa72bac2bc0752f2595a68d26dceb22573beb7f4a98938149e73facd854e21114' }, 'config/qubino/ZMNHCDx.xml' => { 'Revision' => 8, 'md5' => '70c37e94bb435fb029af0b55829db7e244ec7beead5939bc19c25fe525ebebe677a974d1d920699ac74b1a4b62643f5818b317a07b78f00d8ae792cb4da73e11' }, 'config/qubino/ZMNHDA2.xml' => { 'Revision' => 4, 'md5' => '7883b97dc7151ac7c550f56adbafb086a548613a14617da51232bb1e199a97144f89205622555efdac851e2fde437e2e00e65066c591ac1f1d622e7b57a1c59b' }, 'config/qubino/ZMNHDDx.xml' => { 'Revision' => 9, 'md5' => 'de18029a1539e10dd15fc85ede084182e1cfcbc78325602ca6e5b428884f6db6ce1bebdbea331a8ca0f4ba133828c09f13ce6c1f8486871a5ca9c17258358ba1' }, 'config/qubino/ZMNHHDx.xml' => { 'Revision' => 2, 'md5' => '190639b81177c88bd4a340e96d83578085f35ede860d7bc613bc879e4baff907c951d498696a52d84659936714855efae2a62e183d279957e3a8bda14d949a26' }, 'config/qubino/ZMNHIA2.xml' => { 'Revision' => 2, 'md5' => 'f8dde99fe36b78571b75faf9ee7cb3c2d0112d86a0cfd33a6037ae96811dff066649df14fdf88a76a7b77d3005291ef72704a49f23a7a40e24dc7665d5c185d4' }, 'config/qubino/ZMNHIDxS1.xml' => { 'Revision' => 2, 'md5' => '061416a33033dc5cd68fceb1b06a690fa02c5f6c7804453a8d28173d3869b54b7067f87e30eca380330514ad1c078931c338563cf7af6f3da98916134d97d3af' }, 'config/qubino/ZMNHIDxS2.xml' => { 'Revision' => 3, 'md5' => '39e39c091d03726768865e889d20390d30af0cf5da390e49adff1928cc79030a2d59d9c1436942140c2ddceab49c70505f2963e2f54397e3cdb751a174cc3122' }, 'config/qubino/ZMNHJA2.xml' => { 'Revision' => 2, 'md5' => '3545c580bbaf7b12b70e0386d13ff196320ce959767de031e2363858ce20d3cc0ade40928d17dc8f1d2be5177a73da2f51efd65c26c85c9a2735bbd23b4c3377' }, 'config/qubino/ZMNHJD1.xml' => { 'Revision' => 3, 'md5' => '32b118f0bbf83efcb068a27bdefe63777fe8672e69df478aaa066910ebb5af23cdae79bc9c31eced97abec78ffe0616ba3dd76eeaca86babe2984e6e7c18d523' }, 'config/qubino/ZMNHKDx.xml' => { 'Revision' => 2, 'md5' => '9c131e49681ec7db225248b21304ae83faa24bc4b811dad961195757cb70c01127482c12ce480e9778dadfc40357f1c9abe346254edde8848ec9803df9378221' }, 'config/qubino/ZMNHLAx.xml' => { 'Revision' => 2, 'md5' => 'f30b0c98515367bcdb9b5827838268789b8e4167bc0bbfdd3c9b7cf1838e4e8d54c9c1a88c942409175ed9291216a6f3a0d0c19807235283e9ecc8df4829647a' }, 'config/qubino/ZMNHLDx.xml' => { 'Revision' => 3, 'md5' => '5024808b8551691103b25c05fe37ae3b49499a38fe0491bcd492accab0eb346b7e810c3132cd67e1920ed0d971f07dd9303a3b774276aab38ac04610fe5dbd50' }, 'config/qubino/ZMNHMDx.xml' => { 'Revision' => 1, 'md5' => '10bb3f3f11e86e4ec0e164e74e69f990864cd9fd76a4b407b1c26c54f5bcd5f16c3dc08482988b4f557f244da5cbb61b6555d5b1496d5ce3d7086868cd4ba3bc' }, 'config/qubino/ZMNHNDx.xml' => { 'Revision' => 6, 'md5' => 'a10317520ca58616369d1d7782640ffeb84fb778c781f3bb39e7d6a0f22cfdad7aedb65b781f632e36c2c9837188019d00bb8b6509bc022719a64a77ea2c6277' }, 'config/qubino/ZMNHODx.xml' => { 'Revision' => 2, 'md5' => '9e267442a84763403fc4c9ba6088fa59a067e1a5a362300efdcae287697426a53b5b705fde59ae5c106091923fbe51b2856e9c9bdc7bbe9f9601d7dde7878e8c' }, 'config/qubino/ZMNHQDx.xml' => { 'Revision' => 4, 'md5' => 'ecf378103c01da6f196ffc99fdfe30ab93dd71d1b08e89577cc123664dcfa331a9116f2a6dac65b1d75bf76df45b5f44f4f09c041b0d410d1497d00a39d8f4f2' }, 'config/qubino/ZMNHSDx.xml' => { 'Revision' => 5, 'md5' => 'a65c7430dcd17dbe5f1932ffece29cec38b684636c2db1931222c7c042e3e6808a049b149db78b9e3a3b12145da078416b8331d72052cfd0a149b8499242d10c' }, 'config/qubino/ZMNHTDx.xml' => { 'Revision' => 6, 'md5' => '75568a1a5e7119daf2d493b4ea6e7ceb59e065fa9325f933cd61db7334dfc792343946e0dae62b6bc84f8f598d55890aa9e2392419dce0cfd4eb58b6d23e7801' }, 'config/qubino/ZMNHTDxS3.xml' => { 'Revision' => 2, 'md5' => 'df04a24a50282278c6deb7e885702d97ec98a2b4ac2998212caa7c16ddf961b590168214bee1c4ca76512a4386cf9b3199fe129757e4af5a725cc1a2a3d79090' }, 'config/qubino/ZMNHUD1.xml' => { 'Revision' => 3, 'md5' => 'e1b8ae48d7388aefa2464f7e0e51eb23a68f65e8d7d4b35a4c3af29524fb2d53d40e1d861f1d4d798282bd1c916e854f55da894e27dd6ef43ec40c13b3a56610' }, 'config/qubino/ZMNHVDx.xml' => { 'Revision' => 5, 'md5' => '84d8b8e248e7494d1b5ef403cc55c84a9c7e32c484b878c7d1103b89ba58fcff3a7dde495bbeb9d85c41dd2a029cd56da45502a4297f5c7897a9b9b2f5ca2af1' }, 'config/qubino/ZMNHWD1.xml' => { 'Revision' => 5, 'md5' => 'f5833225b7eacbb94d422c08baf8b5b490425a09b15efedcbb08a92700c9918f926b1ecc1b68fdbc0cf1cd460a26f57806f9ed5a625f3147dd2859091ccf99ed' }, 'config/qubino/ZMNHXDx.xml' => { 'Revision' => 4, 'md5' => '318e982feee6e6df7c03da246678861e51eedf93463e134476af6fe5a0905624db9807b0b961147baf98982fdb4942a7ddf987dfeabb27241a39cf0e61d5d6ab' }, 'config/qubino/ZMNHYDx.xml' => { 'Revision' => 3, 'md5' => '16a3c8fd7a16b89e67fd98751b34f133de7058e410eef2ee6ec76f19ca8ab6bfda4e52fd691b453bd64bb9f13768375e438a753c8ff54ef433a9989f1cf58595' }, 'config/qubino/ZMNHZDx.xml' => { 'Revision' => 4, 'md5' => 'ca3b0bf60934b0454f40989634f116d0d4c486ff21db65d3cd2e0bedbf68aa1bfb8578337c8dfa250da807b2588b8331cfda2464a9c54fc8b9717d801d866538' }, 'config/qubino/ZMNKADx.xml' => { 'Revision' => 2, 'md5' => 'ab2ef82408481add2f186cdff6d5316994da84f7d1f25727ec6538909d3b54503c44e90a0ec69f69fd9fa44a6e12fd7cdfa290b52d6b2af30ac5fbb99ca0bde7' }, 'config/qubino/ZMNKIDx.xml' => { 'Revision' => 1, 'md5' => '437e4f7ed4ef2acb48885ad26bb2cdd374994d01e3d6d7f4ebb0003cb61ae6457ce96e4e9b44c96f4e464e9cdce74f0281f5929992054d62de2cf6bf4344d01b' }, 'config/quby/qb2.xml' => { 'Revision' => 1, 'md5' => '4104820b132cd14a69370bb2fbd53e4efb449066a5af14e34e26aa58e24622b55ae0f9a60227fb41b3f34fd473d07e265072649cd84e580890b081a96b8c92d8' }, 'config/rcs/em52-zw.xml' => { 'Revision' => 2, 'md5' => '665997cc9ad56208b97ad149daafb416f34794ab75ec470f419acbe7b15c20ca7510f4676f880a1effe8aa5642ebe3e31c84c618ccf3dbcd2c524e8f51dbe9a9' }, 'config/rcs/pm12-zw.xml' => { 'Revision' => 1, 'md5' => '49da27e755cdc5b06ce24bdda26c67bdfb968cb4b3562298b1394129768326bed2b8f9f0d972397c4c1b6bb98e101391f57b51aa47ebcd29e4a119504e98e13a' }, 'config/rcs/therm0005.xml' => { 'Revision' => 2, 'md5' => '9ce6aac1e07d1ea8b13f9c654fb9081152b3cb67dfe94a37afb681c1262cbb465e1801b0e2687b724e9cc888cfd35d71b390e4a04cadadabfa2bb3a602a5109c' }, 'config/rcs/therm0007.xml' => { 'Revision' => 2, 'md5' => '7c3ab99f982cbca19f26b3600abc65272950e253ed60777f32a501293e5643810b8ba7e172466e675455281c2a35bdea390a589d8d88fa5eac02703d4a6da504' }, 'config/rcs/therm0009.xml' => { 'Revision' => 3, 'md5' => '235f10fcbef7aa54b4bf933a67bcd8009fcdfc9cf66d2b6608f5027901311baa53678ac75506e88493f6027714ea8e9b8fbd42ffa040056428c49bd35a4ed7f4' }, 'config/remotec/bw8120eu.xml' => { 'Revision' => 1, 'md5' => 'ed31f96f6d1f3b33a38d3ba6030aca32065ffb9a12c3447082a252698fb12753a425f96ee7c7039270cb7783be2686f02dd8e356695eb0d6db27d10385c6b8ac' }, 'config/remotec/zfm-80.xml' => { 'Revision' => 3, 'md5' => 'e3b6afb43fa679b8575f94b04caa71d8942ee15ddaf3fc70b15ae194af4d1b38ee710b3f7a0aa2ca9df19f2eebf4611a8927018a98639d3113399614c0704fec' }, 'config/remotec/zrc-100eu.xml' => { 'Revision' => 1, 'md5' => '5b840b10226c7f8e158623b9939ed2c8eee3aa1516de6a78c3f19ffd89fac6fade7acdd6da5a7aedd6394c019ead43902a586351f233740dfaca13f0e2a291cc' }, 'config/remotec/zrc-90.xml' => { 'Revision' => 2, 'md5' => '98ec165810b4b80a4d1e22957432046b7d61dcd6f4ceed69059d81ef1924124ac0f146a17192564b82011a37943aab7852ca97a512ef2dc8bbd1ce8a06f831dc' }, 'config/remotec/zts-110.xml' => { 'Revision' => 4, 'md5' => 'fbac42632e85ac10571db822206b25d8c793e3a1c5e16783f822b094c68411f3742eea8d7b3657a2937f6c406e8184f624b80967acf3c1e31b8bc881dedc359c' }, 'config/remotec/zts-500.xml' => { 'Revision' => 5, 'md5' => 'baf19a0efb011787fe52ba1d4947a9a7affee275b48752084d343bddfcdce9c1e95c1457ba18d56652256d2ec93a9ddcf81c025ec760a3d20e351248b02dfc91' }, 'config/remotec/zurc.xml' => { 'Revision' => 4, 'md5' => '3ffabe2c9da2cd2f4f625682584003c5cdb4302e09a074783c718526b796eb394ed7dd020594167751f46a18894dd54b39d9c4e3b06c5cf64fcca738b4aaad4b' }, 'config/remotec/zxt-120.xml' => { 'Revision' => 7, 'md5' => 'e7545d88ab5223f20078134b437c5e4f5c4e85a8201d92537cb159cc829b8b3fa17b84856cbe68a90e10793c155c4c711cf1675136ef82cc524240c44b4711c6' }, 'config/remotec/zxt-310.xml' => { 'Revision' => 2, 'md5' => '5de09bb88d9c21d33dca3ba693a7ae886e9a4476e50966861b581d22902636df68981a069debbec830380576f14a6676d7fd302f165553c9ba558a3803b8c991' }, 'config/remotec/zxt-600.xml' => { 'Revision' => 4, 'md5' => '55a6ccde16e43ecdeb440406354d761ae34cc7743d6cae4946e928e82826f8d4aafbfedfa5428cbde8a5eaa216c24b6c4417bb04edc28d118763b3c7defb8c1e' }, 'config/ring/PIR-SS.xml' => { 'Revision' => 1, 'md5' => '59652dc6da375fc15e84a385f1d90799e3fc7d6a6295d5f2eb6b28d2d965029a6eae376a21e326b3ce9d85dab066a46282db1a7edaeea29344d075d880c87601' }, 'config/ring/contact-sensor-v2.xml' => { 'Revision' => 2, 'md5' => '1f51fedc85cebb63a19943c3635ef4a33748d37e9c37bda8c0370ae204903ba9325af12ca3b6ef22a32d01d929d02e97bf48c81fdb09b1c003bcf95f171ab479' }, 'config/ring/motion-detector-v2.xml' => { 'Revision' => 1, 'md5' => '40691ad61c15ad9d6cf90f46b2e04e707809db8f5db55250dacce93c19bf6c2057d1ba4b190995e40c044bc4f9f6bd2fa226b5b54935d1a6649632da0bc21d4b' }, 'config/schlage/BE468.xml' => { 'Revision' => 2, 'md5' => '4b373a2ecad0691860087e425fea93ca9914330abef2b1b90ee39b4f8b6fd7298a832578640873ba6662383801e04601a8335062f20f4f787eff432c233ac31c' }, 'config/schlage/BE468ZP.xml' => { 'Revision' => 2, 'md5' => 'cf44b4f428c8013422e2acc14b08bff8c2920e01bcaaef16ab7f655f14d38b6aa678d041bcf0910a44a90aea88b700634d6715df434e3870d70cc8226d0d4fa4' }, 'config/schlage/BE469.xml' => { 'Revision' => 5, 'md5' => 'aef83d8b45e8e4e4e66a4cac2c15f42bda6b1502dea3eca462854b387720571b11f6bc43b8c2684aa31886ab3c1e29d5e167308907080ecc6cf1e273b020bbf0' }, 'config/schlage/BE469ZP.xml' => { 'Revision' => 3, 'md5' => 'b0d05fedf2a1624f715fa0bb19927c29dc57cd3e17dea0697f410c562aece8405f968536f64f6de2a0b4d373ec39aeb13d2de77adcfdfbb7667e5e52b5137d8f' }, 'config/schlage/fe599.xml' => { 'Revision' => 1, 'md5' => '43f87fe9fd2b68691706d1cd0e7287c0a0340664071a14d0af6be62594b83ce4f8b0c335faed4201ff06a97745a3609c7df2412cca8394b70b2790346247e18b' }, 'config/schlagelink/41.xml' => { 'Revision' => 1, 'md5' => '48cb8a0b222d88bbdae8fe708670cf50f65a2eb412aca5ac01e21b330809a65e917963a63f7a969e5dd0250b2705363a2173f0641b21de44ce3d78f751c01156' }, 'config/schlagelink/itemp.xml' => { 'Revision' => 1, 'md5' => '4f3be313a7ae86c458518f7269cc51cc1df19d5900ae319c160c060dda74d57439c1d7f4b1ac881caaad1b726c3349a9c03a6c9d88103d864c31512c434908ab' }, 'config/schlagelink/minikeypad.xml' => { 'Revision' => 3, 'md5' => '8d4411fdc3a3e9b9f943be980cead9e614c02953c82b6066466db7838da7079c5ffbf000fef4a28d8a52a6286bf9811a9c2dab8c79f3670feeda80cc398df4e7' }, 'config/sensative/strips.xml' => { 'Revision' => 15, 'md5' => 'b9d3afd0be617a7a5d87ca36b07dc07ab3fd8dd2e31ffa99a519d4b94ea3ffd87b83e900c97e46a1fdb0dbfbd7b19a388354c1b8734fab5f96b64bad2e222fca' }, 'config/sensative/stripscomfort.xml' => { 'Revision' => 14, 'md5' => 'e76c9730441ff8cd2eba5b52bdbee17109157076813bc628b873abfedc23a62d2a44b27e5f2b3919f82cabe4df44f75f1abfd30494edf2198ffb88a23bb55b63' }, 'config/sercomm/sw-clp01-eu.xml' => { 'Revision' => 1, 'md5' => 'af10355b77d03b65fadf93f853057ded42d39a421df623b45dec230e9b55b34aef95eeded78e70212c02ae9e71745b45e63978706a3093d14a7f391a9177b560' }, 'config/shenzen_neo/ls01ch.xml' => { 'Revision' => 2, 'md5' => '59404ff10eff881692c709bbcec4717aff3179e546253171970482f37188a1f38f77fc3f6231841b5d1c47d8d7fd8983138a53e98cb3b2532b34f9d31ee8f4b5' }, 'config/shenzen_neo/ls02ch.xml' => { 'Revision' => 2, 'md5' => '9d83ab76ccbac89e559c98979142ead8da4851cff7529fb3ed5cfb9b7cb9f393f7ecb823be8c50e768862449b2310e6facec1c4979e8569c147df21541716d41' }, 'config/shenzen_neo/ls03ch.xml' => { 'Revision' => 2, 'md5' => 'a0777d5e97620acc8b2b93df1adf51c848a45c379bd4e900ac3c9d9b8b61446273e2afb917faa71248c5ac467513b75050e0f6fbc5c3dc43f3aeadbd0eb85ca3' }, 'config/shenzen_neo/nas-ab01z.xml' => { 'Revision' => 4, 'md5' => '11df6cacff870c04677b5fc3a3828281d6e59506d09c1696ded074a4a607b87f8f96a42277dd409f64d3f8a91ced972f4ada74a32bfd304e07c19a1bef427a2c' }, 'config/shenzen_neo/nas-cs01z.xml' => { 'Revision' => 1, 'md5' => 'ee9fd5fec7a2c813577ec684901961f3544684b85ad911002798cab563ee5dbab42014cf4ee41f240ae1a2e0095951cc31509a29e9aea602dfaeca8ee323d46d' }, 'config/shenzen_neo/nas-ds01z.xml' => { 'Revision' => 4, 'md5' => 'dfd1992f3edf1e2b0c8e4f4afb6d99575ccfe2ea7c0042668fedccf540993fa39743f9bf969a5038d57dca3e1ab0749d28e1cb0be35272c71248b82625f99c09' }, 'config/shenzen_neo/nas-pd01z.xml' => { 'Revision' => 5, 'md5' => 'cbfd1220724bf3a460a69f6f278903ed790a8bf2dfd704e7a3d1e4c6467d1898a636ecd08bff6f8c1b855706268073648e8fb96f015bec3eec2b035c243089ed' }, 'config/shenzen_neo/nas-pd02z.xml' => { 'Revision' => 3, 'md5' => '2e766627891bbf6bc2a188f6542acbea522b6bb0515c9179fb329a095fcdc9e381efcaa2ec712adfa60bc41f61d7c493ef90f3533760c8cfc0e6cef8bf5bd0bc' }, 'config/shenzen_neo/nas-pd03z.xml' => { 'Revision' => 2, 'md5' => '8ffca12a6fe2f5e1d524c36dc327023c29ab75b9f0291e706d449b78b3391d6d05456b330fdf21d0630acc102e8962f58aa615450ee53bcf7c6fdde8e8c3fc6c' }, 'config/shenzen_neo/nas-rc01z.xml' => { 'Revision' => 1, 'md5' => 'd11ecf14ca8722b1e59f5cb5b20303be9bf66786e9a1d18038f2f0c760f8aeca673b31b993bda0369ed662cc96dfd3b314e8aff94e6fd8b1f2e981f51d90dbef' }, 'config/shenzen_neo/nas-sc03ze.xml' => { 'Revision' => 1, 'md5' => '4c3dae5db0aa2bc3141fa3a5a41e94fc8c77988e269dbdc20b9017802e48809fbc0d572418035a913781eb5272d88365ba2bd316bec056a1e1b0459cb0b1e7b6' }, 'config/shenzen_neo/nas-wr01z.xml' => { 'Revision' => 6, 'md5' => 'ff8d4fa4f5296969721ed7f4a70fb471eca86a227194456a9efb4390b97a365840d171e89d683916e2afd722256e34063dd186f530770d26e110e0c8c3d6de0e' }, 'config/shenzen_neo/nas-wr01ze.xml' => { 'Revision' => 2, 'md5' => '09b5e4644764a9d6fc5482d100ea24d81ec17adc3a436fc7ad0a11259a9b7a770cb7a29b01b6027df1a984ea13a9dde264a49acdb425597260c0699920ecb33d' }, 'config/shenzen_neo/nas-ws02z.xml' => { 'Revision' => 2, 'md5' => '7eccf1cbebc601996e0d6a552217c0b1dc8883cc78fdddb088303888d15832f7734d08f43c0991e8c9535a9dccc1e4b6f509802ed972477b4e45d499f45bbd5c' }, 'config/shenzen_saykey/sk-3007-05.xml' => { 'Revision' => 1, 'md5' => '8f7ab98b4ab3f08f2d56bf834a8dc001973d58b06672ad049426a332b32bfb8072817ff714e22e89f57bcfda113651eb809c8d0e9010f035176feb5050af4bef' }, 'config/simon/10002020-13X.xml' => { 'Revision' => 1, 'md5' => 'd2164162991f71803dffa110f7a4c65fc181cb8563b63097f07362a1cac2e2ac4a88ec775dad27c875b82b28ac3197822c1a69e08ac0e21c7bf2aefe04107e22' }, 'config/simon/10002034-13X.xml' => { 'Revision' => 3, 'md5' => '8bb9641949c548b619a32d4169dd3f3b14367fd98bcc0168ffb6402fab467d0821f1a011e5be2987eab93ccad87692aaea9a63ee568722dc05e69c4a22359485' }, 'config/simon/10002041-13X.xml' => { 'Revision' => 2, 'md5' => '0235c61b4520955df553e5ff62cefbb1a9afd866c63152503893d7bdcd98e9cf7d3a5f6dba69d3b307508ff5eca5cd33acaaf5e1716b89fdad748a9658af7445' }, 'config/simon/10002080-13X.xml' => { 'Revision' => 1, 'md5' => '1a3e7b1f9a01b6f74c66c28754902b29aaee0da9ef780f720f5c3a41eab26d41b5998eb96fd94420c291b72331e2f4982cb092277d90d209fb0501ece3c613d7' }, 'config/smartthings/pgc401m.xml' => { 'Revision' => 1, 'md5' => 'a4e6e5c467601d118de320aaba5443876d46288e5eac6a0eda63bda9df4398efeee59385724c9ea007d0e3c91b8f7f6025157257a8995c79193a24938e8b1c7b' }, 'config/smartthings/sth-eth200.xml' => { 'Revision' => 1, 'md5' => '96f42e76742addc39b55aedb2c9341e15c3c9b90c6a5640209c5c47e47f93e3be3a2c588f20f7030b0cd83002dae36e207b0361ad320fd91b656638979ec519d' }, 'config/somfy/1811265_ZRTSI.xml' => { 'Revision' => 1, 'md5' => '7def694a6414e50226cf75191573d1fbe6a277cefa3170461e7f35301b968e28494cbd9217871ea6808206b9b417c696facf068f7a40892cb790d8b47d916fd8' }, 'config/steinel/is140-2.xml' => { 'Revision' => 2, 'md5' => 'f5538ee6fa326e3f433ba8ad930b38dd8468db94991e8697555ff64c5546f47bd8fd086347e4c80e7f921206bc11b35238a4c78e73d6ea1e751b2f4c4849a884' }, 'config/steinel/l810-led-ihf.xml' => { 'Revision' => 3, 'md5' => '87ec6dd62e0f09a1c81645fdf0d54272791232633a2824f7571e2c44817cd418c4a5cd34b32141f36b8faee28eb93c63b22f514eb9d073d6d6055e24b99fa7c4' }, 'config/steinel/rs-led-d2.xml' => { 'Revision' => 2, 'md5' => '9f3767724904d6ce85e7880dfdfec9c1f851638e0e35045790cc35589d0c9cd653fa176c48a7b818b5b8218c861e2903eb8adeb313a6d4e8bb9a33a61dc90976' }, 'config/steinel/xled-home-2.xml' => { 'Revision' => 2, 'md5' => 'abc03eeac10da39b8eb39afb7709ad9b44c819e6e0d43364599702a2d03f31bda2cfa395d72dbb5c4ece0e456370a1d39be41c5f99edc6fe3951fe512fe4162b' }, 'config/stelpro/stzw402.xml' => { 'Revision' => 3, 'md5' => 'd50042a91f9b2fa3e64d618b8caa2f64ea8ec9c74e7fa82840556dc4d5a8ce1b8d8de840c008ff36619d0cb31393f066dd8a7c286af328ae66ffe0d6b5816221' }, 'config/sunricher/srzv9001k12dimz4.xml' => { 'Revision' => 1, 'md5' => '6b8efae2405b4520f0825ea4959244b607cb52fc20b9b0d288e57626057484089968806e94d85e0bb45b35ddfa24622fbf3a5e9a5653cbae419bf94be56a5572' }, 'config/sunricher/srzv9001k12dimz5.xml' => { 'Revision' => 1, 'md5' => 'd14a319efd47406428b3cd0ad80956677c101dc153047aa431883ab88ba949bcdca9bb34a3d8bccaf093e80e4e49938380483f9cec54419138bab69fd9b586c4' }, 'config/sunricher/srzv9001k2dim.xml' => { 'Revision' => 1, 'md5' => '41d10f53ad831e0c2fc8f41fbac2c190f16b367c62b26477a2eb14e168e39af1adac020c25a1852544e142baba6e0f459429fb5f9fd05942e368039b08e28a4a' }, 'config/sunricher/srzv9001k4dim.xml' => { 'Revision' => 1, 'md5' => 'bf389f5cf7a510d2a12729585ea31ffead4f8a38ff7a4fa75c9aeb9ad7f6b1c748b5846b3e4270e381c266f091294c98431c7e7ffff582b4d8a3f2c73e54f460' }, 'config/sunricher/srzv9001k4dimg2.xml' => { 'Revision' => 1, 'md5' => '1885a9182c782e2dc890aba1e3ad0b6b1f7f409aec258809f21dae57e2c52d6e299eb1afc85c7ab86b642d59378fa50a445195b41432239c03c780885a67df25' }, 'config/sunricher/srzv9001k8.xml' => { 'Revision' => 1, 'md5' => '3bac22970afda1d7629827057b92df49076f16258e76ee02674f0aaf0046a847642edb2c794740f2b8b1e9f38d0c2ec3932259b2803ff416f461757214bd0686' }, 'config/sunricher/srzv9001t4dimeu.xml' => { 'Revision' => 2, 'md5' => '211998372694c7f418d774c3dab739339f07167bb37faa972ce076e4de2391dcfe369ea1ea335d35a9db66f9dce34ea0ac3dad054f2f734c864e1462cb0f5d1d' }, 'config/sunricher/srzv9001tccteu.xml' => { 'Revision' => 1, 'md5' => '9d5e9dcce650ab14636ee926ff6fbb2aad0ee2db3d661192c1d438184656b942dd1a68a14eb6c98337bb2fc021ad36e9755c1e9661b631cd83606e708d20212e' }, 'config/sunricher/srzv9003t4rgbweu.xml' => { 'Revision' => 1, 'md5' => 'a8754c4d9762da7d89d509475ce8f495f3e6d8a857c0dd38b10c0afbef1838ef96e417426edafb67403a011bc388c0dc80454fd64de935d9de38f642dc7bb9f6' }, 'config/sunricher/srzv9100aa.xml' => { 'Revision' => 1, 'md5' => 'ce5b3d47d946173fbb99e491614fae353e440732c22bb7208655c44a7e5374ff49ed2ca8f6e39844e43eae88fde38a0aaa057b9770ad90cc8703355cb61c9706' }, 'config/sunricher/srzv9101sachpeu.xml' => { 'Revision' => 2, 'md5' => 'cfa47e28a8463496354a30d2998b5b11dab834b2ffa1b8e91a687d2ec4e9e41ef73d38d058dd60911aa69cb1164808da94b88d627744250e5abd576ea5f8d1fa' }, 'config/sunricher/srzv9101sachpswitch.xml' => { 'Revision' => 1, 'md5' => '3851b6d24fdb58fe341d96c8faa16ed3f584e6a76b741ff8623b692082004602199196458bf1c123c5b1a54f1031369d6ab12db18925d240e277b27a1e307fdb' }, 'config/sunricher/zv2835rac.xml' => { 'Revision' => 1, 'md5' => 'ab598e4f8d3d9b654023428799d1a381f5fcd8d1cf1c97bde4512b8f310be7f026294f7798eb17cdcd07072058be5c8514fec23f5ef713dfbd3d4a5efaf4129d' }, 'config/sunricher/zv9101.xml' => { 'Revision' => 2, 'md5' => 'adb7779262cbea1eb2832f78e67b253cade102bcf7fd24aa14db965dbde11a8ff073ee654c7bf1af0c2c4f44507b97feffdf142ed8261ff163ada4d766b0d906' }, 'config/sunricher/zv9101fa.xml' => { 'Revision' => 1, 'md5' => '1831cf691c954aa9546e99e5f8218b2d05d2aec3c850ee0bbf543947fbde7bfcf20b8e47fb232b4e43d2c6245aa15c94602b1efe48b1553b5daf75a6adeaa9cc' }, 'config/swiid/swiidinter.xml' => { 'Revision' => 3, 'md5' => '66525f843d8663f34af93e65b6979059e294139474aa3f63974f1ddb5e29c431e87ae0deb220a40169028a5e9e7c8553d2b24587afb905703ff14ffb0e6252ab' }, 'config/swiid/swiidplug.xml' => { 'Revision' => 2, 'md5' => '1de9d7c988ff7753ddf936270a4a2abe3e1de1d5e7e546da3f7c02619dec1f875029af669c9607f398f2634833d0b1f40a34e72cf3c8b2898a644e46f980930c' }, 'config/technisat/03009496.xml' => { 'Revision' => 2, 'md5' => '0bd0aad3afe3672049f401e80f8a37579716823e07c924ac161f865a453c2ed1a0013ebf018d841afe915cb95fa582dd74ebe12efae9bf7707d87205d9cc2df7' }, 'config/technisat/03009497.xml' => { 'Revision' => 2, 'md5' => '34c5e7919ba864bac4fa474f24c6d345cefb5bab88e0d1799a6001f6bec1d5aa928377ade84b8440aff857a1e1748939bd3c7a81eb3d0f541c98a83e54e48231' }, 'config/technisat/03009499.xml' => { 'Revision' => 2, 'md5' => '19371e5b7799c19a07ba4a16bf4d5c546e5fdc8ad9dd728276f415a930cae3c66f0249f310e8e331b4f0a6f9a7551f344cf8c11d699fc6f639c5f6450e356159' }, 'config/telldus/tzdw100.xml' => { 'Revision' => 2, 'md5' => '00dafcf5a0bb13180d8cae532067dbd8833c65374d800fe02134732413c02ea4361a2597bfe4bb0466d0bdde93216cdea5474b8aecc3a9d644212f989401bbdd' }, 'config/telldus/tzwp100.xml' => { 'Revision' => 2, 'md5' => '632f66e9679859f3709bb56fd682d027b4076069e0ffde81fd5c90b01e5d1de5eaa4626a9dcba71257aae8abdc4454b50f4540802a273f4a1fdcd7fb53834d77' }, 'config/telldus/tzwp102.xml' => { 'Revision' => 2, 'md5' => 'f68f1a70eccd43240a3f87b647237abb39a5e66e33be3ad413dab356be16c6a4b6391cdfe3cd62d0bf02a0b4c10ea53d8724981040d7911d29fe3db560418cf7' }, 'config/there/800z.xml' => { 'Revision' => 1, 'md5' => 'b065d0460c3da5e6bab88657b36d0c840db877c3c0c89c26313d7fd4bd12f7f57af2045cf89bcd689449989f0902f3ae3c6487fa9842dc45ca4538931e4a134e' }, 'config/thermofloor/heatit-zdim.xml' => { 'Revision' => 2, 'md5' => '627f5761aa76f8e6046e8f0e82d4d6b50a1395f76afb05936ffc2b42f95fcc15d490b4f33d0083e2300d8de65a9b05e66ceea516776ca911c2473e8f46bdbd10' }, 'config/thermofloor/heatit021-v1.92.xml' => { 'Revision' => 1, 'md5' => '9839f51c4a1fd1c63a2d12843f73c341c329222b6032895805026752671aa2d58d7513c3d07cd7a9090e6dc7866faa19f7d7efb20f3e37253de0ad6ac1604dea' }, 'config/thermofloor/heatit021.xml' => { 'Revision' => 9, 'md5' => 'ccb695b1d42cabdee7c16337e69ddc495f7b7ce6bdb208be7f2158c273c566957299a0406037539830b47cdcc853f20f015a3c91976dbf9a76db672fbfd30faf' }, 'config/thermofloor/heatit056.xml' => { 'Revision' => 3, 'md5' => 'd248ea9d79f6da656599bd9237cedde63af5d5789075d9dce1e355980053d8c25d7439a9de79778280f6086588b595f1bb91313e2ca0e42b9bf850c84c78a925' }, 'config/thermofloor/heatit058.xml' => { 'Revision' => 1, 'md5' => '99b5766881cd43d7ca0bd73e3492c11fbbdbdbfc74a7783ba78e44aa6ec97b84d85ac675bf04ed33403abe4e2a9e741a25264d8a7699261038e7b9f143624336' }, 'config/thermofloor/heatit204.xml' => { 'Revision' => 1, 'md5' => '874663630d7aa76d3b5a0c4161cd8ead079ad2fe2dcbc8e9fbf8e6f6cc9acc21083e3441e3b36f6427459ce208cfc209304f3dca22b364e88adec579c79c4174' }, 'config/thermofloor/heatit20a.xml' => { 'Revision' => 3, 'md5' => 'c230bb573e64439be9d40720f4c5a72e901018078ab9d778aaac156666e248686706fe9d81f7b19a9ada774d9284a8a05c4ef1ef2aed9fb5a762c5c05ad1547e' }, 'config/thermofloor/heatitz4.xml' => { 'Revision' => 2, 'md5' => '2be6250742eb2ed930e0aef28513fb85da3dd37f00824a45c0a7af60797954ec46ccb32df5e4ec15a18e48e8cfe199639f77405d76749455d7850d0869be816b' }, 'config/thermofloor/heatitz8.xml' => { 'Revision' => 2, 'md5' => '1fd512de745b166c79f9d16742f87c10b86ef0c259b504f3d2cb9ac081c22ed96c292a68394a5a7be110aafffa67ee82cb54d2f28e6d1c48cf51ff26fc32428f' }, 'config/trane/TZEMT400AB32MAA.xml' => { 'Revision' => 3, 'md5' => '84e5b345ec16db7d5f5c042815674ccc0ed3eba634ff2be99fbbd6b429fb27828a9a2353281bc2979ae43fbe0a86eebab4030b571d1cb03021ffeb678b7a2f04' }, 'config/trane/TZEMT400BB32MAA.xml' => { 'Revision' => 4, 'md5' => '79a3d5ac283db2152c07a4ea52077b69ea83ea0b82e01265367130a649bba9c506777ca0d226ce8d8f43d4b296d1315ff4fac3030b90f3b3f9b1419b186c3fc7' }, 'config/trane/TZEMT524AA21MA.xml' => { 'Revision' => 3, 'md5' => '46e5a829940d1de88207f121808a62c7526871d0740875ef2976f43eebaad9e629651c266bb458c8843da0b0e880532b59d707f93b3e57f2eec4dfbfd04b5853' }, 'config/vera/vera2.xml' => { 'Revision' => 3, 'md5' => 'c50512474aef869c8f849d9ea2d42bd28dd89de9198c3bb6bc95eff66e67ac50567580ac5a3cc9bdfbdb49e9c1fe036d4e6e9a4987a1135dc5d2b3d0d537dbe7' }, 'config/vision/1701.xml' => { 'Revision' => 1, 'md5' => '2e37f21db47a1c100f6631e34105942ae05691ac224e955e9e46352ef8560e6890a59028573d202d8283684d5851b82be04e7b7d6baa2160489f2068c44b43c8' }, 'config/vision/brg1-433.xml' => { 'Revision' => 1, 'md5' => '7f9cdf21fd4ffcc3b7827c024564774932878b74faf99090321c4c9ee4f33c3326a66fc07a233e35ca058198af676a588f6f41e31506bbd1fdf14c59c2459a22' }, 'config/vision/zd2102.xml' => { 'Revision' => 11, 'md5' => 'd7308c12bd68905b955e4c729d96e0b3279e35a6fde798c6650f077a61391fcac0514c2ee54933c30c5bb1c73cdb85b00ae79c93fe7be775702070d2c84eefac' }, 'config/vision/zd2105us5.xml' => { 'Revision' => 3, 'md5' => 'f520919cd7c02a48643a747d677ae891a96960ba84a4eaf90402a7d8a71f801fc924115f82190901eb658e49ad22d84ce5e7d407240b69be011b19373d10ab1d' }, 'config/vision/zd2201.xml' => { 'Revision' => 5, 'md5' => '3186992dc8f959af67ab8dceeedfd6831649dbddd1d15350a854467d6f0219bb4b6187a7a7995a21133f6d58abc6d77129dfd2a34301d17e8a7ef57b04ac1429' }, 'config/vision/zd2301.xml' => { 'Revision' => 4, 'md5' => '5dbdf01ac0aff9cfc9de47fd4bff6d26642b39a0f5b9a98f9590250f637510370ee3e00963cb04b3d1303bcb74228f3b7d2f307105f69cf6233c4fd9cfd4809e' }, 'config/vision/zf5201.xml' => { 'Revision' => 2, 'md5' => 'ae0d16547c69a3cd390ef6604cf68d2b1645e5448e8bbaabbd47c0aa5b90403b21317aef9b2a72f59a48e99169aa2a5c644b3b075c7a067a9a4c199c9bb184b0' }, 'config/vision/zg8101.xml' => { 'Revision' => 2, 'md5' => '04753ab29b0e8827df53af191b9ea264a510c8b50265ffc75d4574d4d299d70fd790a1ae104c22f579ad56fffbf546cc2efbbf71e1c6ee3b6bd3eebdd3e788d2' }, 'config/vision/zl7101us.xml' => { 'Revision' => 1, 'md5' => '9ad8dfe8ea6f9c603a9a960103592fdd5988175b4cba7cc14b7b3728f5aee1d431d097f7728535078ea1da1866924490409fb016ce12ab17c52ee2a3d2ba14d7' }, 'config/vision/zl7201us.xml' => { 'Revision' => 1, 'md5' => '3aa000512b5312b89d6f7e940e632f39fecdedc5c6f1e11b1f87ba64aba6cddb4c6d96f0e27d8600f35840132110be105badbfaf6ee0c021f11c19b96d4627fb' }, 'config/vision/zl7261.xml' => { 'Revision' => 1, 'md5' => '6765ebbdad546c3073673446a63a7b2bda080ec606ea6fccfedd4a49d76d54c1e48fc3c030eb2e44060751012dfde67b564d6c68d9faf40673d846e45b914e47' }, 'config/vision/zl7431.xml' => { 'Revision' => 2, 'md5' => 'd8437300f7533463a987685da39e0412fb06ab2615532125d51530c0aedff578164ec5cba8593b3bacdb7f15623ed11981f5a87169cf6d6068dfaac45810382e' }, 'config/vision/zl7432us.xml' => { 'Revision' => 1, 'md5' => 'b4f4a7ffb44d5d9f74a9c3003b7cacaf1f28162555ac8134b187804369cdd23923e20e67f0a58141a79ac920a52294bc1ab560dd498530c3944507e144777054' }, 'config/vision/zm1601eu.xml' => { 'Revision' => 4, 'md5' => '607da3bf3b0504dcefd2d6fb9312b6c3d21c1cabe6d1acd77b595aa112b0545fc3ebbfece0089796e9ab0c0b41f254ff28ba2e9f63d4f94615c8251064305dc0' }, 'config/vision/zm1601eu5.xml' => { 'Revision' => 3, 'md5' => '0f55aead2c32ce164f7b85ce9a7ea7d718d152fd8840ed48446d662f32144f6f706e17411f6fb5048577bc98c4e6fbb3f4974f6924ed0370f08f8cd44681cfba' }, 'config/vision/zm1602eu.xml' => { 'Revision' => 2, 'md5' => '298b94cc8f598b57409cf5db86304998053639cd0d74a44dae05f5eb69ac4c91ce7e034a1295242fb2784b52271c2d885675b72e8693650b79cd19c437387113' }, 'config/vision/zm1602eu5.xml' => { 'Revision' => 3, 'md5' => '3e86f5e2fd0bd4a9e2ce3c433e017909efbf006ef6c542328907584531bda2f060264e2fa8c30a9b9d9ae644b772d67bff969a7067f8ca5669c789d360ed75a0' }, 'config/vision/zp3102.xml' => { 'Revision' => 11, 'md5' => 'df1f51d8eede5ca5f9fccd106a2b194692280eb96f383ebdfab4035632bccb3b6a8e0c1a0d44f3abbd7b18e9fcb3a91befae4cd35d7659937eff93116ae4526b' }, 'config/vision/zp3111.xml' => { 'Revision' => 6, 'md5' => '54c3b06afbd284c83a935d5c18ccf21340d81e82188e5d88d1d52ffb655e0e5713aaadb28d9fbea214898dec7e2213816f3ef26dbae8aeafd923029b0ad8c46d' }, 'config/vision/zr1202us.xml' => { 'Revision' => 1, 'md5' => '30d2db0054dc86300fc2fb0cee751cd14d017781764f7894c9e5b1873bf1489ff6da0b5f99a29dc6ba5905a6e98b73544d4be7d79824c43c6e8ac9b261f42aea' }, 'config/vision/zs5101eu.xml' => { 'Revision' => 3, 'md5' => '0de921fc8bc657273b35f1b25aede7c0581ee93c0ea21ec57d4b1e61e405a88ed8a433f1ae465d2d0fc67f2e121ca274869eba7095e56f2e9a7b27c95f59be0d' }, 'config/vision/zs610eu.xml' => { 'Revision' => 1, 'md5' => '372e2a37557c006447508e63779aa958c8929369eb36c42c6207e048b28bf0c3322ed21f4a0ef8f58a5f0273e0799fd0b7f3d09fc2e0bcc944fb775888470e92' }, 'config/vision/zu1401jp.xml' => { 'Revision' => 1, 'md5' => '6c3a3747736a8dbc94d55649dfac4757ed1e7f178e17dcb88b0515ec105b97fd51322047d36540fddf38a8a8663f4c95bc2518dc022e4c6eb4a1aac940206b04' }, 'config/vitrum/vitrumI-Dimmer.xml' => { 'Revision' => 3, 'md5' => '238254ee2cc5feb7effc709529fd6b4811416284cc61215fda1384b72ccba66314b152af7684712044f1008a6b7c063ebcce7bed8872c1e657b6d1f8c048c18c' }, 'config/vitrum/vitrumI-Switch.xml' => { 'Revision' => 3, 'md5' => 'd417c83e11e28dfed63f1b1d685ed8c662c1d9733ec7d1bd1a3d42d648ed70361ee4312f1408cdeedeb5ce8d984e3e7b38f4a11f194dc35eacf359f6121c6040' }, 'config/vitrum/vitrumII-Dimmer.xml' => { 'Revision' => 4, 'md5' => '94048824ccffd27bf338bec81a6ac3f4d1b8c0d1c7af307ad1059986f99daac77522976762d51c13fc51e4710c2f6ddde1194d0502364600afc396c3f22d4104' }, 'config/vitrum/vitrumII-RollerBlind.xml' => { 'Revision' => 3, 'md5' => 'd75c8a6739a61a0aa1c1ff6c18a95c06688322ccd131aace8610270d31fa676c4c29d48107643a7ac735d39e1d5a77ad8465c31c47dbb2a7886eba551e8a7c9b' }, 'config/vitrum/vitrumII-Switch.xml' => { 'Revision' => 3, 'md5' => '1809b19960cae19a6a0216b9b63c30fac4fe14ec6f0a5a8f7b6346dff0461f6102d6ecb5e2ff069163e2b58b15b9b1ed9980623905a735273ca59b18f1915ed7' }, 'config/vitrum/vitrumIII-Dimmer.xml' => { 'Revision' => 2, 'md5' => '76f9677eade9e7eef265a6f907b4caf36fac9b6cd076a4ec92622f154416d224cd3e7747925edd95401d95cf1871a20d3d227a8f46fd7c6e090e757d1bbab080' }, 'config/vitrum/vitrumIII-Switch.xml' => { 'Revision' => 2, 'md5' => '76f9677eade9e7eef265a6f907b4caf36fac9b6cd076a4ec92622f154416d224cd3e7747925edd95401d95cf1871a20d3d227a8f46fd7c6e090e757d1bbab080' }, 'config/vitrum/vitrumIV-Switch.xml' => { 'Revision' => 2, 'md5' => '76f9677eade9e7eef265a6f907b4caf36fac9b6cd076a4ec92622f154416d224cd3e7747925edd95401d95cf1871a20d3d227a8f46fd7c6e090e757d1bbab080' }, 'config/vitrum/vitrumVI-Switch.xml' => { 'Revision' => 2, 'md5' => '76f9677eade9e7eef265a6f907b4caf36fac9b6cd076a4ec92622f154416d224cd3e7747925edd95401d95cf1871a20d3d227a8f46fd7c6e090e757d1bbab080' }, 'config/waynedalton/WDTC-20.xml' => { 'Revision' => 2, 'md5' => '8fe2947f5d31a45af7828268702bf711c46263cde3347ce3d6922558f17c98edc1e2aba13f17a4881f45d0dd0ac04977d61b3d417251d491b35e2f708fcb02cd' }, 'config/wenzhou/sm103.xml' => { 'Revision' => 2, 'md5' => '0544e08b5f873a7db0fa70d8771a7d6ab7e0ecaabccf7159fa56e5d4f65a6585e098763beed0cf8fb019c5ca10738194a18f73f66a5c29bd570cccd4f736e77b' }, 'config/wenzhou/tsp01.xml' => { 'Revision' => 5, 'md5' => 'c724909421d7301bb7597c4360b536965ab40649a7db2a054fb19cfd2c29efa18ccd104217510de5814c1e75b387873a042ce6e0650a8a6f23219656ce29cc69' }, 'config/wenzhou/tz55.xml' => { 'Revision' => 3, 'md5' => 'e0e3de23861dc7ff105f07dbaf1d24524364357fceaa2bf4b55f531b28e25f34ccb3f2af802cb1befe5bf41a6c0182f0865bb165c1d16482a68e6c046349b9fd' }, 'config/wenzhou/tz56.xml' => { 'Revision' => 3, 'md5' => '731e37f2f19957d94f40921c7eaf52c9a304676ea91684e3e59c09289b560f17c0ad9079fd9b1dff5054f40382d28cbfed1666bfb7f98b8d958928018c91a016' }, 'config/wenzhou/tz56s.xml' => { 'Revision' => 1, 'md5' => 'd59911b92fff93130529f8c226086cdf87f13bb80e32c52adabc91d1bab6030015ccc6ed67c9dc1abdd549c239464b1729921f17ca9e4c45fea55ed135d52f00' }, 'config/wenzhou/tz57.xml' => { 'Revision' => 1, 'md5' => 'f5010718afca7611e7c7318942c0d01211706a79c746ba0c7e2f3df5102d79b9edf2181e071f8134bc1f56b44020f87815b4e0a7b01dcd6b0f8af11ec92aac2c' }, 'config/wenzhou/tz65d.xml' => { 'Revision' => 6, 'md5' => 'c142e5b7ca34ce4a6f4cbe242ea63587711cbcc454dae6ed28c923a894e11c97f06442523ffac17120c14376674d8eef286115960aac716383ae96afa0b15e4a' }, 'config/wenzhou/tz66d.xml' => { 'Revision' => 4, 'md5' => '33cdf081b881ef7aa341f5372fba065de24dafed60e3aafacabbd25d6092314d97bb56d89fbcfbd2e120531f99f94c68cd66892f12e26371689c6a07efe1b513' }, 'config/wenzhou/tz67.xml' => { 'Revision' => 6, 'md5' => 'b62b4bf4d4b4634460529385eb1427e7f396dfa29cf510a34e1cdb614cfff959ccf8bb5c5604b20bc012955581884efb8808e4c9d0d777976974ffa4f2bdbde2' }, 'config/wenzhou/tz68.xml' => { 'Revision' => 5, 'md5' => '1692f252e441eaddb2efb274f9b6e9b43a60496f074c8e911c0b088699db1833164278bcffc2de8cdd2a0377f63ecd2c8ffb46655042350cd0db86731619a9ae' }, 'config/wenzhou/tz69.xml' => { 'Revision' => 7, 'md5' => '6cab1b3be95dd92fca2e77e4c6320cb6783519302b711502fb5ba9012d8bd0c958c4759b7e3bfd613714f08d0b96c634aed3485a1217bb9277d4e2024666c05c' }, 'config/wenzhou/tz74.xml' => { 'Revision' => 1, 'md5' => 'c468eb5e6431d0b66ff94aa18bbdfd225ef03a95dead2458078dca813074e34b206c949bb685c05a9767f24b508a22e6a1f1a702f1bd591256d1f236acfa2e92' }, 'config/wenzhou/tz77.xml' => { 'Revision' => 2, 'md5' => 'df47b99135b0b10975717373c17b9feb15cfbba1a4c21542f939950495c5bab2f3fa285237bec363192728b8db58d4f9b00fe3d8d6f1ec9edf93517ae01a9025' }, 'config/wenzhou/tz78.xml' => { 'Revision' => 2, 'md5' => 'c796f0198124f0fe0f76e7e0f97956464f6360648ec188c09d54593cc41041b0a7b45ccc8416bb22aca8cd644b22976ab87ff7f121714a42f72d3414a5300d06' }, 'config/wenzhou/tz79.xml' => { 'Revision' => 1, 'md5' => '2bf67e52c7ea08ed1669c002b5d80ca5101bf88c0c0565c1798d177f7b70a21981770fe89a36d07588c2e562a7728b543ae7e64167ad431a6028a6897dff0f3c' }, 'config/wenzhou/tz88.xml' => { 'Revision' => 7, 'md5' => '571fe7897815e47fd1b640f2bdd741b9daee276510e8348bd6e9002e018a8e16c67b00c94ca6f3d0ce15c847c61ae2eaa0146772b7a8c330aab89f31935ed3b3' }, 'config/wenzhou/tze96.xml' => { 'Revision' => 2, 'md5' => 'f98162d3e7d76b60d0ca68d0ad1e4f5f66259b63715e54df16f19fd10b2c572660fbd60bda464e6e2940b1b66bedb442ce95fd75dd6ec48e4b200027d390887a' }, 'config/widom/DRY.xml' => { 'Revision' => 2, 'md5' => 'dbc331ba0466621612841ab0934432f3c8a7f8e1ba8747047c171690458ba373fc426d217749327f972de6e933d02270abd135a659f096b80968f55fe3d49848' }, 'config/widom/UBS104.xml' => { 'Revision' => 2, 'md5' => '6843a6c3d929b4e54a1751853942e8cea1651c35f39722138cd21ef47746103881cf18242518f9c459087950fdf29f051ec90b56f844b1290a47db87d8a2c47b' }, 'config/widom/UME304C_S.xml' => { 'Revision' => 3, 'md5' => 'cedd8b8d8c43c00c9213bb2aec31fca162f048abe3543a7da214bf4ae65eab07429ad6ed9f4c973aa0da220d9243e348b8b4351367fc856b759cd275fb2fb1b7' }, 'config/widom/UMS2.xml' => { 'Revision' => 4, 'md5' => 'd883982d6a5c8c9051c7b91f6085e305eec436c156acd84a29ec4828a2d59c09dd40713761b1af9715a255f54bb9e9f43ed62afb9d7a632a7b68262c08c7bfc0' }, 'config/widom/WDS.xml' => { 'Revision' => 4, 'md5' => 'd990ef6c9e1876d3980827d7e4c084eaab69193252d3bfe118a87b5307e0583eee1f5454ba2e46e89b805802274f857fecf3e9bd5797b3d59745292729f1d6d8' }, 'config/widom/WDS2.xml' => { 'Revision' => 3, 'md5' => '65c40370ac24ad380200889852a6e11bac19b9602f55dbcbf9b60fbce1836402cae2bbfebc9c5fc70bae76696fc602e0e4f405ae6f7b6b8dc280a287dad5d63a' }, 'config/widom/WSP.xml' => { 'Revision' => 3, 'md5' => '51173e77f7aba3abd136dab21471d3331dd5a10b6e91bcf8b7196fc3406b2047cfaf4e29fc01e6d021e994ee94654e69568aea3054bbe74f31d0af2bd416a230' }, 'config/widom/WTED.xml' => { 'Revision' => 4, 'md5' => '810972a874be37eb108bad40e4ddcd4b55ed3a0deeead8e011cbfeb051df44015a6af4e298d4f206f4ee08fb83dcb7a29bf01c56d069c9748821235b4a6c36a3' }, 'config/wink/wnk-mot1.xml' => { 'Revision' => 1, 'md5' => 'ae12eda098b6ce28ea5dc3614d24217dad04f2ab61bf3c2da40dd23ad8d5ffe4cd65b7544f29b8ecc23e514f90df168152d133ac12c873657c0b09e44a77fbaf' }, 'config/wink/wnk-sir1p.xml' => { 'Revision' => 1, 'md5' => '352c501c9d64d726cc42a4fa095b659d22f83e57bea8062b247e35c0c30358a1e321c82a511eb45fd633fc0d3205f38e9a7353e8ecf5f00d572b2ec3c0776059' }, 'config/zipato/MiniKeypad.xml' => { 'Revision' => 3, 'md5' => '1137446900ed79f792ef14c677ae4e99aeca62b977ef3acfcacf114784f6ea82f09471d7c498c977cdc92228cd3e2903afc445f0782186766c7ae21f2dfdf5cd' }, 'config/zipato/RGBBulb.xml' => { 'Revision' => 3, 'md5' => 'f0e8b19dbd8492ebd4751bba9855b96592b66bfe06e6a8788831e35e89a46f14f5376651995f26c0f966e742ca880cfabb26af0696d632195711f554949cde7c' }, 'config/zipato/RGBBulb2.xml' => { 'Revision' => 3, 'md5' => '3ab581bd5b844da008afc3e601f8486bfd9b4e89f627d018b815955a4cee2a537eaa0ef2714ad4ec2e1b9ce69064e4942a29f1f8703f19181333e13b9ebc4c58' }, 'config/zipato/ne-nas-ab02z.xml' => { 'Revision' => 1, 'md5' => 'ed86cd99980acd98951775be9759aaf72bd9641b1e773bb52ac4a9b4d5a0469cf04fe4ee3f722b5645c8e00268add952b41dc461c816b8ecde9d65f30f1d01bf' }, 'config/zipato/pan04.xml' => { 'Revision' => 3, 'md5' => '73a6ceb8dfa58662bf133853184b7786947c388d9764cb4cc7a0d1ff9f02c1f6faff90ba930d6a96da589abb4c779003e1eeccedf9a663c3aa76408cd3e65d8d' }, 'config/zipato/vszd2102.xml' => { 'Revision' => 3, 'md5' => '3a083cdd5300ea8233f80836cf92de77f94789d3621a23911c103d8789ee0fbe46ee50f233e2f6109e0407e9b304072008cfb1efe7a7108194921cfd4e905511' }, 'config/zipato/zp3102.xml' => { 'Revision' => 4, 'md5' => '9b6e2104c590a66f620ce51e77f1318cb413f690600c932ded4d650e2cf822a085eb2ebb4f3293f6a48cb3c408d15b56e8496923143a5500921fc37b76bbe18d' }, 'config/zooz/zen06.xml' => { 'Revision' => 2, 'md5' => '3272685c18a9649d5b938ec972f5d4fc8732fe16a5f2d5e44c42a8023f2051e1844316320a0bb11bf5521dd0a854c8899384ca629725ddcbfec89432382d8ea1' }, 'config/zooz/zen07.xml' => { 'Revision' => 2, 'md5' => 'c96f925786747bb098e22f5ecb671dc52d51736dd1e8c9a83ab84a77bcb9abe6bae0da1f86af32970da18b2f2f3e987bd2ce4bd1cfa5444f702b5ea32e2dca72' }, 'config/zooz/zen15.xml' => { 'Revision' => 3, 'md5' => 'bee21869106becfe025892a4f334af530450727b855ffe9418a110bfec9534a4855eca768f82f2c2ad3a8c0e78caf0cba704f1570850bcb28dcb506a1eddb2bc' }, 'config/zooz/zen16.xml' => { 'Revision' => 4, 'md5' => 'eab1371f2c81d3dac4edeb677afee22eb684fa157dff73bc89e95c93e0421abd949c382b4f2d2203bf6d4d981e913ed31a3080e649694ffdba1ece3fdc46295a' }, 'config/zooz/zen17.xml' => { 'Revision' => 2, 'md5' => 'c2cf58e4c44fba886e7470fdcc8559ed3f574c3e6f34c02a87094d82df463db20996182e56df000eb211022259fcc7aa2a7cad0089783ed511422bccc287bff5' }, 'config/zooz/zen20.xml' => { 'Revision' => 2, 'md5' => 'ac2c564441a145b501c401ca5fbb62806ae9d69a354bf2abebce04f50e6017c10d3f5d3465975ac771cb047b31d4bca8e1fde9f5c910a36d0bb958c3c1b57826' }, 'config/zooz/zen20v2.xml' => { 'Revision' => 3, 'md5' => '24682aa795ae957a903d0b7f75dffa0262dcf814c5373eeb3fd09f6ef434713de998a70f928a0eb6d0c511d6f6011ae07dcbc2ea84b603b73820516daf4396b6' }, 'config/zooz/zen21.xml' => { 'Revision' => 3, 'md5' => '047323e2ed1a3e5340c052d40737fbdb2d2790e225e002f7d58fa3ad32f592da3e2a8cc0f3dd6cc6f06f7b6b505378482be7125db0a335e56abfd478c1cb398b' }, 'config/zooz/zen21v3.xml' => { 'Revision' => 4, 'md5' => '4ae74d9c845b8404d9b87e42f30283452762f82842dac619e7f3ffa05b91dc191351c950caba575c2e05b60e9a47cd66d2ea8c6f361a8c15bc9efe939f81e434' }, 'config/zooz/zen22.xml' => { 'Revision' => 2, 'md5' => '5516b28dbfb21fa8057cf83e04100d7e27a74d6bffa5c8203924fbd139ffee8536552307cab4c29dc92f4d762c99e357eb5f86641bae733fb226d67fab9b09a5' }, 'config/zooz/zen22v2.xml' => { 'Revision' => 3, 'md5' => 'ea4ce1d9800d69e6e04c4ea5317a891575ee49f751f66754f0371bf9894b19504b90b3c8e80c509a8f458d4e989111b21facc9d0cd6740dcddca1e01dc678039' }, 'config/zooz/zen23.xml' => { 'Revision' => 1, 'md5' => 'b5609b50b35f91a81c21293680581f6a5bfd69cadfdc7987d41f1a41380553d7250fc4ac75d00b2057cf7ec54f5a8479bbe793682e2fcfe207aaa301889fce6f' }, 'config/zooz/zen23v3.xml' => { 'Revision' => 2, 'md5' => '1760d6685c1bdba5b9dc8310c443d8b9badfe505c3b0800ece20d8951d6f35833036d883e4777635449754d0a97618e43d80af9b801d80512bf78b298a18d606' }, 'config/zooz/zen24.xml' => { 'Revision' => 1, 'md5' => '818d5a9b417d8e06cb5864ec4859d82d30d5d2e6e91bbd4672ac3fd84b20585b8c8529c327e0ac49359276674bf7e3cd15f0ac4f812896bf334c24963f6abd18' }, 'config/zooz/zen24v2.xml' => { 'Revision' => 3, 'md5' => '7e5357ea8bfd73d38525c27b3cacf13c157a5a036cc54b0f2cc01d04d39f0ac2c916e6ff28bdc3fd47a1fa2b2fdbf4c17ac89dc9adff4e36a245251ad896ad51' }, 'config/zooz/zen25.xml' => { 'Revision' => 1, 'md5' => 'a1518c737c0eb0b63610dca95ebece7df7be426b8b435fb309314f110c77ddb90146d0b03888d2ac03959b2bfd6d181edb7b71cc59c798aeb7f5fa341c4f0d4d' }, 'config/zooz/zen26.xml' => { 'Revision' => 4, 'md5' => 'c416e8c6296c859c66c9b5817d2a0f4e2d805830019c215e95b4cc160bc95d040f974ee074c96a2c1318c790a91b152665372d2bdb1dcdeef86eef935f741c17' }, 'config/zooz/zen27.xml' => { 'Revision' => 4, 'md5' => '8ab077ab311e67b716860e7d96baea98c08409fdfd12c94e96c814c72e54581d4a418adc97ca25515f6fe9ff36b29abcbfd40a3c00e1220030d0db570d427a9a' }, 'config/zooz/zen30.xml' => { 'Revision' => 3, 'md5' => '97c43b277e9ebdad3e538426470242ddf856e571495ffefe0b64cf6d89c1d654412bfa59a12a89ec0970637ea8cc473d6693802bda28f2190176a007cb9b0f10' }, 'config/zooz/zen31.xml' => { 'Revision' => 2, 'md5' => 'a4ee0ec974ffa1fe6c1e46f0610ad8a2623504b1f52b5d20efdcf665548ca4229d0c9a6c782e5da97b4869dfd2f38b5640f6748424b91f8516dc7cffbf5a0799' }, 'config/zooz/zen32.xml' => { 'Revision' => 1, 'md5' => '44780a6b6961e573dbe019f6b8c40608694908c2047e0c5801e5ca5af0f074447b17e60d90ad2a6bb3ece3c7a023f974507aa3af2b50ee89aa48fd5b953266c6' }, 'config/zooz/zen34.xml' => { 'Revision' => 3, 'md5' => 'd5fa659b35e2b666f4127ae68be223e21808e9828629b29d1fe7abe24b40b6dcf33b6af2ad0ba06eef6975a14b4d65f078940b956ce58f94281cdf0116f01dcd' }, 'config/zooz/zen71.xml' => { 'Revision' => 1, 'md5' => '532785efd4cddfb32361dfd76d09d403882b7df7073a05546df9b03fc9d7e46132596c2889f4674d2ddfe71a221bb64d2b5c8689e6ba5335be2b4f6b1a7509dd' }, 'config/zooz/zen72.xml' => { 'Revision' => 3, 'md5' => 'd90c8971f61267ff65180507bd10e92fbd9086a6599b63bf0ba0820c85b2e7568938129a1f918c8b195636b1fe8f7520ac007b0d808b79210741949293465100' }, 'config/zooz/zen76.xml' => { 'Revision' => 1, 'md5' => 'ad4c7d4bde0b987ab90cf12038946d95c464473145a16c7082c013ec0f4a258274f6d7a9cd2197d4d990f8fc3726e56dc946b3a835158ebe48ab2bd3f9273713' }, 'config/zooz/zen77.xml' => { 'Revision' => 1, 'md5' => '26355b030745a5bac773e0aceaf8813c34f1137ba67e95e843455521a0035cbbe68d37aabfdfbeac0570d150c6a4756b6a93667f45e73339f612fb0aeb247843' }, 'config/zooz/zse08.xml' => { 'Revision' => 1, 'md5' => '78ecc6bdf19ce151d87a328949b4ce16e59bf6fd20212d4a7fd23da700e177259b8903bba5150f87c71f7d6ec4b140855c5337b5053cc358b0e2e8c5c41885dc' }, 'config/zooz/zse09.xml' => { 'Revision' => 5, 'md5' => 'b50183e6c2dc5b4b9678ad3cdd96198e14eaabecf9fcb02783b5027d6cfcc34761eb1ffcf7667e5775b989e624138bfedda4dd5f43caf95d33c5a3d85653fe63' }, 'config/zooz/zse18.xml' => { 'Revision' => 1, 'md5' => '463b089a041215ad5c2f2576648a86d2720477f4d1be2e9f3c8914a9c97e8bd31f1b9cd7300019ffc99224d8da0b9fcac78f2f134fbd6f1b68f3027f2392b753' }, 'config/zooz/zse19.xml' => { 'Revision' => 2, 'md5' => 'b7115353998366bdeebc3f5bd1182429f1c20e0e229ca5e22eb7c6d5fb0e617f5af16faac078ed29c17db01c6e1338628a34d3434e8adfcd1cc08b8a59dcdd2c' }, 'config/zooz/zse29.xml' => { 'Revision' => 3, 'md5' => '0729a5e7b22ffb12c69f1ac58471a9098cceee7f88adb2f86955238a243c92178960e6d7e24c255d7e35ca09570dd60f1174a98ffbd01ccf2c1de92c8e28c675' }, 'config/zooz/zse30.xml' => { 'Revision' => 2, 'md5' => '16731dc5b294943714a42063058ccbbcaa230b5fc3afd675b9ce340dbfd6466f22ffea32b6d055d8ef5bac341bd86123b490e62509c71f97e0cd3a35a8e23203' }, 'config/zooz/zse33.xml' => { 'Revision' => 2, 'md5' => '0484e37ea12b75ce8b33c7501a01c8fd45c2176e0c696ceedc3699a94f71e8bc08ffd425336f58e202c8adba41799a4af0c39d6ca109ba501b5f2fdcffb301a4' }, 'config/zooz/zse40.xml' => { 'Revision' => 4, 'md5' => '1e0ed06e4dd0df87cd985a28f0f1d89c32da3f4568334aae4ed0cf8c525910d43b63a8f4a426d5ee1c71328dc75f58fe0d900d24594f19c7b6ef337a77452d4e' }, 'config/zwave.me/004001.xml' => { 'Revision' => 1, 'md5' => '2c21b7cc32d607fcd6d52cd111dd083607ec2ee55317aa272a373b94aa7c7b78b21b84a98d9a658d89c2233e087413b9e20c7354baacef8a90db5662045d74a8' }, 'config/zwave.me/ZME_05431.xml' => { 'Revision' => 4, 'md5' => 'f6cd0740204353d2dec8fd5e67077f5b7ec5733aff9e4e503c03915c8788f1c03b0efbb8ed70564d238f7e26efefb1cd1deb0c0bb8da210cb791268a4799f222' }, 'config/zwave.me/ZME_05461.xml' => { 'Revision' => 2, 'md5' => '4e05c806c751e12377a794db656f71237b85ba40d033061476b23b1d01578dde05a64a88aca5e5aa807df7d75387d6c961d6dd0f1b5efe40df8d05706d171ffa' }, 'config/zwave.me/ZME_06433.xml' => { 'Revision' => 4, 'md5' => 'a287cd866ea81ee15fc83c90dc6bb3eb535d20f2e125697a97a468b73133aa4195674a0b72e118afc0618b11b7201dcce48e7ab91225df704fcd74fef19f4504' }, 'config/zwave.me/ZME_06436.xml' => { 'Revision' => 4, 'md5' => 'ec35ca48a16152672c4aa51e07df7d31ef6e38b00fca9868bd5983a3e1a6d293247c90715e6e9e337b4eb0fcdb2a93a74fcf152038d65f5942d0e546dcc84c9f' }, 'config/zwave.me/ZME_064381.xml' => { 'Revision' => 1, 'md5' => 'e148ecf81796136f400a5753cd6f9ffebe3ce7c13bdfbeeecc91637eee63af3dbecaf6ba3f781080011c3151994d25c128810b80253bfda858e75dee7f313c0c' }, 'config/zwave.me/ZME_064435.xml' => { 'Revision' => 3, 'md5' => '1625ec4dcadb0ae4d8b949997385f4abe0f185cc3b615abd38164a2cf4b5761eaac9bdd6dba2e713c7cd4a9e866ad0b2f0ed41216c7591a3ed46057930627be8' }, 'config/zwave.me/ZME_KFOB-S.xml' => { 'Revision' => 2, 'md5' => '84e5940a1b022d8da95bfe9b067e17e66767fec7da22c1a1eb350fb3cf18eb175532fd062566f3c62b7a77e211f539ad17467c762b476c237cd1322fd52f74bb' }, 'config/zwave.me/ZME_RC2.xml' => { 'Revision' => 2, 'md5' => 'bfa124a8d90e7fc44894600c87a61831533dd38a39af56190580464bbaf15665b677a7386266d050f607d138d672b0852c57fe4a1dc0ac188bfd26c2cfb437c7' }, 'config/zwave.me/ZME_WALLC-S.xml' => { 'Revision' => 3, 'md5' => '621f081bad2efff30abef88abeebf5e28f06c9bdd01d1dec4231839666d836e08e50a83a3b839322e8916135ba362175dd2727c05f1338dd4f4204e4608ffa24' }, 'config/zwave.me/ZME_WCD2.xml' => { 'Revision' => 3, 'md5' => '90b00f6c25ecfabd71029590bb0d5a20bd2265297d01ba15ab11e4f9f2dd60d63bdb0cc1988bd03c1b1e3420622848bdc80c7b039a7b31c2a50627dd3c8d1e39' }, 'config/zwave.me/ZUno.xml' => { 'Revision' => 4, 'md5' => '74246cca8439213f22c8000f53c8f7599bbed8ce05fb24f8a28ed5179e1625d66584e5c0511a9ce2d464173816aad3dc9563f72042960ca2f129b36d4e48f6ef' }, 'config/zwave.me/iTemp.xml' => { 'Revision' => 3, 'md5' => 'c5e295ffeab7af317db7d2a4a7b619d26dcf253e2a442c626564902bc0a99f40f009a309e1b25c87edd00296e080cb7c737a0abb7eb67e50f9544b0a5f8d2403' }, 'config/zwave.me/kfob.xml' => { 'Revision' => 3, 'md5' => 'c071ad553d96f6e79fa728e477dd6a12c9ddb0a029f69657ee65a2438bf9fdf9c9ee3d57084e6ddfb35a346a54bb51a8c4708642b40968041df0a336a2cba0c4' }, 'config/zwave.me/popp_kfob-c.xml' => { 'Revision' => 4, 'md5' => '91374eeabd5950ae498de528ee67309d78f87bc3f2d18b1cb73e06f4d16f660eb0099e583397e7003a0a5796d7261f5f5ec029ba67ef683319d35c20da4cd3a3' }, 'config/zwave.me/razberry.xml' => { 'Revision' => 1, 'md5' => '5cf581246a71ff451015e9286788a0398788494bdb014ea7a77efd3d4b36e6c7b5ebc9ce2e05471b35a59539ebb5927c75575d56bcb34d99a2e3507f492eb3c6' }, 'config/zwave.me/zme_raz5.xml' => { 'Revision' => 2, 'md5' => 'cdfd903cab9349c17a53d25ff8210d42a5f9197ebbe8fd3e654dc5caedc12c40e96bcb3fadfdf72ce3e05d59c99de58fd21858be5ca8c2c820c8d315e3415149' }, 'config/zwave.me/zweather.xml' => { 'Revision' => 2, 'md5' => 'f40e1e4cc7ff539af041862b90ccf3dc74b602fab35a6e74a406694ee29283077d3b1cd418b52fcdee30269e75e9b07155024cb5f62cb1bebc5fef8012492ba6' }, 'config/zwp/PA-100.xml' => { 'Revision' => 2, 'md5' => '93335c6b61d2f82b5bdc62d2c48cb3e10bf2bad3ea39c9e0e7a82d191e3b74b23937f6c12f473fd5243983382337b23b652dc64f663c74fcd3f1a99be4e58ec4' }, 'config/zwp/WD-100.xml' => { 'Revision' => 3, 'md5' => 'a5bceb54540c63bdc1f03a6f26ff79f1bba74af878895b8f70cdfe67fdd6165c366b1cea29f44a5773549655012aafd4c8cd35fa78180ad30cd1b39de36357e6' } ); openzwave-1.6.1914/cpp/build/winRT/0000777000175200017520000000000014032143177013732 500000000000000openzwave-1.6.1914/cpp/build/winRT/vs2015/0000777000175200017520000000000014032143177014672 500000000000000openzwave-1.6.1914/cpp/build/winRT/vs2015/OpenZWave.sln0000644000175200017520000000316514032142455017205 00000000000000 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenZWave", "OpenZWave.vcxproj", "{E830F9D6-8173-4B0B-9ECE-CAADFA531B54}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|ARM = Release|ARM Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {E830F9D6-8173-4B0B-9ECE-CAADFA531B54}.Debug|ARM.ActiveCfg = Debug|ARM {E830F9D6-8173-4B0B-9ECE-CAADFA531B54}.Debug|ARM.Build.0 = Debug|ARM {E830F9D6-8173-4B0B-9ECE-CAADFA531B54}.Debug|x64.ActiveCfg = Debug|x64 {E830F9D6-8173-4B0B-9ECE-CAADFA531B54}.Debug|x64.Build.0 = Debug|x64 {E830F9D6-8173-4B0B-9ECE-CAADFA531B54}.Debug|x86.ActiveCfg = Debug|Win32 {E830F9D6-8173-4B0B-9ECE-CAADFA531B54}.Debug|x86.Build.0 = Debug|Win32 {E830F9D6-8173-4B0B-9ECE-CAADFA531B54}.Release|ARM.ActiveCfg = Release|ARM {E830F9D6-8173-4B0B-9ECE-CAADFA531B54}.Release|ARM.Build.0 = Release|ARM {E830F9D6-8173-4B0B-9ECE-CAADFA531B54}.Release|x64.ActiveCfg = Release|x64 {E830F9D6-8173-4B0B-9ECE-CAADFA531B54}.Release|x64.Build.0 = Release|x64 {E830F9D6-8173-4B0B-9ECE-CAADFA531B54}.Release|x86.ActiveCfg = Release|Win32 {E830F9D6-8173-4B0B-9ECE-CAADFA531B54}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal openzwave-1.6.1914/cpp/build/winRT/vs2015/OpenZWave.vcxproj.filters0000644000175200017520000012530214032142455021551 00000000000000 {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms {ad9f0909-64c6-4295-90a6-3a8fd944f6fa} {320ad2da-52a3-4cda-a17e-1e32b837539e} {7949eeba-8cef-4504-887d-a08c9ea0ad3d} {02437854-1343-4032-906a-be36f5d1a90f} {0a3fdc63-a605-4f13-8674-bf166df28af5} {a24496cb-7034-4cad-af79-15d2983c84dc} {1f415adf-d268-4000-a737-1409f46c6534} {d141dfa6-424a-465c-b339-38ca596a6c12} {58419e2c-1381-4c50-9d31-b6b4a416a7b5} AES AES AES AES AES Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Main Main Main Main Main Main Main Main Main Main Main Main Platform\WinRT Platform Platform Platform Platform Platform Platform Platform Platform Platform Platform Platform TinyXML TinyXML Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Main Platform Command Classes Command Classes Command Classes Main Command Classes Main Platform Command Classes Command Classes Command Classes Platform Platform\WinRT AES AES AES AES Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Main Main Main Main Main Main Main Main Main Main Platform Platform Platform Platform Platform Platform Platform Platform Platform Platform TinyXML TinyXML TinyXML TinyXML Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Main Platform Command Classes Command Classes Command Classes Main Command Classes Main Platform Command Classes Main Command Classes Command Classes Platform Platform\WinRT Platform\WinRT Platform\WinRT Platform\WinRT Platform\WinRT Platform\WinRT Platform\WinRT Platform\WinRT Platform\WinRT Platform\WinRT Main config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config config openzwave-1.6.1914/cpp/build/winRT/vs2015/OpenZWave.vcxproj0000644000175200017520000010544014032142455020103 00000000000000 Debug ARM Debug ARM64 Debug Win32 Debug x64 Release ARM64 Release ARM Release Win32 Release x64 {e830f9d6-8173-4b0b-9ece-caadfa531b54} StaticLibrary OpenZWave OpenZWave en-US 14.0 true Windows Store 10.0.14393.0 10.0.10240.0 10.0 StaticLibrary true $(DefaultPlatformToolset) StaticLibrary true $(DefaultPlatformToolset) StaticLibrary true $(DefaultPlatformToolset) StaticLibrary true $(DefaultPlatformToolset) StaticLibrary false true $(DefaultPlatformToolset) StaticLibrary false true $(DefaultPlatformToolset) StaticLibrary false true $(DefaultPlatformToolset) StaticLibrary false true $(DefaultPlatformToolset) false $(SolutionDir)$(PlatformTarget)\$(Configuration)\$(MSBuildProjectName)\ $(PlatformTarget)\$(Configuration)\ false $(SolutionDir)$(PlatformTarget)\$(Configuration)\$(MSBuildProjectName)\ $(PlatformTarget)\$(Configuration)\ false $(SolutionDir)$(PlatformTarget)\$(Configuration)\$(MSBuildProjectName)\ $(PlatformTarget)\$(Configuration)\ false $(SolutionDir)$(PlatformTarget)\$(Configuration)\$(MSBuildProjectName)\ $(PlatformTarget)\$(Configuration)\ false $(SolutionDir)$(PlatformTarget)\$(Configuration)\$(MSBuildProjectName)\ $(PlatformTarget)\$(Configuration)\ false $(SolutionDir)$(PlatformTarget)\$(Configuration)\$(MSBuildProjectName)\ $(PlatformTarget)\$(Configuration)\ false $(SolutionDir)$(PlatformTarget)\$(Configuration)\$(MSBuildProjectName)\ $(PlatformTarget)\$(Configuration)\ false $(SolutionDir)$(PlatformTarget)\$(Configuration)\$(MSBuildProjectName)\ $(PlatformTarget)\$(Configuration)\ NotUsing true true WINRT;%(PreprocessorDefinitions) ..\..\..\tinyxml;..\..\..\src;..\..\..\hidapi\hidapi;%(AdditionalIncludeDirectories) Console false false del ..\..\windows\winversion.cpp CALL $(ProjectDir)\..\..\windows\GIT-VS-VERSION-GEN.bat "$(ProjectDir)\" "..\..\windows\winversion.cpp" Xcopy /E /I /Y ..\..\..\..\config config\ exit 0 NotUsing true true WINRT;%(PreprocessorDefinitions) ..\..\..\tinyxml;..\..\..\src;..\..\..\hidapi\hidapi;%(AdditionalIncludeDirectories) Console false false del ..\..\windows\winversion.cpp CALL $(ProjectDir)\..\..\windows\GIT-VS-VERSION-GEN.bat "$(ProjectDir)\" "..\..\windows\winversion.cpp" Xcopy /E /I /Y ..\..\..\..\config config\ exit 0 NotUsing true true LITTLE_ENDIAN;WINRT;%(PreprocessorDefinitions) ..\..\..\tinyxml;..\..\..\src;..\..\..\hidapi\hidapi;%(AdditionalIncludeDirectories) Console false false del ..\..\windows\winversion.cpp CALL "$(ProjectDir)\..\..\windows\GIT-VS-VERSION-GEN.bat" "$(ProjectDir)\" "..\..\windows\winversion.cpp" Xcopy /E /I /Y ..\..\..\..\config config\ exit 0 NotUsing true true LITTLE_ENDIAN;WINRT;%(PreprocessorDefinitions) ..\..\..\tinyxml;..\..\..\src;..\..\..\hidapi\hidapi;%(AdditionalIncludeDirectories) Console false false del ..\..\windows\winversion.cpp CALL "$(ProjectDir)\..\..\windows\GIT-VS-VERSION-GEN.bat" "$(ProjectDir)\" "..\..\windows\winversion.cpp" Xcopy /E /I /Y ..\..\..\..\config config\ exit 0 NotUsing true true LITTLE_ENDIAN;WINRT;%(PreprocessorDefinitions) ..\..\..\tinyxml;..\..\..\src;..\..\..\hidapi\hidapi;%(AdditionalIncludeDirectories) Console false false del ..\..\windows\winversion.cpp CALL "$(ProjectDir)\..\..\windows\GIT-VS-VERSION-GEN.bat" "$(ProjectDir)\" "..\..\windows\winversion.cpp" Xcopy /E /I /Y ..\..\..\..\config config\ exit 0 NotUsing true true LITTLE_ENDIAN;WINRT;%(PreprocessorDefinitions) ..\..\..\tinyxml;..\..\..\src;..\..\..\hidapi\hidapi;%(AdditionalIncludeDirectories) Console false false del ..\..\windows\winversion.cpp CALL "$(ProjectDir)\..\..\windows\GIT-VS-VERSION-GEN.bat" "$(ProjectDir)\" "..\..\windows\winversion.cpp" Xcopy /E /I /Y ..\..\..\..\config config\ exit 0 NotUsing true true WINRT;%(PreprocessorDefinitions) ..\..\..\tinyxml;..\..\..\src;..\..\..\hidapi\hidapi;%(AdditionalIncludeDirectories) Console false false del ..\..\windows\winversion.cpp CALL $(ProjectDir)\..\..\windows\GIT-VS-VERSION-GEN.bat "$(ProjectDir)\" "..\..\windows\winversion.cpp" Xcopy /E /I /Y ..\..\..\..\config config\ exit 0 MachineX64 NotUsing true true WINRT;%(PreprocessorDefinitions) ..\..\..\tinyxml;..\..\..\src;E:\GitHub\OpenZWave\openzwave-dotnet-uwp\open-zwave\cpp\hidapi\hidapi;%(AdditionalIncludeDirectories) Console false false del ..\..\windows\winversion.cpp CALL $(ProjectDir)\..\..\windows\GIT-VS-VERSION-GEN.bat "$(ProjectDir)\" "..\..\windows\winversion.cpp" Xcopy /E /I /Y ..\..\..\..\config config\ exit 0 MachineX64 false false false false openzwave-1.6.1914/cpp/build/OZW_RunTests.sh0000755000175200017520000000246514032142455015475 00000000000000#/bin/sh #### Include the library . `dirname $0`/sh2ju.sh topsrcdir=$1 #### Clean old reports juLogClean #### A call to a customized method CheckXML() { xmllint --noout --schema $* return $? } juLog -name=CheckDeviceClassesXML CheckXML "$topsrcdir/config/device_classes.xsd $topsrcdir/config/device_classes.xml" juLog -name=CheckOptionsXML CheckXML "$topsrcdir/config/options.xsd $topsrcdir/config/options.xml" juLog -name=CheckManufactureSpecificXML CheckXML "$topsrcdir/config/manufacturer_specific.xsd $topsrcdir/config/manufacturer_specific.xml" juLog -name=CheckLocalizationXML CheckXML "$topsrcdir/config/Localization.xsd $topsrcdir/config/Localization.xml" juLog -name=CheckNotificationTypesXML CheckXML "$topsrcdir/config/NotificationCCTypes.xsd $topsrcdir/config/NotificationCCTypes.xml" juLog -name=CheckSensorMultiLevelTypesXML CheckXML "$topsrcdir/config/SensorMultiLevelCCTypes.xsd $topsrcdir/config/SensorMultiLevelCCTypes.xml" for file in $(find $topsrcdir/config/ \( -name "*.xml" ! -name "device_classes.xml" ! -name "options.xml" ! -name "manufacturer_specific.xml" ! -name "Localization.xml" ! -name "NotificationCCTypes.xml" ! -name "SensorMultiLevelCCTypes.xml" \) ) do juLog -name=$file CheckXML "$topsrcdir/config/device_configuration.xsd $file" done cpp/build/testconfig.pl --outputxmlopenzwave-1.6.1914/cpp/build/libopenzwave.pc.in0000644000175200017520000000056514032142455016245 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ sysconfdir=@sysconfdir@ gitversion=@gitversion@ docdir=@docdir@ Name: libopenzwave Description: A Open Source implementation of the ZWave Serial API URL: http://www.openzwave.org/ Version: @VERSION@ Libs: -L${libdir} -lopenzwave Cflags: -I${includedir} Libs.private: @LIBS@ openzwave-1.6.1914/cpp/build/support.mk0000644000175200017520000001377214032142455014660 00000000000000#The Major Version Number VERSION_MAJ ?= 1 #The Minor Version Number VERSION_MIN ?= 6 #the build type we are making (release or debug) BUILD ?= release #the prefix to install the library into PREFIX ?= /usr/local # dont build HID support by default USE_HID ?= 0 # use builtin tinyXML by default USE_BI_TXML ?= 1 #the System we are building on UNAME := $(shell uname -s) # The version of macOS we might be building on DARWIN_VERSION = 0 # A simple flag to help determine if we're building on 10.14 or greater # 0 = false, 1 = true DARWIN_MOJAVE_UP = 0 ifeq ($(UNAME),Darwin) # Returns a macOS version number as `10.14` DARWIN_VERSION := $(shell sw_vers -productVersion) DARWIN_MOJAVE_UP := $(shell expr $(DARWIN_VERSION) \>= 10.14) endif #the location of Doxygen to generate our api documentation DOXYGEN := $(shell which doxygen) #dot is required for doxygen (part of Graphviz) DOT := $(shell which dot) #the machine type we are building on (i686 or x86_64) MACHINE := $(shell uname -m) #the location of xmllink for checking our config files XMLLINT := $(shell which xmllint) #temp directory to build our tarfile for make dist target TMP := /tmp #pkg-config binary for package config files PKGCONFIG := $(shell which pkg-config) #git binary for doing a make dist export GIT := $(shell which git) #check if this is a Git Checkout, or a Distribution File GITDIR := $(wildcard $(top_srcdir)/.git/) ifneq ($(GITDIR),) ifneq ($(GIT),0) GITCO := 1 else GITCO := 0 endif else GITCO := 0 endif ifeq ($(GITCO), 1) _ := $(shell $(GIT) -C $(top_srcdir) update-index --assume-unchanged dist/openzwave.spec 2>&1) ifneq ($(_),) $(warning git update-index returned: $(_)) endif GITVERSION := $(shell $(GIT) -C $(top_srcdir) describe --long --tags --dirty 2>/dev/null | sed s/^v//) _ := $(shell $(GIT) -C $(top_srcdir) update-index --no-assume-unchanged dist/openzwave.spec 2>&1) ifneq ($(_),) $(warning git update-index returned: $(_)) endif ifeq ($(GITVERSION),) $(warning git describe returned an empty result, setting GITVERSION to VERSION_MAJ.VERSION_MIN.-1 and VERSION_REV to 0) GITVERSION := $(VERSION_MAJ).$(VERSION_MIN).-1 VERSION_REV := 0 else VERSION_REV ?= $(shell echo $(GITVERSION) | awk '{split($$0,a,"-"); print a[2]}') endif else ifeq ($(VERSION_REV),) VERFILE := $(wildcard $(top_srcdir)/cpp/src/vers.cpp) ifneq ($(VERFILE),) VERSION_REV := $(shell sed -n 's/uint16_t ozw_vers_revision = \(.*\);$$/\1/p' $(VERFILE)) else $(warning Missing Either Git Binary, Not a Source Checkout or doesn't have a vers.cpp) endif endif endif ifeq ($(VERSION_REV),) VERSION_REV ?= 0 endif # version number to use on the shared library VERSION := $(VERSION_MAJ).$(VERSION_MIN) # using seting from bitbake ifeq ($(BITBAKE_ENV),1) CC := $(CC) CXX := $(CXX) LD := $(CXX) AR := $(AR) RANLIB := $(RANLIB) else # support Cross Compiling options ifeq ($(UNAME),FreeBSD) # Actually hide behind c++ which works for both clang based 10.0 and earlier(?) CC := $(CROSS_COMPILE)cc CXX := $(CROSS_COMPILE)c++ LD := $(CROSS_COMPILE)c++ else CC := $(CROSS_COMPILE)gcc CXX := $(CROSS_COMPILE)g++ LD := $(CROSS_COMPILE)g++ endif ifeq ($(UNAME),Darwin) AR := libtool -static -o RANLIB := ranlib CC := clang CXX := clang++ LD := clang++ else AR := $(CROSS_COMPILE)ar rc RANLIB := $(CROSS_COMPILE)ranlib endif endif SED := sed #determine if we are release or debug Build and set appropriate flags ifeq ($(BUILD), release) CFLAGS += -c $(RELEASE_CFLAGS) CPPFLAGS += $(RELEASE_CPPFLAGS) LDFLAGS += $(RELEASE_LDFLAGS) else CFLAGS += -c $(DEBUG_CFLAGS) CPPFLAGS += $(DEBUG_CPPFLAGS) LDFLAGS += $(DEBUG_LDFLAGS) endif #if /lib64 exists, then setup x86_64 library path to lib64 (good indication if a linux has /lib and lib64). #Else, if it doesnt, then set as /lib. This is used in the make install target ifeq ($(wildcard /lib64),) instlibdir.x86_64 = /lib/ else instlibdir.x86_64 = /lib64/ endif instlibdir.default = /lib/ #our actual install location for the library ifneq ($(instlibdir.$(MACHINE)),) instlibdir ?= $(PREFIX)$(instlibdir.$(MACHINE)) else instlibdir ?= $(PREFIX)$(instlibdir.default) endif #pkg-config doesn't exist, lets try to guess best place to put the pc file ifeq ($(PKGCONFIG),) pkgconfigdir ?= $(shell if [ -d "/usr/lib64/pkgconfig" ]; then echo "/usr/lib64/pkgconfig"; else echo "/usr/lib/pkgconfig"; fi) else pkgconfigdir ?= $(shell test -d "$(instlibdir)/pkgconfig" && echo "$(instlibdir)/pkgconfig" || pkg-config --variable pc_path pkg-config | awk -F: '{ print $$1 }') endif ifeq ($(BITBAKE_ENV),1) sysconfdir := $(PREFIX)/etc/openzwave/ includedir := $(PREFIX)/include/openzwave/ docdir := $(PREFIX)/share/doc/openzwave-$(VERSION).$(VERSION_REV) else sysconfdir ?= $(PREFIX)/etc/openzwave/ includedir ?= $(PREFIX)/include/openzwave/ docdir ?= $(PREFIX)/share/doc/openzwave-$(VERSION).$(VERSION_REV) endif top_builddir ?= $(CURDIR) export top_builddir OBJDIR = $(top_builddir)/.lib DEPDIR = $(top_builddir)/.dep ifeq ($(UNAME),NetBSD) FMTCMD = fmt -g 1 else FMTCMD = fmt -1 endif $(OBJDIR)/%.o : %.cpp @echo "Building $(<:$(top_builddir)/cpp/%=%)" @$(CXX) -MM $(CFLAGS) $(CPPFLAGS) $(INCLUDES) $< > $(DEPDIR)/$*.d @mv -f $(DEPDIR)/$*.d $(DEPDIR)/$*.d.tmp @$(SED) -e 's|.*:|$(OBJDIR)/$*.o: $(DEPDIR)/$*.d|' < $(DEPDIR)/$*.d.tmp > $(DEPDIR)/$*.d; @$(SED) -e 's/.*://' -e 's/\\$$//' < $(DEPDIR)/$*.d.tmp | $(FMTCMD) | \ $(SED) -e 's/^ *//' -e 's/$$/:/' >> $(DEPDIR)/.$*.d; @rm -f $(DEPDIR)/$*.d.tmp @$(CXX) $(CFLAGS) $(CPPFLAGS) $(TARCH) $(INCLUDES) -o $@ $< $(OBJDIR)/%.o : %.c @echo "Building $(<:$(top_builddir)/cpp/src/%=%)" @$(CC) -MM $(CFLAGS) $(INCLUDES) $< > $(DEPDIR)/$*.d @mv -f $(DEPDIR)/$*.d $(DEPDIR)/$*.d.tmp @$(SED) -e 's|.*:|$(OBJDIR)/$*.o: $(DEPDIR)/$*.d|' < $(DEPDIR)/$*.d.tmp > $(DEPDIR)/$*.d; @$(SED) -e 's/.*://' -e 's/\\$$//' < $(DEPDIR)/$*.d.tmp | $(FMTCMD) | \ $(SED) -e 's/^ *//' -e 's/$$/:/' >> $(DEPDIR)/.$*.d; @rm -f $(DEPDIR)/$*.d.tmp @$(CC) $(CFLAGS) $(TARCH) $(INCLUDES) -o $@ $< dummy := $(shell test -d $(OBJDIR) || mkdir -p $(OBJDIR)) dummy := $(shell test -d $(DEPDIR) || mkdir -p $(DEPDIR)) openzwave-1.6.1914/cpp/build/sh2ju.sh0000644000175200017520000000727514032142455014203 00000000000000#!/bin/sh ### Copyright 2010 Manuel Carrasco Moñino. (manolo at apache.org) ### ### Licensed under the Apache License, Version 2.0. ### You may obtain a copy of it at ### http://www.apache.org/licenses/LICENSE-2.0 ### ### A library for shell scripts which creates reports in jUnit format. ### These reports can be used in Jenkins, or any other CI. ### ### Usage: ### - Include this file in your shell script ### - Use juLog to call your command any time you want to produce a new report ### Usage: juLog command arguments ### options: ### -name="TestName" : the test name which will be shown in the junit report ### -error="RegExp" : a regexp which sets the test as failure when the output matches it ### -ierror="RegExp" : same as -error but case insensitive ### - Junit reports are left in the folder 'result' under the directory where the script is executed. ### - Configure Jenkins to parse junit files from the generated folder ### asserts=00; errors=0; total=0; content="" date=`which gdate || which date` # create output folder juDIR=`pwd`/results mkdir -p "$juDIR" || exit # The name of the suite is calculated based in your script name suite=`basename $0 | sed -e 's/.sh$//' | tr "." "_"` # A wrapper for the eval method witch allows catching seg-faults and use tee errfile=/tmp/evErr.$$.log eVal() { eval "$1" echo $? | tr -d "\n" >$errfile } # Method to clean old tests juLogClean() { echo "+++ Removing old junit reports from: $juDIR " rm -f "$juDIR"/TEST-* } # Execute a command and record its results juLog() { # parse arguments ya=""; icase="" while [ -z "$ya" ]; do case "$1" in -name=*) name=`echo "$1" | sed -e 's/-name=//'`; shift;; -ierror=*) ereg=`echo "$1" | sed -e 's/-ierror=//'`; icase="-i"; shift;; -error=*) ereg=`echo "$1" | sed -e 's/-error=//'`; shift;; *) ya=1;; esac done # use first arg as name if it was not given if [ -z "$name" ]; then name="$asserts-$1" shift fi # calculate command to eval [ -z "$1" ] && return cmd="$1"; shift while [ -n "$1" ] do cmd="$cmd \"$1\"" shift done # eval the command sending output to a file outf=/var/tmp/ju$$.txt >$outf echo "" | tee -a $outf echo "+++ Running case: $name " | tee -a $outf echo "+++ working dir: "`pwd` | tee -a $outf echo "+++ command: $cmd" | tee -a $outf ini=`$date +%s.%N` eVal "$cmd" 2>&1 | tee -a $outf evErr=`cat $errfile` rm -f $errfile end=`$date +%s.%N` echo "+++ exit code: $evErr" | tee -a $outf # set the appropriate error, based in the exit code and the regex [ $evErr != 0 ] && err=1 || err=0 out=`cat $outf | sed -e 's/^\([^+]\)/| \1/g'` if [ $err = 0 -a -n "$ereg" ]; then H=`echo "$out" | egrep $icase "$ereg"` [ -n "$H" ] && err=1 fi echo "+++ error: $err" | tee -a $outf rm -f $outf # calculate vars asserts=`expr $asserts + 1` asserts=`printf "%.2d" $asserts` errors=`expr $errors + $err` time=`echo "$end - $ini" | bc -l` total=`echo "$total + $time" | bc -l` # write the junit xml report ## failure tag [ $err = 0 ] && failure="" || failure=" " ## testcase tag content="$content $failure " ## testsuite block cat < "$juDIR/TEST-$suite.xml" $content EOF } openzwave-1.6.1914/cpp/build/testconfigsuppressions.cfg0000644000175200017520000000021014032142455020116 00000000000000#Suppression File for testconfig.pl %CFG = ( 'file.txt' => { 'code' => 500, 'bugid' => 000 } );openzwave-1.6.1914/cpp/build/ozw_config.in0000755000175200017520000000217414032142455015304 00000000000000#!/bin/sh # Little Utility Application to get the OpenZwave Build Configuration # # You can use it in Makefiles etc as: # gcc `ozw_config --Libs` `ozw_config --Cflags` test.c -o test echoerr() { echo "$@" 1>&2; } function getValue { IFS="=: " while read -r name value do if [ "--"$name = $1 ] then echo "${value//\"/}" | tr -d '\r\n' fi done <<< $inputfile } pcfile=@pkgconfigfile@ key=$1 if [ "$key" = "--with-pc" ] then pcfile=$2 key=$3 fi if [ ! -f $pcfile ] then echoerr "$pcfile does not exist" exit 128 fi inputfile=`cat $pcfile | grep -vE '^(\s*$|#)'` if [ ! -z $key ] || [ "$key" = "--help" ] then if [ "$key" = "--Libs" ] then value="-L$(getValue "--libdir") -lopenzwave" elif [ "$key" = "--Cflags" ] then value="-I$(getValue "--includedir")" else value=$(getValue $key) fi if [ ! -z "$value" ] then echo $value else exit 128 fi else echo "OpenZWave Build Configuration Utility" echo "" echo "Options Available:" echo "--with-pc - Use a Alternative pc file" echo "" echo "Get Build Variables:" IFS="=: " while read -r name value do echo "--${name//\"/}" done <<< $inputfile fi openzwave-1.6.1914/cpp/build/windows/0000777000175200017520000000000014032143200014344 500000000000000openzwave-1.6.1914/cpp/build/windows/winversion.tmpl0000644000175200017520000000015314032142455017373 00000000000000unsigned short ozw_vers_minor = 1; unsigned short ozw_vers_major = 5; unsigned short ozw_vers_revision = 0;openzwave-1.6.1914/cpp/build/windows/vs2010/0000777000175200017520000000000014032143200015277 500000000000000openzwave-1.6.1914/cpp/build/windows/vs2010/OpenZWave.sln0000644000175200017520000000242714032142455017627 00000000000000 Microsoft Visual Studio Solution File, Format Version 11.00 # Visual C++ Express 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenZWave", "OpenZWave.vcxproj", "{497F9828-DEC2-4C80-B9E0-AD066CCB587C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 DebugDLL|Win32 = DebugDLL|Win32 Release|Win32 = Release|Win32 ReleaseDLL|Win32 = ReleaseDLL|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Debug|Win32.ActiveCfg = Debug|Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Debug|Win32.Build.0 = Debug|Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Release|Win32.ActiveCfg = Release|Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Release|Win32.Build.0 = Release|Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal openzwave-1.6.1914/cpp/build/windows/vs2010/OpenZWave.vcxproj.filters0000644000175200017520000007341214032142455022177 00000000000000 {c333a1d6-215b-44ad-b8ee-406d5106109e} {44c66a53-03d9-4046-ac24-d3812170e342} {e177d532-917f-42e3-b495-f50646eb9490} {910fd85c-3052-49a4-a9be-3ba6ca7f87c3} {f3912321-42c6-42bf-8c89-cf61f2a985ed} {8a2f2f41-ba21-4299-b85d-cd7511e1de0e} {e7067898-f602-4a8b-af4b-8bcedcd0d0c0} {c511568c-3f02-4010-b603-90e65d6caad2} TinyXML TinyXML Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Main Main Main Main Main Main Main Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Platform Platform Platform Platform Platform\Windows Platform\Windows Platform\Windows Platform\Windows Main Main Main Command Classes Platform Platform\Windows HIDAPI Platform Main Main Platform Platform Platform\Windows Platform\Windows Platform Platform Platform Main Command Classes Command Classes Command Classes Command Classes Value Classes Command Classes AES AES AES AES AES Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Platform Platform\Windows Main Main Platform\Windows Platform\Windows Platform Main Command Classes Command Classes Command Classes Command Classes Main Main Main Main Main Main Platform Platform Platform Platform Platform Platform\Windows Platform\Windows Platform\Windows Platform\Windows Platform\Windows TinyXML TinyXML TinyXML TinyXML Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Value Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Value Classes Value Classes Main Main Main Command Classes Platform Platform\Windows HIDAPI Platform Main Platform Platform Platform\Windows Platform\Windows Platform Platform Main Command Classes Command Classes Value Classes Command Classes Command Classes Main AES AES AES AES Command Classes Command Classes Command Classes Command Classes Command Classes Command Classes Platform Platform\Windows Main Main Platform\Windows Main Command Classes Command Classes Main Command Classes Command Classes openzwave-1.6.1914/cpp/build/windows/vs2010/OpenZWave.vcxproj0000644000175200017520000007060414032142455020530 00000000000000 DebugDLL Win32 Debug Win32 ReleaseDLL Win32 Release Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C} OpenZWave Win32Proj StaticLibrary MultiByte true $(DefaultPlatformToolset) StaticLibrary MultiByte $(DefaultPlatformToolset) DynamicLibrary MultiByte $(DefaultPlatformToolset) DynamicLibrary MultiByte $(DefaultPlatformToolset) <_ProjectFileVersion>10.0.30319.1 $(Configuration)\ $(Configuration)\ $(Configuration)\ $(Configuration)\ AllRules.ruleset AllRules.ruleset AllRules.ruleset AllRules.ruleset $(ProjectName) $(ProjectName)d $(ProjectName) .dll .dll Disabled WIN32;_DEBUG;_LIB;USE_HID=1;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 ProgramDatabase ..\..\..\src;..\..\..\tinyxml;..\..\..\hidapi\hidapi;%(AdditionalIncludeDirectories) $(OutDir)\$(ProjectName).lib setupapi.lib MachineX86 del ..\winversion.cpp CALL "$(ProjectDir)\..\GIT-VS-VERSION-GEN.bat" "$(ProjectDir)\" "..\winversion.cpp" exit 0 Export GIT Revision Disabled WIN32;_DEBUG;_LIB;USE_HID=1;OPENZWAVE_MAKEDLL;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 ProgramDatabase 4251 ..\..\..\src;..\..\..\tinyxml;..\..\..\hidapi\hidapi;%(AdditionalIncludeDirectories) $(OutDir)\$(ProjectName).dll setupapi.lib;dnsapi.lib MachineX86 $(OutDir)$(TargetName)$(TargetExt) Setupapi.lib;Ws2_32.lib;dnsapi.lib;%(AdditionalDependencies) true del ..\winversion.cpp CALL "$(ProjectDir)\..\GIT-VS-VERSION-GEN.bat" "$(ProjectDir)\" "..\winversion.cpp" exit 0 Export GIT Revision MaxSpeed WIN32;_LIB;USE_HID=1;OPENZWAVE_MAKEDLL;%(PreprocessorDefinitions) true Default MultiThreadedDLL Level3 ProgramDatabase 4251 ..\..\..\src;..\..\..\tinyxml;..\..\..\hidapi\hidapi;%(AdditionalIncludeDirectories) $(OutDir)\$(ProjectName).lib setupapi.lib;dnsapi.lib MachineX86 Setupapi.lib;Ws2_32.lib;dnsapi.lib;%(AdditionalDependencies) Export GIT Revision del ..\winversion.cpp CALL "$(ProjectDir)\..\GIT-VS-VERSION-GEN.bat" "$(ProjectDir)\" "..\winversion.cpp" exit 0 MaxSpeed true WIN32;NDEBUG;_LIB;USE_HID=1;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase ..\..\..\src;..\..\..\tinyxml;..\..\..\hidapi\hidapi;%(AdditionalIncludeDirectories) $(OutDir)\$(ProjectName).lib setupapi.lib; del ..\winversion.cpp CALL "$(ProjectDir)\..\GIT-VS-VERSION-GEN.bat" "$(ProjectDir)\" "..\winversion.cpp" exit 0 Export GIT Revision openzwave-1.6.1914/cpp/build/windows/GIT-VS-VERSION-GEN.bat0000644000175200017520000001761214032142455017475 00000000000000@ECHO OFF SETLOCAL REM Script for generation of rc VERSIONINFO & StringFileInfo REM ==================== REM Installation Variables REM ==================== :: VERSION_FILE - Untracked file to be included in packaged source releases. :: it should contain a single line in the format: :: $Project_Name VERSION $tag (ie: Foobar VERSION v1.0.0-alpha0) SET VERSION_FILE=GIT-VS-VERSION-FILE :: DEFAULT_VERSION - Version string to be processed when neither Git nor a :: packed version file is available. SET DEFAULT_VERSION=v1.6.0-NoGit :: COUNT_PATCHES_FROM - Determines which tag to count the number of patches from :: for the final portion of the digital version number. :: Valid values are: :: major - count from earliest Major.0.0* tag. :: minor - count from earliest Major.Minor.0* tag. :: fix - count from earliest Major.Minor.Fix tag. SET COUNT_PATCHES_FROM=fix :: USES_PRERELEASE_TAGS - numeric bool value to determine if GET_GIT_PATCHES :: function should read the number of patches in the format of :: (Default) 1 - Major.Minor.Fix-Stage#-'CommitCount' :: 0 - Major.Minor.Fix-'CommitCount' SET USE_PRERELEASE_TAGS=1 :: -------------------- :CHECK_ARGS :: -------------------- :: Console output only. IF [%1] == [] GOTO START IF "%~1" == "--help" GOTO USAGE IF "%~1" == "--quiet" SET fQUIET=1& SHIFT IF "%~1" == "--force" SET fFORCE=1& SHIFT :: Un-documented switch IF "%~1" == "--test" GOTO TEST IF EXIST %~1\NUL ( :: %1 is a path SET CACHE_FILE=%~s1\%VERSION_FILE% SHIFT ) IF [%~nx1] NEQ [] ( :: %1 is a file SET HEADER_OUT_FILE=%~fs1 SHIFT ) :: This should always be the last argument. IF [%1] NEQ [] GOTO USAGE :: Some basic sanity checks. IF DEFINED fQUIET ( IF NOT DEFINED HEADER_OUT_FILE GOTO USAGE ) IF DEFINED CACHE_FILE ( SET CACHE_FILE=%CACHE_FILE:\\=\% IF NOT DEFINED HEADER_OUT_FILE GOTO USAGE ) GOTO START :: -------------------- :USAGE :: -------------------- ECHO usage: [--help] ^| ^| [--quiet] [--force] [CACHE PATH] [OUT FILE] ECHO. ECHO When called without arguments version information writes to console. ECHO. ECHO --help - displays this output. ECHO. ECHO --quiet - Suppress console output. ECHO --force - Ignore cached version information. ECHO CACHE PATH - Path for non-tracked file to store git-describe version. ECHO OUT FILE - Path to writable file that is included in the project's rc file. ECHO. ECHO Version information is expected to be in the format: vMajor.Minor.Fix[-stage#] ECHO Where -stage# is alpha, beta, or rc. ( example: v1.0.0-alpha0 ) ECHO. ECHO Example pre-build event: ECHO CALL $(SolutionDir)..\scripts\GIT-VS-VERSION-GEN.bat "$(IntDir)\" "$(SolutionDir)..\src\gen-versioninfo.h" ECHO. GOTO END REM =================== REM Entry Point REM =================== :START ECHO. CALL :INIT_VARS CALL :GET_VERSION_STRING IF DEFINED fGIT_AVAILABLE ( IF DEFINED fLEAVE_NOW GOTO END IF DEFINED CACHE_FILE ( CALL :CHECK_CACHE ) ) IF DEFINED fLEAVE_NOW GOTO END CALL :SET_BUILD_PARTS CALL :PREP_OUT CALL :WRITE_OUT GOTO END REM ==================== REM FUNCTIONS REM ==================== :: -------------------- :INIT_VARS :: -------------------- :: The following variables are used for the final version output. :: String Version: Major.Minor.Fix.Stage#[.Patches.SHA1[.dirty]] SET strFILE_VERSION= :: Digital Version: Major, Minor, Fix, Patches SET nbMAJOR_PART=0 SET nbMINOR_PART=0 SET nbFIX_PART=0 SET nbPATCHES_PART=0 :: VERSIONINFO VS_FF_ flags SET fPRIVATE=0 SET fPATCHED=0 SET fPRE_RELEASE=0 :: Supporting StringFileInfo - not used for clean release builds. SET strPRIVATE_BUILD= SET strCOMMENT= GOTO :EOF :: -------------------- :GET_VERSION_STRING :: -------------------- :: Precedence is Git, VERSION_FILE, then DEFAULT_VERSION. :: Check if git is available by testing git describe. CALL git describe>NUL 2>&1 IF NOT ERRORLEVEL 1 ( SET fGIT_AVAILABLE=1 :: Parse git version string CALL :PARSE_GIT_STRING ) ELSE ( :: Use the VERSION_FILE if it exists. IF EXIST "%VERSION_FILE%" ( FOR /F "tokens=3" %%A IN (%VERSION_FILE%) DO ( SET strFILE_VERSION=%%A ) ) ELSE ( :: Default to the DEFAULT_VERSION SET strFILE_VERSION=%DEFAULT_VERSION% ) ) SET strFILE_VERSION=%strFILE_VERSION:~1% SET strFILE_VERSION=%strFILE_VERSION:-=.% GOTO :EOF :: -------------------- :PARSE_GIT_STRING :: -------------------- FOR /F "tokens=*" %%A IN ('"git describe --long --tags --dirty "') DO ( SET strFILE_VERSION=%%A ) echo %strFILE_VERSION% :: If HEAD is dirty then this is not part of an official build and even if a :: commit hasn't been made it should still be marked as dirty and patched. SET tmp= GOTO :EOF :: -------------------- :CHECK_CACHE :: -------------------- :: Exit early if a cached git built version matches the current version. IF DEFINED HEADER_OUT_FILE ( IF EXIST "%HEADER_OUT_FILE%" ( IF [%fFORCE%] EQU [1] DEL "%CACHE_FILE%" IF EXIST "%CACHE_FILE%" ( FOR /F "tokens=*" %%A IN (%CACHE_FILE%) DO ( IF "%%A" == "%strFILE_VERSION%" ( IF NOT DEFINED fQUIET ( ECHO Build version is assumed unchanged from: %strFILE_VERSION%. ) SET fLEAVE_NOW=1 ) ) ) ) ECHO %strFILE_VERSION%> "%CACHE_FILE%" ) GOTO :EOF :: -------------------- :SET_BUILD_PARTS :: -------------------- :: The min version is X.Y.Z and the max is X.Y.Z.Stage#.Commits.SHA.dirty :: strTMP_STAGE_PART is a holder for anything past 'X.Y.Z.'. FOR /F "tokens=1,2,3,* delims=." %%A IN ("%strFile_Version%") DO ( SET nbMAJOR_PART=%%A SET nbMINOR_PART=%%B SET nbFIX_PART=%%C SET strTMP_STAGE_PART=%%D ) GOTO :EOF :: -------------------- :PREP_OUT :: -------------------- SET csvFILE_VERSION=%nbMAJOR_PART%,%nbMINOR_PART%,%nbFIX_PART%,%nbPATCHES_PART% SET hexFILE_VERSION= CALL :SET_HEX IF NOT %fPRIVATE% EQU 0 SET fPRIVATE=VS_FF_PRIVATEBUILD IF NOT %fPATCHED% EQU 0 SET fPATCHED=VS_FF_PATCHED IF NOT %fPRE_RELEASE% EQU 0 SET fPRE_RELEASE=VS_FF_PRERELEASE GOTO :EOF :: -------------------- :SET_HEX :: -------------------- :: Iterate Major, Minor, Fix, Patches as set in csvFILEVERSION and convert to :: hex while appending to the hexFILE_VERION string to give a padded 32bit :: end result. ie: v1.0.1.34 = 0x0001000000010022 SET hex_values=0123456789ABCDEF FOR /F "tokens=1-4 delims=," %%A IN ("%csvFILE_VERSION%") DO ( CALL :int2hex %%A CALL :int2hex %%B CALL :int2hex %%C CALL :int2hex %%D ) SET hexFILE_VERSION=0x%hexFILE_VERSION% SET hex_values= GOTO :EOF :int2hex SETLOCAL ENABLEDELAYEDEXPANSION SET /A pad=4 SET /A iVal=%1 :hex_loop SET /A pad=%pad% - 1 SET /A hVal=%iVal% %% 16 SET hVal=!hex_values:~%hVal%,1! SET hex_word=%hVal%%hex_word% SET /A iVal=%iVal% / 16 IF %iVal% GTR 0 GOTO hex_loop :hex_pad_loop FOR /L %%A in (1,1,%pad%) DO SET hex_word=0!hex_word! ENDLOCAL& SET hexFILE_VERSION=%hexFILE_VERSION%%hex_word% GOTO :EOF :: -------------------- :WRITE_OUT :: -------------------- :: HEADER_OUT falls through to CON_OUT which checks for the QUIET flag. IF DEFINED HEADER_OUT_FILE ( CALL :OUT_HEADER ) ELSE ( IF NOT DEFINED TESTING ( CALL :CON_OUT ) ELSE ( CALL :TEST_OUT ) ) GOTO :EOF :: -------------------- :OUT_HEADER :: -------------------- ECHO unsigned short ozw_vers_major = %nbMAJOR_PART%; >> "%HEADER_OUT_FILE%" ECHO unsigned short ozw_vers_minor = %nbMINOR_PART%; >> "%HEADER_OUT_FILE%" ECHO unsigned short ozw_vers_revision = %nbFIX_PART%; >> "%HEADER_OUT_FILE%" ECHO char ozw_version_string[] = "%strFILE_VERSION%\0"; >> "%HEADER_OUT_FILE%" SET nbMAJOR_PART=0 SET nbMINOR_PART=0 SET nbFIX_PART=0 SET nbPATCHES_PART=0 :: -------------------- :CON_OUT :: -------------------- IF DEFINED fQUIET GOTO :EOF ECHO Version String: %strFILE_VERSION% ECHO Digital Version ID: %csvFILE_VERSION% ECHO Hex Version ID: %hexFILE_VERSION% GOTO :EOF :: -------------------- :END :: -------------------- openzwave-1.6.1914/cpp/build/windows/installer/0000777000175200017520000000000014032143177016356 500000000000000openzwave-1.6.1914/cpp/build/windows/installer/buildall.bat0000644000175200017520000000143514032142455020553 00000000000000msbuild ..\..\..\examples\windows\MinOZW\vs2010\MinOZW.sln /t:Rebuild /p:Configuration="Debug" msbuild ..\..\..\examples\windows\MinOZW\vs2010\MinOZW.sln /t:Rebuild /p:Configuration="DebugDLL" msbuild ..\..\..\examples\windows\MinOZW\vs2010\MinOZW.sln /t:Rebuild /p:Configuration="Release" msbuild ..\..\..\examples\windows\MinOZW\vs2010\MinOZW.sln /t:Rebuild /p:Configuration="ReleaseDLL" copy ..\..\..\..\dotnet\examples\OZWForm\build\vs2010\*.sln ..\..\..\..\dotnet\examples\OZWForm\src\ copy ..\..\..\..\dotnet\examples\OZWForm\build\vs2010\*.csproj ..\..\..\..\dotnet\examples\OZWForm\src\ msbuild ..\..\..\..\dotnet\examples\OZWForm\src\OZWForm.sln /t:Rebuild /p:Configuration="Debug" msbuild ..\..\..\..\dotnet\examples\OZWForm\src\OZWForm.sln /t:Rebuild /p:Configuration="Release" openzwave-1.6.1914/cpp/build/windows/installer/openzwave.nsi0000644000175200017520000000472714032142455021033 00000000000000installDir "$PROGRAMFILES\OpenZWave" Name "OpenZWave" outFile "setup.exe" Page license Page components Page directory Page instfiles UninstPage uninstConfirm UninstPage instfiles LicenseData ..\..\..\..\license\lgpl.txt Section "Core Files" SectionIn RO setOutPath "$INSTDIR" File ..\..\..\..\license\lgpl.txt File ..\..\..\examples\windows\MinOZW\vs2010\ReleaseDLL\OpenZWave.dll setOutPath "$INSTDIR\docs\" File ..\..\..\..\docs\default.htm setOutPath "$INSTDIR\docs\images+css\" File ..\..\..\..\docs\images+css\* setOutPath "$INSTDIR\docs\general\" File ..\..\..\..\docs\general\* createShortCut "$SMPROGRAMS\OpenZWave\Getting Started.lnk" "$INSTDIR\docs\default.htm" SectionEnd Section /o "Development Files" setOutPath "$INSTDIR\development\DebugDLL" File ..\..\..\examples\windows\MinOZW\vs2010\DebugDLL\OpenZWaved.dll File ..\..\..\examples\windows\MinOZW\vs2010\DebugDLL\OpenZWaved.lib setOutPath "$INSTDIR\development\Debug" File ..\..\..\..\dotnet\examples\OZWForm\src\Debug\OpenZWave.lib setOutPath "$INSTDIR\development\ReleaseDLL" File ..\..\..\examples\windows\MinOZW\vs2010\ReleaseDLL\OpenZWave.dll File ..\..\..\examples\windows\MinOZW\vs2010\ReleaseDLL\OpenZWave.lib setOutPath "$INSTDIR\development\Release" File ..\..\..\..\dotnet\examples\OZWForm\src\Release\OpenZWave.lib setOutPath "$INSTDIR\development\include\openzwave\" File ..\..\..\src\*.h setOutPath "$INSTDIR\development\include\openzwave\command_classes\" file ..\..\..\src\command_classes\*.h setOutPath "$INSTDIR\development\include\openzwave\value_classes\" file ..\..\..\src\value_classes\*.h setOutPath "$INSTDIR\development\include\openzwave\platform\" file ..\..\..\src\platform\*.h setOutPath "$INSTDIR\development\include\openzwave\platform\windows\" file ..\..\..\src\platform\windows\*.h SectionEnd Section ".Net Component" SectionIn RO setOutPath "$INSTDIR\dotnet\" File ..\..\..\..\dotnet\examples\OZWForm\src\Debug\OpenZWaveDotNetd.dll File ..\..\..\..\dotnet\examples\OZWForm\src\Debug\OpenZWaveDotNetd.lib File ..\..\..\..\dotnet\examples\OZWForm\src\Release\OpenZWaveDotNet.dll File ..\..\..\..\dotnet\examples\OZWForm\src\Release\OpenZWaveDotNet.lib SectionEnd Section "Examples" setOutPath "$INSTDIR\dotnet\" File ..\..\..\examples\windows\MinOZW\vs2010\ReleaseDLL\MinOZW.exe File ..\..\..\..\dotnet\examples\OZWForm\src\bin\x86\Release\OZWForm.exe createShortCut "$SMPROGRAMS\OpenZWave\OpenZWave Form.lnk" "$INSTDIR\OZWForm.exe" SectionEnd openzwave-1.6.1914/cpp/build/windows/mingw32/0000777000175200017520000000000014032143177015647 500000000000000openzwave-1.6.1914/cpp/build/windows/mingw32/Makefile0000644000175200017520000000513514032142455017225 00000000000000# # Makefile for OpenZWave MingW32 build # Maarten Damen .SUFFIXES: .d .cpp .o .a .PHONY: default clean CC := $(CROSS_COMPILE)gcc CXX := $(CROSS_COMPILE)g++ LD := $(CROSS_COMPILE)g++ AR := $(CROSS_COMPILE)ar rc RANLIB := $(CROSS_COMPILE)ranlib DEBUG_CFLAGS := -DDEBUG -DLOG_STDERR RELEASE_CFLAGS := -O3 DEBUG_LDFLAGS := -g # Change for DEBUG or RELEASE CFLAGS := -c -Wall -Wno-unknown-pragmas -Wno-format -DMINGW $(DEBUG_CFLAGS) LDFLAGS := $(DEBUG_LDFLAGS) LIBDIR := ../../../lib/windows-mingw32 INCLUDES := -I ../../../src -I ../../../src/command_classes/ -I ../../../src/aes/ -I ../../../src/value_classes/ \ -I ../../../src/platform/ -I ../../../src/platform/windows -I ../../../tinyxml/ -I ../../../hidapi/hidapi/ SOURCES := ../../../src ../../../src/command_classes ../../../src/aes ../../../tinyxml ../../../hidapi/windows \ ../../../src/value_classes ../../../src/platform ../../../src/platform/windows VPATH = ../../../src:../../../src/command_classes:../../../src/aes:../../../tinyxml:../../../hidapi/windows:\ ../../../src/value_classes:../../../src/platform:../../../src/platform/windows %.d : %.cpp @set -e; rm -f $@; \ $(CXX) -MM $(INCLUDES) $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ tinyxml := $(notdir $(wildcard ../../../tinyxml/*.cpp)) hidapi := $(notdir $(wildcard ../../../hidapi/linux/hid.c)) # we do not want the libusb version cclasses := $(notdir $(wildcard ../../../src/command_classes/*.cpp)) vclasses := $(notdir $(wildcard ../../../src/value_classes/*.cpp)) aes := $(notdir $(wildcard ../../../src/aes/*.c)) pform := $(notdir $(wildcard ../../../src/platform/*.cpp)) \ $(notdir $(wildcard ../../../src/platform/windows/*.cpp)) indep := $(notdir $(wildcard ../../../src/*.cpp)) %.o : %.cpp $(CXX) $(CFLAGS) $(INCLUDES) -o $@ $< %.o : %.c $(CC) $(CFLAGS) $(INCLUDES) -o $@ $< default: $(LIBDIR)/openzwave.a clean: rm -f *.d *.o -include $(tinyxml:.cpp=.d) -include $(hidapi:.c=.d) -include $(cclasses:.cpp=.d) -include $(vclasses:.cpp=.d) -include $(aes:.c=.d) -include $(pform:.cpp=.d) -include $(indep:.cpp=.d) vers.c: echo 'char ozw_vers[] = "OpenZWave version 1.0.'`svnversion ../..`'";' > vers.c vers.o: vers.c $(LIBDIR)/openzwave.a: $(patsubst %.cpp,%.o,$(tinyxml)) \ $(patsubst %.c,%.o,$(hidapi)) \ $(patsubst %.cpp,%.o,$(cclasses)) \ $(patsubst %.cpp,%.o,$(vclasses)) \ $(patsubst %.c,%.o,$(aes)) \ $(patsubst %.cpp,%.o,$(pform)) \ $(patsubst %.cpp,%.o,$(indep)) vers.o \ | $(LIBDIR)/ $(AR) $@ $? $(LIBDIR)/: mkdir -p $@ openzwave-1.6.1914/cpp/build/windows/mingw-w64/0000777000175200017520000000000014032143177016120 500000000000000openzwave-1.6.1914/cpp/build/windows/mingw-w64/Makefile0000644000175200017520000001057014032142455017475 00000000000000# # Makefile for OpenZWave: MinGW-W64 build # Stefan Broekman .SUFFIXES: .d .cpp .o .a .PHONY: default clean VERSION_MAJ ?= 1 VERSION_MIN ?= 6 VERSION := $(VERSION_MAJ).$(VERSION_MIN) GITVERSION := $(VERSION_MAJ).$(VERSION_MIN).-1 VERSION_REV := 0 CC := $(CROSS_COMPILE)gcc CXX := $(CROSS_COMPILE)g++ LD := $(CROSS_COMPILE)g++ AR := $(CROSS_COMPILE)ar rc RANLIB := $(CROSS_COMPILE)ranlib DEBUG_CFLAGS := -Wall -Wno-unknown-pragmas -Wno-inline -Wno-format -Wno-attributes -Wno-error=sequence-point -Wno-sequence-point -ggdb -DDEBUG -fPIC RELEASE_CFLAGS := -Wall -Wno-unknown-pragmas -Wno-format -Wno-attributes -Wno-error=sequence-point -Wno-sequence-point -O3 -DNDEBUG -fPIC DEBUG_LDFLAGS := -g top_srcdir := ../../../.. STATIC_LIB_NAME=libopenzwave.a SHARED_LIB_NAME=libopenzwave.dll # Change for DEBUG or RELEASE CFLAGS := -c $(RELEASE_CFLAGS) LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB_NAME) $(RELEASE_LDFLAGS) LIBS += -lsetupapi LIBDIR := . OBJDIR := . INCLUDES := -I $(top_srcdir)/cpp/src -I $(top_srcdir)/cpp/tinyxml/ -I $(top_srcdir)/cpp/hidapi/hidapi/ SOURCES_HIDAPI =$(top_srcdir)/cpp/hidapi/windows SOURCES := $(top_srcdir)/cpp/src $(top_srcdir)/cpp/src/command_classes $(top_srcdir)/cpp/tinyxml \ $(top_srcdir)/cpp/src/value_classes $(top_srcdir)/cpp/src/platform $(top_srcdir)/cpp/src/platform/windows $(SOURCES_HIDAPI) $(top_srcdir)/cpp/src/aes/ VPATH = $(top_srcdir)/cpp/src:$(top_srcdir)/cpp/src/command_classes:$(top_srcdir)/cpp/tinyxml:\ $(top_srcdir)/cpp/src/value_classes:$(top_srcdir)/cpp/src/platform:$(top_srcdir)/cpp/src/platform/windows:$(SOURCES_HIDAPI):$(top_srcdir)/cpp/src/aes/ %.d : %.cpp $(CXX) -MM $(CFLAGS) $(INCLUDES) $< > $*.d tinyxml := $(notdir $(wildcard $(top_srcdir)/cpp/tinyxml/*.cpp)) hidapi := $(notdir $(wildcard $(top_srcdir)/cpp/hidapi/linux/*.c)) # we do not want the libusb version cclasses := $(notdir $(wildcard $(top_srcdir)/cpp/src/command_classes/*.cpp)) vclasses := $(notdir $(wildcard $(top_srcdir)/cpp/src/value_classes/*.cpp)) pform := $(notdir $(wildcard $(top_srcdir)/cpp/src/platform/*.cpp)) \ $(notdir $(wildcard $(top_srcdir)/cpp/src/platform/unix/*.cpp)) indep := $(notdir $(filter-out $(top_srcdir)/cpp/src/vers.cpp, $(wildcard $(top_srcdir)/cpp/src/*.cpp))) aes := $(notdir $(wildcard $(top_srcdir)/cpp/src/aes/*.c)) %.o : %.cpp $(CXX) $(CFLAGS) $(INCLUDES) -o $@ $< %.o : %.c $(CC) $(CFLAGS) $(INCLUDES) -o $@ $< default: $(LIBDIR)/$(STATIC_LIB_NAME) #Shared lib compiles and links but not working in projects yet. Disabled for now. #shared: $(LIBDIR)/$(SHARED_LIB_NAME) clean: rm -rf *.d* *.o $(STATIC_LIB_NAME) $(SHARED_LIB_NAME) $(top_srcdir)/cpp/src/vers.cpp -include $(patsubst %.cpp,%.d,$(tinyxml)) -include $(patsubst %.c,%.d,$(hidapi)) -include $(patsubst %.cpp,%.d,$(cclasses)) -include $(patsubst %.cpp,%.d,$(vclasses)) -include $(patsubst %.cpp,%.d,$(pform)) -include $(patsubst %.cpp,%.d,$(indep)) -include $(patsubst %.c,%.d,$(aes)) $(top_srcdir)/cpp/src/vers.cpp: @echo :: Creating vers.cpp @echo #include "Defs.h" > $(top_srcdir)/cpp/src/vers.cpp @echo uint16_t ozw_vers_major = $(VERSION_MAJ); >> $(top_srcdir)/cpp/src/vers.cpp @echo uint16_t ozw_vers_minor = $(VERSION_MIN); >> $(top_srcdir)/cpp/src/vers.cpp @echo uint16_t ozw_vers_revision = $(VERSION_REV); >> $(top_srcdir)/cpp/src/vers.cpp @echo char ozw_version_string[] = "$(GITVERSION)"; >> $(top_srcdir)/cpp/src/vers.cpp $(LIBDIR)/$(STATIC_LIB_NAME): $(patsubst %.cpp,%.o,$(tinyxml)) \ $(patsubst %.c,%.o,$(hidapi)) \ $(patsubst %.cpp,%.o,$(cclasses)) \ $(patsubst %.cpp,%.o,$(vclasses)) \ $(patsubst %.c,%.o,$(aes)) \ $(patsubst %.cpp,%.o,$(pform)) \ $(patsubst %.cpp,%.o,$(indep)) vers.o @echo :: Linking Static Library $(AR) $@ $+ $(RANLIB) $@ @echo :: Finished static library. Library written to: $(LIBDIR)/$(STATIC_LIB_NAME) $(LIBDIR)/$(SHARED_LIB_NAME): $(patsubst %.cpp,$(OBJDIR)/%.o,$(tinyxml)) \ $(patsubst %.c,$(OBJDIR)/%.o,$(hidapi)) \ $(patsubst %.c,$(OBJDIR)/%.o,$(aes)) \ $(patsubst %.cpp,$(OBJDIR)/%.o,$(cclasses)) \ $(patsubst %.cpp,$(OBJDIR)/%.o,$(vclasses)) \ $(patsubst %.cpp,$(OBJDIR)/%.o,$(pform)) \ $(patsubst %.cpp,$(OBJDIR)/%.o,$(indep)) \ $(OBJDIR)/vers.o @echo :: Linking Shared Library $(LD) $(LDFLAGS) -o $@ $+ $(LIBS) @echo :: Finished shared library. Written to: $(LIBDIR)/$(SHARED_LIB_NAME)openzwave-1.6.1914/cpp/build/testconfig.pl0000755000175200017520000004715014032142455015315 00000000000000#!/usr/bin/perl # use module use strict; use XML::Simple; use Data::Dumper; $Data::Dumper::Sortkeys = 1; use Getopt::Long qw(GetOptions); #use Digest::SHA1::File qw( file_md5_hex ); use Digest::file qw(digest_file_hex); my @metadatatypeneeded = ( 'FrequencyName', 'Identifier', 'ZWProductPage' ); my %errors = (); my %warnings = (); sub LogError { if (CheckSuppression($_[0], $_[1])) { return; } my $errordetail; $errordetail->{'file'} = $_[0]; $errordetail->{'code'} = $_[1]; $errordetail->{'description'} = $_[2]; #print Dumper($errordetail); push(@{$errors{$_[0]}}, $errordetail); } sub LogWarning { if (CheckSuppression($_[0], $_[1])) { return; } my $warningdetail; $warningdetail->{'file'} = $_[0]; $warningdetail->{'code'} = $_[1]; $warningdetail->{'description'} = $_[2]; push(@{$warnings{$_[0]}}, $warningdetail); } # check common config file mistakes sub CheckConfig { use strict; use warnings; my $file = $_[0]; my $count = 1; # create object my $xml = new XML::Simple; # read XML file my $data = $xml->XMLin($_[0], ForceArray => [ 'Group', 'MetaDataItem', 'Entry' ], KeyAttr => { CommandClass=>"id"}); # print output #print Dumper($data->{CommandClass}->{133}); foreach my $rev ($data) { #print $_[0]."-".Dumper($rev->{Revision}); my $fr = int $rev->{Revision}; my $md5 = digest_file_hex($_[0], "SHA-512"); if (defined($CFG::versiondb{$_[0]})) { if ($CFG::versiondb{$_[0]}{md5} ne $md5) { my $dbr = int $CFG::versiondb{$_[0]}->{Revision}; if ($dbr >= $fr ) { print $_[0]." - md5 does not match Database - Database Revision:"; print $dbr." File Revision:".$fr; print "\n"; LogError($_[0], 8, "Revision Number Was Not Bumped"); } else { my %versions; $versions{md5} = $md5; $versions{Revision} = $fr; $CFG::versiondb{$_[0]} = \%versions; print($_[0]." - Updating Database\n"); } } } else { my %versions; $versions{md5} = $md5; $versions{Revision} = $fr; $CFG::versiondb{$_[0]} = \%versions; print($_[0]." - Adding new file to Database\n"); } } #print Dumper($data->{CommandClass}->{133}->{Associations}->{Group}); foreach my $group ($data->{CommandClass}->{133}->{Associations}->{Group}) { if (defined($group)) { my $arrSize = @{$group}; if ($arrSize != $data->{CommandClass}->{133}->{Associations}->{num_groups}) { LogError($_[0], 4, "Number of Groups does not equal Group Entries"); } foreach my $entry (@{$group}) { if ((defined($entry->{auto})) && ($entry->{index} == 1) && (lc $entry->{auto} eq "true")) { LogError($_[0], 1,"Association Group 1 has auto equal to true"); } if ((defined($entry->{auto})) && ($entry->{index} != 1) && (lc $entry->{auto} eq "false")) { LogError($_[0], 2, "Association Group $entry->{index} has auto set to False"); } } } else { LogWarning($_[0], 3, "No Association Groups Defined for device"); } } foreach my $metadataitem ($data->{MetaData}) { if (defined($metadataitem)) { my $gotrev = 0; #Check if we have a ChangeLog Entry for this version foreach my $changelog (@{$metadataitem->{ChangeLog}->{Entry}}) { if ($data->{Revision} == $changelog->{'revision'}) { $gotrev = 1; } if (!length($changelog->{'content'})) { LogError($_[0], 9, "No Text in Entry for ChangeLog Revision $changelog->{revision}"); } } if ($gotrev == 0) { LogError($_[0], 9, "No Change Log Entry for this revision"); } #now make sure required attributes have type/id entries my %params = map { $_ => 1 } @metadatatypeneeded; my $gotpic = 0; foreach my $mdi (@{$metadataitem->{MetaDataItem}}) { if (exists $params{$mdi->{name}}) { if (!defined($mdi->{type})) { LogError($_[0], 10, "Type Identifier Required for $mdi->{name}"); } if (!defined($mdi->{id})) { LogError($_[0], 11, "ID Identifier Required for $mdi->{name}"); } } if ($mdi->{name} eq 'ProductPic') { $gotpic = 1; if (defined($mdi->{content})) { if (!-e "config/$mdi->{content}" ) { LogError($_[0], 12, "Image File Missing - config/$mdi->{content}"); } } else { LogError($_[0], 13, "Empty ProductPic Entry"); } } } if ($gotpic == 0) { LogError($_[0], 13, "No ProductPic Entry in MetaData"); } } } $data = $xml->XMLin($_[0], ForceArray => [ 'Value', 'MetaDataItem' ], KeyAttr => { CommandClass=>"id"}); # print output foreach my $valueItem ($data->{CommandClass}->{112}->{Value}) { if (defined($valueItem)) { foreach my $configuration (@{$valueItem}) { if ((defined($configuration->{type})) && (lc $configuration->{type} eq "list") && (not defined($configuration->{size}))) { LogError($_[0], 2, "Parameter: $configuration->{index} The size must be set for a list"); } if ((defined($configuration->{type})) && (lc $configuration->{type} eq "bitset") && (not defined($configuration->{size}))) { LogError($_[0], 2, "Parameter: $configuration->{index} The size must be set for a bitset"); } if ((defined($configuration->{type})) && (lc $configuration->{type} eq "bitset") && (not defined($configuration->{bitmask}))) { LogError($_[0], 2, "Parameter: $configuration->{index} The bitmask must be set for a bitset"); } if ((defined($configuration->{type})) && (lc $configuration->{type} eq "byte") && (defined($configuration->{size}) && ($configuration->{size} != 1 ))) { LogError($_[0], 2, "Parameter: $configuration->{index} The size is wrong for a byte"); } if ((defined($configuration->{type})) && (lc $configuration->{type} eq "short") && (defined($configuration->{size}) && ($configuration->{size} != 2 ))) { LogError($_[0], 2, "Parameter: $configuration->{index} The size is wrong for a short"); } if ((defined($configuration->{type})) && (lc $configuration->{type} eq "int") && (defined($configuration->{size}) && ($configuration->{size} != 3 && $configuration->{size} != 4 ))) { LogError($_[0], 2, "Parameter: $configuration->{index} The size is wrong for a int"); } } } } } # check files match entries in manufacture_specific.xml # check common config file mistakes sub CheckMetaDataID { use strict; use warnings; my $file = $_[0]; my $type = $_[1]; my $id = $_[2]; my $count = 1; # create object my $xml = new XML::Simple; # read XML file my $data = $xml->XMLin($_[0], ForceArray => [ 'Group', 'MetaDataItem', 'Entry' ], KeyAttr => { CommandClass=>"id"}); foreach my $metadataitem ($data->{MetaData}) { if (defined($metadataitem)) { #now make sure required attributes have the right type/id entries foreach my $param (@metadatatypeneeded) { my $gottype = 0; my $gotid = 0; foreach my $mdi (@{$metadataitem->{MetaDataItem}}) { if ($mdi->{name} eq $param) { if (!defined($mdi->{type})) { LogError($_[0], 10, "Type Identifier Required for $mdi->{name}"); } else { if ($mdi->{type} eq $type) { $gottype = 1; } } if (!defined($mdi->{id})) { LogError($_[0], 11, "ID Identifier Required for $mdi->{name}"); } else { if ($mdi->{id} eq $id) { $gotid = 1; } } } } if ($gottype == 0) { LogWarning($_[0], 12, "No Matching Type Entry in Metadata $param for manufacturer_specific entry $type:$id"); } if ($gotid == 0) { LogWarning($_[0], 12, "No Matching ID Entry in Metadata $param for manufacturer_specific entry $type:$id"); } } } } } sub CheckFileExists { my %configfiles = map { lc $_ => 1} @{$_[0]}; # create object my $xml = new XML::Simple; # read XML file my $data = $xml->XMLin("config/manufacturer_specific.xml", KeyAttr => "", ForceArray => [ 'Product' ] ); # do a check of MFS Revision etc my $md5 = digest_file_hex("config/manufacturer_specific.xml", "SHA-512"); my $fr = int $data->{Revision}; if (defined($CFG::versiondb{"config/manufacturer_specific.xml"})) { if ($CFG::versiondb{"config/manufacturer_specific.xml"}{md5} != $md5) { my $dbr = $CFG::versiondb{"config/manufacturer_specific.xml"}->{Revision}; if ($dbr ge $fr ) { print "config/manufacturer_specific.xml"." - md5 does not match Database - Database Revision:"; print $CFG::versiondb{"config/manufacturer_specific.xml"}->{Revision}." File Revision:".$fr; print "\n"; LogError("config/manufacturer_specific.xml", 8, "Revision Number Was Not Bumped"); } else { my %versions; $versions{md5} = $md5; $versions{Revision} = $fr; $CFG::versiondb{"config/manufacturer_specific.xml"} = \%versions; print("config/manufacturer_specific.xml"." - Updating Database\n"); } } } else { my %versions; $versions{md5} = $md5; $versions{Revision} = $fr; $CFG::versiondb{"config/manufacturer_specific.xml"} = \%versions; print("config/manufacturer_specific.xml"." - Adding new file to Database\n"); } foreach my $manu (@{$data->{Manufacturer}}) { if (defined($manu->{Product})) { foreach my $config (@{$manu->{Product}}) { if (defined($config->{config})) { #print Dumper($config->{config}); if (!-e "config/$config->{config}") { LogError("manufacturer_specific.xml", 5, "Config File config/$config->{config} Specified in manufacturer_specific.xml doesn't exist"); } else { delete $configfiles{lc "config/$config->{config}"}; } CheckMetaDataID("config/".$config->{config}, $config->{type}, $config->{id}); } } } } #anything left in $configfiles hasn't been specified in manufacturer_specific.xml #print Dumper(%configfiles); foreach my $unreffile (keys %configfiles) { LogWarning("manufacturer_specific.xml", 7, "Unreferenced Config File $unreffile present on file system"); } } sub CheckLocalization { my %configfiles = map { lc $_ => 1} @{$_[0]}; # create object my $xml = new XML::Simple; my $data = $xml->XMLin("config/Localization.xml", KeyAttr => "", ForceArray => [ 'Localization' ] ); # do a check of MFS Revision etc my $md5 = digest_file_hex("config/Localization.xml", "SHA-512"); my $fr = int $data->{Revision}; if (defined($CFG::versiondb{"config/Localization.xml"})) { if ($CFG::versiondb{"config/Localization.xml"}{md5} != $md5) { my $dbr = $CFG::versiondb{"config/Localization.xml"}->{Revision}; if ($dbr ge $fr ) { print "config/Localization.xml"." - md5 does not match Database - Database Revision:"; print $CFG::versiondb{"config/Localization.xml"}->{Revision}." File Revision:".$fr; print "\n"; LogError("config/Localization.xml", 8, "Revision Number Was Not Bumped"); } else { my %versions; $versions{md5} = $md5; $versions{Revision} = $fr; $CFG::versiondb{"config/Localization.xml"} = \%versions; print("config/Localization.xml"." - Updating Database\n"); } } } else { my %versions; $versions{md5} = $md5; $versions{Revision} = $fr; $CFG::versiondb{"config/Localization.xml"} = \%versions; print("config/Localization.xml"." - Adding new file to Database\n"); } } sub CheckNotificationCCTypes { my %configfiles = map { lc $_ => 1} @{$_[0]}; # create object my $xml = new XML::Simple; my $data = $xml->XMLin("config/NotificationCCTypes.xml", KeyAttr => "", ForceArray => [ 'NotificationTypes' ] ); # do a check of MFS Revision etc my $md5 = digest_file_hex("config/NotificationCCTypes.xml", "SHA-512"); my $fr = int $data->{Revision}; if (defined($CFG::versiondb{"config/NotificationCCTypes.xml"})) { if ($CFG::versiondb{"config/NotificationCCTypes.xml"}{md5} != $md5) { my $dbr = $CFG::versiondb{"config/NotificationCCTypes.xml"}->{Revision}; my $fr = $data->{Revision}; if ($dbr ge $fr ) { print "config/NotificationCCTypes.xml"." - md5 does not match Database - Database Revision:"; print $CFG::versiondb{"config/NotificationCCTypes.xml"}->{Revision}." File Revision:".$fr; print "\n"; LogError("config/NotificationCCTypes.xml", 8, "Revision Number Was Not Bumped"); } else { my %versions; $versions{md5} = $md5; $versions{Revision} = $fr; $CFG::versiondb{"config/NotificationCCTypes.xml"} = \%versions; print("config/NotificationCCTypes.xml"." - Updating Database\n"); } } } else { my %versions; $versions{md5} = $md5; $versions{Revision} = $fr; $CFG::versiondb{"config/NotificationCCTypes.xml"} = \%versions; print("config/NotificationCCTypes.xml"." - Adding new file to Database\n"); } } sub CheckSensorMultiLevelCCTypes { my %configfiles = map { lc $_ => 1} @{$_[0]}; # create object my $xml = new XML::Simple; my $data = $xml->XMLin("config/SensorMultiLevelCCTypes.xml", KeyAttr => "", ForceArray => [ 'SensorTypes' ] ); # do a check of MFS Revision etc my $md5 = digest_file_hex("config/SensorMultiLevelCCTypes.xml", "SHA-512"); my $fr = int $data->{Revision}; if (defined($CFG::versiondb{"config/SensorMultiLevelCCTypes.xml"})) { if ($CFG::versiondb{"config/SensorMultiLevelCCTypes.xml"}{md5} != $md5) { my $dbr = $CFG::versiondb{"config/SensorMultiLevelCCTypes.xml"}->{Revision}; my $fr = $data->{Revision}; if ($dbr ge $fr ) { print "config/SensorMultiLevelCCTypes.xml"." - md5 does not match Database - Database Revision:"; print $CFG::versiondb{"config/SensorMultiLevelCCTypes.xml"}->{Revision}." File Revision:".$fr; print "\n"; LogError("config/SensorMultiLevelCCTypes.xml", 8, "Revision Number Was Not Bumped"); } else { my %versions; $versions{md5} = $md5; $versions{Revision} = $fr; $CFG::versiondb{"config/SensorMultiLevelCCTypes.xml"} = \%versions; print("config/SensorMultiLevelCCTypes.xml"." - Updating Database\n"); } } } else { my %versions; $versions{md5} = $md5; $versions{Revision} = $fr; $CFG::versiondb{"config/SensorMultiLevelCCTypes.xml"} = \%versions; print("config/SensorMultiLevelCCTypes.xml"." - Adding new file to Database\n"); } } sub PrettyPrintErrors() { my $number_of_errors = keys %errors; if ($number_of_errors > 0) { print "\n\nErrors: ", $number_of_errors, ". (Please Correct before Submitting to OZW)\n"; while ((my $key, my $value) = each %errors) { foreach my $detail (@{$value}) { print $key.": ".$detail->{description}." - Error Code $detail->{code}\n"; } print "\n"; } } else { print "\n\nNo errors detected (You can submit your changes to OZW)\n"; } } sub PrettyPrintWarnings() { print "\n\nWarnings: (Can be Ignored)\n"; while ((my $key, my $value) = each %warnings) { foreach my $detail (@{$value}) { print $key.": ".$detail->{description}." - Warning Code $detail->{code}\n"; } print "\n"; } } sub XMLPrintErrors() { my $numerrs = 0; while ((my $key, my $value) = each %errors) { foreach my $detail (@{$value}) { $numerrs++; } } open(my $fh, '>', 'results/OZW_CheckConfig.xml') or die "Could not open file results\OZW_CheckConfig.xml $!"; print $fh "\n"; while ((my $key, my $value) = each %errors) { foreach my $detail (@{$value}) { print $fh "\t{code}-$detail->{file}\" time=\"\">\n"; print $fh "\t\t{description}\">\n"; print $fh "\t\t\n"; print $fh "\t\t{file}\nDescription: $detail->{description}\nError Code: $detail->{code}]]>\n"; print $fh "\t\t\n"; print $fh "\t\n"; } } print $fh "\n"; close $fh; } sub XMLPrintWarnings() { my $numerrs = 0; while ((my $key, my $value) = each %warnings) { foreach my $detail (@{$value}) { $numerrs++; } } open(my $fh, '>', 'results/OZW_CheckConfigWarnings.xml') or die "Could not open file results\OZW_CheckConfig.xml $!"; print $fh "\n"; while ((my $key, my $value) = each %warnings) { foreach my $detail (@{$value}) { print $fh "\t{code}-$detail->{file}\" time=\"\">\n"; print $fh "\t\t{description}\">\n"; print $fh "\t\t\n"; print $fh "\t\t{file}\nDescription: $detail->{description}\nError Code: $detail->{code}]]>\n"; print $fh "\t\t\n"; print $fh "\t\n"; } } print $fh "\n"; close $fh; } # Read a configuration file # The arg can be a relative or full path, or # it can be a file located somewhere in @INC. sub ReadCfg { my $file = "./cpp/build/testconfigsuppressions.cfg"; our $err; { # Put config data into a separate namespace package CFG; # Process the contents of the config file my $rc = do($file); # Check for errors if ($@) { $::err = "ERROR: Failure compiling '$file' - $@"; } elsif (! defined($rc)) { $::err = "ERROR: Failure reading '$file' - $!"; } elsif (! $rc) { $::err = "ERROR: Failure processing '$file'"; } } return ($err); } # Read a configuration file # The arg can be a relative or full path, or # it can be a file located somewhere in @INC. sub ReadVersions { my $file = "./cpp/build/testconfigversions.cfg"; our $err; { # Put config data into a separate namespace package CFG; my %versiondb; # Process the contents of the config file my $rc = do($file); # Check for errors if ($@) { $::err = "ERROR: Failure compiling '$file' - $@"; } elsif (! defined($rc)) { $::err = "ERROR: Failure reading '$file' - $!"; } elsif (! $rc) { $::err = "ERROR: Failure processing '$file'"; } } return ($err); } sub CheckSuppression { my $file = $_[0]; my $code = $_[1]; if (defined($CFG::CFG{$file}) && $CFG::CFG{$file}{'code'} == $code) { return 1 } return; } my $doxml; my $printwarnings; GetOptions( "printwarnings" => \$printwarnings, "outputxml" => \$doxml ) or die("Error in Command Line arguements\n"); if (my $err = ReadCfg()) { print(STDERR $err, "\n"); exit(1); } if (my $err = ReadVersions()) { print(STDERR $err, "\n"); } print "Checking Config Files... Please Wait\n"; my $dirname="config"; opendir(DIR, $dirname); my @dirs = readdir(DIR); closedir DIR; my @filelist; foreach my $key (@dirs) { next if ($key eq "."); next if ($key eq ".."); if(-d "$dirname/$key") { my @files = glob("$dirname/$key/*.xml"); foreach my $file (@files) { next if ($file eq "."); next if ($file eq ".."); push(@filelist, $file); #print "Checking $file\n"; CheckConfig("$file"); } } } CheckFileExists(\@filelist); CheckLocalization(); CheckNotificationCCTypes(); CheckSensorMultiLevelCCTypes(); if ($doxml == 0) { PrettyPrintErrors(); } if ($doxml == 0 && $printwarnings == 1) { PrettyPrintWarnings(); } if ($doxml == 1) { XMLPrintErrors(); } if ($doxml == 1 && $printwarnings == 1) { XMLPrintWarnings(); } my $errorsize = keys %errors; if ($errorsize == 0) { print "\nSaving Revision Database\n"; open my $FH, '>', 'cpp/build/testconfigversions.cfg'; print $FH Data::Dumper->Dump([\%CFG::versiondb], ['*versiondb']); close $FH; } else { exit 1; } openzwave-1.6.1914/cpp/build/Makefile0000644000175200017520000002542314032142455014247 00000000000000# # Makefile for OpenZWave Linux build # Greg Satz # GNU make only # Linux requires libudev-dev # FreeBSD requires port misc/e2fsprogs-libuuid #these variables can be modified by the user if needed # what flags we will use for compiling in debug mode DEBUG_CFLAGS := -Wformat -Wall -Wno-unknown-pragmas -Wno-inline -Werror -Wno-error=sequence-point -Wno-sequence-point -ggdb -DDEBUG -fPIC -DSYSCONFDIR="\"$(PREFIX)/etc/openzwave/\"" DEBUG_CPPFLAGS := -std=c++11 # what flags we will use for compiling in release mode RELEASE_CFLAGS := -Wall -Wno-unknown-pragmas -Werror -Wno-error=sequence-point -Wno-sequence-point -O3 -DNDEBUG -fPIC -DSYSCONFDIR="\"$(PREFIX)/etc/openzwave/\"" RELEASE_CPPFLAGS := -std=c++11 #what flags we will use for linking in debug mode DEBUG_LDFLAGS := -g #default Libraries we should link with ifneq ($(UNAME),FreeBSD) LIBS += -lresolv endif top_srcdir := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))../../) include $(top_srcdir)/cpp/build/support.mk #Mac prefers a dylib, not a so ifeq ($(UNAME),Darwin) SHARED_LIB_NAME=libopenzwave-$(VERSION).dylib SHARED_LIB_UNVERSIONED=libopenzwave.dylib else SHARED_LIB_NAME=libopenzwave.so.$(VERSION) SHARED_LIB_UNVERSIONED=libopenzwave.so endif #if we are on a Mac, add these flags and libs to the compile and link phases ifeq ($(UNAME),Darwin) CFLAGS += -c -DDARWIN ifeq ($(DARWIN_MOJAVE_UP),1) # Newer macOS releases don't support i386 so only build 64-bit DARWIN_BUILD_TARGET = -arch x86_64 else DARWIN_BUILD_TARGET = -arch i386 -arch x86_64 endif TARCH += $(DARWIN_BUILD_TARGET) LDFLAGS += -dynamiclib -install_name "$(DESTDIR)/$(instlibdir)/$(SHARED_LIB_NAME)" LIBS += -framework IOKit -framework CoreFoundation $(DARWIN_BUILD_TARGET) else ifeq ($(UNAME),FreeBSD) LDFLAGS+= -shared -lusb -Wl,-soname,$(SHARED_LIB_NAME) # Pre FreeBSD 10.2 we have no native, or "old" native iconv.h (non-posix compliant # const modifiers) # For these, require libiconv pkg to be installed. ifeq ($(shell test $$(uname -U) -ge 1002000; echo $$?),1) # <10.2 ifeq (,$(wildcard /usr/local/include/iconv.h)) $(error FreeBSD pre 10.2: Please install libiconv from ports) else # Installed, use it CFLAGS += -I/usr/local/include # User application *must* use -liconv; we don't do any linking from this file since we only # build a library. endif endif # For 10.2 and later, use iconv from base, no extra include path required. else ifeq ($(UNAME),NetBSD) CFLAGS += $(shell pkgconf --cflags libusb-1.0) LDFLAGS+= -shared $(shell pkgconf --libs libusb-1.0) else ifeq ($(UNAME),SunOS) CFLAGS+= -I$(PREFIX)/include/libusb-1.0 LDFLAGS+= -shared -lusb-1.0 -liconv else LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB_NAME) endif #CFLAGS += $(CPPFLAGS) #where to put the temporary library LIBDIR ?= $(top_builddir) INCLUDES := -I $(top_srcdir)/cpp/src ifeq ($(USE_BI_TXML), 1) INCLUDES += -I $(top_srcdir)/cpp/tinyxml/ SOURCES_TXML =$(top_srcdir)/cpp/tinyxml/ tinyxml := $(notdir $(wildcard $(top_srcdir)/cpp/tinyxml/*.cpp)) else LIBS+= -ltinyxml endif ifeq ($(USE_HID),1) INCLUDES += -I $(top_srcdir)/cpp/hidapi/hidapi/ CFLAGS += -DUSE_HID ifeq ($(UNAME),Darwin) SOURCES_HIDAPI =$(top_srcdir)/cpp/hidapi/mac else ifeq ($(UNAME),FreeBSD) SOURCES_HIDAPI =$(top_srcdir)/cpp/hidapi/libusb else ifeq ($(UNAME),NetBSD) SOURCES_HIDAPI =$(top_srcdir)/cpp/hidapi/libusb else ifeq ($(UNAME),SunOS) SOURCES_HIDAPI =$(top_srcdir)/cpp/hidapi/libusb else SOURCES_HIDAPI =$(top_srcdir)/cpp/hidapi/linux LIBS += -ludev endif endif # USE_HID SOURCES := $(top_srcdir)/cpp/src $(top_srcdir)/cpp/src/command_classes $(SOURCES_TXML) \ $(top_srcdir)/cpp/src/value_classes $(top_srcdir)/cpp/src/platform $(top_srcdir)/cpp/src/platform/unix $(SOURCES_HIDAPI) $(top_srcdir)/cpp/src/aes/ VPATH = $(top_srcdir)/cpp/src:$(top_srcdir)/cpp/src/command_classes:$(SOURCES_TXML):\ $(top_srcdir)/cpp/src/value_classes:$(top_srcdir)/cpp/src/platform:$(top_srcdir)/cpp/src/platform/unix:$(SOURCES_HIDAPI):$(top_srcdir)/cpp/src/aes/ ifeq ($(USE_HID),1) ifeq ($(UNAME),Darwin) hidapi := $(notdir $(wildcard $(top_srcdir)/cpp/hidapi/mac/*.c)) else ifeq ($(UNAME),FreeBSD) hidapi := $(notdir $(wildcard $(top_srcdir)/cpp/hidapi/libusb/*.c)) else ifeq ($(UNAME),NetBSD) hidapi := $(notdir $(wildcard $(top_srcdir)/cpp/hidapi/libusb/*.c)) else ifeq ($(UNAME),SunOS) hidapi := $(notdir $(wildcard $(top_srcdir)/cpp/hidapi/libusb/*.c)) else hidapi := $(notdir $(wildcard $(top_srcdir)/cpp/hidapi/linux/*.c)) # we do not want the libusb version endif endif # USE_HID ifeq ($(BITBAKE_ENV),1) ar_option := "rc" endif cclasses := $(notdir $(wildcard $(top_srcdir)/cpp/src/command_classes/*.cpp)) vclasses := $(notdir $(wildcard $(top_srcdir)/cpp/src/value_classes/*.cpp)) pform := $(notdir $(wildcard $(top_srcdir)/cpp/src/platform/*.cpp)) \ $(notdir $(wildcard $(top_srcdir)/cpp/src/platform/unix/*.cpp)) indep := $(notdir $(filter-out $(top_srcdir)/cpp/src/vers.cpp, $(wildcard $(top_srcdir)/cpp/src/*.cpp))) aes := $(notdir $(wildcard $(top_srcdir)/cpp/src/aes/*.c)) default: printversion $(LIBDIR)/libopenzwave.a $(LIBDIR)/$(SHARED_LIB_NAME) $(top_builddir)/ozw_config clean: @rm -rf $(DEPDIR) $(OBJDIR) $(LIBDIR)/libopenzwave.so* $(LIBDIR)/libopenzwave*.dylib $(LIBDIR)/libopenzwave.a $(top_builddir)/libopenzwave.pc $(top_builddir)/docs/api $(top_builddir)/Doxyfile $(top_srcdir)/cpp/src/vers.cpp printversion: @echo "Building OpenZWave Version $(GITVERSION) - $(VERSION).$(VERSION_REV)" -include $(patsubst %.cpp,$(DEPDIR)/%.d,$(tinyxml)) -include $(patsubst %.c,$(DEPDIR)/%.d,$(hidapi)) -include $(patsubst %.cpp,$(DEPDIR)/%.d,$(cclasses)) -include $(patsubst %.cpp,$(DEPDIR)/%.d,$(vclasses)) -include $(patsubst %.cpp,$(DEPDIR)/%.d,$(pform)) -include $(patsubst %.cpp,$(DEPDIR)/%.d,$(indep)) -include $(patsubst %.c,$(DEPDIR)/%.d,$(aes)) #create a vers.cpp file that contains our version and subversion revisions $(top_srcdir)/cpp/src/vers.cpp: @echo "Creating vers.cpp" @echo '#include "Defs.h"' > $(top_srcdir)/cpp/src/vers.cpp @echo 'uint16_t ozw_vers_major = $(VERSION_MAJ);' >> $(top_srcdir)/cpp/src/vers.cpp @echo 'uint16_t ozw_vers_minor = $(VERSION_MIN);' >> $(top_srcdir)/cpp/src/vers.cpp @echo 'uint16_t ozw_vers_revision = $(VERSION_REV);' >> $(top_srcdir)/cpp/src/vers.cpp @echo 'char ozw_version_string[] = "$(GITVERSION)";' >> $(top_srcdir)/cpp/src/vers.cpp @$(SED) \ -e 's|[@]VERSION@|$(VERSION).$(VERSION_REV)|g' \ < "$(top_srcdir)/dist/openzwave.spec.in" > "$(top_srcdir)/dist/openzwave.spec" #create a vers.cpp file that contains our version and subversion revisions updateIndexDefines: $(top_srcdir)/cpp/src/ValueIDIndexesDefines.def @$(CXX) -E -P -o $(top_srcdir)/cpp/src/ValueIDIndexesDefines.h -x c++ $< #$(OBJDIR)/vers.o: $(top_builddir)/vers.cpp $(LIBDIR)/libopenzwave.a: $(patsubst %.cpp,$(OBJDIR)/%.o,$(tinyxml)) \ $(patsubst %.c,$(OBJDIR)/%.o,$(hidapi)) \ $(patsubst %.c,$(OBJDIR)/%.o,$(aes)) \ $(patsubst %.cpp,$(OBJDIR)/%.o,$(cclasses)) \ $(patsubst %.cpp,$(OBJDIR)/%.o,$(vclasses)) \ $(patsubst %.cpp,$(OBJDIR)/%.o,$(pform)) \ $(patsubst %.cpp,$(OBJDIR)/%.o,$(indep)) \ $(OBJDIR)/vers.o @echo "Linking Static Library" @$(AR) $(ar_option) $@ $+ @$(RANLIB) $@ $(LIBDIR)/$(SHARED_LIB_NAME): $(patsubst %.cpp,$(OBJDIR)/%.o,$(tinyxml)) \ $(patsubst %.c,$(OBJDIR)/%.o,$(hidapi)) \ $(patsubst %.c,$(OBJDIR)/%.o,$(aes)) \ $(patsubst %.cpp,$(OBJDIR)/%.o,$(cclasses)) \ $(patsubst %.cpp,$(OBJDIR)/%.o,$(vclasses)) \ $(patsubst %.cpp,$(OBJDIR)/%.o,$(pform)) \ $(patsubst %.cpp,$(OBJDIR)/%.o,$(indep)) \ $(OBJDIR)/vers.o @echo "Linking Shared Library" @$(LD) $(LDFLAGS) $(TARCH) -o $@ $+ $(LIBS) @ln -sf $(SHARED_LIB_NAME) $(LIBDIR)/$(SHARED_LIB_UNVERSIONED) $(top_builddir)/libopenzwave.pc: $(top_srcdir)/cpp/build/libopenzwave.pc.in $(PKGCONFIG) @echo "Making libopenzwave pkg-config file" @$(SED) \ -e 's|[@]prefix@|$(PREFIX)|g' \ -e 's|[@]exec_prefix@|$(PREFIX)/bin|g' \ -e 's|[@]libdir@|$(instlibdir)|g' \ -e 's|[@]includedir@|$(includedir)/|g' \ -e 's|[@]sysconfdir@|$(sysconfdir)/|g' \ -e 's|[@]gitversion@|$(GITVERSION)|g' \ -e 's|[@]docdir@|$(docdir)/|g' \ -e 's|[@]VERSION@|$(VERSION)|g' \ -e 's|[@]LIBS@|$(LIBS)|g' \ < "$<" > "$@" $(top_builddir)/ozw_config: $(top_srcdir)/cpp/build/ozw_config.in @echo "Making ozw_config file" @$(SED) \ -e 's|[@]pkgconfigfile@|$(pkgconfigdir)/libopenzwave.pc|g' \ < "$<" > "$@" @chmod +x $(top_builddir)/ozw_config ifeq ($(DOT),) HAVE_DOT = -e 's|[@]HAVE_DOT@|NO|g' else HAVE_DOT = -e 's|[@]HAVE_DOT@|YES|g' endif $(top_builddir)/Doxyfile: $(top_srcdir)/docs/Doxyfile.in $(top_srcdir)/cpp/src/vers.cpp @mkdir -p $(top_builddir)/docs/api/ @$(SED) \ -e 's|[@]OUTPUT_DIR@|$(top_builddir)/docs/api/|g' \ -e 's|[@]TOPSRC_DIR@|$(top_srcdir)|g' \ $(HAVE_DOT) \ -e 's|[@]VERSION@|$(VERSION).$(VERSION_REV)|g' \ < "$<" > "$@" ifeq ($(DOXYGEN),) doc: $(warning Documentation not being built) else doc: $(top_builddir)/Doxyfile @echo "Creating Documentation at $(top_builddir)/docs/api/" @mkdir -p $(top_builddir)/docs/api/ @cd $(top_builddir); $(DOXYGEN) endif install: $(LIBDIR)/$(SHARED_LIB_NAME) doc $(top_builddir)/libopenzwave.pc $(top_builddir)/ozw_config @echo "Installing Shared Library" @install -d $(DESTDIR)/$(instlibdir)/ @cp $(LIBDIR)/$(SHARED_LIB_NAME) $(DESTDIR)/$(instlibdir)/$(SHARED_LIB_NAME) @ln -sf $(SHARED_LIB_NAME) $(DESTDIR)/$(instlibdir)/$(SHARED_LIB_UNVERSIONED) @echo "Installing Headers" @install -d $(DESTDIR)/$(includedir) @install -m 0644 $(top_srcdir)/cpp/src/*.h $(DESTDIR)/$(includedir) @install -d $(DESTDIR)/$(includedir)/command_classes/ @install -m 0644 $(top_srcdir)/cpp/src/command_classes/*.h $(DESTDIR)/$(includedir)/command_classes/ @install -d $(DESTDIR)/$(includedir)/value_classes/ @install -m 0644 $(top_srcdir)/cpp/src/value_classes/*.h $(DESTDIR)/$(includedir)/value_classes/ @install -d $(DESTDIR)/$(includedir)/platform/ @install -m 0644 $(top_srcdir)/cpp/src/platform/*.h $(DESTDIR)/$(includedir)/platform/ @install -d $(DESTDIR)/$(includedir)/platform/unix/ @install -m 0644 $(top_srcdir)/cpp/src/platform/unix/*.h $(DESTDIR)/$(includedir)/platform/unix/ @install -d $(DESTDIR)/$(includedir)/aes/ @install -m 0644 $(top_srcdir)/cpp/src/aes/*.h $(DESTDIR)/$(includedir)/aes/ @install -d $(DESTDIR)/$(sysconfdir)/ @echo "Installing Config Database" @cp -r $(top_srcdir)/config/* $(DESTDIR)/$(sysconfdir) @echo "Installing Documentation" @install -d $(DESTDIR)/$(docdir)/ @cp -r $(top_srcdir)/docs/* $(DESTDIR)/$(docdir) @if [ -d "$(top_builddir)/docs/html/" ]; then cp -r $(top_builddir)/docs/html/* $(DESTDIR)/$(docdir); fi @echo "Installing Pkg-config Files" @install -d $(DESTDIR)/$(pkgconfigdir) @cp $(top_builddir)/libopenzwave.pc $(DESTDIR)/$(pkgconfigdir) @install -d $(DESTDIR)/$(PREFIX)/bin/ @cp $(top_builddir)/ozw_config $(DESTDIR)/$(PREFIX)/bin/ozw_config @chmod 755 $(DESTDIR)/$(PREFIX)/bin/ozw_config .SUFFIXES: .d .cpp .o .a .PHONY: default clean install doc openzwave-1.6.1914/cpp/build/LeakSanitizer-Suppressions.txt0000644000175200017520000000005714032142455020624 00000000000000leak:OpenZWave::Internal::Platform::DNS::DNS() openzwave-1.6.1914/cpp/src/0000777000175200017520000000000014032143202012344 500000000000000openzwave-1.6.1914/cpp/src/Driver.h0000644000175200017520000013022714032142455013702 00000000000000//----------------------------------------------------------------------------- // // Driver.h // // Communicates with a Z-Wave network // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Driver_H #define _Driver_H #include #include #include #include "Defs.h" #include "Group.h" #include "value_classes/ValueID.h" #include "Node.h" #include "platform/Event.h" #include "platform/Mutex.h" #include "platform/Thread.h" #include "platform/TimeStamp.h" #include "aes/aescpp.h" namespace OpenZWave { class Notification; namespace Internal { namespace CC { class ApplicationStatus; class Basic; class CommandClass; class WakeUp; class ControllerReplication; class ManufacturerSpecific; class MultiChannelAssociation; class NodeNaming; class Security; class SceneActivation; } namespace VC { class Value; class ValueStore; } namespace Platform { class Controller; } class DNSThread; struct DNSLookup; class i_HttpClient; struct HttpDownload; class ManufacturerSpecificDB; class Msg; class TimerThread; } /** \brief The Driver class handles communication between OpenZWave * and a device attached via a serial port (typically a controller). */ class OPENZWAVE_EXPORT Driver { friend class Manager; friend class Node; friend class Group; friend class Internal::CC::CommandClass; friend class Internal::CC::ControllerReplication; friend class Internal::DNSThread; friend class Internal::i_HttpClient; friend class Internal::VC::Value; friend class Internal::VC::ValueStore; friend class Internal::CC::Basic; friend class Internal::CC::ManufacturerSpecific; friend class Internal::CC::MultiChannelAssociation; friend class Internal::CC::NodeNaming; friend class Internal::CC::SceneActivation; friend class Internal::CC::WakeUp; friend class Internal::CC::ApplicationStatus; /* for Notification messages */ friend class Internal::CC::Security; friend class Internal::Msg; friend class Internal::ManufacturerSpecificDB; friend class TimerThread; //----------------------------------------------------------------------------- // Controller Interfaces //----------------------------------------------------------------------------- public: enum ControllerInterface { ControllerInterface_Unknown = 0, ControllerInterface_Serial, ControllerInterface_Hid }; //----------------------------------------------------------------------------- // Construction / Destruction //----------------------------------------------------------------------------- private: /** * Creates threads, events and initializes member variables and the node array. */ Driver(string const& _controllerPath, ControllerInterface const& _interface); /** Sets "exit" flags and stops the three background threads (pollThread, serialThread * and driverThread). Then clears out the send queue and node array. Notifies * watchers and exits. */ virtual ~Driver(); /** * Start the driverThread */ void Start(); /** * Entry point for driverThread */ static void DriverThreadEntryPoint(Internal::Platform::Event* _exitEvent, void* _context); /** * ThreadProc for driverThread. This is where all the "action" takes place. *

* First, the thread is initialized by calling Init(). If Init() fails, it will be retried * every 5 seconds for the first two minutes and every 30 seconds thereafter. *

* After the thread is successfully initialized, the thread enters a loop with the * following elements: * - Confirm that m_exit is still false (or exit from the thread if it is true) * - Call ReadMsg() to consume any available messages from the controller * - Call NotifyWatchers() to send any pending notifications * - If the thread is not waiting for an ACK, a callback or a message reply, send [any][the next] queued message[s] * - If there was no message read or sent (workDone=false), sleep for 5 seconds. If nothing happened * within this time frame and something was expected (ACK, callback or reply), retrieve the * last message from the send queue and examine GetSendAttempts(). If greater than 2, give up * and remove the message from the queue. Otherwise, resend the message. * - If something did happen [reset m_wakeEvent] */ void DriverThreadProc(Internal::Platform::Event* _exitEvent); /** * Initialize the controller. Open the specified serial port, start the serialThread * and pollThread, then send a NAK to the device [presumably to flush it]. *

* Then queue the commands to retrieve the Z-Wave interface: * - Get version * - Get home and node IDs * - Get controller capabilities * - Get serial API capabilities * - [Get SUC node ID] * - Get init data [identifying the nodes on the network] * Init() will return false if the serial port could not be opened. */ bool Init(uint32 _attempts); /** * Remove any messages to a node on the queues * Used when deleting a node. */ void RemoveQueues(uint8 const _nodeId); Internal::Platform::Thread* m_driverThread; /**< Thread for reading from the Z-Wave controller, and for creating and managing the other threads for sending, polling etc. */ Internal::DNSThread* m_dns; /**< DNSThread Class */ Internal::Platform::Thread* m_dnsThread; /**< Thread for DNS Queries */ Internal::Platform::Mutex* m_initMutex; /**< Mutex to ensure proper ordering of initialization/deinitialization */ bool m_exit; /**< Flag that is set when the application is exiting. */ bool m_init; /**< Set to true once the driver has been initialised */ bool m_awakeNodesQueried; /**< Set to true once the driver has polled all awake nodes */ bool m_allNodesQueried; /**< Set to true once the driver has polled all nodes */ bool m_notifytransactions; Internal::Platform::TimeStamp m_startTime; /**< Time this driver started (for log report purposes) */ //----------------------------------------------------------------------------- // Configuration //----------------------------------------------------------------------------- private: void RequestConfig(); // Get the network configuration from the Z-Wave network bool ReadCache(); // Read the configuration from a file void WriteCache(); // Save the configuration to a file //----------------------------------------------------------------------------- // Timer //----------------------------------------------------------------------------- private: Internal::TimerThread* m_timer; /**< TimerThread Class */ Internal::Platform::Thread* m_timerThread; /**< Thread for timer events */ public: Internal::TimerThread* GetTimer() { return m_timer; } //----------------------------------------------------------------------------- // Controller //----------------------------------------------------------------------------- private: // Controller Capabilities (return in FUNC_ID_ZW_GET_CONTROLLER_CAPABILITIES) enum { ControllerCaps_Secondary = 0x01, /**< The controller is a secondary. */ ControllerCaps_OnOtherNetwork = 0x02, /**< The controller is not using its default HomeID. */ ControllerCaps_SIS = 0x04, /**< There is a SUC ID Server on the network. */ ControllerCaps_RealPrimary = 0x08, /**< Controller was the primary before the SIS was added. */ ControllerCaps_SUC = 0x10 /**< Controller is a static update controller. */ }; // Init Capabilities (return in FUNC_ID_SERIAL_API_GET_INIT_DATA) enum { InitCaps_Slave = 0x01, /**< */ InitCaps_TimerSupport = 0x02, /**< Controller supports timers. */ InitCaps_Secondary = 0x04, /**< Controller is a secondary. */ InitCaps_SUC = 0x08 /**< Controller is a static update controller. */ }; bool IsPrimaryController() const { return ((m_initCaps & InitCaps_Secondary) == 0); } bool IsStaticUpdateController() const { return ((m_initCaps & InitCaps_SUC) != 0); } bool IsBridgeController() const { return (m_libraryType == 7); } bool IsInclusionController() const { return ((m_controllerCaps & ControllerCaps_SIS) != 0); } bool HasExtendedTxStatus() const { return m_hasExtendedTxStatus; } uint32 GetHomeId() const { return m_homeId; } uint8 GetControllerNodeId() const { return m_Controller_nodeId; } uint8 GetSUCNodeId() const { return m_SUCNodeId; } uint16 GetManufacturerId() const { return m_manufacturerId; } uint16 GetProductType() const { return m_productType; } uint16 GetProductId() const { return m_productId; } string GetControllerPath() const { return m_controllerPath; } ControllerInterface GetControllerInterfaceType() const { return m_controllerInterfaceType; } string GetLibraryVersion() const { return m_libraryVersion; } string GetLibraryTypeName() const { return m_libraryTypeName; } int32 GetSendQueueCount() const { int32 count = 0; for (int32 i = 0; i < MsgQueue_Count; ++i) { count += (int32) (m_msgQueue[i].size()); } return count; } /** * A version of GetNode that does not have the protective "lock" and "release" requirement. * This function can be used within driverThread, which "knows" that the node will not be * changed or deleted while it is being used. * \param _nodeId The nodeId (index into the node array) identifying the node to be returned * \return * A pointer to the specified node (if it exists) or NULL if not. * \see GetNode */ Node* GetNodeUnsafe(uint8 _nodeId); /** * Locks the node array and returns the specified node (if it exists). If a node is returned, * the lock must be released after the node has been processed via a call to ReleaseNodes(). * If the node specified by _nodeId does not exist, the lock is released and NULL is returned. * \param _nodeId The nodeId (index into the node array) identifying the node to be returned * \return * A pointer to the specified node (if it exists) or NULL if not. */ Node* GetNode(uint8 _nodeId); ControllerInterface m_controllerInterfaceType; // Specifies the controller's hardware interface string m_controllerPath; // name or path used to open the controller hardware. Internal::Platform::Controller* m_controller; // Handles communications with the controller hardware. uint32 m_homeId; // Home ID of the Z-Wave controller. Not valid until the DriverReady notification has been received. string m_libraryVersion; // Version of the Z-Wave Library used by the controller. string m_libraryTypeName; // Name describing the library type. uint8 m_libraryType; // Type of library used by the controller. uint8 m_serialAPIVersion[2]; uint16 m_manufacturerId; uint16 m_productType; uint16 m_productId; uint8 m_apiMask[32]; uint8 m_initVersion; // Version of the Serial API used by the controller. uint8 m_initCaps; // Set of flags indicating the serial API capabilities (See IsSlave, HasTimerSupport, IsPrimaryController and IsStaticUpdateController above). uint8 m_controllerCaps; // Set of flags indicating the controller's capabilities (See IsInclusionController above). bool m_hasExtendedTxStatus; // True if the controller accepted SERIAL_API_SETUP_CMD_TX_STATUS_REPORT uint8 m_Controller_nodeId; // Z-Wave Controller's own node ID. Node* m_nodes[256]; // Array containing all the node objects. Internal::Platform::Mutex* m_nodeMutex; // Serializes access to node data Internal::CC::ControllerReplication* m_controllerReplication; // Controller replication is handled separately from the other command classes, due to older hand-held controllers using invalid node IDs. uint8 m_transmitOptions; //----------------------------------------------------------------------------- // Receiving Z-Wave messages //----------------------------------------------------------------------------- private: bool ReadMsg(); void ProcessMsg(uint8* _data, uint8 _length); void HandleGetVersionResponse(uint8* _data); void HandleGetRandomResponse(uint8* _data); void HandleSerialAPISetupResponse(uint8* _data); void HandleGetControllerCapabilitiesResponse(uint8* _data); void HandleGetSerialAPICapabilitiesResponse(uint8* _data); void HandleSerialAPISoftResetResponse(uint8* _data); void HandleEnableSUCResponse(uint8* _data); void HandleSetSUCNodeIdResponse(uint8* _data); void HandleGetSUCNodeIdResponse(uint8* _data); void HandleMemoryGetIdResponse(uint8* _data); /** * Process a response to a FUNC_ID_SERIAL_API_GET_INIT_DATA request. *

* The response message contains a bitmap identifying which of the 232 possible nodes * in the network are actually present. These bitmap values are compared with the * node map (read in from zwcfg_0x[homeid].xml) to see if the node has already been registered * by the OpenZWave library. If it has (the log will show it as "Known") and this is * the first time this message was sent (m_init is false), then AddNodeQuery() is called * to retrieve its current state. If this is a "New" node to OpenZWave, then InitNode() * is called. * \see AddNodeQuery, InitNode, GetNode, ReleaseNodes */ void HandleSerialAPIGetInitDataResponse(uint8* _data); void HandleGetNodeProtocolInfoResponse(uint8* _data); bool HandleRemoveFailedNodeResponse(uint8* _data); void HandleIsFailedNodeResponse(uint8* _data); bool HandleReplaceFailedNodeResponse(uint8* _data); bool HandleAssignReturnRouteResponse(uint8* _data); bool HandleDeleteReturnRouteResponse(uint8* _data); void HandleSendNodeInformationRequest(uint8* _data); void HandleSendDataResponse(uint8* _data, bool _replication); bool HandleNetworkUpdateResponse(uint8* _data); void HandleGetRoutingInfoResponse(uint8* _data); void HandleSendDataRequest(uint8* _data, uint8 _length, bool _replication); void HandleAddNodeToNetworkRequest(uint8* _data); void HandleCreateNewPrimaryRequest(uint8* _data); void HandleControllerChangeRequest(uint8* _data); void HandleSetLearnModeRequest(uint8* _data); void HandleRemoveFailedNodeRequest(uint8* _data); void HandleReplaceFailedNodeRequest(uint8* _data); void HandleRemoveNodeFromNetworkRequest(uint8* _data); void HandleApplicationCommandHandlerRequest(uint8* _data, bool encrypted); void HandlePromiscuousApplicationCommandHandlerRequest(uint8* _data); void HandleAssignReturnRouteRequest(uint8* _data); void HandleDeleteReturnRouteRequest(uint8* _data); void HandleNodeNeighborUpdateRequest(uint8* _data); void HandleNetworkUpdateRequest(uint8* _data); bool HandleApplicationUpdateRequest(uint8* _data); bool HandleRfPowerLevelSetResponse(uint8* _data); bool HandleSerialApiSetTimeoutsResponse(uint8* _data); bool HandleMemoryGetByteResponse(uint8* _data); bool HandleReadMemoryResponse(uint8* _data); void HandleGetVirtualNodesResponse(uint8* _data); bool HandleSetSlaveLearnModeResponse(uint8* _data); void HandleSetSlaveLearnModeRequest(uint8* _data); bool HandleSendSlaveNodeInfoResponse(uint8* _data); void HandleSendSlaveNodeInfoRequest(uint8* _data); void HandleApplicationSlaveCommandRequest(uint8* _data); void HandleSerialAPIResetRequest(uint8* _data); void CommonAddNodeStatusRequestHandler(uint8 _funcId, uint8* _data); bool m_waitingForAck; // True when we are waiting for an ACK from the dongle uint8 m_expectedCallbackId; // If non-zero, we wait for a message with this callback Id uint8 m_expectedReply; // If non-zero, we wait for a message with this function Id uint8 m_expectedCommandClassId; // If the expected reply is FUNC_ID_APPLICATION_COMMAND_HANDLER, this value stores the command class we're waiting to hear from uint8 m_expectedNodeId; // If we are waiting for a FUNC_ID_APPLICATION_COMMAND_HANDLER, make sure we only accept it from this node. //----------------------------------------------------------------------------- // Polling Z-Wave devices //----------------------------------------------------------------------------- private: int32 GetPollInterval() { return m_pollInterval; } void SetPollInterval(int32 _milliseconds, bool _bIntervalBetweenPolls) { m_pollInterval = _milliseconds; m_bIntervalBetweenPolls = _bIntervalBetweenPolls; } bool EnablePoll(const ValueID &_valueId, uint8 _intensity = 1); bool DisablePoll(const ValueID &_valueId); bool isPolled(const ValueID &_valueId); void SetPollIntensity(const ValueID &_valueId, uint8 _intensity); static void PollThreadEntryPoint(Internal::Platform::Event* _exitEvent, void* _context); void PollThreadProc(Internal::Platform::Event* _exitEvent); Internal::Platform::Thread* m_pollThread; // Thread for polling devices on the Z-Wave network struct PollEntry { ValueID m_id; uint8 m_pollCounter; }; list m_pollList; // List of nodes that need to be polled Internal::Platform::Mutex* m_pollMutex; // Serialize access to the polling list int32 m_pollInterval; // Time interval during which all nodes must be polled bool m_bIntervalBetweenPolls; // if true, the library intersperses m_pollInterval between polls; if false, the library attempts to complete all polls within m_pollInterval //----------------------------------------------------------------------------- // Retrieving Node information //----------------------------------------------------------------------------- public: uint8 GetNodeNumber(Internal::Msg const* _msg) const { return (_msg == NULL ? 0 : _msg->GetTargetNodeId()); } private: /** * Creates a new Node object (deleting any previous Node object with the same nodeId) and * queues a full query of the node's parameters (starting at the beginning of the query * stages--Node::QueryStage_None). This function will send Notification::Type_NodeAdded * and Notification::Type_NodeRemoved messages to identify these modifications. * \param _nodeId The node ID of the node to create and query. * \param newNode If this is a new Node added to the network, or we are just creating when we reload. * \param _protocolInfo if this is called via a AddNode command, then this would be the Device Classes, and CommandClass list * \param _length The length of the _protocolInfo field * \see Notification::Type_NodeAdded, Notification::Type_NodeRemoved, Node::QueryStage_None, */ void InitNode(uint8 const _nodeId, bool newNode = false, bool secure = false, uint8 const *_protocolInfo = NULL, uint8 const _length = 0); void InitAllNodes(); // Delete all nodes and fetch the data from the Z-Wave network again. bool IsNodeListeningDevice(uint8 const _nodeId); bool IsNodeFrequentListeningDevice(uint8 const _nodeId); bool IsNodeBeamingDevice(uint8 const _nodeId); bool IsNodeRoutingDevice(uint8 const _nodeId); bool IsNodeSecurityDevice(uint8 const _nodeId); uint32 GetNodeMaxBaudRate(uint8 const _nodeId); uint8 GetNodeVersion(uint8 const _nodeId); uint8 GetNodeSecurity(uint8 const _nodeId); uint8 GetNodeBasic(uint8 const _nodeId); string GetNodeBasicString(uint8 const _nodeId); uint8 GetNodeGeneric(uint8 const _nodeId, uint8 _instance); string GetNodeGenericString(uint8 const _nodeId, uint8 _instance); uint8 GetNodeSpecific(uint8 const _nodeId, uint8 _instance); string GetNodeSpecificString(uint8 const _nodeId, uint8 _instance); string GetNodeType(uint8 const _nodeId); uint32 GetNodeNeighbors(uint8 const _nodeId, uint8** o_neighbors); string GetNodeManufacturerName(uint8 const _nodeId); string GetNodeProductName(uint8 const _nodeId); string GetNodeName(uint8 const _nodeId); string GetNodeLocation(uint8 const _nodeId); uint16 GetNodeDeviceType(uint8 const _nodeId); string GetNodeDeviceTypeString(uint8 const _nodeId); uint8 GetNodeRole(uint8 const _nodeId); string GetNodeRoleString(uint8 const _nodeId); uint8 GetNodePlusType(uint8 const _nodeId); string GetNodePlusTypeString(uint8 const _nodeId); bool IsNodeZWavePlus(uint8 const _nodeId); uint16 GetNodeManufacturerId(uint8 const _nodeId); uint16 GetNodeProductType(uint8 const _nodeId); uint16 GetNodeProductId(uint8 const _nodeId); void SetNodeManufacturerName(uint8 const _nodeId, string const& _manufacturerName); void SetNodeProductName(uint8 const _nodeId, string const& _productName); void SetNodeName(uint8 const _nodeId, string const& _nodeName); void SetNodeLocation(uint8 const _nodeId, string const& _location); void SetNodeLevel(uint8 const _nodeId, uint8 const _level); void SetNodeOn(uint8 const _nodeId); void SetNodeOff(uint8 const _nodeId); Internal::VC::Value* GetValue(ValueID const& _id); bool IsAPICallSupported(uint8 const _apinum) const { return ((m_apiMask[(_apinum - 1) >> 3] & (1 << ((_apinum - 1) & 0x07))) != 0); } void SetAPICall(uint8 const _apinum, bool _toSet) { if (_toSet) { m_apiMask[(_apinum - 1) >> 3] |= (1 << ((_apinum - 1) & 0x07)); } else { m_apiMask[(_apinum - 1) >> 3] &= ~(1 << ((_apinum - 1) & 0x07)); } } uint8 NodeFromMessage(uint8 const* buffer); //----------------------------------------------------------------------------- // Controller commands //----------------------------------------------------------------------------- public: /** * Controller Commands. * Commands to be used with the BeginControllerCommand method. * \see Manager::BeginControllerCommand */ enum ControllerCommand { ControllerCommand_None = 0, /**< No command. */ ControllerCommand_AddDevice, /**< Add a new device or controller to the Z-Wave network. */ ControllerCommand_CreateNewPrimary, /**< Add a new controller to the Z-Wave network. Used when old primary fails. Requires SUC. */ ControllerCommand_ReceiveConfiguration, /**< Receive Z-Wave network configuration information from another controller. */ ControllerCommand_RemoveDevice, /**< Remove a device or controller from the Z-Wave network. */ ControllerCommand_RemoveFailedNode, /**< Move a node to the controller's failed nodes list. This command will only work if the node cannot respond. */ ControllerCommand_HasNodeFailed, /**< Check whether a node is in the controller's failed nodes list. */ ControllerCommand_ReplaceFailedNode, /**< Replace a non-responding node with another. The node must be in the controller's list of failed nodes for this command to succeed. */ ControllerCommand_TransferPrimaryRole, /**< Make a different controller the primary. */ ControllerCommand_RequestNetworkUpdate, /**< Request network information from the SUC/SIS. */ ControllerCommand_RequestNodeNeighborUpdate, /**< Get a node to rebuild its neighbour list. This method also does RequestNodeNeighbors */ ControllerCommand_AssignReturnRoute, /**< Assign a network return routes to a device. */ ControllerCommand_DeleteAllReturnRoutes, /**< Delete all return routes from a device. */ ControllerCommand_SendNodeInformation, /**< Send a node information frame */ ControllerCommand_ReplicationSend, /**< Send information from primary to secondary */ ControllerCommand_CreateButton, /**< Create an id that tracks handheld button presses */ ControllerCommand_DeleteButton /**< Delete id that tracks handheld button presses */ }; /** * Controller States. * States reported via the callback handler passed into the BeginControllerCommand method. * \see Manager::BeginControllerCommand */ enum ControllerState { ControllerState_Normal = 0, /**< No command in progress. */ ControllerState_Starting, /**< The command is starting. */ ControllerState_Cancel, /**< The command was canceled. */ ControllerState_Error, /**< Command invocation had error(s) and was aborted */ ControllerState_Waiting, /**< Controller is waiting for a user action. */ ControllerState_Sleeping, /**< Controller command is on a sleep queue wait for device. */ ControllerState_InProgress, /**< The controller is communicating with the other device to carry out the command. */ ControllerState_Completed, /**< The command has completed successfully. */ ControllerState_Failed, /**< The command has failed. */ ControllerState_NodeOK, /**< Used only with ControllerCommand_HasNodeFailed to indicate that the controller thinks the node is OK. */ ControllerState_NodeFailed /**< Used only with ControllerCommand_HasNodeFailed to indicate that the controller thinks the node has failed. */ }; /** * Controller Errors * Provide some more information about controller failures. */ enum ControllerError { ControllerError_None = 0, ControllerError_ButtonNotFound, /**< Button */ ControllerError_NodeNotFound, /**< Button */ ControllerError_NotBridge, /**< Button */ ControllerError_NotSUC, /**< CreateNewPrimary */ ControllerError_NotSecondary, /**< CreateNewPrimary */ ControllerError_NotPrimary, /**< RemoveFailedNode, AddNodeToNetwork */ ControllerError_IsPrimary, /**< ReceiveConfiguration */ ControllerError_NotFound, /**< RemoveFailedNode */ ControllerError_Busy, /**< RemoveFailedNode, RequestNetworkUpdate */ ControllerError_Failed, /**< RemoveFailedNode, RequestNetworkUpdate */ ControllerError_Disabled, /**< RequestNetworkUpdate error */ ControllerError_Overflow /**< RequestNetworkUpdate error */ }; typedef void (*pfnControllerCallback_t)(ControllerState _state, ControllerError _err, void* _context); private: // The public interface is provided via the wrappers in the Manager class void ResetController(Internal::Platform::Event* _evt); void SoftReset(); void RequestNodeNeighbors(uint8 const _nodeId, uint32 const _requestFlags); bool BeginControllerCommand(ControllerCommand _command, pfnControllerCallback_t _callback, void* _context, bool _highPower, uint8 _nodeId, uint8 _arg); bool CancelControllerCommand(); void AddNodeStop(uint8 const _funcId); // Handle different controller behaviors struct ControllerCommandItem { ControllerState m_controllerState; bool m_controllerStateChanged; bool m_controllerCommandDone; ControllerCommand m_controllerCommand; pfnControllerCallback_t m_controllerCallback; ControllerError m_controllerReturnError; void* m_controllerCallbackContext; bool m_highPower; bool m_controllerAdded; uint8 m_controllerCommandNode; uint8 m_controllerCommandArg; uint8 m_controllerDeviceProtocolInfo[254]; uint8 m_controllerDeviceProtocolInfoLength; }; ControllerCommandItem* m_currentControllerCommand; void DoControllerCommand(); void UpdateControllerState(ControllerState const _state, ControllerError const _error = ControllerError_None); uint8 m_SUCNodeId; void UpdateNodeRoutes(uint8 const_nodeId, bool _doUpdate = false); Internal::Platform::Event* m_controllerResetEvent; //----------------------------------------------------------------------------- // Sending Z-Wave messages //----------------------------------------------------------------------------- public: enum MsgQueue { MsgQueue_Command = 0, MsgQueue_NoOp, MsgQueue_Controller, MsgQueue_WakeUp, MsgQueue_Send, MsgQueue_Query, MsgQueue_Poll, MsgQueue_Count // Number of message queues }; void SendMsg(Internal::Msg* _msg, MsgQueue const _queue); /** * Fetch the transmit options */ uint8 GetTransmitOptions() const { return m_transmitOptions; } private: /** * If there are messages in the send queue (m_sendQueue), gets the next message in the * queue and writes it to the serial port. In sending the message, SendMsg also initializes * variables tracking the message's callback ID (m_expectedCallbackId), expected reply * (m_expectedReply) and expected command class ID (m_expectedCommandClassId). It also * sets m_waitingForAck to true and increments the message's send attempts counter. *

* If there are no messages in the send queue, then SendMsg checks the query queue to * see if there are any outstanding queries that can be processed (target node not asleep). * If so, it retrieves the Node object that needs to be queried and calls that node's * AdvanceQueries member function. If this call results in all of the node's queries to be * completed, SendMsg will remove the node query item from the query queue. * \return TRUE if data was written, FALSE if not * \see Msg, m_sendQueue, m_expectedCallbackId, m_expectedReply, m_expectedCommandClassId, * m_waitingForAck, Msg::GetSendAttempts, Node::AdvanceQueries, GetCurrentNodeQuery, * RemoveNodeQuery, Node::AllQueriesCompleted */ bool WriteNextMsg(MsgQueue const _queue); // Extracts the first message from the queue, and makes it the current one. bool WriteMsg(string const &str); // Sends the current message to the Z-Wave network void RemoveCurrentMsg(); // Deletes the current message and cleans up the callback etc states bool MoveMessagesToWakeUpQueue(uint8 const _targetNodeId, bool const _move); // If a node does not respond, and is of a type that can sleep, this method is used to move all its pending messages to another queue ready for when it wakes up next. bool HandleErrorResponse(uint8 const _error, uint8 const _nodeId, char const* _funcStr, bool _sleepCheck = false); // Handle data errors and process consistently. If message is moved to wake-up queue, return true. bool IsExpectedReply(uint8 const _nodeId); // Determine if reply message is the one we are expecting void SendQueryStageComplete(uint8 const _nodeId, Node::QueryStage const _stage); void RetryQueryStageComplete(uint8 const _nodeId, Node::QueryStage const _stage); void CheckCompletedNodeQueries(); // Send notifications if all awake and/or sleeping nodes have completed their queries // Requests to be sent to nodes are assigned to one of five queues. // From highest to lowest priority, these are // // 0) The security queue, for handling encrypted messages. This is the // highest priority send queue, because the security process inserts // messages to handle the encryption process that must be sent before // a new message can be wrapped. // // 1) The command queue, for controller commands. This is the 2nd highest // priority send queue, because the controller command processes are not // permitted to be interrupted by other requests. // // 2) The controller queue exists to handle multi-step controller commands. These // typically require user interaction or affect the network in some way. // // 3) The No Operation command class queue. This is used for device probing // at startup as well as network diagnostics. // // 4) The wakeup queue. This holds messages that have been held for a // sleeping device that has now woken up. These get a high priority // because such devices do not stay awake for very long. // // 5) The send queue. This is for normal messages, usually triggered by // a user interaction with the application. // // 6) The query queue. For node query messages sent when a new node is // discovered. The query process generates a large number of requests, // so the query queue has a low priority to avoid making the system // unresponsive. // // 7) The poll queue. Requests to devices that need their state polling // at regular intervals. These are of the lowest priority, and are only // sent when nothing else is going on // enum MsgQueueCmd { MsgQueueCmd_SendMsg = 0, MsgQueueCmd_QueryStageComplete, MsgQueueCmd_Controller, MsgQueueCmd_ReloadNode }; class MsgQueueItem { public: MsgQueueItem() : m_msg(NULL), m_nodeId(0), m_queryStage(Node::QueryStage_None), m_retry(false), m_cci(NULL) { } bool operator ==(MsgQueueItem const& _other) const { if (_other.m_command == m_command) { if (m_command == MsgQueueCmd_SendMsg) { return ((*_other.m_msg) == (*m_msg)); } else if (m_command == MsgQueueCmd_QueryStageComplete) { return ((_other.m_nodeId == m_nodeId) && (_other.m_queryStage == m_queryStage)); } else if (m_command == MsgQueueCmd_Controller) { return ((_other.m_cci->m_controllerCommand == m_cci->m_controllerCommand) && (_other.m_cci->m_controllerCallback == m_cci->m_controllerCallback)); } else if (m_command == MsgQueueCmd_ReloadNode) { return (_other.m_nodeId == m_nodeId); } } return false; } MsgQueueCmd m_command; Internal::Msg* m_msg; uint8 m_nodeId; Node::QueryStage m_queryStage; bool m_retry; ControllerCommandItem* m_cci; }; list m_msgQueue[MsgQueue_Count]; Internal::Platform::Event* m_queueEvent[MsgQueue_Count]; // Events for each queue, which are signaled when the queue is not empty Internal::Platform::Mutex* m_sendMutex; // Serialize access to the queues Internal::Msg* m_currentMsg; MsgQueue m_currentMsgQueueSource; // identifies which queue held m_currentMsg Internal::Platform::TimeStamp m_resendTimeStamp; //----------------------------------------------------------------------------- // Network functions //----------------------------------------------------------------------------- private: void TestNetwork(uint8 const _nodeId, uint32 const _count); //----------------------------------------------------------------------------- // Virtual Node commands //----------------------------------------------------------------------------- public: /** * Virtual Node Commands. * Commands to be used with virtual nodes. */ private: uint32 GetVirtualNeighbors(uint8** o_neighbors); void RequestVirtualNeighbors(MsgQueue const _queue); bool IsVirtualNode(uint8 const _nodeId) const { return ((m_virtualNeighbors[(_nodeId - 1) >> 3] & 1 << ((_nodeId - 1) & 0x07)) != 0); } void SendVirtualNodeInfo(uint8 const _fromNodeId, uint8 const _ToNodeId); void SendSlaveLearnModeOff(); void SaveButtons(); void ReadButtons(uint8 const _nodeId); bool m_virtualNeighborsReceived; uint8 m_virtualNeighbors[NUM_NODE_BITFIELD_BYTES]; // Bitmask containing virtual neighbors //----------------------------------------------------------------------------- // SwitchAll //----------------------------------------------------------------------------- private: // The public interface is provided via the wrappers in the Manager class void SwitchAllOn(); void SwitchAllOff(); //----------------------------------------------------------------------------- // Configuration Parameters (wrappers for the Node methods) //----------------------------------------------------------------------------- private: // The public interface is provided via the wrappers in the Manager class bool SetConfigParam(uint8 const _nodeId, uint8 const _param, int32 _value, uint8 const _size); void RequestConfigParam(uint8 const _nodeId, uint8 const _param); //----------------------------------------------------------------------------- // Groups (wrappers for the Node methods) //----------------------------------------------------------------------------- private: // The public interface is provided via the wrappers in the Manager class uint8 GetNumGroups(uint8 const _nodeId); uint32 GetAssociations(uint8 const _nodeId, uint8 const _groupIdx, uint8** o_associations); uint32 GetAssociations(uint8 const _nodeId, uint8 const _groupIdx, InstanceAssociation** o_associations); uint8 GetMaxAssociations(uint8 const _nodeId, uint8 const _groupIdx); bool IsMultiInstance(uint8 const _nodeId, uint8 const _groupIdx); string GetGroupLabel(uint8 const _nodeId, uint8 const _groupIdx); void AddAssociation(uint8 const _nodeId, uint8 const _groupIdx, uint8 const _targetNodeId, uint8 const _instance = 0x00); void RemoveAssociation(uint8 const _nodeId, uint8 const _groupIdx, uint8 const _targetNodeId, uint8 const _instance = 0x00); //----------------------------------------------------------------------------- // Notifications //----------------------------------------------------------------------------- private: void QueueNotification(Notification* _notification); // Adds a notification to the list. Notifications are queued until a point in the thread where we know we do not have any nodes locked. void NotifyWatchers(); // Passes the notifications to all the registered watcher callbacks in turn. list m_notifications; Internal::Platform::Event* m_notificationsEvent; //----------------------------------------------------------------------------- // Statistics //----------------------------------------------------------------------------- public: struct DriverData { uint32 m_SOFCnt; // Number of SOF bytes received uint32 m_ACKWaiting; // Number of unsolicited messages while waiting for an ACK uint32 m_readAborts; // Number of times read were aborted due to timeouts uint32 m_badChecksum; // Number of bad checksums uint32 m_readCnt; // Number of messages successfully read uint32 m_writeCnt; // Number of messages successfully sent uint32 m_CANCnt; // Number of CAN bytes received uint32 m_NAKCnt; // Number of NAK bytes received uint32 m_ACKCnt; // Number of ACK bytes received uint32 m_OOFCnt; // Number of bytes out of framing uint32 m_dropped; // Number of messages dropped & not delivered uint32 m_retries; // Number of messages retransmitted uint32 m_callbacks; // Number of unexpected callbacks uint32 m_badroutes; // Number of failed messages due to bad route response uint32 m_noack; // Number of no ACK returned errors uint32 m_netbusy; // Number of network busy/failure messages uint32 m_notidle; // Number of RF Network Busy messages uint32 m_txverified; // Number of TX Verified messages uint32 m_nondelivery; // Number of messages not delivered to network uint32 m_routedbusy; // Number of messages received with routed busy status uint32 m_broadcastReadCnt; // Number of broadcasts read uint32 m_broadcastWriteCnt; // Number of broadcasts sent }; void LogDriverStatistics(); private: void GetDriverStatistics(DriverData* _data); void GetNodeStatistics(uint8 const _nodeId, Node::NodeData* _data); uint32 m_SOFCnt; // Number of SOF bytes received uint32 m_ACKWaiting; // Number of unsolicited messages while waiting for an ACK uint32 m_readAborts; // Number of times read were aborted due to timeouts uint32 m_badChecksum; // Number of bad checksums uint32 m_readCnt; // Number of messages successfully read uint32 m_writeCnt; // Number of messages successfully sent uint32 m_CANCnt; // Number of CAN bytes received uint32 m_NAKCnt; // Number of NAK bytes received uint32 m_ACKCnt; // Number of ACK bytes received uint32 m_OOFCnt; // Number of bytes out of framing uint32 m_dropped; // Number of messages dropped & not delivered uint32 m_retries; // Number of retransmitted messages uint32 m_callbacks; // Number of unexpected callbacks uint32 m_badroutes; // Number of failed messages due to bad route response uint32 m_noack; // Number of no ACK returned errors uint32 m_netbusy; // Number of network busy/failure messages uint32 m_notidle; // Number of not idle messages uint32 m_txverified; // Number of TX Verified messages uint32 m_nondelivery; // Number of messages not delivered to network uint32 m_routedbusy; // Number of messages received with routed busy status uint32 m_broadcastReadCnt; // Number of broadcasts read uint32 m_broadcastWriteCnt; // Number of broadcasts sent //time_t m_commandStart; // Start time of last command //time_t m_timeoutLost; // Cumulative time lost to timeouts //----------------------------------------------------------------------------- // Security Command Class Related (Version 1.1) //----------------------------------------------------------------------------- public: aes_encrypt_ctx *GetAuthKey(); aes_encrypt_ctx *GetEncKey(); bool isNetworkKeySet(); private: bool initNetworkKeys(bool newnode); uint8 *GetNetworkKey(); bool SendEncryptedMessage(); bool SendNonceRequest(string logmsg); void SendNonceKey(uint8 nodeId, uint8 *nonce); aes_encrypt_ctx *AuthKey; aes_encrypt_ctx *EncryptKey; uint8 m_nonceReportSent; uint8 m_nonceReportSentAttempt; bool m_inclusionkeySet; //----------------------------------------------------------------------------- // Event Signaling for DNS and HTTP Threads //----------------------------------------------------------------------------- private: struct EventMsg { enum EventType { Event_DNS = 1, Event_Http }; EventType type; union { Internal::DNSLookup *lookup; Internal::HttpDownload *httpdownload; } event; }; void SubmitEventMsg(EventMsg *); void ProcessEventMsg(); list m_eventQueueMsg; Internal::Platform::Event* m_queueMsgEvent; // Events for each queue, which are signalled when the queue is not empty Internal::Platform::Mutex* m_eventMutex; // Serialize access to the queues //----------------------------------------------------------------------------- // DNS Related //----------------------------------------------------------------------------- public: bool CheckNodeConfigRevision(Node *); bool CheckMFSConfigRevision(); void ReloadNode(uint8 const _nodeId); private: void processConfigRevision(Internal::DNSLookup *); //----------------------------------------------------------------------------- // HTTP Client Related //----------------------------------------------------------------------------- public: bool setHttpClient(Internal::i_HttpClient *client); private: bool startConfigDownload(uint16 _manufacturerId, uint16 _productType, uint16 _productId, string configfile, uint8 node = 0); bool startDownload(string target, string file); bool startMFSDownload(string configfile); bool refreshNodeConfig(uint8 node); void processDownload(Internal::HttpDownload *); Internal::i_HttpClient *m_httpClient; //----------------------------------------------------------------------------- // Metadata Related //----------------------------------------------------------------------------- public: string const GetMetaData(uint8 const _nodeId, Node::MetaDataFields _metadata); Node::ChangeLogEntry const GetChangeLog(uint8 const _nodeId, uint32_t revision); //----------------------------------------------------------------------------- // ManufacturerSpecificDB Related //----------------------------------------------------------------------------- public: Internal::ManufacturerSpecificDB *GetManufacturerSpecificDB(); bool downloadConfigRevision(Node *); bool downloadMFSRevision(); private: Internal::ManufacturerSpecificDB *m_mfs; }; } // namespace OpenZWave #endif // _Driver_H openzwave-1.6.1914/cpp/src/ZWSecurity.h0000644000175200017520000000363314032142455014537 00000000000000//----------------------------------------------------------------------------- // // ZWSecurity.h // // Common Security/Encryption Routines // // Copyright (c) 2015 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef SECURITY_H_ #define SECURITY_H_ #include #include #include #include "Defs.h" #include "Driver.h" namespace OpenZWave { namespace Internal { bool EncryptBuffer(uint8 *m_buffer, uint8 m_length, Driver *driver, uint8 const _sendingNode, uint8 const _receivingNode, uint8 const m_nonce[8], uint8* e_buffer); bool DecryptBuffer(uint8 *e_buffer, uint8 e_length, Driver *driver, uint8 const _sendingNode, uint8 const _receivingNode, uint8 const m_nonce[8], uint8* m_buffer); bool GenerateAuthentication(uint8 const* _data, uint32 const _length, Driver *driver, uint8 const _sendingNode, uint8 const _receivingNode, uint8 *iv, uint8* _authentication); enum SecurityStrategy { SecurityStrategy_Essential = 0, SecurityStrategy_Supported }; SecurityStrategy ShouldSecureCommandClass(uint8 CommandClass); } // namespace Internal } // namespace OpenZWave #endif /* SECURITY_H_ */ openzwave-1.6.1914/cpp/src/Manager.cpp0000644000175200017520000045123614032142455014362 00000000000000//----------------------------------------------------------------------------- // // Manager.cpp // // The main public interface to OpenZWave. // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include #include #include "Defs.h" #include "CompatOptionManager.h" #include "Manager.h" #include "Driver.h" #include "Localization.h" #include "Node.h" #include "Notification.h" #include "NotificationCCTypes.h" #include "Options.h" #include "Scene.h" #include "SensorMultiLevelCCTypes.h" #include "Utils.h" #include "platform/Mutex.h" #include "platform/Event.h" #include "platform/Log.h" #include "command_classes/CommandClasses.h" #include "command_classes/CommandClass.h" #include "command_classes/WakeUp.h" #include "value_classes/ValueID.h" #include "value_classes/ValueBool.h" #include "value_classes/ValueButton.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueDecimal.h" #include "value_classes/ValueInt.h" #include "value_classes/ValueList.h" #include "value_classes/ValueRaw.h" #include "value_classes/ValueSchedule.h" #include "value_classes/ValueShort.h" #include "value_classes/ValueString.h" #include "value_classes/ValueBitSet.h" using namespace OpenZWave; Manager* Manager::s_instance = NULL; extern uint16_t ozw_vers_major; extern uint16_t ozw_vers_minor; extern uint16_t ozw_vers_revision; extern char ozw_version_string[]; //----------------------------------------------------------------------------- // Construction //----------------------------------------------------------------------------- #include "platform/FileOps.h" //----------------------------------------------------------------------------- // // Static creation of the singleton //----------------------------------------------------------------------------- Manager* Manager::Create() { if (Options::Get() && Options::Get()->AreLocked()) { if ( NULL == s_instance) { s_instance = new Manager(); } return s_instance; } // Options have not been created and locked. Log::Create("", false, true, LogLevel_Debug, LogLevel_Debug, LogLevel_None); Log::Write(LogLevel_Error, "Options have not been created and locked. Exiting..."); OZW_FATAL_ERROR(OZWException::OZWEXCEPTION_OPTIONS, "Options Not Created and Locked"); return NULL; } //----------------------------------------------------------------------------- // // Static method to destroy the singleton. //----------------------------------------------------------------------------- void Manager::Destroy() { delete s_instance; s_instance = NULL; } //----------------------------------------------------------------------------- // // Static method to get the Version of OZW as a string. //----------------------------------------------------------------------------- std::string Manager::getVersionAsString() { std::ostringstream versionstream; versionstream << ozw_vers_major << "." << ozw_vers_minor << "." << ozw_vers_revision; return versionstream.str(); } //----------------------------------------------------------------------------- // // Static method to get the long Version of OZW as a string. //----------------------------------------------------------------------------- std::string Manager::getVersionLongAsString() { std::ostringstream versionstream; versionstream << ozw_version_string; return versionstream.str(); } //----------------------------------------------------------------------------- // // Static method to get the Version of OZW. //----------------------------------------------------------------------------- ozwversion Manager::getVersion() { return version(ozw_vers_major, ozw_vers_minor); } //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Manager::Manager() : m_notificationMutex(new Internal::Platform::Mutex()) { // Ensure the singleton instance is set s_instance = this; // Create the log file (if enabled) bool logging = false; Options::Get()->GetOptionAsBool("Logging", &logging); string userPath = ""; Options::Get()->GetOptionAsString("UserPath", &userPath); string logFileNameBase = "OZW_Log.txt"; Options::Get()->GetOptionAsString("LogFileName", &logFileNameBase); bool bAppend = false; Options::Get()->GetOptionAsBool("AppendLogFile", &bAppend); bool bConsoleOutput = true; Options::Get()->GetOptionAsBool("ConsoleOutput", &bConsoleOutput); int nSaveLogLevel = (int) LogLevel_Detail; Options::Get()->GetOptionAsInt("SaveLogLevel", &nSaveLogLevel); if ((nSaveLogLevel == 0) || (nSaveLogLevel > LogLevel_StreamDetail)) { Log::Write(LogLevel_Warning, "Invalid LogLevel Specified for SaveLogLevel in Options.xml"); nSaveLogLevel = (int) LogLevel_Detail; } int nQueueLogLevel = (int) LogLevel_Debug; Options::Get()->GetOptionAsInt("QueueLogLevel", &nQueueLogLevel); if ((nQueueLogLevel == 0) || (nQueueLogLevel > LogLevel_StreamDetail)) { Log::Write(LogLevel_Warning, "Invalid LogLevel Specified for QueueLogLevel in Options.xml"); nQueueLogLevel = (int) LogLevel_Debug; } int nDumpTrigger = (int) LogLevel_Warning; Options::Get()->GetOptionAsInt("DumpTriggerLevel", &nDumpTrigger); string logFilename = userPath + logFileNameBase; Log::Create(logFilename, bAppend, bConsoleOutput, (LogLevel) nSaveLogLevel, (LogLevel) nQueueLogLevel, (LogLevel) nDumpTrigger); Log::SetLoggingState(logging); Internal::CC::CommandClasses::RegisterCommandClasses(); Internal::Scene::ReadScenes(); // petergebruers replace getVersionAsString() with getVersionLongAsString() because // the latter prints more information, based on the status of the repository // when "make" was run. A Makefile gets this info from git describe --long --tags --dirty Log::Write(LogLevel_Always, "OpenZwave Version %s Starting Up", getVersionLongAsString().c_str()); Log::Write(LogLevel_Always, "Using Language Localization %s", Internal::Localization::Get()->GetSelectedLang().c_str()); if (!Internal::NotificationCCTypes::Create()) { Log::Write(LogLevel_Error, "mgr, Cannot Create NotificationCCTypes!"); } if (!Internal::SensorMultiLevelCCTypes::Create()) { Log::Write(LogLevel_Error, "mgr, Cannot Create SensorMultiLevelCCTypes!"); } } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- Manager::~Manager() { // Clear the pending list while (!m_pendingDrivers.empty()) { list::iterator it = m_pendingDrivers.begin(); delete *it; m_pendingDrivers.erase(it); } m_pendingDrivers.clear(); // Clear the ready map while (!m_readyDrivers.empty()) { map::iterator it = m_readyDrivers.begin(); delete it->second; m_readyDrivers.erase(it); } m_readyDrivers.clear(); m_notificationMutex->Release(); // Clear the watchers list while (!m_watchers.empty()) { list::iterator it = m_watchers.begin(); delete *it; m_watchers.erase(it); } m_watchers.clear(); // Clear the generic device class list while (!Node::s_genericDeviceClasses.empty()) { map::iterator git = Node::s_genericDeviceClasses.begin(); delete git->second; Node::s_genericDeviceClasses.erase(git); } Node::s_genericDeviceClasses.clear(); while (!Node::s_basicDeviceClasses.empty()) { map::iterator git = Node::s_basicDeviceClasses.begin(); Node::s_basicDeviceClasses.erase(git); } Node::s_basicDeviceClasses.clear(); while (!Node::s_roleDeviceClasses.empty()) { map::iterator git = Node::s_roleDeviceClasses.begin(); delete git->second; Node::s_roleDeviceClasses.erase(git); } Node::s_roleDeviceClasses.clear(); while (!Node::s_deviceTypeClasses.empty()) { map::iterator git = Node::s_deviceTypeClasses.begin(); delete git->second; Node::s_deviceTypeClasses.erase(git); } Node::s_deviceTypeClasses.clear(); while (!Node::s_nodeTypes.empty()) { map::iterator git = Node::s_nodeTypes.begin(); delete git->second; Node::s_nodeTypes.erase(git); } Node::s_nodeTypes.clear(); Node::s_deviceClassesLoaded = false; Log::Destroy(); } //----------------------------------------------------------------------------- // Configuration //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Save the configuration of a driver to a file //----------------------------------------------------------------------------- void Manager::WriteConfig(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { driver->WriteCache(); Log::Write(LogLevel_Info, "mgr, Manager::WriteConfig completed for driver with home ID of 0x%.8x", _homeId); } else { Log::Write(LogLevel_Info, "mgr, Manager::WriteConfig failed - _homeId %d not found", _homeId); } Internal::Scene::WriteXML("zwscene.xml"); } //----------------------------------------------------------------------------- // Drivers //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Add a new Z-Wave PC Interface //----------------------------------------------------------------------------- bool Manager::AddDriver(string const& _controllerPath, Driver::ControllerInterface const& _interface) { // Make sure we don't already have a driver for this controller // Search the pending list for (list::iterator pit = m_pendingDrivers.begin(); pit != m_pendingDrivers.end(); ++pit) { if (_controllerPath == (*pit)->GetControllerPath()) { Log::Write(LogLevel_Info, "mgr, Cannot add driver for controller %s - driver already exists", _controllerPath.c_str()); return false; } } // Search the ready map for (map::iterator rit = m_readyDrivers.begin(); rit != m_readyDrivers.end(); ++rit) { if (_controllerPath == rit->second->GetControllerPath()) { Log::Write(LogLevel_Info, "mgr, Cannot add driver for controller %s - driver already exists", _controllerPath.c_str()); return false; } } Driver* driver = new Driver(_controllerPath, _interface); m_pendingDrivers.push_back(driver); driver->Start(); Log::Write(LogLevel_Info, "mgr, Added driver for controller %s", _controllerPath.c_str()); return true; } //----------------------------------------------------------------------------- // // Remove a Z-Wave PC Interface //----------------------------------------------------------------------------- bool Manager::RemoveDriver(string const& _controllerPath) { // Search the pending list for (list::iterator pit = m_pendingDrivers.begin(); pit != m_pendingDrivers.end(); ++pit) { if (_controllerPath == (*pit)->GetControllerPath()) { delete *pit; m_pendingDrivers.erase(pit); Log::Write(LogLevel_Info, "mgr, Driver for controller %s removed", _controllerPath.c_str()); return true; } } // Search the ready map for (map::iterator rit = m_readyDrivers.begin(); rit != m_readyDrivers.end(); ++rit) { if (_controllerPath == rit->second->GetControllerPath()) { /* data race right here: * Before, we were deleting the Driver Class direct from the Map... this was causing a datarace: * 1) Driver::~Driver destructor starts deleting everything.... * 2) This Triggers Notifications such as ValueDeleted etc * 3) Notifications are delivered to applications, and applications start calling * Manager Functions which require the Driver (such as IsPolled(valueid)) * 4) Manager looks up the Driver in the m_readyDriver and returns a pointer to the Driver Class * which is currently being destructed. * 5) All Hell Breaks loose and we crash and burn. * * But we can't change this, as the Driver Destructor triggers internal GetDriver calls... which * will crash and burn if they can't get a valid Driver back... */ Log::Write(LogLevel_Info, "mgr, Driver for controller %s pending removal", _controllerPath.c_str()); delete rit->second; m_readyDrivers.erase(rit); Log::Write(LogLevel_Info, "mgr, Driver for controller %s removed", _controllerPath.c_str()); return true; } } Log::Write(LogLevel_Info, "mgr, Failed to remove driver for controller %s", _controllerPath.c_str()); return false; } //----------------------------------------------------------------------------- // // Get a pointer to the driver for a Z-Wave PC Interface //----------------------------------------------------------------------------- Driver* Manager::GetDriver(uint32 const _homeId) { map::iterator it = m_readyDrivers.find(_homeId); if (it != m_readyDrivers.end()) { return it->second; } Log::Write(LogLevel_Error, "mgr, Manager::GetDriver failed - Home ID 0x%.8x is unknown", _homeId); OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_HOMEID, "Invalid HomeId passed to GetDriver"); //assert(0); << Don't assert as this might be a valid condition when we call RemoveDriver. See comments above. return NULL; } //----------------------------------------------------------------------------- // // Move a driver from pending to ready, and notify any watchers //----------------------------------------------------------------------------- void Manager::SetDriverReady(Driver* _driver, bool success) { // Search the pending list bool found = false; for (list::iterator it = m_pendingDrivers.begin(); it != m_pendingDrivers.end(); ++it) { if ((*it) == _driver) { // Remove the driver from the pending list m_pendingDrivers.erase(it); found = true; break; } } if (found) { if (success) { Log::Write(LogLevel_Info, "mgr, Driver with Home ID of 0x%.8x is now ready.", _driver->GetHomeId()); Log::Write(LogLevel_Info, ""); // Add the driver to the ready map m_readyDrivers[_driver->GetHomeId()] = _driver; } // Notify the watchers Notification* notification = new Notification(success ? Notification::Type_DriverReady : Notification::Type_DriverFailed); notification->SetHomeAndNodeIds(_driver->GetHomeId(), _driver->GetControllerNodeId()); if (!success) notification->SetComPort(_driver->GetControllerPath()); _driver->QueueNotification(notification); } } //----------------------------------------------------------------------------- // // //----------------------------------------------------------------------------- uint8 Manager::GetControllerNodeId(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetControllerNodeId(); } Log::Write(LogLevel_Info, "mgr, GetControllerNodeId() failed - _homeId %d not found", _homeId); return 0xff; } //----------------------------------------------------------------------------- // // //----------------------------------------------------------------------------- uint8 Manager::GetSUCNodeId(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetSUCNodeId(); } Log::Write(LogLevel_Info, "mgr, GetSUCNodeId() failed - _homeId %d not found", _homeId); return 0xff; } //----------------------------------------------------------------------------- // // //----------------------------------------------------------------------------- bool Manager::IsPrimaryController(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->IsPrimaryController(); } Log::Write(LogLevel_Info, "mgr, IsPrimaryController() failed - _homeId %d not found", _homeId); return false; } //----------------------------------------------------------------------------- // // //----------------------------------------------------------------------------- bool Manager::IsStaticUpdateController(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->IsStaticUpdateController(); } Log::Write(LogLevel_Info, "mgr, IsStaticUpdateController() failed - _homeId %d not found", _homeId); return false; } //----------------------------------------------------------------------------- // // //----------------------------------------------------------------------------- bool Manager::IsBridgeController(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->IsBridgeController(); } Log::Write(LogLevel_Info, "mgr, IsBridgeController() failed - _homeId %d not found", _homeId); return false; } //----------------------------------------------------------------------------- // // //----------------------------------------------------------------------------- bool Manager::HasExtendedTxStatus(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->HasExtendedTxStatus(); } Log::Write(LogLevel_Info, "mgr, HasExtendedTxStatus() failed - _homeId %d not found", _homeId); return false; } //----------------------------------------------------------------------------- // // //----------------------------------------------------------------------------- string Manager::GetLibraryVersion(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetLibraryVersion(); } Log::Write(LogLevel_Info, "mgr, GetLibraryVersion() failed - _homeId %d not found", _homeId); return ""; } //----------------------------------------------------------------------------- // // //----------------------------------------------------------------------------- string Manager::GetLibraryTypeName(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetLibraryTypeName(); } Log::Write(LogLevel_Info, "mgr, GetLibraryTypeName() failed - _homeId %d not found", _homeId); return ""; } //----------------------------------------------------------------------------- // // //----------------------------------------------------------------------------- int32 Manager::GetSendQueueCount(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetSendQueueCount(); } Log::Write(LogLevel_Info, "mgr, GetSendQueueCount() failed - _homeId %d not found", _homeId); return -1; } //----------------------------------------------------------------------------- // // Send driver statistics to the log file //----------------------------------------------------------------------------- void Manager::LogDriverStatistics(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->LogDriverStatistics(); } Log::Write(LogLevel_Warning, "mgr, LogDriverStatistics() failed - _homeId %d not found", _homeId); } //----------------------------------------------------------------------------- // // Retrieve controller interface type //----------------------------------------------------------------------------- Driver::ControllerInterface Manager::GetControllerInterfaceType(uint32 const _homeId) { Driver::ControllerInterface ifType = Driver::ControllerInterface_Unknown; if (Driver* driver = GetDriver(_homeId)) { ifType = driver->GetControllerInterfaceType(); } return ifType; } //----------------------------------------------------------------------------- // // Retrieve controller interface path //----------------------------------------------------------------------------- string Manager::GetControllerPath(uint32 const _homeId) { string path = ""; if (Driver* driver = GetDriver(_homeId)) { path = driver->GetControllerPath(); } return path; } //----------------------------------------------------------------------------- // Polling Z-Wave values //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Return the polling interval //----------------------------------------------------------------------------- int32 Manager::GetPollInterval() { for (map::iterator rit = m_readyDrivers.begin(); rit != m_readyDrivers.end(); ++rit) { return rit->second->GetPollInterval(); } for (list::iterator pit = m_pendingDrivers.begin(); pit != m_pendingDrivers.end(); ++pit) { return (*pit)->GetPollInterval(); } return 0; } //----------------------------------------------------------------------------- // // Set the polling interval on all drivers //----------------------------------------------------------------------------- void Manager::SetPollInterval(int32 _milliseconds, bool _bIntervalBetweenPolls) { for (list::iterator pit = m_pendingDrivers.begin(); pit != m_pendingDrivers.end(); ++pit) { (*pit)->SetPollInterval(_milliseconds, _bIntervalBetweenPolls); } for (map::iterator rit = m_readyDrivers.begin(); rit != m_readyDrivers.end(); ++rit) { rit->second->SetPollInterval(_milliseconds, _bIntervalBetweenPolls); } } //----------------------------------------------------------------------------- // // Enable polling of a value //----------------------------------------------------------------------------- bool Manager::EnablePoll(ValueID const &_valueId, uint8 const _intensity) { if (Driver* driver = GetDriver(_valueId.GetHomeId())) { return (driver->EnablePoll(_valueId, _intensity)); } Log::Write(LogLevel_Info, "mgr, EnablePoll failed - Driver with Home ID 0x%.8x is not available", _valueId.GetHomeId()); return false; } //----------------------------------------------------------------------------- // // Disable polling of a value //----------------------------------------------------------------------------- bool Manager::DisablePoll(ValueID const &_valueId) { if (Driver* driver = GetDriver(_valueId.GetHomeId())) { return (driver->DisablePoll(_valueId)); } Log::Write(LogLevel_Info, "mgr, DisablePoll failed - Driver with Home ID 0x%.8x is not available", _valueId.GetHomeId()); return false; } //----------------------------------------------------------------------------- // // Check polling status of a value //----------------------------------------------------------------------------- bool Manager::isPolled(ValueID const &_valueId) { if (Driver* driver = GetDriver(_valueId.GetHomeId())) { return (driver->isPolled(_valueId)); } Log::Write(LogLevel_Info, "mgr, isPolled failed - Driver with Home ID 0x%.8x is not available", _valueId.GetHomeId()); return false; } //----------------------------------------------------------------------------- // // Change the intensity with which this value is polled //----------------------------------------------------------------------------- void Manager::SetPollIntensity(ValueID const &_valueId, uint8 const _intensity) { if (Driver* driver = GetDriver(_valueId.GetHomeId())) { return (driver->SetPollIntensity(_valueId, _intensity)); } Log::Write(LogLevel_Error, "mgr, SetPollIntensity failed - Driver with Home ID 0x%.8x is not available", _valueId.GetHomeId()); } //----------------------------------------------------------------------------- // // Change the intensity with which this value is polled //----------------------------------------------------------------------------- uint8 Manager::GetPollIntensity(ValueID const &_valueId) { uint8 intensity = 0; if (Driver* driver = GetDriver(_valueId.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::Value* value = driver->GetValue(_valueId)) { intensity = value->GetPollIntensity(); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetPollIntensity"); } } return intensity; } //----------------------------------------------------------------------------- // Retrieving Node information //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Fetch the data for a node from the Z-Wave network //----------------------------------------------------------------------------- bool Manager::RefreshNodeInfo(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { // Cause the node's data to be obtained from the Z-Wave network // in the same way as if it had just been added. Internal::LockGuard LG(driver->m_nodeMutex); driver->ReloadNode(_nodeId); return true; } return false; } //----------------------------------------------------------------------------- // // Fetch the command class data for a node from the Z-Wave network //----------------------------------------------------------------------------- bool Manager::RequestNodeState(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); // Retreive the Node's session and dynamic data Node* node = driver->GetNode(_nodeId); if (node) { node->SetQueryStage(Node::QueryStage_Associations); return true; } } return false; } //----------------------------------------------------------------------------- // // Fetch only the dynamic command class data for a node from the Z-Wave network //----------------------------------------------------------------------------- bool Manager::RequestNodeDynamic(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); // Retreive the Node's dynamic data Node* node = driver->GetNode(_nodeId); if (node) { node->SetQueryStage(Node::QueryStage_Dynamic); return true; } } return false; } //----------------------------------------------------------------------------- // // Get whether the node is a listening device that does not go to sleep //----------------------------------------------------------------------------- bool Manager::IsNodeListeningDevice(uint32 const _homeId, uint8 const _nodeId) { bool res = false; if (Driver* driver = GetDriver(_homeId)) { res = driver->IsNodeListeningDevice(_nodeId); } return res; } //----------------------------------------------------------------------------- // // Get whether the node is a listening device that does not go to sleep //----------------------------------------------------------------------------- bool Manager::IsNodeFrequentListeningDevice(uint32 const _homeId, uint8 const _nodeId) { bool res = false; if (Driver* driver = GetDriver(_homeId)) { res = driver->IsNodeFrequentListeningDevice(_nodeId); } return res; } //----------------------------------------------------------------------------- // // Get whether the node is a beam capable device. //----------------------------------------------------------------------------- bool Manager::IsNodeBeamingDevice(uint32 const _homeId, uint8 const _nodeId) { bool res = false; if (Driver* driver = GetDriver(_homeId)) { res = driver->IsNodeBeamingDevice(_nodeId); } return res; } //----------------------------------------------------------------------------- // // Get whether the node is a routing device that passes messages to other nodes //----------------------------------------------------------------------------- bool Manager::IsNodeRoutingDevice(uint32 const _homeId, uint8 const _nodeId) { bool res = false; if (Driver* driver = GetDriver(_homeId)) { res = driver->IsNodeRoutingDevice(_nodeId); } return res; } //----------------------------------------------------------------------------- // // Get the security attribute for a node. //----------------------------------------------------------------------------- bool Manager::IsNodeSecurityDevice(uint32 const _homeId, uint8 const _nodeId) { bool security = 0; if (Driver* driver = GetDriver(_homeId)) { security = driver->IsNodeSecurityDevice(_nodeId); } return security; } //----------------------------------------------------------------------------- // // Get the maximum baud rate of a node's communications //----------------------------------------------------------------------------- uint32 Manager::GetNodeMaxBaudRate(uint32 const _homeId, uint8 const _nodeId) { uint32 baud = 0; if (Driver* driver = GetDriver(_homeId)) { baud = driver->GetNodeMaxBaudRate(_nodeId); } return baud; } //----------------------------------------------------------------------------- // // Get the version number of a node //----------------------------------------------------------------------------- uint8 Manager::GetNodeVersion(uint32 const _homeId, uint8 const _nodeId) { uint8 version = 0; if (Driver* driver = GetDriver(_homeId)) { version = driver->GetNodeVersion(_nodeId); } return version; } //----------------------------------------------------------------------------- // // Get the security byte of a node //----------------------------------------------------------------------------- uint8 Manager::GetNodeSecurity(uint32 const _homeId, uint8 const _nodeId) { uint8 version = 0; if (Driver* driver = GetDriver(_homeId)) { version = driver->GetNodeSecurity(_nodeId); } return version; } //----------------------------------------------------------------------------- // // Get if the Node is a ZWave Plus Supported Node //----------------------------------------------------------------------------- bool Manager::IsNodeZWavePlus(uint32 const _homeId, uint8 const _nodeId) { bool version = false; if (Driver* driver = GetDriver(_homeId)) { version = driver->IsNodeZWavePlus(_nodeId); } return version; } //----------------------------------------------------------------------------- // // Get the basic type of a node //----------------------------------------------------------------------------- uint8 Manager::GetNodeBasic(uint32 const _homeId, uint8 const _nodeId) { uint8 basic = 0; if (Driver* driver = GetDriver(_homeId)) { basic = driver->GetNodeBasic(_nodeId); } return basic; } //----------------------------------------------------------------------------- // // Get the basic type of a node //----------------------------------------------------------------------------- string Manager::GetNodeBasicString(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetNodeBasicString(_nodeId); } return "Unknown"; } //----------------------------------------------------------------------------- // // Get the generic type of a node //----------------------------------------------------------------------------- uint8 Manager::GetNodeGeneric(uint32 const _homeId, uint8 const _nodeId, uint8 const _instance) { uint8 genericType = 0; if (Driver* driver = GetDriver(_homeId)) { genericType = driver->GetNodeGeneric(_nodeId, _instance); } return genericType; } //----------------------------------------------------------------------------- // // Get the generic type of a node //----------------------------------------------------------------------------- string Manager::GetNodeGenericString(uint32 const _homeId, uint8 const _nodeId, uint8 const _instance) { if (Driver *driver = GetDriver(_homeId)) { return driver->GetNodeGenericString(_nodeId, _instance); } return "Unknown"; } //----------------------------------------------------------------------------- // // Get the specific type of a node //----------------------------------------------------------------------------- uint8 Manager::GetNodeSpecific(uint32 const _homeId, uint8 const _nodeId, uint8 const _instance) { uint8 specific = 0; if (Driver* driver = GetDriver(_homeId)) { specific = driver->GetNodeSpecific(_nodeId, _instance); } return specific; } //----------------------------------------------------------------------------- // // Get the specific type of a node //----------------------------------------------------------------------------- string Manager::GetNodeSpecificString(uint32 const _homeId, uint8 const _nodeId, uint8 const _instance) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetNodeSpecificString(_nodeId, _instance); } return "Unknown"; } //----------------------------------------------------------------------------- // // Get a string describing the type of a node //----------------------------------------------------------------------------- string Manager::GetNodeType(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { if (driver->IsNodeZWavePlus(_nodeId)) return driver->GetNodeDeviceTypeString(_nodeId); else return driver->GetNodeType(_nodeId); } return "Unknown"; } //----------------------------------------------------------------------------- // // Get the bitmap of this node's neighbors //----------------------------------------------------------------------------- uint32 Manager::GetNodeNeighbors(uint32 const _homeId, uint8 const _nodeId, uint8** o_neighbors) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetNodeNeighbors(_nodeId, o_neighbors); } return 0; } //----------------------------------------------------------------------------- // // Syncronise OZW's copy of the Neighbor List for a Node with the Controller //----------------------------------------------------------------------------- void Manager::SyncronizeNodeNeighbors(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { driver->RequestNodeNeighbors(_nodeId, 0); } return; } //----------------------------------------------------------------------------- // // Get the manufacturer name of a node //----------------------------------------------------------------------------- string Manager::GetNodeManufacturerName(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetNodeManufacturerName(_nodeId); } return "Unknown"; } //----------------------------------------------------------------------------- // // Get the product name of a node //----------------------------------------------------------------------------- string Manager::GetNodeProductName(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetNodeProductName(_nodeId); } return "Unknown"; } //----------------------------------------------------------------------------- // // Get the user-editable name of a node //----------------------------------------------------------------------------- string Manager::GetNodeName(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetNodeName(_nodeId); } return "Unknown"; } //----------------------------------------------------------------------------- // // Get the location of a node //----------------------------------------------------------------------------- string Manager::GetNodeLocation(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetNodeLocation(_nodeId); } return "Unknown"; } //----------------------------------------------------------------------------- // // Set the manufacturer name a node //----------------------------------------------------------------------------- void Manager::SetNodeManufacturerName(uint32 const _homeId, uint8 const _nodeId, string const& _manufacturerName) { if (Driver* driver = GetDriver(_homeId)) { driver->SetNodeManufacturerName(_nodeId, _manufacturerName); } } //----------------------------------------------------------------------------- // // Set the product name of a node //----------------------------------------------------------------------------- void Manager::SetNodeProductName(uint32 const _homeId, uint8 const _nodeId, string const& _productName) { if (Driver* driver = GetDriver(_homeId)) { driver->SetNodeProductName(_nodeId, _productName); } } //----------------------------------------------------------------------------- // // Set the node name value with the specified ID //----------------------------------------------------------------------------- void Manager::SetNodeName(uint32 const _homeId, uint8 const _nodeId, string const& _nodeName) { if (Driver* driver = GetDriver(_homeId)) { driver->SetNodeName(_nodeId, _nodeName); } } //----------------------------------------------------------------------------- // // Set a string describing the location of a node //----------------------------------------------------------------------------- void Manager::SetNodeLocation(uint32 const _homeId, uint8 const _nodeId, string const& _location ) { if (Driver* driver = GetDriver(_homeId)) { driver->SetNodeLocation(_nodeId, _location); } } //----------------------------------------------------------------------------- // // Get the manufacturer ID value of a node //----------------------------------------------------------------------------- string Manager::GetNodeManufacturerId(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { uint16 mid = driver->GetNodeManufacturerId(_nodeId); std::stringstream ss; ss << "0x" << std::hex << std::setw(4) << std::setfill('0') << mid; return ss.str(); } return "Unknown"; } //----------------------------------------------------------------------------- // // Get the product type value of a node //----------------------------------------------------------------------------- string Manager::GetNodeProductType(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { uint16 mid = driver->GetNodeProductType(_nodeId); std::stringstream ss; ss << "0x" << std::hex << std::setw(4) << std::setfill('0') << mid; return ss.str(); } return "Unknown"; } //----------------------------------------------------------------------------- // // Get the node device type as reported in the Z-Wave+ Info report. //----------------------------------------------------------------------------- uint16 Manager::GetNodeDeviceType(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetNodeDeviceType(_nodeId); } return 0x00; // unknown } //----------------------------------------------------------------------------- // // Get the node device type as reported in the Z-Wave+ Info report. //----------------------------------------------------------------------------- string Manager::GetNodeDeviceTypeString(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetNodeDeviceTypeString(_nodeId); } return ""; // unknown } //----------------------------------------------------------------------------- // // Get the node role as reported in the Z-Wave+ Info report. //----------------------------------------------------------------------------- uint8 Manager::GetNodeRole(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetNodeRole(_nodeId); } return 0x00; // unknown } //----------------------------------------------------------------------------- // // Get the node role as reported in the Z-Wave+ Info report. //----------------------------------------------------------------------------- string Manager::GetNodeRoleString(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetNodeRoleString(_nodeId); } return ""; // unknown } uint8 Manager::GetNodePlusType(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetNodePlusType(_nodeId); } return 0x00; // unknown } string Manager::GetNodePlusTypeString(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetNodePlusTypeString(_nodeId); } return ""; // unknown } //----------------------------------------------------------------------------- // // Get the product Id value with the specified ID //----------------------------------------------------------------------------- string Manager::GetNodeProductId(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { uint16 mid = driver->GetNodeProductId(_nodeId); std::stringstream ss; ss << "0x" << std::hex << std::setw(4) << std::setfill('0') << mid; return ss.str(); } return "Unknown"; } //----------------------------------------------------------------------------- // // Helper method to turn a node on //----------------------------------------------------------------------------- void Manager::SetNodeOn(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { driver->SetNodeOn(_nodeId); } } //----------------------------------------------------------------------------- // // Helper method to turn a node off //----------------------------------------------------------------------------- void Manager::SetNodeOff(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { driver->SetNodeOff(_nodeId); } } //----------------------------------------------------------------------------- // // Helper method to return whether a particular class is available in a node //----------------------------------------------------------------------------- bool Manager::IsNodeInfoReceived(uint32 const _homeId, uint8 const _nodeId) { bool result = false; if (Driver* driver = GetDriver(_homeId)) { Node *node; // Need to lock and unlock nodes to check this information Internal::LockGuard LG(driver->m_nodeMutex); if ((node = driver->GetNode(_nodeId)) != NULL) { result = node->NodeInfoReceived(); } } return result; } //----------------------------------------------------------------------------- // // Helper method to return whether a particular class is available in a node //----------------------------------------------------------------------------- bool Manager::GetNodeClassInformation(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, string *_className, uint8 *_classVersion) { bool result = false; if (Driver* driver = GetDriver(_homeId)) { Node *node; // Need to lock and unlock nodes to check this information Internal::LockGuard LG(driver->m_nodeMutex); if ((node = driver->GetNode(_nodeId)) != NULL) { Internal::CC::CommandClass *cc; if (node->NodeInfoReceived() && ((cc = node->GetCommandClass(_commandClassId)) != NULL)) { if (_className) { *_className = cc->GetCommandClassName(); } if (_classVersion) { *_classVersion = cc->GetVersion(); } // Positive result result = true; } } } return result; } //----------------------------------------------------------------------------- // // Get a String representing the Command Class Name //----------------------------------------------------------------------------- string Manager::GetCommandClassName(uint8 const _commandClassId) { return OpenZWave::Internal::CC::CommandClasses::GetName(_commandClassId); } //----------------------------------------------------------------------------- // // Helper method to return whether a node is awake or sleeping //----------------------------------------------------------------------------- bool Manager::IsNodeAwake(uint32 const _homeId, uint8 const _nodeId) { if (IsNodeListeningDevice(_homeId, _nodeId)) { return true; // if listening then always awake } bool result = true; if (Driver* driver = GetDriver(_homeId)) { // Need to lock and unlock nodes to check this information Internal::LockGuard LG(driver->m_nodeMutex); if (Node* node = driver->GetNode(_nodeId)) { if (Internal::CC::WakeUp* wcc = static_cast(node->GetCommandClass(Internal::CC::WakeUp::StaticGetCommandClassId()))) { result = wcc->IsAwake(); } } } return result; } //----------------------------------------------------------------------------- // // Helper method to return whether a node is on the network or not //----------------------------------------------------------------------------- bool Manager::IsNodeFailed(uint32 const _homeId, uint8 const _nodeId) { bool result = false; if (Driver* driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); if (Node* node = driver->GetNode(_nodeId)) { result = !node->IsNodeAlive(); } } return result; } //----------------------------------------------------------------------------- // // Helper method to return whether a node's query stage //----------------------------------------------------------------------------- string Manager::GetNodeQueryStage(uint32 const _homeId, uint8 const _nodeId) { string result = "Unknown"; if (Driver* driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); if (Node* node = driver->GetNode(_nodeId)) { result = node->GetQueryStageName(node->GetCurrentQueryStage()); } } return result; } //----------------------------------------------------------------------------- // // Helper method to set the basic level of a node //----------------------------------------------------------------------------- void Manager::SetNodeLevel(uint32 const _homeId, uint8 const _nodeId, uint8 const _level) { if (Driver* driver = GetDriver(_homeId)) { return driver->SetNodeLevel(_nodeId, _level); } } //----------------------------------------------------------------------------- // Instances //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Gets the user-friendly Instance label for the valueID //----------------------------------------------------------------------------- string Manager::GetInstanceLabel(ValueID const &_id) { return GetInstanceLabel(_id.GetHomeId(), _id.GetNodeId(), _id.GetCommandClassId(), _id.GetInstance()); } //----------------------------------------------------------------------------- // // Gets the user-friendly Instance label for the cc and instance //----------------------------------------------------------------------------- string Manager::GetInstanceLabel(uint32 const _homeId, uint8 const _node, uint8 const _cc, uint8 const _instance) { string label; if (Driver* driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); if (Node* node = driver->GetNode(_node)) { label = node->GetInstanceLabel(_cc, _instance); return label; } OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_NODEID, "Invalid Node passed to GetInstanceLabel"); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_HOMEID, "Invalid HomeId passed to GetInstanceLabel"); } return label; } //----------------------------------------------------------------------------- // Values //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Gets the user-friendly label for the value //----------------------------------------------------------------------------- string Manager::GetValueLabel(ValueID const& _id, int32 _pos) { string label; if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (_pos != -1) { if (_id.GetType() != ValueID::ValueType_BitSet) { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "ValueID passed to GetValueLabel is not a BitSet but a position was requested"); return label; } Internal::VC::ValueBitSet *value = static_cast(driver->GetValue(_id)); label = value->GetBitLabel(_pos); value->Release(); return label; } else { bool useinstancelabels = true; Options::Get()->GetOptionAsBool("IncludeInstanceLabel", &useinstancelabels); Node* node = driver->GetNode(_id.GetNodeId()); if ((useinstancelabels) && (node)) { if (node->GetNumInstances(_id.GetCommandClassId()) > 1) { label = GetInstanceLabel(_id).append(" "); } } if (Internal::VC::Value* value = driver->GetValue(_id)) { label.append(value->GetLabel()); value->Release(); return label; } } OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueLabel"); } return label; } //----------------------------------------------------------------------------- // // Sets the user-friendly label for the value //----------------------------------------------------------------------------- void Manager::SetValueLabel(ValueID const& _id, string const& _value, int32 _pos) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (_pos != -1) { if (_id.GetType() != ValueID::ValueType_BitSet) { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "ValueID passed to SetValueLabel is not a BitSet but a position was requested"); return; } Internal::VC::ValueBitSet *value = static_cast(driver->GetValue(_id)); value->SetBitLabel(_pos, _value); value->Release(); return; } else { if (Internal::VC::Value* value = driver->GetValue(_id)) { value->SetLabel(_value); value->Release(); return; } } OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValueLabel"); } } //----------------------------------------------------------------------------- // // Gets the units that the value is measured in //----------------------------------------------------------------------------- string Manager::GetValueUnits(ValueID const& _id) { string units; if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::Value* value = driver->GetValue(_id)) { units = value->GetUnits(); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueUnits"); } } return units; } //----------------------------------------------------------------------------- // // Sets the units that the value is measured in //----------------------------------------------------------------------------- void Manager::SetValueUnits(ValueID const& _id, string const& _value) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::Value* value = driver->GetValue(_id)) { value->SetUnits(_value); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValueUnits"); } } } //----------------------------------------------------------------------------- // // Gets a help string describing the value's purpose and usage //----------------------------------------------------------------------------- string Manager::GetValueHelp(ValueID const& _id, int32 _pos) { string help; if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (_pos != -1) { if (_id.GetType() != ValueID::ValueType_BitSet) { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "ValueID passed to GetValueHelp is not a BitSet but a position was requested"); return help; } Internal::VC::ValueBitSet *value = static_cast(driver->GetValue(_id)); help = value->GetBitHelp(_pos); value->Release(); return help; } else { if (Internal::VC::Value* value = driver->GetValue(_id)) { help = value->GetHelp(); value->Release(); return help; } } } OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueHelp"); return help; } //----------------------------------------------------------------------------- // // Sets a help string describing the value's purpose and usage //----------------------------------------------------------------------------- void Manager::SetValueHelp(ValueID const& _id, string const& _value, int32 _pos) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (_pos != -1) { if (_id.GetType() != ValueID::ValueType_BitSet) { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "ValueID passed to SetValueHelp is not a BitSet but a position was requested"); return; } Internal::VC::ValueBitSet *value = static_cast(driver->GetValue(_id)); value->SetBitHelp(_pos, _value); value->Release(); return; } else { if (Internal::VC::Value* value = driver->GetValue(_id)) { value->SetHelp(_value); value->Release(); return; } } } OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValueHelp"); } //----------------------------------------------------------------------------- // // Gets the minimum for a value //----------------------------------------------------------------------------- int32 Manager::GetValueMin(ValueID const& _id) { int32 limit = 0; if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::Value* value = driver->GetValue(_id)) { limit = value->GetMin(); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueMin"); } } return limit; } //----------------------------------------------------------------------------- // // Gets the maximum for a value //----------------------------------------------------------------------------- int32 Manager::GetValueMax(ValueID const& _id) { int32 limit = 0; if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::Value* value = driver->GetValue(_id)) { limit = value->GetMax(); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueMax"); } } return limit; } //----------------------------------------------------------------------------- // // Test whether the value is read-only //----------------------------------------------------------------------------- bool Manager::IsValueReadOnly(ValueID const& _id) { bool res = false; if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::Value* value = driver->GetValue(_id)) { res = value->IsReadOnly(); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to IsValueReadOnly"); } } return res; } //----------------------------------------------------------------------------- // // Test whether the value is write-only //----------------------------------------------------------------------------- bool Manager::IsValueWriteOnly(ValueID const& _id) { bool res = false; if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::Value* value = driver->GetValue(_id)) { res = value->IsWriteOnly(); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to IsValueWriteOnly"); } } return res; } //----------------------------------------------------------------------------- // // Test whether the value has been set by a status message from the device //----------------------------------------------------------------------------- bool Manager::IsValueSet(ValueID const& _id) { bool res = false; if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::Value* value = driver->GetValue(_id)) { res = value->IsSet(); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to IsValueSet"); } } return res; } //----------------------------------------------------------------------------- // // Test whether the value is currently being polled //----------------------------------------------------------------------------- bool Manager::IsValuePolled(ValueID const& _id) { bool res = false; if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::Value* value = driver->GetValue(_id)) { res = value->IsPolled(); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to IsValuePolled"); } } return res; } //----------------------------------------------------------------------------- // // Test whether the valueID is Valid //----------------------------------------------------------------------------- bool Manager::IsValueValid(ValueID const& _id) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::Value* value = driver->GetValue(_id)) { value->Release(); return true; } } return false; } //----------------------------------------------------------------------------- // // Gets a bit from a BitSet as a bool //----------------------------------------------------------------------------- bool Manager::GetValueAsBitSet(ValueID const& _id, uint8 _pos, bool* o_value) { if (o_value) { if (ValueID::ValueType_BitSet == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueBitSet* value = static_cast(driver->GetValue(_id))) { *o_value = value->GetBit(_pos); value->Release(); return true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsBitSet"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetValueAsBitSet is not a BitSet Value"); } } return false; } //----------------------------------------------------------------------------- // // Gets a value as a bool //----------------------------------------------------------------------------- bool Manager::GetValueAsBool(ValueID const& _id, bool* o_value) { bool res = false; if (o_value) { if (ValueID::ValueType_Bool == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueBool* value = static_cast(driver->GetValue(_id))) { *o_value = value->GetValue(); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsBool"); } } } else if (ValueID::ValueType_Button == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueButton* value = static_cast(driver->GetValue(_id))) { *o_value = value->IsPressed(); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsBool"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetValueAsBool is not a Bool or Button Value"); } } return res; } //----------------------------------------------------------------------------- // // Gets a value as an 8-bit unsigned integer //----------------------------------------------------------------------------- bool Manager::GetValueAsByte(ValueID const& _id, uint8* o_value) { bool res = false; if (o_value) { if (ValueID::ValueType_Byte == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueByte* value = static_cast(driver->GetValue(_id))) { *o_value = value->GetValue(); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsByte"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetValueAsByte is not a Byte Value"); } } return res; } //----------------------------------------------------------------------------- // // Gets a value as a floating point number //----------------------------------------------------------------------------- bool Manager::GetValueAsFloat(ValueID const& _id, float* o_value) { bool res = false; if (o_value) { if (ValueID::ValueType_Decimal == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueDecimal* value = static_cast(driver->GetValue(_id))) { string str = value->GetValue(); *o_value = (float) atof(str.c_str()); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsFloat"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetValueAsFloat is not a Float Value"); } } return res; } //----------------------------------------------------------------------------- // // Gets a value as a 32-bit signed integer //----------------------------------------------------------------------------- bool Manager::GetValueAsInt(ValueID const& _id, int32* o_value) { bool res = false; if (o_value) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (ValueID::ValueType_Int == _id.GetType()) { if (Internal::VC::ValueInt* value = static_cast(driver->GetValue(_id))) { *o_value = value->GetValue(); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsInt"); } } else if (ValueID::ValueType_BitSet == _id.GetType()) { if (Internal::VC::ValueBitSet* value = static_cast(driver->GetValue(_id))) { *o_value = value->GetValue(); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsInt"); } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetValueAsInt is not a Int or BitSet Value"); } } } return res; } //----------------------------------------------------------------------------- // // Gets a value as a collection of bytes //----------------------------------------------------------------------------- bool Manager::GetValueAsRaw(ValueID const& _id, uint8** o_value, uint8* o_length) { bool res = false; if (o_value && o_length) { if (ValueID::ValueType_Raw == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueRaw* value = static_cast(driver->GetValue(_id))) { *o_length = value->GetLength(); *o_value = new uint8[*o_length]; memcpy(*o_value, value->GetValue(), *o_length); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsRaw"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetValueAsRaw is not a Raw Value"); } } return res; } //----------------------------------------------------------------------------- // // Gets a value as a 16-bit signed integer //----------------------------------------------------------------------------- bool Manager::GetValueAsShort(ValueID const& _id, int16* o_value) { bool res = false; if (o_value) { if (ValueID::ValueType_Short == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueShort* value = static_cast(driver->GetValue(_id))) { *o_value = value->GetValue(); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsShort"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetValueAsShort is not a Short Value"); } } return res; } //----------------------------------------------------------------------------- // // Creates a string representation of the value, regardless of type //----------------------------------------------------------------------------- bool Manager::GetValueAsString(ValueID const& _id, string* o_value) { bool res = false; char str[256] = { 0 }; if (o_value) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); switch (_id.GetType()) { case ValueID::ValueType_BitSet: { if (Internal::VC::ValueBitSet* value = static_cast(driver->GetValue(_id))) { *o_value = value->GetAsString(); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsString"); } break; } case ValueID::ValueType_Bool: { if (Internal::VC::ValueBool* value = static_cast(driver->GetValue(_id))) { *o_value = value->GetValue() ? "True" : "False"; value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsString"); } break; } case ValueID::ValueType_Byte: { if (Internal::VC::ValueByte* value = static_cast(driver->GetValue(_id))) { snprintf(str, sizeof(str), "%u", value->GetValue()); *o_value = str; value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsString"); } break; } case ValueID::ValueType_Decimal: { if (Internal::VC::ValueDecimal* value = static_cast(driver->GetValue(_id))) { *o_value = value->GetValue(); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsString"); } break; } case ValueID::ValueType_Int: { if (Internal::VC::ValueInt* value = static_cast(driver->GetValue(_id))) { snprintf(str, sizeof(str), "%d", value->GetValue()); *o_value = str; value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsString"); } break; } case ValueID::ValueType_List: { if (Internal::VC::ValueList* value = static_cast(driver->GetValue(_id))) { Internal::VC::ValueList::Item const *item = value->GetItem(); if (item == NULL) { o_value = NULL; res = false; } else { *o_value = item->m_label; res = true; } value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsString"); } break; } case ValueID::ValueType_Raw: { if (Internal::VC::ValueRaw* value = static_cast(driver->GetValue(_id))) { *o_value = value->GetAsString(); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsString"); } break; } case ValueID::ValueType_Short: { if (Internal::VC::ValueShort* value = static_cast(driver->GetValue(_id))) { snprintf(str, sizeof(str), "%d", value->GetValue()); *o_value = str; value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsString"); } break; } case ValueID::ValueType_String: { if (Internal::VC::ValueString* value = static_cast(driver->GetValue(_id))) { *o_value = value->GetValue(); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsString"); } break; } case ValueID::ValueType_Button: { if (Internal::VC::ValueButton* value = static_cast(driver->GetValue(_id))) { *o_value = value->IsPressed() ? "True" : "False"; value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsString"); } break; } case ValueID::ValueType_Schedule: { if (Internal::VC::ValueSchedule* value = static_cast(driver->GetValue(_id))) { *o_value = value->GetAsString(); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueAsString"); } break; } } } } return res; } //----------------------------------------------------------------------------- // // Gets the selected item from a list value (returning a string) //----------------------------------------------------------------------------- bool Manager::GetValueListSelection(ValueID const& _id, string* o_value) { bool res = false; if (o_value) { if (ValueID::ValueType_List == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueList* value = static_cast(driver->GetValue(_id))) { Internal::VC::ValueList::Item const *item = value->GetItem(); if (item != NULL && item->m_label.length() > 0) { *o_value = item->m_label; res = true; } else { o_value = NULL; Log::Write(LogLevel_Warning, "ValueList returned a NULL value for GetValueListSelection: %s", value->GetLabel().c_str()); } value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueListSelection"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetValueListSelection is not a List Value"); } } return res; } //----------------------------------------------------------------------------- // // Gets the selected item from a list value (returning the index) //----------------------------------------------------------------------------- bool Manager::GetValueListSelection(ValueID const& _id, int32* o_value) { bool res = false; if (o_value) { if (ValueID::ValueType_List == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueList* value = static_cast(driver->GetValue(_id))) { Internal::VC::ValueList::Item const *item = value->GetItem(); if (item == NULL) { res = false; } else { *o_value = item->m_value; res = true; } value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueListSelection"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetValueListSelection is not a List Value"); } } return res; } //----------------------------------------------------------------------------- // // Gets the list of items from a list value //----------------------------------------------------------------------------- bool Manager::GetValueListItems(ValueID const& _id, vector* o_value) { bool res = false; if (o_value) { if (ValueID::ValueType_List == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueList* value = static_cast(driver->GetValue(_id))) { o_value->clear(); res = value->GetItemLabels(o_value); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueListItems"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetValueListItems is not a List Value"); } } return res; } //----------------------------------------------------------------------------- // // Gets the list of values from a list value //----------------------------------------------------------------------------- bool Manager::GetValueListValues(ValueID const& _id, vector* o_value) { bool res = false; if (o_value) { if (ValueID::ValueType_List == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueList* value = static_cast(driver->GetValue(_id))) { o_value->clear(); res = value->GetItemValues(o_value); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueListValues"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetValueListValues is not a List Value"); } } return res; } //----------------------------------------------------------------------------- // // Gets a value's scale as a uint8 //----------------------------------------------------------------------------- bool Manager::GetValueFloatPrecision(ValueID const& _id, uint8* o_value) { bool res = false; if (o_value) { if (ValueID::ValueType_Decimal == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueDecimal* value = static_cast(driver->GetValue(_id))) { *o_value = value->GetPrecision(); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueFloatPrecision"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetValueFloatPrecision is not a Decimal Value"); } } return res; } //----------------------------------------------------------------------------- // // Sets a bit in a BitSet Value //----------------------------------------------------------------------------- bool Manager::SetValue(ValueID const& _id, uint8 _pos, bool const _value) { bool res = false; if (ValueID::ValueType_BitSet == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { if (_id.GetNodeId() != driver->GetControllerNodeId()) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueBitSet* value = static_cast(driver->GetValue(_id))) { if (_value) res = value->SetBit(_pos); else res = value->ClearBit(_pos); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to SetValue is not a BitSet Value"); } return res; } //----------------------------------------------------------------------------- // // Sets the value from a bool //----------------------------------------------------------------------------- bool Manager::SetValue(ValueID const& _id, bool const _value) { bool res = false; if (ValueID::ValueType_Bool == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { if (_id.GetNodeId() != driver->GetControllerNodeId()) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueBool* value = static_cast(driver->GetValue(_id))) { res = value->Set(_value); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to SetValue is not a bool Value"); } return res; } //----------------------------------------------------------------------------- // // Sets the value from a byte //----------------------------------------------------------------------------- bool Manager::SetValue(ValueID const& _id, uint8 const _value) { bool res = false; if (ValueID::ValueType_Byte == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { if (_id.GetNodeId() != driver->GetControllerNodeId()) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueByte* value = static_cast(driver->GetValue(_id))) { res = value->Set(_value); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } } } } else if (ValueID::ValueType_BitSet == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { if (_id.GetNodeId() != driver->GetControllerNodeId()) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueBitSet* value = static_cast(driver->GetValue(_id))) { if (value->GetSize() == 1) { res = value->Set(_value); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "BitSet ValueID is Not of Size 1 (SetValue uint8)"); } } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to SetValue is not a Byte Value"); } return res; } //----------------------------------------------------------------------------- // // Sets the value from a floating point number //----------------------------------------------------------------------------- bool Manager::SetValue(ValueID const& _id, float const _value) { bool res = false; if (ValueID::ValueType_Decimal == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { if (_id.GetNodeId() != driver->GetControllerNodeId()) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueDecimal* value = static_cast(driver->GetValue(_id))) { char str[256]; snprintf(str, sizeof(str), "%f", _value); // remove trailing zeros (and the decimal point, if present) // TODO: better way of figuring out which locale is being used ('.' or ',' to separate decimals) size_t nLen; if ((strchr(str, '.') != NULL) || (strchr(str, ',') != NULL)) { for (nLen = strlen(str) - 1; nLen > 0; nLen--) { if (str[nLen] == '0') str[nLen] = 0; else break; } if ((str[nLen] == '.') || (str[nLen] == ',')) str[nLen] = 0; } // now set the value res = value->Set(str); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to SetValue is not a Decimal Value"); } return res; } //----------------------------------------------------------------------------- // // Sets the value from a 32-bit signed integer //----------------------------------------------------------------------------- bool Manager::SetValue(ValueID const& _id, int32 const _value) { bool res = false; if (ValueID::ValueType_Int == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { if (_id.GetNodeId() != driver->GetControllerNodeId()) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueInt* value = static_cast(driver->GetValue(_id))) { res = value->Set(_value); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } } } } else if (ValueID::ValueType_BitSet == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { if (_id.GetNodeId() != driver->GetControllerNodeId()) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueBitSet* value = static_cast(driver->GetValue(_id))) { if (value->GetSize() == 4) { res = value->Set(_value); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "BitSet ValueID is Not of Size 4 (SetValue uint32)"); } } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to SetValue is not a Int Value"); } return res; } //----------------------------------------------------------------------------- // // Sets the value from a collection of bytes //----------------------------------------------------------------------------- bool Manager::SetValue(ValueID const& _id, uint8 const* _value, uint8 const _length) { bool res = false; if (ValueID::ValueType_Raw == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { if (_id.GetNodeId() != driver->GetControllerNodeId()) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueRaw* value = static_cast(driver->GetValue(_id))) { res = value->Set(_value, _length); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to SetValue is not a Raw Value"); } return res; } //----------------------------------------------------------------------------- // // Sets the value from a 16-bit signed integer //----------------------------------------------------------------------------- bool Manager::SetValue(ValueID const& _id, int16 const _value) { bool res = false; if (ValueID::ValueType_Short == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { if (_id.GetNodeId() != driver->GetControllerNodeId()) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueShort* value = static_cast(driver->GetValue(_id))) { res = value->Set(_value); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } } } } else if (ValueID::ValueType_BitSet == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { if (_id.GetNodeId() != driver->GetControllerNodeId()) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueBitSet* value = static_cast(driver->GetValue(_id))) { if (value->GetSize() == 2) { res = value->Set(_value); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "BitSet ValueID is Not of Size 2 (SetValue uint16)"); } } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to SetValue is not a Short Value"); } return res; } //----------------------------------------------------------------------------- // // Sets the selected item in a list by value //----------------------------------------------------------------------------- bool Manager::SetValueListSelection(ValueID const& _id, string const& _selectedItem) { bool res = false; if (ValueID::ValueType_List == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { if (_id.GetNodeId() != driver->GetControllerNodeId()) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueList* value = static_cast(driver->GetValue(_id))) { res = value->SetByLabel(_selectedItem); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValueListSelection"); } } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to SetValueListSelection is not a List Value"); } return res; } //----------------------------------------------------------------------------- // // Sets the value from a string //----------------------------------------------------------------------------- bool Manager::SetValue(ValueID const& _id, string const& _value) { bool res = false; if (Driver* driver = GetDriver(_id.GetHomeId())) { if (_id.GetNodeId() != driver->GetControllerNodeId()) { Internal::LockGuard LG(driver->m_nodeMutex); switch (_id.GetType()) { case ValueID::ValueType_BitSet: { if (Internal::VC::ValueBitSet* value = static_cast(driver->GetValue(_id))) { res = value->SetFromString(_value); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } break; } case ValueID::ValueType_Bool: { if (Internal::VC::ValueBool* value = static_cast(driver->GetValue(_id))) { if (!strcasecmp("true", _value.c_str())) { res = value->Set(true); } else if (!strcasecmp("false", _value.c_str())) { res = value->Set(false); } value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } break; } case ValueID::ValueType_Byte: { if (Internal::VC::ValueByte* value = static_cast(driver->GetValue(_id))) { uint32 val = (uint32) atoi(_value.c_str()); if (val < 256) { res = value->Set((uint8) val); } value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } break; } case ValueID::ValueType_Decimal: { if (Internal::VC::ValueDecimal* value = static_cast(driver->GetValue(_id))) { res = value->Set(_value); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } break; } case ValueID::ValueType_Int: { if (Internal::VC::ValueInt* value = static_cast(driver->GetValue(_id))) { int32 val = atoi(_value.c_str()); res = value->Set(val); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } break; } case ValueID::ValueType_List: { if (Internal::VC::ValueList* value = static_cast(driver->GetValue(_id))) { res = value->SetByLabel(_value); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } break; } case ValueID::ValueType_Short: { if (Internal::VC::ValueShort* value = static_cast(driver->GetValue(_id))) { int32 val = (uint32) atoi(_value.c_str()); if ((val < 32768) && (val >= -32768)) { res = value->Set((int16) val); } value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } break; } case ValueID::ValueType_String: { if (Internal::VC::ValueString* value = static_cast(driver->GetValue(_id))) { res = value->Set(_value); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } break; } case ValueID::ValueType_Raw: { if (Internal::VC::ValueRaw* value = static_cast(driver->GetValue(_id))) { res = value->SetFromString(_value); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetValue"); } break; } case ValueID::ValueType_Schedule: case ValueID::ValueType_Button: { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "ValueID passed to SetValue cannot be set on Schedule or Button"); break; } } } } return res; } //----------------------------------------------------------------------------- // // Instruct the driver to refresh this value by sending a message to the device //----------------------------------------------------------------------------- bool Manager::RefreshValue(ValueID const& _id) { bool bRet = false; // return value if (Driver* driver = GetDriver(_id.GetHomeId())) { Node *node; // Need to lock and unlock nodes to check this information Internal::LockGuard LG(driver->m_nodeMutex); if ((node = driver->GetNode(_id.GetNodeId())) != NULL) { Internal::CC::CommandClass* cc = node->GetCommandClass(_id.GetCommandClassId()); if (cc) { uint16_t index = _id.GetIndex(); uint8 instance = _id.GetInstance(); Log::Write(LogLevel_Info, "mgr, Refreshing node %d: %s index = %d instance = %d (to confirm a reported change)", node->m_nodeId, cc->GetCommandClassName().c_str(), index, instance); cc->RequestValue(0, index, instance, Driver::MsgQueue_Send); bRet = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to RefreshValue"); bRet = false; } } } return bRet; } //----------------------------------------------------------------------------- // // Set the verify changes flag for the specified value //----------------------------------------------------------------------------- void Manager::SetChangeVerified(ValueID const& _id, bool _verify) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::Value* value = driver->GetValue(_id)) { value->SetChangeVerified(_verify); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetChangeVerified"); } } } //----------------------------------------------------------------------------- // // Get the verify changes flag for the specified value //----------------------------------------------------------------------------- bool Manager::GetChangeVerified(ValueID const& _id) { bool res = false; if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::Value* value = driver->GetValue(_id)) { res = value->GetChangeVerified(); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetChangeVerified"); } } return res; } //----------------------------------------------------------------------------- // // Starts an activity in a device. //----------------------------------------------------------------------------- bool Manager::PressButton(ValueID const& _id) { bool res = false; if (ValueID::ValueType_Button == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueButton* value = static_cast(driver->GetValue(_id))) { res = value->PressButton(); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to PressButton"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to PressButton is not a Button Value"); } return res; } //----------------------------------------------------------------------------- // // Stops an activity in a device. //----------------------------------------------------------------------------- bool Manager::ReleaseButton(ValueID const& _id) { bool res = false; if (ValueID::ValueType_Button == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueButton* value = static_cast(driver->GetValue(_id))) { res = value->ReleaseButton(); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to ReleaseButton"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to ReleaseButton is not a Button Value"); } return res; } //----------------------------------------------------------------------------- // // Sets a BitMask on a BitSet ValueID //----------------------------------------------------------------------------- bool Manager::SetBitMask(ValueID const& _id, uint32 _mask) { bool res = false; if (ValueID::ValueType_BitSet == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueBitSet* value = static_cast(driver->GetValue(_id))) { res = value->SetBitMask(_mask); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetBitMask"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to SetBitMask is not a BitSet Value"); } return res; } //----------------------------------------------------------------------------- // // Gets a BitMask on a BitSet ValueID //----------------------------------------------------------------------------- bool Manager::GetBitMask(ValueID const& _id, int32* o_mask) { bool res = false; if (o_mask) { if (ValueID::ValueType_BitSet == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueBitSet* value = static_cast(driver->GetValue(_id))) { *o_mask = value->GetBitMask(); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetBitMask"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetBitMask is not a BitSet Value"); } } return res; } //----------------------------------------------------------------------------- // m_nodeMutex); if (Internal::VC::ValueBitSet* value = static_cast(driver->GetValue(_id))) { *o_size = value->GetSize(); value->Release(); res = true; } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetBitSetSize"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetBitSetSize is not a BitSet Value"); } } return res; } //----------------------------------------------------------------------------- // Climate Control Schedules //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Get the number of switch points defined in a schedule //----------------------------------------------------------------------------- uint8 Manager::GetNumSwitchPoints(ValueID const& _id) { // bool res = false; uint8 numSwitchPoints = 0; if (ValueID::ValueType_Schedule == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueSchedule* value = static_cast(driver->GetValue(_id))) { numSwitchPoints = value->GetNumSwitchPoints(); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetNumSwitchPoints"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetNumSwitchPoints is not a Schedule Value"); } return numSwitchPoints; } //----------------------------------------------------------------------------- // // Set a switch point in the schedule //----------------------------------------------------------------------------- bool Manager::SetSwitchPoint(ValueID const& _id, uint8 const _hours, uint8 const _minutes, int8 const _setback) { bool res = false; if (ValueID::ValueType_Schedule == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueSchedule* value = static_cast(driver->GetValue(_id))) { res = value->SetSwitchPoint(_hours, _minutes, _setback); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to SetSwitchPoint"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to SetSwitchPoint is not a Schedule Value"); } return res; } //----------------------------------------------------------------------------- // // Remove a switch point from the schedule //----------------------------------------------------------------------------- bool Manager::RemoveSwitchPoint(ValueID const& _id, uint8 const _hours, uint8 const _minutes) { bool res = false; if (ValueID::ValueType_Schedule == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueSchedule* value = static_cast(driver->GetValue(_id))) { uint8 idx; res = value->FindSwitchPoint(_hours, _minutes, &idx); if (res) { res = value->RemoveSwitchPoint(idx); } value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to RemoveSwitchPoint"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to RemoveSwitchPoint is not a Schedule Value"); } return res; } //----------------------------------------------------------------------------- // // Clears all switch points from the schedule //----------------------------------------------------------------------------- void Manager::ClearSwitchPoints(ValueID const& _id) { if (ValueID::ValueType_Schedule == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueSchedule* value = static_cast(driver->GetValue(_id))) { value->ClearSwitchPoints(); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to ClearSwitchPoints"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to ClearSwitchPoints is not a Schedule Value"); } } //----------------------------------------------------------------------------- // // Gets switch point data from the schedule //----------------------------------------------------------------------------- bool Manager::GetSwitchPoint(ValueID const& _id, uint8 const _idx, uint8* o_hours, uint8* o_minutes, int8* o_setback) { bool res = false; if (ValueID::ValueType_Schedule == _id.GetType()) { if (Driver* driver = GetDriver(_id.GetHomeId())) { Internal::LockGuard LG(driver->m_nodeMutex); if (Internal::VC::ValueSchedule* value = static_cast(driver->GetValue(_id))) { res = value->GetSwitchPoint(_idx, o_hours, o_minutes, o_setback); value->Release(); } else { OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetSwitchPoint"); } } } else { OZW_ERROR(OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID, "ValueID passed to GetSwitchPoint is not a Schedule Value"); } return res; } //----------------------------------------------------------------------------- // SwitchAll //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // All devices that support the SwitchAll command class will be turned on //----------------------------------------------------------------------------- void Manager::SwitchAllOn(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->SwitchAllOn(); } } //----------------------------------------------------------------------------- // // All devices that support the SwitchAll command class will be turned off //----------------------------------------------------------------------------- void Manager::SwitchAllOff(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->SwitchAllOff(); } } //----------------------------------------------------------------------------- // Configuration Parameters //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Set the value of one of the configuration parameters of a device //----------------------------------------------------------------------------- bool Manager::SetConfigParam(uint32 const _homeId, uint8 const _nodeId, uint8 const _param, int32 _value, uint8 const _size) { if (Driver* driver = GetDriver(_homeId)) { return driver->SetConfigParam(_nodeId, _param, _value, _size); } return false; } //----------------------------------------------------------------------------- // // Request the value of one of the configuration parameters of a device //----------------------------------------------------------------------------- void Manager::RequestConfigParam(uint32 const _homeId, uint8 const _nodeId, uint8 const _param) { if (Driver* driver = GetDriver(_homeId)) { driver->RequestConfigParam(_nodeId, _param); } } //----------------------------------------------------------------------------- // // Request the values of all of the known configuration parameters of a device //----------------------------------------------------------------------------- void Manager::RequestAllConfigParams(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); Node* node = driver->GetNode(_nodeId); if (node) { node->SetQueryStage(Node::QueryStage_Configuration); } } } //----------------------------------------------------------------------------- // Groups //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Gets the number of association groups reported by this node //----------------------------------------------------------------------------- uint8 Manager::GetNumGroups(uint32 const _homeId, uint8 const _nodeId) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetNumGroups(_nodeId); } return 0; } //----------------------------------------------------------------------------- // // Gets the associations for a group //----------------------------------------------------------------------------- uint32 Manager::GetAssociations(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx, uint8** o_associations) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetAssociations(_nodeId, _groupIdx, o_associations); } return 0; } //----------------------------------------------------------------------------- // // Gets the associations for a group // struct InstanceAssociation is defined in Group.h and contains // a (NodeID, End Point) pair. //----------------------------------------------------------------------------- uint32 Manager::GetAssociations(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx, InstanceAssociation** o_associations) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetAssociations(_nodeId, _groupIdx, o_associations); } return 0; } //----------------------------------------------------------------------------- // // Gets the maximum number of associations for a group //----------------------------------------------------------------------------- uint8 Manager::GetMaxAssociations(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetMaxAssociations(_nodeId, _groupIdx); } return 0; } //----------------------------------------------------------------------------- // // Returns true is group supports multi instance. //----------------------------------------------------------------------------- bool Manager::IsMultiInstance(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx) { if (Driver* driver = GetDriver(_homeId)) { return driver->IsMultiInstance(_nodeId, _groupIdx); } return 0; } //----------------------------------------------------------------------------- // // Gets the label for a particular group //----------------------------------------------------------------------------- string Manager::GetGroupLabel(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetGroupLabel(_nodeId, _groupIdx); } return ""; } //----------------------------------------------------------------------------- // // Adds a node to an association group //----------------------------------------------------------------------------- void Manager::AddAssociation(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx, uint8 const _targetNodeId, uint8 const _endPoint) { if (Driver* driver = GetDriver(_homeId)) { driver->AddAssociation(_nodeId, _groupIdx, _targetNodeId, _endPoint); } } //----------------------------------------------------------------------------- // // Removes a node from an association group //----------------------------------------------------------------------------- void Manager::RemoveAssociation(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx, uint8 const _targetNodeId, uint8 const _endPoint) { if (Driver* driver = GetDriver(_homeId)) { driver->RemoveAssociation(_nodeId, _groupIdx, _targetNodeId, _endPoint); } } //----------------------------------------------------------------------------- // Notifications //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Add a watcher to the list //----------------------------------------------------------------------------- bool Manager::AddWatcher(pfnOnNotification_t _watcher, void* _context) { // Ensure this watcher is not already on the list m_notificationMutex->Lock(); for (list::iterator it = m_watchers.begin(); it != m_watchers.end(); ++it) { if (((*it)->m_callback == _watcher) && ((*it)->m_context == _context)) { // Already in the list m_notificationMutex->Unlock(); return false; } } m_watchers.push_back(new Watcher(_watcher, _context)); m_notificationMutex->Unlock(); return true; } //----------------------------------------------------------------------------- // // Remove a watcher from the list //----------------------------------------------------------------------------- bool Manager::RemoveWatcher(pfnOnNotification_t _watcher, void* _context) { m_notificationMutex->Lock(); list::iterator it = m_watchers.begin(); while (it != m_watchers.end()) { if (((*it)->m_callback == _watcher) && ((*it)->m_context == _context)) { delete (*it); list::iterator next = m_watchers.erase(it); for (list::iterator*>::iterator extIt = m_watcherIterators.begin(); extIt != m_watcherIterators.end(); ++extIt) { if ((**extIt) == it) { (**extIt) = next; } } m_notificationMutex->Unlock(); return true; } ++it; } m_notificationMutex->Unlock(); return false; } //----------------------------------------------------------------------------- // // Notify any watching objects of a value change //----------------------------------------------------------------------------- void Manager::NotifyWatchers(Notification* _notification) { m_notificationMutex->Lock(); list::iterator it = m_watchers.begin(); m_watcherIterators.push_back(&it); while (it != m_watchers.end()) { Watcher* pWatcher = *(it++); pWatcher->m_callback(_notification, pWatcher->m_context); } m_watcherIterators.pop_back(); m_notificationMutex->Unlock(); } //----------------------------------------------------------------------------- // Controller commands //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Reset controller and erase all node information //----------------------------------------------------------------------------- void Manager::ResetController(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { Internal::Platform::Event *event = new Internal::Platform::Event(); driver->ResetController(event); Internal::Platform::Wait::Single(event); event->Release(); string path = driver->GetControllerPath(); Driver::ControllerInterface intf = driver->GetControllerInterfaceType(); RemoveDriver(path); AddDriver(path, intf); Internal::Platform::Wait::Multiple( NULL, 0, 500); } OPENZWAVE_DEPRECATED_WARNINGS_OFF; RemoveAllScenes(_homeId); OPENZWAVE_DEPRECATED_WARNINGS_ON; } //----------------------------------------------------------------------------- // // Soft-reset the Z-Wave controller chip //----------------------------------------------------------------------------- void Manager::SoftReset(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { driver->SoftReset(); } } //----------------------------------------------------------------------------- // // Start the controller performing one of its network management functions //----------------------------------------------------------------------------- bool Manager::BeginControllerCommand(uint32 const _homeId, Driver::ControllerCommand _command, Driver::pfnControllerCallback_t _callback, // = NULL void* _context, // = NULL bool _highPower, // = false uint8 _nodeId, // = 0xff uint8 _arg // = 0 ) { if (Driver* driver = GetDriver(_homeId)) { return driver->BeginControllerCommand(_command, _callback, _context, _highPower, _nodeId, _arg); } return false; } //----------------------------------------------------------------------------- // // Stop the current controller function //----------------------------------------------------------------------------- bool Manager::CancelControllerCommand(uint32 const _homeId) { if (Driver* driver = GetDriver(_homeId)) { return (driver->CancelControllerCommand()); } return false; } //----------------------------------------------------------------------------- // // Send a number of test messages to a node and record results. //----------------------------------------------------------------------------- void Manager::TestNetworkNode(uint32 const _homeId, uint8 const _nodeId, uint32 const _count) { if (Driver* driver = GetDriver(_homeId)) { driver->TestNetwork(_nodeId, _count); } } //----------------------------------------------------------------------------- // // Send a number of test messages to every node and record results. //----------------------------------------------------------------------------- void Manager::TestNetwork(uint32 const _homeId, uint32 const _count) { if (Driver* driver = GetDriver(_homeId)) { driver->TestNetwork(0, _count); } } //----------------------------------------------------------------------------- // // Heal a single node in the network //----------------------------------------------------------------------------- void Manager::HealNetworkNode(uint32 const _homeId, uint8 const _nodeId, bool _doRR) { if (Driver* driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); Node* node = driver->GetNode(_nodeId); if (node) { driver->BeginControllerCommand(Driver::ControllerCommand_RequestNodeNeighborUpdate, NULL, NULL, true, _nodeId, 0); if (_doRR) { driver->UpdateNodeRoutes(_nodeId, true); } } } } //----------------------------------------------------------------------------- // // Heal the Z-Wave network one node at a time. //----------------------------------------------------------------------------- void Manager::HealNetwork(uint32 const _homeId, bool _doRR) { if (Driver* driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); for (uint8 i = 0; i < 255; i++) { if (driver->m_nodes[i] != NULL) { driver->BeginControllerCommand(Driver::ControllerCommand_RequestNodeNeighborUpdate, NULL, NULL, true, i, 0); if (_doRR) { driver->UpdateNodeRoutes(i, true); } } } } } //----------------------------------------------------------------------------- // // Add a Device to the Network. //----------------------------------------------------------------------------- bool Manager::AddNode(uint32 const _homeId, bool _doSecurity) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); /* we use the Args option to communicate if Security CC should be initialized */ return driver->BeginControllerCommand(Driver::ControllerCommand_AddDevice, NULL, NULL, true, 0, (_doSecurity == true ? 1 : 0)); } return false; } //----------------------------------------------------------------------------- // // Remove a Device from the Network. //----------------------------------------------------------------------------- bool Manager::RemoveNode(uint32 const _homeId) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); return driver->BeginControllerCommand(Driver::ControllerCommand_RemoveDevice, NULL, NULL, true, 0, 0); } return false; } //----------------------------------------------------------------------------- // // Remove a Specific Device from the network if its non-responsive. //----------------------------------------------------------------------------- bool Manager::RemoveFailedNode(uint32 const _homeId, uint8 const _nodeId) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); return driver->BeginControllerCommand(Driver::ControllerCommand_RemoveFailedNode, NULL, NULL, true, _nodeId, 0); } return false; } //----------------------------------------------------------------------------- // // Test if the Controller Believes the Node has Failed. //----------------------------------------------------------------------------- bool Manager::HasNodeFailed(uint32 const _homeId, uint8 const _nodeId) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); return driver->BeginControllerCommand(Driver::ControllerCommand_HasNodeFailed, NULL, NULL, true, _nodeId, 0); } return false; } //----------------------------------------------------------------------------- // // Ask a Node to update its Return Route to the Controller //----------------------------------------------------------------------------- bool Manager::AssignReturnRoute(uint32 const _homeId, uint8 const _nodeId) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); return driver->BeginControllerCommand(Driver::ControllerCommand_AssignReturnRoute, NULL, NULL, true, _nodeId, 0); } return false; } //----------------------------------------------------------------------------- // // Ask a Node to update its Neighbor Table. //----------------------------------------------------------------------------- bool Manager::RequestNodeNeighborUpdate(uint32 const _homeId, uint8 const _nodeId) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); return driver->BeginControllerCommand(Driver::ControllerCommand_RequestNodeNeighborUpdate, NULL, NULL, true, _nodeId, 0); } return false; } //----------------------------------------------------------------------------- // // Ask a Node to delete all its Return Routes //----------------------------------------------------------------------------- bool Manager::DeleteAllReturnRoutes(uint32 const _homeId, uint8 const _nodeId) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); return driver->BeginControllerCommand(Driver::ControllerCommand_DeleteAllReturnRoutes, NULL, NULL, true, _nodeId, 0); } return false; } //----------------------------------------------------------------------------- // // Send a NIF frame from the Controller to the Node //----------------------------------------------------------------------------- bool Manager::SendNodeInformation(uint32 const _homeId, uint8 const _nodeId) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); return driver->BeginControllerCommand(Driver::ControllerCommand_SendNodeInformation, NULL, NULL, true, _nodeId, 0); } return false; } //----------------------------------------------------------------------------- // // Send a NIF frame from the Controller to the Node //----------------------------------------------------------------------------- bool Manager::CreateNewPrimary(uint32 const _homeId) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); return driver->BeginControllerCommand(Driver::ControllerCommand_CreateNewPrimary, NULL, NULL, true, 0, 0); } return false; } //----------------------------------------------------------------------------- // // Send a NIF frame from the Controller to the Node //----------------------------------------------------------------------------- bool Manager::ReceiveConfiguration(uint32 const _homeId) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); return driver->BeginControllerCommand(Driver::ControllerCommand_ReceiveConfiguration, NULL, NULL, true, 0, 0); } return false; } //----------------------------------------------------------------------------- // // Send a NIF frame from the Controller to the Node //----------------------------------------------------------------------------- bool Manager::ReplaceFailedNode(uint32 const _homeId, uint8 const _nodeId) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); return driver->BeginControllerCommand(Driver::ControllerCommand_ReplaceFailedNode, NULL, NULL, true, _nodeId, 0); } return false; } //----------------------------------------------------------------------------- // // Send a NIF frame from the Controller to the Node //----------------------------------------------------------------------------- bool Manager::TransferPrimaryRole(uint32 const _homeId) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); return driver->BeginControllerCommand(Driver::ControllerCommand_TransferPrimaryRole, NULL, NULL, true, 0, 0); } return false; } //----------------------------------------------------------------------------- // // Send a NIF frame from the Controller to the Node //----------------------------------------------------------------------------- bool Manager::RequestNetworkUpdate(uint32 const _homeId, uint8 const _nodeId) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); return driver->BeginControllerCommand(Driver::ControllerCommand_RequestNetworkUpdate, NULL, NULL, true, _nodeId, 0); } return false; } //----------------------------------------------------------------------------- // // Send a NIF frame from the Controller to the Node //----------------------------------------------------------------------------- bool Manager::ReplicationSend(uint32 const _homeId, uint8 const _nodeId) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); return driver->BeginControllerCommand(Driver::ControllerCommand_ReplicationSend, NULL, NULL, true, _nodeId, 0); } return false; } //----------------------------------------------------------------------------- // // Send a NIF frame from the Controller to the Node //----------------------------------------------------------------------------- bool Manager::CreateButton(uint32 const _homeId, uint8 const _nodeId, uint8 const _buttonid) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); return driver->BeginControllerCommand(Driver::ControllerCommand_CreateButton, NULL, NULL, true, _nodeId, _buttonid); } return false; } //----------------------------------------------------------------------------- // // Send a NIF frame from the Controller to the Node //----------------------------------------------------------------------------- bool Manager::DeleteButton(uint32 const _homeId, uint8 const _nodeId, uint8 const _buttonid) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); return driver->BeginControllerCommand(Driver::ControllerCommand_DeleteButton, NULL, NULL, true, _nodeId, _buttonid); } return false; } //----------------------------------------------------------------------------- // // Send a custom message to a node. // XXX TODO - Move the implementation to the Driver Class //----------------------------------------------------------------------------- void Manager::SendRawData(uint32 const _homeId, uint8 const _nodeId, string const& _logText, uint8 const _msgType, bool const _sendSecure, uint8 const* _content, uint8 const _length) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); Node* node = driver->GetNode(_nodeId); if (node) { Internal::Msg* msg = new Internal::Msg(_logText, _nodeId, _msgType, FUNC_ID_ZW_SEND_DATA, true); for (uint8 i = 0; i < _length; i++) { msg->Append(_content[i]); } msg->Append(driver->GetTransmitOptions()); if (_sendSecure) { msg->setEncrypted(); } driver->SendMsg(msg, Driver::MsgQueue_Send); } } } //----------------------------------------------------------------------------- // // Return the number of defined scenes. //----------------------------------------------------------------------------- uint8 Manager::GetNumScenes() { return Internal::Scene::s_sceneCnt; } //----------------------------------------------------------------------------- // // Return an array of all Scene Ids //----------------------------------------------------------------------------- uint8 Manager::GetAllScenes(uint8** _sceneIds) { *_sceneIds = NULL; return Internal::Scene::GetAllScenes(_sceneIds); } //----------------------------------------------------------------------------- // // Remove every scene id //----------------------------------------------------------------------------- void Manager::RemoveAllScenes(uint32 const _homeId) { for (int i = 1; i < 256; i++) { if (_homeId == 0) // remove every device from every scene { OPENZWAVE_DEPRECATED_WARNINGS_OFF RemoveScene(i); OPENZWAVE_DEPRECATED_WARNINGS_ON } else { Internal::Scene *scene = Internal::Scene::Get(i); if (scene != NULL) { scene->RemoveValues(_homeId); } } } } //----------------------------------------------------------------------------- // // Create a new scene and return new Scene ID. //----------------------------------------------------------------------------- uint8 Manager::CreateScene() { for (int i = 1; i < 256; i++) { Internal::Scene* scene = Internal::Scene::Get(i); if (scene != NULL) { continue; } new Internal::Scene(i); return i; } return 0; } //----------------------------------------------------------------------------- // // Remove scene and delete its contents //----------------------------------------------------------------------------- bool Manager::RemoveScene(uint8 const _sceneId) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { delete scene; return true; } return false; } //----------------------------------------------------------------------------- // // Add a bool ValueID/value pair to the scene //----------------------------------------------------------------------------- bool Manager::AddSceneValue(uint8 const _sceneId, ValueID const& _valueId, bool const _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { return scene->AddValue(_valueId, _value ? "True" : "False"); } return false; } //----------------------------------------------------------------------------- // // Add a byte ValueID/value pair to the scene //----------------------------------------------------------------------------- bool Manager::AddSceneValue(uint8 const _sceneId, ValueID const& _valueId, uint8 const _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { char str[16]; snprintf(str, sizeof(str), "%d", _value); return scene->AddValue(_valueId, str); } return false; } //----------------------------------------------------------------------------- // // Add a decimal ValueID/value pair to the scene //----------------------------------------------------------------------------- bool Manager::AddSceneValue(uint8 const _sceneId, ValueID const& _valueId, float const _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { char str[16]; snprintf(str, sizeof(str), "%f", _value); return scene->AddValue(_valueId, str); } return false; } //----------------------------------------------------------------------------- // // Add an integer ValueID/value pair to the scene //----------------------------------------------------------------------------- bool Manager::AddSceneValue(uint8 const _sceneId, ValueID const& _valueId, int32 const _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { char str[16]; snprintf(str, sizeof(str), "%d", _value); return scene->AddValue(_valueId, str); } return false; } //----------------------------------------------------------------------------- // // Add a short ValueID/value pair to the scene //----------------------------------------------------------------------------- bool Manager::AddSceneValue(uint8 const _sceneId, ValueID const& _valueId, int16 const _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { char str[16]; snprintf(str, sizeof(str), "%d", _value); return scene->AddValue(_valueId, str); } return false; } //----------------------------------------------------------------------------- // // Add a string ValueID/value pair to the scene //----------------------------------------------------------------------------- bool Manager::AddSceneValue(uint8 const _sceneId, ValueID const& _valueId, string const& _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { return scene->AddValue(_valueId, _value); } return false; } //----------------------------------------------------------------------------- // // Add a list selection item ValueID/value pair to the scene (as string) //----------------------------------------------------------------------------- bool Manager::AddSceneValueListSelection(uint8 const _sceneId, ValueID const& _valueId, string const& _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { return scene->AddValue(_valueId, _value); } return false; } //----------------------------------------------------------------------------- // // Add a list selection item ValueID/value pair to the scene (as integer) //----------------------------------------------------------------------------- bool Manager::AddSceneValueListSelection(uint8 const _sceneId, ValueID const& _valueId, int32 const _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { char str[16]; snprintf(str, sizeof(str), "%d", _value); return scene->AddValue(_valueId, str); } return false; } //----------------------------------------------------------------------------- // // Remove a ValueID/value pair from the scene //----------------------------------------------------------------------------- bool Manager::RemoveSceneValue(uint8 const _sceneId, ValueID const& _valueId) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { return scene->RemoveValue(_valueId); } return false; } //----------------------------------------------------------------------------- // // Return a scene's Value ID //----------------------------------------------------------------------------- int Manager::SceneGetValues(uint8 const _sceneId, vector* o_value) { o_value->clear(); Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { return scene->GetValues(o_value); } return 0; } //----------------------------------------------------------------------------- // // Return a scene's Value ID bool value //----------------------------------------------------------------------------- bool Manager::SceneGetValueAsBool(uint8 const _sceneId, ValueID const& _valueId, bool* o_value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { string str; if (scene->GetValue(_valueId, &str)) { *o_value = !strcasecmp("true", str.c_str()); return true; } } return false; } //----------------------------------------------------------------------------- // // Return a scene's Value ID byte value //----------------------------------------------------------------------------- bool Manager::SceneGetValueAsByte(uint8 const _sceneId, ValueID const& _valueId, uint8* o_value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { string str; if (scene->GetValue(_valueId, &str)) { *o_value = (uint8) atoi(str.c_str()); return true; } } return false; } //----------------------------------------------------------------------------- // // Return a scene's Value ID float value //----------------------------------------------------------------------------- bool Manager::SceneGetValueAsFloat(uint8 const _sceneId, ValueID const& _valueId, float* o_value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { string str; if (scene->GetValue(_valueId, &str)) { *o_value = (float) atof(str.c_str()); return true; } } return false; } //----------------------------------------------------------------------------- // // Return a scene's Value ID integer value //----------------------------------------------------------------------------- bool Manager::SceneGetValueAsInt(uint8 const _sceneId, ValueID const& _valueId, int32* o_value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { string str; if (scene->GetValue(_valueId, &str)) { *o_value = (int32) atoi(str.c_str()); return true; } } return false; } //----------------------------------------------------------------------------- // // Return a scene's Value ID short value //----------------------------------------------------------------------------- bool Manager::SceneGetValueAsShort(uint8 const _sceneId, ValueID const& _valueId, int16* o_value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { string str; if (scene->GetValue(_valueId, &str)) { *o_value = (int16) atoi(str.c_str()); return true; } } return false; } //----------------------------------------------------------------------------- // // Return a scene's Value ID string value //----------------------------------------------------------------------------- bool Manager::SceneGetValueAsString(uint8 const _sceneId, ValueID const& _valueId, string* o_value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { if (scene->GetValue(_valueId, o_value)) { return true; } } return false; } //----------------------------------------------------------------------------- // // Return a scene's Value ID list selection (as string) value //----------------------------------------------------------------------------- bool Manager::SceneGetValueListSelection(uint8 const _sceneId, ValueID const& _valueId, string* o_value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { if (scene->GetValue(_valueId, o_value)) { return true; } } return false; } //----------------------------------------------------------------------------- // // Return a scene's Value ID list selection (as integer) value //----------------------------------------------------------------------------- bool Manager::SceneGetValueListSelection(uint8 const _sceneId, ValueID const& _valueId, int32* o_value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { string str; if (scene->GetValue(_valueId, &str)) { *o_value = (int32) atoi(str.c_str()); return true; } } return false; } //----------------------------------------------------------------------------- // // Set a scene's ValueID bool value. //----------------------------------------------------------------------------- bool Manager::SetSceneValue(uint8 const _sceneId, ValueID const& _valueId, bool const _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { return scene->SetValue(_valueId, _value ? "True" : "False"); } return false; } //----------------------------------------------------------------------------- // // Set a scene's ValueID byte value. //----------------------------------------------------------------------------- bool Manager::SetSceneValue(uint8 const _sceneId, ValueID const& _valueId, uint8 const _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { char str[16]; snprintf(str, sizeof(str), "%d", _value); return scene->SetValue(_valueId, str); } return false; } //----------------------------------------------------------------------------- // // Set a scene's ValueID float value. //----------------------------------------------------------------------------- bool Manager::SetSceneValue(uint8 const _sceneId, ValueID const& _valueId, float const _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { char str[16]; snprintf(str, sizeof(str), "%f", _value); return scene->SetValue(_valueId, str); } return false; } //----------------------------------------------------------------------------- // // Set a scene's ValueID integer value. //----------------------------------------------------------------------------- bool Manager::SetSceneValue(uint8 const _sceneId, ValueID const& _valueId, int32 const _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { char str[16]; snprintf(str, sizeof(str), "%d", _value); return scene->SetValue(_valueId, str); } return false; } //----------------------------------------------------------------------------- // // Set a scene's ValueID short value. //----------------------------------------------------------------------------- bool Manager::SetSceneValue(uint8 const _sceneId, ValueID const& _valueId, int16 const _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { char str[16]; snprintf(str, sizeof(str), "%d", _value); return scene->SetValue(_valueId, str); } return false; } //----------------------------------------------------------------------------- // // Set a scene's ValueID string value. //----------------------------------------------------------------------------- bool Manager::SetSceneValue(uint8 const _sceneId, ValueID const& _valueId, string const& _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { return scene->SetValue(_valueId, _value); } return false; } //----------------------------------------------------------------------------- // // Set a scene's ValueID list item value (as string). //----------------------------------------------------------------------------- bool Manager::SetSceneValueListSelection(uint8 const _sceneId, ValueID const& _valueId, string const& _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { return scene->SetValue(_valueId, _value); } return false; } //----------------------------------------------------------------------------- // // Set a scene's ValueID list item value (as integer). //----------------------------------------------------------------------------- bool Manager::SetSceneValueListSelection(uint8 const _sceneId, ValueID const& _valueId, int32 const _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { char str[16]; snprintf(str, sizeof(str), "%d", _value); return scene->SetValue(_valueId, str); } return false; } //----------------------------------------------------------------------------- // // Return a scene's label //----------------------------------------------------------------------------- string Manager::GetSceneLabel(uint8 const _sceneId) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { return scene->GetLabel(); } return NULL; } //----------------------------------------------------------------------------- // // Set a scene's label //----------------------------------------------------------------------------- void Manager::SetSceneLabel(uint8 const _sceneId, string const& _value) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { scene->SetLabel(_value); } } //----------------------------------------------------------------------------- // // Check if a Scene ID exists //----------------------------------------------------------------------------- bool Manager::SceneExists(uint8 const _sceneId) { return Internal::Scene::Get(_sceneId) != NULL; } //----------------------------------------------------------------------------- // // Perform all the settings for the given Scene ID //----------------------------------------------------------------------------- bool Manager::ActivateScene(uint8 const _sceneId) { Internal::Scene *scene = Internal::Scene::Get(_sceneId); if (scene != NULL) { return scene->Activate(); } return false; } //----------------------------------------------------------------------------- // // Retrieve driver based counters. //----------------------------------------------------------------------------- void Manager::GetDriverStatistics(uint32 const _homeId, Driver::DriverData* _data) { if (Driver* driver = GetDriver(_homeId)) { driver->GetDriverStatistics(_data); } } //----------------------------------------------------------------------------- // // Retrieve driver based counters. //----------------------------------------------------------------------------- void Manager::GetNodeStatistics(uint32 const _homeId, uint8 const _nodeId, Node::NodeData* _data) { if (Driver* driver = GetDriver(_homeId)) { driver->GetNodeStatistics(_nodeId, _data); } } //----------------------------------------------------------------------------- // // Convert the RouteScheme to a String //----------------------------------------------------------------------------- string Manager::GetNodeRouteScheme(Node::NodeData *_data) { switch (_data->m_routeScheme) { case ROUTINGSCHEME_IDLE: return "Idle"; case ROUTINGSCHEME_DIRECT: return "Direct"; case ROUTINGSCHEME_CACHED_ROUTE_SR: return "Static Route"; case ROUTINGSCHEME_CACHED_ROUTE: return "Last Working Route"; case ROUTINGSCHEME_CACHED_ROUTE_NLWR: return "Next to Last Working Route"; case ROUTINGSCHEME_ROUTE: return "Auto Route"; case ROUTINGSCHEME_RESORT_DIRECT: return "Resort to Direct"; case ROUTINGSCHEME_RESORT_EXPLORE: return "Explorer Route"; } return "Unknown"; } //----------------------------------------------------------------------------- // // Convert the RouteSpeed to a String. //----------------------------------------------------------------------------- string Manager::GetNodeRouteSpeed(Node::NodeData *_data) { switch (_data->m_routeSpeed) { case ROUTE_SPEED_AUTO: return "Auto"; case ROUTE_SPEED_9600: return "9600"; case ROUTE_SPEED_40K: return "40K"; case ROUTE_SPEED_100K: return "100K"; } return "Unknown"; } //----------------------------------------------------------------------------- // // Retrieve MetaData about a Node. //----------------------------------------------------------------------------- string const Manager::GetMetaData(uint32 const _homeId, uint8 const _nodeId, Node::MetaDataFields _metadata) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetMetaData(_nodeId, _metadata); } return ""; } //----------------------------------------------------------------------------- // // Retrieve ChangeLog of a Configuration File about a Node. //----------------------------------------------------------------------------- Node::ChangeLogEntry const Manager::GetChangeLog(uint32 const _homeId, uint8 const _nodeId, uint32_t revision) { if (Driver* driver = GetDriver(_homeId)) { return driver->GetChangeLog(_nodeId, revision); } Node::ChangeLogEntry cle; cle.revision = -1; return cle; } //----------------------------------------------------------------------------- // // get the latest config file revision //----------------------------------------------------------------------------- bool Manager::checkLatestConfigFileRevision(uint32 const _homeId, uint8 const _nodeId) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); Node* node = driver->GetNode(_nodeId); if (node) { return driver->CheckNodeConfigRevision(node); } } return false; } //----------------------------------------------------------------------------- // // get the latest ManufacturerSpecific.xml file revision //----------------------------------------------------------------------------- bool Manager::checkLatestMFSRevision(uint32 const _homeId) { if (Driver *driver = GetDriver(_homeId)) { return driver->CheckMFSConfigRevision(); } return false; } //----------------------------------------------------------------------------- // // Download the latest Config File Revision for a node. //----------------------------------------------------------------------------- bool Manager::downloadLatestConfigFileRevision(uint32 const _homeId, uint8 const _nodeId) { if (Driver *driver = GetDriver(_homeId)) { Internal::LockGuard LG(driver->m_nodeMutex); Node* node = driver->GetNode(_nodeId); if (node) { return driver->downloadConfigRevision(node); } } return false; } //----------------------------------------------------------------------------- // // Download the Latest ManufacturerSpecific Revision //----------------------------------------------------------------------------- bool Manager::downloadLatestMFSRevision(uint32 const _homeId) { if (Driver *driver = GetDriver(_homeId)) { return driver->downloadMFSRevision(); } return false; } openzwave-1.6.1914/cpp/src/Node.h0000644000175200017520000010556614032142455013344 00000000000000//----------------------------------------------------------------------------- // // Node.h // // A node in the Z-Wave network // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Node_H #define _Node_H #include #include #include #include #include "Defs.h" #include "value_classes/ValueID.h" #include "value_classes/ValueList.h" #include "Msg.h" #include "platform/TimeStamp.h" #include "Group.h" class TiXmlElement; class TiXmlNode; namespace OpenZWave { namespace Internal { namespace CC { class CommandClass; class Association; class AssociationCommandConfiguration; class ControllerReplication; class Hail; class ManufacturerSpecific; class MultiChannelAssociation; class MultiInstance; class NodeNaming; class Version; class ZWavePlusInfo; } namespace VC { class Value; class ValueStore; } namespace Platform { class Mutex; } class ProductDescriptor; class ManufacturerSpecificDB; } class Driver; class Group; /** \brief The Node class describes a Z-Wave node object...typically a device on the * Z-Wave network. */ class Node { friend class Manager; friend class Driver; friend class Group; friend class Internal::VC::Value; friend class ValueButton; friend class Internal::CC::Association; friend class Internal::CC::AssociationCommandConfiguration; friend class Internal::CC::CommandClass; friend class Internal::CC::ControllerReplication; friend class Internal::CC::Hail; friend class Internal::CC::ManufacturerSpecific; friend class Internal::CC::MultiInstance; friend class Internal::CC::MultiChannelAssociation; friend class Internal::CC::NodeNaming; friend class Internal::CC::Version; friend class Internal::CC::ZWavePlusInfo; friend class Internal::ManufacturerSpecificDB; //----------------------------------------------------------------------------- // Construction //----------------------------------------------------------------------------- public: /** Constructor initializes the node object, associating it with a specific * network (_homeId) and network node (_nodeId). * \param _homeId The homeId of the network to which this node is connected. * \param _nodeId The nodeId of this node. */ Node(uint32 const _homeId, uint8 const _nodeId); /** Destructor cleans up memory allocated to node and its child objects. */ virtual ~Node(); private: /** Returns a pointer to the driver (interface with a Z-Wave controller) * associated with this node. */ Driver* GetDriver() const; //----------------------------------------------------------------------------- // Initialization //----------------------------------------------------------------------------- public: enum QueryStage { QueryStage_None, /**< Query process hasn't started for this node */ QueryStage_ProtocolInfo, /**< Retrieve protocol information */ QueryStage_Probe, /**< Ping device to see if alive */ QueryStage_WakeUp, /**< Start wake up process if a sleeping node */ QueryStage_NodeInfo, /**< Retrieve info about supported, controlled command classes */ QueryStage_NodePlusInfo, /**< Retrieve ZWave+ info and update device classes */ QueryStage_SecurityReport, /**< Retrieve a list of Command Classes that require Security */ QueryStage_Versions, /**< Retrieve version information */ QueryStage_ManufacturerSpecific1, /**< Retrieve manufacturer name and product ids if ProtocolInfo lets us */ QueryStage_Instances, /**< Retrieve information about multiple command class instances */ QueryStage_ManufacturerSpecific2, /**< Retrieve manufacturer name and product ids */ QueryStage_Static, /**< Retrieve static information (doesn't change) */ QueryStage_CacheLoad, /**< Ping a device upon restarting with cached config for the device */ QueryStage_Probe1 = QueryStage_CacheLoad, /** < Depreciated name. /todo Remove in 2.0 timeframe */ QueryStage_Associations, /**< Retrieve information about associations */ QueryStage_Neighbors, /**< Retrieve node neighbor list */ QueryStage_Session, /**< Retrieve session information (changes infrequently) */ QueryStage_Dynamic, /**< Retrieve dynamic information (changes frequently) */ QueryStage_Configuration, /**< Retrieve configurable parameter information (only done on request) */ QueryStage_Complete /**< Query process is completed for this node */ }; /** * This function advances the query process (see Remarks below for more detail on the * process). It iterates through the various query stages enumerated in Node::QueryStage. * * \remark * For OpenZWave to discover everything about a node, we have to follow a certain * order of queries, because the results of one stage may affect what is requested * in the next stage. The stage is saved with the node data, so that any incomplete * queries can be restarted the next time the application runs. *

* The individual command classes also store some state information as to whether * they have had a response to certain queries. This state information is * initialized by the SetStaticRequests call in QueryStage_None. It is also saved, * so we do not need to request state from every command class if some have previously * responded. */ void AdvanceQueries(); /** * Signal that a specific query stage has been completed for this node. This will * only work if the query process for this node is indeed at the specified stage. * Otherwise, the function returns with no action. * \param _stage The current stage of the query process. */ void QueryStageComplete(QueryStage const _stage); /** * Retry the specified query stage (up to _maxAttempts retries). This will * only work if the query process for this node is indeed at the specified stage. * Otherwise, the function returns with no action. * \param _stage The query stage to retry. * \param _maxAttempts */ void QueryStageRetry(QueryStage const _stage, uint8 const _maxAttempts = 0); // maxAttempts of zero means no limit /** * This function sets the query stage for the node (but only to an earlier stage). * If a later stage is specified than the current one, it is ignored. * \param _stage The desired query stage. * \see m_queryStage, m_queryPending */ void SetQueryStage(QueryStage const _stage, bool const _advance = true); /** * Returns the current query stage enum. * \return Enum value with the current query stage. * \see m_queryStage */ Node::QueryStage GetCurrentQueryStage() { return m_queryStage; } /** * Returns the specified query stage string. * \param _stage The query stage. * \return Specified query stage string. * \see m_queryStage, m_queryPending */ string GetQueryStageName(QueryStage const _stage); /** * Returns whether the library thinks a node is functioning properly * \return boolean status of node. */ bool IsNodeAlive() const { return m_nodeAlive; } /** * This function handles a response to the FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO * command for this node. If protocol information has already been retrieved * for the node, the function simply returns. Otherwise, it populates several * member variables about the device at this node: * - m_routing (whether it is a routing node (capable of passing commands along to other nodes in the network) or not * - m_maxBaudRate (the maximum baud rate at which this device can communicate) * - m_version (TODO) * - m_security (whether device supports security features) * - m_listening (device is powered and listening constantly) * - m_frequentListening (device can be woken up with a beam) * - m_beaming (device is beam capable) */ void UpdateProtocolInfo(uint8 const* _data); /** * this function is called when the Node is added via a AddNode request. the ProtocolInfo field contains the * devices classes and the CommandClasses that the node supports, so we can build a pretty good Node out of that * info. * @param _protocolInfo Byte 0 - Basic Device Class Byte 1 - Generic Device Class, Byte 2 - Specific Device Classes Remaining Bytes - Supported Command Classes * @param _length length of the _protocolInfo field. */ void SetProtocolInfo(uint8 const* _protocolInfo, uint8 const _length); void UpdateNodeInfo(uint8 const* _data, uint8 const _length); bool ProtocolInfoReceived() const { return m_protocolInfoReceived; } bool NodeInfoReceived() const { return m_nodeInfoReceived; } bool IsNodeZWavePlus() const { return m_nodePlusInfoReceived; } bool AllQueriesCompleted() const { return (QueryStage_Complete == m_queryStage); } void SetNodePlusInfoReceived(const bool _received) { m_nodePlusInfoReceived = _received; } /** * Handle dead node detection tracking. * Use this routine to set state of nodes. * Tracks state as well as send notifications. */ void SetNodeAlive(bool const _isAlive); private: void SetStaticRequests(); QueryStage m_queryStage; bool m_queryPending; bool m_queryConfiguration; uint8 m_queryRetries; bool m_protocolInfoReceived; bool m_basicprotocolInfoReceived; bool m_nodeInfoReceived; bool m_nodePlusInfoReceived; bool m_manufacturerSpecificClassReceived; bool m_nodeInfoSupported; bool m_refreshonNodeInfoFrame; bool m_nodeAlive; //----------------------------------------------------------------------------- // Capabilities //----------------------------------------------------------------------------- public: // Security flags enum { SecurityFlag_Security = 0x01, SecurityFlag_Controller = 0x02, SecurityFlag_SpecificDevice = 0x04, SecurityFlag_RoutingSlave = 0x08, SecurityFlag_BeamCapability = 0x10, SecurityFlag_Sensor250ms = 0x20, SecurityFlag_Sensor1000ms = 0x40, SecurityFlag_OptionalFunctionality = 0x80 }; // Node Ids enum { NodeBroadcast = 0xff }; bool IsListeningDevice() const { return m_listening; } bool IsFrequentListeningDevice() const { return m_frequentListening; } bool IsBeamingDevice() const { return m_beaming; } bool IsRoutingDevice() const { return m_routing; } bool IsSecurityDevice() const { return m_security; } uint32 GetMaxBaudRate() const { return m_maxBaudRate; } uint8 GetVersion() const { return m_version; } uint8 GetSecurity() const { return m_security; } uint8 GetNodeId() const { return m_nodeId; } uint8 GetBasic() const { return m_basic; } string GetBasicString(); uint8 GetGeneric(uint8 const _instance) const; string GetGenericString(uint8 const _instance); uint8 GetSpecific(uint8 const _instance) const; string GetSpecificString(uint8 const _instance); string GetEndPointDeviceClassLabel(uint8 const _generic, uint8 const _specific); string const& GetType() const { return m_type; } uint32 GetNeighbors(uint8** o_neighbors); bool IsController() const { return (m_basic == 0x01 || m_basic == 0x02) && (m_generic == 0x01 || m_generic == 0x02); } bool IsAddingNode() const { return m_addingNode; } /* These three *AddingNode functions are used to tell if we this node is just being discovered. Currently used by the Security CC to initiate the Network Key Exchange */ void SetAddingNode() { m_addingNode = true; } void ClearAddingNode() { m_addingNode = false; } bool IsNodeReset(); private: bool m_listening; bool m_frequentListening; bool m_beaming; bool m_routing; uint32 m_maxBaudRate; uint8 m_version; bool m_security; uint32 m_homeId; uint8 m_nodeId; uint8 m_basic; //*< Basic device class (0x01-Controller, 0x02-Static Controller, 0x03-Slave, 0x04-Routing Slave uint8 m_generic; uint8 m_specific; string m_type; // Label representing the specific/generic/basic value uint8 m_neighbors[29]; // Bitmask containing the neighboring nodes uint8 m_numRouteNodes; // number of node routes uint8 m_routeNodes[5]; // nodes to route to map m_buttonMap; // Map button IDs into virtual node numbers bool m_addingNode; //----------------------------------------------------------------------------- // Device Naming //----------------------------------------------------------------------------- private: // Manufacturer, Product and Name are stored here so they can be set by the // user even if the device does not support the relevant command classes. string GetManufacturerName() const { return m_manufacturerName; } string GetProductName() const { return m_productName; } string GetNodeName() const { return m_nodeName; } string GetLocation() const { return m_location; } // string GetManufacturerId()const{ return std::to_string(m_manufacturerId); } uint16 GetManufacturerId() const { return m_manufacturerId; } // string GetProductType()const{ return string(m_productType); } uint16 GetProductType() const { return m_productType; } // string GetProductId()const{ return string(m_productId); } uint16 GetProductId() const { return m_productId; } void SetManufacturerName(string const& _manufacturerName) { m_manufacturerName = _manufacturerName; } void SetProductName(string const& _productName) { m_productName = _productName; } void SetNodeName(string const& _nodeName); void SetLocation(string const& _location); void SetManufacturerId(uint16 const& _manufacturerId) { m_manufacturerId = _manufacturerId; } void SetProductType(uint16 const& _productType) { m_productType = _productType; } void SetProductId(uint16 const& _productId) { m_productId = _productId; } string m_manufacturerName; string m_productName; string m_nodeName; string m_location; uint16 m_manufacturerId; uint16 m_productType; uint16 m_productId; // zwave+ info uint16 GetDeviceType() const { return m_deviceType; } string GetDeviceTypeString(); uint8 GetRoleType() const { return m_role; } string GetRoleTypeString(); uint8 GetNodeType() const { return m_nodeType; } string GetNodeTypeString(); uint16 m_deviceType; uint8 m_role; uint8 m_nodeType; //----------------------------------------------------------------------------- // Command Classes //----------------------------------------------------------------------------- public: /** * This function retrieves a pointer to the requested command class object (if supported by this node). * \param _commandClassId Class ID (a single byte value) identifying the command class requested. * \return Pointer to the requested CommandClass object if supported, otherwise NULL. * \see CommandClass, m_commandClassMap */ Internal::CC::CommandClass* GetCommandClass(uint8 const _commandClassId) const; void ApplicationCommandHandler(uint8 const* _data, bool encrypted); /** * This function sets up Secured Command Classes. It iterates over the existing command classes marking them * as Secured if they exist, and if they don't, it creates new Command Classes and sets them up as Secured * @param _data a list of Command Classes that are Secured by the Device * @param _length the length of the _data string * @param _instance the instance of the Class thats Secured. */ void SetSecuredClasses(uint8 const* _data, uint8 const _length, uint32 const _instance = 1); void SetSecured(bool secure); bool IsSecured(); /** * This function sets a Global Instance Label for all CommandClasses that don't define their * own labels */ void SetInstanceLabel(uint8 const _instance, char *label); /** This function gets a Instance Label for a ValueID. It either users the Global Instance Label * above, or a Label for a Specific CC */ string GetInstanceLabel(uint8 const _ccid, uint8 const _instance); /** Get The Number of Instances on this node * */ uint8 GetNumInstances(uint8 const _ccid); private: /** * Creates the specified command class object and adds it to the node (via the * m_commandClassMap) if it doesn't exist. * No new object is created if it already exists for this node. * \param _commandClassId Class ID (a single byte value) identifying the command class requested. * \return Pointer to the CommandClass object just added to the map (NULL if the object * was already there or if the CommandClass object creation failed). * \see CommandClass, CommandClasses::CreateCommandClass, m_commandClassMap */ Internal::CC::CommandClass* AddCommandClass(uint8 const _commandClassId); /** * Removes a command class object from the node (via the m_commandClassMap). Before removing the * object, this function also removes any values stored in the object's ValueStore. * \param _commandClassId Class ID (a single byte value) identifying the command class to be removed. * \see m_commandClassMap, ValueStore, GetValueStore, ValueStore::RemoveCommandClassValues */ void RemoveCommandClass(uint8 const _commandClassId); void ReadXML(TiXmlElement const* _nodeElement); void ReadDeviceProtocolXML(TiXmlElement const* _ccsElement); void ReadCommandClassesXML(TiXmlElement const* _ccsElement); void WriteXML(TiXmlElement* _nodeElement); map m_commandClassMap; /**< Map of command class ids and pointers to associated command class objects */ bool m_secured; /**< Is this Node added Securely */ map m_globalInstanceLabel; /** < The Global Labels for Instances for CC that dont define their own labels */ TiXmlNode *m_nodeCache; //----------------------------------------------------------------------------- // Configuration Revision Related Classes //----------------------------------------------------------------------------- public: void SetProductDetails(std::shared_ptr product); /** Get a path to the config file for this device * * @return a path relative to the config directory for the config file. returns a empty string if a config file is not present. */ string getConfigPath(); /** Get the latest local revision of the config file for this node * * @return a revision number */ uint32 getFileConfigRevision() { return m_fileConfigRevision; } ; /** Get the Revision number of the config that is laoded for this Node * * @return the revision number currently loaded. */ uint32 getLoadedConfigRevision() { return m_loadedConfigRevision; } ; /** Get the Latest Config File revision available at openzwave.com * * @return The latest revision number available */ uint32 getLatestConfigRevision() { return m_latestConfigRevision; } ; /** Set the revision number of the Config File for this device * * @param rev the revision number */ void setFileConfigRevision(uint32 rev); /** Set the revision number of the config that is loaded for this device * * @param rev the revision number */ void setLoadedConfigRevision(uint32 rev); /** Set the revision number of the latest available config file for this device * * @param rev the revision number */ void setLatestConfigRevision(uint32 rev); /** Check the latest available revision number for this device. * */ void checkLatestConfigRevision(); private: std::shared_ptr m_Product; uint32 m_fileConfigRevision; uint32 m_loadedConfigRevision; uint32 m_latestConfigRevision; //----------------------------------------------------------------------------- // Basic commands (helpers that go through the basic command class) //----------------------------------------------------------------------------- public: void SetLevel(uint8 const _level); //----------------------------------------------------------------------------- // On/Off commands (helpers that go through the basic or switchall command class) //----------------------------------------------------------------------------- public: void SetNodeOn(); void SetNodeOff(); //----------------------------------------------------------------------------- // Values (handled by the command classes) //----------------------------------------------------------------------------- public: ValueID CreateValueID(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, ValueID::ValueType const _type); Internal::VC::Value* GetValue(ValueID const& _id); Internal::VC::Value* GetValue(uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex); bool RemoveValue(uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex); // Helpers for creating values bool CreateValueBitSet(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, int32 const _default, uint8 const _pollIntensity); bool CreateValueBool(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, bool const _default, uint8 const _pollIntensity); bool CreateValueButton(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, uint8 const _pollIntensity); bool CreateValueByte(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _default, uint8 const _pollIntensity); bool CreateValueDecimal(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, string const& _default, uint8 const _pollIntensity); bool CreateValueInt(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, int32 const _default, uint8 const _pollIntensity); bool CreateValueList(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _size, vector const& _items, int32 const _default, uint8 const _pollIntensity); bool CreateValueRaw(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const* _default, uint8 const _length, uint8 const _pollIntensity); bool CreateValueSchedule(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _pollIntensity); bool CreateValueShort(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, int16 const _default, uint8 const _pollIntensity); bool CreateValueString(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, string const& _default, uint8 const _pollIntensity); // helpers for removing values void RemoveValueList(Internal::VC::ValueList* _value); void ReadValueFromXML(uint8 const _commandClassId, TiXmlElement const* _valueElement); bool CreateValueFromXML(uint8 const _commandClassId, TiXmlElement const* _valueElement); private: Internal::VC::ValueStore* GetValueStore() const { return m_values; } Internal::VC::ValueStore* m_values; // Values reported via command classes //----------------------------------------------------------------------------- // Configuration Parameters (handled by the Configuration command class) //----------------------------------------------------------------------------- private: bool SetConfigParam(uint8 const _param, int32 _value, uint8 const _size); void RequestConfigParam(uint8 const _param); bool RequestAllConfigParams(uint32 const _requestFlags); //----------------------------------------------------------------------------- // Dynamic Values (used by query and other command classes for updating) //----------------------------------------------------------------------------- private: bool RequestDynamicValues(); public: //----------------------------------------------------------------------------- // Refresh Dynamic Values from CommandClasses on Wakeup //----------------------------------------------------------------------------- void RefreshValuesOnWakeup(); //----------------------------------------------------------------------------- // Groups //----------------------------------------------------------------------------- private: // The public interface is provided via the wrappers in the Manager class uint8 GetNumGroups(); uint32 GetAssociations(uint8 const _groupIdx, uint8** o_associations); uint32 GetAssociations(uint8 const _groupIdx, InstanceAssociation** o_associations); uint8 GetMaxAssociations(uint8 const _groupIdx); bool IsMultiInstance(uint8 const _groupIdx); string GetGroupLabel(uint8 const _groupIdx); void AddAssociation(uint8 const _groupIdx, uint8 const _targetNodeId, uint8 const _instance = 0x00); void RemoveAssociation(uint8 const _groupIdx, uint8 const _targetNodeId, uint8 const _instance = 0x00); void AutoAssociate(); // The following methods are not exposed Group* GetGroup(uint8 const _groupIdx); // Get a pointer to a Group object. This must only be called while holding the node Lock. void AddGroup(Group* _group); // The groups are fixed properties of a device, so there is no need for a matching RemoveGroup. void WriteGroups(TiXmlElement* _associationsElement); // Write the group data out to XNL map m_groups; // Maps group indices to Group objects. //----------------------------------------------------------------------------- // Device Classes (static data read from the device_classes.xml file) //----------------------------------------------------------------------------- private: // Container for device class info class DeviceClass { public: DeviceClass(TiXmlElement const* _el); ~DeviceClass() { delete[] m_mandatoryCommandClasses; } uint8 const* GetMandatoryCommandClasses() { return m_mandatoryCommandClasses; } uint8 GetBasicMapping() { return m_basicMapping; } string const& GetLabel() { return m_label; } private: uint8* m_mandatoryCommandClasses; // Zero terminated array of mandatory command classes for this device type. uint8 m_basicMapping; // Command class that COMMAND_CLASS_BASIC maps on to, or zero if there is no mapping. string m_label; // Descriptive label for the device. }; // Container for generic device class info class GenericDeviceClass: public DeviceClass { public: GenericDeviceClass(TiXmlElement const* _el); ~GenericDeviceClass(); DeviceClass* GetSpecificDeviceClass(uint8 const& _specific); private: map m_specificDeviceClasses; }; bool SetDeviceClasses(uint8 const _basic, uint8 const _generic, uint8 const _specific); // Set the device class data for the node bool SetPlusDeviceClasses(uint8 const _role, uint8 const _nodeType, uint16 const _deviceType); // Set the device class data for the node based on the Zwave+ info report bool AddMandatoryCommandClasses(uint8 const* _commandClasses); // Add mandatory command classes as specified in the device_classes.xml to the node. bool ReadDeviceClasses(); // Read the static device class data from the device_classes.xml file static bool s_deviceClassesLoaded; // True if the xml file has already been loaded static map s_basicDeviceClasses; // Map of basic device classes. static map s_genericDeviceClasses; // Map of generic device classes. static map s_roleDeviceClasses; // Map of Zwave+ role device classes. static map s_deviceTypeClasses; // Map of Zwave+ device type device classes. static map s_nodeTypes; // Map of ZWave+ Node Types //----------------------------------------------------------------------------- // Statistics //----------------------------------------------------------------------------- public: struct CommandClassData { uint8 m_commandClassId; uint32 m_sentCnt; uint32 m_receivedCnt; }; struct NodeData { uint32 m_sentCnt; uint32 m_sentFailed; uint32 m_retries; uint32 m_receivedCnt; uint32 m_receivedDups; uint32 m_receivedUnsolicited; string m_sentTS; string m_receivedTS; uint32 m_lastRequestRTT; uint32 m_averageRequestRTT; // ms uint32 m_lastResponseRTT; uint32 m_averageResponseRTT; uint8 m_quality; // Node quality measure uint8 m_lastReceivedMessage[254]; list m_ccData; bool m_txStatusReportSupported; uint16 m_txTime; uint8 m_hops; char m_rssi_1[8]; char m_rssi_2[8]; char m_rssi_3[8]; char m_rssi_4[8]; char m_rssi_5[8]; uint8 m_ackChannel; uint8 m_lastTxChannel; TXSTATUS_ROUTING_SCHEME m_routeScheme; char m_routeUsed[9]; TXSTATUS_ROUTE_SPEED m_routeSpeed; uint8 m_routeTries; uint8 m_lastFailedLinkFrom; uint8 m_lastFailedLinkTo; }; private: void GetNodeStatistics(NodeData* _data); uint32 m_sentCnt; // Number of messages sent from this node. uint32 m_sentFailed; // Number of sent messages failed uint32 m_retries; // Number of message retries uint32 m_receivedCnt; // Number of messages received from this node. uint32 m_receivedDups; // Number of duplicated messages received; uint32 m_receivedUnsolicited; // Number of messages received unsolicited uint32 m_lastRequestRTT; // Last message request RTT uint32 m_lastResponseRTT; // Last message response RTT Internal::Platform::TimeStamp m_sentTS; // Last message sent time Internal::Platform::TimeStamp m_receivedTS; // Last message received time uint32 m_averageRequestRTT; // Average Request round trip time. uint32 m_averageResponseRTT; // Average Response round trip time. uint8 m_quality; // Node quality measure uint8 m_lastReceivedMessage[254]; // Place to hold last received message uint8 m_errors; bool m_txStatusReportSupported; // if Extended Status Reports are available uint16 m_txTime; // Time Taken to Transmit the last frame uint8 m_hops; // Hops taken in transmitting last frame char m_rssi_1[8]; // RSSI Level of last transmission char m_rssi_2[8]; // RSSI Level of last transmission char m_rssi_3[8]; // RSSI Level of last transmission char m_rssi_4[8]; // RSSI Level of last transmission char m_rssi_5[8]; // RSSI Level of last transmission uint8 m_ackChannel; // Channel we received the last ACK on uint8 m_lastTxChannel; // Channel we transmitted the last frame on TXSTATUS_ROUTING_SCHEME m_routeScheme; // The Scheme used to route the last frame uint8 m_routeUsed[4]; // The Route Taken in the last frame TXSTATUS_ROUTE_SPEED m_routeSpeed; // Baud Rate of the last frame uint8 m_routeTries; // The number of attempts to route the last frame uint8 m_lastFailedLinkFrom; // The last failed link from uint8 m_lastFailedLinkTo; // The last failed link to //----------------------------------------------------------------------------- // Encryption Related //----------------------------------------------------------------------------- public: uint8 *GenerateNonceKey(); uint8 *GetNonceKey(uint32 nonceid); private: uint8 m_lastnonce; uint8 m_nonces[8][8]; //----------------------------------------------------------------------------- // MetaData Related //----------------------------------------------------------------------------- public: /** * MetaData Fields. * Available Fields that contain metadata about a device. * \see Manager::AddWatcher * \see Manager::BeginControllerCommand */ enum MetaDataFields { MetaData_OzwInfoPage_URL, MetaData_ZWProductPage_URL, MetaData_ProductPic, MetaData_Description, MetaData_ProductManual_URL, MetaData_ProductPage_URL, MetaData_InclusionHelp, MetaData_ExclusionHelp, MetaData_ResetHelp, MetaData_WakeupHelp, MetaData_ProductSupport_URL, MetaData_Frequency, MetaData_Name, MetaData_Identifier, MetaData_Invalid = 255 }; struct ChangeLogEntry { string author; string date; int revision; string description; }; string const GetMetaData(MetaDataFields); MetaDataFields GetMetaDataId(string); string const GetMetaDataString(MetaDataFields); ChangeLogEntry const GetChangeLog(uint32_t); private: void ReadMetaDataFromXML(TiXmlElement const* _valueElement); void WriteMetaDataXML(TiXmlElement*); map m_metadata; map m_changeLog; }; } //namespace OpenZWave #endif //_Node_H openzwave-1.6.1914/cpp/src/SensorMultiLevelCCTypes.cpp0000755000175200017520000002222614032142455017513 00000000000000//----------------------------------------------------------------------------- // // SensorMultiLevelCCTypes.cpp // // SensorMultiLevelCCTypes for SensorMultiLevel Command Class // // Copyright (c) 2019 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "SensorMultiLevelCCTypes.h" #include #include "tinyxml.h" #include "Options.h" #include "Utils.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { SensorMultiLevelCCTypes *SensorMultiLevelCCTypes::m_instance = NULL; std::map > SensorMultiLevelCCTypes::SensorTypes; uint32 SensorMultiLevelCCTypes::m_revision(0); SensorMultiLevelCCTypes::SensorMultiLevelCCTypes() { } bool SensorMultiLevelCCTypes::ReadXML() { // Parse the Z-Wave manufacturer and product XML file. string configPath; Options::Get()->GetOptionAsString("ConfigPath", &configPath); string path = configPath + "SensorMultiLevelCCTypes.xml"; TiXmlDocument* pDoc = new TiXmlDocument(); if (!pDoc->LoadFile(path.c_str(), TIXML_ENCODING_UTF8)) { delete pDoc; Log::Write(LogLevel_Warning, "Unable to load SensorMultiLevelCCTypes file %s", path.c_str()); return false; } pDoc->SetUserData((void*) path.c_str()); Log::Write(LogLevel_Info, "Loading SensorMultiLevelCCTypes File %s", path.c_str()); TiXmlElement const* root = pDoc->RootElement(); char const *str = root->Value(); if (str && !strcmp(str, "SensorTypes")) { // Read in the revision attributes str = root->Attribute("Revision"); if (!str) { Log::Write(LogLevel_Warning, "Error in SensorMultiLevel Config file at line %d - missing Revision attribute", root->Row()); delete pDoc; return false; } m_revision = atol(str); } TiXmlElement const* SensorTypeElement = root->FirstChildElement(); while (SensorTypeElement) { char const* str = SensorTypeElement->Value(); char* pStopChar; if (str && !strcmp(str, "SensorType")) { SensorMultiLevelTypes *st = new SensorMultiLevelTypes; str = SensorTypeElement->Attribute("id"); if (!str) { Log::Write(LogLevel_Warning, "SensorMultiLevelCCTypes::ReadXML: Error in %s at line %d - missing SensorType ID attribute", SensorTypeElement->GetDocument()->GetUserData(), SensorTypeElement->Row()); SensorTypeElement = SensorTypeElement->NextSiblingElement(); delete st; continue; } st->id = (uint32) strtol(str, &pStopChar, 10); str = SensorTypeElement->Attribute("name"); if (!str) { Log::Write(LogLevel_Warning, "SensorMultiLevelCCTypes::ReadXML: Error in %s at line %d - missing SensorType name attribute", SensorTypeElement->GetDocument()->GetUserData(), SensorTypeElement->Row()); SensorTypeElement = SensorTypeElement->NextSiblingElement(); delete st; continue; } st->name = str; trim(st->name); TiXmlElement const* SensorScaleElement = SensorTypeElement->FirstChildElement(); while (SensorScaleElement) { str = SensorScaleElement->Value(); if (str && !strcmp(str, "SensorScale")) { SensorMultiLevelScales *ss = new SensorMultiLevelScales; str = SensorScaleElement->Attribute("id"); if (!str) { Log::Write(LogLevel_Warning, "SensorMultiLevelCCTypes::ReadXML: Error in %s at line %d - missing SensorScale id attribute", SensorScaleElement->GetDocument()->GetUserData(), SensorScaleElement->Row()); SensorScaleElement = SensorScaleElement->NextSiblingElement(); delete ss; continue; } ss->id = (uint32) strtol(str, &pStopChar, 10); str = SensorScaleElement->Attribute("name"); if (!str) { Log::Write(LogLevel_Warning, "SensorMultiLevelCCTypes::ReadXML: Error in %s at line %d - missing SensorScale name attribute", SensorScaleElement->GetDocument()->GetUserData(), SensorScaleElement->Row()); SensorScaleElement = SensorScaleElement->NextSiblingElement(); delete ss; continue; } ss->name = str; trim(ss->name); str = SensorScaleElement->GetText(); if (str) { ss->unit = str; trim(ss->unit); } if (st->allSensorScales.find(ss->id) == st->allSensorScales.end()) st->allSensorScales[ss->id] = std::shared_ptr(ss); else { Log::Write(LogLevel_Warning, "SensorMultiLevelCCTypes::ReadXML: Error in %s at line %d - A SensorScale with id %d already exists. Skipping ", SensorScaleElement->GetDocument()->GetUserData(), SensorScaleElement->Row(), ss->id); delete ss; } } SensorScaleElement = SensorScaleElement->NextSiblingElement(); } if (SensorTypes.find(st->id) == SensorTypes.end()) SensorTypes[st->id] = std::shared_ptr(st); else { Log::Write(LogLevel_Warning, "SensorMultiLevelCCTypes::ReadXML: Error in %s at line %d - A SensorTypeElement with id %d already exists. Skipping ", SensorTypeElement->GetDocument()->GetUserData(), SensorTypeElement->Row(), st->id); delete st; } } SensorTypeElement = SensorTypeElement->NextSiblingElement(); } Log::Write(LogLevel_Info, "Loaded %s With Revision %d", pDoc->GetUserData(), m_revision); #if 0 std::cout << "SensorMultiLevelCCTypes" << std::endl; for (std::map::iterator it = SensorTypes.begin(); it != SensorTypes.end(); it++) { std::cout << "\tSensorTypes:" << (uint32)it->first << " Name: " << it->second->name << std::endl; for (std::map::iterator it2 = it->second->allSensorScales.begin(); it2 != it->second->allSensorScales.end(); it2++) { std::cout << "\t\tSensorScales: " << (uint32)it2->first << " Name: " << it2->second->name << std::endl; } } exit(0); #endif delete pDoc; return true; } std::string SensorMultiLevelCCTypes::GetSensorName(uint32 type) { if (SensorTypes.find(type) != SensorTypes.end()) { return SensorTypes.at(type)->name; } Log::Write(LogLevel_Warning, "SensorMultiLevelCCTypes::GetSensorName - Unknown SensorType %d", type); return "Unknown"; } std::string SensorMultiLevelCCTypes::GetSensorUnit(uint32 type, uint8 scale) { if (SensorTypes.find(type) == SensorTypes.end()) { Log::Write(LogLevel_Warning, "SensorMultiLevelCCTypes::GetSensorUnit - Unknown SensorType %d", type); return ""; } SensorScales ss = SensorTypes.at(type)->allSensorScales; if (ss.find(scale) == ss.end()) { Log::Write(LogLevel_Warning, "SensorMultiLevelCCTypes::GetSensorUnit - Unknown SensorScale %d", scale); return ""; } return ss.at(scale)->unit; } std::string SensorMultiLevelCCTypes::GetSensorUnitName(uint32 type, uint8 scale) { if (SensorTypes.find(type) == SensorTypes.end()) { Log::Write(LogLevel_Warning, "SensorMultiLevelCCTypes::GetSensorUnit - Unknown SensorType %d", type); return ""; } SensorScales ss = SensorTypes.at(type)->allSensorScales; if (ss.find(scale) == ss.end()) { Log::Write(LogLevel_Warning, "SensorMultiLevelCCTypes::GetSensorUnit - Unknown SensorScale %d", scale); return ""; } return ss.at(scale)->name; } const SensorMultiLevelCCTypes::SensorScales SensorMultiLevelCCTypes::GetSensorScales(uint32 type) { if (SensorTypes.find(type) == SensorTypes.end()) { Log::Write(LogLevel_Warning, "SensorMultiLevelCCTypes::GetSensorUnit - Unknown SensorType %d", type); return SensorScales(); } return SensorTypes.at(type)->allSensorScales; } bool SensorMultiLevelCCTypes::Create() { if (m_instance != NULL) { return true; } m_instance = new SensorMultiLevelCCTypes(); if (!ReadXML()) { OZW_ERROR(OZWException::OZWEXCEPTION_CONFIG, "Cannot Create SensorMultiLevelCCTypes Class! - Missing/Invalid Config File?"); return false; } return true; } SensorMultiLevelCCTypes *SensorMultiLevelCCTypes::Get() { if (m_instance != NULL) { return m_instance; } m_instance = new SensorMultiLevelCCTypes(); if (!ReadXML()) { OZW_ERROR(OZWException::OZWEXCEPTION_CONFIG, "Cannot Get SensorMultiLevelCCTypes Class! - Missing/Invalid Config File?"); } return m_instance; } } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/ValueIDIndexes.h0000644000175200017520000000306414032142455015256 00000000000000//----------------------------------------------------------------------------- // // ValueIDIndexes.h // // List of all Possible ValueID Indexes in OZW // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- /* This file is includes the pre-processed ValueIDIndexesDefines.h to avoid problems * with MSVC not supporting enough arguments with Macro's. * If you are adding a ValueID, you should add its index ENUM to ValuIDIndexDefines.def and the run * 'make updateIndexDefines' to regenerate the the ValueIDIndexDefines.h file */ #include #ifndef _ValueIDIndexes_H #define _ValueIDIndexes_H namespace OpenZWave { #ifdef _MSC_VER #define strncpy(x, y, z) strncpy_s(x, sizeof(x), y, sizeof(x)-1) #endif #include "ValueIDIndexesDefines.h" } #endif openzwave-1.6.1914/cpp/src/DoxygenMain.h0000644000175200017520000001144114032142455014665 00000000000000/** * \mainpage OpenZWave * \section Introduction Introduction to OpenZWave * OpenZWave is an open-source, cross-platform library designed to enable * anyone to add support for Z-Wave home-automation devices to their * applications, without requiring any in depth knowledge of the Z-Wave * protocol. *

* For more information about the OpenZWave project: see README.md in the * root of the OpenZWave repository. * \section ZWave Z-Wave Concepts * Z-Wave is a proprietary wireless communications protocol employing mesh * networking technology. A mesh network allows low power devices to * communicate over long ranges, and around radio black spots by passing * messages from one node to another. It is important to note that not all * Z-Wave devices are active all the time, especially those that are battery * powered. These nodes cannot take part in the forwarding of messages * across the mesh. *

* Each Z-Wave device is known as "Node" in the network. A Z-Wave network * can contain up to 232 nodes. If more devices are required, then * multiple networks need to be set up using separate Z-Wave controllers. * OpenZWave supports multiple controllers, but on its own does not bridge * the networks, allowing a device on one to directly control a device on * another. This functionality would have to be supplied by the application. *

* Z-Wave nodes can be divided into two types: Controllers and Slaves. The * controllers are usually in the form of hand-held remote controls, or PC * interfaces. The switches, dimmers, movement sensors etc are all slaves. * Controllers and Devices * Replication * Command Classes * Values *


* \section Library The OpenZWave Library * \subsection Overview Overview * \subsection Manager The Manager * All Z-Wave functionality is accessed via the Manager class. While this * does not make for the most efficient code structure, it does enable * the library to handle potentially complex and hard-to-debug issues * such as multi-threading and object lifespans behind the scenes. * Application development is therefore simplified and less prone to bugs. *

* \subsection Notifications Notifications * Communication between the PC and devices on the the Z-Wave network occurs * asynchronously. Some devices, notably movement sensors, sleep most of the * time to save battery power, and can only receive commands when awake. * Therefore a command to change a value in a device may not occur immediately. * It may take several seconds or minutes, or even never arrive at all. * For this reason, many OpenZWave methods, even those that request * information, do not return that information directly. A request will be * sent to the network, and the response sent to the application some time * later via a system of notification callbacks. The notification handler * will be at the core of any application using OpenZWave. It is here that * all information regarding device configurations and states will be reported. *

* A Z-Wave network is a dynamic entity. Controllers and devices can be * added or removed at any time. Once a network has been set up, this * probably won't happen very often, but OpenZWave, and any application * built upon it, must cope all the same. The notification callback system * is used to inform the application of any changes to the structure of the * network. * \subsection Values Working with Values * * \subsection Guidelines Application Development Guidelines * The main considerations when designing an application based upon * OpenZWave are: * * - Communication with Z-Wave devices is asynchronous and not guaranteed * to be reliable. Do not rely on receiving a response to any request. * * - A Z-Wave network may change at any time. The application's notification * callback handler must deal with all notifications, and any representation * of the state of the Z-Wave network held by the application must be * modified to match. User interfaces should be built dynamically from the * information reported in the notification callbacks, and must be able to cope * with the addition and removal of devices. * * Some users will have more than one Z-Wave controller, to allow for remote * locations or to work around the 232 device limit. OpenZWave is designed * for use with multiple controllers, and all applications should be written * to support this. * * - There is no need to save the state of the network and restore it on * the next run. OpenZWave does this automatically, and is designed to cope * with any changes that occur to the network while the application is not * running. * *


* \section Licensing Licensing * See README.md in the root of the OpenZWave project. *
* \section Support Support * See README.md in the root of the OpenZWave project. *

*/ openzwave-1.6.1914/cpp/src/Options.cpp0000644000175200017520000004725314032142455014443 00000000000000//----------------------------------------------------------------------------- // // Options.h // // Program options read from XML files or the command line. // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include "Defs.h" #include "Options.h" #include "Utils.h" #include "Manager.h" #include "platform/Log.h" #include "platform/FileOps.h" #include "tinyxml.h" using namespace OpenZWave; Options* Options::s_instance = NULL; //----------------------------------------------------------------------------- // // Static method to create an Options object //----------------------------------------------------------------------------- Options* Options::Create(string const& _configPath, string const& _userPath, string const& _commandLine) { if (s_instance == NULL) { string configPath = _configPath; string userPath = _userPath; // Make sure a trailing path delimiter is present if (configPath.size() > 0 && configPath[configPath.size() - 1] != '/') { configPath += "/"; } if (userPath.size() > 0 && userPath[userPath.size() - 1] != '/') { userPath += "/"; } Internal::Platform::FileOps::Create(); if (!Internal::Platform::FileOps::FolderExists(configPath)) { Log::Create("", false, true, LogLevel_Debug, LogLevel_Debug, LogLevel_None); /* Try some default directories */ if (Internal::Platform::FileOps::FolderExists("config/")) { Log::Write(LogLevel_Error, "Cannot find a path to the configuration files at %s, Using config/ instead...", configPath.c_str()); configPath = "config/"; } else if (Internal::Platform::FileOps::FolderExists("/etc/openzwave/")) { Log::Write(LogLevel_Error, "Cannot find a path to the configuration files at %s, Using /etc/openzwave/ instead...", configPath.c_str()); configPath = "/etc/openzwave/"; #ifdef SYSCONFDIR } else if ( Internal::Platform::FileOps::FolderExists(SYSCONFDIR ) ) { Log::Write( LogLevel_Error, "Cannot find a path to the configuration files at %s, Using %s instead...", configPath.c_str(), SYSCONFDIR); configPath = SYSCONFDIR; #endif } else { Log::Write(LogLevel_Error, "Cannot find a path to the configuration files at %s. Exiting...", configPath.c_str()); OZW_FATAL_ERROR(OZWException::OZWEXCEPTION_CONFIG, "Cannot Find Configuration Files"); return NULL; } } Internal::Platform::FileOps::Destroy(); s_instance = new Options(configPath, userPath, _commandLine); // Add the default options s_instance->AddOptionString("ConfigPath", configPath, false); // Path to the OpenZWave config folder. s_instance->AddOptionString("UserPath", userPath, false); // Path to the user's data folder. s_instance->AddOptionBool("Logging", true); // Enable logging of library activity. s_instance->AddOptionString("LogFileName", "OZW_Log.txt", false); // Name of the log file (can be changed via Log::SetLogFileName) s_instance->AddOptionBool("AppendLogFile", false); // Append new session logs to existing log file (false = overwrite) s_instance->AddOptionBool("ConsoleOutput", true); // Display log information on console (as well as save to disk) s_instance->AddOptionInt("SaveLogLevel", LogLevel_Detail); // Save (to file) log messages equal to or above LogLevel_Detail s_instance->AddOptionInt("QueueLogLevel", LogLevel_Debug); // Save (in RAM) log messages equal to or above LogLevel_Debug s_instance->AddOptionInt("DumpTriggerLevel", LogLevel_None); // Default is to never dump RAM-stored log messages s_instance->AddOptionBool("Associate", true); // Enable automatic association of the controller with group one of every device. s_instance->AddOptionString("Exclude", string(""), true); // Remove support for the listed command classes. s_instance->AddOptionString("Include", string(""), true); // Only handle the specified command classes. The Exclude option is ignored if anything is listed here. s_instance->AddOptionBool("NotifyTransactions", false); // Notifications when transaction complete is reported. s_instance->AddOptionString("Interface", string(""), true); // Identify the serial port to be accessed (TODO: change the code so more than one serial port can be specified and HID) s_instance->AddOptionBool("SaveConfiguration", true); // Save the XML configuration upon driver close. s_instance->AddOptionInt("DriverMaxAttempts", 0); s_instance->AddOptionInt("PollInterval", 30000); // 30 seconds (can easily poll 30 values in this time; ~120 values is the effective limit for 30 seconds) s_instance->AddOptionBool("IntervalBetweenPolls", false); // if false, try to execute the entire poll list within the PollInterval time frame // if true, wait for PollInterval milliseconds between polls s_instance->AddOptionBool("SuppressValueRefresh", false); // if true, notifications for refreshed (but unchanged) values will not be sent s_instance->AddOptionBool("PerformReturnRoutes", false); // if true, return routes will be updated s_instance->AddOptionString("NetworkKey", string(""), false); s_instance->AddOptionBool("RefreshAllUserCodes", false); // if true, during startup, we refresh all the UserCodes the device reports it supports. If False, we stop after we get the first "Available" slot (Some devices have 250+ usercode slots! - That makes our Session Stage Very Long ) s_instance->AddOptionInt("RetryTimeout", RETRY_TIMEOUT); // How long do we wait to timeout messages sent s_instance->AddOptionBool("EnableSIS", true); // Automatically become a SUC if there is no SUC on the network. s_instance->AddOptionBool("AssumeAwake", true); // Assume Devices that Support the Wakeup CC are awake when we first query them.... s_instance->AddOptionBool("NotifyOnDriverUnload", false); // Should we send the Node/Value Notifications on Driver Unloading - Read comments in Driver::~Driver() method about possible race conditions s_instance->AddOptionString("SecurityStrategy", "SUPPORTED", false); // Should we encrypt CC's that are available via both clear text and Security CC? s_instance->AddOptionString("CustomSecuredCC", "0x62,0x4c,0x63", false); // What List of Custom CC should we always encrypt if SecurityStrategy is CUSTOM s_instance->AddOptionBool("EnforceSecureReception", true); // if we recieve a clear text message for a CC that is Secured, should we drop the message s_instance->AddOptionBool("AutoUpdateConfigFile", true); // if we should automatically update config files for devices if they are out of date s_instance->AddOptionString("ReloadAfterUpdate", "AWAKE", false); // Should we automatically Reload Nodes after a update s_instance->AddOptionString("Language", "", false); // Language we should use s_instance->AddOptionBool("IncludeInstanceLabel", true); // Should we include the Instance Label in Value Labels on MultiInstance Devices #if defined WINRT s_instance->AddOptionInt( "ThreadTerminateTimeout", -1); // Since threads cannot be terminated in WinRT, Thread::Terminate will simply wait for them to exit on there own #endif } return s_instance; } //----------------------------------------------------------------------------- // // Static method to destroy an Options object //----------------------------------------------------------------------------- bool Options::Destroy() { if (Manager::Get()) { // Cannot delete Options because Manager object still exists OZW_ERROR(OZWException::OZWEXCEPTION_OPTIONS, "Cannot Delete Options Class as Manager Class is still around"); return false; } delete s_instance; s_instance = NULL; return true; } //----------------------------------------------------------------------------- // // Static method to Get an Options object //----------------------------------------------------------------------------- Options* Options::Get() { return s_instance; } //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Options::Options(string const& _configPath, string const& _userPath, string const& _commandLine) : m_xml("options.xml"), m_commandLine(_commandLine), m_SystemPath(_configPath), m_LocalPath(_userPath), m_locked(false) { } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- Options::~Options() { // Clear the options map while (!m_options.empty()) { map::iterator it = m_options.begin(); delete it->second; m_options.erase(it); } } //----------------------------------------------------------------------------- // // Add a boolean option. //----------------------------------------------------------------------------- bool Options::AddOptionBool(string const& _name, bool const _value) { // get (or create) option Option* option = AddOption(_name); if (option == NULL) return false; // set unique option members option->m_type = Options::OptionType_Bool; option->m_valueBool = _value; // save in m_options map string lowerName = Internal::ToLower(_name); m_options[lowerName] = option; return true; } //----------------------------------------------------------------------------- // // Add an integer option. //----------------------------------------------------------------------------- bool Options::AddOptionInt(string const& _name, int32 const _value) { // get (or create) option Option* option = AddOption(_name); if (option == NULL) return false; // set unique option members option->m_type = Options::OptionType_Int; option->m_valueInt = _value; // save in m_options map string lowerName = Internal::ToLower(_name); m_options[lowerName] = option; return true; } //----------------------------------------------------------------------------- // // Add a string option. //----------------------------------------------------------------------------- bool Options::AddOptionString(string const& _name, string const& _value, bool const _append) { // get (or create) option Option* option = AddOption(_name); if (option == NULL) return false; // set unique option members option->m_type = Options::OptionType_String; option->m_valueString = _value; option->m_append = _append; // save in m_options map string lowerName = Internal::ToLower(_name); m_options[lowerName] = option; return true; } //----------------------------------------------------------------------------- // // Get the value of a boolean option. //----------------------------------------------------------------------------- bool Options::GetOptionAsBool(string const& _name, bool* o_value) { Option* option = Find(_name); if (o_value && option && (OptionType_Bool == option->m_type)) { *o_value = option->m_valueBool; return true; } Log::Write(LogLevel_Warning, "Specified option [%s] was not found.", _name.c_str()); return false; } //----------------------------------------------------------------------------- // // Get the value of an integer option. //----------------------------------------------------------------------------- bool Options::GetOptionAsInt(string const& _name, int32* o_value) { Option* option = Find(_name); if (o_value && option && (OptionType_Int == option->m_type)) { *o_value = option->m_valueInt; return true; } Log::Write(LogLevel_Warning, "Specified option [%s] was not found.", _name.c_str()); return false; } //----------------------------------------------------------------------------- // // Get the value of a string option. //----------------------------------------------------------------------------- bool Options::GetOptionAsString(string const& _name, string* o_value) { Option* option = Find(_name); if (o_value && option && (OptionType_String == option->m_type)) { *o_value = option->m_valueString; return true; } Log::Write(LogLevel_Warning, "Specified option [%s] was not found.", _name.c_str()); return false; } //----------------------------------------------------------------------------- // // Get the type of value stored in an option. //----------------------------------------------------------------------------- Options::OptionType Options::GetOptionType(string const& _name) { Option* option = Find(_name); if (option) { return option->m_type; } // Option not found Log::Write(LogLevel_Warning, "Specified option [%s] was not found.", _name.c_str()); return OptionType_Invalid; } //----------------------------------------------------------------------------- // // Read all the option XMLs and Command Lines, and lock their values. //----------------------------------------------------------------------------- bool Options::Lock() { if (m_locked) { Log::Write(LogLevel_Error, "Options are already final (locked)."); return false; } ParseOptionsXML(m_SystemPath + m_xml); ParseOptionsXML(m_LocalPath + m_xml); ParseOptionsString(m_commandLine); m_locked = true; /* Log our Configured Options */ map::iterator it; Log::Write(LogLevel_Info, "Options:"); for (it = m_options.begin(); it != m_options.end(); it++) { Option *opt = it->second; switch (opt->m_type) { case OptionType_Bool: Log::Write(LogLevel_Info, "\t%s: %s", it->first.c_str(), opt->m_valueBool == true ? "true" : "false"); break; case OptionType_Int: Log::Write(LogLevel_Info, "\t%s: %d", it->first.c_str(), opt->m_valueInt); break; case OptionType_String: Log::Write(LogLevel_Info, "\t%s: %s", it->first.c_str(), opt->m_valueString.c_str()); break; case OptionType_Invalid: Log::Write(LogLevel_Info, "\t%s: Invalid Type"); break; } } return true; } //----------------------------------------------------------------------------- // // Parse a string containing program options, such as a command line //----------------------------------------------------------------------------- bool Options::ParseOptionsString(string const& _commandLine) { bool res = true; size_t pos = 0; size_t start = 0; while (1) { // find start of first option name pos = _commandLine.find_first_of("--", start); if (string::npos == pos) { break; } start = pos + 2; // found an option. Get the name. string optionName; pos = _commandLine.find(" ", start); if (string::npos == pos) { optionName = _commandLine.substr(start); start = pos; } else { optionName = _commandLine.substr(start, pos - start); start = pos + 1; } // Find the matching option object Option* option = Find(optionName); if (option) { // Read the values int numValues = 0; bool parsing = true; while (parsing) { string value; size_t back = start; pos = _commandLine.find(" ", start); if (string::npos == pos) { // Last value in string value = _commandLine.substr(start); parsing = false; start = pos; } else { value = _commandLine.substr(start, pos - start); start = pos + 1; } if (!value.compare(0, 2, "--")) { // Value is actually the next option. if (!numValues) { // No values were read for this option // This is ok only for bool options, where we assume no value means "true". if (OptionType_Bool == option->m_type) { option->m_valueBool = true; } else { res = false; } } start = back; // back up to the beginning of the next option break; } else if (value.size() > 0) { // Set the value option->SetValueFromString(value); numValues++; } } } } return res; } //----------------------------------------------------------------------------- // // Parse an XML file containing program options //----------------------------------------------------------------------------- bool Options::ParseOptionsXML(string const& _filename) { TiXmlDocument doc; if (!doc.LoadFile(_filename.c_str(), TIXML_ENCODING_UTF8)) { Log::Write(LogLevel_Warning, "Failed to Parse %s: %s", _filename.c_str(), doc.ErrorDesc()); return false; } doc.SetUserData((void *) _filename.c_str()); Log::Write(LogLevel_Info, "Reading %s for Options", _filename.c_str()); TiXmlElement const* optionsElement = doc.RootElement(); // Read the options TiXmlElement const* optionElement = optionsElement->FirstChildElement(); while (optionElement) { char const* str = optionElement->Value(); if (str && !strcmp(str, "Option")) { char const* name = optionElement->Attribute("name"); if (name) { Option* option = Find(name); if (option) { char const* value = optionElement->Attribute("value"); if (value) { // Set the value option->SetValueFromString(value); } } } } optionElement = optionElement->NextSiblingElement(); } return true; } //----------------------------------------------------------------------------- // // General setup for adding a specific option //----------------------------------------------------------------------------- Options::Option* Options::AddOption(string const& _name) { if (m_locked) { Log::Write(LogLevel_Error, "Options have been locked. No more may be added."); return NULL; } // get a pointer to the option (and create a new Option if it doesn't already exist) Option* option = Find(_name); if (option == NULL) { option = new Option(_name); } return option; } //----------------------------------------------------------------------------- // // Find an option by name //----------------------------------------------------------------------------- Options::Option* Options::Find(string const& _name) { string lowername = Internal::ToLower(_name); map::iterator it = m_options.find(lowername); if (it != m_options.end()) { return it->second; } return NULL; } //----------------------------------------------------------------------------- // // Find an option by name //----------------------------------------------------------------------------- bool Options::Option::SetValueFromString(string const& _value) { if (OptionType_Bool == m_type) { string lowerValue = Internal::ToLower(_value); if ((lowerValue == "true") || (lowerValue == "1")) { m_valueBool = true; return true; } if ((lowerValue == "false") || (lowerValue == "0")) { m_valueBool = false; return true; } return false; } if (OptionType_Int == m_type) { m_valueInt = (int32) atol(_value.c_str()); return true; } if (OptionType_String == m_type) { if (m_append && (m_valueString.size() > 0)) { m_valueString += (string(",") + _value); } else { m_valueString = _value; } return true; } return false; } openzwave-1.6.1914/cpp/src/Scene.cpp0000644000175200017520000003143114032142455014034 00000000000000//----------------------------------------------------------------------------- // // Scene.cpp // // A collection of ValueIDs to be used together. // // Copyright (c) 2011 Greg Satz // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "Manager.h" #include "platform/Log.h" #include "value_classes/Value.h" #include "value_classes/ValueID.h" #include "Scene.h" #include "Options.h" #include "tinyxml.h" namespace OpenZWave { namespace Internal { uint32 const c_sceneVersion = 1; //----------------------------------------------------------------------------- // Statics //----------------------------------------------------------------------------- uint8 Scene::s_sceneCnt = 0; Scene* Scene::s_scenes[256] = { 0 }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Scene::Scene(uint8 const _sceneId) : m_sceneId(_sceneId), m_label("") { s_scenes[_sceneId] = this; s_sceneCnt++; } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- Scene::~Scene() { while (!m_values.empty()) { SceneStorage* ss = m_values.back(); m_values.pop_back(); delete ss; } s_sceneCnt--; s_scenes[m_sceneId] = NULL; } //----------------------------------------------------------------------------- // // Write ourselves to an XML document //----------------------------------------------------------------------------- void Scene::WriteXML(string const& _name) { char str[16]; // Create a new XML document to contain the driver configuration TiXmlDocument doc; TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "utf-8", ""); TiXmlElement* scenesElement = new TiXmlElement("Scenes"); doc.LinkEndChild(decl); doc.LinkEndChild(scenesElement); scenesElement->SetAttribute("xmlns", "http://code.google.com/p/open-zwave/"); snprintf(str, sizeof(str), "%d", c_sceneVersion); scenesElement->SetAttribute("version", str); for (int i = 1; i < 256; i++) { if (s_scenes[i] == NULL) { continue; } TiXmlElement* sceneElement = new TiXmlElement("Scene"); snprintf(str, sizeof(str), "%d", i); sceneElement->SetAttribute("id", str); sceneElement->SetAttribute("label", s_scenes[i]->m_label.c_str()); for (vector::iterator vt = s_scenes[i]->m_values.begin(); vt != s_scenes[i]->m_values.end(); ++vt) { TiXmlElement* valueElement = new TiXmlElement("Value"); snprintf(str, sizeof(str), "0x%.8x", (*vt)->m_id.GetHomeId()); valueElement->SetAttribute("homeId", str); snprintf(str, sizeof(str), "%d", (*vt)->m_id.GetNodeId()); valueElement->SetAttribute("nodeId", str); valueElement->SetAttribute("genre", Internal::VC::Value::GetGenreNameFromEnum((*vt)->m_id.GetGenre())); snprintf(str, sizeof(str), "%d", (*vt)->m_id.GetCommandClassId()); valueElement->SetAttribute("commandClassId", str); snprintf(str, sizeof(str), "%d", (*vt)->m_id.GetInstance()); valueElement->SetAttribute("instance", str); snprintf(str, sizeof(str), "%d", (*vt)->m_id.GetIndex()); valueElement->SetAttribute("index", str); valueElement->SetAttribute("type", Internal::VC::Value::GetTypeNameFromEnum((*vt)->m_id.GetType())); TiXmlText* textElement = new TiXmlText((*vt)->m_value.c_str()); valueElement->LinkEndChild(textElement); sceneElement->LinkEndChild(valueElement); } scenesElement->LinkEndChild(sceneElement); } string userPath; Options::Get()->GetOptionAsString("UserPath", &userPath); string filename = userPath + _name; doc.SaveFile(filename.c_str()); } //----------------------------------------------------------------------------- // // Read scene configuration from an XML document //----------------------------------------------------------------------------- bool Scene::ReadScenes() { int32 intVal; char const* str; // Load the XML document that contains the driver configuration string userPath; Options::Get()->GetOptionAsString("UserPath", &userPath); string filename = userPath + "zwscene.xml"; TiXmlDocument doc; if (!doc.LoadFile(filename.c_str(), TIXML_ENCODING_UTF8)) { return false; } TiXmlElement const* scenesElement = doc.RootElement(); // Version if (TIXML_SUCCESS == scenesElement->QueryIntAttribute("version", &intVal)) { if ((uint32) intVal != c_sceneVersion) { Log::Write(LogLevel_Alert, "Driver::ReadScenes - %s is from an older version of OpenZWave and cannot be loaded.", filename.c_str()); return false; } } else { Log::Write(LogLevel_Alert, "Driver::ReadScenes - %s is from an older version of OpenZWave and cannot be loaded.", filename.c_str()); return false; } TiXmlElement const* sceneElement = scenesElement->FirstChildElement(); while (sceneElement) { Scene* scene = NULL; if (TIXML_SUCCESS == sceneElement->QueryIntAttribute("id", &intVal)) { scene = new Scene((uint8) intVal); } if (scene == NULL) { continue; } str = sceneElement->Attribute("label"); if (str) { scene->m_label = str; } // Read the ValueId for this scene TiXmlElement const* valueElement = sceneElement->FirstChildElement(); while (valueElement) { char const* elementName = valueElement->Value(); if (elementName && !strcmp(elementName, "Value")) { uint32 homeId = 0; str = valueElement->Attribute("homeId"); if (str) { char *p; homeId = (uint32) strtol(str, &p, 0); } uint8 nodeId = 0; if (TIXML_SUCCESS == valueElement->QueryIntAttribute("nodeId", &intVal)) { nodeId = intVal; } ValueID::ValueGenre genre = Internal::VC::Value::GetGenreEnumFromName(valueElement->Attribute("genre")); uint8 commandClassId = 0; if (TIXML_SUCCESS == valueElement->QueryIntAttribute("commandClassId", &intVal)) { commandClassId = intVal; } uint8 instance = 0; if (TIXML_SUCCESS == valueElement->QueryIntAttribute("instance", &intVal)) { instance = intVal; } uint8 index = 0; if (TIXML_SUCCESS == valueElement->QueryIntAttribute("index", &intVal)) { index = intVal; } ValueID::ValueType type = Internal::VC::Value::GetTypeEnumFromName(valueElement->Attribute("type")); char const* data = valueElement->GetText(); scene->m_values.push_back(new SceneStorage(ValueID(homeId, nodeId, genre, commandClassId, instance, index, type), data)); } valueElement = valueElement->NextSiblingElement(); } sceneElement = sceneElement->NextSiblingElement(); } return true; } //----------------------------------------------------------------------------- // // Return the Scene object given the Scene Id //----------------------------------------------------------------------------- Scene* Scene::Get(uint8 const _sceneId) { if (s_scenes[_sceneId] != NULL) { return s_scenes[_sceneId]; } return NULL; } //----------------------------------------------------------------------------- // // Return an array of uint8 of used Scene IDs and the count //----------------------------------------------------------------------------- uint8 Scene::GetAllScenes(uint8** _sceneIds) { if (s_sceneCnt > 0) { *_sceneIds = new uint8[s_sceneCnt]; int j = 0; for (int i = 1; i < 256; i++) { if (s_scenes[i] != NULL) { (*_sceneIds)[j++] = s_scenes[i]->m_sceneId; } } } return s_sceneCnt; } //----------------------------------------------------------------------------- // // Add a ValueID and a string to the scene. //----------------------------------------------------------------------------- bool Scene::AddValue(ValueID const& _valueId, string const& _value) { m_values.push_back(new SceneStorage(_valueId, _value)); return true; } //----------------------------------------------------------------------------- // // Remove the first ValueID found //----------------------------------------------------------------------------- bool Scene::RemoveValue(ValueID const& _valueId) { for (vector::iterator it = m_values.begin(); it != m_values.end(); ++it) { if ((*it)->m_id == _valueId) { delete *it; m_values.erase(it); return true; } } return false; } //----------------------------------------------------------------------------- // // Remove all ValueIDs from given Home ID //----------------------------------------------------------------------------- void Scene::RemoveValues(uint32 const _homeId) { for (auto it = m_values.begin(); it != m_values.end();) { if ((*it)->m_id.GetHomeId() == _homeId) { delete *it; it = m_values.erase(it); } else it++; } // If the scene is now empty, delete it. if (m_values.empty()) { delete this; } } //----------------------------------------------------------------------------- // // Remove all ValueIDs from given Home ID and node ID //----------------------------------------------------------------------------- void Scene::RemoveValues(uint32 const _homeId, uint8 const _nodeId) { for (int i = 1; i < 256; i++) { Scene *scene = Scene::Get(i); if (scene != NULL) { for (auto it = scene->m_values.begin(); it != scene->m_values.end();) { if ((*it)->m_id.GetHomeId() == _homeId && (*it)->m_id.GetNodeId() == _nodeId) { delete *it; it = scene->m_values.erase(it); } else it++; } // If the scene is now empty, delete it. if (scene->m_values.empty()) { delete scene; } } } } //----------------------------------------------------------------------------- // // Return all ValueIDs for the given scene. //----------------------------------------------------------------------------- int Scene::GetValues(vector* o_value) { int size = (int) m_values.size(); if (size > 0) { for (vector::iterator it = m_values.begin(); it != m_values.end(); ++it) { o_value->push_back((*it)->m_id); } } return size; } //----------------------------------------------------------------------------- // // Return a ValueID's value as string //----------------------------------------------------------------------------- bool Scene::GetValue(ValueID const& _valueId, string* o_value) { for (vector::iterator it = m_values.begin(); it != m_values.end(); ++it) { if ((*it)->m_id == _valueId) { *o_value = (*it)->m_value; return true; } } return false; } //----------------------------------------------------------------------------- // // Set a ValueID's value as string //----------------------------------------------------------------------------- bool Scene::SetValue(ValueID const& _valueId, string const& _value) { for (vector::iterator it = m_values.begin(); it != m_values.end(); ++it) { if ((*it)->m_id == _valueId) { (*it)->m_value = _value; return true; } } return false; } //----------------------------------------------------------------------------- // // Execute scene activation by running each ValueId/value //----------------------------------------------------------------------------- bool Scene::Activate() { bool res = true; for (vector::iterator it = m_values.begin(); it != m_values.end(); ++it) { if (!Manager::Get()->SetValue((*it)->m_id, (*it)->m_value)) { res = false; } } return res; } } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/0000777000175200017520000000000014032143201014167 500000000000000openzwave-1.6.1914/cpp/src/platform/unix/0000777000175200017520000000000014032143201015152 500000000000000openzwave-1.6.1914/cpp/src/platform/unix/WaitImpl.h0000644000175200017520000000422114032142455016776 00000000000000//----------------------------------------------------------------------------- // // WaitImpl.h // // POSIX implementation of a base class for objects we // want to be able to wait for. // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _WaitImpl_H #define _WaitImpl_H #include #include #include #include "Defs.h" #include "platform/Ref.h" #include "platform/Wait.h" namespace OpenZWave { namespace Internal { namespace Platform { /** \brief Windows specific implementation of Wait objects. */ class WaitImpl { private: friend class Wait; WaitImpl(Wait* _owner); virtual ~WaitImpl(); void AddWatcher(Wait::pfnWaitNotification_t _callback, void* _context); bool RemoveWatcher(Wait::pfnWaitNotification_t _callback, void* _context); void Notify(); static int32 Multiple(Wait** _objects, uint32 _numObjects, int32 _timeout = -1); WaitImpl(Wait const&); // prevent copy WaitImpl& operator =(WaitImpl const&); // prevent assignment struct Watcher { Wait::pfnWaitNotification_t m_callback; void* m_context; }; list m_watchers; Wait* m_owner; pthread_mutex_t m_criticalSection; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_WaitImpl_H openzwave-1.6.1914/cpp/src/platform/unix/DNSImpl.h0000644000175200017520000000257314032142455016526 00000000000000//----------------------------------------------------------------------------- // // DNSImpl.h // // Unix DNS Lookup Routines. // // Copyright (c) 2016 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _DNSImpl_H #define _DNSImpl_H #include "Defs.h" #include "platform/DNS.h" namespace OpenZWave { namespace Internal { namespace Platform { class DNSImpl { public: DNSImpl(); virtual ~DNSImpl(); virtual bool LookupTxT(string, string &); DNSError status; private: }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/platform/unix/MutexImpl.cpp0000644000175200017520000001032414032142455017530 00000000000000//---------------------------------------------------------------------------- // // MutexImpl.cpp // // POSIX implementation of the cross-platform mutex // // Copyright (c) 2010, Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "platform/Log.h" #include "MutexImpl.h" #include #include namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- MutexImpl::MutexImpl() : m_lockCount(0) { pthread_mutexattr_t ma; pthread_mutexattr_init(&ma); pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE); int err = pthread_mutex_init(&m_criticalSection, &ma); if (err != 0) { Log::Write(LogLevel_Error, "MutexImpl::MutexImpl error %d (%d)\n", errno, err); } pthread_mutexattr_destroy(&ma); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- MutexImpl::~MutexImpl() { if (m_lockCount != 0) { Log::Write(LogLevel_Error, "MutexImpl:~MutexImpl: - Destroying a Locked Mutex: %d", m_lockCount); } pthread_mutex_destroy(&m_criticalSection); } //----------------------------------------------------------------------------- // // Lock the mutex //----------------------------------------------------------------------------- bool MutexImpl::Lock(bool const _bWait) { if (m_lockCount < 0) { Log::Write(LogLevel_Error, "MutexImpl:Lock - Lock is Negative: %d", m_lockCount); m_lockCount = 0; } if (_bWait) { // We will wait for the lock int err = pthread_mutex_lock(&m_criticalSection); if (err == 0) { ++m_lockCount; return true; } Log::Write(LogLevel_Error, "MutexImpl::Lock failed with error: %d (%d)", errno, err); return false; } // Returns immediately, even if the lock was not available. if (pthread_mutex_trylock(&m_criticalSection)) { return false; } ++m_lockCount; return true; } //----------------------------------------------------------------------------- // // Release our lock on the mutex //----------------------------------------------------------------------------- void MutexImpl::Unlock() { if (m_lockCount < 0) { // No locks - we have a mismatched lock/release pair Log::Write(LogLevel_Error, "MutexImpl:Unlock - Lock is Negative - MisMatched Lock/Release Pair: %d", m_lockCount); /* reset the lockCount to 0 */ m_lockCount = 0; } else { --m_lockCount; } /* try to unlock Regardless of the lockCount */ int err = pthread_mutex_unlock(&m_criticalSection); if (err != 0) { Log::Write(LogLevel_Error, "MutexImpl::UnLock failed with error: %d (%d)\n", errno, err); } } //----------------------------------------------------------------------------- // // Test whether the mutex is free //----------------------------------------------------------------------------- bool MutexImpl::IsSignalled() { return (0 == m_lockCount); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/unix/DNSImpl.cpp0000644000175200017520000000556414032142455017064 00000000000000//----------------------------------------------------------------------------- // // DNSImpl.cpp // // Unix DNS Lookup Routines. // // Copyright (c) 2016 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include #include #include #include "DNSImpl.h" namespace OpenZWave { namespace Internal { namespace Platform { DNSImpl::DNSImpl() : status(DNSError_None) { res_init(); } DNSImpl::~DNSImpl() { } bool DNSImpl::LookupTxT(string lookup, string &result) { int response; unsigned char query_buffer[1024]; ns_msg nsMsg; ns_rr rr; const unsigned char *p, *start; unsigned char l; int rrlen; char outb[1025]; #ifdef __APPLE_CC__ response = res_query(lookup.c_str(), ns_c_in, ns_t_txt, query_buffer, sizeof(query_buffer)); #else response= res_query(lookup.c_str(), C_IN, ns_t_txt, query_buffer, sizeof(query_buffer)); #endif if (response < 0) { Log::Write(LogLevel_Warning, "Error looking up txt Record: %s - %s", lookup.c_str(), hstrerror(h_errno)); switch (h_errno) { case HOST_NOT_FOUND: status = DNSError_NotFound; break; case NO_DATA: status = DNSError_NotFound; break; case NO_RECOVERY: status = DNSError_InternalError; break; case TRY_AGAIN: status = DNSError_InternalError; break; default: status = DNSError_InternalError; break; } return false; } ns_initparse(query_buffer, response, &nsMsg); ns_parserr(&nsMsg, ns_s_an, 0, &rr); p = start = ns_rr_rdata(rr); rrlen = ns_rr_rdlen(rr); if (rrlen > 1024) { status = DNSError_InternalError; return false; } while (p < start + rrlen) { l = *p; p++; if (p + l > start + rrlen) { break; } memcpy(outb, p, l); outb[l] = 0; p += l; } result = outb; status = DNSError_None; return true; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/unix/FileOpsImpl.cpp0000644000175200017520000001151714032142455017774 00000000000000//----------------------------------------------------------------------------- // // FileOpsImpl.cpp // // Unix implementation of file operations // // Copyright (c) 2012, Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include "FileOpsImpl.h" #include "Utils.h" namespace OpenZWave { namespace Internal { namespace Platform { using std::ios_base; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- FileOpsImpl::FileOpsImpl() { } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- FileOpsImpl::~FileOpsImpl() { } //----------------------------------------------------------------------------- // // Determine if a folder exists //----------------------------------------------------------------------------- bool FileOpsImpl::FolderExists(const string _folderName) { DIR *dirp = opendir(_folderName.c_str()); if (dirp != NULL) { closedir(dirp); return true; } else return false; } bool FileOpsImpl::FileExists(const string _filename) { struct stat buffer; return (stat(_filename.c_str(), &buffer) == 0); } bool FileOpsImpl::FileWriteable(const string _filename) { if (!FileExists(_filename)) { string fn = ozwdirname(_filename); return (access(fn.c_str(), W_OK | F_OK) == 0); } return (access(_filename.c_str(), W_OK | F_OK) == 0); } bool FileOpsImpl::FileRotate(const string _filename) { int i = 1; string newFile; /* find a filename not used yet */ newFile = _filename; newFile.append(".").append(intToString(i)); while (FileExists(newFile)) { i++; newFile = _filename; newFile.append(".").append(intToString(i)); } /* copy the file */ if (!FileCopy(_filename, newFile)) { Log::Write(LogLevel_Warning, "File Rotate Failed: %s -> %s", _filename.c_str(), newFile.c_str()); return false; } /* remove the old file */ if (remove(_filename.c_str())) { Log::Write(LogLevel_Warning, "File Removal failed: %s", _filename.c_str()); return false; } return true; } bool FileOpsImpl::FileCopy(const string _sourcefile, const string _destfile) { if (!FileExists(_sourcefile)) { Log::Write(LogLevel_Warning, "Source File %s doesn't exist in FileCopy", _sourcefile.c_str()); return false; } if (FileExists(_destfile)) { Log::Write(LogLevel_Warning, "Destination File %s exists in FileCopy", _destfile.c_str()); return false; } /* make sure the Destination Folder Exists */ if (!FolderExists(ozwdirname(_destfile))) { Log::Write(LogLevel_Warning, "Destination Folder %s Doesn't Exist", ozwdirname(_destfile).c_str()); return false; } std::ifstream in(_sourcefile.c_str(), ios_base::in | ios_base::binary); std::ofstream out(_destfile.c_str(), ios_base::out | ios_base::binary); char buf[COPY_BUF_SIZE]; do { in.read(&buf[0], COPY_BUF_SIZE); out.write(&buf[0], in.gcount()); } while (in.gcount() > 0); in.close(); out.close(); return true; } bool FileOpsImpl::FolderCreate(const string _dirname) { if (FolderExists(_dirname)) { Log::Write(LogLevel_Warning, "Folder %s Exists for FolderCreate", _dirname.c_str()); return false; } int ret = mkdir(_dirname.c_str(), 0777); if (ret == 0) return true; Log::Write(LogLevel_Warning, "Create Directory Failed: %s - %s", _dirname.c_str(), strerror(errno)); return false; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/unix/ThreadImpl.h0000644000175200017520000000363314032142455017307 00000000000000//---------------------------------------------------------------------------- // // ThreadImpl.h // // POSIX implementation of a cross-platform thread // // Copyright (c) 2010, Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ThreadImpl_H #define _ThreadImpl_H #include #include #include #include namespace OpenZWave { namespace Internal { namespace Platform { class Thread; class Event; class ThreadImpl { private: friend class Thread; ThreadImpl(Thread* _owner, string const& _tname); ~ThreadImpl(); bool Start(Thread::pfnThreadProc_t _pfnThreadProc, Event* _exitEvent, void* _context); void Sleep(uint32 _millisecs); bool IsSignalled(); bool Terminate(); void Run(); static void* ThreadProc(void *parg); Thread* m_owner; Event* m_exitEvent; pthread_t m_hThread; Thread::pfnThreadProc_t m_pfnThreadProc; void* m_pContext; bool m_bIsRunning; string m_name; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_ThreadImpl_H openzwave-1.6.1914/cpp/src/platform/unix/FileOpsImpl.h0000644000175200017520000000335714032142455017444 00000000000000//----------------------------------------------------------------------------- // // FileOpsImpl.h // // Unix implementation of file operations // // Copyright (c) 2012, Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _FileOpsImpl_H #define _FileOpsImpl_H #include #include #include "Defs.h" #include "platform/FileOps.h" #define COPY_BUF_SIZE 4096 namespace OpenZWave { namespace Internal { namespace Platform { class FileOpsImpl { friend class FileOps; private: FileOpsImpl(); ~FileOpsImpl(); bool FolderExists(const string _filename); bool FileExists(const string _filename); bool FileWriteable(const string _filename); bool FileRotate(const string _filename); bool FileCopy(const string, const string); bool FolderCreate(const string _dirname); }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_FileOpsImpl_H openzwave-1.6.1914/cpp/src/platform/unix/MutexImpl.h0000644000175200017520000000316514032142455017202 00000000000000//---------------------------------------------------------------------------- // // MutexImpl.h // // POSIX implementation of the cross-platform mutex // // Copyright (c) 2010, Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _MutexImpl_H #define _MutexImpl_H #include #include namespace OpenZWave { namespace Internal { namespace Platform { class MutexImpl { private: friend class Mutex; MutexImpl(); ~MutexImpl(); bool Lock(bool const _bWait = true); void Unlock(); bool IsSignalled(); int32 m_lockCount; // Keep track of the locks (there can be more than one if they occur on the same thread. pthread_mutex_t m_criticalSection; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_MutexIF_H openzwave-1.6.1914/cpp/src/platform/unix/EventImpl.cpp0000644000175200017520000001527014032142455017514 00000000000000//----------------------------------------------------------------------------- // // EventImpl.cpp // // POSIX implementation of a cross-platform event // // Copyright (c) 2010, Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "EventImpl.h" #include #include #ifdef __ANDROID__ #include "android.h" #endif namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- EventImpl::EventImpl() : m_manualReset(true), m_isSignaled(false), m_waitingThreads(0) { pthread_mutexattr_t ma; pthread_mutexattr_init(&ma); pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK); pthread_mutex_init(&m_lock, &ma); pthread_mutexattr_destroy(&ma); pthread_condattr_t ca; pthread_condattr_init(&ca); #ifndef __NetBSD__ pthread_condattr_setpshared(&ca, PTHREAD_PROCESS_PRIVATE); #endif pthread_cond_init(&m_condition, &ca); pthread_condattr_destroy(&ca); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- EventImpl::~EventImpl() { pthread_mutex_destroy(&m_lock); pthread_cond_destroy(&m_condition); } //----------------------------------------------------------------------------- // // Set the event to signalled //----------------------------------------------------------------------------- void EventImpl::Set() { int err = pthread_mutex_lock(&m_lock); if (err != 0) { fprintf(stderr, "EventImpl::Set lock error %d (%d)\n", errno, err); assert(0); } if (m_manualReset) { m_isSignaled = true; err = pthread_cond_broadcast(&m_condition); if (err != 0) { fprintf(stderr, "EventImpl::Set cond broadcast error %d (%d)\n", errno, err); assert(0); } } else { if (!m_waitingThreads) { m_isSignaled = true; } else { err = pthread_cond_signal(&m_condition); if (err != 0) { fprintf(stderr, "EventImpl::Set cond signal error %d (%d)\n", errno, err); assert(0); } } } err = pthread_mutex_unlock(&m_lock); if (err != 0) { fprintf(stderr, "EventImpl::Set unlock error %d (%d)\n", errno, err); assert(0); } } //----------------------------------------------------------------------------- // // Set the event to not signalled //----------------------------------------------------------------------------- void EventImpl::Reset() { int err = pthread_mutex_lock(&m_lock); if (err != 0) { fprintf(stderr, "EventImpl::Reset lock error %d (%d)\n", errno, err); assert(0); } m_isSignaled = false; err = pthread_mutex_unlock(&m_lock); if (err != 0) { fprintf(stderr, "EventImpl::Reset unlock error %d (%d)\n", errno, err); assert(0); } } //----------------------------------------------------------------------------- // // Test whether the event is set //----------------------------------------------------------------------------- bool EventImpl::IsSignalled() { return m_isSignaled; } //----------------------------------------------------------------------------- // // Wait for the event to become signalled //----------------------------------------------------------------------------- bool EventImpl::Wait(int32 const _timeout /* milliseconds */ ) { bool result = true; int err = pthread_mutex_lock(&m_lock); if (err != 0) { fprintf(stderr, "EventImpl::Wait lock error %d (%d)\n", errno, err); assert(0); } if (m_isSignaled) { if (!m_manualReset) { m_isSignaled = false; } } else { ++m_waitingThreads; if (_timeout == 0) { result = m_isSignaled; } else if (_timeout > 0) { struct timeval now; struct timespec abstime; gettimeofday(&now, NULL); abstime.tv_sec = now.tv_sec + (_timeout / 1000); // Now add the remainder of our timeout to the microseconds part of 'now' now.tv_usec += (_timeout % 1000) * 1000; // Careful now! Did it wrap? while (now.tv_usec >= (1000 * 1000)) { // Yes it did so bump our seconds and subtract now.tv_usec -= (1000 * 1000); abstime.tv_sec++; } abstime.tv_nsec = now.tv_usec * 1000; while (!m_isSignaled) { int oldstate; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); err = pthread_cond_timedwait(&m_condition, &m_lock, &abstime); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); if (err == ETIMEDOUT) { result = false; break; } else if (err == 0) { result = true; } else { fprintf(stderr, "EventImpl::Wait cond timedwait error %d (%d)\n", errno, err); assert(0); } } } else { while (!m_isSignaled) { int oldstate; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); err = pthread_cond_wait(&m_condition, &m_lock); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); if (err != 0) { fprintf(stderr, "EventImpl::Wait cond wait error %d (%d)\n", errno, err); assert(0); } } } --m_waitingThreads; } err = pthread_mutex_unlock(&m_lock); if (err != 0) { fprintf(stderr, "EventImpl::Wait unlock error %d (%d)\n", errno, err); assert(0); } return result; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/unix/TimeStampImpl.h0000644000175200017520000000506314032142455020002 00000000000000//----------------------------------------------------------------------------- // // TimeStampImpl.h // // OSX implementation of a TimeStamp // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _TimeStampImpl_H #define _TimeStampImpl_H #include #include #include #include "Defs.h" namespace OpenZWave { namespace Internal { namespace Platform { /** \brief Windows implementation of a timestamp. */ class TimeStampImpl { public: /** * Constructor. * Creates a TimeStampImpl object. */ TimeStampImpl(); /** * Destructor. * Destroys the TimeStampImpl object. */ ~TimeStampImpl(); /** * SetTime. Sets the timestamp to now, plus the offset in milliseconds. * \param _milliseconds positive or negative offset from * now in milliseconds. */ void SetTime(int32 _milliseconds); /** * TimeRemaining. Gets the difference between now and the timestamp * time in milliseconds. * \return milliseconds remaining until we reach the timestamp. The * return value is negative if the timestamp is in the past. */ int32 TimeRemaining(); /** * Return as as string */ string GetAsString(); /** * Overload the subtract operator to get the difference between * two timestamps in milliseconds. */ int32 operator-(TimeStampImpl const& _other); private: TimeStampImpl(TimeStampImpl const&); // prevent copy TimeStampImpl& operator =(TimeStampImpl const&); // prevent assignment struct timespec m_stamp; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_TimeStampImpl_H openzwave-1.6.1914/cpp/src/platform/unix/LogImpl.cpp0000644000175200017520000002531014032142455017150 00000000000000//----------------------------------------------------------------------------- // // LogImpl.cpp // // Unix implementation of message and error logging // // Copyright (c) 2010, Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include #include #include "Defs.h" #include "LogImpl.h" namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- LogImpl::LogImpl(string const& _filename, bool const _bAppendLog, bool const _bConsoleOutput, LogLevel const _saveLevel, LogLevel const _queueLevel, LogLevel const _dumpTrigger) : m_filename(_filename), // name of log file m_bConsoleOutput(_bConsoleOutput), // true to provide a copy of output to console m_bAppendLog(_bAppendLog), // true to append (and not overwrite) any existing log m_saveLevel(_saveLevel), // level of messages to log to file m_queueLevel(_queueLevel), // level of messages to log to queue m_dumpTrigger(_dumpTrigger), // dump queued messages when this level is seen pFile( NULL) { if (!m_filename.empty()) { if (!m_bAppendLog) { this->pFile = fopen(m_filename.c_str(), "w"); } else { this->pFile = fopen(m_filename.c_str(), "a"); } if (this->pFile == NULL) { std::cerr << "Could Not Open OZW Log File." << std::endl; } else { setlinebuf(this->pFile); } } setlinebuf(stdout); // To prevent buffering and lock contention issues } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- LogImpl::~LogImpl() { if (this->pFile) fclose(this->pFile); } unsigned int LogImpl::toEscapeCode(LogLevel _level) { unsigned int code = 39; switch (_level) { case LogLevel_Internal: case LogLevel_StreamDetail: code = 97; break; // 97=bright white case LogLevel_Debug: code = 36; break; // 36=cyan case LogLevel_Detail: code = 94; break; // 94=bright blue case LogLevel_Info: code = 39; break; // 39=white case LogLevel_Alert: code = 93; break; // 93=bright yellow case LogLevel_Warning: code = 33; break; // 33=yellow case LogLevel_Error: code = 31; break; // 31=red case LogLevel_Fatal: code = 95; break; // 95=bright magenta case LogLevel_Always: code = 32; break; // 32=green case LogLevel_Invalid: case LogLevel_None: code = 39; break; // 39=white (reset to default) } return code; } //----------------------------------------------------------------------------- // // Write to the log //----------------------------------------------------------------------------- void LogImpl::Write(LogLevel _logLevel, uint8 const _nodeId, char const* _format, va_list _args) { // create a timestamp string string timeStr = GetTimeStampString(); string nodeStr = GetNodeString(_nodeId); string loglevelStr = GetLogLevelString(_logLevel); // handle this message if ((_logLevel <= m_queueLevel) || (_logLevel == LogLevel_Internal)) // we're going to do something with this message... { char lineBuf[1024] = { 0 }; //int lineLen = 0; if (_format != NULL && _format[0] != '\0') { va_list saveargs; va_copy(saveargs, _args); vsnprintf(lineBuf, sizeof(lineBuf), _format, _args); va_end(saveargs); } // should this message be saved to file (and possibly written to console?) if ((_logLevel <= m_saveLevel) || (_logLevel == LogLevel_Internal)) { std::string outBuf; if (this->pFile != NULL || m_bConsoleOutput) { if (_logLevel != LogLevel_Internal) // don't add a second timestamp to display of queued messages { outBuf.append(timeStr); outBuf.append(loglevelStr); outBuf.append(nodeStr); outBuf.append(lineBuf); outBuf.append("\n"); } // print message to file (and possibly screen) if (this->pFile != NULL) { fputs(outBuf.c_str(), pFile); } if (m_bConsoleOutput) { fprintf(stdout, "\x1B[%02um", toEscapeCode(_logLevel)); fputs(outBuf.c_str(), stdout); fprintf(stdout, "\x1b[39m"); /* always return to normal */ fprintf(stdout, "\x1B[%02um", toEscapeCode(LogLevel_Info)); } } } if (_logLevel != LogLevel_Internal) { char queueBuf[1024]; string threadStr = GetThreadId(); snprintf(queueBuf, sizeof(queueBuf), "%s%s%s", timeStr.c_str(), threadStr.c_str(), lineBuf); Queue(queueBuf); } } // now check to see if the _dumpTrigger has been hit if ((_logLevel <= m_dumpTrigger) && (_logLevel != LogLevel_Internal) && (_logLevel != LogLevel_Always)) QueueDump(); } //----------------------------------------------------------------------------- // // Write to the log queue //----------------------------------------------------------------------------- void LogImpl::Queue(char const* _buffer) { string bufStr = _buffer; m_logQueue.push_back(bufStr); // rudimentary queue size management if (m_logQueue.size() > 500) { m_logQueue.pop_front(); } } //----------------------------------------------------------------------------- // // Dump the LogQueue to output device //----------------------------------------------------------------------------- void LogImpl::QueueDump() { Log::Write(LogLevel_Always, ""); Log::Write(LogLevel_Always, "Dumping queued log messages"); Log::Write(LogLevel_Always, ""); list::iterator it = m_logQueue.begin(); while (it != m_logQueue.end()) { string strTemp = *it; Log::Write(LogLevel_Internal, strTemp.c_str()); it++; } m_logQueue.clear(); Log::Write(LogLevel_Always, ""); Log::Write(LogLevel_Always, "End of queued log message dump"); Log::Write(LogLevel_Always, ""); } //----------------------------------------------------------------------------- // // Clear the LogQueue //----------------------------------------------------------------------------- void LogImpl::QueueClear() { m_logQueue.clear(); } //----------------------------------------------------------------------------- // // Sets the various log state variables //----------------------------------------------------------------------------- void LogImpl::SetLoggingState(LogLevel _saveLevel, LogLevel _queueLevel, LogLevel _dumpTrigger) { m_saveLevel = _saveLevel; m_queueLevel = _queueLevel; m_dumpTrigger = _dumpTrigger; } //----------------------------------------------------------------------------- // // Generate a string with formatted current time //----------------------------------------------------------------------------- std::string LogImpl::GetTimeStampString() { // Get a timestamp struct timeval tv; gettimeofday(&tv, NULL); // use threadsafe verion of localtime. Reported by nihilus, 2019-04 // https://www.gnu.org/software/libc/manual/html_node/Broken_002ddown-Time.html#Broken_002ddown-Time struct tm *tm, xtm; memset(&xtm, 0, sizeof(xtm)); tm = localtime_r(&tv.tv_sec, &xtm); // create a time stamp string for the log message char buf[100]; snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d.%03d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int) tv.tv_usec / 1000); string str = buf; return str; } //----------------------------------------------------------------------------- // // Generate a string with formatted node id //----------------------------------------------------------------------------- std::string LogImpl::GetNodeString(uint8 const _nodeId) { if (_nodeId == 0) { return ""; } else if (_nodeId == 255) // should make distinction between broadcast and controller better for SwitchAll broadcast { return "contrlr, "; } else { char buf[20]; snprintf(buf, sizeof(buf), "Node%03d, ", _nodeId); return buf; } } //----------------------------------------------------------------------------- // // Generate a string with formatted thread id //----------------------------------------------------------------------------- std::string LogImpl::GetThreadId() { char buf[20]; snprintf(buf, sizeof(buf), "%08lx ", (long unsigned int) pthread_self()); string str = buf; return str; } //----------------------------------------------------------------------------- // // Provide a new log file name (applicable to future writes) //----------------------------------------------------------------------------- void LogImpl::SetLogFileName(const string &_filename) { m_filename = _filename; } //----------------------------------------------------------------------------- // // Provide a new log file name (applicable to future writes) //----------------------------------------------------------------------------- std::string LogImpl::GetLogLevelString(LogLevel _level) { if ((_level >= LogLevel_None) && (_level <= LogLevel_Internal)) { char buf[20]; snprintf(buf, sizeof(buf), "%s, ", LogLevelString[_level]); return buf; } else return "Unknown, "; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/unix/EventImpl.h0000644000175200017520000000335314032142455017160 00000000000000//----------------------------------------------------------------------------- // // EventImpl.h // // POSIX implementation of a cross-platform event // // Copyright (c) 2010, Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _EventImpl_H #define _EventImpl_H #include #include namespace OpenZWave { namespace Internal { namespace Platform { class EventImpl { private: friend class Event; friend class SocketImpl; friend class Wait; EventImpl(); ~EventImpl(); void Set(); void Reset(); bool Wait(int32 _timeout); // The wait method is to be used only by the Wait::Multiple method bool IsSignalled(); pthread_mutex_t m_lock; pthread_cond_t m_condition; bool m_manualReset; bool m_isSignaled; unsigned int m_waitingThreads; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_EventImpl_H openzwave-1.6.1914/cpp/src/platform/unix/TimeStampImpl.cpp0000644000175200017520000001063414032142455020335 00000000000000//----------------------------------------------------------------------------- // // TimeStampImpl.cpp // // OSX implementation of a TimeStamp // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include "Defs.h" #include "TimeStampImpl.h" namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- TimeStampImpl::TimeStampImpl() { SetTime(0); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- TimeStampImpl::~TimeStampImpl() { } //----------------------------------------------------------------------------- // // Sets the timestamp to now, plus an offset in milliseconds //----------------------------------------------------------------------------- void TimeStampImpl::SetTime(int32 _milliseconds // = 0 ) { struct timeval now; gettimeofday(&now, NULL); m_stamp.tv_sec = now.tv_sec + (_milliseconds / 1000); // Now add the remainder of our timeout to the microseconds part of 'now' now.tv_usec += ((_milliseconds % 1000) * 1000); // Careful now! Did it wrap? if (now.tv_usec >= 1000000) { // Yes it did so bump our seconds and modulo now.tv_usec %= 1000000; m_stamp.tv_sec++; } m_stamp.tv_nsec = now.tv_usec * 1000; } //----------------------------------------------------------------------------- // // Gets the difference between now and the timestamp time in milliseconds //----------------------------------------------------------------------------- int32 TimeStampImpl::TimeRemaining() { int32 diff; struct timeval now; gettimeofday(&now, NULL); // Seconds diff = (int32) ((m_stamp.tv_sec - now.tv_sec) * 1000); // Milliseconds diff += (((m_stamp.tv_nsec / 1000) - now.tv_usec) / 1000); return diff; } //----------------------------------------------------------------------------- // // Return a string representation //----------------------------------------------------------------------------- std::string TimeStampImpl::GetAsString() { char str[100]; // use threadsafe verion of localtime. Reported by nihilus, 2019-04 // https://www.gnu.org/software/libc/manual/html_node/Broken_002ddown-Time.html#Broken_002ddown-Time struct tm *tm, xtm; memset(&xtm, 0, sizeof(xtm)); tm = localtime_r(&m_stamp.tv_sec, &xtm); snprintf(str, sizeof(str), "%04d-%02d-%02d %02d:%02d:%02d:%03d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int) (m_stamp.tv_nsec / (1000 * 1000))); return str; } //----------------------------------------------------------------------------- // // Overload the subtract operator to get the difference between two // timestamps in milliseconds //----------------------------------------------------------------------------- int32 TimeStampImpl::operator-(TimeStampImpl const& _other) { // Seconds int32 diff = (int32) ((m_stamp.tv_sec - _other.m_stamp.tv_sec) * 1000); // Milliseconds diff += ((m_stamp.tv_nsec - _other.m_stamp.tv_nsec) / 1000000); return diff; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/unix/SerialControllerImpl.cpp0000644000175200017520000002444314032142455021720 00000000000000//----------------------------------------------------------------------------- // // SerialControllerImpl.cpp // // POSIX implementation of a cross-platform serial port // // Copyright (c) 2010, Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include #include "Defs.h" #include "platform/Thread.h" #include "platform/Event.h" #include "SerialControllerImpl.h" #include "platform/Log.h" #ifdef __ANDROID__ #include "android.h" #endif #ifdef __sun // SunOS doesn't have the cfsetspeed convenience function. int cfsetspeed(struct termios *tios, speed_t speed) { return (cfsetispeed(tios, speed) || cfsetospeed(tios, speed)); } #endif namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- SerialControllerImpl::SerialControllerImpl(SerialController* _owner) : m_owner(_owner), m_hSerialController(-1), m_pThread( NULL) { } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- SerialControllerImpl::~SerialControllerImpl() { flock(m_hSerialController, LOCK_UN); if (m_hSerialController >= 0) close(m_hSerialController); } //----------------------------------------------------------------------------- // // Open the serial port //----------------------------------------------------------------------------- bool SerialControllerImpl::Open() { // Try to init the serial port if (!Init(1)) { // Failed. We bail to allow the app a chance to take over, rather than retry // automatically. Automatic retries only occur after a successful init. return false; } // Start the read thread m_pThread = new Thread("SerialController"); m_pThread->Start(SerialReadThreadEntryPoint, this); return true; } //----------------------------------------------------------------------------- // // Close the serial port //----------------------------------------------------------------------------- void SerialControllerImpl::Close() { if (m_pThread) { m_pThread->Stop(); m_pThread->Release(); m_pThread = NULL; } close(m_hSerialController); m_hSerialController = -1; } //----------------------------------------------------------------------------- // // Entry point of the thread for receiving data from the serial port //----------------------------------------------------------------------------- void SerialControllerImpl::SerialReadThreadEntryPoint(Event* _exitEvent, void* _context) { SerialControllerImpl* impl = (SerialControllerImpl*) _context; if (impl) { impl->ReadThreadProc(_exitEvent); } } //----------------------------------------------------------------------------- // // Handle receiving data //----------------------------------------------------------------------------- void SerialControllerImpl::ReadThreadProc(Event* _exitEvent) { uint32 attempts = 0; while (!_exitEvent->IsSignalled()) { // Init must have been called successfully during Open, so we // don't do it again until the end of the loop if (-1 != m_hSerialController) { // Enter read loop. Call will only return if // an exit is requested or an error occurs Read(_exitEvent); // Reset the attempts, so we get a rapid retry for temporary errors attempts = 0; } if (attempts < 25) { // Retry every 5 seconds for the first two minutes... if (Wait::Single(_exitEvent, 5000) >= 0) { // Exit signalled. break; } } else { // ...retry every 30 seconds after that if (Wait::Single(_exitEvent, 30000) >= 0) { // Exit signalled. break; } } Init(++attempts); } } //----------------------------------------------------------------------------- // // Initialize the serial port //----------------------------------------------------------------------------- bool SerialControllerImpl::Init(uint32 const _attempts) { string device = m_owner->m_serialControllerName; Log::Write(LogLevel_Info, "Trying to open serial port %s (attempt %d)", device.c_str(), _attempts); #ifdef __NetBSD__ m_hSerialController = open( device.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); #else m_hSerialController = open(device.c_str(), O_RDWR | O_NOCTTY, 0); #endif if (-1 == m_hSerialController) { //Error Log::Write(LogLevel_Error, "ERROR: Cannot open serial port %s. Error code %d", device.c_str(), errno); goto SerialOpenFailure; } if (flock(m_hSerialController, LOCK_EX | LOCK_NB) != 0) { Log::Write(LogLevel_Error, "ERROR: Cannot get exclusive lock for serial port %s. Error code %d", device.c_str(), errno); goto SerialOpenFailure; } int bits; bits = 0; ioctl(m_hSerialController, TIOCMSET, &bits); // Configure the serial device parameters // Build on the current configuration struct termios tios; bzero(&tios, sizeof(tios)); tcgetattr(m_hSerialController, &tios); switch (m_owner->m_parity) { case SerialController::Parity_None: tios.c_iflag = IGNPAR; break; case SerialController::Parity_Odd: tios.c_iflag = INPCK; tios.c_cflag = PARENB | PARODD; break; default: Log::Write(LogLevel_Error, "ERROR: Parity not supported"); goto SerialOpenFailure; } switch (m_owner->m_stopBits) { case SerialController::StopBits_One: break; // default case SerialController::StopBits_Two: tios.c_cflag |= CSTOPB; break; default: Log::Write(LogLevel_Error, "ERROR: Stopbits not supported"); goto SerialOpenFailure; } tios.c_iflag |= IGNBRK; tios.c_cflag |= CS8 | CREAD | CLOCAL; tios.c_oflag = 0; tios.c_lflag = 0; for (int i = 0; i < NCCS; i++) tios.c_cc[i] = 0; tios.c_cc[VMIN] = 0; tios.c_cc[VTIME] = 1; switch (m_owner->m_baud) { case 300: cfsetspeed(&tios, B300); break; case 1200: cfsetspeed(&tios, B1200); break; case 2400: cfsetspeed(&tios, B2400); break; case 4800: cfsetspeed(&tios, B4800); break; case 9600: cfsetspeed(&tios, B9600); break; case 19200: cfsetspeed(&tios, B19200); break; case 38400: cfsetspeed(&tios, B38400); break; case 57600: cfsetspeed(&tios, B57600); break; #ifdef DARWIN case 76800: cfsetspeed( &tios, B76800 ); break; #endif case 115200: cfsetspeed(&tios, B115200); break; case 230400: cfsetspeed(&tios, B230400); break; default: Log::Write(LogLevel_Error, "Baud rate not supported"); goto SerialOpenFailure; } if (tcsetattr(m_hSerialController, TCSANOW, &tios) == -1) { // Error. Clean up and exit Log::Write(LogLevel_Error, "ERROR: Failed to set serial port parameters"); goto SerialOpenFailure; } tcflush(m_hSerialController, TCIOFLUSH); // Open successful Log::Write(LogLevel_Info, "Serial port %s opened (attempt %d)", device.c_str(), _attempts); return true; SerialOpenFailure: Log::Write(LogLevel_Error, "ERROR: Failed to open serial port %s", device.c_str()); if (m_hSerialController >= 0) { close(m_hSerialController); m_hSerialController = -1; } return false; } //----------------------------------------------------------------------------- // // Read data from the serial port //----------------------------------------------------------------------------- void SerialControllerImpl::Read(Event* _exitEvent) { uint8 buffer[256]; while (!_exitEvent->IsSignalled()) { int32 bytesRead; int err; do { bytesRead = read(m_hSerialController, buffer, sizeof(buffer)); if (bytesRead > 0) m_owner->Put(buffer, bytesRead); } while (bytesRead > 0); do { struct timeval *whenp; fd_set rds, eds; int oldstate; FD_ZERO(&rds); FD_SET(m_hSerialController, &rds); FD_ZERO(&eds); FD_SET(m_hSerialController, &eds); whenp = NULL; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); err = select(m_hSerialController + 1, &rds, NULL, &eds, whenp); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); } while (err <= 0); } } //----------------------------------------------------------------------------- // // Send data to the serial port //----------------------------------------------------------------------------- uint32 SerialControllerImpl::Write(uint8* _buffer, uint32 _length) { if (-1 == m_hSerialController) { //Error Log::Write(LogLevel_Error, "ERROR: Serial port must be opened before writing"); return 0; } // Write the data uint32 bytesWritten; bytesWritten = write(m_hSerialController, _buffer, _length); return bytesWritten; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/unix/android.h0000644000175200017520000000024014032142455016665 00000000000000#ifndef _android_H #define _android_H #define pthread_setcancelstate(state, oldstate) ((void)0); *oldstate = 0 #define pthread_cancel(thread) ((void)0) #endifopenzwave-1.6.1914/cpp/src/platform/unix/WaitImpl.cpp0000644000175200017520000001133314032142455017333 00000000000000//----------------------------------------------------------------------------- // // WaitImpl.cpp // // POSIX implementation of an abstract base class for objects we // want to be able to wait for. // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "platform/Wait.h" #include "WaitImpl.h" #include #include #include namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- WaitImpl::WaitImpl(Wait* _owner) : m_owner(_owner) { pthread_mutexattr_t ma; pthread_mutexattr_init(&ma); pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&m_criticalSection, &ma); pthread_mutexattr_destroy(&ma); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- WaitImpl::~WaitImpl() { pthread_mutex_destroy(&m_criticalSection); } //----------------------------------------------------------------------------- // // Add a watcher to our object. //----------------------------------------------------------------------------- void WaitImpl::AddWatcher(Wait::pfnWaitNotification_t _callback, void* _context) { // Add the watcher to our list Watcher watcher; watcher.m_callback = _callback; watcher.m_context = _context; int err; if ((err = pthread_mutex_lock(&m_criticalSection)) != 0) { fprintf(stderr, "WaitImpl::AddWatcher lock error %s\n", strerror(err)); assert(0); } m_watchers.push_back(watcher); if ((err = pthread_mutex_unlock(&m_criticalSection)) != 0) { fprintf(stderr, "WaitImpl::AddWatcher unlock error %s\n", strerror(err)); assert(0); } // If the object is already in a signalled state, notify the watcher immediately if (m_owner->IsSignalled()) { _callback(_context); } } //----------------------------------------------------------------------------- // // Remove a watcher from our object. //----------------------------------------------------------------------------- bool WaitImpl::RemoveWatcher(Wait::pfnWaitNotification_t _callback, void* _context) { bool res = false; if (pthread_mutex_lock(&m_criticalSection) != 0) { fprintf(stderr, "WaitImpl::RemoveWatcher lock error %d\n", errno); assert(0); } for (list::iterator it = m_watchers.begin(); it != m_watchers.end(); ++it) { Watcher const& watcher = *it; if ((watcher.m_callback == _callback) && (watcher.m_context == _context)) { m_watchers.erase(it); res = true; break; } } if (pthread_mutex_unlock(&m_criticalSection) != 0) { fprintf(stderr, "WaitImpl::RemoveWatcher unlock error %d\n", errno); assert(0); } return res; } //----------------------------------------------------------------------------- // // Notify all the watchers that the object has become signalled //----------------------------------------------------------------------------- void WaitImpl::Notify() { if (pthread_mutex_lock(&m_criticalSection) != 0) { fprintf(stderr, "WaitImpl::Notify lock error %d\n", errno); assert(0); } for (list::iterator it = m_watchers.begin(); it != m_watchers.end(); ++it) { Watcher const& watcher = *it; watcher.m_callback(watcher.m_context); } if (pthread_mutex_unlock(&m_criticalSection) != 0) { fprintf(stderr, "WaitImpl::Notify unlock error %d\n", errno); assert(0); } } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/unix/ThreadImpl.cpp0000644000175200017520000001341614032142455017642 00000000000000//---------------------------------------------------------------------------- // // ThreadImpl.h // // POSIX implementation of a cross-platform thread // // Copyright (c) 2010, Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "Defs.h" #include "platform/Event.h" #include "platform/Thread.h" #include "ThreadImpl.h" #ifdef __ANDROID__ #include "android.h" #endif #ifdef DARWIN #define pthread_yield pthread_yield_np #endif namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ThreadImpl::ThreadImpl(Thread* _owner, string const& _tname) : m_owner(_owner), // m_hThread( NULL ), /* p_thread_t isn't a pointer in Linux, so can't do this */ m_bIsRunning(false), m_name(_tname) { } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- ThreadImpl::~ThreadImpl() { } //----------------------------------------------------------------------------- // // Start a function running on this thread //----------------------------------------------------------------------------- bool ThreadImpl::Start(Thread::pfnThreadProc_t _pfnThreadProc, Event* _exitEvent, void* _pContext) { pthread_attr_t ta; pthread_attr_init(&ta); pthread_attr_setstacksize(&ta, 0); pthread_attr_setdetachstate(&ta, PTHREAD_CREATE_JOINABLE); // Create a thread to run the specified function m_pfnThreadProc = _pfnThreadProc; m_pContext = _pContext; m_exitEvent = _exitEvent; m_exitEvent->Reset(); pthread_create(&m_hThread, &ta, ThreadImpl::ThreadProc, this); string threadname("OZW-"); threadname.append(m_name); #if !defined(__APPLE_CC__) && !defined(__FreeBSD__) && !defined(__NetBSD__) pthread_setname_np( m_hThread, threadname.c_str() ); #elif defined(__NetBSD__) if ( threadname.length() > PTHREAD_MAX_NAMELEN_NP ) threadname.resize( PTHREAD_MAX_NAMELEN_NP ); pthread_setname_np( m_hThread, "%s", (void *)threadname.c_str() ); #endif //fprintf(stderr, "thread %s starting %08x\n", m_name.c_str(), m_hThread); //fflush(stderr); pthread_attr_destroy(&ta); return true; } //----------------------------------------------------------------------------- // // End this thread //----------------------------------------------------------------------------- bool ThreadImpl::Terminate() { void* data = NULL; //fprintf(stderr, "thread %s stopping %08x running %d\n", m_name.c_str(), m_hThread, m_bIsRunning ); //fflush(stderr); if (!m_bIsRunning) { return false; } // This will kill an app that doesn't catch and ignore it. // We need to find another way to interrupt select. // thread_kill( m_hThread, SIGALRM ); //m_hThread = NULL; m_bIsRunning = false; pthread_cancel(m_hThread); pthread_join(m_hThread, &data); return true; } //----------------------------------------------------------------------------- // // Cause thread to sleep for the specified number of milliseconds //----------------------------------------------------------------------------- void ThreadImpl::Sleep(uint32 _millisecs) { usleep(_millisecs * 1000); } //----------------------------------------------------------------------------- // // Test whether the thread has completed //----------------------------------------------------------------------------- bool ThreadImpl::IsSignalled() { return !m_bIsRunning; } //----------------------------------------------------------------------------- // // Entry point for running a function on this thread //----------------------------------------------------------------------------- void *ThreadImpl::ThreadProc(void* _pArg) { ThreadImpl* pImpl = (ThreadImpl*) _pArg; //fprintf(stderr, "thread %s run begin %08x running %d\n", pImpl->m_name.c_str(), pImpl->m_hThread, pImpl->m_bIsRunning ); //fflush(stderr); pImpl->Run(); //fprintf(stderr, "thread %s run end %08x running %d\n", pImpl->m_name.c_str(), pImpl->m_hThread, pImpl->m_bIsRunning ); //fflush(stderr); return 0; } //----------------------------------------------------------------------------- // // Entry point for running a function on this thread //----------------------------------------------------------------------------- void ThreadImpl::Run() { m_bIsRunning = true; m_pfnThreadProc(m_exitEvent, m_pContext); m_bIsRunning = false; // Let any watchers know that the thread has finished running m_owner->Notify(); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/unix/LogImpl.h0000644000175200017520000000511614032142455016617 00000000000000//----------------------------------------------------------------------------- // // LogImpl.h // // Unix implementation of message and error logging // // Copyright (c) 2010, Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _LogImpl_H #define _LogImpl_H #include #include #include #include #include #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace Platform { class LogImpl: public i_LogImpl { private: friend class OpenZWave::Log; LogImpl(string const& _filename, bool const _bAppendLog, bool const _bConsoleOutput, LogLevel const _saveLevel, LogLevel const _queueLevel, LogLevel const _dumpTrigger); ~LogImpl(); void Write(LogLevel _level, uint8 const _nodeId, char const* _format, va_list _args); void Queue(char const* _buffer); void QueueDump(); void QueueClear(); void SetLoggingState(LogLevel _saveLevel, LogLevel _queueLevel, LogLevel _dumpTrigger); void SetLogFileName(const string &_filename); string GetTimeStampString(); string GetNodeString(uint8 const _nodeId); string GetThreadId(); string GetLogLevelString(LogLevel _level); unsigned int toEscapeCode(LogLevel _level); string m_filename; /**< filename specified by user (default is ozw_log.txt) */ bool m_bConsoleOutput; /**< if true, send log output to console as well as to the file */ bool m_bAppendLog; /**< if true, the log file should be appended to any with the same name */ list m_logQueue; /**< list of queued log messages */ LogLevel m_saveLevel; LogLevel m_queueLevel; LogLevel m_dumpTrigger; FILE* pFile; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_LogImpl_H openzwave-1.6.1914/cpp/src/platform/unix/SerialControllerImpl.h0000644000175200017520000000374514032142455021367 00000000000000// // SerialControllerImpl.h // // POSIX implementation of a cross-platform serial port // // Copyright (c) 2010, Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _SerialControllerImpl_H #define _SerialControllerImpl_H #include #include #include #include #include #include #include #include #include "Defs.h" #include "platform/SerialController.h" namespace OpenZWave { namespace Internal { namespace Platform { class SerialControllerImpl { public: void ReadThreadProc(Event* _exitEvent); private: friend class SerialController; SerialControllerImpl(SerialController* _owner); ~SerialControllerImpl(); bool Open(); void Close(); uint32 Write(uint8* _buffer, uint32 _length); bool Init(uint32 const _attempts); void Read(Event* _exitEvent); SerialController* m_owner; int m_hSerialController; Thread* m_pThread; static void SerialReadThreadEntryPoint(Event* _exitEvent, void* _content); }; } // namespace platform } // namespace Internal } // namespace OpenZWave #endif //_SerialControllerImpl_H openzwave-1.6.1914/cpp/src/platform/Event.cpp0000644000175200017520000000620614032142455015706 00000000000000//----------------------------------------------------------------------------- // // Event.cpp // // Cross-platform event // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "platform/Event.h" #ifdef WIN32 #include "platform/windows/EventImpl.h" // Platform-specific implementation of an event #elif defined WINRT #include "platform/winRT/EventImpl.h" // Platform-specific implementation of an event #else #include "platform/unix/EventImpl.h" // Platform-specific implementation of an event #endif namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Event::Event() : m_pImpl(new EventImpl()) { } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- Event::~Event() { delete m_pImpl; } //----------------------------------------------------------------------------- // // Set the event to signalled //----------------------------------------------------------------------------- void Event::Set() { m_pImpl->Set(); Notify(); // Notify any watchers that the event is now set } //----------------------------------------------------------------------------- // // Set the event to not signalled //----------------------------------------------------------------------------- void Event::Reset() { m_pImpl->Reset(); } //----------------------------------------------------------------------------- // // Test whether the event is set //----------------------------------------------------------------------------- bool Event::IsSignalled() { return m_pImpl->IsSignalled(); } //----------------------------------------------------------------------------- // // Wait for the event to become signalled //----------------------------------------------------------------------------- bool Event::Wait(int32 const _timeout) { return m_pImpl->Wait(_timeout); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/Thread.h0000644000175200017520000000635414032142455015505 00000000000000//----------------------------------------------------------------------------- // // Thread.h // // Cross-platform threads // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Thread_H #define _Thread_H #include #include "Defs.h" #include "platform/Wait.h" namespace OpenZWave { namespace Internal { namespace Platform { class ThreadImpl; class Event; /** \brief Implements a platform-independent thread management class. * \ingroup Platform */ class Thread: public Wait { public: typedef void (*pfnThreadProc_t)(Event* _exitEvent, void* _context); /** * Constructor. * Creates a thread object that can be used to serialize access to a shared resource. */ Thread(string const& _name); /** * Start running a function on this thread. * Attempts to start a function running on this thread. The call will fail if another * function is already running. * \param _pThreadProc pointer to the function to be run. The function must take a * single void pointer as its only argument, and return void. On entry, the pointer * will be set to the context provided to this Start method. * \param _context pointer allowing any relevant data to be passed to the thread function. * \return True if the function was successfully started. * \see Stop, IsRunning */ bool Start(pfnThreadProc_t _pfnThreadProc, void* _context); /** * Stop a function running on this thread. * Attempts to stop a function running on this thread. The call will fail if no * function is running. * \return True if the function was successfully stopped. * \see Start, IsRunning */ bool Stop(); /** * Causes the thread to sleep for the specified number of milliseconds. * \param _millisecs Number of milliseconds to sleep. */ void Sleep(uint32 _millisecs); protected: /** * Used by the Wait class to test whether the thread has been completed. */ virtual bool IsSignalled(); /** * Destructor. * Destroys the Thread object. */ virtual ~Thread(); private: ThreadImpl* m_pImpl; // Pointer to an object that encapsulates the platform-specific implementation of a thread. Event* m_exitEvent; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_Thread_H openzwave-1.6.1914/cpp/src/platform/DNS.h0000644000175200017520000000432214032142455014713 00000000000000//----------------------------------------------------------------------------- // // DNS.h // // Cross-platform DNS Operations // // Copyright (c) 2015 Justin Hammond // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _DNS_H #define _DNS_H #include #include #include "Defs.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace Platform { class DNSImpl; /** \brief Return codes for DNS lookups * \ingroup Platform */ enum DNSError { DNSError_None = 0, DNSError_NotFound, /**< No Record Exists - There for no Config File exists */ DNSError_DomainError, /**< Domain didn't resolve etc */ DNSError_InternalError /**< A Internal Error Occured */ }; /** \brief Implements platform-independent DNS lookup Operations. * \ingroup Platform */ class DNS { public: DNS(); ~DNS(); /** * \brief Starts a DNS lookup for a TXT record * * This function will lookup the TXT record for a address * * \param lookup the DNS address to lookup * \param result the result of the lookup request, or empty if the lookup failed. * * \return success/failure of the Lookup request */ bool LookupTxT(string lookup, string &result); DNSError status; private: DNSImpl *m_pImpl; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/platform/Event.h0000644000175200017520000000462414032142455015355 00000000000000//----------------------------------------------------------------------------- // // Event.h // // Cross-platform manual-reset event // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Event_H #define _Event_H #include "platform/Wait.h" namespace OpenZWave { namespace Internal { namespace Platform { class EventImpl; /** \brief Platform-independent definition of event objects. * \ingroup Platform */ class Event: public Wait { friend class SerialControllerImpl; friend class Wait; public: /** * Constructor. * Creates a cross-platform event object equivalent to the Windows manual-reset event */ Event(); /** * Set the event to signalled. * \see Reset, Wait */ void Set(); /** * Set the event to not signalled. * \see Set, Wait */ void Reset(); protected: /** * Used by the Wait class to test whether the event is set. */ virtual bool IsSignalled(); /** * Used by the Wait::Multiple method. * returns true if the event signalled, false if it timed out */ bool Wait(int32 _timeout); /** * Destructor. * Destroys the event object. */ ~Event(); private: Event(Event const&); // prevent copy Event& operator =(Event const&); // prevent assignment EventImpl* m_pImpl; // Pointer to an object that encapsulates the platform-specific implementation of a event. }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_Event_H openzwave-1.6.1914/cpp/src/platform/Log.h0000644000175200017520000001770714032142455015023 00000000000000//----------------------------------------------------------------------------- // // Log.h // // Cross-platform message and error logging // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Log_H #define _Log_H #include #include #include #include "Defs.h" namespace OpenZWave { namespace Internal { namespace Platform { class Mutex; } } extern char const *LogLevelString[]; /** \brief Various LogLevels available to the Application * \ingroup Platform * * \see Log::SetLoggingState */ enum LogLevel { LogLevel_Invalid, /**< Invalid Log Status */ LogLevel_None, /**< Disable all logging */ LogLevel_Always, /**< These messages should always be shown */ LogLevel_Fatal, /**< A likely fatal issue in the library */ LogLevel_Error, /**< A serious issue with the library or the network */ LogLevel_Warning, /**< A minor issue from which the library should be able to recover */ LogLevel_Alert, /**< Something unexpected by the library about which the controlling application should be aware */ LogLevel_Info, /**< Everything is working fine...these messages provide streamlined feedback on each message */ LogLevel_Detail, /**< Detailed information on the progress of each message */ LogLevel_Debug, /**< Very detailed information on progress that will create a huge log file quickly But this level (as others) can be queued and sent to the log only on an error or warning */ LogLevel_StreamDetail, /**< Will include low-level byte transfers from controller to buffer to application and back */ LogLevel_Internal /**< Used only within the log class (uses existing timestamp, etc.) */ }; /** \brief A Abstract class to create a Custom Logging Method * \ingroup Platform * * Use this as the basis to create a custom logging class for your applation. * \see Log::SetLoggingClass */ class i_LogImpl { public: i_LogImpl() { } ; virtual ~i_LogImpl() { } ; virtual void Write(LogLevel _level, uint8 const _nodeId, char const* _format, va_list _args) = 0; virtual void QueueDump() = 0; virtual void QueueClear() = 0; virtual void SetLoggingState(LogLevel _saveLevel, LogLevel _queueLevel, LogLevel _dumpTrigger) = 0; virtual void SetLogFileName(const string &_filename) = 0; }; /** \brief Implements a platform-independent log...written to the console and, optionally, a file. * \ingroup Platform */ class OPENZWAVE_EXPORT Log { public: /** \brief Create a log. * * Creates the cross-platform logging singleton. * Any previous log will be cleared. * \return a pointer to the logging object. * \see Destroy, Write */ static Log* Create(string const& _filename, bool const _bAppend, bool const _bConsoleOutput, LogLevel const _saveLevel, LogLevel const _queueLevel, LogLevel const _dumpTrigger); /** \brief Create a log. * * Creates the cross-platform logging singleton. * Any previous log will be cleared. * \param LogClass a Logging Class that inherits the i_LogImpl Class to use to Log * \return a pointer to the logging object. * \see Destroy, Write */ static Log* Create(i_LogImpl *LogClass); /** \brief Destroys the log. * * Destroys the logging singleton. The log can no longer * be written to without another call to Create. * \see Create, Write */ static void Destroy(); /** * \brief Set the Logging Implementation Class to replace the standard File/Console logging * * \param LogClass A Logging Class that inherits the i_LogImpl Class used to Log to * \param Append if this new Logging Class should be appended to the list of Logging Implementations, * or replace the existing Logging Class * \return Bool Value indicating success or failure */ static bool SetLoggingClass(i_LogImpl *LogClass, bool Append = false); /** \brief Enable or disable library logging (retained for backward compatibility) * * \param _dologging If true, logging is enabled; if false, disabled */ static void SetLoggingState(bool _dologging); /**\brief Enable or disable library logging. * * To disable, set _saveLevel and _queueLevel to LogLevel_None. * * \param _saveLevel LogLevel of messages to write in real-time * \param _queueLevel LogLevel of messages to queue to be dumped in case of an error * \param _dumpTrigger LogLevel of message that triggers a queue dump (probably LogLevel_Error or LogLevel_Warning) */ static void SetLoggingState(LogLevel _saveLevel, LogLevel _queueLevel, LogLevel _dumpTrigger); /**\brief Determine whether logging is enabled or not (retained for backward compatibility) * * \param _dologging If true, logging is enabled; if false, disabled */ static bool GetLoggingState(); /**\brief Obtain the various logging levels. * * \param _saveLevel LogLevel of messages to write in real-time * \param _queueLevel LogLevel of messages to queue to be dumped in case of an error * \param _dumpTrigger LogLevel of message that triggers a queue dump (probably LogLevel_Error or LogLevel_Warning) */ static void GetLoggingState(LogLevel* _saveLevel, LogLevel* _queueLevel, LogLevel* _dumpTrigger); /** \brief Change the log file name. * * This will start a new log file (or potentially start appending * information to an existing one. Developers might want to use this function, together with a timer * in the controlling application, to create timestamped log file names. * \param _filename Name of the new (or existing) file to use for log output. */ static void SetLogFileName(const string &_filename); /**\brief Write an entry to the log. * * Writes a formatted string to the log. * \param _level Specifies the type of log message (Error, Warning, Debug, etc.) * \param _format. A string formatted in the same manner as used with printf etc. * \param ... a variable number of arguments, to be included in the formatted string. * \see Create, Destroy */ static void Write(LogLevel _level, char const* _format, ...); /**\brief Write an entry to the log. * * Writes a formatted string to the log. * \param _level Specifies the type of log message (Error, Warning, Debug, etc.) * \param _nodeId Node Id this entry is about. * \param _format. A string formatted in the same manner as used with printf etc. * \param ... a variable number of arguments, to be included in the formatted string. * \see Create, Destroy */ static void Write(LogLevel _level, uint8 const _nodeId, char const* _format, ...); /** \brief Send the queued log messages to the log output. */ static void QueueDump(); /** * Clear the log message queue */ static void QueueClear(); private: Log(string const& _filename, bool const _bAppend, bool const _bConsoleOutput, LogLevel _saveLevel, LogLevel _queueLevel, LogLevel _dumpTrigger); ~Log(); static std::vector m_pImpls; /**< Pointer to an object that encapsulates the platform-specific logging implementation. */ static Log* s_instance; Internal::Platform::Mutex* m_logMutex; }; } // namespace OpenZWave #endif //_Log_H openzwave-1.6.1914/cpp/src/platform/HidController.cpp0000644000175200017520000004104514032142455017375 00000000000000//----------------------------------------------------------------------------- // // HidController.h // // Cross-platform HID port handler // // Copyright (c) 2010 Jason Frazier // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Msg.h" #include "platform/Thread.h" #include "platform/Event.h" #include "platform/Log.h" #include "platform/TimeStamp.h" #include "platform/HidController.h" #ifdef USE_HID #include "hidapi.h" #define CHECK_HIDAPI_RESULT(RESULT, ERRORLABEL) if (RESULT < 0) goto ERRORLABEL #define PACKET_BUFFER_LENGTH 256 // are these specific to Wayne-Dalton? #define FEATURE_REPORT_LENGTH 0x40 #define INPUT_REPORT_LENGTH 0x5 #define OUTPUT_REPORT_LENGTH 0x0 namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- HidController::HidController ( ): m_hHidController( NULL ), m_thread( NULL ), m_vendorId( 0x1b5f ),// Wayne Dalton m_productId( 0x01 ),// ControlThink ThinkStick m_serialNumber( "" ), m_hidControllerName( "" ), m_bOpen( false ) { } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- HidController::~HidController ( ) { } //----------------------------------------------------------------------------- // // Set the USB vendor ID search value. The HID port must be closed for the setting to be accepted. //----------------------------------------------------------------------------- bool HidController::SetVendorId ( uint32 const _vendorId ) { if( m_bOpen ) { return false; } m_vendorId = _vendorId; return true; } //----------------------------------------------------------------------------- // // Set the USB product ID search value. The HID port must be closed for the setting to be accepted. //----------------------------------------------------------------------------- bool HidController::SetProductId ( uint32 const _productId ) { if( m_bOpen ) { return false; } m_productId = _productId; return true; } //----------------------------------------------------------------------------- // // Set the USB serial number search value. The HID port must be closed for the setting to be accepted. //----------------------------------------------------------------------------- bool HidController::SetSerialNumber ( string const& _serialNumber ) { if( m_bOpen ) { return false; } m_serialNumber = _serialNumber; return true; } //----------------------------------------------------------------------------- // // Open and configure a HID port //----------------------------------------------------------------------------- bool HidController::Open ( string const& _hidControllerName ) { if( m_bOpen ) { return false; } m_hidControllerName = _hidControllerName; // Try to init the serial port if( !Init( 1 ) ) { // Failed. We bail to allow the app a chance to take over, rather than retry // automatically. Automatic retries only occur after a successful init. return false; } m_thread = new Thread( "HidController" ); // Start the read thread m_thread->Start( ThreadEntryPoint, this ); return true; } //----------------------------------------------------------------------------- // // Close a HID port //----------------------------------------------------------------------------- bool HidController::Close ( ) { if( m_thread ) { m_thread->Stop(); m_thread->Release(); m_thread = NULL; } hid_close( m_hHidController ); m_hHidController = NULL; m_bOpen = false; hid_exit(); return true; } //----------------------------------------------------------------------------- // // Entry point of the thread for receiving data from the HID port //----------------------------------------------------------------------------- void HidController::ThreadEntryPoint ( Event* _exitEvent, void* _context ) { HidController* hc = (HidController*)_context; if( hc ) { hc->ThreadProc( _exitEvent ); } } //----------------------------------------------------------------------------- // // Handle receiving data //----------------------------------------------------------------------------- void HidController::ThreadProc ( Event* _exitEvent ) { uint32 attempts = 0; while( true ) { // Init must have been called successfully during Open, so we // don't do it again until the end of the loop if( m_hHidController ) { // Enter read loop. Call will only return if // an exit is requested or an error occurs Read(); // Reset the attempts, so we get a rapid retry for temporary errors attempts = 0; } if( attempts < 25 ) { // Retry every 5 seconds for the first two minutes... if( Wait::Single( _exitEvent, 5000 ) >= 0 ) { // Exit signalled. break; } } else { // ...retry every 30 seconds after that if( Wait::Single( _exitEvent, 30000 ) >= 0 ) { // Exit signalled. break; } } Init( ++attempts ); } } //----------------------------------------------------------------------------- // // Open the HID port //----------------------------------------------------------------------------- bool HidController::Init ( uint32 const _attempts ) { // HIDAPI result int hidApiResult; const uint8 dataOutEnableZwave[3] = { 0x02, 0x01, 0x04}; hid_init(); Log::Write( LogLevel_Info, " Open HID port %s", m_hidControllerName.c_str() ); m_hHidController = hid_open(m_vendorId, m_productId, NULL); if (!m_hHidController) { Log::Write( LogLevel_Error, "Cannot find specified HID port with VID:%04hx and PID:0x%04hx.", m_vendorId, m_productId ); // Enumerate connected HIDs for debugging purposes // Note: most OS intentionally hide keyboard/mouse devices from HID access struct hid_device_info *devices, *currentDevice; devices = hid_enumerate(0x0, 0x0); currentDevice = devices; Log::Write( LogLevel_Error, "Enumerating connected HIDs:" ); while (currentDevice) { Log::Write( LogLevel_Error, "\tVID:%04hx\tPID:0x%04hx\tSN:%ls\tMfg:%ls\tProd:%ls\tPath:%s", currentDevice->vendor_id, currentDevice->product_id, currentDevice->serial_number, currentDevice->manufacturer_string, currentDevice->product_string, currentDevice->path); currentDevice = currentDevice->next; } hid_free_enumeration(devices); goto HidOpenFailure; } wchar_t hidInfoString[255]; hidInfoString[0] = 0x0000; Log::Write( LogLevel_Info, " Found HID ZWave controller:"); Log::Write( LogLevel_Info, " Vendor ID: 0x%04hx", m_vendorId); Log::Write( LogLevel_Info, " Product ID: 0x%04hx", m_productId); hidApiResult = hid_get_manufacturer_string(m_hHidController, hidInfoString, 255); if (hidApiResult < 0) { Log::Write( LogLevel_Info, " Manufacturer: <>", hidApiResult ); } else { Log::Write( LogLevel_Info, " Manufacturer: %ls", hidInfoString ); } hidApiResult = hid_get_product_string(m_hHidController, hidInfoString, 255); if (hidApiResult < 0) { Log::Write( LogLevel_Info, " Product name: <>", hidApiResult ); } else { Log::Write( LogLevel_Info, " Product name: %ls", hidInfoString ); } hidApiResult = hid_get_serial_number_string(m_hHidController, hidInfoString, 255); if (hidApiResult < 0) { Log::Write( LogLevel_Warning, "Serial #: <>", hidApiResult ); } else { size_t serialLength = wcslen(hidInfoString); char* serialHex = new char[serialLength + 1]; memset(serialHex, 0, serialLength + 1); for (size_t i = 0; i < serialLength; ++i) { snprintf(&serialHex[i], serialLength - i + 1, "%hx", (unsigned short)(hidInfoString[i] & 0x0f)); } Log::Write( LogLevel_Info, " Serial #: %ls --> %s", hidInfoString, serialHex ); delete [] serialHex; } Log::Write( LogLevel_Info, "" ); // Turn on ZWave data via a short series of feature reports uint8 dataIn[FEATURE_REPORT_LENGTH]; // Get Report ID 2 // Not sure what the result is for, we don't use it so far hidApiResult = GetFeatureReport(FEATURE_REPORT_LENGTH, 0x02, dataIn ); CHECK_HIDAPI_RESULT(hidApiResult, HidOpenFailure); // Send Report ID 2 - 1 byte "0x04" // Enables ZWave packet reports on ID 4 (tx) and ID 5 (rx) hidApiResult = SendFeatureReport(0x3, dataOutEnableZwave); CHECK_HIDAPI_RESULT(hidApiResult, HidOpenFailure); // Get Report ID 2 // Not sure what the result is for, we don't use it so far hidApiResult = GetFeatureReport(FEATURE_REPORT_LENGTH, 0x02, dataIn ); CHECK_HIDAPI_RESULT(hidApiResult, HidOpenFailure); // Ensure that reads for input reports are blocked. // Input report data is polled in Wait() to check if there are feature // reports waiting to be retrieved that contain ZWave rx packets. hidApiResult = hid_set_nonblocking(m_hHidController, 0); CHECK_HIDAPI_RESULT(hidApiResult, HidOpenFailure); // Open successful m_bOpen = true; return true; HidOpenFailure: Log::Write( LogLevel_Error, "Failed to open HID port %s", m_hidControllerName.c_str() ); const wchar_t* errString = hid_error(m_hHidController); Log::Write( LogLevel_Error, "HIDAPI ERROR STRING (if any): %ls", errString); hid_close(m_hHidController); m_hHidController = NULL; return false; } //----------------------------------------------------------------------------- // // Read data from the HID port //----------------------------------------------------------------------------- void HidController::Read ( ) { uint8 buffer[FEATURE_REPORT_LENGTH]; int bytesRead = 0; uint8 inputReport[INPUT_REPORT_LENGTH]; TimeStamp readTimer; while( true ) { // Rx feature report buffer should contain // [0] - 0x05 (rx feature report ID) // [1] - length of rx data (or 0x00 and no further bytes if no rx data waiting) // [2]... - rx data // We poll this waiting for data. bytesRead = GetFeatureReport(FEATURE_REPORT_LENGTH, 0x5, buffer); CHECK_HIDAPI_RESULT(bytesRead, HidPortError); if( bytesRead >= 2 ) { if( buffer[1] > 0 ) { string tmp = ""; for (int i = 0; i < buffer[1]; i++) { char bstr[16]; snprintf( bstr, sizeof(bstr), "0x%.2x ", buffer[2+i] ); tmp += bstr; } Log::Write( LogLevel_Detail, "hid report read=%d ID=%d len=%d %s", bytesRead, buffer[0], buffer[1], tmp.c_str() ); } if( buffer[1] > 0 ) { Put( &buffer[2], buffer[1] ); } } if( readTimer.TimeRemaining() <= 0 ) { // Hang a hid_read to acknowledge receipt. Seems the response is conveying // transaction status. // Wayne-Dalton input report data is structured as follows (best guess): // [0] 0x03 - input report ID // [1] 0x01 - ??? never changes // [2] 0xNN - if 0x01, no feature reports waiting // if 0x02, feature report ID 0x05 is waiting to be retrieved // [3,4] 0xNNNN - Number of ZWave messages? int hidApiResult = hid_read( m_hHidController, inputReport, INPUT_REPORT_LENGTH ); //if( hidApiResult != 0 ) //{ // string tmp = ""; // for( int i = 0; i < INPUT_REPORT_LENGTH; i++ ) // { // char bstr[16]; // snprintf(bstr, sizeof(bstr), "%02x ", inputReport[i] ); // tmp += bstr; // } // Log::Write( LogLevel_Detail, "hid read %d %s", hidApiResult, tmp.c_str() ); //} if( hidApiResult == -1 ) { const wchar_t* errString = hid_error(m_hHidController); Log::Write( LogLevel_Warning, "Error: HID port returned error reading input bytes: 0x%08hx, HIDAPI error string: %ls", hidApiResult, errString ); } readTimer.SetTime( 100 ); } m_thread->Sleep(10); } HidPortError: Log::Write( LogLevel_Warning, "Error: HID port returned error reading rest of packet: 0x%08hx, HIDAPI error string:", bytesRead ); Log::Write( LogLevel_Warning, "%ls", hid_error(m_hHidController)); } //----------------------------------------------------------------------------- // // Send data to the HID port //----------------------------------------------------------------------------- uint32 HidController::Write ( uint8* _buffer, uint32 _length ) { if( !m_bOpen ) { //Error Log::Write( LogLevel_Warning, "Error: HID port must be opened before writing" ); return 0; } if ( FEATURE_REPORT_LENGTH - 2 < _length) { //Error Log::Write( LogLevel_Info, "Error: Write buffer length %d exceeded feature report data capacity %d", _length, FEATURE_REPORT_LENGTH - 2 ); return 0; } // transmit buffer should be arranged: // byte 0 - 0x04 (tx feature report) // byte 1 - length of tx data // byte 2.... - tx data uint8 hidBuffer[FEATURE_REPORT_LENGTH]; memset(hidBuffer, 0, FEATURE_REPORT_LENGTH); hidBuffer[0] = 0x4; hidBuffer[1] = (uint8)_length; memcpy(&hidBuffer[2], _buffer, _length); Log::Write( LogLevel_Debug, " HidController::Write (sent to controller)" ); LogData(_buffer, _length, " Write: "); int bytesSent = SendFeatureReport(FEATURE_REPORT_LENGTH, hidBuffer); if (bytesSent < 2) { //Error const wchar_t* errString = hid_error(m_hHidController); Log::Write( LogLevel_Warning, "Error: HID port returned error sending bytes: 0x%08hx, HIDAPI error string: %ls", bytesSent, errString ); return 0; } return (uint32)bytesSent - 2; } //----------------------------------------------------------------------------- // // Read bytes from the specified HID feature report //----------------------------------------------------------------------------- int HidController::GetFeatureReport ( uint32 _length, uint8 _reportId, uint8* _buffer ) { int result; _buffer[0] = _reportId; result = hid_get_feature_report(m_hHidController, _buffer, _length); if (result < 0) { Log::Write( LogLevel_Info, "Error: HID GetFeatureReport on ID 0x%hx returned (0x%.8x)", _reportId, result ); } return result; } //----------------------------------------------------------------------------- // // Write bytes to the specified HID feature report //----------------------------------------------------------------------------- int HidController::SendFeatureReport ( uint32 _length, const uint8* _data ) { int result; result = hid_send_feature_report(m_hHidController, _data, _length); if (result < 0) { Log::Write( LogLevel_Info, "Error: HID SendFeatureReport on ID 0x%hx returned (0x%.8x)", _data[0], result ); } return result; } } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif /* USE_HID */ openzwave-1.6.1914/cpp/src/platform/Stream.h0000644000175200017520000001103114032142455015515 00000000000000//----------------------------------------------------------------------------- // // Stream.h // // Cross-platform circular buffer with signalling // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Stream_H #define _Stream_H #include "Defs.h" #include "platform/Wait.h" #include namespace OpenZWave { namespace Internal { namespace Platform { class Mutex; /** \brief Platform-independent definition of a circular buffer. * \ingroup Platform */ class Stream: public Wait { friend class Wait; public: /** * Constructor. * Creates a cross-platform ring buffer object */ Stream(uint32 _bufferSize); /** * Set the number of bytes the buffer must contain before it becomes signalled. * Once the threshold is set, the application can use Wait::Single or Wait::Multiple * to wait until the buffer has been filled with the desired amount of data. * \param _size the amount of data in bytes that the buffer must contain for it to become signalled. * \see Wait::Single, Wait::Multiple */ void SetSignalThreshold(uint32 _size); /** * Copies the requested amount of data from the stream, removing it from the stream as it does so. * If there is insufficient data available, the method returns false, and no data is transferred. * \param _buffer pointer to a block of memory that will be filled with the stream data. * \param _size the amount of data in bytes to copy from the stream. * \return true if all the requested data has been copied. False if there was not enough data in * the stream. * \see GetDataSize, Put */ bool Get(uint8* _buffer, uint32 _size); /** * Copies the requested amount of data from the buffer into the stream. * If there is insufficient room available in the stream's circular buffer, and no data is transferred. * \param _buffer pointer to a block of memory that will be copied into the stream. * \param _size the amount of data in bytes to copy to the stream. * \return true if all the requested data has been copied. False if there was not enough space in * the stream's circular buffer. * \see Get, GetDataSize */ bool Put(uint8* _buffer, uint32 _size); /** * Returns the amount of data in bytes that is stored in the stream. * \return the number of bytes of data in the stream. * \see Get, GetDataSize */ uint32 GetDataSize() const { return m_dataSize; } /** * Empties the stream bytes held in the buffer. * This is called when the library gets out of sync with the controller and sends a "NAK" * to the controller. */ void Purge(); protected: /** * Formats stream buffer data for output to the log. * \param _buffer pointer to the stream buffer "head" location * \param _size number of valid bytes currently in the buffer * \param _function string containing text to display before the data */ void LogData(uint8* _buffer, uint32 _size, const string &_function); /** * Used by the Wait class to test whether the buffer contains sufficient data. */ virtual bool IsSignalled(); /** * Destructor. * Destroys the ring buffer object. */ ~Stream(); private: Stream(Stream const&); // prevent copy Stream& operator =(Stream const&); // prevent assignment uint8* m_buffer; uint32 m_bufferSize; uint32 m_signalSize; uint32 m_dataSize; uint32 m_head; uint32 m_tail; Mutex* m_mutex; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_Event_H openzwave-1.6.1914/cpp/src/platform/Wait.cpp0000644000175200017520000001237114032142455015531 00000000000000//----------------------------------------------------------------------------- // // Wait.cpp // // Base class for objects we want to be able to wait for. // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "Defs.h" #include "platform/Wait.h" #include "platform/Event.h" #include "platform/Log.h" #ifdef WIN32 #include "platform/windows/WaitImpl.h" // Platform-specific implementation of a Wait object #elif defined WINRT #include "platform/winRT/WaitImpl.h" // Platform-specific implementation of a Wait object #else #include "platform/unix/WaitImpl.h" // Platform-specific implementation of a Wait object #endif namespace OpenZWave { namespace Internal { namespace Platform { void WaitMultipleCallback(void* _context); //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Wait::Wait() { m_pImpl = new WaitImpl(this); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- Wait::~Wait() { delete m_pImpl; } //----------------------------------------------------------------------------- // // Add a watcher to our object. //----------------------------------------------------------------------------- void Wait::AddWatcher(pfnWaitNotification_t _callback, void* _context) { if (!_callback) { assert(0); return; } // Add a ref so our object cannot disappear while being watched AddRef(); // Add the watcher (platform specific code required here for thread safety) m_pImpl->AddWatcher(_callback, _context); } //----------------------------------------------------------------------------- // // Remove a watcher from our object. //----------------------------------------------------------------------------- void Wait::RemoveWatcher(pfnWaitNotification_t _callback, void* _context) { if (m_pImpl->RemoveWatcher(_callback, _context)) { Release(); } } //----------------------------------------------------------------------------- // // Notify all the watchers that the object has become signalled //----------------------------------------------------------------------------- void Wait::Notify() { m_pImpl->Notify(); } //----------------------------------------------------------------------------- // // Wait for one of multiple objects to become signalled. //----------------------------------------------------------------------------- int32 Wait::Multiple(Wait** _objects, uint32 _numObjects, int32 _timeout // = -1 ) { uint32 i; // Create an event that will be set when any of the objects in the list becomes signalled. Event* waitEvent = new Event(); // Add a watcher to each object in the list, passing in the event as the context. for (i = 0; i < _numObjects; ++i) { // Log::Write( LogLevel_Info, "Wait::Multiple - Object %p %d", _objects[i], _objects[i]->IsSignalled()); _objects[i]->AddWatcher(WaitMultipleCallback, waitEvent); } int32 res = -1; // Default to timeout result string str = ""; if (waitEvent->Wait(_timeout)) { // An object was signalled. Run through the list // and see which one it was. for (i = 0; i < _numObjects; ++i) { if (_objects[i]->IsSignalled()) { if (res == -1) res = (int32) i; char buf[15]; snprintf(buf, sizeof(buf), "%d, ", i); str += buf; } } } // Log::Write( LogLevel_Debug, "Wait::Multiple res=%d num=%d >%s", res, _numObjects, str.c_str() ); // Remove the watchers for (i = 0; i < _numObjects; ++i) { _objects[i]->RemoveWatcher(WaitMultipleCallback, waitEvent); } // We're done with the event now waitEvent->Release(); return res; } //----------------------------------------------------------------------------- // // Callback handler for the watchers added during WaitImpl::Multiple //----------------------------------------------------------------------------- void WaitMultipleCallback(void* _context) { Event* waitEvent = (Event*) _context; waitEvent->Set(); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/HttpClient.cpp0000644000175200017520000010027714032142455016706 00000000000000// minihttp.cpp - All functionality required for a minimal TCP/HTTP client packed in one file. // Released under the WTFPL (See minihttp.h) #ifdef _MSC_VER # ifndef _CRT_SECURE_NO_WARNINGS # define _CRT_SECURE_NO_WARNINGS # endif # ifndef _CRT_SECURE_NO_DEPRECATE # define _CRT_SECURE_NO_DEPRECATE # endif #endif #ifdef WINRT # include # include #elif _WIN32 # ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0501 # endif # include # include #if !defined(EWOULDBLOCK) # define EWOULDBLOCK WSAEWOULDBLOCK #endif #if !defined(ETIMEDOUT) # define ETIMEDOUT WSAETIMEDOUT #endif #if !defined(ECONNRESET) # define ECONNRESET WSAECONNRESET #endif #if !defined(ENOTCONN) # define ENOTCONN WSAENOTCONN #endif # include #else # include # include # include # include # include # include # define SOCKET_ERROR (-1) # define INVALID_SOCKET (SOCKET)(~0) typedef intptr_t SOCKET; #endif #include #include #include #include #include #include #include #include #include #include #ifdef MINIHTTP_USE_POLARSSL # include "polarssl/net.h" # include "polarssl/ssl.h" # include "polarssl/entropy.h" # include "polarssl/ctr_drbg.h" #endif #include "platform/HttpClient.h" #include "platform/Log.h" #include "Utils.h" #define SOCKETVALID(s) ((s) != INVALID_SOCKET) //#define _DEBUG #ifdef _MSC_VER # define STRNICMP _strnicmp #else # define STRNICMP strncasecmp #endif #ifdef _DEBUG # define traceprint(...) {printf(__VA_ARGS__);} #else # define traceprint(...) {} #endif namespace OpenZWave { namespace Internal { namespace Platform { #ifdef MINIHTTP_USE_POLARSSL // ------------------------ SSL STUFF ------------------------- bool HasSSL ( ) { return true; } struct SSLCtx { SSLCtx ( ): _inited(0) { entropy_init(&entropy); x509_crt_init(&cacert); memset(&ssl, 0, sizeof(ssl_context)); } ~SSLCtx ( ) { entropy_free(&entropy); x509_crt_free(&cacert); ssl_free(&ssl); if(_inited & 1) ctr_drbg_free(&ctr_drbg); if(_inited & 2) ssl_free(&ssl); } bool init ( ) { const char *pers = "minihttp"; const size_t perslen = strlen(pers); int err = ctr_drbg_init(&ctr_drbg, entropy_func, &entropy, (unsigned char *)pers, perslen); if(err) { traceprint("SSLCtx::init(): ctr_drbg_init() returned %d\n", err); return false; } _inited |= 1; err = ssl_init(&ssl); if(err) { traceprint("SSLCtx::init(): ssl_init() returned %d\n", err); return false; } _inited |= 2; return true; } void reset ( ) { ssl_session_reset(&ssl); } entropy_context entropy; ctr_drbg_context ctr_drbg; ssl_context ssl; x509_crt cacert; private: unsigned _inited; }; // ------------------------------------------------------------ #else // MINIHTTP_USE_POLARSSL bool HasSSL() { return false; } #endif // MINIHTTP_USE_POLARSSL #define DEFAULT_BUFSIZE 4096 inline int _GetError() { #ifdef _WIN32 return WSAGetLastError(); #else return errno; #endif } inline std::string _GetErrorStr(int e) { std::string ret; #ifdef WINRT LPTSTR s = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 512); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), s, 512, NULL ); char buffer[1024]; wcstombs(buffer, s, sizeof(buffer)); HeapFree(GetProcessHeap(), 0, s); ret = buffer; #elif _WIN32 LPTSTR s; ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, e, 0, (LPTSTR)&s, 0, NULL); if(s) ret = s; ::LocalFree(s); #else const char *s = strerror(e); if (s) ret = s; #endif return ret; } bool InitNetwork() { #ifdef _WIN32 WSADATA wsadata; if(WSAStartup(MAKEWORD(2,2), &wsadata)) { traceprint("WSAStartup ERROR: %s", _GetErrorStr(_GetError()).c_str()); return false; } #endif return true; } void StopNetwork() { #ifdef _WIN32 WSACleanup(); #endif } static bool _Resolve(const char *host, unsigned int port, struct sockaddr_in *addr) { char port_str[16]; sprintf(port_str, "%u", port); struct addrinfo hnt, *res = 0; memset(&hnt, 0, sizeof(hnt)); hnt.ai_family = AF_INET; hnt.ai_socktype = SOCK_STREAM; if (getaddrinfo(host, port_str, &hnt, &res)) { traceprint("RESOLVE ERROR: %s", _GetErrorStr(_GetError()).c_str()); return false; } if (res) { if (res->ai_family != AF_INET) { traceprint("RESOLVE WTF: %s", _GetErrorStr(_GetError()).c_str()); freeaddrinfo(res); return false; } memcpy(addr, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); return true; } return false; } // FIXME: this does currently not handle links like: // http://example.com/index.html#pos bool SplitURI(const std::string& uri, std::string& protocol, std::string& host, std::string& file, int& port, bool& useSSL) { const char *p = uri.c_str(); const char *sl = strstr(p, "//"); unsigned int offs = 0; if (sl) { size_t colon = uri.find(':'); size_t firstslash = uri.find('/'); if (colon < firstslash) protocol = uri.substr(0, colon); if (strncmp(p, "http://", 7) == 0) { useSSL = false; offs = 7; } else if (strncmp(p, "https://", 8) == 0) { useSSL = true; offs = 8; } else return false; p = sl + 2; } sl = strchr(p, '/'); if (!sl) { host = p; file = "/"; } else { host = uri.substr(offs, sl - p); file = sl; } port = -1; size_t colon = host.find(':'); if (colon != std::string::npos) { port = atoi(host.c_str() + colon); host.erase(port); } return true; } void URLEncode(const std::string& s, std::string& enc) { const size_t len = s.length(); char buf[3]; buf[0] = '%'; for (size_t i = 0; i < len; i++) { const unsigned char c = s[i]; // from https://www.ietf.org/rfc/rfc1738.txt, page 3 // with some changes for compatibility if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == ',') enc += (char) c; else if (c == ' ') enc += '+'; else { unsigned nib = (c >> 4) & 0xf; buf[1] = nib < 10 ? '0' + nib : 'a' + (nib - 10); nib = c & 0xf; buf[2] = nib < 10 ? '0' + nib : 'a' + (nib - 10); enc.append(&buf[0], 3); } } } static bool _SetNonBlocking(SOCKET s, bool nonblock) { if (!SOCKETVALID(s)) return false; #ifdef MINIHTTP_USE_POLARSSL if(nonblock) return net_set_nonblock(s) == 0; else return net_set_block(s) == 0; #elif defined(_WIN32) ULONG tmp = !!nonblock; if(::ioctlsocket(s, FIONBIO, &tmp) == SOCKET_ERROR) return false; #else int tmp = ::fcntl(s, F_GETFL); if (tmp < 0) return false; if (::fcntl(s, F_SETFL, nonblock ? (tmp | O_NONBLOCK) : (tmp |= ~O_NONBLOCK)) < 0) return false; #endif return true; } TcpSocket::TcpSocket() : _inbuf(NULL), _readptr(NULL), _writeptr(NULL), _inbufSize(0), _writeSize(0), _recvSize(0), _lastport(0), _nonblocking(false), _s(INVALID_SOCKET), _sslctx(NULL) { } TcpSocket::~TcpSocket() { close(); if (_inbuf) free(_inbuf); } bool TcpSocket::isOpen() { return SOCKETVALID(_s); } void TcpSocket::close() { if (!SOCKETVALID(_s)) return; traceprint("TcpSocket::close\n"); _OnCloseInternal(); #ifdef MINIHTTP_USE_POLARSSL if(_sslctx) ((SSLCtx*)_sslctx)->reset(); net_close(_s); shutdownSSL(); #else # ifdef _WIN32 ::closesocket((SOCKET)_s); # else ::close(_s); # endif #endif _s = INVALID_SOCKET; _recvSize = 0; } void TcpSocket::_OnCloseInternal() { _OnClose(); } bool TcpSocket::SetNonBlocking(bool nonblock) { _nonblocking = nonblock; return _SetNonBlocking(_s, nonblock); } void TcpSocket::SetBufsizeIn(unsigned int s) { if (s < 512) s = 512; if (s != _inbufSize) _inbuf = (char*) realloc(_inbuf, s); _inbufSize = s; _writeSize = s - 1; _readptr = _writeptr = _inbuf; } static bool _openSocket(SOCKET *ps, const char *host, unsigned port) { #ifdef MINIHTTP_USE_POLARSSL int s; int err = net_connect(&s, host, port); if(err) { traceprint("open_ssl: net_connect(%s, %u) returned %d\n", host, port, err); return false; } #else sockaddr_in addr; if (!_Resolve(host, port, &addr)) { traceprint("RESOLV ERROR: %s\n", _GetErrorStr(_GetError()).c_str()); return false; } SOCKET s = socket(AF_INET, SOCK_STREAM, 0); if (!SOCKETVALID(s)) { traceprint("SOCKET ERROR: %s\n", _GetErrorStr(_GetError()).c_str()); return false; } if (::connect(s, (sockaddr*) &addr, sizeof(sockaddr))) { traceprint("CONNECT ERROR: %s\n", _GetErrorStr(_GetError()).c_str()); return false; } #endif *ps = s; return true; } #ifdef MINIHTTP_USE_POLARSSL void traceprint_ssl ( void *ctx, int level, const char *str ) { (void)ctx; printf("ssl: [%d] %s\n", level, str); } static bool _openSSL ( void *ps, SSLCtx *ctx ) { ssl_set_endpoint(&ctx->ssl, SSL_IS_CLIENT); ssl_set_authmode(&ctx->ssl, SSL_VERIFY_OPTIONAL); ssl_set_ca_chain(&ctx->ssl, &ctx->cacert, NULL, NULL); /* SSLv3 is deprecated, set minimum to TLS 1.0 */ ssl_set_min_version(&ctx->ssl, SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_1); // The following is removed from newer polarssl versions #ifdef SSL_ARC4_DISABLED /* RC4 is deprecated, disable it */ ssl_set_arc4_support(&ctx->ssl, SSL_ARC4_DISABLED ); #endif ssl_set_rng(&ctx->ssl, ctr_drbg_random, &ctx->ctr_drbg); ssl_set_dbg(&ctx->ssl, traceprint_ssl, NULL); //ssl_set_ciphersuites( &ctx->ssl, ssl_default_ciphersuites); // FIXME ssl_set_bio(&ctx->ssl, net_recv, ps, net_send, ps); traceprint("SSL handshake now...\n"); int err; while( (err = ssl_handshake(&ctx->ssl)) ) { if(err != POLARSSL_ERR_NET_WANT_READ && err != POLARSSL_ERR_NET_WANT_WRITE) { traceprint("open_ssl: ssl_handshake returned -0x%x\n\n", -err); return false; } } traceprint("SSL handshake done\n"); return true; } #endif bool TcpSocket::open(const char *host, unsigned int port) { if (isOpen()) { if ((host && host != _host) || (port && port != _lastport)) close(); // ... and continue connecting to new host/port else return true; // still connected, to same host and port. } if (host) _host = host; else host = _host.c_str(); if (port) _lastport = port; else { port = _lastport; if (!port) return false; } traceprint("TcpSocket::open(): host = [%s], port = %d\n", host, port); assert(!SOCKETVALID(_s)); _recvSize = 0; { SOCKET s; if (!_openSocket(&s, host, port)) return false; _s = s; #ifdef SO_NOSIGPIPE // Don't fire SIGPIPE when trying to write to a closed socket { int set = 1; setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *) &set, sizeof(int)); } #endif } _SetNonBlocking(_s, _nonblocking); // restore setting if it was set in invalid state. static call because _s is intentionally still invalid here. #ifdef MINIHTTP_USE_POLARSSL if(_sslctx) { traceprint("TcpSocket::open(): SSL requested...\n"); if(!_openSSL(&_s, (SSLCtx*)_sslctx)) { close(); return false; } } #endif _OnOpen(); return true; } #ifdef MINIHTTP_USE_POLARSSL void TcpSocket::shutdownSSL ( ) { delete ((SSLCtx*)_sslctx); _sslctx = NULL; } bool TcpSocket::initSSL ( const char *certs ) { SSLCtx *ctx = (SSLCtx*)_sslctx; if(ctx) ctx->reset(); else { ctx = new SSLCtx(); _sslctx = ctx; if(!ctx->init()) { shutdownSSL(); return false; } } if(certs) { int err = x509_crt_parse(&ctx->cacert, (const unsigned char*)certs, strlen(certs)); if(err) { shutdownSSL(); traceprint("x509_crt_parse() returned %d\n", err); return false; } } return true; } SSLResult TcpSocket::verifySSL ( ) { if(!_sslctx) return SSLR_NO_SSL; SSLCtx *ctx = (SSLCtx*)_sslctx; unsigned r = SSLR_OK; int res = ssl_get_verify_result(&ctx->ssl); if(res) { if(res & BADCERT_EXPIRED) r |= SSLR_CERT_EXPIRED; if(res & BADCERT_REVOKED) r |= SSLR_CERT_REVOKED; if(res & BADCERT_CN_MISMATCH) r |= SSLR_CERT_CN_MISMATCH; if(res & BADCERT_NOT_TRUSTED) r |= SSLR_CERT_NOT_TRUSTED; if(res & BADCERT_MISSING) r |= SSLR_CERT_MISSING; if(res & BADCERT_SKIP_VERIFY) r |= SSLR_CERT_SKIP_VERIFY; if(res & BADCERT_FUTURE) r |= SSLR_CERT_FUTURE; // More than just this? if(res & (BADCERT_SKIP_VERIFY | SSLR_CERT_NOT_TRUSTED)) r |= SSLR_FAIL; } return (SSLResult)r; } #else // MINIHTTP_USE_POLARSSL void TcpSocket::shutdownSSL() { } bool TcpSocket::initSSL(const char *certs) { traceprint("initSSL: Compiled without SSL support!"); return false; } SSLResult TcpSocket::verifySSL() { return SSLR_NO_SSL; } #endif bool TcpSocket::SendBytes(const void *str, unsigned int len) { if (!len) return true; if (!SOCKETVALID(_s)) return false; //traceprint("SEND: '%s'\n", str); unsigned written = 0; while (true) // FIXME: buffer bytes to an internal queue instead? { int ret = _writeBytes((const unsigned char*) str + written, len - written); if (ret > 0) { assert((unsigned )ret <= len); written += (unsigned) ret; if (written >= len) break; } else if (ret < 0) { #ifdef _DEBUG int err = ret == -1 ? _GetError() : ret; traceprint("SendBytes: error %d: %s\n", err, _GetErrorStr(err).c_str()); #endif close(); return false; } // and if ret == 0, keep trying. } assert(written == len); return true; } int TcpSocket::_writeBytes(const unsigned char *buf, size_t len) { int ret = 0; #ifdef MINIHTTP_USE_POLARSSL int err; if(_sslctx) err = ssl_write(&((SSLCtx*)_sslctx)->ssl, buf, len); else err = net_send(&_s, buf, len); switch(err) { case POLARSSL_ERR_NET_WANT_WRITE: ret = 0; // FIXME: Nothing written, try later? default: ret = err; } #else int flags = 0; #ifdef MSG_NOSIGNAL flags |= MSG_NOSIGNAL; #endif return ::send(_s, (const char*) buf, len, flags); #endif return ret; } void TcpSocket::_ShiftBuffer() { size_t by = _readptr - _inbuf; memmove(_inbuf, _readptr, by); _readptr = _inbuf; _writeptr = _inbuf + by; _writeSize = _inbufSize - by - 1; } void TcpSocket::_OnData() { _OnRecv(_readptr, _recvSize); } int TcpSocket::_readBytes(unsigned char *buf, size_t maxlen) { #ifdef MINIHTTP_USE_POLARSSL if(_sslctx) return ssl_read(&((SSLCtx*)_sslctx)->ssl, buf, maxlen); else return net_recv(&_s, buf, maxlen); #else return recv(_s, (char*) buf, maxlen, 0); // last char is used as string terminator #endif } bool TcpSocket::update() { if (!_OnUpdate()) return false; if (!isOpen()) return false; if (!_inbuf) SetBufsizeIn(DEFAULT_BUFSIZE); int bytes = _readBytes((unsigned char*) _writeptr, _writeSize); //traceprint("TcpSocket::update: _readBytes() result %d\n", bytes); if (bytes > 0) // we received something { _inbuf[bytes] = 0; _recvSize = bytes; // reset pointers for next read _writeSize = _inbufSize - 1; _readptr = _writeptr = _inbuf; _OnData(); } else if (bytes == 0) // remote has closed the connection { close(); } else // whoops, error? { // Possible that the error is returned directly (in that case, < -1, or -1 is returned and the error has to be retrieved seperately. // But in the latter case, error numbers may be positive (at least on windows...) int err = bytes == -1 ? _GetError() : bytes; switch (err) { case EWOULDBLOCK: #if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN) case EAGAIN: // linux man pages say this can also happen instead of EWOULDBLOCK #endif return false; #ifdef MINIHTTP_USE_POLARSSL case POLARSSL_ERR_NET_WANT_READ: break; // Try again later #endif default: traceprint("SOCKET UPDATE ERROR: (%d): %s\n", err, _GetErrorStr(err).c_str()) ; case ECONNRESET: case ENOTCONN: case ETIMEDOUT: #ifdef _WIN32 case WSAECONNABORTED: case WSAESHUTDOWN: #endif close(); break; } } return true; } // ========================== // ===== HTTP SPECIFIC ====== // ========================== #ifdef MINIHTTP_SUPPORT_HTTP POST& POST::add(const char *key, const char *value) { if (!empty()) data += '&'; URLEncode(key, data); data += '='; URLEncode(value, data); return *this; } HttpSocket::HttpSocket() : TcpSocket(), _user_agent("OpenZWave"), _accept_encoding(), _tmpHdr(), _keep_alive(0), _remaining(0), _contentLen(0), _status(0), _inProgress(false), _chunkedTransfer(false), _mustClose(true), _followRedir(true), _alwaysHandle(false), _filename(), _pFile(NULL) { } HttpSocket::~HttpSocket() { } void HttpSocket::_OnOpen() { TcpSocket::_OnOpen(); _chunkedTransfer = false; _mustClose = true; } void HttpSocket::_OnCloseInternal() { if (!IsRedirecting() || _alwaysHandle) _OnClose(); } bool HttpSocket::_OnUpdate() { if (!TcpSocket::_OnUpdate()) return false; if (_inProgress && !_chunkedTransfer && !_remaining && _status) _FinishRequest(); //traceprint("HttpSocket::_OnUpdate, Q = %d\n", (unsigned)_requestQ.size()); // initiate transfer if queue is not empty, but the socket somehow forgot to proceed if (_requestQ.size() && !_remaining && !_chunkedTransfer && !_inProgress) _DequeueMore(); return true; } bool HttpSocket::Download(const std::string& url, const char *extraRequest, void *user, const POST *post) { if (_filename.length() == 0) { traceprint("No Filename Set\n"); return false; } Request req; req.user = user; if (post) req.post = *post; SplitURI(url, req.protocol, req.host, req.resource, req.port, req.useSSL); if (IsRedirecting() && req.host.empty()) // if we're following a redirection to the same host, the server is likely to omit its hostname req.host = _curRequest.host; if (req.port < 0) req.port = req.useSSL ? 443 : 80; if (extraRequest) req.extraGetHeaders = extraRequest; return SendRequest(req, false); } bool HttpSocket::_Redirect(std::string loc, bool forceGET) { traceprint("Following HTTP redirect to: %s\n", loc.c_str()); if (loc.empty()) return false; Request req; req.user = _curRequest.user; req.useSSL = _curRequest.useSSL; if (!forceGET) req.post = _curRequest.post; SplitURI(loc, req.protocol, req.host, req.resource, req.port, req.useSSL); if (req.protocol.empty()) // assume local resource { req.host = _curRequest.host; req.resource = loc; } if (req.host.empty()) req.host = _curRequest.host; if (req.port < 0) req.port = _curRequest.port; req.extraGetHeaders = _curRequest.extraGetHeaders; return SendRequest(req, false); } bool HttpSocket::SendRequest(const std::string what, const char *extraRequest, void *user) { Request req(what, _host, _lastport, user); if (extraRequest) req.extraGetHeaders = extraRequest; return SendRequest(req, false); } bool HttpSocket::QueueRequest(const std::string what, const char *extraRequest, void *user) { Request req(what, _host, _lastport, user); if (extraRequest) req.extraGetHeaders = extraRequest; return SendRequest(req, true); } bool HttpSocket::SendRequest(Request& req, bool enqueue) { if (req.host.empty() || !req.port) return false; const bool post = !req.post.empty(); std::stringstream r; const char *crlf = "\r\n"; r << (post ? "POST " : "GET ") << req.resource << " HTTP/1.1" << crlf; r << "Host: " << req.host << crlf; if (_keep_alive) { r << "Connection: Keep-Alive" << crlf; r << "Keep-Alive: " << _keep_alive << crlf; } else r << "Connection: close" << crlf; if (_user_agent.length()) r << "User-Agent: " << _user_agent << crlf; if (_accept_encoding.length()) r << "Accept-Encoding: " << _accept_encoding << crlf; if (post) { r << "Content-Length: " << req.post.length() << crlf; r << "Content-Type: application/x-www-form-urlencoded" << crlf; } if (req.extraGetHeaders.length()) { r << req.extraGetHeaders; if (req.extraGetHeaders.compare(req.extraGetHeaders.length() - 2, std::string::npos, crlf)) r << crlf; } r << crlf; // header terminator // FIXME: appending this to the 'header' field is probably not a good idea if (post) r << req.post.str(); req.header = r.str(); return _EnqueueOrSend(req, enqueue); } bool HttpSocket::_EnqueueOrSend(const Request& req, bool forceQueue) { traceprint("HttpSocket::_EnqueueOrSend, forceQueue = %d\n", forceQueue); if (_inProgress || forceQueue) // do not send while receiving other data { traceprint("HTTP: Transfer pending; putting into queue. Now %u waiting.\n", (unsigned int)_requestQ.size()); _requestQ.push(req); return true; } // ok, we can send directly traceprint("HTTP: Open request for immediate send.\n"); if (!_OpenRequest(req)) return false; bool sent = SendBytes(req.header.c_str(), req.header.length()); _inProgress = sent; return sent; } // called whenever a request is finished completely and the socket checks for more things to send void HttpSocket::_DequeueMore() { traceprint("HttpSocket::_DequeueMore, Q = %u\n", (unsigned)_requestQ.size()); _FinishRequest(); // In case this was not done yet. // _inProgress is known to be false here if (_requestQ.size()) // still have other requests queued? if (_EnqueueOrSend(_requestQ.front(), false)) // could we send? _requestQ.pop(); // if so, we are done with this request // otherwise, we are done for now. socket is kept alive for future sends. Nothing to do. } bool HttpSocket::_OpenRequest(const Request& req) { if (_inProgress) { traceprint("HttpSocket::_OpenRequest(): _inProgress == true, should not be called."); return false; } if (req.useSSL && !hasSSL()) { traceprint("HttpSocket::_OpenRequest(): Is an SSL connection, but SSL was not inited, doing that now\n"); if (!initSSL(NULL)) // FIXME: supply cert list? { traceprint("FAILED to init SSL"); return false; } } if (!open(req.host.c_str(), req.port)) return false; _inProgress = true; _curRequest = req; _status = 0; return true; } void HttpSocket::_FinishRequest() { traceprint("HttpSocket::_FinishRequest\n"); if (_inProgress) { traceprint("... in progress. redirecting = %d\n", IsRedirecting()); if (!IsRedirecting() || _alwaysHandle) _OnRequestDone(); // notify about finished request _inProgress = false; _hdrs.clear(); if (_mustClose) close(); } } void HttpSocket::_ProcessChunk() { if (!_chunkedTransfer) return; unsigned int chunksize = -1; while (true) { // less data required until chunk end than received, means the new chunk starts somewhere in the middle // of the received data block. finish this chunk first. if (_remaining) { if (_remaining <= _recvSize) // it contains the rest of the chunk, including CRLF { _OnRecvInternal(_readptr, _remaining - 2); // implicitly skip CRLF _readptr += _remaining; _recvSize -= _remaining; _remaining = 0; // done with this one. if (!chunksize) // and if chunksize was 0, we are done with all chunks. break; } else // buffer did not yet arrive completely { _OnRecvInternal(_readptr, _recvSize); _remaining -= _recvSize; _recvSize = 0; // done with the whole buffer, but not with the chunk return; // nothing else to do here } } // each chunk identifier ends with CRLF. // if we don't find that, we hit the corner case that the chunk identifier was not fully received. // in that case, adjust the buffer and wait for the rest of the data to be appended char *term = strstr(_readptr, "\r\n"); if (!term) { if (_recvSize) // if there is still something queued, move it to the left of the buffer and append on next read _ShiftBuffer(); return; } term += 2; // skip CRLF // when we are here, the (next) chunk header was completely received. chunksize = strtoul(_readptr, NULL, 16); _remaining = chunksize + 2; // the http protocol specifies that each chunk has a trailing CRLF _recvSize -= (term - _readptr); _readptr = term; } if (!chunksize) // this was the last chunk, no further data expected unless requested { _chunkedTransfer = false; _DequeueMore(); if (_recvSize) traceprint("_ProcessChunk: There are %u bytes left in the buffer, huh?\n", _recvSize); if (_mustClose) close(); } } void HttpSocket::_ParseHeaderFields(const char *s, size_t size) { // Key: Value data\r\n const char * const maxs = s + size; while (s < maxs) { while (isspace(*s)) { ++s; if (s >= maxs) return; } const char * const colon = strchr(s, ':'); if (!colon) return; const char *valEnd = strchr(colon, '\n'); // last char of val data if (!valEnd) return; while (valEnd[-1] == '\n' || valEnd[-1] == '\r') // skip backwards if necessary --valEnd; const char *val = colon + 1; // value starts after ':' ... while (isspace(*val) && val < valEnd) // skip spaces after the colon ++val; std::string key(s, colon - s); key = ToLower(key); std::string valstr(val, valEnd - val); _hdrs[key] = valstr; traceprint("HDR: %s: %s\n", key.c_str(), valstr.c_str()); s = valEnd; } } const char *HttpSocket::Hdr(const char *h) const { std::map::const_iterator it = _hdrs.find(h); return it == _hdrs.end() ? NULL : it->second.c_str(); } static int safeatoi(const char *s) { return s ? atoi(s) : 0; } bool HttpSocket::_HandleStatus() { _remaining = _contentLen = safeatoi(Hdr("content-length")); const char *encoding = Hdr("transfer-encoding"); _chunkedTransfer = encoding && !STRNICMP(encoding, "chunked", 7); const char *conn = Hdr("connection"); // if its not keep-alive, server will close it, so we can too _mustClose = !conn || STRNICMP(conn, "keep-alive", 10); const bool success = IsSuccess(); if (!(_chunkedTransfer || _contentLen) && success) traceprint("_ParseHeader: Not chunked transfer and content-length==0, this will go fail"); traceprint("Got HTTP Status %d\n", _status); if (success) return true; bool forceGET = false; switch (_status) { case 303: forceGET = true; // As per spec, continue with a GET request case 301: case 302: case 307: case 308: if (_followRedir) if (const char *loc = Hdr("location")) _Redirect(loc, forceGET); return false; default: return false; } } bool HttpSocket::IsRedirecting() const { switch (_status) { case 301: case 302: case 303: case 307: case 308: return true; } return false; } bool HttpSocket::IsSuccess() const { const unsigned s = _status; return s >= 200 && s <= 205; } void HttpSocket::_ParseHeader() { _tmpHdr += _inbuf; const char *hptr = _tmpHdr.c_str(); if ((_recvSize >= 5 || _tmpHdr.size() >= 5) && memcmp("HTTP/", hptr, 5)) { traceprint("_ParseHeader: not HTTP stream\n"); return; } const char *hdrend = strstr(hptr, "\r\n\r\n"); if (!hdrend) { traceprint("_ParseHeader: could not find end-of-header marker, or incomplete buf; delaying.\n"); return; } //traceprint(hptr); hptr = strchr(hptr + 5, ' '); // skip "HTTP/", already known if (!hptr) return; // WTF? ++hptr; // number behind first space is the status code _status = atoi(hptr); // Default values _chunkedTransfer = false; _contentLen = 0; // yet unknown hptr = strstr(hptr, "\r\n"); _ParseHeaderFields(hptr + 2, hdrend - hptr); // FIXME: return value indicates success. // Bail out on non-success, or at least make it so that _OnRecv() is not called. // (Unless an override bool is given that even non-successful answers get their data delivered!) _HandleStatus(); // get ready _readptr = strstr(_inbuf, "\r\n\r\n") + 4; // skip double newline. must have been found in hptr earlier. _recvSize -= (_readptr - _inbuf); // skip the header part _tmpHdr.clear(); } // generic http header parsing void HttpSocket::_OnData() { if (!(_chunkedTransfer || (_remaining && _recvSize))) _ParseHeader(); if (_chunkedTransfer) { _ProcessChunk(); // first, try to finish one or more chunks } else if (_remaining && _recvSize) // something remaining? if so, we got a header earlier, but not all data { _remaining -= _recvSize; _OnRecvInternal(_readptr, _recvSize); if (int(_remaining) < 0) { traceprint("_OnRecv: _remaining wrap-around, huh??\n"); _remaining = 0; } if (!_remaining) // received last block? { if (_mustClose) close(); else _DequeueMore(); } // nothing else to do here. } // otherwise, the server sent just the header, with the data following in the next packet } void HttpSocket::_OnRecv(void *buf, unsigned int size) { if (!size) return; if (!_pFile) { _pFile = fopen(_filename.c_str(), "w"); } if (!_pFile) { Log::Write(LogLevel_Error, "Failed to open file %s: %s", _filename.c_str(), strerror(errno)); return; } fwrite(buf, size, 1, _pFile); } void HttpSocket::_OnClose() { if (!ExpectMoreData()) _FinishRequest(); if (_pFile) { fclose(_pFile); _pFile = NULL; } } void HttpSocket::_OnRecvInternal(void *buf, unsigned int size) { if (IsSuccess() || _alwaysHandle) _OnRecv(buf, size); } #endif // =========================== // ===== SOCKET SET ========== // =========================== #ifdef MINIHTTP_SUPPORT_SOCKET_SET SocketSet::~SocketSet() { deleteAll(); } void SocketSet::deleteAll() { for (Store::iterator it = _store.begin(); it != _store.end(); ++it) delete it->first; _store.clear(); } bool SocketSet::update() { bool interesting = false; Store::iterator it = _store.begin(); for (; it != _store.end();) { TcpSocket *sock = it->first; SocketSetData& sdata = it->second; interesting = sock->update() || interesting; if (sdata.deleteWhenDone && !sock->isOpen() && !sock->HasPendingTask()) { traceprint("Delete socket\n"); delete sock; it = _store.erase(it); } else ++it; } return interesting; } void SocketSet::remove(TcpSocket *s) { _store.erase(s); } void SocketSet::add(TcpSocket *s, bool deleteWhenDone) { s->SetNonBlocking(true); SocketSetData sdata; sdata.deleteWhenDone = deleteWhenDone; _store[s] = sdata; } #endif } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/winRT/0000777000175200017520000000000014032143201015232 500000000000000openzwave-1.6.1914/cpp/src/platform/winRT/WaitImpl.h0000644000175200017520000000416714032142455017067 00000000000000//----------------------------------------------------------------------------- // // WaitImpl.h // // WinRT implementation of a base class for objects we // want to be able to wait for. // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _WaitImpl_H #define _WaitImpl_H #include #include #include "Defs.h" #include "platform/Ref.h" #include "platform/Wait.h" namespace OpenZWave { namespace Internal { namespace Platform { /** \brief Windows specific implementation of Wait objects. */ class WaitImpl { private: friend class Wait; WaitImpl(Wait* _owner); virtual ~WaitImpl(); void AddWatcher(Wait::pfnWaitNotification_t _callback, void* _context); bool RemoveWatcher(Wait::pfnWaitNotification_t _callback, void* _context); void Notify(); static int32 Multiple(Wait** _objects, uint32 _numObjects, int32 _timeout = -1); WaitImpl(Wait const&); // prevent copy WaitImpl& operator =(WaitImpl const&); // prevent assignment struct Watcher { Wait::pfnWaitNotification_t m_callback; void* m_context; }; list m_watchers; Wait* m_owner; CRITICAL_SECTION m_criticalSection; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_WaitImpl_H openzwave-1.6.1914/cpp/src/platform/winRT/DNSImpl.h0000644000175200017520000000260014032142455016575 00000000000000//----------------------------------------------------------------------------- // // DNSImpl.h // // Windows DNS Lookup Routines. // // Copyright (c) 2016 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _DNSImpl_H #define _DNSImpl_H #include "Defs.h" #include "platform/DNS.h" namespace OpenZWave { namespace Internal { namespace Platform { class DNSImpl { public: DNSImpl(); virtual ~DNSImpl(); virtual bool LookupTxT(string, string &); DNSError status; private: }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/platform/winRT/MutexImpl.cpp0000644000175200017520000000616314032142455017616 00000000000000//----------------------------------------------------------------------------- // // MutexImpl.cpp // // WinRT implementation of the cross-platform mutex // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "MutexImpl.h" namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- MutexImpl::MutexImpl() : m_lockCount(0) { InitializeCriticalSectionEx(&m_criticalSection, 0, 0); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- MutexImpl::~MutexImpl() { DeleteCriticalSection(&m_criticalSection); } //----------------------------------------------------------------------------- // // Lock the mutex //----------------------------------------------------------------------------- bool MutexImpl::Lock(bool const _bWait // = true; ) { if (_bWait) { // We will wait for the lock EnterCriticalSection(&m_criticalSection); ++m_lockCount; return true; } // Returns immediately, even if the lock was not available. if (TryEnterCriticalSection(&m_criticalSection)) { ++m_lockCount; return true; } return false; } //----------------------------------------------------------------------------- // // Release our lock on the mutex //----------------------------------------------------------------------------- void MutexImpl::Unlock() { if (!m_lockCount) { // No locks - we have a mismatched lock/release pair assert(0); } else { --m_lockCount; LeaveCriticalSection(&m_criticalSection); } } //----------------------------------------------------------------------------- // // Test whether the mutex is free //----------------------------------------------------------------------------- bool MutexImpl::IsSignalled() { return (0 == m_lockCount); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/winRT/DNSImpl.cpp0000644000175200017520000000412514032142455017134 00000000000000//----------------------------------------------------------------------------- // // DNSImpl.cpp // // Windows DNS Lookup Routines. // // Copyright (c) 2016 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include #include #include "DNSImpl.h" namespace OpenZWave { namespace Internal { namespace Platform { DNSImpl::DNSImpl() { } DNSImpl::~DNSImpl() { } bool DNSImpl::LookupTxT(string lookup, string &result) { #if 0 PDNS_RECORD qr, rp; DNS_STATUS rc; rc = DnsQuery(lookup.c_str(), DNS_TYPE_TEXT, DNS_QUERY_STANDARD, NULL, &qr, NULL); if (rc != ERROR_SUCCESS) { Log::Write(LogLevel_Warning, "Error looking up txt Record: %s - %d", lookup.c_str(), rc); status = DNSError_InternaError; return false; } for (rp = qr; rp != NULL; rp = rp->pNext) { if (rp->wType == DNS_TYPE_TEXT) { result = rp->Data.TXT.pStringArray[0]; status = DNSError_None; break; } } DnsRecordListFree(qr, DnsFreeRecordList); return true; #endif Log::Write(LogLevel_Error, "DNS Lookups Not Implemented on WinRT Platform"); status = DNSError_InternalError; return false; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/winRT/FileOpsImpl.cpp0000644000175200017520000001274414032142455020057 00000000000000//----------------------------------------------------------------------------- // // FileOpsImpl.cpp // // WinRT implementation of file operations // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "FileOpsImpl.h" #include "Utils.h" namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- FileOpsImpl::FileOpsImpl() { } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- FileOpsImpl::~FileOpsImpl() { } //----------------------------------------------------------------------------- // // Determine if a folder exists and is accessible by the calling App //----------------------------------------------------------------------------- bool FileOpsImpl::FolderExists(const string &_folderName) { WIN32_FILE_ATTRIBUTE_DATA fad = { 0 }; wstring wFolderName(_folderName.begin(), _folderName.end()); if (0 == GetFileAttributesEx(wFolderName.c_str(), GetFileExInfoStandard, &fad)) return false; return (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false; } bool FileOpsImpl::FileExists(const string _filename) { WIN32_FILE_ATTRIBUTE_DATA fad = { 0 }; wstring wFileName(_filename.begin(), _filename.end()); if (0 == GetFileAttributesEx(wFileName.c_str(), GetFileExInfoStandard, &fad)) return false; return (fad.dwFileAttributes != INVALID_FILE_ATTRIBUTES && !(fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); } bool FileOpsImpl::FileWriteable(const string _filename) { WIN32_FILE_ATTRIBUTE_DATA fad = { 0 }; if (!FileExists(_filename)) { /* check if the directory is writtable */ wstring wFileName(ozwdirname(_filename).begin(), ozwdirname(_filename).end()); if (0 == GetFileAttributesEx(wFileName.c_str(), GetFileExInfoStandard, &fad)) return false; } else { wstring wFileName(_filename.begin(), _filename.end()); if (0 == GetFileAttributesEx(wFileName.c_str(), GetFileExInfoStandard, &fad)) return false; } return (fad.dwFileAttributes != INVALID_FILE_ATTRIBUTES && !(fad.dwFileAttributes & FILE_ATTRIBUTE_READONLY)); } bool FileOpsImpl::FileRotate(const string _filename) { int i = 1; string newFile; /* find a filename not used yet */ newFile = _filename; newFile.append(".").append(intToString(i)); while (FileExists(newFile)) { i++; newFile = _filename; newFile.append(".").append(intToString(i)); } /* copy the file */ if (!FileCopy(_filename, newFile)) { Log::Write(LogLevel_Warning, "File Rotate Failed: %s -> %s", _filename.c_str(), newFile.c_str()); return false; } /* remove the old file */ if (DeleteFileA(_filename.c_str()) == 0) { Log::Write(LogLevel_Warning, "File Removal failed: %s", _filename.c_str()); return false; } return true; } bool FileOpsImpl::FileCopy(const string _sourcefile, const string _destfile) { if (!FileExists(_sourcefile)) { Log::Write(LogLevel_Warning, "Source File %s doesn't exist in FileCopy", _sourcefile.c_str()); return false; } if (FileExists(_destfile)) { Log::Write(LogLevel_Warning, "Destination File %s exists in FileCopy", _destfile.c_str()); return false; } /* make sure the Destination Folder Exists */ if (!FolderExists(ozwdirname(_destfile))) { Log::Write(LogLevel_Warning, "Destination Folder %s Doesn't Exist", ozwdirname(_destfile)); return false; } wstring wSrcFileName(_sourcefile.begin(), _sourcefile.end()); wstring wDstFileName(_destfile.begin(), _destfile.end()); if (CopyFile2(wSrcFileName.c_str(), wDstFileName.c_str(), FALSE) == 0) { Log::Write(LogLevel_Warning, "CopyFile Failed %s - %s", _sourcefile.c_str(), _destfile.c_str()); return false; } return true; } bool FileOpsImpl::FolderCreate(const string _dirname) { if (FolderExists(_dirname)) { Log::Write(LogLevel_Warning, "Folder %s Exists for FolderCreate", _dirname.c_str()); return false; } if (CreateDirectoryA(_dirname.c_str(), NULL) == 0) { Log::Write(LogLevel_Warning, "Create Directory Failed: %s", _dirname.c_str()); return false; } return true; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/winRT/ThreadImpl.h0000644000175200017520000000400314032142455017357 00000000000000//----------------------------------------------------------------------------- // // ThreadImpl.h // // WinRT implementation of a cross-platform thread // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ThreadImpl_H #define _ThreadImpl_H #include #include #include "platform/Thread.h" #include namespace OpenZWave { namespace Internal { namespace Platform { class Thread; class Event; /** \brief Windows-specific implementation of the Thread class. */ class ThreadImpl { private: friend class Thread; ThreadImpl(Thread* _owner, string const& _name); ~ThreadImpl(); bool Start(Thread::pfnThreadProc_t _pfnThreadProc, Event* _exitEvent, void* _context); void Sleep(uint32 _milliseconds); bool Terminate(); bool IsSignalled(); void Run();static DWORD WINAPI ThreadProc( void* _pArg ); Thread* m_owner; Event* m_exitEvent; Thread::pfnThreadProc_t m_pfnThreadProc; void* m_context; bool m_bIsRunning; string m_name; static int32 s_threadTerminateTimeout; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_ThreadImpl_H openzwave-1.6.1914/cpp/src/platform/winRT/FileOpsImpl.h0000644000175200017520000000331514032142455017516 00000000000000//----------------------------------------------------------------------------- // // FileOpsImpl.h // // WinRT implementation of file operations // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _FileOpsImpl_H #define _FileOpsImpl_H #include #include #include "Defs.h" #include "platform/FileOps.h" namespace OpenZWave { namespace Internal { namespace Platform { class FileOpsImpl { friend class FileOps; private: FileOpsImpl(); ~FileOpsImpl(); bool FolderExists(const string &_filename); bool FileExists(const string _filename); bool FileWriteable(const string _filename); bool FileRotate(const string _filename); bool FileCopy(const string, const string); bool FolderCreate(const string _dirname); }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_FileOpsImpl_H openzwave-1.6.1914/cpp/src/platform/winRT/MutexImpl.h0000644000175200017520000000324514032142455017261 00000000000000//----------------------------------------------------------------------------- // // MutexImpl.h // // WinRT implementation of the cross-platform mutex // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _MutexImpl_H #define _MutexImpl_H #include namespace OpenZWave { namespace Internal { namespace Platform { /** \brief Windows-specific implementation of the Mutex class. */ class MutexImpl { private: friend class Mutex; MutexImpl(); ~MutexImpl(); bool Lock(bool const _bWait = true); void Unlock(); bool IsSignalled(); CRITICAL_SECTION m_criticalSection; uint32 m_lockCount; // Keep track of the locks (there can be more than one if they occur on the same thread. }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_MutexIF_H openzwave-1.6.1914/cpp/src/platform/winRT/EventImpl.cpp0000644000175200017520000000612614032142455017574 00000000000000//----------------------------------------------------------------------------- // // EventImpl.cpp // // WinRT implementation of a cross-platform event // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "Defs.h" #include "EventImpl.h" namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- EventImpl::EventImpl() { // Create a manual reset event m_hEvent = ::CreateEventEx( NULL, NULL, CREATE_EVENT_MANUAL_RESET, SYNCHRONIZE | EVENT_MODIFY_STATE); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- EventImpl::~EventImpl() { ::CloseHandle(m_hEvent); } //----------------------------------------------------------------------------- // // Set the event to signalled //----------------------------------------------------------------------------- void EventImpl::Set() { ::SetEvent(m_hEvent); } //----------------------------------------------------------------------------- // // Set the event to not signalled //----------------------------------------------------------------------------- void EventImpl::Reset() { ::ResetEvent(m_hEvent); } //----------------------------------------------------------------------------- // // Test whether the event is set //----------------------------------------------------------------------------- bool EventImpl::IsSignalled() { return (WAIT_OBJECT_0 == WaitForSingleObjectEx(m_hEvent, 0, FALSE)); } //----------------------------------------------------------------------------- // // Wait for the event to become signalled //----------------------------------------------------------------------------- bool EventImpl::Wait(int32 const _timeout) { return (WAIT_TIMEOUT != ::WaitForSingleObjectEx(m_hEvent, (DWORD) _timeout, FALSE)); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/winRT/HidControllerWinRT.cpp0000644000175200017520000002107714032142455021367 00000000000000//----------------------------------------------------------------------------- // // HidControllerWinRT.cpp // // WinRT implementation of a HidController // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "HidControllerWinRT.h" #include "platform/Log.h" #include #include namespace OpenZWave { namespace Internal { namespace Platform { using namespace Windows::Devices::Enumeration; using namespace Windows::Devices::HumanInterfaceDevice; using namespace Windows::Devices::Usb; using namespace Windows::Foundation; using namespace Windows::Storage::Streams; using namespace Platform; using namespace Concurrency; #define AQS_FORMAT L"System.Devices.InterfaceClassGuid:=\"{4D1E55B2-F16F-11CF-88CB-001111000030}\" AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True AND System.DeviceInterface.Hid.VendorId:=%04d AND System.DeviceInterface.Hid.ProductId:=%04d" #define AQS_LENGTH 300 //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- HidController::HidController() : m_vendorId(0x1b5f), // Wayne Dalton m_productId(0x01), // ControlThink ThinkStick m_serialNumber(""), m_hidControllerName(""), m_bOpen(false) { } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- HidController::~HidController() { if (m_device != nullptr) { m_device->InputReportReceived -= m_inputReportEventToken; } } //----------------------------------------------------------------------------- // // Set the USB vendor ID search value. The HID port must be closed for the setting to be accepted. //----------------------------------------------------------------------------- bool HidController::SetVendorId(uint32 const _vendorId) { if (m_bOpen) { return false; } m_vendorId = _vendorId; return true; } //----------------------------------------------------------------------------- // // Set the USB product ID search value. The HID port must be closed for the setting to be accepted. //----------------------------------------------------------------------------- bool HidController::SetProductId(uint32 const _productId) { if (m_bOpen) { return false; } m_productId = _productId; return true; } //----------------------------------------------------------------------------- // // Set the USB serial number search value. The HID port must be closed for the setting to be accepted. //----------------------------------------------------------------------------- bool HidController::SetSerialNumber(string const& _serialNumber) { if (m_bOpen) { return false; } m_serialNumber = _serialNumber; return true; } //----------------------------------------------------------------------------- // // Open and configure a HID port //----------------------------------------------------------------------------- bool HidController::Open(string const& _hidControllerName) { if (m_bOpen) { return false; } m_hidControllerName = _hidControllerName; bool success = false; try { create_task(Init()).then([&success, this](bool initResult) { success = initResult; if (success && m_device != nullptr) { m_inputReportEventToken = m_device->InputReportReceived += ref new TypedEventHandler ([this](HidDevice ^sender, HidInputReportReceivedEventArgs ^args) { auto reader = DataReader::FromBuffer(args->Report->Data); uint32 bufferSize = reader->UnconsumedBufferLength; std::vector data(bufferSize); if (!data.empty()) { reader->ReadBytes(::Platform::ArrayReference(&data[0], bufferSize)); Put(&data[0], bufferSize); } }); } }).wait(); } catch (::Platform::Exception^ ex) { } return success; } //----------------------------------------------------------------------------- // // Close a HID port //----------------------------------------------------------------------------- bool HidController::Close() { if (m_device != nullptr) { m_device->InputReportReceived -= m_inputReportEventToken; delete m_device; m_device = nullptr; } return true; } //----------------------------------------------------------------------------- // // Open the HID port //----------------------------------------------------------------------------- task HidController::Init() { // Yields the same as API above w/o the usage page and usage Id filters wchar_t buffer[AQS_LENGTH]; swprintf_s(buffer, AQS_FORMAT, m_vendorId, m_productId); auto selector = ref new ::Platform::String(buffer); return create_task(Windows::Devices::Enumeration::DeviceInformation::FindAllAsync(selector)) .then([this](DeviceInformationCollection ^ devices) -> ::Platform::String ^ { ::Platform::String ^deviceId = L""; for (auto iterator = devices->First(); iterator->HasCurrent; iterator->MoveNext()) { // Not sure how to differentiate when there are multiple things returned. // Just return first matching ID for now deviceId = iterator->Current->Id; break; } return deviceId; }).then([this](::Platform::String ^deviceId) -> IAsyncOperation ^ { return HidDevice::FromIdAsync(deviceId, Windows::Storage::FileAccessMode::Read); }).then([this](task deviceTask) -> bool { try { m_device = deviceTask.get(); if (m_device == nullptr) { return false; } // Send Report ID 2 - 1 byte "0x04" // Enables ZWave packet reports on ID 4 (tx) and ID 5 (rx) uint8 data = 0x04; SendFeatureReport(&data, 1, 2); return true; } catch (::Platform::Exception^ ex) { return false; } }); } //----------------------------------------------------------------------------- // // Send data to the HID port //----------------------------------------------------------------------------- uint32 HidController::Write(uint8* _buffer, uint32 _length) { // report Id 0x04 is tx feature report return SendFeatureReport(_buffer, _length, 0x04); } //----------------------------------------------------------------------------- // // Send a feature report with the specified data and report ID //----------------------------------------------------------------------------- uint32 HidController::SendFeatureReport(uint8* _buffer, uint32 _length, unsigned short reportId) { auto featureReport = m_device->CreateFeatureReport(); auto dataWriter = ref new DataWriter(); auto array = ref new ::Platform::Array(_buffer, _length); dataWriter->WriteBytes(::Platform::ArrayReference < uint8 > (_buffer, _length)); featureReport->Data = dataWriter->DetachBuffer(); uint32 bytesWritten = 0; try { bytesWritten = create_task(m_device->SendFeatureReportAsync(featureReport)).get(); } catch (::Platform::Exception^) { } return bytesWritten; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/winRT/TimeStampImpl.h0000644000175200017520000000474314032142455020066 00000000000000//----------------------------------------------------------------------------- // // TimeStampImpl.h // // WinRT implementation of a TimeStamp // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _TimeStampImpl_H #define _TimeStampImpl_H #include "Defs.h" namespace OpenZWave { namespace Internal { namespace Platform { /** \brief Windows implementation of a timestamp. */ class TimeStampImpl { public: /** * Constructor. * Creates a TimeStampImpl object. */ TimeStampImpl(); /** * Destructor. * Destroys the TimeStampImpl object. */ ~TimeStampImpl(); /** * SetTime. Sets the timestamp to now, plus the offset in milliseconds. * \param _milliseconds positive or negative offset from * now in milliseconds. */ void SetTime(int32 _milliseconds); /** * TimeRemaining. Gets the difference between now and the timestamp * time in milliseconds. * \return milliseconds remaining until we reach the timestamp. The * return value is negative if the timestamp is in the past. */ int32 TimeRemaining(); /** * Return as as string */ string GetAsString(); /** * Overload the subtract operator to get the difference between * two timestamps in milliseconds. */ int32 operator-(TimeStampImpl const& _other); private: TimeStampImpl(TimeStampImpl const&); // prevent copy TimeStampImpl& operator =(TimeStampImpl const&); // prevent assignment int64 m_stamp; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_TimeStampImpl_H openzwave-1.6.1914/cpp/src/platform/winRT/HidControllerWinRT.h0000644000175200017520000001007114032142455021024 00000000000000//----------------------------------------------------------------------------- // // HidControllerImpl.h // // WinRT implementation of a HidController // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _HidControllerImpl_H #define _HidControllerImpl_H #include #include "Defs.h" #include "platform/Controller.h" #include namespace OpenZWave { namespace Internal { namespace Platform { class HidController: public Controller { public: /** * Constructor. * Creates an object that represents a HID port. */ HidController(); /** * Destructor. * Destroys the HID port object. */ virtual ~HidController(); /** * Set the USB vendor ID search value. The HID port must be closed for the setting to be accepted. * @param _baud Vendor ID value to match when enumerating USB HID devices. * @return True if the vendor ID value was accepted. * @see Open, Close */ bool SetVendorId(uint32 const _vendorId); /** * Set the USB product ID search value. The HID port must be closed for the setting to be accepted. * @param _parity Product ID value to match when enumerating USB HID devices. * @return True if the product ID value was accepted. * @see Open, Close */ bool SetProductId(uint32 const _productId); /** * Set the USB serial number search value. The HID port must be closed for the setting to be accepted. * @param _parity Serial number string to match when enumerating USB HID devices. If empty, any serial number will be accepted. * @return True if the serial number value was accepted. * @see Open, Close */ bool SetSerialNumber(string const& _serialNumber); /** * Open a HID port. * Attempts to open a HID port and initialize it with the specified paramters. * @param _HidControllerName The name of the port to open. For example, ttyS1 on Linux, or \\.\COM2 in Windows. * @return True if the port was opened and configured successfully. * @see Close, Read, Write */ bool Open(string const& _hidControllerName); /** * Close a HID port. * Closes the HID port. * @return True if the port was closed successfully, or false if the port was already closed, or an error occurred. * @see Open */ bool Close(); /** * Write to a HID port. * Attempts to write data to an open HID port. * @param _buffer Pointer to a block of memory containing the data to be written. * @param _length Length in bytes of the data. * @return The number of bytes written. * @see Read, Open, Close */ uint32 Write(uint8* _buffer, uint32 _length); private: uint32 SendFeatureReport(uint8* _buffer, uint32 _length, unsigned short reportId); Concurrency::task Init(); Windows::Devices::HumanInterfaceDevice::HidDevice ^ m_device; Windows::Foundation::EventRegistrationToken m_inputReportEventToken; uint32 m_vendorId; uint32 m_productId; string m_serialNumber; string m_hidControllerName; bool m_bOpen; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_HidControllerImpl_H openzwave-1.6.1914/cpp/src/platform/winRT/LogImpl.cpp0000644000175200017520000002275414032142455017241 00000000000000//----------------------------------------------------------------------------- // // LogImpl.cpp // // WinRT implementation of message and error logging // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include "Defs.h" #include "LogImpl.h" #ifdef MINGW #define vsprintf_s vsnprintf #define strcpy_s(DEST, NUM, SOURCE) strncpy(DEST, SOURCE, NUM) errno_t fopen_s(FILE** pFile, const char *filename, const char *mode) { if (!pFile) { _set_errno(EINVAL); return EINVAL; } *pFile = fopen(filename, mode); if (!*pFile) { return errno; } return 0; } #endif namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- LogImpl::LogImpl(string const& _filename, bool const _bAppendLog, bool const _bConsoleOutput, LogLevel const _saveLevel, LogLevel const _queueLevel, LogLevel const _dumpTrigger) : m_filename(_filename), // name of log file m_bAppendLog(_bAppendLog), // true to append (and not overwrite) any existing log m_bConsoleOutput(_bConsoleOutput), // true to provide a copy of output to console m_saveLevel(_saveLevel), // level of messages to log to file m_queueLevel(_queueLevel), // level of messages to log to queue m_dumpTrigger(_dumpTrigger) // dump queued messages when this level is seen { string accessType; // create an adjusted file name and timestamp string string timeStr = GetTimeStampString(); if (m_bAppendLog) { accessType = "a"; } else { accessType = "w"; } FILE* pFile; if (!fopen_s(&pFile, m_filename.c_str(), accessType.c_str())) { fprintf(pFile, "\nLogging started %s\n\n", timeStr.c_str()); fclose(pFile); } } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- LogImpl::~LogImpl() { } //----------------------------------------------------------------------------- // // Write to the log //----------------------------------------------------------------------------- void LogImpl::Write(LogLevel _logLevel, uint8 const _nodeId, char const* _format, va_list _args) { // create a timestamp string string timeStr = GetTimeStampString(); string nodeStr = GetNodeString(_nodeId); string logLevelStr = GetLogLevelString(_logLevel); // handle this message if ((_logLevel <= m_queueLevel) || (_logLevel == LogLevel_Internal)) // we're going to do something with this message... { char lineBuf[1024]; if (!_format || (_format[0] == 0)) { strcpy_s(lineBuf, 1024, ""); } else { vsprintf_s(lineBuf, sizeof(lineBuf), _format, _args); } // should this message be saved to file (and possibly written to console?) if ((_logLevel <= m_saveLevel) || (_logLevel == LogLevel_Internal)) { // save to file FILE* pFile = NULL; if (!fopen_s(&pFile, m_filename.c_str(), "a") || m_bConsoleOutput) { if (_logLevel != LogLevel_Internal) // don't add a second timestamp to display of queued messages { if (pFile != NULL) { fprintf(pFile, "%s%s%s", timeStr.c_str(), logLevelStr.c_str(), nodeStr.c_str()); } if (m_bConsoleOutput) { printf("%s%s%s", timeStr.c_str(), logLevelStr.c_str(), nodeStr.c_str()); } } // print message to file (and possibly screen) if (pFile != NULL) { fprintf(pFile, "%s", lineBuf); fprintf(pFile, "\n"); fclose(pFile); } if (m_bConsoleOutput) { printf("%s", lineBuf); printf("\n"); } } } if (_logLevel != LogLevel_Internal) { char queueBuf[1024]; string threadStr = GetThreadId(); sprintf_s(queueBuf, sizeof(queueBuf), "%s%s%s", timeStr.c_str(), threadStr.c_str(), lineBuf); Queue(queueBuf); } } // now check to see if the _dumpTrigger has been hit if ((_logLevel <= m_dumpTrigger) && (_logLevel != LogLevel_Internal) && (_logLevel != LogLevel_Always)) { QueueDump(); } } //----------------------------------------------------------------------------- // // Write to the log queue //----------------------------------------------------------------------------- void LogImpl::Queue(char const* _buffer) { string bufStr = _buffer; m_logQueue.push_back(bufStr); // rudimentary queue size management if (m_logQueue.size() > 500) { m_logQueue.pop_front(); } } //----------------------------------------------------------------------------- // // Dump the LogQueue to output device //----------------------------------------------------------------------------- void LogImpl::QueueDump() { Log::Write(LogLevel_Internal, "\n\nDumping queued log messages\n"); list::iterator it = m_logQueue.begin(); while (it != m_logQueue.end()) { string strTemp = *it; Log::Write(LogLevel_Internal, strTemp.c_str()); ++it; } m_logQueue.clear(); Log::Write(LogLevel_Internal, "\nEnd of queued log message dump\n\n"); } //----------------------------------------------------------------------------- // // Clear the LogQueue //----------------------------------------------------------------------------- void LogImpl::QueueClear() { m_logQueue.clear(); } //----------------------------------------------------------------------------- // // Sets the various log state variables //----------------------------------------------------------------------------- void LogImpl::SetLoggingState(LogLevel _saveLevel, LogLevel _queueLevel, LogLevel _dumpTrigger) { m_saveLevel = _saveLevel; m_queueLevel = _queueLevel; m_dumpTrigger = _dumpTrigger; } //----------------------------------------------------------------------------- // // Generate a string with formatted current time //----------------------------------------------------------------------------- string LogImpl::GetTimeStampString() { // Get a timestamp SYSTEMTIME time; ::GetLocalTime(&time); // create a time stamp string for the log message char buf[100]; sprintf_s(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d.%03d ", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond, time.wMilliseconds); string str = buf; return str; } //----------------------------------------------------------------------------- // // Generate a string with formatted node id //----------------------------------------------------------------------------- string LogImpl::GetNodeString(uint8 const _nodeId) { if (_nodeId == 0) { return ""; } else if (_nodeId == 255) // should make distinction between broadcast and controller better for SwitchAll broadcast { return "contrlr, "; } else { char buf[20]; snprintf(buf, sizeof(buf), "Node%03d, ", _nodeId); return buf; } } //----------------------------------------------------------------------------- // // Generate a string with formatted thread id //----------------------------------------------------------------------------- string LogImpl::GetThreadId() { char buf[20]; DWORD dwThread = ::GetCurrentThreadId(); sprintf_s(buf, sizeof(buf), "%04d ", dwThread); string str = buf; return str; } //----------------------------------------------------------------------------- // // Provide a new log file name (applicable to future writes) //----------------------------------------------------------------------------- void LogImpl::SetLogFileName(const string &_filename) { m_filename = _filename; } //----------------------------------------------------------------------------- // // Provide a new log file name (applicable to future writes) //----------------------------------------------------------------------------- string LogImpl::GetLogLevelString(LogLevel _level) { if ((_level >= LogLevel_None) && (_level <= LogLevel_Internal)) { char buf[20]; snprintf(buf, sizeof(buf), "%s, ", LogLevelString[_level]); return buf; } else return "Unknown, "; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/winRT/EventImpl.h0000644000175200017520000000325614032142455017242 00000000000000//----------------------------------------------------------------------------- // // EventImpl.h // // WinRT implementation of a cross-platform event // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _EventImpl_H #define _EventImpl_H #include #include "Defs.h" namespace OpenZWave { namespace Internal { namespace Platform { /** \brief Windows-specific implementation of the Event class. */ class EventImpl { private: friend class Event; friend class SocketImpl; friend class Wait; EventImpl(); ~EventImpl(); void Set(); void Reset(); bool Wait(int32 _timeout); // The wait method is to be used only by the Wait::Multiple method bool IsSignalled(); HANDLE m_hEvent; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_EventImpl_H openzwave-1.6.1914/cpp/src/platform/winRT/TimeStampImpl.cpp0000644000175200017520000000730114032142455020412 00000000000000//----------------------------------------------------------------------------- // // TimeStampImpl.cpp // // WinRT implementation of a TimeStamp // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include "Defs.h" #include "TimeStampImpl.h" namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- TimeStampImpl::TimeStampImpl() { SetTime(0); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- TimeStampImpl::~TimeStampImpl() { } //----------------------------------------------------------------------------- // // Sets the timestamp to now, plus an offset in milliseconds //----------------------------------------------------------------------------- void TimeStampImpl::SetTime(int32 _milliseconds // = 0 ) { int64 offset = ((int64) _milliseconds) * 10000LL; // Timestamp is stored in 100ns steps. GetSystemTimeAsFileTime((FILETIME*) &m_stamp); m_stamp += offset; } //----------------------------------------------------------------------------- // // Gets the difference between now and the timestamp time in milliseconds //----------------------------------------------------------------------------- int32 TimeStampImpl::TimeRemaining() { int64 now; GetSystemTimeAsFileTime((FILETIME*) &now); return (int32) ((m_stamp - now) / 10000LL); } //----------------------------------------------------------------------------- // // Return a string representation //----------------------------------------------------------------------------- string TimeStampImpl::GetAsString() { // Convert m_stamp (FILETIME) to SYSTEMTIME for ease of use SYSTEMTIME time; ::FileTimeToSystemTime((FILETIME*) &m_stamp, &time); char buf[100]; sprintf_s(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d:%03d ", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond, time.wMilliseconds); string str = buf; return str; } //----------------------------------------------------------------------------- // // Overload the subtract operator to get the difference between two // timestamps in milliseconds //----------------------------------------------------------------------------- int32 TimeStampImpl::operator-(TimeStampImpl const& _other) { return (int32) ((m_stamp - _other.m_stamp) / 10000LL); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/winRT/SerialControllerImpl.cpp0000644000175200017520000001727314032142455022003 00000000000000//----------------------------------------------------------------------------- // // SerialControllerImpl.cpp // // WinRT Implementation of the cross-platform serial port // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "SerialControllerImpl.h" #include "platform/Log.h" #include #include namespace OpenZWave { namespace Internal { namespace Platform { using namespace Windows::Devices::SerialCommunication; using namespace Windows::Devices::Enumeration; using namespace Windows::Storage::Streams; using namespace Windows::Foundation; using namespace Concurrency; using namespace Platform; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- SerialControllerImpl::SerialControllerImpl(SerialController* _owner) : m_owner(_owner) { } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- SerialControllerImpl::~SerialControllerImpl() { Close(); } //----------------------------------------------------------------------------- // // Close the serial port //----------------------------------------------------------------------------- void SerialControllerImpl::Close() { // cancel read task m_readTaskCancelationTokenSource.cancel(); } //----------------------------------------------------------------------------- // // Open the serial port //----------------------------------------------------------------------------- bool SerialControllerImpl::Open() { Log::Write(LogLevel_Info, "Trying to open serial port %s", m_owner->m_serialControllerName.c_str()); try { auto selector = SerialDevice::GetDeviceSelector(); return create_task(DeviceInformation::FindAllAsync(selector)) .then([this](DeviceInformationCollection ^ devices) -> IAsyncOperation ^ { wstring ourId(m_owner->m_serialControllerName.begin(), m_owner->m_serialControllerName.end()); for (auto iterator = devices->First(); iterator->HasCurrent; iterator->MoveNext()) { wstring currentId = iterator->Current->Id->Data(); if (currentId.find(ourId) != wstring::npos) { return SerialDevice::FromIdAsync(iterator->Current->Id); } } return create_async([]() -> SerialDevice ^ { return nullptr;}); }).then([this](SerialDevice ^ device) -> bool { if (device == nullptr) { return false; } m_serialDevice = device; m_serialDevice->BaudRate = m_owner->m_baud; m_serialDevice->DataBits = 8; switch (m_owner->m_stopBits) { case SerialController::StopBits::StopBits_One: { m_serialDevice->StopBits = SerialStopBitCount::One; break; } case SerialController::StopBits::StopBits_OneAndAHalf: { m_serialDevice->StopBits = SerialStopBitCount::OnePointFive; break; } case SerialController::StopBits::StopBits_Two: { m_serialDevice->StopBits = SerialStopBitCount::Two; break; } } switch (m_owner->m_parity) { case SerialController::Parity::Parity_Even: { m_serialDevice->Parity = SerialParity::Even; break; } case SerialController::Parity::Parity_Mark: { m_serialDevice->Parity = SerialParity::Mark; break; } case SerialController::Parity::Parity_None: { m_serialDevice->Parity = SerialParity::None; break; } case SerialController::Parity::Parity_Odd: { m_serialDevice->Parity = SerialParity::Odd; break; } case SerialController::Parity::Parity_Space: { m_serialDevice->Parity = SerialParity::Space; break; } } Windows::Foundation::TimeSpan timespan; timespan.Duration = 1; m_serialDevice->ReadTimeout = timespan; StartReadTask(); return true; }).get(); } catch (...) { return false; } } //----------------------------------------------------------------------------- // // Start a background task which reads available data and passes it along to SerialController //----------------------------------------------------------------------------- void SerialControllerImpl::StartReadTask() { // Read serial data on background task cancellation_token token = m_readTaskCancelationTokenSource.get_token(); create_task([token, this]() { uint32 readBufferLength = 512; Buffer ^ buffer = ref new Buffer(readBufferLength); for (;;) { try { create_task(m_serialDevice->InputStream->ReadAsync(buffer, readBufferLength, InputStreamOptions::None)) .then([&, this](IBuffer ^ outBuffer) { if (token.is_canceled()) return; auto reader = DataReader::FromBuffer(outBuffer); auto bytesRead = reader->UnconsumedBufferLength; std::vector byteVector(bytesRead); if (!byteVector.empty()) { reader->ReadBytes(::Platform::ArrayReference(byteVector.data(), bytesRead)); m_owner->Put(byteVector.data(), bytesRead); } }).wait(); } catch (::Platform::Exception^ ex) { if (ex->HResult == HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED)) { m_owner->Close(); } } if (token.is_canceled()) { cancel_current_task(); } } }, token); } //----------------------------------------------------------------------------- // // Send data to the serial port //----------------------------------------------------------------------------- uint32 SerialControllerImpl::Write(uint8* _buffer, uint32 _length) { uint32 retVal = 0; if (m_serialDevice == nullptr) { //Error Log::Write(LogLevel_Error, "ERROR: Serial port must be opened before writing\n"); return 0; } DataWriter ^ writer = ref new DataWriter(); writer->WriteBytes(ref new ::Platform::Array(_buffer, _length)); try { auto writeTask = create_task(m_serialDevice->OutputStream->WriteAsync(writer->DetachBuffer())); // since the consumer of this function expects this to be synchronous, just wait here. retVal = writeTask.get(); } catch (::Platform::Exception^ ) { //ignore - return 0 retVal = 0; } return retVal; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/winRT/WaitImpl.cpp0000644000175200017520000000756114032142455017423 00000000000000//----------------------------------------------------------------------------- // // WaitImpl.cpp // // WinRT implementation of a base class for objects we // want to be able to wait for. // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "platform/Wait.h" #include "WaitImpl.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- WaitImpl::WaitImpl(Wait* _owner) : m_owner(_owner) { InitializeCriticalSectionEx(&m_criticalSection, 0, 0); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- WaitImpl::~WaitImpl() { DeleteCriticalSection(&m_criticalSection); } //----------------------------------------------------------------------------- // // Add a watcher to our object. //----------------------------------------------------------------------------- void WaitImpl::AddWatcher(Wait::pfnWaitNotification_t _callback, void* _context) { // Add the watcher to our list Watcher watcher; watcher.m_callback = _callback; watcher.m_context = _context; EnterCriticalSection(&m_criticalSection); m_watchers.push_back(watcher); LeaveCriticalSection(&m_criticalSection); // If the object is already in a signalled state, notify the watcher immediately if (m_owner->IsSignalled()) { _callback(_context); } } //----------------------------------------------------------------------------- // // Remove a watcher from our object. //----------------------------------------------------------------------------- bool WaitImpl::RemoveWatcher(Wait::pfnWaitNotification_t _callback, void* _context) { bool res = false; EnterCriticalSection(&m_criticalSection); for (list::iterator it = m_watchers.begin(); it != m_watchers.end(); ++it) { Watcher const& watcher = *it; if ((watcher.m_callback == _callback) && (watcher.m_context == _context)) { m_watchers.erase(it); res = true; break; } } LeaveCriticalSection(&m_criticalSection); return res; } //----------------------------------------------------------------------------- // // Notify all the watchers that the object has become signalled //----------------------------------------------------------------------------- void WaitImpl::Notify() { EnterCriticalSection(&m_criticalSection); for (list::iterator it = m_watchers.begin(); it != m_watchers.end(); ++it) { Watcher const& watcher = *it; watcher.m_callback(watcher.m_context); } LeaveCriticalSection(&m_criticalSection); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/winRT/ThreadImpl.cpp0000644000175200017520000001031414032142455017714 00000000000000//----------------------------------------------------------------------------- // // ThreadImpl.cpp // // WinRT implementation of a cross-platform thread // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "platform/Event.h" #include "platform/Thread.h" #include "ThreadImpl.h" #include "Options.h" namespace OpenZWave { namespace Internal { namespace Platform { using namespace Concurrency; using namespace Windows::Foundation; using namespace Windows::System::Threading; int32 ThreadImpl::s_threadTerminateTimeout = -1; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ThreadImpl::ThreadImpl(Thread* _owner, string const& _name) : m_owner(_owner), m_bIsRunning(false), m_name(_name) { static bool staticsInitialized = false; if (!staticsInitialized) { if (Options::Get() != nullptr) { Options::Get()->GetOptionAsInt("ThreadTerminateTimeout", &s_threadTerminateTimeout); } staticsInitialized = true; } } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- ThreadImpl::~ThreadImpl() { } //----------------------------------------------------------------------------- // // Start a function running on this thread //----------------------------------------------------------------------------- bool ThreadImpl::Start(Thread::pfnThreadProc_t _pfnThreadProc, Event* _exitEvent, void* _context) { // Create a thread to run the specified function m_pfnThreadProc = _pfnThreadProc; m_context = _context; m_exitEvent = _exitEvent; m_exitEvent->Reset(); create_task([this]() { m_bIsRunning = true; try { m_pfnThreadProc(m_exitEvent, m_context); } catch (::Platform::Exception^) { } m_bIsRunning = false; // Let any watchers know that the thread has finished running. m_owner->Notify(); }); return true; } //----------------------------------------------------------------------------- // // Cause thread to sleep for the specified number of milliseconds //----------------------------------------------------------------------------- void ThreadImpl::Sleep(uint32 _millisecs) { ::Sleep(_millisecs); } //----------------------------------------------------------------------------- // // Force the thread to stop //----------------------------------------------------------------------------- bool ThreadImpl::Terminate() { // No way to do this on WinRT, so give the thread a bit of extra time to exit on its own if (!m_bIsRunning) { return false; } if (Wait::Single(m_owner, s_threadTerminateTimeout) < 0) { return false; } return true; } //----------------------------------------------------------------------------- // // Test whether the thread has completed //----------------------------------------------------------------------------- bool ThreadImpl::IsSignalled() { return !m_bIsRunning; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/winRT/LogImpl.h0000644000175200017520000000504414032142455016677 00000000000000//----------------------------------------------------------------------------- // // LogImpl.h // // WinRT implementation of message and error logging // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _LogImpl_H #define _LogImpl_H #include "Defs.h" #include #include "platform/Log.h" #include "Windows.h" namespace OpenZWave { namespace Internal { namespace Platform { /** \brief Windows-specific implementation of the Log class. */ class LogImpl: public i_LogImpl { private: friend class OpenZWave::Log; LogImpl(string const& _filename, bool const _bAppendLog, bool const _bConsoleOutput, LogLevel const _saveLevel, LogLevel const _queueLevel, LogLevel const _dumpTrigger); ~LogImpl(); void Write(LogLevel _level, uint8 const _nodeId, char const* _format, va_list _args); void Queue(char const* _buffer); void QueueDump(); void QueueClear(); void SetLoggingState(LogLevel _saveLevel, LogLevel _queueLevel, LogLevel _dumpTrigger); void SetLogFileName(const string &_filename); string GetTimeStampString(); string GetNodeString(uint8 const _nodeId); string GetThreadId(); string GetLogLevelString(LogLevel _level); string m_filename; /**< filename specified by user (default is ozw_log.txt) */ bool m_bConsoleOutput; /**< if true, send log output to console as well as to the file */ bool m_bAppendLog; /**< if true, the log file should be appended to any with the same name */ list m_logQueue; /**< list of queued log messages */ LogLevel m_saveLevel; LogLevel m_queueLevel; LogLevel m_dumpTrigger; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_LogImpl_H openzwave-1.6.1914/cpp/src/platform/winRT/SerialControllerImpl.h0000644000175200017520000000353514032142455021444 00000000000000//----------------------------------------------------------------------------- // // SerialControllerImpl.h // // WinRT Implementation of the cross-platform serial port // // Copyright (c) 2015 Microsoft Corporation // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _SerialControllerImpl_H #define _SerialControllerImpl_H #include #include #include "Defs.h" #include "platform/SerialController.h" namespace OpenZWave { namespace Internal { namespace Platform { class SerialControllerImpl { private: friend class SerialController; SerialControllerImpl(SerialController* _owner); ~SerialControllerImpl(); bool Open(); void Close(); uint32 Write(uint8* _buffer, uint32 _length); void StartReadTask(); Windows::Devices::SerialCommunication::SerialDevice ^ m_serialDevice; Concurrency::cancellation_token_source m_readTaskCancelationTokenSource; SerialController* m_owner; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_SerialControllerImpl_H openzwave-1.6.1914/cpp/src/platform/Thread.cpp0000644000175200017520000000706714032142455016042 00000000000000//----------------------------------------------------------------------------- // // Thread.cpp // // Cross-platform threads // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "platform/Event.h" #include "platform/Thread.h" #ifdef WIN32 #include "platform/windows/ThreadImpl.h" // Platform-specific implementation of a thread #elif defined WINRT #include "platform/winRT/ThreadImpl.h" // Platform-specific implementation of a thread #else #include "platform/unix/ThreadImpl.h" // Platform-specific implementation of a thread #endif namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Thread::Thread(string const& _name) { m_exitEvent = new Event(); m_pImpl = new ThreadImpl(this, _name); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- Thread::~Thread() { delete m_pImpl; m_exitEvent->Release(); } //----------------------------------------------------------------------------- // // Start a function running on this thread //----------------------------------------------------------------------------- bool Thread::Start(pfnThreadProc_t _pfnThreadProc, void* _context) { return (m_pImpl->Start(_pfnThreadProc, m_exitEvent, _context)); } //----------------------------------------------------------------------------- // // Stop a function running on this thread //----------------------------------------------------------------------------- bool Thread::Stop() { int32 timeout = 2000; // Give the thread 2 seconds to exit m_exitEvent->Set(); if (Wait::Single(this, timeout) < 0) { // Timed out m_pImpl->Terminate(); return false; } return true; } //----------------------------------------------------------------------------- // // Causes the thread to sleep for the specified number of milliseconds. //----------------------------------------------------------------------------- void Thread::Sleep(uint32 _milliseconds) { return (m_pImpl->Sleep(_milliseconds)); } //----------------------------------------------------------------------------- // // Test whether the event is set //----------------------------------------------------------------------------- bool Thread::IsSignalled() { return m_pImpl->IsSignalled(); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/FileOps.cpp0000644000175200017520000001150414032142455016163 00000000000000//----------------------------------------------------------------------------- // // FileOps.cpp // // Cross-platform File Operations // // Copyright (c) 2012 Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "platform/FileOps.h" #ifdef WIN32 #include "platform/windows/FileOpsImpl.h" // Platform-specific implementation of a File Operations #elif defined WINRT #include "platform/winRT/FileOpsImpl.h" // Platform-specific implementation of a File Operations #else #include "platform/unix/FileOpsImpl.h" // Platform-specific implementation of a File Operations #endif namespace OpenZWave { namespace Internal { namespace Platform { FileOps* FileOps::s_instance = NULL; FileOpsImpl* FileOps::m_pImpl = NULL; //----------------------------------------------------------------------------- // // Static creation of the singleton //----------------------------------------------------------------------------- FileOps* FileOps::Create() { if (s_instance == NULL) { s_instance = new FileOps(); } return s_instance; } //----------------------------------------------------------------------------- // // Static method to destroy the fileops singleton. //----------------------------------------------------------------------------- void FileOps::Destroy() { delete s_instance; s_instance = NULL; } //----------------------------------------------------------------------------- // // Static method to check for existance of a folder //----------------------------------------------------------------------------- bool FileOps::FolderExists(const string &_folderName) { if (s_instance != NULL) { return s_instance->m_pImpl->FolderExists(_folderName); } return false; } /** * FileExists. Check for the existance of a file. * \param string. file name. * \return Bool value indicating existance. */ bool FileOps::FileExists(const string &_fileName) { if (s_instance != NULL) { return s_instance->m_pImpl->FileExists(_fileName); } return false; } /** * FileWriteable. Check if we can write to a file. * \param string. file name. * \return Bool value indicating write permissions. */ bool FileOps::FileWriteable(const string &_fileName) { if (s_instance != NULL) { return s_instance->m_pImpl->FileWriteable(_fileName); } return false; } /** * FileRotate. Rotate a File * \param string. file name. * \return Bool value indicating write permissions. */ bool FileOps::FileRotate(const string &_fileName) { if (s_instance != NULL) { return s_instance->m_pImpl->FileRotate(_fileName); } return false; } /** * FileCopy. Copy a File * \param string. source file name. * \param string. destination file name * \return Bool value indicating success. */ bool FileOps::FileCopy(const string &_fileName, const string &_destfileName) { if (s_instance != NULL) { return s_instance->m_pImpl->FileCopy(_fileName, _destfileName); } return false; } /** * FolderCreate. Create a Folder * \param string. folder name * \return Bool value indicating success. */ bool FileOps::FolderCreate(const string &_folderName) { if (s_instance != NULL) { return s_instance->m_pImpl->FolderCreate(_folderName); } return false; } //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- FileOps::FileOps() { m_pImpl = new FileOpsImpl(); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- FileOps::~FileOps() { delete m_pImpl; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/Wait.h0000644000175200017520000000763714032142455015207 00000000000000//----------------------------------------------------------------------------- // // Wait.h // // Cross-platform abstract base class for objects we // want to be able to wait for. // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Wait_H #define _Wait_H #include #include "platform/Ref.h" namespace OpenZWave { namespace Internal { namespace Platform { class WaitImpl; /** \brief Platform-independent definition of Wait objects. * \ingroup Platform */ class Wait: public Ref { friend class WaitImpl; friend class ThreadImpl; public: enum { Timeout_Immediate = 0, Timeout_Infinite = -1 }; typedef void (*pfnWaitNotification_t)(void* _context); /** * Add a watcher to our object. The watcher will be triggered * by the derived class, when it enters a certain state. * \param _callback pointer to the function that will be called when the wait is over. * \param _context pointer to custom data that will be sent with the callback. */ void AddWatcher(pfnWaitNotification_t _callback, void* _context); /** * Remove a watcher from our object. Both the _callback and _context pointers * must match those used in a previous call to AddWatcher. * \param _callback pointer to the function that will be called when the wait is over. * \param _context pointer to custom data that will be sent with the callback. */ void RemoveWatcher(pfnWaitNotification_t _callback, void* _context); /** * Wait for a single object to become signalled. * \param _object pointer to the object to wait on. * \param _timeout optional maximum time to wait. Defaults to -1, which means wait forever. * \return zero if the object was signalled, -1 if the wait timed out. */ static int32 Single(Wait* _object, int32 _timeout = -1) { return Multiple(&_object, 1, _timeout); } /** * Wait for one of multiple objects to become signalled. If more than one object is in * a signalled state, the lowest array index will be returned. * \param _objects array of pointers to objects to wait on. * \param _numObjects number of objects in the array. * \param _timeout optional maximum time to wait. Defaults to -1, which means wait forever. * \return index into the array of the object that was signalled, -1 if the wait timed out. */ static int32 Multiple(Wait** _objects, uint32 _numObjects, int32 _timeout = -1); protected: Wait(); virtual ~Wait(); /** * Notify the watchers that the object is signalled. */ void Notify(); /** * Test whether an object is signalled. */ virtual bool IsSignalled() = 0; private: Wait(Wait const&); // prevent copy Wait& operator =(Wait const&); // prevent assignment WaitImpl* m_pImpl; // Pointer to an object that encapsulates the platform-specific implementation of a Wait object. }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_Wait_H openzwave-1.6.1914/cpp/src/platform/FileOps.h0000644000175200017520000000630114032142455015627 00000000000000//----------------------------------------------------------------------------- // // FileOps.h // // Cross-platform File Operations // // Copyright (c) 2012 Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _FileOps_H #define _FileOps_H #include #include #include "Defs.h" namespace OpenZWave { namespace Internal { namespace Platform { class FileOpsImpl; /** \brief Implements platform-independent File Operations. * \ingroup Platform */ class FileOps { public: /** * Create a FileOps cross-platform singleton. * \return a pointer to the file operations object. * \see Destroy. */ static FileOps* Create(); /** * Destroys the FileOps singleton. * \see Create. */ static void Destroy(); /** * FolderExists. Check for the existence of a folder. * \param string. Folder name. * \return Bool value indicating existence. */ static bool FolderExists(const string &_folderName); /** * FileExists. Check for the existence of a file. * \param string. file name. * \return Bool value indicating existence. */ static bool FileExists(const string &_fileName); /** * FileWriteable. Check if we can write to a file. * \param string. file name. * \return Bool value indicating write permissions. */ static bool FileWriteable(const string &_fileName); /** * FileRotate. Rotate a File * \param string. file name. * \return Bool value indicating write permissions. */ static bool FileRotate(const string &_fileName); /** * FileCopy. Copy a File * \param string. source file name. * \param string. destination file name * \return Bool value indicating success. */ static bool FileCopy(const string &_fileName, const string &_destinationfile); /** * FolderCreate. Create a Folder * \param string. folder name * \return Bool value indicating success. */ static bool FolderCreate(const string &_folderName); private: FileOps(); ~FileOps(); static FileOpsImpl* m_pImpl; // Pointer to an object that encapsulates the platform-specific implementation of the FileOps. static FileOps* s_instance; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_FileOps_H openzwave-1.6.1914/cpp/src/platform/HttpClient.h0000644000175200017520000003101214032142455016341 00000000000000//----------------------------------------------------------------------------- // // HttpClient.h // // Cross-platform HttpClient // // Originally based upon minihttp client // Copyright (c) 2016 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- // Original License Text: /* This program is free software. It comes without any warranty, to * the extent permitted by applicable law. You can redistribute it * and/or modify it under the terms of the Do What The Fuck You Want * To Public License, Version 2, as published by Sam Hocevar. * See http://sam.zoy.org/wtfpl/COPYING for more details. */ #ifndef MINIHTTPSOCKET_H #define MINIHTTPSOCKET_H // ---- Compile config ----- #define MINIHTTP_SUPPORT_HTTP #define MINIHTTP_SUPPORT_SOCKET_SET // ------------------------- // Intentionally avoid pulling in any other headers #include #include #include namespace OpenZWave { /** \defgroup SimpleHttpClient Basic HTTP(s) Client * * a Basic HTTP Client for talking to webservers */ namespace Internal { namespace Platform { /** \brief Initialize the Network for HTTP requests * \ingroup SimpleHttpClient * * Initializes the Network for HTTP requests * * \returns success/failure */ bool InitNetwork(); /** \brief Stop the Network for HTTP requests * \ingroup SimpleHttpClient * * Stops the Network for HTTP requests and releases resources associated with it */ void StopNetwork(); /** \brief Indicates if we support HTTPS requests * \ingroup SimpleHttpClient * * Indicates if we support HTTPS requests * * \returns success/failure * \todo SSL is not actually implemented yet. */ bool HasSSL(); /** \brief Split a URL into its different parts/ports etc * \ingroup SimpleHttpClient * * Split a URL Into the different parts/ports * * \param uri the URL to parse * \param host the Hostname of the URL * \param file the directory/file name of the URL * \param port the port number of the URL, or 80 if not specified * * \returns success/failure */ bool SplitURI(const std::string& uri, std::string& host, std::string& file, int& port); /** \brief Encode a String suitable for sending as a URL request (eg Get) * \ingroup SimpleHttpClient * * Encode a String so it can be sent as part of a URL request * * \param s the string to encode * \param enc the encoded version of the string that is returned * */ void URLEncode(const std::string& s, std::string& enc); /** \brief Result Codes for SSL operations * \ingroup SimpleHttpClient * */ enum SSLResult { SSLR_OK = 0x0, /**< No Error */ SSLR_NO_SSL = 0x1, /**< SSL Is not required */ SSLR_FAIL = 0x2, /**< Internal SSL Engine Failure */ SSLR_CERT_EXPIRED = 0x4, /**< SSL Certificate has expired */ SSLR_CERT_REVOKED = 0x8, /**< SSL Certificate is revoked */ SSLR_CERT_CN_MISMATCH = 0x10, /**< SSL CN Name does not match Hostname */ SSLR_CERT_NOT_TRUSTED = 0x20, /**< SSL Certificate is not trusted */ SSLR_CERT_MISSING = 0x40, /**< SSL Certificate is missing */ SSLR_CERT_SKIP_VERIFY = 0x80, /**< SSL Certificate Verification is disabled */ SSLR_CERT_FUTURE = 0x100, /**< SSL Certificate is valid in the future */ _SSLR_FORCE32BIT = 0x7fffffff }; /** \brief a TCP Socket that can optionally be protected via SSL * \ingroup SimpleHttpClient * * This represents a TCP Socket that can be encrypted via SSL and * is used to connect to a TCP Server (in this case, a HTTP(s) Server */ class TcpSocket { public: TcpSocket(); virtual ~TcpSocket(); virtual bool HasPendingTask() const { return false; } bool open(const char *addr = NULL, unsigned int port = 0); void close(); bool update(); // returns true if something interesting happened (incoming data, closed connection, etc) bool isOpen(void); void SetBufsizeIn(unsigned int s); bool SetNonBlocking(bool nonblock); unsigned int GetBufSize() { return _inbufSize; } const char *GetHost(void) { return _host.c_str(); } bool SendBytes(const void *buf, unsigned int len); // SSL related bool initSSL(const char *certs); bool hasSSL() const { return !!_sslctx; } void shutdownSSL(); SSLResult verifySSL(); protected: virtual void _OnCloseInternal(); virtual void _OnData(); // data received callback. Internal, should only be overloaded to call _OnRecv() virtual void _OnRecv(void *buf, unsigned int size) = 0; virtual void _OnClose() { } ; // close callback virtual void _OnOpen() { } // called when opened virtual bool _OnUpdate() { return true; } // called before reading from the socket void _ShiftBuffer(); char *_inbuf; char *_readptr; // part of inbuf, optionally skipped header char *_writeptr; // passed to recv(). usually equal to _inbuf, but may point inside the buffer in case of a partial transfer. unsigned int _inbufSize; // size of internal buffer unsigned int _writeSize; // how many bytes can be written to _writeptr; unsigned int _recvSize; // incoming size, max _inbufSize - 1 unsigned int _lastport; // port used in last open() call bool _nonblocking; // Default true. If false, the current thread is blocked while waiting for input. #ifdef _WIN32 intptr_t _s; // socket handle. really an int, but to be sure its 64 bit compatible as it seems required on windows, we use this. #else long _s; #endif std::string _host; private: int _writeBytes(const unsigned char *buf, size_t len); int _readBytes(unsigned char *buf, size_t maxlen); void *_sslctx; }; #ifdef MINIHTTP_SUPPORT_HTTP enum HttpCode { HTTP_OK = 200, HTTP_NOTFOUND = 404, }; /** \brief This class is used for Posting data to a HTTP(s) server * \ingroup SimpleHttpClient * * Post some data to a HTTP(s) server * */ class POST { public: void reserve(size_t res) { data.reserve(res); } POST& add(const char *key, const char *value); const char *c_str() const { return data.c_str(); } const std::string& str() const { return data; } bool empty() const { return data.empty(); } size_t length() const { return data.length(); } private: std::string data; }; /** \brief Main class for making a HTTP request to a HTTP(s) server * \ingroup SimpleHttpClient * * Make a request to a HTTP Server * */ struct Request { Request() : port(80), user(NULL) { } Request(const std::string& h, const std::string& res, int p = 80, void *u = NULL) : host(h), resource(res), port(80), user(u), useSSL(false) { } std::string protocol; std::string host; std::string header; // set by socket std::string resource; std::string extraGetHeaders; int port; void *user; bool useSSL; POST post; // if this is empty, it's a GET request, otherwise a POST request }; /** \brief a Socket that speaks HTTP protocol. * \ingroup SimpleHttpClient * * Talk to a HTTP(s) server * */ class HttpSocket: public OpenZWave::Internal::Platform::TcpSocket { public: HttpSocket(); virtual ~HttpSocket(); virtual bool HasPendingTask() const { return ExpectMoreData() || _requestQ.size(); } void SetKeepAlive(unsigned int secs) { _keep_alive = secs; } void SetUserAgent(const std::string &s) { _user_agent = s; } void SetAcceptEncoding(const std::string& s) { _accept_encoding = s; } void SetFollowRedirect(bool follow) { _followRedir = follow; } void SetAlwaysHandle(bool h) { _alwaysHandle = h; } void SetDownloadFile(std::string filename) { _filename = filename; } bool Download(const std::string& url, const char *extraRequest = NULL, void *user = NULL, const POST *post = NULL); bool SendRequest(Request& what, bool enqueue); bool SendRequest(const std::string what, const char *extraRequest = NULL, void *user = NULL); bool QueueRequest(const std::string what, const char *extraRequest = NULL, void *user = NULL); unsigned int GetRemaining() const { return _remaining; } unsigned int GetStatusCode() const { return _status; } unsigned int GetContentLen() const { return _contentLen; } bool ChunkedTransfer() const { return _chunkedTransfer; } bool ExpectMoreData() const { return _remaining || _chunkedTransfer; } const Request &GetCurrentRequest() const { return _curRequest; } const char *Hdr(const char *h) const; bool IsRedirecting() const; bool IsSuccess() const; protected: virtual void _OnCloseInternal(); virtual void _OnClose(); virtual void _OnData(); // data received callback. Internal, should only be overloaded to call _OnRecv() virtual void _OnRecv(void *buf, unsigned int size); virtual void _OnOpen(); // called when opene virtual bool _OnUpdate(); // called before reading from the socket // new ones: virtual void _OnRequestDone() { } bool _Redirect(std::string loc, bool forceGET); void _ProcessChunk(); bool _EnqueueOrSend(const Request& req, bool forceQueue = false); void _DequeueMore(); bool _OpenRequest(const Request& req); void _ParseHeader(); void _ParseHeaderFields(const char *s, size_t size); bool _HandleStatus(); // Returns whether the processed request was successful, or not void _FinishRequest(); void _OnRecvInternal(void *buf, unsigned int size); std::string _user_agent; std::string _accept_encoding; // Default empty. std::string _tmpHdr; // used to save the http header if the incoming buffer was not large enough unsigned int _keep_alive; // http related unsigned int _remaining; // http "Content-Length: X" - already recvd. 0 if ready for next packet. // For chunked transfer encoding, this holds the remaining size of the current chunk unsigned int _contentLen; // as reported by server unsigned int _status; // http status code, HTTP_OK if things are good std::queue _requestQ; std::map _hdrs; // Maps HTTP header fields to their values Request _curRequest; bool _inProgress; bool _chunkedTransfer; bool _mustClose; // keep-alive specified, or not bool _followRedir; // Default true. Follow 3xx redirects if this is set. bool _alwaysHandle; // Also deliver to _OnRecv() if a non-success code was received. std::string _filename; FILE* _pFile; }; #endif // ------------------------------------------------------------------------ #ifdef MINIHTTP_SUPPORT_SOCKET_SET /** \brief Support Multiple TCP Socket connections * \ingroup SimpleHttpClient * * to Support multiple TCP Socket Connections * */ class SocketSet { public: virtual ~SocketSet(); void deleteAll(); bool update(); void add(TcpSocket *s, bool deleteWhenDone = true); bool has(TcpSocket *s); void remove(TcpSocket *s); inline size_t size() { return _store.size(); } //protected: struct SocketSetData { bool deleteWhenDone; // To be extended }; typedef std::map Store; Store _store; }; #endif } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/platform/DNS.cpp0000644000175200017520000000350114032142455015244 00000000000000//----------------------------------------------------------------------------- // // DNS.cpp // // Cross-platform DNS Operations // // Copyright (c) 2015 Justin Hammond // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "platform/DNS.h" #ifdef WIN32 #include "platform/windows/DNSImpl.h" // Platform-specific implementation of a DNS Operations #elif defined WINRT #include "platform/winRT/DNSImpl.h" // Platform-specific implementation of a DNS Operations #else #include "platform/unix/DNSImpl.h" // Platform-specific implementation of a DNS Operations #endif namespace OpenZWave { namespace Internal { namespace Platform { DNS::DNS() : status(DNSError_None) { this->m_pImpl = new DNSImpl(); } DNS::~DNS() { delete this->m_pImpl; } bool DNS::LookupTxT(string lookup, string &result) { bool ret = this->m_pImpl->LookupTxT(lookup, result); status = this->m_pImpl->status; return ret; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/HidController.h0000644000175200017520000001161114032142455017036 00000000000000//----------------------------------------------------------------------------- // // HidController.h // // Cross-platform HID port handler // // Copyright (c) 2010 Jason Frazier // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _HidController_H #define _HidController_H #include #include "Defs.h" #include "platform/Controller.h" #ifdef USE_HID struct hid_device_; typedef struct hid_device_ hid_device; namespace OpenZWave { namespace Internal { namespace Platform { class Driver; class Msg; class Thread; class Event; /** \brief Interface for controllers that implement a HID emulation * \ingroup Platform */ class HidController: public Controller { public: /** * Constructor. * Creates an object that represents a HID port. */ HidController(); /** * Destructor. * Destroys the HID port object. */ virtual ~HidController(); /** * Set the USB vendor ID search value. The HID port must be closed for the setting to be accepted. * @param _baud Vendor ID value to match when enumerating USB HID devices. * @return True if the vendor ID value was accepted. * @see Open, Close */ bool SetVendorId( uint32 const _vendorId ); /** * Set the USB product ID search value. The HID port must be closed for the setting to be accepted. * @param _parity Product ID value to match when enumerating USB HID devices. * @return True if the product ID value was accepted. * @see Open, Close */ bool SetProductId( uint32 const _productId ); /** * Set the USB serial number search value. The HID port must be closed for the setting to be accepted. * @param _parity Serial number string to match when enumerating USB HID devices. If empty, any serial number will be accepted. * @return True if the serial number value was accepted. * @see Open, Close */ bool SetSerialNumber( string const& _serialNumber ); /** * Open a HID port. * Attempts to open a HID port and initialize it with the specified parameters. * @param _HidControllerName The name of the port to open. For example, ttyS1 on Linux, or \\.\COM2 in Windows. * @return True if the port was opened and configured successfully. * @see Close, Read, Write */ bool Open( string const& _hidControllerName ); /** * Close a HID port. * Closes the HID port. * @return True if the port was closed successfully, or false if the port was already closed, or an error occurred. * @see Open */ bool Close(); /** * Write to a HID port. * Attempts to write data to an open HID port. * @param _buffer Pointer to a block of memory containing the data to be written. * @param _length Length in bytes of the data. * @return The number of bytes written. * @see Read, Open, Close */ uint32 Write( uint8* _buffer, uint32 _length ); private: bool Init( uint32 const _attempts ); void Read(); // helpers for internal use only /** * Read bytes from the specified HID feature report * @param _buffer Buffer array for receiving the feature report bytes. * @param _length Length of the buffer array. * @param _reportId ID of the report to read. * @return Actual number of bytes retrieved, or -1 on error. */ int GetFeatureReport( uint32 _length, uint8 _reportId, uint8* _buffer ); /** * Write bytes to the specified HID feature report * @param _data Bytes to be written to the feature report. * @param _length Length of bytes to be written. * @return Actal number of bytes written, or -1 on error. */ int SendFeatureReport( uint32 _length, const uint8* _data ); static void ThreadEntryPoint( Event* _exitEvent, void* _context ); void ThreadProc( Event* _exitEvent ); hid_device* m_hHidController; Thread* m_thread; uint32 m_vendorId; uint32 m_productId; string m_serialNumber; string m_hidControllerName; bool m_bOpen; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif #endif //_HidController_H openzwave-1.6.1914/cpp/src/platform/Mutex.cpp0000644000175200017520000000564014032142455015730 00000000000000//----------------------------------------------------------------------------- // // Mutex.cpp // // Cross-platform mutex // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "platform/Mutex.h" #ifdef WIN32 #include "platform/windows/MutexImpl.h" // Platform-specific implementation of a mutex #elif defined WINRT #include "platform/winRT/MutexImpl.h" // Platform-specific implementation of a mutex #else #include "platform/unix/MutexImpl.h" // Platform-specific implementation of a mutex #endif namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Mutex::Mutex() : m_pImpl(new MutexImpl()) { } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- Mutex::~Mutex() { delete m_pImpl; } //----------------------------------------------------------------------------- // // Lock the mutex //----------------------------------------------------------------------------- bool Mutex::Lock(bool const _bWait // = true; ) { return m_pImpl->Lock(_bWait); } //----------------------------------------------------------------------------- // // Release our lock on the mutex //----------------------------------------------------------------------------- void Mutex::Unlock() { m_pImpl->Unlock(); if (IsSignalled()) { // The mutex has no owners, so notify the watchers Notify(); } } //----------------------------------------------------------------------------- // // Test whether the event is set //----------------------------------------------------------------------------- bool Mutex::IsSignalled() { return m_pImpl->IsSignalled(); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/Stream.cpp0000644000175200017520000001414514032142455016061 00000000000000//----------------------------------------------------------------------------- // // Stream.h // // Cross-platform circular buffer with signalling // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "platform/Stream.h" #include "platform/Mutex.h" #include "platform/Log.h" #include #include namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Stream::Stream(uint32 _bufferSize) : m_bufferSize(_bufferSize), m_signalSize(1), m_dataSize(0), m_head(0), m_tail(0), m_mutex(new Mutex()) { m_buffer = new uint8[m_bufferSize]; memset(m_buffer, 0x00, m_bufferSize); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- Stream::~Stream() { m_mutex->Release(); delete[] m_buffer; } //----------------------------------------------------------------------------- // // Set the amount of data that must be in the buffer for to to be signalled //----------------------------------------------------------------------------- void Stream::SetSignalThreshold(uint32 _size) { m_signalSize = _size; if (IsSignalled()) { // We have more data than we are waiting for, so notify the watchers Notify(); } } //----------------------------------------------------------------------------- // // Remove data from the buffer //----------------------------------------------------------------------------- bool Stream::Get(uint8* _buffer, uint32 _size) { if (m_dataSize < _size) { // There is not enough data in the buffer to fulfill the request Log::Write(LogLevel_Error, "ERROR: Not enough data in stream buffer"); return false; } m_mutex->Lock(); if ((m_tail + _size) > m_bufferSize) { // We will have to wrap around uint32 block1 = m_bufferSize - m_tail; uint32 block2 = _size - block1; memcpy(_buffer, &m_buffer[m_tail], block1); memcpy(&_buffer[block1], m_buffer, block2); m_tail = block2; } else { // Requested data is in a contiguous block memcpy(_buffer, &m_buffer[m_tail], _size); m_tail += _size; } LogData(_buffer, _size, " Read (buffer->application): "); m_dataSize -= _size; m_mutex->Unlock(); return true; } //----------------------------------------------------------------------------- // // Add data to the buffer //----------------------------------------------------------------------------- bool Stream::Put(uint8* _buffer, uint32 _size) { if ((m_bufferSize - m_dataSize) < _size) { // There is not enough space left in the buffer for the data Log::Write(LogLevel_Error, "ERROR: Not enough space in stream buffer"); return false; } m_mutex->Lock(); if ((m_head + _size) > m_bufferSize) { // We will have to wrap around uint32 block1 = m_bufferSize - m_head; uint32 block2 = _size - block1; memcpy(&m_buffer[m_head], _buffer, block1); memcpy(m_buffer, &_buffer[block1], block2); uint8 * logpos = m_buffer + m_head; m_head = block2; LogData(logpos, block1, " Read (controller->buffer): "); LogData(m_buffer, block2, " Read (controller->buffer): "); } else { // There is enough space before we reach the end of the buffer memcpy(&m_buffer[m_head], _buffer, _size); m_head += _size; LogData(m_buffer + m_head - _size, _size, " Read (controller->buffer): "); } m_dataSize += _size; if (IsSignalled()) { // We now have more data than we are waiting for, so notify the watchers Notify(); } m_mutex->Unlock(); return true; } //----------------------------------------------------------------------------- // // Empty the data buffer //----------------------------------------------------------------------------- void Stream::Purge() { m_tail = 0; m_head = 0; m_dataSize = 0; } //----------------------------------------------------------------------------- // // Test whether there is enough data to be signalled //----------------------------------------------------------------------------- bool Stream::IsSignalled() { return (m_dataSize >= m_signalSize); } //----------------------------------------------------------------------------- // // Format the stream buffer data for log output //----------------------------------------------------------------------------- void Stream::LogData(uint8* _buffer, uint32 _length, const string &_function) { if (!_length) return; string str = ""; for (uint32 i = 0; i < _length; ++i) { if (i) { str += ", "; } char byteStr[8]; snprintf(byteStr, sizeof(byteStr), "0x%.2x", _buffer[i]); str += byteStr; } Log::Write(LogLevel_StreamDetail, "%s%s", _function.c_str(), str.c_str()); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/SerialController.cpp0000644000175200017520000001177114032142455020113 00000000000000//----------------------------------------------------------------------------- // // SerialController.h // // Cross-platform serial port handler // // Copyright (c) 2010 Jason Frazier // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Msg.h" #include "platform/Event.h" #include "platform/Thread.h" #include "platform/SerialController.h" #include "platform/Log.h" #ifdef WIN32 #include "platform/windows/SerialControllerImpl.h" // Platform-specific implementation of a serial port #elif defined WINRT #include "platform/winRT/SerialControllerImpl.h" // Platform-specific implementation of a serial port #else #include "platform/unix/SerialControllerImpl.h" // Platform-specific implementation of a serial port #endif namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- SerialController::SerialController() : m_baud(115200), m_parity(SerialController::Parity_None), m_stopBits(SerialController::StopBits_One), m_bOpen(false) { m_pImpl = new SerialControllerImpl(this); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- SerialController::~SerialController() { delete m_pImpl; } //----------------------------------------------------------------------------- // // Set the serial port baud rate. // The serial port must be closed for the setting to be accepted. //----------------------------------------------------------------------------- bool SerialController::SetBaud(uint32 const _baud) { if (m_bOpen) { return false; } m_baud = _baud; return true; } //----------------------------------------------------------------------------- // // Set the serial port parity. // The serial port must be closed for the setting to be accepted. //----------------------------------------------------------------------------- bool SerialController::SetParity(Parity const _parity) { if (m_bOpen) { return false; } m_parity = _parity; return true; } //----------------------------------------------------------------------------- // // Set the serial port stop bits. // The serial port must be closed for the setting to be accepted. //----------------------------------------------------------------------------- bool SerialController::SetStopBits(StopBits const _stopBits) { if (m_bOpen) { return false; } m_stopBits = _stopBits; return true; } //----------------------------------------------------------------------------- // // Open and configure a serial port //----------------------------------------------------------------------------- bool SerialController::Open(string const& _serialControllerName) { if (m_bOpen) { return false; } m_serialControllerName = _serialControllerName; m_bOpen = m_pImpl->Open(); return m_bOpen; } //----------------------------------------------------------------------------- // // Close a serial port //----------------------------------------------------------------------------- bool SerialController::Close() { if (!m_bOpen) { return false; } m_pImpl->Close(); m_bOpen = false; return true; } //----------------------------------------------------------------------------- // // Write data to an open serial port //----------------------------------------------------------------------------- uint32 SerialController::Write(uint8* _buffer, uint32 _length) { if (!m_bOpen) { return 0; } Log::Write(LogLevel_StreamDetail, " SerialController::Write (sent to controller)"); LogData(_buffer, _length, " Write: "); return (m_pImpl->Write(_buffer, _length)); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/SerialController.h0000644000175200017520000001072114032142455017552 00000000000000//----------------------------------------------------------------------------- // // SerialController.h // // Cross-platform serial port handler // // Copyright (c) 2010 Jason Frazier // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _SerialController_H #define _SerialController_H #include #include "Defs.h" #include "platform/Controller.h" namespace OpenZWave { namespace Internal { namespace Platform { // class Driver; // class Msg; class SerialControllerImpl; /** \brief Interface for controllers that implement a Serial Interface (USB Serial Port Emulation) * \ingroup Platform */ class SerialController: public Controller { friend class SerialControllerImpl; public: enum Parity { Parity_None = 0, Parity_Odd, Parity_Even, Parity_Mark, Parity_Space }; enum StopBits { StopBits_One = 0, StopBits_OneAndAHalf = 1, StopBits_Two = 2 }; /** * Constructor. * Creates an object that represents a serial port. */ SerialController(); /** * Destructor. * Destroys the serial port object. */ virtual ~SerialController(); /** * Set the serial port baud rate. The serial port must be closed for the setting to be accepted. * @param _baud Integer containing the expected baud-rate of the serial connection. Most Z-Wave interfaces run at 115200 baud. * @return True if the baud value was accepted. * @see Open, Close */ bool SetBaud(uint32 const _baud); /** * Set the serial port parity. The serial port must be closed for the setting to be accepted. * @param _parity Parity enum value indicating the serial data's expected type of parity bits, if any. * @return True if the parity value was accepted. * @see Open, Close */ bool SetParity(Parity const _parity); /** * Set the serial port stop bits. The serial port must be closed for the setting to be accepted. * @param _stopBits StopBits enum value indicating the serial data's expected number of stop-bits. * @return True if the stop bits value was accepted. * @see Open, Close */ bool SetStopBits(StopBits const _stopBits); /** * Open a serial port. * Attempts to open a serial port and initialize it with the specified parameters. * @param _SerialControllerName The name of the port to open. For example, ttyS1 on Linux, or \\.\COM2 in Windows. * @return True if the port was opened and configured successfully. * @see Close, Read, Write */ bool Open(string const& _SerialControllerName); /** * Close a serial port. * Closes the serial port. * @return True if the port was closed successfully, or false if the port was already closed, or an error occurred. * @see Open */ bool Close(); /** * Write to a serial port. * Attempts to write data to an open serial port. * @param _buffer Pointer to a block of memory containing the data to be written. * @param _length Length in bytes of the data. * @return The number of bytes written. * @see Read, Open, Close */ uint32 Write(uint8* _buffer, uint32 _length); private: uint32 m_baud; SerialController::Parity m_parity; SerialController::StopBits m_stopBits; string m_serialControllerName; OpenZWave::Internal::Platform::SerialControllerImpl* m_pImpl; // Pointer to an object that encapsulates the platform-specific implementation of the serial port. bool m_bOpen; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_SerialController_H openzwave-1.6.1914/cpp/src/platform/TimeStamp.cpp0000644000175200017520000000665414032142455016537 00000000000000//----------------------------------------------------------------------------- // // TimeStamp.h // // Cross-platform TimeStamp // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "Defs.h" #include "platform/TimeStamp.h" #ifdef WIN32 #include "platform/windows/TimeStampImpl.h" // Platform-specific implementation of a TimeStamp #elif defined WINRT #include "platform/winRT/TimeStampImpl.h" // Platform-specific implementation of a TimeStamp #else #include "platform/unix/TimeStampImpl.h" // Platform-specific implementation of a TimeStamp #endif namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- TimeStamp::TimeStamp() : m_pImpl(new TimeStampImpl()) { } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- TimeStamp::~TimeStamp() { delete m_pImpl; } //----------------------------------------------------------------------------- // // Sets the timestamp to now, plus an offset in milliseconds //----------------------------------------------------------------------------- void TimeStamp::SetTime(int32 _milliseconds // = 0 ) { m_pImpl->SetTime(_milliseconds); } //----------------------------------------------------------------------------- // // Gets the difference between now and the timestamp time in milliseconds //----------------------------------------------------------------------------- int32 TimeStamp::TimeRemaining() { return m_pImpl->TimeRemaining(); } //----------------------------------------------------------------------------- // // Return object as a string //----------------------------------------------------------------------------- std::string TimeStamp::GetAsString() { return m_pImpl->GetAsString(); } //----------------------------------------------------------------------------- // // Overload the subtract operator to get the difference between two // timestamps in milliseconds //----------------------------------------------------------------------------- int32 TimeStamp::operator-(TimeStamp const& _other) { return (int32) (m_pImpl - _other.m_pImpl); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/windows/0000777000175200017520000000000014032143201015661 500000000000000openzwave-1.6.1914/cpp/src/platform/windows/WaitImpl.h0000644000175200017520000000420214032142455017504 00000000000000//----------------------------------------------------------------------------- // // WaitImpl.h // // Windows implementation of a base class for objects we // want to be able to wait for. // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _WaitImpl_H #define _WaitImpl_H #include #include #include "Defs.h" #include "platform/Ref.h" #include "platform/Wait.h" namespace OpenZWave { namespace Internal { namespace Platform { /** \brief Windows specific implementation of Wait objects. */ class WaitImpl { private: friend class Wait; WaitImpl(Wait* _owner); virtual ~WaitImpl(); void AddWatcher(Wait::pfnWaitNotification_t _callback, void* _context); bool RemoveWatcher(Wait::pfnWaitNotification_t _callback, void* _context); void Notify(); static int32 Multiple(Wait** _objects, uint32 _numObjects, int32 _timeout = -1); WaitImpl(Wait const&); // prevent copy WaitImpl& operator =(WaitImpl const&); // prevent assignment struct Watcher { Wait::pfnWaitNotification_t m_callback; void* m_context; }; list m_watchers; Wait* m_owner; CRITICAL_SECTION m_criticalSection; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_WaitImpl_H openzwave-1.6.1914/cpp/src/platform/windows/DNSImpl.h0000644000175200017520000000257714032142455017241 00000000000000//----------------------------------------------------------------------------- // // DNSImpl.h // // Windows DNS Lookup Routines. // // Copyright (c) 2016 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _DNSImpl_H #define _DNSImpl_H #include "Defs.h" #include "platform/DNS.h" namespace OpenZWave { namespace Internal { namespace Platform { class DNSImpl { public: DNSImpl(); virtual ~DNSImpl(); virtual bool LookupTxT(string, string &); DNSError status; private: }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/platform/windows/MutexImpl.cpp0000644000175200017520000000616514032142455020247 00000000000000//----------------------------------------------------------------------------- // // MutexImpl.cpp // // Windows Implementation of the cross-platform mutex // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "MutexImpl.h" namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- MutexImpl::MutexImpl() : m_lockCount(0) { InitializeCriticalSection(&m_criticalSection); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- MutexImpl::~MutexImpl() { DeleteCriticalSection(&m_criticalSection); } //----------------------------------------------------------------------------- // // Lock the mutex //----------------------------------------------------------------------------- bool MutexImpl::Lock(bool const _bWait // = true; ) { if (_bWait) { // We will wait for the lock EnterCriticalSection(&m_criticalSection); ++m_lockCount; return true; } // Returns immediately, even if the lock was not available. if (TryEnterCriticalSection(&m_criticalSection)) { ++m_lockCount; return true; } return false; } //----------------------------------------------------------------------------- // // Release our lock on the mutex //----------------------------------------------------------------------------- void MutexImpl::Unlock() { if (!m_lockCount) { // No locks - we have a mismatched lock/release pair assert(0); } else { --m_lockCount; LeaveCriticalSection(&m_criticalSection); } } //----------------------------------------------------------------------------- // // Test whether the mutex is free //----------------------------------------------------------------------------- bool MutexImpl::IsSignalled() { return (0 == m_lockCount); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/windows/DNSImpl.cpp0000644000175200017520000000370214032142455017563 00000000000000//----------------------------------------------------------------------------- // // DNSImpl.cpp // // Windows DNS Lookup Routines. // // Copyright (c) 2016 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include #include #include "DNSImpl.h" namespace OpenZWave { namespace Internal { namespace Platform { DNSImpl::DNSImpl() { } DNSImpl::~DNSImpl() { } bool DNSImpl::LookupTxT(string lookup, string &result) { PDNS_RECORD qr, rp; DNS_STATUS rc; rc = DnsQuery(lookup.c_str(), DNS_TYPE_TEXT, DNS_QUERY_STANDARD, NULL, &qr, NULL); if (rc != ERROR_SUCCESS) { Log::Write(LogLevel_Warning, "Error looking up txt Record: %s - %d", lookup.c_str(), rc); status = DNSError_InternalError; return false; } for (rp = qr; rp != NULL; rp = rp->pNext) { if (rp->wType == DNS_TYPE_TEXT) { result = rp->Data.TXT.pStringArray[0]; status = DNSError_None; break; } } DnsRecordListFree(qr, DnsFreeRecordList); return true; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/windows/FileOpsImpl.cpp0000644000175200017520000001151414032142455020500 00000000000000//----------------------------------------------------------------------------- // // FileOpsImpl.cpp // // Unix implementation of file operations // // Copyright (c) 2012, Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "FileOpsImpl.h" #include "Utils.h" namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- FileOpsImpl::FileOpsImpl() { } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- FileOpsImpl::~FileOpsImpl() { } //----------------------------------------------------------------------------- // // Determine if a folder exists //----------------------------------------------------------------------------- bool FileOpsImpl::FolderExists(const string &_folderName) { uint32 ftype = GetFileAttributesA(_folderName.c_str()); if (ftype == INVALID_FILE_ATTRIBUTES) return false; // something is wrong with _foldername path if (ftype & FILE_ATTRIBUTE_DIRECTORY) return true; return false; } bool FileOpsImpl::FileExists(const string _filename) { DWORD dwAttrib = GetFileAttributesA(_filename.c_str()); return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); } bool FileOpsImpl::FileWriteable(const string _filename) { DWORD dwAttrib; if (!FileExists(_filename)) { /* check if the directory is writtable */ dwAttrib = GetFileAttributesA(ozwdirname(_filename).c_str()); } else { dwAttrib = GetFileAttributesA(_filename.c_str()); } return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_READONLY)); } bool FileOpsImpl::FileRotate(const string _filename) { int i = 1; string newFile; /* find a filename not used yet */ newFile = _filename; newFile.append(".").append(intToString(i)); while (FileExists(newFile)) { i++; newFile = _filename; newFile.append(".").append(intToString(i)); } /* copy the file */ if (!FileCopy(_filename, newFile)) { Log::Write(LogLevel_Warning, "File Rotate Failed: %s -> %s", _filename.c_str(), newFile.c_str()); return false; } /* remove the old file */ if (DeleteFileA(_filename.c_str()) == 0) { Log::Write(LogLevel_Warning, "File Removal failed: %s", _filename.c_str()); return false; } return true; } bool FileOpsImpl::FileCopy(const string _sourcefile, const string _destfile) { if (!FileExists(_sourcefile)) { Log::Write(LogLevel_Warning, "Source File %s doesn't exist in FileCopy", _sourcefile.c_str()); return false; } if (FileExists(_destfile)) { Log::Write(LogLevel_Warning, "Destination File %s exists in FileCopy", _destfile.c_str()); return false; } /* make sure the Destination Folder Exists */ if (!FolderExists(ozwdirname(_destfile))) { Log::Write(LogLevel_Warning, "Destination Folder %s Doesn't Exist", ozwdirname(_destfile)); return false; } if (CopyFileA(_sourcefile.c_str(), _destfile.c_str(), FALSE) == 0) { Log::Write(LogLevel_Warning, "CopyFile Failed %s - %s", _sourcefile.c_str(), _destfile.c_str()); return false; } return true; } bool FileOpsImpl::FolderCreate(const string _dirname) { if (FolderExists(_dirname)) { Log::Write(LogLevel_Warning, "Folder %s Exists for FolderCreate", _dirname.c_str()); return false; } if (CreateDirectoryA(_dirname.c_str(), NULL) == 0) { Log::Write(LogLevel_Warning, "Create Directory Failed: %s", _dirname.c_str()); return false; } return true; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/windows/ThreadImpl.h0000644000175200017520000000374114032142455020016 00000000000000//----------------------------------------------------------------------------- // // ThreadImpl.h // // Windows implementation of a cross-platform thread // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ThreadImpl_H #define _ThreadImpl_H #include #include #include "platform/Thread.h" namespace OpenZWave { namespace Internal { namespace Platform { class Thread; class Event; /** \brief Windows-specific implementation of the Thread class. */ class ThreadImpl { private: friend class Thread; ThreadImpl(Thread* _owner, string const& _name); ~ThreadImpl(); bool Start(Thread::pfnThreadProc_t _pfnThreadProc, Event* _exitEvent, void* _context); void Sleep(uint32 _milliseconds); bool Terminate(); bool IsSignalled(); void Run();static DWORD WINAPI ThreadProc( void* _pArg ); Thread* m_owner; HANDLE m_hThread; Event* m_exitEvent; Thread::pfnThreadProc_t m_pfnThreadProc; void* m_context; bool m_bIsRunning; string m_name; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_ThreadImpl_H openzwave-1.6.1914/cpp/src/platform/windows/FileOpsImpl.h0000644000175200017520000000332414032142455020145 00000000000000//----------------------------------------------------------------------------- // // FileOpsImpl.h // // Unix implementation of file operations // // Copyright (c) 2012, Greg Satz // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _FileOpsImpl_H #define _FileOpsImpl_H #include #include #include "Defs.h" #include "platform/FileOps.h" namespace OpenZWave { namespace Internal { namespace Platform { class FileOpsImpl { friend class FileOps; private: FileOpsImpl(); ~FileOpsImpl(); bool FolderExists(const string &_filename); bool FileExists(const string _filename); bool FileWriteable(const string _filename); bool FileRotate(const string _filename); bool FileCopy(const string, const string); bool FolderCreate(const string _dirname); }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_FileOpsImpl_H openzwave-1.6.1914/cpp/src/platform/windows/MutexImpl.h0000644000175200017520000000325714032142455017713 00000000000000//----------------------------------------------------------------------------- // // MutexImpl.h // // Windows Implementation of the cross-platform mutex // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _MutexImpl_H #define _MutexImpl_H #include namespace OpenZWave { namespace Internal { namespace Platform { /** \brief Windows-specific implementation of the Mutex class. */ class MutexImpl { private: friend class Mutex; MutexImpl(); ~MutexImpl(); bool Lock(bool const _bWait = true); void Unlock(); bool IsSignalled(); CRITICAL_SECTION m_criticalSection; uint32 m_lockCount; // Keep track of the locks (there can be more than one if they occur on the same thread. }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_MutexIF_H openzwave-1.6.1914/cpp/src/platform/windows/EventImpl.cpp0000644000175200017520000000603414032142455020221 00000000000000//----------------------------------------------------------------------------- // // EventImpl.cpp // // Windows implementation of a cross-platform event // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "Defs.h" #include "EventImpl.h" namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- EventImpl::EventImpl() { // Create a manual reset event m_hEvent = ::CreateEvent( NULL, TRUE, FALSE, NULL); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- EventImpl::~EventImpl() { ::CloseHandle(m_hEvent); } //----------------------------------------------------------------------------- // // Set the event to signalled //----------------------------------------------------------------------------- void EventImpl::Set() { ::SetEvent(m_hEvent); } //----------------------------------------------------------------------------- // // Set the event to not signalled //----------------------------------------------------------------------------- void EventImpl::Reset() { ::ResetEvent(m_hEvent); } //----------------------------------------------------------------------------- // // Test whether the event is set //----------------------------------------------------------------------------- bool EventImpl::IsSignalled() { return (WAIT_OBJECT_0 == WaitForSingleObject(m_hEvent, 0)); } //----------------------------------------------------------------------------- // // Wait for the event to become signalled //----------------------------------------------------------------------------- bool EventImpl::Wait(int32 const _timeout) { return (WAIT_TIMEOUT != ::WaitForSingleObject(m_hEvent, (DWORD) _timeout)); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/windows/TimeStampImpl.h0000644000175200017520000000475714032142455020522 00000000000000//----------------------------------------------------------------------------- // // TimeStampImpl.h // // Windows implementation of a TimeStamp // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _TimeStampImpl_H #define _TimeStampImpl_H #include "Defs.h" namespace OpenZWave { namespace Internal { namespace Platform { /** \brief Windows implementation of a timestamp. */ class TimeStampImpl { public: /** * Constructor. * Creates a TimeStampImpl object. */ TimeStampImpl(); /** * Destructor. * Destroys the TimeStampImpl object. */ ~TimeStampImpl(); /** * SetTime. Sets the timestamp to now, plus the offset in milliseconds. * \param _milliseconds positive or negative offset from * now in milliseconds. */ void SetTime(int32 _milliseconds); /** * TimeRemaining. Gets the difference between now and the timestamp * time in milliseconds. * \return milliseconds remaining until we reach the timestamp. The * return value is negative if the timestamp is in the past. */ int32 TimeRemaining(); /** * Return as as string */ string GetAsString(); /** * Overload the subtract operator to get the difference between * two timestamps in milliseconds. */ int32 operator-(TimeStampImpl const& _other); private: TimeStampImpl(TimeStampImpl const&); // prevent copy TimeStampImpl& operator =(TimeStampImpl const&); // prevent assignment int64 m_stamp; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_TimeStampImpl_H openzwave-1.6.1914/cpp/src/platform/windows/LogImpl.cpp0000644000175200017520000002562514032142455017670 00000000000000//----------------------------------------------------------------------------- // // LogImpl.cpp // // Windows implementation of message and error logging // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include #include "Defs.h" #include "LogImpl.h" #ifdef MINGW #define vsprintf_s vsnprintf #define strcpy_s(DEST, NUM, SOURCE) strncpy(DEST, SOURCE, NUM) errno_t fopen_s(FILE** pFile, const char *filename, const char *mode) { if (!pFile) { #if defined(_MSC_VER) && _MSC_VER >= 1400 _set_errno(EINVAL); #elif defined(__MINGW64__) _set_errno(EINVAL); #else errno = EINVAL; #endif return EINVAL; } *pFile = fopen(filename, mode); if (!*pFile) { return errno; } return 0; } #endif namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- LogImpl::LogImpl(string const& _filename, bool const _bAppendLog, bool const _bConsoleOutput, LogLevel const _saveLevel, LogLevel const _queueLevel, LogLevel const _dumpTrigger) : m_filename(_filename), // name of log file m_bConsoleOutput(_bConsoleOutput), // true to provide a copy of output to console m_bAppendLog(_bAppendLog), // true to append (and not overwrite) any existing log m_saveLevel(_saveLevel), // level of messages to log to file m_queueLevel(_queueLevel), // level of messages to log to queue m_dumpTrigger(_dumpTrigger) // dump queued messages when this level is seen { string accessType; // create an adjusted file name and timestamp string string timeStr = GetTimeStampString(); if (m_bAppendLog) { accessType = "a"; } else { accessType = "w"; } FILE* pFile; if (!fopen_s(&pFile, _filename.c_str(), accessType.c_str())) { fprintf(pFile, "\nLogging started %s\n\n", timeStr.c_str()); fclose(pFile); } } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- LogImpl::~LogImpl() { } unsigned int LogImpl::toEscapeCode(LogLevel _level) { unsigned short code; switch (_level) { case LogLevel_Debug: code = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break; //blue case LogLevel_Detail: code = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break; //blue case LogLevel_Info: code = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break; // white case LogLevel_Alert: code = FOREGROUND_RED | FOREGROUND_GREEN; break; // orange case LogLevel_Warning: code = FOREGROUND_RED | FOREGROUND_GREEN; break; // orange case LogLevel_Error: code = FOREGROUND_RED; break; // red case LogLevel_Fatal: code = FOREGROUND_RED | FOREGROUND_INTENSITY; break; // light red case LogLevel_Always: code = FOREGROUND_GREEN; break; // green default: code = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break; // white } return (code); } //----------------------------------------------------------------------------- // // Write to the log //----------------------------------------------------------------------------- void LogImpl::Write(LogLevel _logLevel, uint8 const _nodeId, char const* _format, va_list _args) { // create a timestamp string string timeStr = GetTimeStampString(); string nodeStr = GetNodeString(_nodeId); string logLevelStr = GetLogLevelString(_logLevel); // handle this message if ((_logLevel <= m_queueLevel) || (_logLevel == LogLevel_Internal)) // we're going to do something with this message... { char lineBuf[1024]; if (!_format || (_format[0] == 0)) { strcpy_s(lineBuf, 1024, ""); } else { vsprintf_s(lineBuf, sizeof(lineBuf), _format, _args); } // should this message be saved to file (and possibly written to console?) if ((_logLevel <= m_saveLevel) || (_logLevel == LogLevel_Internal)) { // save to file FILE* pFile = NULL; if (!fopen_s(&pFile, m_filename.c_str(), "a") || m_bConsoleOutput) { if (_logLevel != LogLevel_Internal) // don't add a second timestamp to display of queued messages { if (pFile != NULL) { fprintf(pFile, "%s%s%s", timeStr.c_str(), logLevelStr.c_str(), nodeStr.c_str()); } if (m_bConsoleOutput) { printf("%s%s%s", timeStr.c_str(), logLevelStr.c_str(), nodeStr.c_str()); } } // print message to file (and possibly screen) if (pFile != NULL) { fprintf(pFile, "%s", lineBuf); fprintf(pFile, "\n"); fclose(pFile); } if (m_bConsoleOutput) { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), toEscapeCode(_logLevel)); printf("%s", lineBuf); printf("\n"); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); } } } if (_logLevel != LogLevel_Internal) { char queueBuf[1024]; string threadStr = GetThreadId(); sprintf_s(queueBuf, sizeof(queueBuf), "%s%s%s", timeStr.c_str(), threadStr.c_str(), lineBuf); Queue(queueBuf); } } // now check to see if the _dumpTrigger has been hit if ((_logLevel <= m_dumpTrigger) && (_logLevel != LogLevel_Internal) && (_logLevel != LogLevel_Always)) { QueueDump(); } } //----------------------------------------------------------------------------- // // Write to the log queue //----------------------------------------------------------------------------- void LogImpl::Queue(char const* _buffer) { string bufStr = _buffer; m_logQueue.push_back(bufStr); // rudimentary queue size management if (m_logQueue.size() > 500) { m_logQueue.pop_front(); } } //----------------------------------------------------------------------------- // // Dump the LogQueue to output device //----------------------------------------------------------------------------- void LogImpl::QueueDump() { Log::Write(LogLevel_Internal, "\n\nDumping queued log messages\n"); list::iterator it = m_logQueue.begin(); while (it != m_logQueue.end()) { string strTemp = *it; Log::Write(LogLevel_Internal, "%s", strTemp.c_str()); ++it; } m_logQueue.clear(); Log::Write(LogLevel_Internal, "\nEnd of queued log message dump\n\n"); } //----------------------------------------------------------------------------- // // Clear the LogQueue //----------------------------------------------------------------------------- void LogImpl::QueueClear() { m_logQueue.clear(); } //----------------------------------------------------------------------------- // // Sets the various log state variables //----------------------------------------------------------------------------- void LogImpl::SetLoggingState(LogLevel _saveLevel, LogLevel _queueLevel, LogLevel _dumpTrigger) { m_saveLevel = _saveLevel; m_queueLevel = _queueLevel; m_dumpTrigger = _dumpTrigger; } //----------------------------------------------------------------------------- // // Generate a string with formatted current time //----------------------------------------------------------------------------- string LogImpl::GetTimeStampString() { // Get a timestamp SYSTEMTIME time; ::GetLocalTime(&time); // create a time stamp string for the log message char buf[100]; sprintf_s(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d.%03d ", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond, time.wMilliseconds); string str = buf; return str; } //----------------------------------------------------------------------------- // // Generate a string with formatted node id //----------------------------------------------------------------------------- string LogImpl::GetNodeString(uint8 const _nodeId) { if (_nodeId == 0) { return ""; } else if (_nodeId == 255) // should make distinction between broadcast and controller better for SwitchAll broadcast { return "contrlr, "; } else { char buf[20]; snprintf(buf, sizeof(buf), "Node%03d, ", _nodeId); return buf; } } //----------------------------------------------------------------------------- // // Generate a string with formatted thread id //----------------------------------------------------------------------------- string LogImpl::GetThreadId() { char buf[20]; DWORD dwThread = ::GetCurrentThreadId(); sprintf_s(buf, sizeof(buf), "%04d ", dwThread); string str = buf; return str; } //----------------------------------------------------------------------------- // // Provide a new log file name (applicable to future writes) //----------------------------------------------------------------------------- void LogImpl::SetLogFileName(const string &_filename) { m_filename = _filename; } //----------------------------------------------------------------------------- // // Provide a new log file name (applicable to future writes) //----------------------------------------------------------------------------- string LogImpl::GetLogLevelString(LogLevel _level) { if ((_level >= LogLevel_None) && (_level <= LogLevel_Internal)) { char buf[20]; snprintf(buf, sizeof(buf), "%s, ", LogLevelString[_level]); return buf; } else return "Unknown, "; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/windows/EventImpl.h0000644000175200017520000000327014032142455017665 00000000000000//----------------------------------------------------------------------------- // // EventImpl.h // // Windows implementation of a cross-platform event // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _EventImpl_H #define _EventImpl_H #include #include "Defs.h" namespace OpenZWave { namespace Internal { namespace Platform { /** \brief Windows-specific implementation of the Event class. */ class EventImpl { private: friend class Event; friend class SocketImpl; friend class Wait; EventImpl(); ~EventImpl(); void Set(); void Reset(); bool Wait(int32 _timeout); // The wait method is to be used only by the Wait::Multiple method bool IsSignalled(); HANDLE m_hEvent; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_EventImpl_H openzwave-1.6.1914/cpp/src/platform/windows/TimeStampImpl.cpp0000644000175200017520000000730014032142455021040 00000000000000//----------------------------------------------------------------------------- // // TimeStampImpl.h // // Cross-platform TimeStampImpl // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include "Defs.h" #include "TimeStampImpl.h" namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- TimeStampImpl::TimeStampImpl() { SetTime(0); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- TimeStampImpl::~TimeStampImpl() { } //----------------------------------------------------------------------------- // // Sets the timestamp to now, plus an offset in milliseconds //----------------------------------------------------------------------------- void TimeStampImpl::SetTime(int32 _milliseconds // = 0 ) { int64 offset = ((int64) _milliseconds) * 10000LL; // Timestamp is stored in 100ns steps. GetSystemTimeAsFileTime((FILETIME*) &m_stamp); m_stamp += offset; } //----------------------------------------------------------------------------- // // Gets the difference between now and the timestamp time in milliseconds //----------------------------------------------------------------------------- int32 TimeStampImpl::TimeRemaining() { int64 now; GetSystemTimeAsFileTime((FILETIME*) &now); return (int32) ((m_stamp - now) / 10000LL); } //----------------------------------------------------------------------------- // // Return a string representation //----------------------------------------------------------------------------- string TimeStampImpl::GetAsString() { // Convert m_stamp (FILETIME) to SYSTEMTIME for ease of use SYSTEMTIME time; ::FileTimeToSystemTime((FILETIME*) &m_stamp, &time); char buf[100]; sprintf_s(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d:%03d ", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond, time.wMilliseconds); string str = buf; return str; } //----------------------------------------------------------------------------- // // Overload the subtract operator to get the difference between two // timestamps in milliseconds //----------------------------------------------------------------------------- int32 TimeStampImpl::operator-(TimeStampImpl const& _other) { return (int32) ((m_stamp - _other.m_stamp) / 10000LL); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/windows/SerialControllerImpl.cpp0000644000175200017520000002760014032142455022425 00000000000000//----------------------------------------------------------------------------- // // SerialControllerImpl.cpp // // Windows Implementation of the cross-platform serial port // // Copyright (c) 2010 Jason Frazier // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "SerialControllerImpl.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace Platform { DWORD WINAPI SerialReadThreadEntryPoint(void* _context); //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- SerialControllerImpl::SerialControllerImpl(SerialController* _owner) : m_owner(_owner) { } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- SerialControllerImpl::~SerialControllerImpl() { CloseHandle(m_hSerialController); } //----------------------------------------------------------------------------- // // Open the serial port //----------------------------------------------------------------------------- bool SerialControllerImpl::Open() { // Try to init the serial port if (!Init(1)) { // Failed. We bail to allow the app a chance to take over, rather than retry // automatically. Automatic retries only occur after a successful init. return false; } // Create an event to trigger exiting the read thread m_hExit = ::CreateEvent( NULL, TRUE, FALSE, NULL); // Start the read thread m_hThread = ::CreateThread( NULL, 0, SerialReadThreadEntryPoint, this, CREATE_SUSPENDED, NULL); ::ResumeThread(m_hThread); return true; } //----------------------------------------------------------------------------- // // Close the serial port //----------------------------------------------------------------------------- void SerialControllerImpl::Close() { ::SetEvent(m_hExit); ::WaitForSingleObject(m_hThread, INFINITE); CloseHandle(m_hThread); m_hThread = INVALID_HANDLE_VALUE; CloseHandle(m_hExit); m_hExit = INVALID_HANDLE_VALUE; CloseHandle(m_hSerialController); m_hSerialController = INVALID_HANDLE_VALUE; } //----------------------------------------------------------------------------- // // Entry point of the thread for receiving data from the serial port //----------------------------------------------------------------------------- DWORD WINAPI SerialReadThreadEntryPoint(void* _context) { SerialControllerImpl* impl = (SerialControllerImpl*) _context; if (impl) { impl->ReadThreadProc(); } return 0; } //----------------------------------------------------------------------------- // // Handle receiving data //----------------------------------------------------------------------------- void SerialControllerImpl::ReadThreadProc() { uint32 attempts = 0; while (true) { // Init must have been called successfully during Open, so we // don't do it again until the end of the loop if (INVALID_HANDLE_VALUE != m_hSerialController) { // Enter read loop. Call will only return if // an exit is requested or an error occurs Read(); // Reset the attempts, so we get a rapid retry for temporary errors attempts = 0; } if (attempts < 25) { // Retry every 5 seconds for the first two minutes... if (WAIT_OBJECT_0 == ::WaitForSingleObject(m_hExit, 5000)) { // Exit signalled. break; } } else { // ...retry every 30 seconds after that if (WAIT_OBJECT_0 == ::WaitForSingleObject(m_hExit, 30000)) { // Exit signalled. break; } } Init(++attempts); } } //----------------------------------------------------------------------------- // // Initialize the serial port //----------------------------------------------------------------------------- bool SerialControllerImpl::Init(uint32 const _attempts) { Log::Write(LogLevel_Info, " Trying to open serial port %s (Attempt %d)", m_owner->m_serialControllerName.c_str(), _attempts); m_hSerialController = CreateFileA(m_owner->m_serialControllerName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (INVALID_HANDLE_VALUE == m_hSerialController) { //Error Log::Write(LogLevel_Error, "ERROR: Cannot open serial port %s. Error code %d\n", m_owner->m_serialControllerName.c_str(), GetLastError()); goto SerialOpenFailure; } // Configure the serial device parameters // Build on the current configuration DCB dcb; if (!GetCommState(m_hSerialController, &dcb)) { //Error. Clean up and exit Log::Write(LogLevel_Error, "ERROR: Failed to read serial port state"); goto SerialOpenFailure; } // Fill in the Device Control Block dcb.BaudRate = (DWORD) m_owner->m_baud; dcb.ByteSize = 8; dcb.Parity = (BYTE) m_owner->m_parity; dcb.StopBits = (BYTE) m_owner->m_stopBits; if (!SetCommState(m_hSerialController, &dcb)) { //Error. Clean up and exit Log::Write(LogLevel_Error, "ERROR: Failed to set serial port state"); goto SerialOpenFailure; } // Set the timeouts for the serial port COMMTIMEOUTS commTimeouts; commTimeouts.ReadIntervalTimeout = MAXDWORD; commTimeouts.ReadTotalTimeoutConstant = 0; commTimeouts.ReadTotalTimeoutMultiplier = 0; commTimeouts.WriteTotalTimeoutConstant = 0; commTimeouts.WriteTotalTimeoutMultiplier = 0; if (!SetCommTimeouts(m_hSerialController, &commTimeouts)) { // Error. Clean up and exit Log::Write(LogLevel_Error, "ERROR: Failed to set serial port timeouts"); goto SerialOpenFailure; } // Set the serial port to signal when data is received if (!SetCommMask(m_hSerialController, EV_RXCHAR)) { //Error. Clean up and exit Log::Write(LogLevel_Info, "ERROR: Failed to set serial port mask"); goto SerialOpenFailure; } // Clear any residual data from the serial port PurgeComm(m_hSerialController, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); // Open successful Log::Write(LogLevel_Info, " Serial port %s opened (attempt %d)", m_owner->m_serialControllerName.c_str(), _attempts); return true; SerialOpenFailure: Log::Write(LogLevel_Info, "ERROR: Failed to open serial port %s (attempt %d)", m_owner->m_serialControllerName.c_str(), _attempts); CloseHandle(m_hSerialController); m_hSerialController = INVALID_HANDLE_VALUE; return false; } //----------------------------------------------------------------------------- // // Read data from the serial port //----------------------------------------------------------------------------- void SerialControllerImpl::Read() { uint8 buffer[256]; OVERLAPPED overlapped; memset(&overlapped, 0, sizeof(overlapped)); overlapped.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL); while (true) { // Try to read all available data from the serial port DWORD bytesRead = 0; do { if (::ReadFile(m_hSerialController, buffer, 256, NULL, &overlapped)) { // Read completed GetOverlappedResult(m_hSerialController, &overlapped, &bytesRead, TRUE); // Copy to the stream buffer if (bytesRead > 0) m_owner->Put(buffer, bytesRead); } else { //Wait for the read to complete if (ERROR_IO_PENDING == GetLastError()) { // Wait for the read to complete or the // signal that this thread should exit. HANDLE handles[2]; handles[0] = overlapped.hEvent; handles[1] = m_hExit; DWORD res = WaitForMultipleObjects(2, handles, FALSE, INFINITE); if ((WAIT_OBJECT_0 + 1) == res) { // Exit signalled. Cancel the read. goto exitRead; } if (WAIT_TIMEOUT == res) { // Timed out - should never happen goto exitRead; } // Read completed GetOverlappedResult(m_hSerialController, &overlapped, &bytesRead, TRUE); // Copy to the stream buffer if (bytesRead > 0) m_owner->Put(buffer, bytesRead); } else { // An error has occurred goto exitRead; } } } while (bytesRead > 0); // Clear the event ResetEvent(overlapped.hEvent); // Nothing available to read, so wait for the next rx char event DWORD dwEvtMask; if (!WaitCommEvent(m_hSerialController, &dwEvtMask, &overlapped)) { if (ERROR_IO_PENDING == GetLastError()) { // Wait for either some data to arrive or // the signal that this thread should exit. HANDLE handles[2]; handles[0] = overlapped.hEvent; handles[1] = m_hExit; DWORD res = WaitForMultipleObjects(2, handles, FALSE, INFINITE); if ((WAIT_OBJECT_0 + 1) == res) { // Exit signalled. Prevent WaitCommEvent from corrupting the // stack by forcing it to exit. goto exitRead; } if (WAIT_TIMEOUT == res) { // Timed out - should never happen goto exitRead; } GetOverlappedResult(m_hSerialController, &overlapped, &bytesRead, TRUE); } } // Clear the event ResetEvent(overlapped.hEvent); // Loop back to the top to read the waiting data } exitRead: // Exit event has been signalled, or an error has occurred SetCommMask(m_hSerialController, 0); CancelIo(m_hSerialController); CloseHandle(overlapped.hEvent); } //----------------------------------------------------------------------------- // // Send data to the serial port //----------------------------------------------------------------------------- uint32 SerialControllerImpl::Write(uint8* _buffer, uint32 _length) { if (INVALID_HANDLE_VALUE == m_hSerialController) { //Error Log::Write(LogLevel_Error, "ERROR: Serial port must be opened before writing\n"); return 0; } // Write the data OVERLAPPED overlapped; memset(&overlapped, 0, sizeof(overlapped)); overlapped.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL); DWORD bytesWritten; if (!::WriteFile(m_hSerialController, _buffer, _length, &bytesWritten, &overlapped)) { //Wait for the write to complete if (ERROR_IO_PENDING == GetLastError()) { GetOverlappedResult(m_hSerialController, &overlapped, &bytesWritten, TRUE); } else { Log::Write(LogLevel_Error, "ERROR: Serial port write (0x%.8x)", GetLastError()); } } CloseHandle(overlapped.hEvent); return (uint32) bytesWritten; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/windows/WaitImpl.cpp0000644000175200017520000000757614032142455020060 00000000000000//----------------------------------------------------------------------------- // // WaitImpl.cpp // // Windows implementation of an abstract base class for objects we // want to be able to wait for. // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "platform/Wait.h" #include "WaitImpl.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- WaitImpl::WaitImpl(Wait* _owner) : m_owner(_owner) { InitializeCriticalSection(&m_criticalSection); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- WaitImpl::~WaitImpl() { DeleteCriticalSection(&m_criticalSection); } //----------------------------------------------------------------------------- // // Add a watcher to our object. //----------------------------------------------------------------------------- void WaitImpl::AddWatcher(Wait::pfnWaitNotification_t _callback, void* _context) { // Add the watcher to our list Watcher watcher; watcher.m_callback = _callback; watcher.m_context = _context; EnterCriticalSection(&m_criticalSection); m_watchers.push_back(watcher); LeaveCriticalSection(&m_criticalSection); // If the object is already in a signalled state, notify the watcher immediately if (m_owner->IsSignalled()) { _callback(_context); } } //----------------------------------------------------------------------------- // // Remove a watcher from our object. //----------------------------------------------------------------------------- bool WaitImpl::RemoveWatcher(Wait::pfnWaitNotification_t _callback, void* _context) { bool res = false; EnterCriticalSection(&m_criticalSection); for (list::iterator it = m_watchers.begin(); it != m_watchers.end(); ++it) { Watcher const& watcher = *it; if ((watcher.m_callback == _callback) && (watcher.m_context == _context)) { m_watchers.erase(it); res = true; break; } } LeaveCriticalSection(&m_criticalSection); return res; } //----------------------------------------------------------------------------- // // Notify all the watchers that the object has become signalled //----------------------------------------------------------------------------- void WaitImpl::Notify() { EnterCriticalSection(&m_criticalSection); for (list::iterator it = m_watchers.begin(); it != m_watchers.end(); ++it) { Watcher const& watcher = *it; watcher.m_callback(watcher.m_context); } LeaveCriticalSection(&m_criticalSection); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/windows/ThreadImpl.cpp0000644000175200017520000001070114032142455020343 00000000000000//----------------------------------------------------------------------------- // // ThreadImpl.cpp // // Windows implementation of a cross-platform thread // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "platform/Event.h" #include "platform/Thread.h" #include "ThreadImpl.h" namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ThreadImpl::ThreadImpl(Thread* _owner, string const& _name) : m_owner(_owner), m_hThread(INVALID_HANDLE_VALUE), m_bIsRunning(false), m_name(_name) { } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- ThreadImpl::~ThreadImpl() { } //----------------------------------------------------------------------------- // // Start a function running on this thread //----------------------------------------------------------------------------- bool ThreadImpl::Start(Thread::pfnThreadProc_t _pfnThreadProc, Event* _exitEvent, void* _context) { // Create a thread to run the specified function m_pfnThreadProc = _pfnThreadProc; m_context = _context; m_exitEvent = _exitEvent; m_exitEvent->Reset(); HANDLE hThread = ::CreateThread( NULL, 0, ThreadImpl::ThreadProc, this, CREATE_SUSPENDED, NULL); m_hThread = hThread; ::ResumeThread(hThread); return true; } //----------------------------------------------------------------------------- // // Cause thread to sleep for the specified number of milliseconds //----------------------------------------------------------------------------- void ThreadImpl::Sleep(uint32 _millisecs) { ::Sleep(_millisecs); } //----------------------------------------------------------------------------- // // Force the thread to stop //----------------------------------------------------------------------------- bool ThreadImpl::Terminate() { if (!m_bIsRunning) { return false; } // This can cause all sorts of trouble if the thread is holding a lock. TerminateThread(m_hThread, 0); m_hThread = INVALID_HANDLE_VALUE; return true; } //----------------------------------------------------------------------------- // // Test whether the thread has completed //----------------------------------------------------------------------------- bool ThreadImpl::IsSignalled() { return !m_bIsRunning; } //----------------------------------------------------------------------------- // // Entry point for running a function on this thread //----------------------------------------------------------------------------- DWORD WINAPI ThreadImpl::ThreadProc(void* _pArg) { ThreadImpl* pImpl = (ThreadImpl*) _pArg; pImpl->Run(); return 0; } //----------------------------------------------------------------------------- // // Entry point for running a function on this thread //----------------------------------------------------------------------------- void ThreadImpl::Run() { m_bIsRunning = true; m_pfnThreadProc(m_exitEvent, m_context); m_bIsRunning = false; // Let any watchers know that the thread has finished running. m_owner->Notify(); } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/platform/windows/LogImpl.h0000644000175200017520000000513714032142455017331 00000000000000//----------------------------------------------------------------------------- // // LogImpl.h // // Windows implementation of message and error logging // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _LogImpl_H #define _LogImpl_H #include "Defs.h" #include #include "platform/Log.h" #include namespace OpenZWave { namespace Internal { namespace Platform { /** \brief Windows-specific implementation of the Log class. */ class LogImpl: public i_LogImpl { private: friend class OpenZWave::Log; LogImpl(string const& _filename, bool const _bAppendLog, bool const _bConsoleOutput, LogLevel const _saveLevel, LogLevel const _queueLevel, LogLevel const _dumpTrigger); ~LogImpl(); void Write(LogLevel _level, uint8 const _nodeId, char const* _format, va_list _args); void Queue(char const* _buffer); void QueueDump(); void QueueClear(); void SetLoggingState(LogLevel _saveLevel, LogLevel _queueLevel, LogLevel _dumpTrigger); void SetLogFileName(const string &_filename); string GetTimeStampString(); string GetNodeString(uint8 const _nodeId); string GetThreadId(); string GetLogLevelString(LogLevel _level); unsigned int toEscapeCode(LogLevel _level); string m_filename; /**< filename specified by user (default is ozw_log.txt) */ bool m_bConsoleOutput; /**< if true, send log output to console as well as to the file */ bool m_bAppendLog; /**< if true, the log file should be appended to any with the same name */ list m_logQueue; /**< list of queued log messages */ LogLevel m_saveLevel; LogLevel m_queueLevel; LogLevel m_dumpTrigger; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_LogImpl_H openzwave-1.6.1914/cpp/src/platform/windows/SerialControllerImpl.h0000644000175200017520000000347514032142455022076 00000000000000//----------------------------------------------------------------------------- // // SerialControllerImpl.h // // Windows Implementation of the cross-platform serial port // // Copyright (c) 2010 Jason Frazier // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _SerialControllerImpl_H #define _SerialControllerImpl_H #include #include "Defs.h" #include "platform/SerialController.h" namespace OpenZWave { namespace Internal { namespace Platform { class SerialControllerImpl { public: void ReadThreadProc(); private: friend class SerialController; SerialControllerImpl(SerialController* _owner); ~SerialControllerImpl(); bool Open(); void Close(); uint32 Write(uint8* _buffer, uint32 _length); bool Init(uint32 const _attempts); void Read(); SerialController* m_owner; HANDLE m_hThread; HANDLE m_hExit; HANDLE m_hSerialController; }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_SerialControllerImpl_H openzwave-1.6.1914/cpp/src/platform/Log.cpp0000644000175200017520000002651214032142455015350 00000000000000//----------------------------------------------------------------------------- // // Log.cpp // // Cross-platform message and error logging // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "Defs.h" #include "platform/Mutex.h" #include "platform/Log.h" #ifdef WIN32 #include "platform/windows/LogImpl.h" // Platform-specific implementation of a log #elif defined WINRT #include "platform/winRT/LogImpl.h" // Platform-specific implementation of a log #else #include "platform/unix/LogImpl.h" // Platform-specific implementation of a log #endif using namespace OpenZWave; char const *OpenZWave::LogLevelString[] = { "Invalid", /**< Invalid Log Level Status - Used to Indicate error from Importing bad Options.xml */ "None", /**< LogLevel_None Disable all logging */ "Always", /**< LogLevel_Always These messages should always be shown */ "Fatal", /**< LogLevel_Fatal A likely fatal issue in the library */ "Error", /**< LogLevel_Error A serious issue with the library or the network */ "Warning", /**< LogLevel_Warning A minor issue from which the library should be able to recover */ "Alert", /**< LogLevel_Alert Something unexpected by the library about which the controlling application should be aware */ "Info", /**< LogLevel_Info Everything's working fine...these messages provide streamlined feedback on each message */ "Detail", /**< LogLevel_Detail Detailed information on the progress of each message */ "Debug", /**< LogLevel_Debug Very detailed information on progress that will create a huge log file quickly But this level (as others) can be queued and sent to the log only on an error or warning */ "StreamDetail", /**< LogLevel_StreamDetail Will include low-level byte transfers from controller to buffer to application and back */ "Internal" /**< LogLevel_Internal Used only within the log class (uses existing timestamp, etc.) */ }; Log* Log::s_instance = NULL; std::vector Log::m_pImpls; static bool s_dologging; //----------------------------------------------------------------------------- // // Static creation of the singleton //----------------------------------------------------------------------------- Log* Log::Create(string const& _filename, bool const _bAppend, bool const _bConsoleOutput, LogLevel const _saveLevel, LogLevel const _queueLevel, LogLevel const _dumpTrigger) { if ( NULL == s_instance) { s_instance = new Log(_filename, _bAppend, _bConsoleOutput, _saveLevel, _queueLevel, _dumpTrigger); s_dologging = true; // default logging to true so no change to what people experience now } else { Log::Destroy(); s_instance = new Log(_filename, _bAppend, _bConsoleOutput, _saveLevel, _queueLevel, _dumpTrigger); s_dologging = true; // default logging to true so no change to what people experience now } return s_instance; } //----------------------------------------------------------------------------- // // Static creation of the singleton //----------------------------------------------------------------------------- /* It isn't clear this is ever called or used. If no one complains, consider deleting this code in April 2012. Log* Log::Create ( i_LogImpl *LogClass ) { if (NULL == s_instance ) { s_instance = new Log( "" ); s_dologging = true; } SetLoggingClass( LogClass ); return s_instance; } */ //----------------------------------------------------------------------------- // // Static method to destroy the logging singleton. //----------------------------------------------------------------------------- void Log::Destroy() { delete s_instance; s_instance = NULL; } //----------------------------------------------------------------------------- // // Set log class //----------------------------------------------------------------------------- bool Log::SetLoggingClass(i_LogImpl *LogClass, bool Append) { if (!Append) { for (std::vector::iterator it = s_instance->m_pImpls.begin(); it != s_instance->m_pImpls.end();) { i_LogImpl *lc = *it; delete lc; it = s_instance->m_pImpls.erase(it); } } s_instance->m_pImpls.push_back(LogClass); return true; } //----------------------------------------------------------------------------- // // Set flag to actually write to log or skip it (legacy version) // If logging is enabled, the default log detail settings will be used // Write to file/screen LogLevel_Detail // Save in queue for errors LogLevel_Debug // Trigger for dumping queue LogLevel_Warning // Console output? Yes // Append to an existing log? No (overwrite) //----------------------------------------------------------------------------- void Log::SetLoggingState(bool _dologging) { bool prevLogging = s_dologging; s_dologging = _dologging; if (!prevLogging && s_dologging) Log::Write(LogLevel_Always, "Logging started\n\n"); } //----------------------------------------------------------------------------- // // Set flag to actually write to log or skip it //----------------------------------------------------------------------------- void Log::SetLoggingState(LogLevel _saveLevel, LogLevel _queueLevel, LogLevel _dumpTrigger) { // parameter checking: // _queueLevel cannot be less than or equal to _saveLevel (where lower ordinals are more severe conditions) // _dumpTrigger cannot be greater than or equal to _queueLevel if (_queueLevel <= _saveLevel) Log::Write(LogLevel_Warning, "Only lower priority messages may be queued for error-driven display."); if (_dumpTrigger >= _queueLevel) Log::Write(LogLevel_Warning, "The trigger for dumping queued messages must be a higher-priority message than the level that is queued."); bool prevLogging = s_dologging; // s_dologging is true if any messages are to be saved in file or queue if ((_saveLevel > LogLevel_Always) || (_queueLevel > LogLevel_Always)) { s_dologging = true; } else { s_dologging = false; } if (s_instance && s_dologging && (s_instance->m_pImpls.size() > 0)) { s_instance->m_logMutex->Lock(); for (std::vector::iterator it = s_instance->m_pImpls.begin(); it != s_instance->m_pImpls.end(); it++) (*it)->SetLoggingState(_saveLevel, _queueLevel, _dumpTrigger); s_instance->m_logMutex->Unlock(); } if (!prevLogging && s_dologging) Log::Write(LogLevel_Always, "Logging started\n\n"); } //----------------------------------------------------------------------------- // // Return a flag to indicate whether logging is enabled //----------------------------------------------------------------------------- bool Log::GetLoggingState() { return s_dologging; } //----------------------------------------------------------------------------- // // Write to the log //----------------------------------------------------------------------------- void Log::Write(LogLevel _level, char const* _format, ...) { if (s_instance && s_dologging && (s_instance->m_pImpls.size() > 0)) { s_instance->m_logMutex->Lock(); // double locks if recursive va_list args; va_start(args, _format); for (std::vector::iterator it = s_instance->m_pImpls.begin(); it != s_instance->m_pImpls.end(); it++) (*it)->Write(_level, 0, _format, args); va_end(args); s_instance->m_logMutex->Unlock(); } } //----------------------------------------------------------------------------- // // Write to the log //----------------------------------------------------------------------------- void Log::Write(LogLevel _level, uint8 const _nodeId, char const* _format, ...) { if (s_instance && s_dologging && (s_instance->m_pImpls.size() > 0)) { if (_level != LogLevel_Internal) s_instance->m_logMutex->Lock(); va_list args; va_start(args, _format); for (std::vector::iterator it = s_instance->m_pImpls.begin(); it != s_instance->m_pImpls.end(); it++) (*it)->Write(_level, _nodeId, _format, args); va_end(args); if (_level != LogLevel_Internal) s_instance->m_logMutex->Unlock(); } } //----------------------------------------------------------------------------- // // Send queued messages to the log (and empty the queue) //----------------------------------------------------------------------------- void Log::QueueDump() { if (s_instance && s_dologging && (s_instance->m_pImpls.size() > 0)) { s_instance->m_logMutex->Lock(); for (std::vector::iterator it = s_instance->m_pImpls.begin(); it !=s_instance->m_pImpls.end(); it++) (*it)->QueueDump(); s_instance->m_logMutex->Unlock(); } } //----------------------------------------------------------------------------- // // Empty the queued message queue //----------------------------------------------------------------------------- void Log::QueueClear() { if (s_instance && s_dologging && (s_instance->m_pImpls.size() > 0)) { s_instance->m_logMutex->Lock(); for (std::vector::iterator it = s_instance->m_pImpls.begin(); it !=s_instance->m_pImpls.end(); it++) (*it)->QueueClear(); s_instance->m_logMutex->Unlock(); } } //----------------------------------------------------------------------------- // // Change the name of the log file (will start writing a new file) //----------------------------------------------------------------------------- void Log::SetLogFileName(const string &_filename) { if (s_instance && s_dologging && (s_instance->m_pImpls.size() > 0)) { s_instance->m_logMutex->Lock(); for (std::vector::iterator it = s_instance->m_pImpls.begin(); it !=s_instance->m_pImpls.end(); it++) (*it)->SetLogFileName(_filename); s_instance->m_logMutex->Unlock(); } } //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Log::Log(string const& _filename, bool const _bAppend, bool const _bConsoleOutput, LogLevel const _saveLevel, LogLevel const _queueLevel, LogLevel const _dumpTrigger) : m_logMutex(new Internal::Platform::Mutex()) { if (m_pImpls.size() == 0) { m_pImpls.push_back(new Internal::Platform::LogImpl(_filename, _bAppend, _bConsoleOutput, _saveLevel, _queueLevel, _dumpTrigger)); } } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- Log::~Log() { m_logMutex->Release(); for (std::vector::iterator it = s_instance->m_pImpls.begin(); it != s_instance->m_pImpls.end();) { i_LogImpl *lc = *it; delete lc; it = s_instance->m_pImpls.erase(it); } } openzwave-1.6.1914/cpp/src/platform/Mutex.h0000644000175200017520000000511614032142455015373 00000000000000//----------------------------------------------------------------------------- // // Mutex.h // // Cross-platform mutex // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Mutex_H #define _Mutex_H #include "platform/Wait.h" namespace OpenZWave { namespace Internal { namespace Platform { class MutexImpl; /** \brief Implements a platform-independent mutex--for serializing access to a shared resource. * \ingroup Platform */ class Mutex: public Wait { public: /** * Constructor. * Creates a mutex object that can be used to serialize access to a shared resource. */ Mutex(); /** * Lock the mutex. * Attempts to lock the mutex. * There must be a matching call to Release for every call to Lock. * \param _bWait Defaults to true. Set this argument to false if the method should return * immediately, even if the lock is not available. * \return True if the lock was obtained. * \see Unlock */ bool Lock(bool const _bWait = true); /** * Releases the lock on the mutex. * There must be a matching call to Release for every call to Lock. * \see Lock */ void Unlock(); /** * Used by the Wait class to test whether the mutex is free. */ virtual bool IsSignalled(); protected: /** * Destructor. * Destroys the mutex object. */ ~Mutex(); private: Mutex(Mutex const&); // prevent copy Mutex& operator =(Mutex const&); // prevent assignment MutexImpl* m_pImpl; // Pointer to an object that encapsulates the platform-specific implementation of a mutex. }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_Mutex_H openzwave-1.6.1914/cpp/src/platform/Controller.h0000644000175200017520000000665214032142455016422 00000000000000//----------------------------------------------------------------------------- // // Controller.h // // Cross-platform, hardware-abstracted controller data interface // // Copyright (c) 2010 Jason Frazier // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Controller_H #define _Controller_H #include #include #include "Defs.h" #include "Driver.h" #include "platform/Stream.h" namespace OpenZWave { namespace Internal { namespace Platform { /** \defgroup Platform Platform Abstraction Support * * These files abstract differences in platforms that OZW supports * */ /** \brief Represents a USB Controller * \ingroup Platform * * Controller is derived from Stream rather than containing one, so that * we can use its Wait abilities without having to duplicate them here. * The stream is used for input. Buffering of output is handled by the OS. */ class Controller: public Stream { public: /** * Consructor. * Creates the controller object. */ Controller() : Stream(2048) { } /** * Destructor. * Destroys the controller object. */ virtual ~Controller() { } /** * Open a controller. * Attempts to open a controller and initialize it with the specified paramters. * @param _controllerName The name of the port to open. For example, ttyS1 on Linux, or \\.\COM2 in Windows. * @see Close, Read, Write */ virtual bool Open(string const& _controllerName) = 0; /** * Close a controller. * Closes the controller. * @return True if the controller was closed successfully, or false if the controller was already closed, or an error occurred. * @see Open */ virtual bool Close() = 0; /** * Write to a controller. * Attempts to write data to an open controller. * @param _buffer Pointer to a block of memory containing the data to be written. * @param _length Length in bytes of the data. * @return The number of bytes written. * @see Read, Open, Close */ virtual uint32 Write(uint8* _buffer, uint32 _length) = 0; /** * Read from a controller. * Attempts to read data from an open controller. * @param _buffer Pointer to a block of memory large enough to hold the requested data. * @param _length Length in bytes of the data to be read. * @return The number of bytes read. * @see Write, Open, Close */ uint32 Read(uint8* _buffer, uint32 _length); }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_Controller_H openzwave-1.6.1914/cpp/src/platform/Ref.h0000644000175200017520000000506314032142455015006 00000000000000//----------------------------------------------------------------------------- // // Ref.h // // Reference counting for objects. // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Ref_H #define _Ref_H #pragma once #include "Defs.h" namespace OpenZWave { namespace Internal { namespace Platform { /** * Provides reference counting for objects. * Any class wishing to include reference counting should be derived from Ref. * Derived classes must declare their destructor as protected virtual. * On construction, the reference count is set to one. Calls to AddRef increment * the count. Calls to Release decrement the count. When the count reaches * zero, the object is deleted. * \ingroup Platform */ class Ref { public: /** * Initializes the RefCount to one. The object * can only be deleted through a call to Release. * \see AddRef, Release */ Ref() { m_refs = 1; } /** * Increases the reference count of the object. * Every call to AddRef requires a matching call * to Release before the object will be deleted. * \see Release */ void AddRef() { ++m_refs; } /** * Removes a reference to an object. * If this was the last reference to the message, the * object is deleted. * \see AddRef */ int32 Release() { if (0 >= (--m_refs)) { delete this; return 0; } return m_refs; } protected: virtual ~Ref() { } private: // Reference counting int32 m_refs; }; // class Ref }// namespace Platform } // namespace Internal } // namespace OpenZWave #endif // _Ref_H openzwave-1.6.1914/cpp/src/platform/TimeStamp.h0000644000175200017520000000524214032142455016174 00000000000000//----------------------------------------------------------------------------- // // TimeStamp.h // // Cross-platform TimeStamp // // Copyright (c) 2010 Mal Lansell // All rights reserved. // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _TimeStamp_H #define _TimeStamp_H #include "Defs.h" namespace OpenZWave { namespace Internal { namespace Platform { class TimeStampImpl; /** \brief Implements a platform-independent TimeStamp. * \ingroup Platform */ class OPENZWAVE_EXPORT TimeStamp { public: /** * Constructor. * Creates a TimeStamp object. */ TimeStamp(); /** * Destructor. * Destroys the TimeStamp object. */ ~TimeStamp(); /** * SetTime. Sets the timestamp to now, plus the offset in milliseconds. * \param _milliseconds optional positive or negative offset from * now in milliseconds. Defaults to zero. */ void SetTime(int32 _milliseconds = 0); /** * TimeRemaining. Gets the difference between now and the timestamp * time in milliseconds. * \return milliseconds remaining until we reach the timestamp. The * return value is negative if the timestamp is in the past. */ int32 TimeRemaining(); /** * Return as a string for output. * \return string */ string GetAsString(); /** * Overload the subtract operator to get the difference between * two timestamps in milliseconds. */ int32 operator-(TimeStamp const& _other); private: TimeStamp(TimeStamp const&); // prevent copy TimeStamp& operator =(TimeStamp const&); // prevent assignment TimeStampImpl* m_pImpl; // Pointer to an object that encapsulates the platform-specific implementation of the TimeStamp. }; } // namespace Platform } // namespace Internal } // namespace OpenZWave #endif //_TimeStamp_H openzwave-1.6.1914/cpp/src/platform/Controller.cpp0000644000175200017520000000324514032142455016750 00000000000000//----------------------------------------------------------------------------- // // Controller.cpp // // Cross-platform, hardware-abstracted controller data interface // // Copyright (c) 2010 Jason Frazier // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "Driver.h" #include "platform/Controller.h" namespace OpenZWave { namespace Internal { namespace Platform { //----------------------------------------------------------------------------- // // Read from a controller //----------------------------------------------------------------------------- uint32 Controller::Read(uint8* _buffer, uint32 _length) { // Fetch the data from the ring buffer (which is an all or nothing read) if (Get(_buffer, _length)) { return _length; } return 0; } } // namespace Platform } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/ManufacturerSpecificDB.cpp0000644000175200017520000004222214032142455017307 00000000000000//----------------------------------------------------------------------------- // // ManufacturerSpecificDB.cpp // // Interface for Handling Device Configuration Files. // // Copyright (c) 2016 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "ManufacturerSpecificDB.h" #include "tinyxml.h" #include "Options.h" #include "Driver.h" #include "platform/Log.h" #include "platform/FileOps.h" #include "platform/Mutex.h" #include "Notification.h" #include "Utils.h" namespace OpenZWave { namespace Internal { ManufacturerSpecificDB *ManufacturerSpecificDB::s_instance = NULL; std::map ManufacturerSpecificDB::s_manufacturerMap; std::map > ManufacturerSpecificDB::s_productMap; bool ManufacturerSpecificDB::s_bXmlLoaded = false; ManufacturerSpecificDB *ManufacturerSpecificDB::Create() { if ( NULL == s_instance) { s_instance = new ManufacturerSpecificDB(); } return s_instance; } void ManufacturerSpecificDB::Destroy() { delete s_instance; s_instance = NULL; } ManufacturerSpecificDB::ManufacturerSpecificDB() : m_MfsMutex(new Internal::Platform::Mutex()), m_revision(0), m_latestRevision(0), m_initializing(true) { // Ensure the singleton instance is set s_instance = this; if (!s_bXmlLoaded) { if (!LoadProductXML()) { OZW_ERROR(OZWException::OZWEXCEPTION_CONFIG, "Cannot Load/Read ManufacturerSpecificDB! - Missing/Invalid Config File?"); } } } ManufacturerSpecificDB::~ManufacturerSpecificDB() { if (!s_bXmlLoaded) UnloadProductXML(); } //----------------------------------------------------------------------------- // // Load the Config File Revision from each config file specified in our // ManufacturerSpecific.xml file //----------------------------------------------------------------------------- void ManufacturerSpecificDB::LoadConfigFileRevision(ProductDescriptor *product) { // Parse the Z-Wave manufacturer and product XML file. string configPath; Options::Get()->GetOptionAsString("ConfigPath", &configPath); if (product->GetConfigPath().size() > 0) { string path = configPath + product->GetConfigPath(); TiXmlDocument* pDoc = new TiXmlDocument(); if (!pDoc->LoadFile(path.c_str(), TIXML_ENCODING_UTF8)) { delete pDoc; Log::Write(LogLevel_Info, "Unable to load config file %s", path.c_str()); return; } pDoc->SetUserData((void *) path.c_str()); TiXmlElement const* root = pDoc->RootElement(); char const *str = root->Value(); if (str && !strcmp(str, "Product")) { str = root->Attribute("xmlns"); if (str && strcmp(str, "https://github.com/OpenZWave/open-zwave")) { Log::Write(LogLevel_Info, "Product Config File % has incorrect xml Namespace", path.c_str()); delete pDoc; return; } // Read in the revision attributes str = root->Attribute("Revision"); if (!str) { Log::Write(LogLevel_Info, "Error in Product Config file at line %d - missing Revision attribute", root->Row()); delete pDoc; return; } product->SetConfigRevision(atol(str)); } delete pDoc; } } //----------------------------------------------------------------------------- // // Load the XML that maps manufacturer and product IDs to human-readable names //----------------------------------------------------------------------------- bool ManufacturerSpecificDB::LoadProductXML() { LockGuard LG(m_MfsMutex); // Parse the Z-Wave manufacturer and product XML file. string configPath; Options::Get()->GetOptionAsString("ConfigPath", &configPath); string filename = configPath + "manufacturer_specific.xml"; TiXmlDocument* pDoc = new TiXmlDocument(); if (!pDoc->LoadFile(filename.c_str(), TIXML_ENCODING_UTF8)) { delete pDoc; Log::Write(LogLevel_Info, "Unable to load %s", filename.c_str()); return false; } pDoc->SetUserData((void *) filename.c_str()); TiXmlElement const* root = pDoc->RootElement(); char const* str; char* pStopChar; str = root->Attribute("Revision"); if (str) { Log::Write(LogLevel_Info, "Manufacturer_Specific.xml file Revision is %s", str); m_revision = atoi(str); } else { Log::Write(LogLevel_Warning, "Manufacturer_Specific.xml file has no Revision"); m_revision = 0; } TiXmlElement const* manufacturerElement = root->FirstChildElement(); while (manufacturerElement) { str = manufacturerElement->Value(); if (str && !strcmp(str, "Manufacturer")) { // Read in the manufacturer attributes str = manufacturerElement->Attribute("id"); if (!str) { Log::Write(LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing manufacturer id attribute", manufacturerElement->Row()); delete pDoc; return false; } uint16 manufacturerId = (uint16) strtol(str, &pStopChar, 16); str = manufacturerElement->Attribute("name"); if (!str) { Log::Write(LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing manufacturer name attribute", manufacturerElement->Row()); delete pDoc; return false; } // Add this manufacturer to the map s_manufacturerMap[manufacturerId] = str; // Parse all the products for this manufacturer TiXmlElement const* productElement = manufacturerElement->FirstChildElement(); while (productElement) { str = productElement->Value(); if (str && !strcmp(str, "Product")) { str = productElement->Attribute("type"); if (!str) { Log::Write(LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing product type attribute", productElement->Row()); delete pDoc; return false; } uint16 productType = (uint16) strtol(str, &pStopChar, 16); str = productElement->Attribute("id"); if (!str) { Log::Write(LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing product id attribute", productElement->Row()); delete pDoc; return false; } uint16 productId = (uint16) strtol(str, &pStopChar, 16); str = productElement->Attribute("name"); if (!str) { Log::Write(LogLevel_Info, "Error in manufacturer_specific.xml at line %d - missing product name attribute", productElement->Row()); delete pDoc; return false; } string productName = str; // Optional config path string dconfigPath; str = productElement->Attribute("config"); if (str) { dconfigPath = str; } // Add the product to the map ProductDescriptor* product = new ProductDescriptor(manufacturerId, productType, productId, productName, s_manufacturerMap[manufacturerId], dconfigPath); if (s_productMap[product->GetKey()] != NULL) { std::shared_ptr c = s_productMap[product->GetKey()]; Log::Write(LogLevel_Info, "Product name collision: %s type %x id %x manufacturerid %x, collides with %s, type %x id %x manufacturerid %x", productName.c_str(), productType, productId, manufacturerId, c->GetProductName().c_str(), c->GetProductType(), c->GetProductId(), c->GetManufacturerId()); delete product; } else { LoadConfigFileRevision(product); s_productMap[product->GetKey()] = std::shared_ptr(product); } } // Move on to the next product. productElement = productElement->NextSiblingElement(); } } // Move on to the next manufacturer. manufacturerElement = manufacturerElement->NextSiblingElement(); } s_bXmlLoaded = true; delete pDoc; return true; } //----------------------------------------------------------------------------- // // Free the XML that maps manufacturer and product IDs //----------------------------------------------------------------------------- void ManufacturerSpecificDB::UnloadProductXML() { LockGuard LG(m_MfsMutex); if (s_bXmlLoaded) { map >::iterator pit = s_productMap.begin(); while (!s_productMap.empty()) { s_productMap.erase(pit); pit = s_productMap.begin(); } map::iterator mit = s_manufacturerMap.begin(); while (!s_manufacturerMap.empty()) { s_manufacturerMap.erase(mit); mit = s_manufacturerMap.begin(); } s_bXmlLoaded = false; } } void ManufacturerSpecificDB::checkConfigFiles(Driver *driver) { LockGuard LG(m_MfsMutex); if (!s_bXmlLoaded) { if (!LoadProductXML()) { OZW_ERROR(OZWException::OZWEXCEPTION_CONFIG, "Cannot Load/Read ManufacturerSpecificDB! - Missing/Invalid Config File?"); } } string configPath; Options::Get()->GetOptionAsString("ConfigPath", &configPath); map >::iterator pit; for (pit = s_productMap.begin(); pit != s_productMap.end(); pit++) { std::shared_ptr c = pit->second; if (c->GetConfigPath().size() > 0) { string path = configPath + c->GetConfigPath(); if (!Internal::Platform::FileOps::Create()->FileExists(path)) { /* check if we are downloading already */ std::list::iterator iter = std::find(m_downloading.begin(), m_downloading.end(), path); /* check if the file exists */ if (iter == m_downloading.end()) { Log::Write(LogLevel_Warning, "Config File for %s does not exist - %s", c->GetProductName().c_str(), path.c_str()); /* try to download it */ if (driver->startConfigDownload(c->GetManufacturerId(), c->GetProductType(), c->GetProductId(), path)) { m_downloading.push_back(path); } else { Log::Write(LogLevel_Warning, "Can't download file %s", path.c_str()); Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetUserAlertNotification(Notification::Alert_ConfigFileDownloadFailed); driver->QueueNotification(notification); } } else if (iter != m_downloading.end()) { Log::Write(LogLevel_Debug, "Config file for %s already queued", c->GetProductName().c_str()); } } else { checkConfigFileContents(driver, path); } } } checkInitialized(); } void ManufacturerSpecificDB::configDownloaded(Driver *driver, string file, uint8 node, bool success) { /* check if we are downloading already */ std::list::iterator iter = std::find(m_downloading.begin(), m_downloading.end(), file); if (iter != m_downloading.end()) { m_downloading.erase(iter); if ((node > 0) && success) { driver->refreshNodeConfig(node); } else { checkInitialized(); } } else { Log::Write(LogLevel_Warning, "File is not in the list of downloading files: %s", file.c_str()); checkInitialized(); } } void ManufacturerSpecificDB::checkConfigFileContents(Driver *driver, string file) { string configPath; Options::Get()->GetOptionAsString("ConfigPath", &configPath); TiXmlDocument* pDoc = new TiXmlDocument(); if (!pDoc->LoadFile(file.c_str(), TIXML_ENCODING_UTF8)) { delete pDoc; Log::Write(LogLevel_Info, "Unable to load %s", file.c_str()); return; } pDoc->SetUserData((void *) file.c_str()); TiXmlElement const* root = pDoc->RootElement(); TiXmlElement const* metaDataElement = root->FirstChildElement("MetaData"); if (metaDataElement) { TiXmlElement const* metaDataItem = metaDataElement->FirstChildElement("MetaDataItem"); while (metaDataItem) { char const *str = metaDataItem->Attribute("name"); if (str && !strcmp(str, "ProductPic")) { str = metaDataItem->GetText(); if (str) { string imagefile = configPath + str; if (!Internal::Platform::FileOps::Create()->FileExists(imagefile)) { /* check if we are downloading already */ std::list::iterator iter = std::find(m_downloading.begin(), m_downloading.end(), imagefile); /* check if the file exists */ if (iter == m_downloading.end()) { if (driver->startDownload(imagefile, metaDataItem->GetText())) { Log::Write(LogLevel_Info, "Missing Picture %s - Starting Download", imagefile.c_str()); m_downloading.push_back(imagefile); } } } } } metaDataItem = metaDataItem->NextSiblingElement("MetaDataItem"); } } } void ManufacturerSpecificDB::fileDownloaded(Driver *, string file, bool success) { /* check if we are downloading already */ std::list::iterator iter = std::find(m_downloading.begin(), m_downloading.end(), file); if (iter != m_downloading.end()) { m_downloading.erase(iter); } checkInitialized(); } void ManufacturerSpecificDB::mfsConfigDownloaded(Driver *driver, string file, bool success) { /* check if we are downloading already */ std::list::iterator iter = std::find(m_downloading.begin(), m_downloading.end(), file); if (iter != m_downloading.end()) { m_downloading.erase(iter); if (success) { UnloadProductXML(); if (!LoadProductXML()) { OZW_ERROR(OZWException::OZWEXCEPTION_CONFIG, "Cannot Load/Read ManufacturerSpecificDB! - Missing/Invalid Config File?"); } checkConfigFiles(driver); } } else { Log::Write(LogLevel_Warning, "File is not in the list of downloading files: %s", file.c_str()); } checkInitialized(); } bool ManufacturerSpecificDB::isReady() { if (!m_initializing && (m_downloading.size() == 0)) return true; return false; } void ManufacturerSpecificDB::checkInitialized() { if (!m_initializing) return; Log::Write(LogLevel_Debug, "Downloads Remaining: %d", m_downloading.size()); if (m_downloading.size() == 0) { Log::Write(LogLevel_Info, "ManufacturerSpecificDB Initialized"); m_initializing = false; } } std::shared_ptr ManufacturerSpecificDB::getProduct(uint16 _manufacturerId, uint16 _productType, uint16 _productId) { if (!s_bXmlLoaded) { if (!LoadProductXML()) { OZW_ERROR(OZWException::OZWEXCEPTION_CONFIG, "Cannot Load/Read ManufacturerSpecificDB! - Missing/Invalid Config File?"); } } // Try to get the real manufacturer and product names map::iterator mit = s_manufacturerMap.find(_manufacturerId); if (mit != s_manufacturerMap.end()) { // Get the product map >::iterator pit = s_productMap.find(ProductDescriptor::GetKey(_manufacturerId, _productType, _productId)); if (pit != s_productMap.end()) { return pit->second; } } return NULL; } bool ManufacturerSpecificDB::updateConfigFile(Driver *driver, Node *node) { string configPath; bool ret = false; Options::Get()->GetOptionAsString("ConfigPath", &configPath); string path = configPath + node->getConfigPath(); if (driver->startConfigDownload(node->GetManufacturerId(), node->GetProductType(), node->GetProductId(), path, node->GetNodeId())) { m_downloading.push_back(path); ret = true; } else { Log::Write(LogLevel_Warning, "Can't download Config file %s", node->getConfigPath().c_str()); Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetUserAlertNotification(Notification::Alert_ConfigFileDownloadFailed); driver->QueueNotification(notification); } checkInitialized(); return ret; } bool ManufacturerSpecificDB::updateMFSConfigFile(Driver *driver) { bool ret = false; string configPath; Options::Get()->GetOptionAsString("ConfigPath", &configPath); string path = configPath + "manufacturer_specific.xml"; if (driver->startMFSDownload(path)) { m_downloading.push_back(path); ret = true; } else { Log::Write(LogLevel_Warning, "Can't download ManufacturerSpecifix.xml Config file"); Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetUserAlertNotification(Notification::Alert_ConfigFileDownloadFailed); driver->QueueNotification(notification); } checkInitialized(); return ret; } } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/aes/0000777000175200017520000000000014032143200013112 500000000000000openzwave-1.6.1914/cpp/src/aes/aeskey.c0000644000175200017520000004020014032142455014462 00000000000000/* --------------------------------------------------------------------------- Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 */ #include "aesopt.h" #include "aestab.h" #if defined( USE_INTEL_AES_IF_PRESENT ) # include "aes_ni.h" #else /* map names here to provide the external API ('name' -> 'aes_name') */ # define aes_xi(x) aes_ ## x #endif #ifdef USE_VIA_ACE_IF_PRESENT # include "aes_via_ace.h" #endif #if defined(__cplusplus) extern "C" { #endif /* Initialise the key schedule from the user supplied key. The key length can be specified in bytes, with legal values of 16, 24 and 32, or in bits, with legal values of 128, 192 and 256. These values correspond with Nk values of 4, 6 and 8 respectively. The following macros implement a single cycle in the key schedule generation process. The number of cycles needed for each cx->n_col and nk value is: nk = 4 5 6 7 8 ------------------------------ cx->n_col = 4 10 9 8 7 7 cx->n_col = 5 14 11 10 9 9 cx->n_col = 6 19 15 12 11 11 cx->n_col = 7 21 19 16 13 14 cx->n_col = 8 29 23 19 17 14 */ #if defined( REDUCE_CODE_SIZE ) # define ls_box ls_sub uint32_t ls_sub(const uint32_t t, const uint32_t n); # define inv_mcol im_sub uint32_t im_sub(const uint32_t x); # ifdef ENC_KS_UNROLL # undef ENC_KS_UNROLL # endif # ifdef DEC_KS_UNROLL # undef DEC_KS_UNROLL # endif #endif #if (FUNCS_IN_C & ENC_KEYING_IN_C) #if defined(AES_128) || defined( AES_VAR ) #define ke4(k,i) \ { k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ k[4*(i)+5] = ss[1] ^= ss[0]; \ k[4*(i)+6] = ss[2] ^= ss[1]; \ k[4*(i)+7] = ss[3] ^= ss[2]; \ } AES_RETURN aes_xi(encrypt_key128)(const unsigned char *key, aes_encrypt_ctx cx[1]) { uint32_t ss[4]; cx->ks[0] = ss[0] = word_in(key, 0); cx->ks[1] = ss[1] = word_in(key, 1); cx->ks[2] = ss[2] = word_in(key, 2); cx->ks[3] = ss[3] = word_in(key, 3); #ifdef ENC_KS_UNROLL ke4(cx->ks, 0); ke4(cx->ks, 1); ke4(cx->ks, 2); ke4(cx->ks, 3); ke4(cx->ks, 4); ke4(cx->ks, 5); ke4(cx->ks, 6); ke4(cx->ks, 7); ke4(cx->ks, 8); #else { uint32_t i; for(i = 0; i < 9; ++i) ke4(cx->ks, i); } #endif ke4(cx->ks, 9); cx->inf.l = 0; cx->inf.b[0] = 10 * 16; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; #endif return EXIT_SUCCESS; } #endif #if defined(AES_192) || defined( AES_VAR ) #define kef6(k,i) \ { k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ k[6*(i)+ 7] = ss[1] ^= ss[0]; \ k[6*(i)+ 8] = ss[2] ^= ss[1]; \ k[6*(i)+ 9] = ss[3] ^= ss[2]; \ } #define ke6(k,i) \ { kef6(k,i); \ k[6*(i)+10] = ss[4] ^= ss[3]; \ k[6*(i)+11] = ss[5] ^= ss[4]; \ } AES_RETURN aes_xi(encrypt_key192)(const unsigned char *key, aes_encrypt_ctx cx[1]) { uint32_t ss[6]; cx->ks[0] = ss[0] = word_in(key, 0); cx->ks[1] = ss[1] = word_in(key, 1); cx->ks[2] = ss[2] = word_in(key, 2); cx->ks[3] = ss[3] = word_in(key, 3); cx->ks[4] = ss[4] = word_in(key, 4); cx->ks[5] = ss[5] = word_in(key, 5); #ifdef ENC_KS_UNROLL ke6(cx->ks, 0); ke6(cx->ks, 1); ke6(cx->ks, 2); ke6(cx->ks, 3); ke6(cx->ks, 4); ke6(cx->ks, 5); ke6(cx->ks, 6); #else { uint32_t i; for(i = 0; i < 7; ++i) ke6(cx->ks, i); } #endif kef6(cx->ks, 7); cx->inf.l = 0; cx->inf.b[0] = 12 * 16; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; #endif return EXIT_SUCCESS; } #endif #if defined(AES_256) || defined( AES_VAR ) #define kef8(k,i) \ { k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ k[8*(i)+ 9] = ss[1] ^= ss[0]; \ k[8*(i)+10] = ss[2] ^= ss[1]; \ k[8*(i)+11] = ss[3] ^= ss[2]; \ } #define ke8(k,i) \ { kef8(k,i); \ k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \ k[8*(i)+13] = ss[5] ^= ss[4]; \ k[8*(i)+14] = ss[6] ^= ss[5]; \ k[8*(i)+15] = ss[7] ^= ss[6]; \ } AES_RETURN aes_xi(encrypt_key256)(const unsigned char *key, aes_encrypt_ctx cx[1]) { uint32_t ss[8]; cx->ks[0] = ss[0] = word_in(key, 0); cx->ks[1] = ss[1] = word_in(key, 1); cx->ks[2] = ss[2] = word_in(key, 2); cx->ks[3] = ss[3] = word_in(key, 3); cx->ks[4] = ss[4] = word_in(key, 4); cx->ks[5] = ss[5] = word_in(key, 5); cx->ks[6] = ss[6] = word_in(key, 6); cx->ks[7] = ss[7] = word_in(key, 7); #ifdef ENC_KS_UNROLL ke8(cx->ks, 0); ke8(cx->ks, 1); ke8(cx->ks, 2); ke8(cx->ks, 3); ke8(cx->ks, 4); ke8(cx->ks, 5); #else { uint32_t i; for(i = 0; i < 6; ++i) ke8(cx->ks, i); } #endif kef8(cx->ks, 6); cx->inf.l = 0; cx->inf.b[0] = 14 * 16; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; #endif return EXIT_SUCCESS; } #endif #endif #if (FUNCS_IN_C & DEC_KEYING_IN_C) /* this is used to store the decryption round keys */ /* in forward or reverse order */ #ifdef AES_REV_DKS #define v(n,i) ((n) - (i) + 2 * ((i) & 3)) #else #define v(n,i) (i) #endif #if DEC_ROUND == NO_TABLES #define ff(x) (x) #else #define ff(x) inv_mcol(x) #if defined( dec_imvars ) #define d_vars dec_imvars #endif #endif #if defined(AES_128) || defined( AES_VAR ) #define k4e(k,i) \ { k[v(40,(4*(i))+4)] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ k[v(40,(4*(i))+5)] = ss[1] ^= ss[0]; \ k[v(40,(4*(i))+6)] = ss[2] ^= ss[1]; \ k[v(40,(4*(i))+7)] = ss[3] ^= ss[2]; \ } #if 1 #define kdf4(k,i) \ { ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \ ss[1] = ss[1] ^ ss[3]; \ ss[2] = ss[2] ^ ss[3]; \ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ ss[i % 4] ^= ss[4]; \ ss[4] ^= k[v(40,(4*(i)))]; k[v(40,(4*(i))+4)] = ff(ss[4]); \ ss[4] ^= k[v(40,(4*(i))+1)]; k[v(40,(4*(i))+5)] = ff(ss[4]); \ ss[4] ^= k[v(40,(4*(i))+2)]; k[v(40,(4*(i))+6)] = ff(ss[4]); \ ss[4] ^= k[v(40,(4*(i))+3)]; k[v(40,(4*(i))+7)] = ff(ss[4]); \ } #define kd4(k,i) \ { ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \ k[v(40,(4*(i))+4)] = ss[4] ^= k[v(40,(4*(i)))]; \ k[v(40,(4*(i))+5)] = ss[4] ^= k[v(40,(4*(i))+1)]; \ k[v(40,(4*(i))+6)] = ss[4] ^= k[v(40,(4*(i))+2)]; \ k[v(40,(4*(i))+7)] = ss[4] ^= k[v(40,(4*(i))+3)]; \ } #define kdl4(k,i) \ { ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \ k[v(40,(4*(i))+4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \ k[v(40,(4*(i))+5)] = ss[1] ^ ss[3]; \ k[v(40,(4*(i))+6)] = ss[0]; \ k[v(40,(4*(i))+7)] = ss[1]; \ } #else #define kdf4(k,i) \ { ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ff(ss[0]); \ ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ff(ss[1]); \ ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ff(ss[2]); \ ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ff(ss[3]); \ } #define kd4(k,i) \ { ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \ ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[v(40,(4*(i))+ 4)] = ss[4] ^= k[v(40,(4*(i)))]; \ ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[4] ^= k[v(40,(4*(i))+ 1)]; \ ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[4] ^= k[v(40,(4*(i))+ 2)]; \ ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[4] ^= k[v(40,(4*(i))+ 3)]; \ } #define kdl4(k,i) \ { ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ss[0]; \ ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[1]; \ ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[2]; \ ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[3]; \ } #endif AES_RETURN aes_xi(decrypt_key128)(const unsigned char *key, aes_decrypt_ctx cx[1]) { uint32_t ss[5]; #if defined( d_vars ) d_vars; #endif cx->ks[v(40,(0))] = ss[0] = word_in(key, 0); cx->ks[v(40,(1))] = ss[1] = word_in(key, 1); cx->ks[v(40,(2))] = ss[2] = word_in(key, 2); cx->ks[v(40,(3))] = ss[3] = word_in(key, 3); #ifdef DEC_KS_UNROLL kdf4(cx->ks, 0); kd4(cx->ks, 1); kd4(cx->ks, 2); kd4(cx->ks, 3); kd4(cx->ks, 4); kd4(cx->ks, 5); kd4(cx->ks, 6); kd4(cx->ks, 7); kd4(cx->ks, 8); kdl4(cx->ks, 9); #else { uint32_t i; for(i = 0; i < 10; ++i) k4e(cx->ks, i); #if !(DEC_ROUND == NO_TABLES) for(i = N_COLS; i < 10 * N_COLS; ++i) cx->ks[i] = inv_mcol(cx->ks[i]); #endif } #endif cx->inf.l = 0; cx->inf.b[0] = 10 * 16; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; #endif return EXIT_SUCCESS; } #endif #if defined(AES_192) || defined( AES_VAR ) #define k6ef(k,i) \ { k[v(48,(6*(i))+ 6)] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ k[v(48,(6*(i))+ 7)] = ss[1] ^= ss[0]; \ k[v(48,(6*(i))+ 8)] = ss[2] ^= ss[1]; \ k[v(48,(6*(i))+ 9)] = ss[3] ^= ss[2]; \ } #define k6e(k,i) \ { k6ef(k,i); \ k[v(48,(6*(i))+10)] = ss[4] ^= ss[3]; \ k[v(48,(6*(i))+11)] = ss[5] ^= ss[4]; \ } #define kdf6(k,i) \ { ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ff(ss[0]); \ ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ff(ss[1]); \ ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ff(ss[2]); \ ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ff(ss[3]); \ ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ff(ss[4]); \ ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ff(ss[5]); \ } #define kd6(k,i) \ { ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \ ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[v(48,(6*(i))+ 6)] = ss[6] ^= k[v(48,(6*(i)))]; \ ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[6] ^= k[v(48,(6*(i))+ 1)]; \ ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[6] ^= k[v(48,(6*(i))+ 2)]; \ ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[6] ^= k[v(48,(6*(i))+ 3)]; \ ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ss[6] ^= k[v(48,(6*(i))+ 4)]; \ ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ss[6] ^= k[v(48,(6*(i))+ 5)]; \ } #define kdl6(k,i) \ { ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ss[0]; \ ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[1]; \ ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[2]; \ ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[3]; \ } AES_RETURN aes_xi(decrypt_key192)(const unsigned char *key, aes_decrypt_ctx cx[1]) { uint32_t ss[7]; #if defined( d_vars ) d_vars; #endif cx->ks[v(48,(0))] = ss[0] = word_in(key, 0); cx->ks[v(48,(1))] = ss[1] = word_in(key, 1); cx->ks[v(48,(2))] = ss[2] = word_in(key, 2); cx->ks[v(48,(3))] = ss[3] = word_in(key, 3); #ifdef DEC_KS_UNROLL cx->ks[v(48,(4))] = ff(ss[4] = word_in(key, 4)); cx->ks[v(48,(5))] = ff(ss[5] = word_in(key, 5)); kdf6(cx->ks, 0); kd6(cx->ks, 1); kd6(cx->ks, 2); kd6(cx->ks, 3); kd6(cx->ks, 4); kd6(cx->ks, 5); kd6(cx->ks, 6); kdl6(cx->ks, 7); #else cx->ks[v(48,(4))] = ss[4] = word_in(key, 4); cx->ks[v(48,(5))] = ss[5] = word_in(key, 5); { uint32_t i; for(i = 0; i < 7; ++i) k6e(cx->ks, i); k6ef(cx->ks, 7); #if !(DEC_ROUND == NO_TABLES) for(i = N_COLS; i < 12 * N_COLS; ++i) cx->ks[i] = inv_mcol(cx->ks[i]); #endif } #endif cx->inf.l = 0; cx->inf.b[0] = 12 * 16; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; #endif return EXIT_SUCCESS; } #endif #if defined(AES_256) || defined( AES_VAR ) #define k8ef(k,i) \ { k[v(56,(8*(i))+ 8)] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ k[v(56,(8*(i))+ 9)] = ss[1] ^= ss[0]; \ k[v(56,(8*(i))+10)] = ss[2] ^= ss[1]; \ k[v(56,(8*(i))+11)] = ss[3] ^= ss[2]; \ } #define k8e(k,i) \ { k8ef(k,i); \ k[v(56,(8*(i))+12)] = ss[4] ^= ls_box(ss[3],0); \ k[v(56,(8*(i))+13)] = ss[5] ^= ss[4]; \ k[v(56,(8*(i))+14)] = ss[6] ^= ss[5]; \ k[v(56,(8*(i))+15)] = ss[7] ^= ss[6]; \ } #define kdf8(k,i) \ { ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ff(ss[0]); \ ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ff(ss[1]); \ ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ff(ss[2]); \ ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ff(ss[3]); \ ss[4] ^= ls_box(ss[3],0); k[v(56,(8*(i))+12)] = ff(ss[4]); \ ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ff(ss[5]); \ ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ff(ss[6]); \ ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ff(ss[7]); \ } #define kd8(k,i) \ { ss[8] = ls_box(ss[7],3) ^ t_use(r,c)[i]; \ ss[0] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+ 8)] = ss[8] ^= k[v(56,(8*(i)))]; \ ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[8] ^= k[v(56,(8*(i))+ 1)]; \ ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[8] ^= k[v(56,(8*(i))+ 2)]; \ ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[8] ^= k[v(56,(8*(i))+ 3)]; \ ss[8] = ls_box(ss[3],0); \ ss[4] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+12)] = ss[8] ^= k[v(56,(8*(i))+ 4)]; \ ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ss[8] ^= k[v(56,(8*(i))+ 5)]; \ ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ss[8] ^= k[v(56,(8*(i))+ 6)]; \ ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ss[8] ^= k[v(56,(8*(i))+ 7)]; \ } #define kdl8(k,i) \ { ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ss[0]; \ ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[1]; \ ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[2]; \ ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \ } AES_RETURN aes_xi(decrypt_key256)(const unsigned char *key, aes_decrypt_ctx cx[1]) { uint32_t ss[9]; #if defined( d_vars ) d_vars; #endif cx->ks[v(56,(0))] = ss[0] = word_in(key, 0); cx->ks[v(56,(1))] = ss[1] = word_in(key, 1); cx->ks[v(56,(2))] = ss[2] = word_in(key, 2); cx->ks[v(56,(3))] = ss[3] = word_in(key, 3); #ifdef DEC_KS_UNROLL cx->ks[v(56,(4))] = ff(ss[4] = word_in(key, 4)); cx->ks[v(56,(5))] = ff(ss[5] = word_in(key, 5)); cx->ks[v(56,(6))] = ff(ss[6] = word_in(key, 6)); cx->ks[v(56,(7))] = ff(ss[7] = word_in(key, 7)); kdf8(cx->ks, 0); kd8(cx->ks, 1); kd8(cx->ks, 2); kd8(cx->ks, 3); kd8(cx->ks, 4); kd8(cx->ks, 5); kdl8(cx->ks, 6); #else cx->ks[v(56,(4))] = ss[4] = word_in(key, 4); cx->ks[v(56,(5))] = ss[5] = word_in(key, 5); cx->ks[v(56,(6))] = ss[6] = word_in(key, 6); cx->ks[v(56,(7))] = ss[7] = word_in(key, 7); { uint32_t i; for(i = 0; i < 6; ++i) k8e(cx->ks, i); k8ef(cx->ks, 6); #if !(DEC_ROUND == NO_TABLES) for(i = N_COLS; i < 14 * N_COLS; ++i) cx->ks[i] = inv_mcol(cx->ks[i]); #endif } #endif cx->inf.l = 0; cx->inf.b[0] = 14 * 16; #ifdef USE_VIA_ACE_IF_PRESENT if(VIA_ACE_AVAILABLE) cx->inf.b[1] = 0xff; #endif return EXIT_SUCCESS; } #endif #endif #if defined( AES_VAR ) AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]) { switch(key_len) { case 16: case 128: return aes_encrypt_key128(key, cx); case 24: case 192: return aes_encrypt_key192(key, cx); case 32: case 256: return aes_encrypt_key256(key, cx); default: return EXIT_FAILURE; } } AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]) { switch(key_len) { case 16: case 128: return aes_decrypt_key128(key, cx); case 24: case 192: return aes_decrypt_key192(key, cx); case 32: case 256: return aes_decrypt_key256(key, cx); default: return EXIT_FAILURE; } } #endif #if defined(__cplusplus) } #endif openzwave-1.6.1914/cpp/src/aes/aes.txt0000644000175200017520000005750114032142455014362 00000000000000 An AES (Rijndael) Implementation in C/C++ (as specified in FIPS-197) ==================================================================== Changes in this Version (14/11/2013) ==================================== 1. Added the ability to use Intel's hardware support for AES on Windows using Microsoft Visual Studio. 2. Added the include 'stdint.h' and used the uint_t instead of the old uint_t (e.g. uint_32t is now uint32_t). 3. Added a missing .text directive in aes_x86_v2.asm that caused runtime errors in one build configuration. Changes in this Version (16/04/2007) ==================================== These changes remove errors in the VC++ build files and add some improvements in file naming consitency and portability. There are no changes to overcome reported bugs in the code. 1. gen_tabs() has been renamed to aes_init() to better decribe its function to those not familiar with AES internals. 2. via_ace.h has been renamed to aes_via_ace.h. 3. Minor changes have been made to aestab.h and aestab.c to enable all the code to be compiled in either C or C++. 4. The code for detecting memory alignment in aesmdoes.c has been simplified and a new routine has been added: aes_test_alignment_detection() to check that the aligment test is likely to be correct. 5. The addition of support for Structured Exception Handling (SEH) to YASM (well done Peter and Michael!) has allowed the AMD64 x64 assembler code to be changed to comply with SEH requriements. 6. Corrections to build files (for win32 debug build). Overview ======== This code implements AES for both 32 and 64 bit systems with optional assembler support for x86 and AMD64/EM64T (but optimised for AMD64). The basic AES source code files are as follows: aes.h the header file needed to use AES in C aescpp.h the header file required with to use AES in C++ aesopt.h the header file for setting options (and some common code) aestab.h the header file for the AES table declaration aescrypt.c the main C source code file for encryption and decryption aeskey.c the main C source code file for the key schedule aestab.c the main file for the AES tables brg_types.h a header defining some standard types and DLL defines brg_endian.h a header containing code to detect or define endianness aes_x86_v1.asm x86 assembler (YASM) alternative to aescrypt.c using large tables aes_x86_v2.asm x86 assembler (YASM) alternative to aescrypt.c using compressed tables aes_amd64.asm AMD64 assembler (YASM) alternative to aescrypt.c using compressed tables In addition AES modes are implemented in the files: aes_modes.c AES modes with optional support for VIA ACE detection and use aes_via_ace.h the header file for VIA ACE support and Intel hardware support for AES (AES_NI) is implemented in the files aes_ni.h defines for AES_NI implementation aes_ni.c the AES_NI implementation Other associated files for testing and support are: aesaux.h header for auxilliary routines for testsing aesaux.c auxilliary routines for testsingt aestst.h header file for setting the testing environment rdtsc.h a header file that provides access to the Time Stamp Counter aestst.c a simple test program for quick tests of the AES code aesgav.c a program to generate and verify the test vector files aesrav.c a program to verify output against the test vector files aestmr.c a program to time the code on x86 systems modetest.c a program to test the AES modes support vbxam.doc a demonstration of AES DLL use from Visual Basic in Microsoft Word vb.txt Visual Basic code from the above example (win32 only) aesxam.c an example of AES use tablegen.c a program to generate a simplified 'aestab.c' file for use with compilers that find aestab.c too complex yasm.rules the YASM build rules file for Microsoft Visual Studio 2005 via_ace.txt describes support for the VIA ACE cryptography engine aes.txt this file Building The AES Libraries -------------------------- A. Versions ----------- The code can be used to build static and dynamic libraries, each in five versions: Key scheduling code in C, encrypt/decrypt in: C C source code (win32 and x64) ASM_X86_V1C large table x86 assembler code (win32) ASM_X86_V2C compressed table x86 assembler code (win32) ASM_AMD64 compressed table x64 assembler code (x64) Key scheduling and encrypt/decrypt code in assembler: ASM_X86_V2 compressed table x86 assembler (win32) The C version can be compiled for Win32 or x64 whereas the x86 and x64 assembler versions are for Win32 and x64 respectively. If Intel's hardware support for AES (AES_NI) is available, it can be used with either the C or the ASM_AMD64 version. If ASM_AMD64 is to be used, it is important that the define USE_INTEL_AES_IF_PRESENT in asm_amd64.asm is set to the same value as it has in aesopt.h B. YASM ------- If you wish to use the x86 assembler files you will also need the YASM open source x86 assembler (r1331 or later) for Windows which can be obtained from: http://www.tortall.net/projects/yasm/ This assembler should be placed in the bin directory used by VC++, which, for Visual Stduio 2005, is typically: C:\Program Files (x86)\Microsoft Visual Studio 8\VC\bin You will also need to move the yasm.rules file from this distribution into the directory where Visual Studio 2005 expects to find it, which is typically: C:\Program Files (x86)\Microsoft Visual Studio 8\VC\VCProjectDefaults Alternatively you can configure the path for rules files within Visual Studio. C. Configuration ---------------- The following configurations are available as projects for Visual Studio but the following descriptions should allow them to be built in other x86 environments lib_generic_c Win32 and x64 headers: aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs.h (+ aes_ni.h for AES_NI) C source: aescrypt.c, aeskey.c, aestab.c, aes_modes.c (+ aes_ni.c for AES_NI) defines dll_generic_c Win32 and x64 headers: aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs.h (+ aes_ni.h for AES_NI) C source: aescrypt.c, aeskey.c, aestab.c, aes_modes.c (+ aes_ni.c for AES_NI) defines DLL_EXPORT lib_asm_x86_v1c Win32 headers: aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs.h C source: aeskey.c, aestab.c, aes_modes.c x86 assembler: aes_x86_v1.asm defines ASM_X86_V1C (set for C and assembler files) dll_asm_x86_v1c Win32 headers: aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs.h C source: aeskey.c, aestab.c, aes_modes.c x86 assembler: aes_x86_v1.asm defines DLL_EXPORT, ASM_X86_V1C (set for C and assembler files) lib_asm_x86_v2c Win32 headers: aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs.h C source: aeskey.c, aestab.c, aes_modes.c x86 assembler: aes_x86_v2.asm defines ASM_X86_V2C (set for C and assembler files) dll_asm_x86_v2c Win32 headers: aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs.h C source: aeskey.c, aestab.c, aes_modes.c x86 assembler: aes_x86_v1.asm defines DLL_EXPORT, ASM_X86_V2C (set for C and assembler files) lib_asm_x86_v2 Win32 headers: aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs.h C source: aes_modes.c x86 assembler: aes_x86_v1.asm defines ASM_X86_V2 (set for C and assembler files) dll_asm_x86_v2 Win32 headers: aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs.h C source: aes_modes.c x86 assembler: aes_x86_v1.asm defines DLL_EXPORT, ASM_AMD64_C (set for C and assembler files) lib_asm_amd64_c x64 headers: aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs.h (+ aes_ni.h for AES_NI) C source: aes_modes.c (+ aes_ni.c for AES_NI) x86 assembler: aes_amd64.asm defines ASM_X86_V2 (set for C and assembler files) dll_asm_amd64_c x64 headers: aes.h, aesopt.h, aestab.h, brg_endian.h, tdefs.h (+ aes_ni.h for AES_NI) C source: aes_modes.c (+ aes_ni.c for AES_NI) x86 assembler: aes_amd64.asm defines DLL_EXPORT, ASM_AMD64_C (set for C and assembler files) Notes: ASM_X86_V1C is defined if using the version 1 assembler code (aescrypt1.asm). The defines in the assember file must match those in aes.h and aesopt.h). Also remember to include/exclude the right assembler and C files in the build to avoid undefined or multiply defined symbols - include aes_x86_v1.asm and exclude aescrypt.c ASM_X86_V2 is defined if using the version 2 assembler code (aes_x86_v2.asm). This version provides a full, self contained assembler version and does not use any C source code files except for the mutiple block encryption modes that are provided by aes_modes.c. The define ASM_X86_V2 must be set on the YASM command line (or in aes_x86_v2.asm) to use this version and all C files except aec_modes.c and, for the DLL build, aestab.c must be excluded from the build. ASM_X86_V2C is defined when using the version 2 assembler code (aes_x86_v2.asm) with faster key scheduling provided by the in C code (the options in the assember file must match those in aes.h and aesopt.h). In this case aeskey.c and aestab.c are needed with aes_x86_v2.asm and the define ASM_X86_V2C must be set for both the C files and for aes_x86_v2.asm in the build commands(or in aesopt.h and aes_x86_v2.asm). Include aes_x86_v2.asm, aeskey.c and aestab.c, exclude aescrypt.c for this option. ASM_AMD64_C is defined when using the AMD64 assembly code because the C key scheduling is used in this case. DLL_EXPORT must be defined to generate the DLL version of the code and to run tests on it DLL_IMPORT must be defined to use the DLL version of the code in an application program Directories the paths for the various directories for test vector input and output have to be set in aestst.h VIA ACE see the via_ace.txt for this item Static The static libraries are named: Libraries aes_lib_generic_c.lib aes_lib_asm_x86_v1c.lib aes_lib_asm_x86_v2.lib aes_lib_asm_x86_v2c.lib aes_lib_asm_amd64_c.lib and placed in one of the the directories: lib\win32\release\ lib\win32\debug\ lib\x64\release\ lib\x64\debug\ in the aes root directory depending on the platform(win32 or x64) and the build (release or debug). After any of these is built it is then copied into the aes\lib directory, which is the library location that is subsequently used for testing. Hence testing is always for the last static library built. Dynamic These libraries are named: Libraries aes_lib_generic_c.dll aes_lib_asm_x86_v1c.dll aes_lib_asm_x86_v2.dll aes_lib_asm_x86_v2c.dll aes_lib_asm_amd64_c.dll and placed in one of the the directories: dll\win32\release\ dll\win32\debug\ dll\x64\release\ dll\x64\debug\ in the aes root directory depending on the platform(win32 or x64) and the build (release or debug). Each DLL library: aes_.dll has three associated files: aes_dll_.lib the library file for implicit linking aes_dll_.exp the exports file aes_dll_.pdb the symbol file After any DLL is built it and its three related files are then copied to the aes\dll directory, which is the library location used in subsequent testing. Hence testing is always for the last DLL built. D. Testing ---------- These tests require that the test vector files are placed in the 'testvals' subdirectory. If the AES Algorithm Validation Suite tests are used then the *.fax files need to be put in the 'testvals\fax' subdirectory. This is covered in more detail below. The projects test_lib and time_lib are used to test and time the last static library built. They use the files: test_lib: Win32 (x64 for the C and AMD64 versions) headers: aes.h, aescpp.h, brg_types.h, aesaux.h and aestst.h C source: aesaux.c, aesrav.c defines: time_lib: Win32 (x64 for the C and AMD64 versions) headers: aes.h, aescpp.h, brg_types.h, aesaux.h, aestst.h and rdtsc.h C source: aesaux.c, aestmr.c defines: The projects test_dll and time_dll are used to test and time the last DLL built. These use the files: test_dll: Win32 (x64 for the C and AMD64 versions) headers: aes.h, aescpp.h, brg_types.h, aesaux.h and aestst.h C source: aesaux.c, aesrav.c defines: DLL_IMPORT time_dll: Win32 (x64 for the C and AMD64 versions) headers: aes.h, aescpp.h, brg_types.h, aesaux.h aestst.h and rdtsc.h C source: aesaux.c, aestmr.c defines: DLL_IMPORT and link to the DLL using dynamic (run-time) linking. However, if the lib file associated with the DLL is linked into this project and the symbol DYNAMIC_LINK in aestst.h is left undefined, then implicit linking will be used The above tests take command line arguments that determine which test are run as follows: test_lib /t:[knec] /k:[468] test_dll /t:[knec] /k:[468] where the symbols in square brackets can be used in any combination (without the brackets) and have the following meanings: /t:[knec] selects which tests are used /k:[468] selects the key lengths used /c compares output with reference (see later) k: generate ECB Known Answer Test files n: generate ECB Known Answer Test files (new) e: generate ECB Monte Carlo Test files c: generate CBC Monte Carlo Test files and the characters giving the lengths are digits representing the key lengths in 32-bit units (4, 6, 8 for lengths of 128, 192 or 256 bits respectively). The project test_modes tests the AES modes. It uses the files: test_modes: Win32 or x64 headers: aes.h, aescpp.h, brg_types.h, aesaux,h and aestst.h C source: aesaux.c, modetest.c defines: none for static library test, DLL_IMPORT for DLL test which again links to the last library built. E. Other Applications --------------------- These are: gen_tests builds the test_vector files. The commad line is gen_tests /t:knec /k:468 /c as described earlier test_aes_avs run the AES Algorithm Validation Suite tests for ECB, CBC, CFB and OFB modes gen_tables builds a simple version of aes_tab.c (in aestab2.c) for compilers that cannot handle the normal version aes_example provides an example of AES use These applications are linked to the last static library built or, if DLL_IMPORT is defined during compilation, to the last DLL built. F. Use of the VIA ACE Cryptography Engine (x86 only) ---------------------------------------------------- The use of the code with the VIA ACE cryptography engine in described in the file via_ace.txt. In outline aes_modes.c is used and USE_VIA_ACE_IF_PRESENT is defined either in section 2 of aesopt.h or as a compilation option in Visual Studio. If in addition ASSUME_VIA_ACE_PRESENT is also defined then all normal AES code will be removed if not needed to support VIA ACE use. If VIA ACE support is needed and AES assembler is being used only the ASM_X86_V1C and ASM_X86_V2C versions should be used since ASM_X86_V2 and ASM_AMD64 do not support the VIA ACE engine. G. The AES Test Vector Files ---------------------------- These files fall in the following groups (where is a two digit number): 1. ecbvk.txt ECB vectors with variable key 2. ecbvt.txt ECB vectors with variable text 3. ecbnk.txt new ECB vectors with variable key 4. ecbnt.txt new ECB vectors with variable text 5. ecbme.txt ECB monte carlo encryption test vectors 6. ecbmd.txt ECB monte carlo decryption test vectors 7. cbcme.txt CBC monte carlo encryption test vectors 8. cbcmd.txt CBC monte carlo decryption test vectors The first digit of the numeric suffix on the filename gives the block size in 32 bit units and the second numeric digit gives the key size. For example, the file ecbvk44.txt provides the test vectors for ECB encryption with a 128 bit block size and a 128 bit key size. The test routines expect to find these files in the 'testvals' subdirectory within the aes root directory. The 'outvals' subdirectory is used for outputs that are compared with the files in 'testvals'. Note that the monte carlo test vectors are the result of applying AES iteratively 10000 times, not just once. The AES Algorithm Validation Suite tests can be run for ECB, CBC, CFB and OFB modes (CFB1 and CFB8 are not implemented). The test routine uses the *.fax test files, which should be placed in the 'testvals\fax' subdirectory. H. The Basic AES Calling Interface ---------------------------------- The basic AES code keeps its state in a context, there being different contexts for encryption and decryption: aes_encrypt_ctx aes_decrypt_ctx The AES code is initialised with the call aes_init(void) although this is only essential if the option to generate the AES tables at run-time has been set in the options (i.e.fixed tables are not being used). The AES encryption key is set by one of the calls: aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]) aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]) aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]) or by: aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]) where the key length is set by 'key_len', which can be the length in bits or bytes. Similarly, the AES decryption key is set by one of: aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]) aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]) aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]) or by: aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]) Encryption and decryption for a single 16 byte block is then achieved using: aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]) aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]) The above subroutines return a value of EXIT_SUCCESS or EXIT_FAILURE depending on whether the operation succeeded or failed. I. The Calling Interface for the AES Modes ------------------------------------------ The subroutines for the AES modes, ECB, CBC, CFB, OFB and CTR, each process blocks of variable length and can also be called several times to complete single mode operations incrementally on long messages (or those messages, not all of which are available at the same time). The calls: aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, const aes_encrypt_ctx cx[1]) aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, const aes_decrypt_ctx cx[1]) for ECB operations and those for CBC: aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, const aes_encrypt_ctx cx[1]) aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, const aes_decrypt_ctx cx[1]) can only process blocks whose lengths are multiples of 16 bytes but the calls for CFB, OFB and CTR mode operations: aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, aes_encrypt_ctx cx[1]) aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, aes_encrypt_ctx cx[1]) aes_ofb_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, aes_encrypt_ctx cx[1]) aes_ofb_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, aes_encrypt_ctx cx[1]) aes_ctr_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]) aes_ctr_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]) can process blocks of any length. Note also that CFB, OFB and CTR mode calls only use AES encryption contexts even during decryption operations. The calls CTR mode operations use a buffer (cbuf) which holds the counter value together with a function parameter: void cbuf_inc(unsigned char *cbuf); that is ued to update the counter value after each 16 byte AES operation. The counter buffer is updated appropriately to allow for incremental operations. Please note the following IMPORTANT points about the AES mode subroutines: 1. All modes are reset when a new AES key is set. 2. Incremental calls to the different modes cannot be mixed. If a change of mode is needed a new key must be set or a reset must be issued (see below). 3. For modes with IVs, the IV value is an input AND an ouTput since it is updated after each call to the value needed for any subsequent incremental call(s). If the mode is reset, the IV hence has to be set (or reset) as well. 4. ECB operations must be multiples of 16 bytes but do not need to be reset for new operations. 5. CBC operations must also be multiples of 16 bytes and are reset for a new operation by setting the IV. 6. CFB, OFB and CTR mode must be reset by setting a new IV value AND by calling: aes_mode_reset(aes_encrypt_ctx cx[1]) For CTR mode the cbuf value also has to be reset. 7. CFB, OFB and CTR modes only use AES encryption operations and contexts and do not need AES decrytpion operations. 8. AES keys remain valid across resets and changes of mode (but encryption and decryption keys must both be set if they are needed). Brian Gladman 14/11/2013 openzwave-1.6.1914/cpp/src/aes/aestab.c0000644000175200017520000003642114032142455014452 00000000000000/* --------------------------------------------------------------------------- Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 */ #define DO_TABLES #include "aes.h" #include "aesopt.h" #if defined(FIXED_TABLES) #define sb_data(w) {\ w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) } #define isb_data(w) {\ w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) } #define mm_data(w) {\ w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) } #define rc_data(w) {\ w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\ w(0x1b), w(0x36) } #define h0(x) (x) #define w0(p) bytes2word(p, 0, 0, 0) #define w1(p) bytes2word(0, p, 0, 0) #define w2(p) bytes2word(0, 0, p, 0) #define w3(p) bytes2word(0, 0, 0, p) #define u0(p) bytes2word(f2(p), p, p, f3(p)) #define u1(p) bytes2word(f3(p), f2(p), p, p) #define u2(p) bytes2word(p, f3(p), f2(p), p) #define u3(p) bytes2word(p, p, f3(p), f2(p)) #define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p)) #define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p)) #define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p)) #define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p)) #endif #if defined(FIXED_TABLES) || !defined(FF_TABLES) #define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY)) #define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY)) #define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \ ^ (((x>>5) & 4) * WPOLY)) #define f3(x) (f2(x) ^ x) #define f9(x) (f8(x) ^ x) #define fb(x) (f8(x) ^ f2(x) ^ x) #define fd(x) (f8(x) ^ f4(x) ^ x) #define fe(x) (f8(x) ^ f4(x) ^ f2(x)) #else #define f2(x) ((x) ? pow[log[x] + 0x19] : 0) #define f3(x) ((x) ? pow[log[x] + 0x01] : 0) #define f9(x) ((x) ? pow[log[x] + 0xc7] : 0) #define fb(x) ((x) ? pow[log[x] + 0x68] : 0) #define fd(x) ((x) ? pow[log[x] + 0xee] : 0) #define fe(x) ((x) ? pow[log[x] + 0xdf] : 0) #endif #include "aestab.h" #if defined(__cplusplus) extern "C" { #endif #if defined(FIXED_TABLES) /* implemented in case of wrong call for fixed tables */ AES_RETURN aes_init(void) { return EXIT_SUCCESS; } #else /* Generate the tables for the dynamic table option */ #if defined(FF_TABLES) #define gf_inv(x) ((x) ? pow[ 255 - log[x]] : 0) #else /* It will generally be sensible to use tables to compute finite field multiplies and inverses but where memory is scarse this code might sometimes be better. But it only has effect during initialisation so its pretty unimportant in overall terms. */ /* return 2 ^ (n - 1) where n is the bit number of the highest bit set in x with x in the range 1 < x < 0x00000200. This form is used so that locals within fi can be bytes rather than words */ static uint8_t hibit(const uint32_t x) { uint8_t r = (uint8_t)((x >> 1) | (x >> 2)); r |= (r >> 2); r |= (r >> 4); return (r + 1) >> 1; } /* return the inverse of the finite field element x */ static uint8_t gf_inv(const uint8_t x) { uint8_t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; if(x < 2) return x; for( ; ; ) { if(n1) while(n2 >= n1) /* divide polynomial p2 by p1 */ { n2 /= n1; /* shift smaller polynomial left */ p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ v2 ^= v1 * n2; /* shift accumulated value and */ n2 = hibit(p2); /* add into result */ } else return v1; if(n2) /* repeat with values swapped */ while(n1 >= n2) { n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1); } else return v2; } } #endif /* The forward and inverse affine transformations used in the S-box */ uint8_t fwd_affine(const uint8_t x) { uint32_t w = x; w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); return 0x63 ^ ((w ^ (w >> 8)) & 0xff); } uint8_t inv_affine(const uint8_t x) { uint32_t w = x; w = (w << 1) ^ (w << 3) ^ (w << 6); return 0x05 ^ ((w ^ (w >> 8)) & 0xff); } static int init = 0; AES_RETURN aes_init(void) { uint32_t i, w; #if defined(FF_TABLES) uint8_t pow[512], log[256]; if(init) return EXIT_SUCCESS; /* log and power tables for GF(2^8) finite field with WPOLY as modular polynomial - the simplest primitive root is 0x03, used here to generate the tables */ i = 0; w = 1; do { pow[i] = (uint8_t)w; pow[i + 255] = (uint8_t)w; log[w] = (uint8_t)i++; w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0); } while (w != 1); #else if(init) return EXIT_SUCCESS; #endif for(i = 0, w = 1; i < RC_LENGTH; ++i) { t_set(r,c)[i] = bytes2word(w, 0, 0, 0); w = f2(w); } for(i = 0; i < 256; ++i) { uint8_t b; b = fwd_affine(gf_inv((uint8_t)i)); w = bytes2word(f2(b), b, b, f3(b)); #if defined( SBX_SET ) t_set(s,box)[i] = b; #endif #if defined( FT1_SET ) /* tables for a normal encryption round */ t_set(f,n)[i] = w; #endif #if defined( FT4_SET ) t_set(f,n)[0][i] = w; t_set(f,n)[1][i] = upr(w,1); t_set(f,n)[2][i] = upr(w,2); t_set(f,n)[3][i] = upr(w,3); #endif w = bytes2word(b, 0, 0, 0); #if defined( FL1_SET ) /* tables for last encryption round (may also */ t_set(f,l)[i] = w; /* be used in the key schedule) */ #endif #if defined( FL4_SET ) t_set(f,l)[0][i] = w; t_set(f,l)[1][i] = upr(w,1); t_set(f,l)[2][i] = upr(w,2); t_set(f,l)[3][i] = upr(w,3); #endif #if defined( LS1_SET ) /* table for key schedule if t_set(f,l) above is*/ t_set(l,s)[i] = w; /* not of the required form */ #endif #if defined( LS4_SET ) t_set(l,s)[0][i] = w; t_set(l,s)[1][i] = upr(w,1); t_set(l,s)[2][i] = upr(w,2); t_set(l,s)[3][i] = upr(w,3); #endif b = gf_inv(inv_affine((uint8_t)i)); w = bytes2word(fe(b), f9(b), fd(b), fb(b)); #if defined( IM1_SET ) /* tables for the inverse mix column operation */ t_set(i,m)[b] = w; #endif #if defined( IM4_SET ) t_set(i,m)[0][b] = w; t_set(i,m)[1][b] = upr(w,1); t_set(i,m)[2][b] = upr(w,2); t_set(i,m)[3][b] = upr(w,3); #endif #if defined( ISB_SET ) t_set(i,box)[i] = b; #endif #if defined( IT1_SET ) /* tables for a normal decryption round */ t_set(i,n)[i] = w; #endif #if defined( IT4_SET ) t_set(i,n)[0][i] = w; t_set(i,n)[1][i] = upr(w,1); t_set(i,n)[2][i] = upr(w,2); t_set(i,n)[3][i] = upr(w,3); #endif w = bytes2word(b, 0, 0, 0); #if defined( IL1_SET ) /* tables for last decryption round */ t_set(i,l)[i] = w; #endif #if defined( IL4_SET ) t_set(i,l)[0][i] = w; t_set(i,l)[1][i] = upr(w,1); t_set(i,l)[2][i] = upr(w,2); t_set(i,l)[3][i] = upr(w,3); #endif } init = 1; return EXIT_SUCCESS; } #endif #if defined(__cplusplus) } #endif openzwave-1.6.1914/cpp/src/aes/brg_endian.h0000644000175200017520000001225214032142455015304 00000000000000/* --------------------------------------------------------------------------- Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 */ #ifndef _BRG_ENDIAN_H #define _BRG_ENDIAN_H #define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ #define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ /* Include files where endian defines and byteswap functions may reside */ #if defined( __sun ) # include #elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) # include #elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) # include #elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) # if !defined( __MINGW32__ ) && !defined( _AIX ) # include # if !defined( __BEOS__ ) # include # endif # endif #endif /* Now attempt to set the define for platform byte order using any */ /* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ /* seem to encompass most endian symbol definitions */ #if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) # if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN # elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN # endif #elif defined( BIG_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #elif defined( LITTLE_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #endif #if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) # if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN # elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN # endif #elif defined( _BIG_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #elif defined( _LITTLE_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #endif #if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) # if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN # elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN # endif #elif defined( __BIG_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #elif defined( __LITTLE_ENDIAN ) # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #endif #if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) # if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN # elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN # endif #elif defined( __BIG_ENDIAN__ ) # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #elif defined( __LITTLE_ENDIAN__ ) # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #endif /* if the platform byte order could not be determined, then try to */ /* set this define using common machine defines */ #if !defined(PLATFORM_BYTE_ORDER) #if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ defined( vax ) || defined( vms ) || defined( VMS ) || \ defined( __VMS ) || defined( _M_X64 ) # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX ) # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #elif 0 /* **** EDIT HERE IF NECESSARY **** */ # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN #elif 0 /* **** EDIT HERE IF NECESSARY **** */ # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN #else # error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order #endif #endif #endif openzwave-1.6.1914/cpp/src/aes/brg_types.h0000644000175200017520000001626714032142455015224 00000000000000/* --------------------------------------------------------------------------- Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 The unsigned integer types defined here are of the form uint_t where is the length of the type; for example, the unsigned 32-bit type is 'uint32_t'. These are NOT the same as the 'C99 integer types' that are defined in the inttypes.h and stdint.h headers since attempts to use these types have shown that support for them is still highly variable. However, since the latter are of the form uint_t, a regular expression search and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t') can be used to convert the types used here to the C99 standard types. */ #ifndef _BRG_TYPES_H #define _BRG_TYPES_H #if defined(__cplusplus) extern "C" { #endif #include #include #if defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) # include # define ptrint_t intptr_t #elif defined( __ECOS__ ) # define intptr_t unsigned int # define ptrint_t intptr_t #elif defined( __GNUC__ ) && ( __GNUC__ >= 3 ) # define ptrint_t intptr_t #else # define ptrint_t int #endif #ifndef BRG_UI32 # define BRG_UI32 # if UINT_MAX == 4294967295u # define li_32(h) 0x##h##u # elif ULONG_MAX == 4294967295u # define li_32(h) 0x##h##ul # elif defined( _CRAY ) # error This code needs 32-bit data types, which Cray machines do not provide # else # error Please define uint32_t as a 32-bit unsigned integer type in brg_types.h # endif #endif #ifndef BRG_UI64 # if defined( __BORLANDC__ ) && !defined( __MSDOS__ ) # define BRG_UI64 # define li_64(h) 0x##h##ui64 # elif defined( _MSC_VER ) && ( _MSC_VER < 1300 ) /* 1300 == VC++ 7.0 */ # define BRG_UI64 # define li_64(h) 0x##h##ui64 # elif defined( __sun ) && defined( ULONG_MAX ) && ULONG_MAX == 0xfffffffful # define BRG_UI64 # define li_64(h) 0x##h##ull # elif defined( __MVS__ ) # define BRG_UI64 # define li_64(h) 0x##h##ull # elif defined( UINT_MAX ) && UINT_MAX > 4294967295u # if UINT_MAX == 18446744073709551615u # define BRG_UI64 # define li_64(h) 0x##h##u # endif # elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u # if ULONG_MAX == 18446744073709551615ul # define BRG_UI64 # define li_64(h) 0x##h##ul # endif # elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u # if ULLONG_MAX == 18446744073709551615ull # define BRG_UI64 # define li_64(h) 0x##h##ull # endif # elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u # if ULONG_LONG_MAX == 18446744073709551615ull # define BRG_UI64 # define li_64(h) 0x##h##ull # endif # endif #endif #if !defined( BRG_UI64 ) # if defined( NEED_UINT_64T ) # error Please define uint64_t as an unsigned 64 bit type in brg_types.h # endif #endif #ifndef RETURN_VALUES # define RETURN_VALUES # if defined( DLL_EXPORT ) # if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) # define VOID_RETURN __declspec( dllexport ) void __stdcall # define INT_RETURN __declspec( dllexport ) int __stdcall # elif defined( __GNUC__ ) # define VOID_RETURN __declspec( __dllexport__ ) void # define INT_RETURN __declspec( __dllexport__ ) int # else # error Use of the DLL is only available on the Microsoft, Intel and GCC compilers # endif # elif defined( DLL_IMPORT ) # if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) # define VOID_RETURN __declspec( dllimport ) void __stdcall # define INT_RETURN __declspec( dllimport ) int __stdcall # elif defined( __GNUC__ ) # define VOID_RETURN __declspec( __dllimport__ ) void # define INT_RETURN __declspec( __dllimport__ ) int # else # error Use of the DLL is only available on the Microsoft, Intel and GCC compilers # endif # elif defined( __WATCOMC__ ) # define VOID_RETURN void __cdecl # define INT_RETURN int __cdecl # else # define VOID_RETURN void # define INT_RETURN int # endif #endif /* These defines are used to detect and set the memory alignment of pointers. Note that offsets are in bytes. ALIGN_OFFSET(x,n) return the positive or zero offset of the memory addressed by the pointer 'x' from an address that is aligned on an 'n' byte boundary ('n' is a power of 2) ALIGN_FLOOR(x,n) return a pointer that points to memory that is aligned on an 'n' byte boundary and is not higher than the memory address pointed to by 'x' ('n' is a power of 2) ALIGN_CEIL(x,n) return a pointer that points to memory that is aligned on an 'n' byte boundary and is not lower than the memory address pointed to by 'x' ('n' is a power of 2) */ #define ALIGN_OFFSET(x,n) (((ptrint_t)(x)) & ((n) - 1)) #define ALIGN_FLOOR(x,n) ((uint8_t*)(x) - ( ((ptrint_t)(x)) & ((n) - 1))) #define ALIGN_CEIL(x,n) ((uint8_t*)(x) + (-((ptrint_t)(x)) & ((n) - 1))) /* These defines are used to declare buffers in a way that allows faster operations on longer variables to be used. In all these defines 'size' must be a power of 2 and >= 8. NOTE that the buffer size is in bytes but the type length is in bits UNIT_TYPEDEF(x,size) declares a variable 'x' of length 'size' bits BUFR_TYPEDEF(x,size,bsize) declares a buffer 'x' of length 'bsize' bytes defined as an array of variables each of 'size' bits (bsize must be a multiple of size / 8) UNIT_CAST(x,size) casts a variable to a type of length 'size' bits UPTR_CAST(x,size) casts a pointer to a pointer to a varaiable of length 'size' bits */ #define UI_TYPE(size) uint##size##_t #define UNIT_TYPEDEF(x,size) typedef UI_TYPE(size) x #define BUFR_TYPEDEF(x,size,bsize) typedef UI_TYPE(size) x[bsize / (size >> 3)] #define UNIT_CAST(x,size) ((UI_TYPE(size) )(x)) #define UPTR_CAST(x,size) ((UI_TYPE(size)*)(x)) #if defined(__cplusplus) } #endif #endif openzwave-1.6.1914/cpp/src/aes/aes_modes.c0000644000175200017520000007530014032142455015151 00000000000000/* --------------------------------------------------------------------------- Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 These subroutines implement multiple block AES modes for ECB, CBC, CFB, OFB and CTR encryption, The code provides support for the VIA Advanced Cryptography Engine (ACE). NOTE: In the following subroutines, the AES contexts (ctx) must be 16 byte aligned if VIA ACE is being used */ #include #include #include #include "aesopt.h" #if defined( AES_MODES ) #if defined(__cplusplus) extern "C" { #endif #if defined( _MSC_VER ) && ( _MSC_VER > 800 ) #pragma intrinsic(memcpy) #endif #define BFR_BLOCKS 8 /* These values are used to detect long word alignment in order to */ /* speed up some buffer operations. This facility may not work on */ /* some machines so this define can be commented out if necessary */ #define FAST_BUFFER_OPERATIONS #define lp32(x) ((uint32_t*)(x)) #if defined( USE_VIA_ACE_IF_PRESENT ) #include "aes_via_ace.h" #pragma pack(16) aligned_array(unsigned long, enc_gen_table, 12, 16) = NEH_ENC_GEN_DATA; aligned_array(unsigned long, enc_load_table, 12, 16) = NEH_ENC_LOAD_DATA; aligned_array(unsigned long, enc_hybrid_table, 12, 16) = NEH_ENC_HYBRID_DATA; aligned_array(unsigned long, dec_gen_table, 12, 16) = NEH_DEC_GEN_DATA; aligned_array(unsigned long, dec_load_table, 12, 16) = NEH_DEC_LOAD_DATA; aligned_array(unsigned long, dec_hybrid_table, 12, 16) = NEH_DEC_HYBRID_DATA; /* NOTE: These control word macros must only be used after */ /* a key has been set up because they depend on key size */ /* See the VIA ACE documentation for key type information */ /* and aes_via_ace.h for non-default NEH_KEY_TYPE values */ #ifndef NEH_KEY_TYPE # define NEH_KEY_TYPE NEH_HYBRID #endif #if NEH_KEY_TYPE == NEH_LOAD #define kd_adr(c) ((uint8_t*)(c)->ks) #elif NEH_KEY_TYPE == NEH_GENERATE #define kd_adr(c) ((uint8_t*)(c)->ks + (c)->inf.b[0]) #elif NEH_KEY_TYPE == NEH_HYBRID #define kd_adr(c) ((uint8_t*)(c)->ks + ((c)->inf.b[0] == 160 ? 160 : 0)) #else #error no key type defined for VIA ACE #endif #else #define aligned_array(type, name, no, stride) type name[no] #define aligned_auto(type, name, no, stride) type name[no] #endif #if defined( _MSC_VER ) && _MSC_VER > 1200 #define via_cwd(cwd, ty, dir, len) \ unsigned long* cwd = (dir##_##ty##_table + ((len - 128) >> 4)) #else #define via_cwd(cwd, ty, dir, len) \ aligned_auto(unsigned long, cwd, 4, 16); \ cwd[1] = cwd[2] = cwd[3] = 0; \ cwd[0] = neh_##dir##_##ty##_key(len) #endif /* test the code for detecting and setting pointer alignment */ AES_RETURN aes_test_alignment_detection(unsigned int n) /* 4 <= n <= 16 */ { uint8_t p[16]; uint32_t i, count_eq = 0, count_neq = 0; if(n < 4 || n > 16) return EXIT_FAILURE; for(i = 0; i < n; ++i) { uint8_t *qf = ALIGN_FLOOR(p + i, n), *qh = ALIGN_CEIL(p + i, n); if(qh == qf) ++count_eq; else if(qh == qf + n) ++count_neq; else return EXIT_FAILURE; } return (count_eq != 1 || count_neq != n - 1 ? EXIT_FAILURE : EXIT_SUCCESS); } AES_RETURN aes_mode_reset(aes_encrypt_ctx ctx[1]) { ctx->inf.b[2] = 0; return EXIT_SUCCESS; } AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, const aes_encrypt_ctx ctx[1]) { int nb = len >> 4; if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE; #if defined( USE_VIA_ACE_IF_PRESENT ) if(ctx->inf.b[1] == 0xff) { uint8_t *ksp = (uint8_t*)(ctx->ks); via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); if(ALIGN_OFFSET( ctx, 16 )) return EXIT_FAILURE; if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) { via_ecb_op5(ksp, cwd, ibuf, obuf, nb); } else { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); uint8_t *ip, *op; while(nb) { int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE); via_ecb_op5(ksp, cwd, ip, op, m); if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE); ibuf += m * AES_BLOCK_SIZE; obuf += m * AES_BLOCK_SIZE; nb -= m; } } return EXIT_SUCCESS; } #endif #if !defined( ASSUME_VIA_ACE_PRESENT ) while(nb--) { if(aes_encrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; ibuf += AES_BLOCK_SIZE; obuf += AES_BLOCK_SIZE; } #endif return EXIT_SUCCESS; } AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, const aes_decrypt_ctx ctx[1]) { int nb = len >> 4; if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE; #if defined( USE_VIA_ACE_IF_PRESENT ) if(ctx->inf.b[1] == 0xff) { uint8_t *ksp = kd_adr(ctx); via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); if(ALIGN_OFFSET( ctx, 16 )) return EXIT_FAILURE; if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) { via_ecb_op5(ksp, cwd, ibuf, obuf, nb); } else { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); uint8_t *ip, *op; while(nb) { int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE); via_ecb_op5(ksp, cwd, ip, op, m); if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE); ibuf += m * AES_BLOCK_SIZE; obuf += m * AES_BLOCK_SIZE; nb -= m; } } return EXIT_SUCCESS; } #endif #if !defined( ASSUME_VIA_ACE_PRESENT ) while(nb--) { if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; ibuf += AES_BLOCK_SIZE; obuf += AES_BLOCK_SIZE; } #endif return EXIT_SUCCESS; } AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, const aes_encrypt_ctx ctx[1]) { int nb = len >> 4; if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE; #if defined( USE_VIA_ACE_IF_PRESENT ) if(ctx->inf.b[1] == 0xff) { uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); if(ALIGN_OFFSET( ctx, 16 )) return EXIT_FAILURE; if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ { ivp = liv; memcpy(liv, iv, AES_BLOCK_SIZE); } if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 )) { via_cbc_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp); } else { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); uint8_t *ip, *op; while(nb) { int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE); via_cbc_op7(ksp, cwd, ip, op, m, ivp, ivp); if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE); ibuf += m * AES_BLOCK_SIZE; obuf += m * AES_BLOCK_SIZE; nb -= m; } } if(iv != ivp) memcpy(iv, ivp, AES_BLOCK_SIZE); return EXIT_SUCCESS; } #endif #if !defined( ASSUME_VIA_ACE_PRESENT ) # ifdef FAST_BUFFER_OPERATIONS if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) while(nb--) { lp32(iv)[0] ^= lp32(ibuf)[0]; lp32(iv)[1] ^= lp32(ibuf)[1]; lp32(iv)[2] ^= lp32(ibuf)[2]; lp32(iv)[3] ^= lp32(ibuf)[3]; if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; memcpy(obuf, iv, AES_BLOCK_SIZE); ibuf += AES_BLOCK_SIZE; obuf += AES_BLOCK_SIZE; } else # endif while(nb--) { iv[ 0] ^= ibuf[ 0]; iv[ 1] ^= ibuf[ 1]; iv[ 2] ^= ibuf[ 2]; iv[ 3] ^= ibuf[ 3]; iv[ 4] ^= ibuf[ 4]; iv[ 5] ^= ibuf[ 5]; iv[ 6] ^= ibuf[ 6]; iv[ 7] ^= ibuf[ 7]; iv[ 8] ^= ibuf[ 8]; iv[ 9] ^= ibuf[ 9]; iv[10] ^= ibuf[10]; iv[11] ^= ibuf[11]; iv[12] ^= ibuf[12]; iv[13] ^= ibuf[13]; iv[14] ^= ibuf[14]; iv[15] ^= ibuf[15]; if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; memcpy(obuf, iv, AES_BLOCK_SIZE); ibuf += AES_BLOCK_SIZE; obuf += AES_BLOCK_SIZE; } #endif return EXIT_SUCCESS; } AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, const aes_decrypt_ctx ctx[1]) { unsigned char tmp[AES_BLOCK_SIZE]; int nb = len >> 4; if(len & (AES_BLOCK_SIZE - 1)) return EXIT_FAILURE; #if defined( USE_VIA_ACE_IF_PRESENT ) if(ctx->inf.b[1] == 0xff) { uint8_t *ksp = kd_adr(ctx), *ivp = iv; aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); if(ALIGN_OFFSET( ctx, 16 )) return EXIT_FAILURE; if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ { ivp = liv; memcpy(liv, iv, AES_BLOCK_SIZE); } if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 )) { via_cbc_op6(ksp, cwd, ibuf, obuf, nb, ivp); } else { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); uint8_t *ip, *op; while(nb) { int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE); via_cbc_op6(ksp, cwd, ip, op, m, ivp); if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE); ibuf += m * AES_BLOCK_SIZE; obuf += m * AES_BLOCK_SIZE; nb -= m; } } if(iv != ivp) memcpy(iv, ivp, AES_BLOCK_SIZE); return EXIT_SUCCESS; } #endif #if !defined( ASSUME_VIA_ACE_PRESENT ) # ifdef FAST_BUFFER_OPERATIONS if(!ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) while(nb--) { memcpy(tmp, ibuf, AES_BLOCK_SIZE); if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; lp32(obuf)[0] ^= lp32(iv)[0]; lp32(obuf)[1] ^= lp32(iv)[1]; lp32(obuf)[2] ^= lp32(iv)[2]; lp32(obuf)[3] ^= lp32(iv)[3]; memcpy(iv, tmp, AES_BLOCK_SIZE); ibuf += AES_BLOCK_SIZE; obuf += AES_BLOCK_SIZE; } else # endif while(nb--) { memcpy(tmp, ibuf, AES_BLOCK_SIZE); if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; obuf[ 0] ^= iv[ 0]; obuf[ 1] ^= iv[ 1]; obuf[ 2] ^= iv[ 2]; obuf[ 3] ^= iv[ 3]; obuf[ 4] ^= iv[ 4]; obuf[ 5] ^= iv[ 5]; obuf[ 6] ^= iv[ 6]; obuf[ 7] ^= iv[ 7]; obuf[ 8] ^= iv[ 8]; obuf[ 9] ^= iv[ 9]; obuf[10] ^= iv[10]; obuf[11] ^= iv[11]; obuf[12] ^= iv[12]; obuf[13] ^= iv[13]; obuf[14] ^= iv[14]; obuf[15] ^= iv[15]; memcpy(iv, tmp, AES_BLOCK_SIZE); ibuf += AES_BLOCK_SIZE; obuf += AES_BLOCK_SIZE; } #endif return EXIT_SUCCESS; } AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) { int cnt = 0, b_pos = (int)ctx->inf.b[2], nb; if(b_pos) /* complete any partial block */ { while(b_pos < AES_BLOCK_SIZE && cnt < len) { *obuf++ = (iv[b_pos++] ^= *ibuf++); cnt++; } b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); } if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */ { #if defined( USE_VIA_ACE_IF_PRESENT ) if(ctx->inf.b[1] == 0xff) { int m; uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); if(ALIGN_OFFSET( ctx, 16 )) return EXIT_FAILURE; if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ { ivp = liv; memcpy(liv, iv, AES_BLOCK_SIZE); } if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) { via_cfb_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp); ibuf += nb * AES_BLOCK_SIZE; obuf += nb * AES_BLOCK_SIZE; cnt += nb * AES_BLOCK_SIZE; } else /* input, output or both are unaligned */ { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); uint8_t *ip, *op; while(nb) { m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE); via_cfb_op7(ksp, cwd, ip, op, m, ivp, ivp); if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE); ibuf += m * AES_BLOCK_SIZE; obuf += m * AES_BLOCK_SIZE; cnt += m * AES_BLOCK_SIZE; } } if(ivp != iv) memcpy(iv, ivp, AES_BLOCK_SIZE); } #else # ifdef FAST_BUFFER_OPERATIONS if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) while(cnt + AES_BLOCK_SIZE <= len) { assert(b_pos == 0); if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; lp32(obuf)[0] = lp32(iv)[0] ^= lp32(ibuf)[0]; lp32(obuf)[1] = lp32(iv)[1] ^= lp32(ibuf)[1]; lp32(obuf)[2] = lp32(iv)[2] ^= lp32(ibuf)[2]; lp32(obuf)[3] = lp32(iv)[3] ^= lp32(ibuf)[3]; ibuf += AES_BLOCK_SIZE; obuf += AES_BLOCK_SIZE; cnt += AES_BLOCK_SIZE; } else # endif while(cnt + AES_BLOCK_SIZE <= len) { assert(b_pos == 0); if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; obuf[ 0] = iv[ 0] ^= ibuf[ 0]; obuf[ 1] = iv[ 1] ^= ibuf[ 1]; obuf[ 2] = iv[ 2] ^= ibuf[ 2]; obuf[ 3] = iv[ 3] ^= ibuf[ 3]; obuf[ 4] = iv[ 4] ^= ibuf[ 4]; obuf[ 5] = iv[ 5] ^= ibuf[ 5]; obuf[ 6] = iv[ 6] ^= ibuf[ 6]; obuf[ 7] = iv[ 7] ^= ibuf[ 7]; obuf[ 8] = iv[ 8] ^= ibuf[ 8]; obuf[ 9] = iv[ 9] ^= ibuf[ 9]; obuf[10] = iv[10] ^= ibuf[10]; obuf[11] = iv[11] ^= ibuf[11]; obuf[12] = iv[12] ^= ibuf[12]; obuf[13] = iv[13] ^= ibuf[13]; obuf[14] = iv[14] ^= ibuf[14]; obuf[15] = iv[15] ^= ibuf[15]; ibuf += AES_BLOCK_SIZE; obuf += AES_BLOCK_SIZE; cnt += AES_BLOCK_SIZE; } #endif } while(cnt < len) { if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; while(cnt < len && b_pos < AES_BLOCK_SIZE) { *obuf++ = (iv[b_pos++] ^= *ibuf++); cnt++; } b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); } ctx->inf.b[2] = (uint8_t)b_pos; return EXIT_SUCCESS; } AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) { int cnt = 0, b_pos = (int)ctx->inf.b[2], nb; if(b_pos) /* complete any partial block */ { uint8_t t; while(b_pos < AES_BLOCK_SIZE && cnt < len) { t = *ibuf++; *obuf++ = t ^ iv[b_pos]; iv[b_pos++] = t; cnt++; } b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); } if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */ { #if defined( USE_VIA_ACE_IF_PRESENT ) if(ctx->inf.b[1] == 0xff) { int m; uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); if(ALIGN_OFFSET( ctx, 16 )) return EXIT_FAILURE; if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ { ivp = liv; memcpy(liv, iv, AES_BLOCK_SIZE); } if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) { via_cfb_op6(ksp, cwd, ibuf, obuf, nb, ivp); ibuf += nb * AES_BLOCK_SIZE; obuf += nb * AES_BLOCK_SIZE; cnt += nb * AES_BLOCK_SIZE; } else /* input, output or both are unaligned */ { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); uint8_t *ip, *op; while(nb) { m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); if(ip != ibuf) /* input buffer is not aligned */ memcpy(buf, ibuf, m * AES_BLOCK_SIZE); via_cfb_op6(ksp, cwd, ip, op, m, ivp); if(op != obuf) /* output buffer is not aligned */ memcpy(obuf, buf, m * AES_BLOCK_SIZE); ibuf += m * AES_BLOCK_SIZE; obuf += m * AES_BLOCK_SIZE; cnt += m * AES_BLOCK_SIZE; } } if(ivp != iv) memcpy(iv, ivp, AES_BLOCK_SIZE); } #else # ifdef FAST_BUFFER_OPERATIONS if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) &&!ALIGN_OFFSET( iv, 4 )) while(cnt + AES_BLOCK_SIZE <= len) { uint32_t t; assert(b_pos == 0); if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; t = lp32(ibuf)[0], lp32(obuf)[0] = t ^ lp32(iv)[0], lp32(iv)[0] = t; t = lp32(ibuf)[1], lp32(obuf)[1] = t ^ lp32(iv)[1], lp32(iv)[1] = t; t = lp32(ibuf)[2], lp32(obuf)[2] = t ^ lp32(iv)[2], lp32(iv)[2] = t; t = lp32(ibuf)[3], lp32(obuf)[3] = t ^ lp32(iv)[3], lp32(iv)[3] = t; ibuf += AES_BLOCK_SIZE; obuf += AES_BLOCK_SIZE; cnt += AES_BLOCK_SIZE; } else # endif while(cnt + AES_BLOCK_SIZE <= len) { uint8_t t; assert(b_pos == 0); if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; t = ibuf[ 0], obuf[ 0] = t ^ iv[ 0], iv[ 0] = t; t = ibuf[ 1], obuf[ 1] = t ^ iv[ 1], iv[ 1] = t; t = ibuf[ 2], obuf[ 2] = t ^ iv[ 2], iv[ 2] = t; t = ibuf[ 3], obuf[ 3] = t ^ iv[ 3], iv[ 3] = t; t = ibuf[ 4], obuf[ 4] = t ^ iv[ 4], iv[ 4] = t; t = ibuf[ 5], obuf[ 5] = t ^ iv[ 5], iv[ 5] = t; t = ibuf[ 6], obuf[ 6] = t ^ iv[ 6], iv[ 6] = t; t = ibuf[ 7], obuf[ 7] = t ^ iv[ 7], iv[ 7] = t; t = ibuf[ 8], obuf[ 8] = t ^ iv[ 8], iv[ 8] = t; t = ibuf[ 9], obuf[ 9] = t ^ iv[ 9], iv[ 9] = t; t = ibuf[10], obuf[10] = t ^ iv[10], iv[10] = t; t = ibuf[11], obuf[11] = t ^ iv[11], iv[11] = t; t = ibuf[12], obuf[12] = t ^ iv[12], iv[12] = t; t = ibuf[13], obuf[13] = t ^ iv[13], iv[13] = t; t = ibuf[14], obuf[14] = t ^ iv[14], iv[14] = t; t = ibuf[15], obuf[15] = t ^ iv[15], iv[15] = t; ibuf += AES_BLOCK_SIZE; obuf += AES_BLOCK_SIZE; cnt += AES_BLOCK_SIZE; } #endif } while(cnt < len) { uint8_t t; if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; while(cnt < len && b_pos < AES_BLOCK_SIZE) { t = *ibuf++; *obuf++ = t ^ iv[b_pos]; iv[b_pos++] = t; cnt++; } b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); } ctx->inf.b[2] = (uint8_t)b_pos; return EXIT_SUCCESS; } AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) { int cnt = 0, b_pos = (int)ctx->inf.b[2], nb; if(b_pos) /* complete any partial block */ { while(b_pos < AES_BLOCK_SIZE && cnt < len) { *obuf++ = iv[b_pos++] ^ *ibuf++; cnt++; } b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); } if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */ { #if defined( USE_VIA_ACE_IF_PRESENT ) if(ctx->inf.b[1] == 0xff) { int m; uint8_t *ksp = (uint8_t*)(ctx->ks), *ivp = iv; aligned_auto(uint8_t, liv, AES_BLOCK_SIZE, 16); via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); if(ALIGN_OFFSET( ctx, 16 )) return EXIT_FAILURE; if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ { ivp = liv; memcpy(liv, iv, AES_BLOCK_SIZE); } if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) { via_ofb_op6(ksp, cwd, ibuf, obuf, nb, ivp); ibuf += nb * AES_BLOCK_SIZE; obuf += nb * AES_BLOCK_SIZE; cnt += nb * AES_BLOCK_SIZE; } else /* input, output or both are unaligned */ { aligned_auto(uint8_t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); uint8_t *ip, *op; while(nb) { m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); if(ip != ibuf) memcpy(buf, ibuf, m * AES_BLOCK_SIZE); via_ofb_op6(ksp, cwd, ip, op, m, ivp); if(op != obuf) memcpy(obuf, buf, m * AES_BLOCK_SIZE); ibuf += m * AES_BLOCK_SIZE; obuf += m * AES_BLOCK_SIZE; cnt += m * AES_BLOCK_SIZE; } } if(ivp != iv) memcpy(iv, ivp, AES_BLOCK_SIZE); } #else # ifdef FAST_BUFFER_OPERATIONS if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) while(cnt + AES_BLOCK_SIZE <= len) { assert(b_pos == 0); if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; lp32(obuf)[0] = lp32(iv)[0] ^ lp32(ibuf)[0]; lp32(obuf)[1] = lp32(iv)[1] ^ lp32(ibuf)[1]; lp32(obuf)[2] = lp32(iv)[2] ^ lp32(ibuf)[2]; lp32(obuf)[3] = lp32(iv)[3] ^ lp32(ibuf)[3]; ibuf += AES_BLOCK_SIZE; obuf += AES_BLOCK_SIZE; cnt += AES_BLOCK_SIZE; } else # endif while(cnt + AES_BLOCK_SIZE <= len) { assert(b_pos == 0); if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; obuf[ 0] = iv[ 0] ^ ibuf[ 0]; obuf[ 1] = iv[ 1] ^ ibuf[ 1]; obuf[ 2] = iv[ 2] ^ ibuf[ 2]; obuf[ 3] = iv[ 3] ^ ibuf[ 3]; obuf[ 4] = iv[ 4] ^ ibuf[ 4]; obuf[ 5] = iv[ 5] ^ ibuf[ 5]; obuf[ 6] = iv[ 6] ^ ibuf[ 6]; obuf[ 7] = iv[ 7] ^ ibuf[ 7]; obuf[ 8] = iv[ 8] ^ ibuf[ 8]; obuf[ 9] = iv[ 9] ^ ibuf[ 9]; obuf[10] = iv[10] ^ ibuf[10]; obuf[11] = iv[11] ^ ibuf[11]; obuf[12] = iv[12] ^ ibuf[12]; obuf[13] = iv[13] ^ ibuf[13]; obuf[14] = iv[14] ^ ibuf[14]; obuf[15] = iv[15] ^ ibuf[15]; ibuf += AES_BLOCK_SIZE; obuf += AES_BLOCK_SIZE; cnt += AES_BLOCK_SIZE; } #endif } while(cnt < len) { if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; while(cnt < len && b_pos < AES_BLOCK_SIZE) { *obuf++ = iv[b_pos++] ^ *ibuf++; cnt++; } b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); } ctx->inf.b[2] = (uint8_t)b_pos; return EXIT_SUCCESS; } #define BFR_LENGTH (BFR_BLOCKS * AES_BLOCK_SIZE) AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx ctx[1]) { unsigned char *ip; int i, blen, b_pos = (int)(ctx->inf.b[2]); #if defined( USE_VIA_ACE_IF_PRESENT ) aligned_auto(uint8_t, buf, BFR_LENGTH, 16); if(ctx->inf.b[1] == 0xff && ALIGN_OFFSET( ctx, 16 )) return EXIT_FAILURE; #else uint8_t buf[BFR_LENGTH]; #endif if(b_pos) { memcpy(buf, cbuf, AES_BLOCK_SIZE); if(aes_ecb_encrypt(buf, buf, AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; while(b_pos < AES_BLOCK_SIZE && len) { *obuf++ = *ibuf++ ^ buf[b_pos++]; --len; } if(len) ctr_inc(cbuf), b_pos = 0; } while(len) { blen = (len > BFR_LENGTH ? BFR_LENGTH : len), len -= blen; for(i = 0, ip = buf; i < (blen >> 4); ++i) { memcpy(ip, cbuf, AES_BLOCK_SIZE); ctr_inc(cbuf); ip += AES_BLOCK_SIZE; } if(blen & (AES_BLOCK_SIZE - 1)) memcpy(ip, cbuf, AES_BLOCK_SIZE), i++; #if defined( USE_VIA_ACE_IF_PRESENT ) if(ctx->inf.b[1] == 0xff) { via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); via_ecb_op5((ctx->ks), cwd, buf, buf, i); } else #endif if(aes_ecb_encrypt(buf, buf, i * AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS) return EXIT_FAILURE; i = 0; ip = buf; # ifdef FAST_BUFFER_OPERATIONS if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( ip, 4 )) while(i + AES_BLOCK_SIZE <= blen) { lp32(obuf)[0] = lp32(ibuf)[0] ^ lp32(ip)[0]; lp32(obuf)[1] = lp32(ibuf)[1] ^ lp32(ip)[1]; lp32(obuf)[2] = lp32(ibuf)[2] ^ lp32(ip)[2]; lp32(obuf)[3] = lp32(ibuf)[3] ^ lp32(ip)[3]; i += AES_BLOCK_SIZE; ip += AES_BLOCK_SIZE; ibuf += AES_BLOCK_SIZE; obuf += AES_BLOCK_SIZE; } else #endif while(i + AES_BLOCK_SIZE <= blen) { obuf[ 0] = ibuf[ 0] ^ ip[ 0]; obuf[ 1] = ibuf[ 1] ^ ip[ 1]; obuf[ 2] = ibuf[ 2] ^ ip[ 2]; obuf[ 3] = ibuf[ 3] ^ ip[ 3]; obuf[ 4] = ibuf[ 4] ^ ip[ 4]; obuf[ 5] = ibuf[ 5] ^ ip[ 5]; obuf[ 6] = ibuf[ 6] ^ ip[ 6]; obuf[ 7] = ibuf[ 7] ^ ip[ 7]; obuf[ 8] = ibuf[ 8] ^ ip[ 8]; obuf[ 9] = ibuf[ 9] ^ ip[ 9]; obuf[10] = ibuf[10] ^ ip[10]; obuf[11] = ibuf[11] ^ ip[11]; obuf[12] = ibuf[12] ^ ip[12]; obuf[13] = ibuf[13] ^ ip[13]; obuf[14] = ibuf[14] ^ ip[14]; obuf[15] = ibuf[15] ^ ip[15]; i += AES_BLOCK_SIZE; ip += AES_BLOCK_SIZE; ibuf += AES_BLOCK_SIZE; obuf += AES_BLOCK_SIZE; } while(i++ < blen) *obuf++ = *ibuf++ ^ ip[b_pos++]; } ctx->inf.b[2] = (uint8_t)b_pos; return EXIT_SUCCESS; } #if defined(__cplusplus) } #endif #endif openzwave-1.6.1914/cpp/src/aes/aescrypt.c0000644000175200017520000002411014032142455015035 00000000000000/* --------------------------------------------------------------------------- Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 */ #include "aesopt.h" #include "aestab.h" #if defined( USE_INTEL_AES_IF_PRESENT ) #include #else /* map names here to provide the external API ('name' -> 'aes_name') */ # define aes_xi(x) aes_ ## x #endif #if defined(__cplusplus) extern "C" { #endif #define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c]) #define so(y,x,c) word_out(y, c, s(x,c)) #if defined(ARRAYS) #define locals(y,x) x[4],y[4] #else #define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3 #endif #define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ s(y,2) = s(x,2); s(y,3) = s(x,3); #define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) #define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) #define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) #if ( FUNCS_IN_C & ENCRYPTION_IN_C ) /* Visual C++ .Net v7.1 provides the fastest encryption code when using Pentium optimiation with small code but this is poor for decryption so we need to control this with the following VC++ pragmas */ #if defined( _MSC_VER ) && !defined( _WIN64 ) #pragma optimize( "s", on ) #endif /* Given the column (c) of the output state variable, the following macros give the input state variables which are needed in its computation for each row (r) of the state. All the alternative macros give the same end values but expand into different ways of calculating these values. In particular the complex macro used for dynamically variable block sizes is designed to expand to a compile time constant whenever possible but will expand to conditional clauses on some branches (I am grateful to Frank Yellin for this construction) */ #define fwd_var(x,r,c)\ ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ : r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\ : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ : ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))) #if defined(FT4_SET) #undef dec_fmvars #define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c)) #elif defined(FT1_SET) #undef dec_fmvars #define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c)) #else #define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c))) #endif #if defined(FL4_SET) #define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c)) #elif defined(FL1_SET) #define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c)) #else #define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c)) #endif AES_RETURN aes_xi(encrypt)(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]) { uint32_t locals(b0, b1); const uint32_t *kp; #if defined( dec_fmvars ) dec_fmvars; /* declare variables for fwd_mcol() if needed */ #endif if(cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16) return EXIT_FAILURE; kp = cx->ks; state_in(b0, in, kp); #if (ENC_UNROLL == FULL) switch(cx->inf.b[0]) { case 14 * 16: round(fwd_rnd, b1, b0, kp + 1 * N_COLS); round(fwd_rnd, b0, b1, kp + 2 * N_COLS); kp += 2 * N_COLS; case 12 * 16: round(fwd_rnd, b1, b0, kp + 1 * N_COLS); round(fwd_rnd, b0, b1, kp + 2 * N_COLS); kp += 2 * N_COLS; case 10 * 16: round(fwd_rnd, b1, b0, kp + 1 * N_COLS); round(fwd_rnd, b0, b1, kp + 2 * N_COLS); round(fwd_rnd, b1, b0, kp + 3 * N_COLS); round(fwd_rnd, b0, b1, kp + 4 * N_COLS); round(fwd_rnd, b1, b0, kp + 5 * N_COLS); round(fwd_rnd, b0, b1, kp + 6 * N_COLS); round(fwd_rnd, b1, b0, kp + 7 * N_COLS); round(fwd_rnd, b0, b1, kp + 8 * N_COLS); round(fwd_rnd, b1, b0, kp + 9 * N_COLS); round(fwd_lrnd, b0, b1, kp +10 * N_COLS); } #else #if (ENC_UNROLL == PARTIAL) { uint32_t rnd; for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) { kp += N_COLS; round(fwd_rnd, b1, b0, kp); kp += N_COLS; round(fwd_rnd, b0, b1, kp); } kp += N_COLS; round(fwd_rnd, b1, b0, kp); #else { uint32_t rnd; for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) { kp += N_COLS; round(fwd_rnd, b1, b0, kp); l_copy(b0, b1); } #endif kp += N_COLS; round(fwd_lrnd, b0, b1, kp); } #endif state_out(out, b0); return EXIT_SUCCESS; } #endif #if ( FUNCS_IN_C & DECRYPTION_IN_C) /* Visual C++ .Net v7.1 provides the fastest encryption code when using Pentium optimiation with small code but this is poor for decryption so we need to control this with the following VC++ pragmas */ #if defined( _MSC_VER ) && !defined( _WIN64 ) #pragma optimize( "t", on ) #endif /* Given the column (c) of the output state variable, the following macros give the input state variables which are needed in its computation for each row (r) of the state. All the alternative macros give the same end values but expand into different ways of calculating these values. In particular the complex macro used for dynamically variable block sizes is designed to expand to a compile time constant whenever possible but will expand to conditional clauses on some branches (I am grateful to Frank Yellin for this construction) */ #define inv_var(x,r,c)\ ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ : r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\ : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ : ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))) #if defined(IT4_SET) #undef dec_imvars #define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c)) #elif defined(IT1_SET) #undef dec_imvars #define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c)) #else #define inv_rnd(y,x,k,c) (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))) #endif #if defined(IL4_SET) #define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c)) #elif defined(IL1_SET) #define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c)) #else #define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)) #endif /* This code can work with the decryption key schedule in the */ /* order that is used for encrytpion (where the 1st decryption */ /* round key is at the high end ot the schedule) or with a key */ /* schedule that has been reversed to put the 1st decryption */ /* round key at the low end of the schedule in memory (when */ /* AES_REV_DKS is defined) */ #ifdef AES_REV_DKS #define key_ofs 0 #define rnd_key(n) (kp + n * N_COLS) #else #define key_ofs 1 #define rnd_key(n) (kp - n * N_COLS) #endif AES_RETURN aes_xi(decrypt)(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]) { uint32_t locals(b0, b1); #if defined( dec_imvars ) dec_imvars; /* declare variables for inv_mcol() if needed */ #endif const uint32_t *kp; if(cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16) return EXIT_FAILURE; kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0); state_in(b0, in, kp); #if (DEC_UNROLL == FULL) kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2)); switch(cx->inf.b[0]) { case 14 * 16: round(inv_rnd, b1, b0, rnd_key(-13)); round(inv_rnd, b0, b1, rnd_key(-12)); case 12 * 16: round(inv_rnd, b1, b0, rnd_key(-11)); round(inv_rnd, b0, b1, rnd_key(-10)); case 10 * 16: round(inv_rnd, b1, b0, rnd_key(-9)); round(inv_rnd, b0, b1, rnd_key(-8)); round(inv_rnd, b1, b0, rnd_key(-7)); round(inv_rnd, b0, b1, rnd_key(-6)); round(inv_rnd, b1, b0, rnd_key(-5)); round(inv_rnd, b0, b1, rnd_key(-4)); round(inv_rnd, b1, b0, rnd_key(-3)); round(inv_rnd, b0, b1, rnd_key(-2)); round(inv_rnd, b1, b0, rnd_key(-1)); round(inv_lrnd, b0, b1, rnd_key( 0)); } #else #if (DEC_UNROLL == PARTIAL) { uint32_t rnd; for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) { kp = rnd_key(1); round(inv_rnd, b1, b0, kp); kp = rnd_key(1); round(inv_rnd, b0, b1, kp); } kp = rnd_key(1); round(inv_rnd, b1, b0, kp); #else { uint32_t rnd; for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) { kp = rnd_key(1); round(inv_rnd, b1, b0, kp); l_copy(b0, b1); } #endif kp = rnd_key(1); round(inv_lrnd, b0, b1, kp); } #endif state_out(out, b0); return EXIT_SUCCESS; } #endif #if defined(__cplusplus) } #endif openzwave-1.6.1914/cpp/src/aes/aestab.h0000644000175200017520000001232414032142455014453 00000000000000/* --------------------------------------------------------------------------- Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 This file contains the code for declaring the tables needed to implement AES. The file aesopt.h is assumed to be included before this header file. If there are no global variables, the definitions here can be used to put the AES tables in a structure so that a pointer can then be added to the AES context to pass them to the AES routines that need them. If this facility is used, the calling program has to ensure that this pointer is managed appropriately. In particular, the value of the t_dec(in,it) item in the table structure must be set to zero in order to ensure that the tables are initialised. In practice the three code sequences in aeskey.c that control the calls to aes_init() and the aes_init() routine itself will have to be changed for a specific implementation. If global variables are available it will generally be preferable to use them with the precomputed FIXED_TABLES option that uses static global tables. The following defines can be used to control the way the tables are defined, initialised and used in embedded environments that require special features for these purposes the 't_dec' construction is used to declare fixed table arrays the 't_set' construction is used to set fixed table values the 't_use' construction is used to access fixed table values 256 byte tables: t_xxx(s,box) => forward S box t_xxx(i,box) => inverse S box 256 32-bit word OR 4 x 256 32-bit word tables: t_xxx(f,n) => forward normal round t_xxx(f,l) => forward last round t_xxx(i,n) => inverse normal round t_xxx(i,l) => inverse last round t_xxx(l,s) => key schedule table t_xxx(i,m) => key schedule table Other variables and tables: t_xxx(r,c) => the rcon table */ #if !defined( _AESTAB_H ) #define _AESTAB_H #if defined(__cplusplus) extern "C" { #endif #define t_dec(m,n) t_##m##n #define t_set(m,n) t_##m##n #define t_use(m,n) t_##m##n #if defined(FIXED_TABLES) # if !defined( __GNUC__ ) && (defined( __MSDOS__ ) || defined( __WIN16__ )) /* make tables far data to avoid using too much DGROUP space (PG) */ # define CONST const far # else # define CONST const # endif #else # define CONST #endif #if defined(DO_TABLES) # define EXTERN #else # define EXTERN extern #endif #if defined(_MSC_VER) && defined(TABLE_ALIGN) #define ALIGN __declspec(align(TABLE_ALIGN)) #else #define ALIGN #endif #if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 ) # define XP_DIR __cdecl #else # define XP_DIR #endif #if defined(DO_TABLES) && defined(FIXED_TABLES) #define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] = b(e) #define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) } EXTERN ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH] = rc_data(w0); #else #define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] #define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] EXTERN ALIGN CONST uint32_t t_dec(r,c)[RC_LENGTH]; #endif #if defined( SBX_SET ) d_1(uint8_t, t_dec(s,box), sb_data, h0); #endif #if defined( ISB_SET ) d_1(uint8_t, t_dec(i,box), isb_data, h0); #endif #if defined( FT1_SET ) d_1(uint32_t, t_dec(f,n), sb_data, u0); #endif #if defined( FT4_SET ) d_4(uint32_t, t_dec(f,n), sb_data, u0, u1, u2, u3); #endif #if defined( FL1_SET ) d_1(uint32_t, t_dec(f,l), sb_data, w0); #endif #if defined( FL4_SET ) d_4(uint32_t, t_dec(f,l), sb_data, w0, w1, w2, w3); #endif #if defined( IT1_SET ) d_1(uint32_t, t_dec(i,n), isb_data, v0); #endif #if defined( IT4_SET ) d_4(uint32_t, t_dec(i,n), isb_data, v0, v1, v2, v3); #endif #if defined( IL1_SET ) d_1(uint32_t, t_dec(i,l), isb_data, w0); #endif #if defined( IL4_SET ) d_4(uint32_t, t_dec(i,l), isb_data, w0, w1, w2, w3); #endif #if defined( LS1_SET ) #if defined( FL1_SET ) #undef LS1_SET #else d_1(uint32_t, t_dec(l,s), sb_data, w0); #endif #endif #if defined( LS4_SET ) #if defined( FL4_SET ) #undef LS4_SET #else d_4(uint32_t, t_dec(l,s), sb_data, w0, w1, w2, w3); #endif #endif #if defined( IM1_SET ) d_1(uint32_t, t_dec(i,m), mm_data, v0); #endif #if defined( IM4_SET ) d_4(uint32_t, t_dec(i,m), mm_data, v0, v1, v2, v3); #endif #if defined(__cplusplus) } #endif #endif openzwave-1.6.1914/cpp/src/aes/aes.h0000644000175200017520000001636514032142455013775 00000000000000/* --------------------------------------------------------------------------- Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 This file contains the definitions required to use AES in C. See aesopt.h for optimisation details. */ #ifndef _AES_H #define _AES_H #include /* This include is used to find 8 & 32 bit unsigned integer types */ #include "brg_types.h" #if defined(__cplusplus) extern "C" { #endif #define AES_128 /* if a fast 128 bit key scheduler is needed */ #define AES_192 /* if a fast 192 bit key scheduler is needed */ #define AES_256 /* if a fast 256 bit key scheduler is needed */ #define AES_VAR /* if variable key size scheduler is needed */ #define AES_MODES /* if support is needed for modes */ /* The following must also be set in assembler files if being used */ #define AES_ENCRYPT /* if support for encryption is needed */ #define AES_DECRYPT /* if support for decryption is needed */ #define AES_BLOCK_SIZE 16 /* the AES block size in bytes */ #define N_COLS 4 /* the number of columns in the state */ /* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */ /* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */ /* or 44, 52 or 60 32-bit words. */ #if defined( AES_VAR ) || defined( AES_256 ) #define KS_LENGTH 60 #elif defined( AES_192 ) #define KS_LENGTH 52 #else #define KS_LENGTH 44 #endif #define AES_RETURN INT_RETURN /* the character array 'inf' in the following structures is used */ /* to hold AES context information. This AES code uses cx->inf.b[0] */ /* to hold the number of rounds multiplied by 16. The other three */ /* elements can be used by code that implements additional modes */ typedef union { uint32_t l; uint8_t b[4]; } aes_inf; #ifdef _MSC_VER #pragma warning( disable : 4324 ) #endif #ifdef _WIN64 __declspec(align(16)) #endif typedef struct { uint32_t ks[KS_LENGTH]; aes_inf inf; } aes_encrypt_ctx; #ifdef _WIN64 __declspec(align(16)) #endif typedef struct { uint32_t ks[KS_LENGTH]; aes_inf inf; } aes_decrypt_ctx; #ifdef _MSC_VER #pragma warning( default : 4324 ) #endif /* This routine must be called before first use if non-static */ /* tables are being used */ AES_RETURN aes_init(void); /* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */ /* those in the range 128 <= key_len <= 256 are given in bits */ #if defined( AES_ENCRYPT ) #if defined( AES_128 ) || defined( AES_VAR) AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); #endif #if defined( AES_192 ) || defined( AES_VAR) AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); #endif #if defined( AES_256 ) || defined( AES_VAR) AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); #endif #if defined( AES_VAR ) AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]); #endif AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]); #endif #if defined( AES_DECRYPT ) #if defined( AES_128 ) || defined( AES_VAR) AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); #endif #if defined( AES_192 ) || defined( AES_VAR) AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); #endif #if defined( AES_256 ) || defined( AES_VAR) AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); #endif #if defined( AES_VAR ) AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]); #endif AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]); #endif #if defined( AES_MODES ) /* Multiple calls to the following subroutines for multiple block */ /* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */ /* long messages incrementally provided that the context AND the iv */ /* are preserved between all such calls. For the ECB and CBC modes */ /* each individual call within a series of incremental calls must */ /* process only full blocks (i.e. len must be a multiple of 16) but */ /* the CFB, OFB and CTR mode calls can handle multiple incremental */ /* calls of any length. Each mode is reset when a new AES key is */ /* set but ECB and CBC operations can be reset without setting a */ /* new key by setting a new IV value. To reset CFB, OFB and CTR */ /* without setting the key, aes_mode_reset() must be called and the */ /* IV must be set. NOTE: All these calls update the IV on exit so */ /* this has to be reset if a new operation with the same IV as the */ /* previous one is required (or decryption follows encryption with */ /* the same IV array). */ AES_RETURN aes_test_alignment_detection(unsigned int n); AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, const aes_encrypt_ctx cx[1]); AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, const aes_decrypt_ctx cx[1]); AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, const aes_encrypt_ctx cx[1]); AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, const aes_decrypt_ctx cx[1]); AES_RETURN aes_mode_reset(aes_encrypt_ctx cx[1]); AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, aes_encrypt_ctx cx[1]); AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, aes_encrypt_ctx cx[1]); #define aes_ofb_encrypt aes_ofb_crypt #define aes_ofb_decrypt aes_ofb_crypt AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *iv, aes_encrypt_ctx cx[1]); typedef void cbuf_inc(unsigned char *cbuf); #define aes_ctr_encrypt aes_ctr_crypt #define aes_ctr_decrypt aes_ctr_crypt AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]); #endif #if defined(__cplusplus) } #endif #endif openzwave-1.6.1914/cpp/src/aes/aesopt.h0000644000175200017520000006667514032142455014531 00000000000000/* --------------------------------------------------------------------------- Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 This file contains the compilation options for AES (Rijndael) and code that is common across encryption, key scheduling and table generation. OPERATION These source code files implement the AES algorithm Rijndael designed by Joan Daemen and Vincent Rijmen. This version is designed for the standard block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24 and 32 bytes). This version is designed for flexibility and speed using operations on 32-bit words rather than operations on bytes. It can be compiled with either big or little endian internal byte order but is faster when the native byte order for the processor is used. THE CIPHER INTERFACE The cipher interface is implemented as an array of bytes in which lower AES bit sequence indexes map to higher numeric significance within bytes. uint8_t (an unsigned 8-bit type) uint32_t (an unsigned 32-bit type) struct aes_encrypt_ctx (structure for the cipher encryption context) struct aes_decrypt_ctx (structure for the cipher decryption context) AES_RETURN the function return type C subroutine calls: AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]); AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]); IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that you call aes_init() before AES is used so that the tables are initialised. C++ aes class subroutines: Class AESencrypt for encryption Construtors: AESencrypt(void) AESencrypt(const unsigned char *key) - 128 bit key Members: AES_RETURN key128(const unsigned char *key) AES_RETURN key192(const unsigned char *key) AES_RETURN key256(const unsigned char *key) AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const Class AESdecrypt for encryption Construtors: AESdecrypt(void) AESdecrypt(const unsigned char *key) - 128 bit key Members: AES_RETURN key128(const unsigned char *key) AES_RETURN key192(const unsigned char *key) AES_RETURN key256(const unsigned char *key) AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const */ #if !defined( _AESOPT_H ) #define _AESOPT_H #if defined( __cplusplus ) #include "aescpp.h" #else #include "aes.h" #endif /* PLATFORM SPECIFIC INCLUDES */ #include "brg_endian.h" /* CONFIGURATION - THE USE OF DEFINES Later in this section there are a number of defines that control the operation of the code. In each section, the purpose of each define is explained so that the relevant form can be included or excluded by setting either 1's or 0's respectively on the branches of the related #if clauses. The following local defines should not be changed. */ #define ENCRYPTION_IN_C 1 #define DECRYPTION_IN_C 2 #define ENC_KEYING_IN_C 4 #define DEC_KEYING_IN_C 8 #define NO_TABLES 0 #define ONE_TABLE 1 #define FOUR_TABLES 4 #define NONE 0 #define PARTIAL 1 #define FULL 2 /* --- START OF USER CONFIGURED OPTIONS --- */ /* 1. BYTE ORDER WITHIN 32 BIT WORDS The fundamental data processing units in Rijndael are 8-bit bytes. The input, output and key input are all enumerated arrays of bytes in which bytes are numbered starting at zero and increasing to one less than the number of bytes in the array in question. This enumeration is only used for naming bytes and does not imply any adjacency or order relationship from one byte to another. When these inputs and outputs are considered as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte. In this implementation bits are numbered from 0 to 7 starting at the numerically least significant end of each byte (bit n represents 2^n). However, Rijndael can be implemented more efficiently using 32-bit words by packing bytes into words so that bytes 4*n to 4*n+3 are placed into word[n]. While in principle these bytes can be assembled into words in any positions, this implementation only supports the two formats in which bytes in adjacent positions within words also have adjacent byte numbers. This order is called big-endian if the lowest numbered bytes in words have the highest numeric significance and little-endian if the opposite applies. This code can work in either order irrespective of the order used by the machine on which it runs. Normally the internal byte order will be set to the order of the processor on which the code is to be run but this define can be used to reverse this in special situations WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set. This define will hence be redefined later (in section 4) if necessary */ #if 1 # define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER #elif 0 # define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN #elif 0 # define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN #else # error The algorithm byte order is not defined #endif /* 2. Intel AES AND VIA ACE SUPPORT */ #if defined( __GNUC__ ) && defined( __i386__ ) \ || defined(_WIN32) && defined(_M_IX86) \ && !(defined(_WIN64) || defined(_WIN32_WCE) || defined(_MSC_VER) && (_MSC_VER <= 800)) # define VIA_ACE_POSSIBLE #endif /* Define this option if support for the Intel AESNI is required (not currently available with GCC). If AESNI is known to be present, then defining ASSUME_INTEL_AES_VIA_PRESENT will replace the ordinary encryption/decryption. If USE_INTEL_AES_IF_PRESENT is defined then AESNI will be used if it is detected (both present and enabled). AESNI uses a decryption key schedule with the first decryption round key at the high end of the key scedule with the following round keys at lower positions in memory. So AES_REV_DKS must NOT be defined when AESNI will be used. ALthough it is unlikely that assembler code will be used with an AESNI build, if it is then AES_REV_DKS must NOT be defined when such assembler files are built */ #if 0 && defined( _WIN64 ) && defined( _MSC_VER ) # define INTEL_AES_POSSIBLE #endif #if defined( INTEL_AES_POSSIBLE ) && !defined( USE_INTEL_AES_IF_PRESENT ) # define USE_INTEL_AES_IF_PRESENT #endif /* Define this option if support for the VIA ACE is required. This uses inline assembler instructions and is only implemented for the Microsoft, Intel and GCC compilers. If VIA ACE is known to be present, then defining ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption code. If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if it is detected (both present and enabled) but the normal AES code will also be present. When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte aligned; other input/output buffers do not need to be 16 byte aligned but there are very large performance gains if this can be arranged. VIA ACE also requires the decryption key schedule to be in reverse order (which later checks below ensure). AES_REV_DKS must be set for assembler code used with a VIA ACE build */ #if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( USE_VIA_ACE_IF_PRESENT ) # define USE_VIA_ACE_IF_PRESENT #endif #if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( ASSUME_VIA_ACE_PRESENT ) # define ASSUME_VIA_ACE_PRESENT # endif /* 3. ASSEMBLER SUPPORT This define (which can be on the command line) enables the use of the assembler code routines for encryption, decryption and key scheduling as follows: ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for encryption and decryption and but with key scheduling in C ASM_X86_V2 uses assembler (aes_x86_v2.asm) with compressed tables for encryption, decryption and key scheduling ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for encryption and decryption and but with key scheduling in C ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for encryption and decryption and but with key scheduling in C Change one 'if 0' below to 'if 1' to select the version or define as a compilation option. */ #if 0 && !defined( ASM_X86_V1C ) # define ASM_X86_V1C #elif 0 && !defined( ASM_X86_V2 ) # define ASM_X86_V2 #elif 0 && !defined( ASM_X86_V2C ) # define ASM_X86_V2C #elif 0 && !defined( ASM_AMD64_C ) # define ASM_AMD64_C #endif #if (defined ( ASM_X86_V1C ) || defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) \ && !defined( _M_IX86 ) || defined( ASM_AMD64_C ) && !defined( _M_X64 ) # error Assembler code is only available for x86 and AMD64 systems #endif /* 4. FAST INPUT/OUTPUT OPERATIONS. On some machines it is possible to improve speed by transferring the bytes in the input and output arrays to and from the internal 32-bit variables by addressing these arrays as if they are arrays of 32-bit words. On some machines this will always be possible but there may be a large performance penalty if the byte arrays are not aligned on the normal word boundaries. On other machines this technique will lead to memory access errors when such 32-bit word accesses are not properly aligned. The option SAFE_IO avoids such problems but will often be slower on those machines that support misaligned access (especially so if care is taken to align the input and output byte arrays on 32-bit word boundaries). If SAFE_IO is not defined it is assumed that access to byte arrays as if they are arrays of 32-bit words will not cause problems when such accesses are misaligned. */ #if 1 && !defined( _MSC_VER ) # define SAFE_IO #endif /* 5. LOOP UNROLLING The code for encryption and decrytpion cycles through a number of rounds that can be implemented either in a loop or by expanding the code into a long sequence of instructions, the latter producing a larger program but one that will often be much faster. The latter is called loop unrolling. There are also potential speed advantages in expanding two iterations in a loop with half the number of iterations, which is called partial loop unrolling. The following options allow partial or full loop unrolling to be set independently for encryption and decryption */ #if 1 # define ENC_UNROLL FULL #elif 0 # define ENC_UNROLL PARTIAL #else # define ENC_UNROLL NONE #endif #if 1 # define DEC_UNROLL FULL #elif 0 # define DEC_UNROLL PARTIAL #else # define DEC_UNROLL NONE #endif #if 1 # define ENC_KS_UNROLL #endif #if 1 # define DEC_KS_UNROLL #endif /* 6. FAST FINITE FIELD OPERATIONS If this section is included, tables are used to provide faster finite field arithmetic (this has no effect if FIXED_TABLES is defined). */ #if 1 # define FF_TABLES #endif /* 7. INTERNAL STATE VARIABLE FORMAT The internal state of Rijndael is stored in a number of local 32-bit word varaibles which can be defined either as an array or as individual names variables. Include this section if you want to store these local varaibles in arrays. Otherwise individual local variables will be used. */ #if 1 # define ARRAYS #endif /* 8. FIXED OR DYNAMIC TABLES When this section is included the tables used by the code are compiled statically into the binary file. Otherwise the subroutine aes_init() must be called to compute them before the code is first used. */ #if 1 && !(defined( _MSC_VER ) && ( _MSC_VER <= 800 )) # define FIXED_TABLES #endif /* 9. MASKING OR CASTING FROM LONGER VALUES TO BYTES In some systems it is better to mask longer values to extract bytes rather than using a cast. This option allows this choice. */ #if 0 # define to_byte(x) ((uint8_t)(x)) #else # define to_byte(x) ((x) & 0xff) #endif /* 10. TABLE ALIGNMENT On some sytsems speed will be improved by aligning the AES large lookup tables on particular boundaries. This define should be set to a power of two giving the desired alignment. It can be left undefined if alignment is not needed. This option is specific to the Microsft VC++ compiler - it seems to sometimes cause trouble for the VC++ version 6 compiler. */ #if 1 && defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) # define TABLE_ALIGN 32 #endif /* 11. REDUCE CODE AND TABLE SIZE This replaces some expanded macros with function calls if AES_ASM_V2 or AES_ASM_V2C are defined */ #if 0 && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) # define REDUCE_CODE_SIZE #endif /* 12. TABLE OPTIONS This cipher proceeds by repeating in a number of cycles known as 'rounds' which are implemented by a round function which can optionally be speeded up using tables. The basic tables are each 256 32-bit words, with either one or four tables being required for each round function depending on how much speed is required. The encryption and decryption round functions are different and the last encryption and decrytpion round functions are different again making four different round functions in all. This means that: 1. Normal encryption and decryption rounds can each use either 0, 1 or 4 tables and table spaces of 0, 1024 or 4096 bytes each. 2. The last encryption and decryption rounds can also use either 0, 1 or 4 tables and table spaces of 0, 1024 or 4096 bytes each. Include or exclude the appropriate definitions below to set the number of tables used by this implementation. */ #if 1 /* set tables for the normal encryption round */ # define ENC_ROUND FOUR_TABLES #elif 0 # define ENC_ROUND ONE_TABLE #else # define ENC_ROUND NO_TABLES #endif #if 1 /* set tables for the last encryption round */ # define LAST_ENC_ROUND FOUR_TABLES #elif 0 # define LAST_ENC_ROUND ONE_TABLE #else # define LAST_ENC_ROUND NO_TABLES #endif #if 1 /* set tables for the normal decryption round */ # define DEC_ROUND FOUR_TABLES #elif 0 # define DEC_ROUND ONE_TABLE #else # define DEC_ROUND NO_TABLES #endif #if 1 /* set tables for the last decryption round */ # define LAST_DEC_ROUND FOUR_TABLES #elif 0 # define LAST_DEC_ROUND ONE_TABLE #else # define LAST_DEC_ROUND NO_TABLES #endif /* The decryption key schedule can be speeded up with tables in the same way that the round functions can. Include or exclude the following defines to set this requirement. */ #if 1 # define KEY_SCHED FOUR_TABLES #elif 0 # define KEY_SCHED ONE_TABLE #else # define KEY_SCHED NO_TABLES #endif /* ---- END OF USER CONFIGURED OPTIONS ---- */ /* VIA ACE support is only available for VC++ and GCC */ #if !defined( _MSC_VER ) && !defined( __GNUC__ ) # if defined( ASSUME_VIA_ACE_PRESENT ) # undef ASSUME_VIA_ACE_PRESENT # endif # if defined( USE_VIA_ACE_IF_PRESENT ) # undef USE_VIA_ACE_IF_PRESENT # endif #endif #if defined( ASSUME_VIA_ACE_PRESENT ) && !defined( USE_VIA_ACE_IF_PRESENT ) # define USE_VIA_ACE_IF_PRESENT #endif /* define to reverse decryption key schedule */ #if 1 || defined( USE_VIA_ACE_IF_PRESENT ) && !defined ( AES_REV_DKS ) # define AES_REV_DKS #endif /* Intel AESNI uses a decryption key schedule in the encryption order */ #if defined( USE_INTEL_AES_IF_PRESENT ) && defined ( AES_REV_DKS ) # undef AES_REV_DKS #endif /* Assembler support requires the use of platform byte order */ #if ( defined( ASM_X86_V1C ) || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) ) \ && (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER) # undef ALGORITHM_BYTE_ORDER # define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER #endif /* In this implementation the columns of the state array are each held in 32-bit words. The state array can be held in various ways: in an array of words, in a number of individual word variables or in a number of processor registers. The following define maps a variable name x and a column number c to the way the state array variable is to be held. The first define below maps the state into an array x[c] whereas the second form maps the state into a number of individual variables x0, x1, etc. Another form could map individual state colums to machine register names. */ #if defined( ARRAYS ) # define s(x,c) x[c] #else # define s(x,c) x##c #endif /* This implementation provides subroutines for encryption, decryption and for setting the three key lengths (separately) for encryption and decryption. Since not all functions are needed, masks are set up here to determine which will be implemented in C */ #if !defined( AES_ENCRYPT ) # define EFUNCS_IN_C 0 #elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) # define EFUNCS_IN_C ENC_KEYING_IN_C #elif !defined( ASM_X86_V2 ) # define EFUNCS_IN_C ( ENCRYPTION_IN_C | ENC_KEYING_IN_C ) #else # define EFUNCS_IN_C 0 #endif #if !defined( AES_DECRYPT ) # define DFUNCS_IN_C 0 #elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) # define DFUNCS_IN_C DEC_KEYING_IN_C #elif !defined( ASM_X86_V2 ) # define DFUNCS_IN_C ( DECRYPTION_IN_C | DEC_KEYING_IN_C ) #else # define DFUNCS_IN_C 0 #endif #define FUNCS_IN_C ( EFUNCS_IN_C | DFUNCS_IN_C ) /* END OF CONFIGURATION OPTIONS */ #define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2)) /* Disable or report errors on some combinations of options */ #if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES # undef LAST_ENC_ROUND # define LAST_ENC_ROUND NO_TABLES #elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES # undef LAST_ENC_ROUND # define LAST_ENC_ROUND ONE_TABLE #endif #if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE # undef ENC_UNROLL # define ENC_UNROLL NONE #endif #if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES # undef LAST_DEC_ROUND # define LAST_DEC_ROUND NO_TABLES #elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES # undef LAST_DEC_ROUND # define LAST_DEC_ROUND ONE_TABLE #endif #if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE # undef DEC_UNROLL # define DEC_UNROLL NONE #endif #if defined( bswap32 ) # define aes_sw32 bswap32 #elif defined( bswap_32 ) # define aes_sw32 bswap_32 #else # define brot(x,n) (((uint32_t)(x) << n) | ((uint32_t)(x) >> (32 - n))) # define aes_sw32(x) ((brot((x),8) & 0x00ff00ff) | (brot((x),24) & 0xff00ff00)) #endif /* upr(x,n): rotates bytes within words by n positions, moving bytes to higher index positions with wrap around into low positions ups(x,n): moves bytes by n positions to higher index positions in words but without wrap around bval(x,n): extracts a byte from a word WARNING: The definitions given here are intended only for use with unsigned variables and with shift counts that are compile time constants */ #if ( ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN ) # define upr(x,n) (((uint32_t)(x) << (8 * (n))) | ((uint32_t)(x) >> (32 - 8 * (n)))) # define ups(x,n) ((uint32_t) (x) << (8 * (n))) # define bval(x,n) to_byte((x) >> (8 * (n))) # define bytes2word(b0, b1, b2, b3) \ (((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | (b0)) #endif #if ( ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN ) # define upr(x,n) (((uint32_t)(x) >> (8 * (n))) | ((uint32_t)(x) << (32 - 8 * (n)))) # define ups(x,n) ((uint32_t) (x) >> (8 * (n))) # define bval(x,n) to_byte((x) >> (24 - 8 * (n))) # define bytes2word(b0, b1, b2, b3) \ (((uint32_t)(b0) << 24) | ((uint32_t)(b1) << 16) | ((uint32_t)(b2) << 8) | (b3)) #endif #if defined( SAFE_IO ) # define word_in(x,c) bytes2word(((const uint8_t*)(x)+4*c)[0], ((const uint8_t*)(x)+4*c)[1], \ ((const uint8_t*)(x)+4*c)[2], ((const uint8_t*)(x)+4*c)[3]) # define word_out(x,c,v) { ((uint8_t*)(x)+4*c)[0] = bval(v,0); ((uint8_t*)(x)+4*c)[1] = bval(v,1); \ ((uint8_t*)(x)+4*c)[2] = bval(v,2); ((uint8_t*)(x)+4*c)[3] = bval(v,3); } #elif ( ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER ) # define word_in(x,c) (*((uint32_t*)(x)+(c))) # define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = (v)) #else # define word_in(x,c) aes_sw32(*((uint32_t*)(x)+(c))) # define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = aes_sw32(v)) #endif /* the finite field modular polynomial and elements */ #define WPOLY 0x011b #define BPOLY 0x1b /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ #define gf_c1 0x80808080 #define gf_c2 0x7f7f7f7f #define gf_mulx(x) ((((x) & gf_c2) << 1) ^ ((((x) & gf_c1) >> 7) * BPOLY)) /* The following defines provide alternative definitions of gf_mulx that might give improved performance if a fast 32-bit multiply is not available. Note that a temporary variable u needs to be defined where gf_mulx is used. #define gf_mulx(x) (u = (x) & gf_c1, u |= (u >> 1), ((x) & gf_c2) << 1) ^ ((u >> 3) | (u >> 6)) #define gf_c4 (0x01010101 * BPOLY) #define gf_mulx(x) (u = (x) & gf_c1, ((x) & gf_c2) << 1) ^ ((u - (u >> 7)) & gf_c4) */ /* Work out which tables are needed for the different options */ #if defined( ASM_X86_V1C ) # if defined( ENC_ROUND ) # undef ENC_ROUND # endif # define ENC_ROUND FOUR_TABLES # if defined( LAST_ENC_ROUND ) # undef LAST_ENC_ROUND # endif # define LAST_ENC_ROUND FOUR_TABLES # if defined( DEC_ROUND ) # undef DEC_ROUND # endif # define DEC_ROUND FOUR_TABLES # if defined( LAST_DEC_ROUND ) # undef LAST_DEC_ROUND # endif # define LAST_DEC_ROUND FOUR_TABLES # if defined( KEY_SCHED ) # undef KEY_SCHED # define KEY_SCHED FOUR_TABLES # endif #endif #if ( FUNCS_IN_C & ENCRYPTION_IN_C ) || defined( ASM_X86_V1C ) # if ENC_ROUND == ONE_TABLE # define FT1_SET # elif ENC_ROUND == FOUR_TABLES # define FT4_SET # else # define SBX_SET # endif # if LAST_ENC_ROUND == ONE_TABLE # define FL1_SET # elif LAST_ENC_ROUND == FOUR_TABLES # define FL4_SET # elif !defined( SBX_SET ) # define SBX_SET # endif #endif #if ( FUNCS_IN_C & DECRYPTION_IN_C ) || defined( ASM_X86_V1C ) # if DEC_ROUND == ONE_TABLE # define IT1_SET # elif DEC_ROUND == FOUR_TABLES # define IT4_SET # else # define ISB_SET # endif # if LAST_DEC_ROUND == ONE_TABLE # define IL1_SET # elif LAST_DEC_ROUND == FOUR_TABLES # define IL4_SET # elif !defined(ISB_SET) # define ISB_SET # endif #endif #if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) # if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C)) # if KEY_SCHED == ONE_TABLE # if !defined( FL1_SET ) && !defined( FL4_SET ) # define LS1_SET # endif # elif KEY_SCHED == FOUR_TABLES # if !defined( FL4_SET ) # define LS4_SET # endif # elif !defined( SBX_SET ) # define SBX_SET # endif # endif # if (FUNCS_IN_C & DEC_KEYING_IN_C) # if KEY_SCHED == ONE_TABLE # define IM1_SET # elif KEY_SCHED == FOUR_TABLES # define IM4_SET # elif !defined( SBX_SET ) # define SBX_SET # endif # endif #endif /* generic definitions of Rijndael macros that use tables */ #define no_table(x,box,vf,rf,c) bytes2word( \ box[bval(vf(x,0,c),rf(0,c))], \ box[bval(vf(x,1,c),rf(1,c))], \ box[bval(vf(x,2,c),rf(2,c))], \ box[bval(vf(x,3,c),rf(3,c))]) #define one_table(x,op,tab,vf,rf,c) \ ( tab[bval(vf(x,0,c),rf(0,c))] \ ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \ ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \ ^ op(tab[bval(vf(x,3,c),rf(3,c))],3)) #define four_tables(x,tab,vf,rf,c) \ ( tab[0][bval(vf(x,0,c),rf(0,c))] \ ^ tab[1][bval(vf(x,1,c),rf(1,c))] \ ^ tab[2][bval(vf(x,2,c),rf(2,c))] \ ^ tab[3][bval(vf(x,3,c),rf(3,c))]) #define vf1(x,r,c) (x) #define rf1(r,c) (r) #define rf2(r,c) ((8+r-c)&3) /* perform forward and inverse column mix operation on four bytes in long word x in */ /* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */ #if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) #if defined( FM4_SET ) /* not currently used */ # define fwd_mcol(x) four_tables(x,t_use(f,m),vf1,rf1,0) #elif defined( FM1_SET ) /* not currently used */ # define fwd_mcol(x) one_table(x,upr,t_use(f,m),vf1,rf1,0) #else # define dec_fmvars uint32_t g2 # define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1)) #endif #if defined( IM4_SET ) # define inv_mcol(x) four_tables(x,t_use(i,m),vf1,rf1,0) #elif defined( IM1_SET ) # define inv_mcol(x) one_table(x,upr,t_use(i,m),vf1,rf1,0) #else # define dec_imvars uint32_t g2, g4, g9 # define inv_mcol(x) (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = (x) ^ gf_mulx(g4), g4 ^= g9, \ (x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1)) #endif #if defined( FL4_SET ) # define ls_box(x,c) four_tables(x,t_use(f,l),vf1,rf2,c) #elif defined( LS4_SET ) # define ls_box(x,c) four_tables(x,t_use(l,s),vf1,rf2,c) #elif defined( FL1_SET ) # define ls_box(x,c) one_table(x,upr,t_use(f,l),vf1,rf2,c) #elif defined( LS1_SET ) # define ls_box(x,c) one_table(x,upr,t_use(l,s),vf1,rf2,c) #else # define ls_box(x,c) no_table(x,t_use(s,box),vf1,rf2,c) #endif #endif #if defined( ASM_X86_V1C ) && defined( AES_DECRYPT ) && !defined( ISB_SET ) # define ISB_SET #endif #endif openzwave-1.6.1914/cpp/src/aes/aescpp.h0000644000175200017520000001156714032142455014477 00000000000000/* --------------------------------------------------------------------------- Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. The redistribution and use of this software (with or without changes) is allowed without the payment of fees or royalties provided that: source code distributions include the above copyright notice, this list of conditions and the following disclaimer; binary distributions include the above copyright notice, this list of conditions and the following disclaimer in their documentation. This software is provided 'as is' with no explicit or implied warranties in respect of its operation, including, but not limited to, correctness and fitness for purpose. --------------------------------------------------------------------------- Issue Date: 20/12/2007 This file contains the definitions required to use AES (Rijndael) in C++. */ #ifndef _AESCPP_H #define _AESCPP_H #include "aes.h" #if defined( AES_ENCRYPT ) class AESencrypt { public: aes_encrypt_ctx cx[1]; AESencrypt(void) { aes_init(); }; #if defined(AES_128) AESencrypt(const unsigned char key[]) { aes_encrypt_key128(key, cx); } AES_RETURN key128(const unsigned char key[]) { return aes_encrypt_key128(key, cx); } #endif #if defined(AES_192) AES_RETURN key192(const unsigned char key[]) { return aes_encrypt_key192(key, cx); } #endif #if defined(AES_256) AES_RETURN key256(const unsigned char key[]) { return aes_encrypt_key256(key, cx); } #endif #if defined(AES_VAR) AES_RETURN key(const unsigned char key[], int key_len) { return aes_encrypt_key(key, key_len, cx); } #endif AES_RETURN encrypt(const unsigned char in[], unsigned char out[]) const { return aes_encrypt(in, out, cx); } #ifndef AES_MODES AES_RETURN ecb_encrypt(const unsigned char in[], unsigned char out[], int nb) const { while(nb--) { aes_encrypt(in, out, cx), in += AES_BLOCK_SIZE, out += AES_BLOCK_SIZE; } } #endif #ifdef AES_MODES AES_RETURN mode_reset(void) { return aes_mode_reset(cx); } AES_RETURN ecb_encrypt(const unsigned char in[], unsigned char out[], int nb) const { return aes_ecb_encrypt(in, out, nb, cx); } AES_RETURN cbc_encrypt(const unsigned char in[], unsigned char out[], int nb, unsigned char iv[]) const { return aes_cbc_encrypt(in, out, nb, iv, cx); } AES_RETURN cfb_encrypt(const unsigned char in[], unsigned char out[], int nb, unsigned char iv[]) { return aes_cfb_encrypt(in, out, nb, iv, cx); } AES_RETURN cfb_decrypt(const unsigned char in[], unsigned char out[], int nb, unsigned char iv[]) { return aes_cfb_decrypt(in, out, nb, iv, cx); } AES_RETURN ofb_crypt(const unsigned char in[], unsigned char out[], int nb, unsigned char iv[]) { return aes_ofb_crypt(in, out, nb, iv, cx); } typedef void ctr_fn(unsigned char ctr[]); AES_RETURN ctr_crypt(const unsigned char in[], unsigned char out[], int nb, unsigned char iv[], ctr_fn cf) { return aes_ctr_crypt(in, out, nb, iv, cf, cx); } #endif }; #endif #if defined( AES_DECRYPT ) class AESdecrypt { public: aes_decrypt_ctx cx[1]; AESdecrypt(void) { aes_init(); }; #if defined(AES_128) AESdecrypt(const unsigned char key[]) { aes_decrypt_key128(key, cx); } AES_RETURN key128(const unsigned char key[]) { return aes_decrypt_key128(key, cx); } #endif #if defined(AES_192) AES_RETURN key192(const unsigned char key[]) { return aes_decrypt_key192(key, cx); } #endif #if defined(AES_256) AES_RETURN key256(const unsigned char key[]) { return aes_decrypt_key256(key, cx); } #endif #if defined(AES_VAR) AES_RETURN key(const unsigned char key[], int key_len) { return aes_decrypt_key(key, key_len, cx); } #endif AES_RETURN decrypt(const unsigned char in[], unsigned char out[]) const { return aes_decrypt(in, out, cx); } #ifndef AES_MODES AES_RETURN ecb_decrypt(const unsigned char in[], unsigned char out[], int nb) const { while(nb--) { aes_decrypt(in, out, cx), in += AES_BLOCK_SIZE, out += AES_BLOCK_SIZE; } } #endif #ifdef AES_MODES AES_RETURN ecb_decrypt(const unsigned char in[], unsigned char out[], int nb) const { return aes_ecb_decrypt(in, out, nb, cx); } AES_RETURN cbc_decrypt(const unsigned char in[], unsigned char out[], int nb, unsigned char iv[]) const { return aes_cbc_decrypt(in, out, nb, iv, cx); } #endif }; #endif #endif openzwave-1.6.1914/cpp/src/Localization.h0000755000175200017520000001332314032142455015077 00000000000000//----------------------------------------------------------------------------- // // Localization.h // // Localization for CC and Value Classes // // Copyright (c) 2018 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef VALUEHELP_H #define VALUEHELP_H #include #include #include #include "Defs.h" #include "Driver.h" #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { class LabelLocalizationEntry: public Internal::Platform::Ref { public: LabelLocalizationEntry(uint16 _index, uint32 _pos = -1); ~LabelLocalizationEntry() { } void AddLabel(string label, string lang = ""); string GetLabel(string lang); uint64 GetIdx(); bool HasLabel(string lang); private: uint16 m_index; uint32 m_pos; map m_Label; string m_defaultLabel; }; class ValueLocalizationEntry: public Internal::Platform::Ref { public: ValueLocalizationEntry(uint8 _commandClass, uint16 _index, uint32 _pos = -1); ~ValueLocalizationEntry() { } uint64 GetIdx(); string GetHelp(string lang); void AddHelp(string HelpText, string lang = ""); bool HasHelp(string lang); string GetLabel(string lang); void AddLabel(string Label, string lang = ""); bool HasLabel(string lang); void AddItemLabel(string label, int32 itemIndex, string lang = ""); string GetItemLabel(string lang, int32 itemIndex); bool HasItemLabel(int32 itemIndex, string lang); void AddItemHelp(string label, int32 itemIndex, string lang = ""); string GetItemHelp(string lang, int32 itemIndex); bool HasItemHelp(int32 itemIndex, string lang); private: uint8 m_commandClass; uint16 m_index; uint32 m_pos; map m_HelpText; map m_LabelText; map > m_ItemLabelText; map > m_ItemHelpText; string m_DefaultHelpText; string m_DefaultLabelText; map m_DefaultItemLabelText; map m_DefaultItemHelpText; }; class Localization { //----------------------------------------------------------------------------- // Construction //----------------------------------------------------------------------------- private: Localization(); ~Localization(); static bool ReadXML(); static void ReadCCXMLLabel(uint8 ccID, const TiXmlElement *labelElement); static void ReadXMLValue(uint8 node, uint8 ccID, const TiXmlElement *valueElement); static void ReadXMLVIDItemLabel(uint8 node, uint8 ccID, uint16 indexId, uint32 pos, const TiXmlElement *labelElement); static void ReadGlobalXMLLabel(const TiXmlElement *labelElement); static uint64 GetValueKey(uint8 _node, uint8 _commandClass, uint16 _index, uint32 _pos, bool unique = false); public: static Localization* Get(); void SetupCommandClass(Internal::CC::CommandClass *cc); string GetSelectedLang() { return Localization::m_selectedLang; } ; bool SetValueHelp(uint8 node, uint8 ccID, uint16 indexID, uint32 pos, string help, string lang = ""); string const GetValueHelp(uint8 node, uint8 ccID, uint16 indexId, uint32 pos); bool SetValueLabel(uint8 node, uint8 ccID, uint16 indexID, uint32 pos, string label, string lang = ""); string const GetValueLabel(uint8 node, uint8 ccID, uint16 indexId, int32 pos) const; string const GetValueItemLabel(uint8 node, uint8 ccID, uint16 indexId, int32 pos, int32 itemIndex) const; bool SetValueItemLabel(uint8 node, uint8 ccID, uint16 indexId, int32 pos, int32 itemIndex, string label, string lang = ""); string const GetValueItemHelp(uint8 node, uint8 ccID, uint16 indexId, int32 pos, int32 itemIndex) const; bool SetValueItemHelp(uint8 node, uint8 ccID, uint16 indexId, int32 pos, int32 itemIndex, string label, string lang = ""); string const GetGlobalLabel(string text); bool SetGlobalLabel(string index, string text, string lang); static void ReadXMLVIDLabel(uint8 node, uint8 ccID, uint16 indexId, uint32 pos, const TiXmlElement *labelElement); static void ReadXMLVIDHelp(uint8 node, uint8 ccID, uint16 indexId, uint32 pos, const TiXmlElement *helpElement); bool WriteXMLVIDHelp(uint8 node, uint8 ccID, uint16 indexId, uint32 pos, TiXmlElement *valueElement); //----------------------------------------------------------------------------- // Instance Functions //----------------------------------------------------------------------------- private: static Localization* m_instance; static map > m_valueLocalizationMap; static map > m_commandClassLocalizationMap; static map > m_globalLabelLocalizationMap; static string m_selectedLang; static uint32 m_revision; }; } // namespace Internal } // namespace OpenZWave #endif // VALUEHELP_H openzwave-1.6.1914/cpp/src/DNSThread.cpp0000644000175200017520000000714014032142455014553 00000000000000//----------------------------------------------------------------------------- // // DNSThread.h // // Async DNS Lookups // // Copyright (c) 2016 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "DNSThread.h" #include "Utils.h" #include "Driver.h" namespace OpenZWave { namespace Internal { DNSThread::DNSThread(Driver *driver) : m_driver(driver), m_dnsMutex(new Internal::Platform::Mutex()), m_dnsRequestEvent(new Internal::Platform::Event()) { } DNSThread::~DNSThread() { m_dnsMutex->Release(); m_dnsRequestEvent->Release(); } void DNSThread::DNSThreadEntryPoint(Internal::Platform::Event* _exitEvent, void* _context) { DNSThread* dns = (DNSThread*) _context; if (dns) { dns->DNSThreadProc(_exitEvent); } } void DNSThread::DNSThreadProc(Internal::Platform::Event* _exitEvent) { Log::Write(LogLevel_Info, "Starting DNSThread"); while (true) { // DNSThread has been initialized const uint32 count = 2; Internal::Platform::Wait* waitObjects[count]; int32 timeout = Internal::Platform::Wait::Timeout_Infinite; // timeout = 5000; waitObjects[0] = _exitEvent; // Thread must exit. waitObjects[1] = m_dnsRequestEvent; // DNS Request // Wait for something to do int32 res = Internal::Platform::Wait::Multiple(waitObjects, count, timeout); switch (res) { case -1: /* timeout */ Log::Write(LogLevel_Warning, "DNSThread Timeout..."); break; case 0: /* exitEvent */ Log::Write(LogLevel_Info, "Stopping DNSThread"); return; case 1: /* dnsEvent */ processResult(); break; } } } bool DNSThread::sendRequest(DNSLookup *lookup) { Log::Write(LogLevel_Info, lookup->NodeID, "Queuing Lookup on %s for Node %d", lookup->lookup.c_str(), lookup->NodeID); LockGuard LG(m_dnsMutex); m_dnslist.push_back(lookup); m_dnsRequestEvent->Set(); return true; } void DNSThread::processResult() { string result; Internal::DNSLookup *lookup; { LockGuard LG(m_dnsMutex); lookup = m_dnslist.front(); m_dnslist.pop_front(); if (m_dnslist.empty()) m_dnsRequestEvent->Reset(); } Log::Write(LogLevel_Info, "LookupTxT Checking %s", lookup->lookup.c_str()); if (!m_dnsresolver.LookupTxT(lookup->lookup, lookup->result)) { Log::Write(LogLevel_Warning, "Lookup on %s Failed", lookup->lookup.c_str()); } else { Log::Write(LogLevel_Info, "Lookup for %s returned %s", lookup->lookup.c_str(), lookup->result.c_str()); } lookup->status = m_dnsresolver.status; /* send the response back to the Driver for processing */ Driver::EventMsg *event = new Driver::EventMsg(); event->type = Driver::EventMsg::Event_DNS; event->event.lookup = lookup; this->m_driver->SubmitEventMsg(event); } } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/Bitfield.h0000644000175200017520000000407714032142455014174 00000000000000//----------------------------------------------------------------------------- // // Bitfield.h // // Variable length bitfield implementation // // Copyright (c) 2011 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Bitfield_H #define _Bitfield_H #include #include "Defs.h" namespace OpenZWave { namespace Internal { class OPENZWAVE_EXPORT Bitfield { friend class Iterator; public: Bitfield(); Bitfield(uint32 value); ~Bitfield(); bool Set(uint8 _idx); bool Clear(uint8 _idx); bool IsSet(uint8 _idx) const; uint32 GetNumSetBits() const; uint32 GetValue() const; bool SetValue(uint32 val); uint32 GetSize() const; class Iterator { friend class Bitfield; public: uint32 operator *() const; Iterator& operator++(); Iterator operator++(int); bool operator ==(const Iterator &rhs); bool operator !=(const Iterator &rhs); private: Iterator(Bitfield const* _bitfield, uint32 _idx); void NextSetBit(); uint32 m_idx; Bitfield const* m_bitfield; }; Iterator Begin() const; Iterator End() const; private: vector m_bits; uint32 m_numSetBits; uint32 m_value; }; } // namespace OpenZWave } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/vers.cpp0000644000175200017520000000024114032142711013744 00000000000000#include "Defs.h" uint16_t ozw_vers_major = 1; uint16_t ozw_vers_minor = 6; uint16_t ozw_vers_revision = 1914; char ozw_version_string[] = "1.6-1914-g99f10b5f"; openzwave-1.6.1914/cpp/src/Notification.cpp0000644000175200017520000002452114032142455015427 00000000000000//----------------------------------------------------------------------------- // // Notification.cpp // // OZW to Application Notification Callbacks // // Copyright (c) 2015 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "Notification.h" #include "Driver.h" #include "command_classes/CommandClasses.h" using namespace OpenZWave; //----------------------------------------------------------------------------- // // Return a string representation of OZW //----------------------------------------------------------------------------- string Notification::GetAsString() const { string str; string command; switch (m_type) { case Type_ValueAdded: { str = "ValueAdded "; std::stringstream ss; ss << "CC: " << Internal::CC::CommandClasses::GetName(GetValueID().GetCommandClassId()) << " Instance: " << (int)GetValueID().GetInstance() << " Index: " << std::dec << GetValueID().GetIndex(); str += ss.str(); break; } case Type_ValueRemoved: { str = "ValueRemoved "; std::stringstream ss; ss << "CC: " << Internal::CC::CommandClasses::GetName(GetValueID().GetCommandClassId()) << " Instance: " << (int)GetValueID().GetInstance() << " Index: " << std::dec << GetValueID().GetIndex(); str += ss.str(); break; } case Type_ValueChanged: { str = "ValueChanged "; std::stringstream ss; ss << "CC: " << Internal::CC::CommandClasses::GetName(GetValueID().GetCommandClassId()) << " Instance: " << (int)GetValueID().GetInstance() << " Index: " << std::dec << GetValueID().GetIndex(); str += ss.str(); break; } case Type_ValueRefreshed: { str = "ValueRefreshed "; std::stringstream ss; ss << "CC: " << Internal::CC::CommandClasses::GetName(GetValueID().GetCommandClassId()) << " Instance: " << (int)GetValueID().GetInstance() << " Index: " << std::dec << GetValueID().GetIndex(); str += ss.str(); break; } case Type_Group: str = "Group"; break; case Type_NodeNew: str = "NodeNew"; break; case Type_NodeAdded: str = "NodeAdded"; break; case Type_NodeRemoved: str = "NodeRemoved"; break; case Type_NodeProtocolInfo: str = "NodeProtocolInfo"; break; case Type_NodeNaming: str = "NodeNaming"; break; case Type_NodeEvent: str = "NodeEvent"; break; case Type_PollingDisabled: str = "PollingDisabled"; break; case Type_PollingEnabled: str = "PollingEnabled"; break; case Type_SceneEvent: str = "SceneEvent"; break; case Type_CreateButton: str = "CreateButton"; break; case Type_DeleteButton: str = "DeleteButton"; break; case Type_ButtonOn: str = "ButtonOn"; break; case Type_ButtonOff: str = "ButtonOff"; break; case Type_DriverReady: str = "DriverReady"; break; case Type_DriverFailed: str = "DriverFailed: " + m_comport; break; case Type_DriverReset: str = "DriverReset"; break; case Type_EssentialNodeQueriesComplete: str = "EssentialNodeQueriesComplete"; break; case Type_NodeQueriesComplete: str = "NodeQueriesComplete"; break; case Type_AwakeNodesQueried: str = "AwakeNodesQueried"; break; case Type_AllNodesQueriedSomeDead: str = "AllNodesQueriedSomeDead"; break; case Type_AllNodesQueried: str = "AllNodesQueried"; break; case Type_Notification: switch (m_byte) { case Code_MsgComplete: str = "Notification - MsgComplete"; break; case Code_Timeout: str = "Notification - TimeOut"; break; case Code_NoOperation: str = "Notification - NoOperation"; break; case Code_Awake: str = "Notification - Node Awake"; break; case Code_Sleep: str = "Notification - Node Asleep"; break; case Code_Dead: str = "Notification - Node Dead"; break; case Code_Alive: str = "Notification - Node Alive"; break; } break; case Type_DriverRemoved: str = "DriverRemoved"; break; case Type_ControllerCommand: switch (m_command) { case Driver::ControllerCommand_AddDevice: command = "AddDevice "; break; case Driver::ControllerCommand_AssignReturnRoute: command = "AssignReturnRoute "; break; case Driver::ControllerCommand_CreateButton: command = "CreateButton "; break; case Driver::ControllerCommand_CreateNewPrimary: command = "CreateNewPrimary "; break; case Driver::ControllerCommand_DeleteAllReturnRoutes: command = "DeleteAllReturnRoutes "; break; case Driver::ControllerCommand_DeleteButton: command = "DeleteButton "; break; case Driver::ControllerCommand_HasNodeFailed: command = "HasNodeFailed "; break; case Driver::ControllerCommand_ReceiveConfiguration: command = "ReceiveConfiguration "; break; case Driver::ControllerCommand_RemoveDevice: command = "RemoveDevice "; break; case Driver::ControllerCommand_RemoveFailedNode: command = "RemoveFailedNode "; break; case Driver::ControllerCommand_ReplaceFailedNode: command = "ReplaceFailedNode "; break; case Driver::ControllerCommand_ReplicationSend: command = "ReplicationSend "; break; case Driver::ControllerCommand_RequestNetworkUpdate: command = "RequestNetworkUpdate "; break; case Driver::ControllerCommand_RequestNodeNeighborUpdate: command = "RequestNodeNeighborUpdate "; break; case Driver::ControllerCommand_SendNodeInformation: command = "SendNodeInformation "; break; case Driver::ControllerCommand_TransferPrimaryRole: command = "TransferPrimaryRole "; break; } switch (m_event) { case Driver::ControllerState_Normal: str = command + "ControllerCommand - Normal"; break; case Driver::ControllerState_Starting: str = command + "ControllerCommand - Starting"; break; case Driver::ControllerState_Cancel: str = command + "ControllerCommand - Canceled"; break; case Driver::ControllerState_Error: switch (m_byte) { case Driver::ControllerError_None: str = "ControllerCommand - Error - None"; break; case Driver::ControllerError_ButtonNotFound: str = "ControllerCommand - Error - ButtonNotFound"; break; case Driver::ControllerError_NodeNotFound: str = "ControllerCommand - Error - NodeNotFound"; break; case Driver::ControllerError_NotBridge: str = "ControllerCommand - Error - NotBridge"; break; case Driver::ControllerError_NotSUC: str = "ControllerCommand - Error - NotSUC"; break; case Driver::ControllerError_NotSecondary: str = "ControllerCommand - Error - NotSecondary"; break; case Driver::ControllerError_NotPrimary: str = "ControllerCommand - Error - NotPrimary"; break; case Driver::ControllerError_IsPrimary: str = "ControllerCommand - Error - IsPrimary"; break; case Driver::ControllerError_NotFound: str = "ControllerCommand - Error - NotFound"; break; case Driver::ControllerError_Busy: str = "ControllerCommand - Error - Busy"; break; case Driver::ControllerError_Failed: str = "ControllerCommand - Error - Failed"; break; case Driver::ControllerError_Disabled: str = "ControllerCommand - Error - Disabled"; break; case Driver::ControllerError_Overflow: str = "ControllerCommand - Error - OverFlow"; break; } break; case Driver::ControllerState_Waiting: str = command + "ControllerCommand - Waiting"; break; case Driver::ControllerState_Sleeping: str = command + "ControllerCommand - Sleeping"; break; case Driver::ControllerState_InProgress: str = command + "ControllerCommand - InProgress"; break; case Driver::ControllerState_Completed: str = command + "ControllerCommand - Completed"; break; case Driver::ControllerState_Failed: str = command + "ControllerCommand - Failed"; break; case Driver::ControllerState_NodeOK: str = command + "ControllerCommand - NodeOK"; break; case Driver::ControllerState_NodeFailed: str = command + "ControllerCommand - NodeFailed"; break; } break; case Type_NodeReset: str = "Node Reset"; break; case Type_UserAlerts: switch (m_useralerttype) { case Alert_None: str = "User Alert - No Alert"; break; case Alert_ConfigOutOfDate: str = "User Alert - Config File out of Date"; break; case Alert_MFSOutOfDate: str = "User Alert - Manufacturer_specific.xml out of Date"; break; case Alert_ConfigFileDownloadFailed: str = "A Config File Failed to download"; break; case Alert_DNSError: str = "A DNS Error Occurred"; break; case Alert_NodeReloadRequired: str = "Node Reload Is Required due to new Config File"; break; case Alert_UnsupportedController: str = "Controller Library is not a type we support"; break; case Alert_ApplicationStatus_Retry: str = "Application Status: Retry Later"; break; case Alert_ApplicationStatus_Queued: str = "Application Status: Command has been queued for execution later"; break; case Alert_ApplicationStatus_Rejected: str = "Application Status: Command Rejected"; } break; case Type_ManufacturerSpecificDBReady: str = "ManufacturerSpecificDB Ready"; break; } return str; } std::ostream& operator<<(std::ostream &os, const Notification &dt) { os << dt.GetAsString(); return os; } std::ostream& operator<<(std::ostream &os, const Notification *dt) { os << dt->GetAsString(); return os; } openzwave-1.6.1914/cpp/src/Utils.cpp0000644000175200017520000001252514032142455014102 00000000000000//----------------------------------------------------------------------------- // // Utils.h // // Miscellaneous helper functions // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "Utils.h" #include namespace OpenZWave { namespace Internal { //----------------------------------------------------------------------------- // // Convert a string to all upper-case. //----------------------------------------------------------------------------- std::string ToUpper(std::string const& _str) { std::string upper = _str; transform(upper.begin(), upper.end(), upper.begin(), ::toupper); return upper; } //----------------------------------------------------------------------------- // // Convert a string to all lower-case. //----------------------------------------------------------------------------- std::string ToLower(std::string const& _str) { std::string lower = _str; transform(lower.begin(), lower.end(), lower.begin(), ::tolower); return lower; } //----------------------------------------------------------------------------- // // Remove WhiteSpaces from the begining and end of a string //----------------------------------------------------------------------------- std::string &removewhitespace(std::string &s) { if (s.size() == 0) { return s; } int val = 0; for (size_t cur = 0; cur < s.size(); cur++) { if (s[cur] != ' ' && isalnum(s[cur])) { s[val] = s[cur]; val++; } } s.resize(val); return s; } std::string& ltrim(std::string& s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char c) { return isgraph(c);})); return s; } std::string& rtrim(std::string& s) { s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char c) { return isgraph(c);}).base(), s.end()); return s; } std::string& trim(std::string& s) { return Internal::ltrim(Internal::rtrim(s)); } //----------------------------------------------------------------------------- // // Split a String into a vector, seperated by anything specified in seperators. //----------------------------------------------------------------------------- void split(std::vector& lst, const std::string& input, const std::string& separators, bool remove_empty) { std::ostringstream word; for (size_t n = 0; n < input.size(); ++n) { if (std::string::npos == separators.find(input[n])) word << input[n]; else { if (!word.str().empty() || !remove_empty) lst.push_back(word.str()); word.str(""); } } if (!word.str().empty() || !remove_empty) lst.push_back(word.str()); } void PrintHex(std::string prefix, uint8_t const *data, uint32 const length) { Log::Write(LogLevel_Info, "%s: %s", prefix.c_str(), PktToString(data, length).c_str()); } string PktToString(uint8 const *data, uint32 const length) { char byteStr[5]; std::string str; for (uint32 i = 0; i < length; ++i) { if (i) { str += ", "; } snprintf(byteStr, sizeof(byteStr), "0x%.2x", data[i]); str += byteStr; } return str; } static const char* separators() { #if __unix__ return "/"; #else // __unix__ return "\\/"; #endif // __unix__ } string ozwdirname(string m_path) { const size_t lastSlash = m_path.find_last_of(separators()); if (lastSlash == std::string::npos) return ""; return m_path.substr(0, lastSlash); } string intToString(int x) { #if __cplusplus==201103L || __APPLE__ return to_string(x); #else return static_cast< std::ostringstream & >( ( std::ostringstream() << std::dec << x ) ).str(); #endif } const char* rssi_to_string(uint8 _data) { static char buf[8]; switch (_data) { case 127: { return "---"; break; } case 126: { return "MAX"; break; } case 125: { return "MIN"; break; } default: if (_data >= 11 && _data <= 124) { return "UNK"; } else { snprintf(buf, 5, "%4d", (unsigned int) _data - 256); return buf; } } } } // namespace Internal } // namespace OpenZWave #if (defined _WINDOWS || defined WIN32 || defined _MSC_VER) && (!defined MINGW && !defined __MINGW32__ && !defined __MINGW64__) /* Windows doesn't have localtime_r - use the "secure" version instead */ struct tm *localtime_r(const time_t *_clock, struct tm *_result) { _localtime64_s(_result, _clock); return _result; } #endif openzwave-1.6.1914/cpp/src/TimerThread.cpp0000644000175200017520000002356214032142455015215 00000000000000//----------------------------------------------------------------------------- // // TimerThread.cpp // // Timer for scheduling future events // // Copyright (c) 2017 h3ctrl // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "TimerThread.h" #include "Utils.h" #include "platform/Log.h" #include "Driver.h" namespace OpenZWave { namespace Internal { //----------------------------------------------------------------------------- // // Main entry point for the timer thread. //----------------------------------------------------------------------------- void TimerThread::TimerThreadEntryPoint(Internal::Platform::Event* _exitEvent, void* _context) { TimerThread* timer = (TimerThread*) _context; if (timer) { timer->TimerThreadProc(_exitEvent); } } //----------------------------------------------------------------------------- // // Constructor. //----------------------------------------------------------------------------- TimerThread::TimerThread(Driver *_driver) : //m_driver( _driver ), m_timerEvent(new Internal::Platform::Event()), m_timerMutex(new Internal::Platform::Mutex()), m_timerTimeout(Internal::Platform::Wait::Timeout_Infinite) { } //----------------------------------------------------------------------------- // // Destructor. //----------------------------------------------------------------------------- TimerThread::~TimerThread() { { LockGuard LG(m_timerMutex); for (list::iterator it = m_timerEventList.begin(); it != m_timerEventList.end(); ++it) { delete (*it); } } m_timerMutex->Release(); m_timerEvent->Release(); } //----------------------------------------------------------------------------- // // Thread for timer based actions //----------------------------------------------------------------------------- void TimerThread::TimerThreadProc(Internal::Platform::Event* _exitEvent) { Log::Write(LogLevel_Info, "Timer: thread starting"); Internal::Platform::Wait* waitObjects[2]; waitObjects[0] = _exitEvent; waitObjects[1] = m_timerEvent; uint32 count = 2; // Initially no timer events so infinite timeout. m_timerTimeout = Internal::Platform::Wait::Timeout_Infinite; while (1) { Log::Write(LogLevel_Detail, "Timer: waiting with timeout %d ms", m_timerTimeout); int32 res = Internal::Platform::Wait::Multiple(waitObjects, count, m_timerTimeout); if (res == 0) { // Exit has been signalled return; } else { // Timeout or new entry to timer list. m_timerTimeout = Internal::Platform::Wait::Timeout_Infinite; // Go through all waiting actions, and see if any need to be performed. LockGuard LG(m_timerMutex); list::iterator it = m_timerEventList.begin(); while (it != m_timerEventList.end()) { int32 tr = (*it)->timestamp.TimeRemaining(); if (tr <= 0) { // Expired so perform action and remove from list. Log::Write(LogLevel_Info, "Timer: delayed event"); TimerEventEntry *te = *(it++); te->instance->TimerFireEvent(te); } else { // Time remaining. m_timerTimeout = (m_timerTimeout == Internal::Platform::Wait::Timeout_Infinite) ? tr : std::min(m_timerTimeout, tr); ++it; } } m_timerEvent->Reset(); } } // while( 1 ) } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- TimerThread::TimerEventEntry* TimerThread::TimerSetEvent(int32 _milliseconds, TimerCallback _callback, Timer *_instance, uint32 id) { Log::Write(LogLevel_Info, "Timer: adding event in %d ms", _milliseconds); TimerEventEntry *te = new TimerEventEntry(); te->timestamp.SetTime(_milliseconds); te->callback = _callback; te->instance = _instance; te->id = id; // Don't want driver thread and timer thread accessing list at the same time. LockGuard LG(m_timerMutex); m_timerEventList.push_back(te); m_timerEvent->Set(); return te; } //----------------------------------------------------------------------------- // // Delete the Specific Timer //----------------------------------------------------------------------------- void TimerThread::TimerDelEvent(TimerEventEntry *te) { LockGuard LG(m_timerMutex); list::iterator it = find(m_timerEventList.begin(), m_timerEventList.end(), te); if (it != m_timerEventList.end()) { delete ((*it)); m_timerEventList.erase(it); } else { Log::Write(LogLevel_Warning, "Cant Find TimerEvent to Delete in TimerDelEvent"); } } //----------------------------------------------------------------------------- // // Constuctor for Timer SubClass with Driver passed in //----------------------------------------------------------------------------- Timer::Timer(Driver *_driver) : m_driver(_driver) { } ; //----------------------------------------------------------------------------- // // Default Constuctor for Timer SubClass //----------------------------------------------------------------------------- Timer::Timer() : m_driver(NULL) { } ; //----------------------------------------------------------------------------- // // Deconstuctor for Timer SubClass //----------------------------------------------------------------------------- Timer::~Timer() { TimerDelEvents(); } //----------------------------------------------------------------------------- // // Create a new TimerCallback //----------------------------------------------------------------------------- TimerThread::TimerEventEntry* Timer::TimerSetEvent(int32 _milliseconds, TimerThread::TimerCallback _callback, uint32 id) { if (m_driver) { TimerThread::TimerEventEntry *te = m_driver->GetTimer()->TimerSetEvent(_milliseconds, _callback, this, id); if (te) { m_timerEventList.push_back(te); return te; } Log::Write(LogLevel_Warning, "Could Not Register Timer Callback"); return NULL; } else { Log::Write(LogLevel_Warning, "Driver Not Set for TimerThread"); return NULL; } } //----------------------------------------------------------------------------- // // Delete all TimerEvents associated with this instance //----------------------------------------------------------------------------- void Timer::TimerDelEvents() { if (m_driver) { list::iterator it = m_timerEventList.begin(); while (it != m_timerEventList.end()) { m_driver->GetTimer()->TimerDelEvent((*it)); it = m_timerEventList.erase(it); } } else { Log::Write(LogLevel_Warning, "Driver Not Set for Timer"); } } //----------------------------------------------------------------------------- // // Associate this instance with a Driver //----------------------------------------------------------------------------- void Timer::SetDriver(Driver *_driver) { m_driver = _driver; } //----------------------------------------------------------------------------- // // Delete a specific TimerEvent //----------------------------------------------------------------------------- void Timer::TimerDelEvent(TimerThread::TimerEventEntry *te) { if (m_driver) { list::iterator it = find(m_timerEventList.begin(), m_timerEventList.end(), te); if (it != m_timerEventList.end()) { m_driver->GetTimer()->TimerDelEvent((*it)); m_timerEventList.erase(it); } else { Log::Write(LogLevel_Warning, "Cant Find TimerEvent to Delete in TimerDelEvent"); } } else { Log::Write(LogLevel_Warning, "Driver Not Set for Timer"); return; } } //----------------------------------------------------------------------------- // // Delete a specific TimerEvent //----------------------------------------------------------------------------- void Timer::TimerDelEvent(uint32 id) { if (m_driver) { for (list::iterator it = m_timerEventList.begin(); it != m_timerEventList.end(); it++) { if ((*it)->id == id) { m_driver->GetTimer()->TimerDelEvent((*it)); m_timerEventList.erase(it); return; } } Log::Write(LogLevel_Warning, "Cant Find TimerEvent %d to Delete in TimerDelEvent", id); return; } else { Log::Write(LogLevel_Warning, "Driver Not Set for TimerThread"); return; } } //----------------------------------------------------------------------------- // // Execute a Callback //----------------------------------------------------------------------------- void Timer::TimerFireEvent(TimerThread::TimerEventEntry *te) { te->callback(te->id); TimerDelEvent(te); } } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/Scene.h0000644000175200017520000000657514032142455013514 00000000000000//----------------------------------------------------------------------------- // // Scene.h // // A collection of ValueIDs to be used together. // // Copyright (c) 2011 Greg Satz // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Scene_H #define _Scene_H #include #include #include "Defs.h" class TiXmlElement; namespace OpenZWave { namespace Internal { /** \brief Collection of ValueIDs to be treated as a unit. */ class Scene { friend class OpenZWave::Manager; friend class OpenZWave::Driver; friend class OpenZWave::Node; //----------------------------------------------------------------------------- // Construction //----------------------------------------------------------------------------- private: Scene(uint8 const _sceneId); ~Scene(); static void WriteXML(string const& _name); static bool ReadScenes(); //----------------------------------------------------------------------------- // Scene functions //----------------------------------------------------------------------------- private: static Scene* Get(uint8 const _sceneId); static uint8 GetAllScenes(uint8** _sceneIds); string const& GetLabel() const { return m_label; } void SetLabel(string const &_label) { m_label = _label; } bool AddValue(ValueID const& _valueId, string const& _value); bool RemoveValue(ValueID const& _valueId); void RemoveValues(uint32 const _homeId); static void RemoveValues(uint32 const _homeId, uint8 const _nodeId); int GetValues(vector* o_value); bool GetValue(ValueID const& _valueId, string* o_value); bool SetValue(ValueID const& _valueId, string const& _value); bool Activate(); //----------------------------------------------------------------------------- // ValueID/value storage //----------------------------------------------------------------------------- private: class SceneStorage { public: SceneStorage(ValueID const& _id, string const& _value) : m_id(_id), m_value(_value) { } ; ~SceneStorage() { } ; ValueID const m_id; string m_value; }; //----------------------------------------------------------------------------- // Member variables //----------------------------------------------------------------------------- private: uint8 m_sceneId; string m_label; vector m_values; static uint8 s_sceneCnt; static Scene* s_scenes[256]; }; } // namespace Internal } //namespace OpenZWave #endif //_Scene_H openzwave-1.6.1914/cpp/src/Notification.h0000644000175200017520000003501114032142455015070 00000000000000//----------------------------------------------------------------------------- // // Notification.h // // Contains details of a Z-Wave event reported to the user // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Notification_H #define _Notification_H #include #include "Defs.h" #include "value_classes/ValueID.h" namespace OpenZWave { namespace Internal { namespace CC { class ApplicationStatus; class Basic; class ManufacturerSpecific; class NodeNaming; class SceneActivation; class WakeUp; } namespace VC { class Value; class ValueStore; } class ManufacturerSpecificDB; } /** \brief Provides a container for data sent via the notification callback * handler installed by a call to Manager::AddWatcher. * * A notification object is only ever created or deleted internally by * OpenZWave. */ class OPENZWAVE_EXPORT Notification { friend class Manager; friend class Driver; friend class Node; friend class Group; friend class Internal::VC::Value; friend class Internal::VC::ValueStore; friend class Internal::CC::Basic; friend class Internal::CC::ManufacturerSpecific; friend class Internal::CC::NodeNaming; friend class Internal::CC::SceneActivation; friend class Internal::CC::WakeUp; friend class Internal::CC::ApplicationStatus; friend class Internal::ManufacturerSpecificDB; /* allow us to Stream a Notification */ //friend std::ostream &operator<<(std::ostream &os, const Notification &dt); public: /** * Notification types. * Notifications of various Z-Wave events sent to the watchers * registered with the Manager::AddWatcher method. * \see Manager::AddWatcher * \see Manager::BeginControllerCommand */ enum NotificationType { Type_ValueAdded = 0, /**< A new node value has been added to OpenZWave's list. These notifications occur after a node has been discovered, and details of its command classes have been received. Each command class may generate one or more values depending on the complexity of the item being represented. */ Type_ValueRemoved, /**< A node value has been removed from OpenZWave's list. This only occurs when a node is removed. */ Type_ValueChanged, /**< A node value has been updated from the Z-Wave network and it is different from the previous value. */ Type_ValueRefreshed, /**< A node value has been updated from the Z-Wave network. */ Type_Group, /**< The associations for the node have changed. The application should rebuild any group information it holds about the node. */ Type_NodeNew, /**< A new node has been found (not already stored in zwcfg*.xml file) */ Type_NodeAdded, /**< A new node has been added to OpenZWave's list. This may be due to a device being added to the Z-Wave network, or because the application is initializing itself. */ Type_NodeRemoved, /**< A node has been removed from OpenZWave's list. This may be due to a device being removed from the Z-Wave network, or because the application is closing. */ Type_NodeProtocolInfo, /**< Basic node information has been received, such as whether the node is a listening device, a routing device and its baud rate and basic, generic and specific types. It is after this notification that you can call Manager::GetNodeType to obtain a label containing the device description. */ Type_NodeNaming, /**< One of the node names has changed (name, manufacturer, product). */ Type_NodeEvent, /**< A node has triggered an event. This is commonly caused when a node sends a Basic_Set command to the controller. The event value is stored in the notification. */ Type_PollingDisabled, /**< Polling of a node has been successfully turned off by a call to Manager::DisablePoll */ Type_PollingEnabled, /**< Polling of a node has been successfully turned on by a call to Manager::EnablePoll */ Type_SceneEvent, /**< Scene Activation Set received (Depreciated in 1.8) */ Type_CreateButton, /**< Handheld controller button event created */ Type_DeleteButton, /**< Handheld controller button event deleted */ Type_ButtonOn, /**< Handheld controller button on pressed event */ Type_ButtonOff, /**< Handheld controller button off pressed event */ Type_DriverReady, /**< A driver for a PC Z-Wave controller has been added and is ready to use. The notification will contain the controller's Home ID, which is needed to call most of the Manager methods. */ Type_DriverFailed, /**< Driver failed to load */ Type_DriverReset, /**< All nodes and values for this driver have been removed. This is sent instead of potentially hundreds of individual node and value notifications. */ Type_EssentialNodeQueriesComplete, /**< The queries on a node that are essential to its operation have been completed. The node can now handle incoming messages. */ Type_NodeQueriesComplete, /**< All the initialization queries on a node have been completed. */ Type_AwakeNodesQueried, /**< All awake nodes have been queried, so client application can expected complete data for these nodes. */ Type_AllNodesQueriedSomeDead, /**< All nodes have been queried but some dead nodes found. */ Type_AllNodesQueried, /**< All nodes have been queried, so client application can expected complete data. */ Type_Notification, /**< An error has occurred that we need to report. */ Type_DriverRemoved, /**< The Driver is being removed. (either due to Error or by request) Do Not Call Any Driver Related Methods after receiving this call */ Type_ControllerCommand, /**< When Controller Commands are executed, Notifications of Success/Failure etc are communicated via this Notification * Notification::GetEvent returns Driver::ControllerCommand and Notification::GetNotification returns Driver::ControllerState */ Type_NodeReset, /**< The Device has been reset and thus removed from the NodeList in OZW */ Type_UserAlerts, /**< Warnings and Notifications Generated by the library that should be displayed to the user (eg, out of date config files) */ Type_ManufacturerSpecificDBReady /**< The ManufacturerSpecific Database Is Ready */ }; /** * Notification codes. * Notifications of the type Type_Notification convey some * extra information defined here. */ enum NotificationCode { Code_MsgComplete = 0, /**< Completed messages */ Code_Timeout, /**< Messages that timeout will send a Notification with this code. */ Code_NoOperation, /**< Report on NoOperation message sent completion */ Code_Awake, /**< Report when a sleeping node wakes up */ Code_Sleep, /**< Report when a node goes to sleep */ Code_Dead, /**< Report when a node is presumed dead */ Code_Alive /**< Report when a node is revived */ }; /** * User Alert Types - These are messages that should be displayed to users to inform them of * potential issues such as Out of Date configuration files etc */ enum UserAlertNotification { Alert_None, /**< No Alert Currently Present */ Alert_ConfigOutOfDate, /**< One of the Config Files is out of date. Use GetNodeId to determine which node is effected. */ Alert_MFSOutOfDate, /**< the manufacturer_specific.xml file is out of date. */ Alert_ConfigFileDownloadFailed, /**< A Config File failed to download */ Alert_DNSError, /**< A error occurred performing a DNS Lookup */ Alert_NodeReloadRequired, /**< A new Config file has been discovered for this node, and its pending a Reload to Take affect */ Alert_UnsupportedController, /**< The Controller is not running a Firmware Library we support */ Alert_ApplicationStatus_Retry, /**< Application Status CC returned a Retry Later Message */ Alert_ApplicationStatus_Queued, /**< Command Has been Queued for later execution */ Alert_ApplicationStatus_Rejected, /**< Command has been rejected */ }; /** * Get the type of this notification. * \return the notification type. * \see NotificationType */ NotificationType GetType() const { return m_type; } /** * Get the Home ID of the driver sending this notification. * \return the driver Home ID */ uint32 GetHomeId() const { return m_valueId.GetHomeId(); } /** * Get the ID of any node involved in this notification. * \return the node's ID */ uint8 GetNodeId() const { return m_valueId.GetNodeId(); } /** * Get the unique ValueID of any value involved in this notification. * \return the value's ValueID */ ValueID const& GetValueID() const { return m_valueId; } /** * Get the index of the association group that has been changed. Only valid in Notification::Type_Group notifications. * \return the group index. */ uint8 GetGroupIdx() const { assert(Type_Group == m_type); return m_byte; } /** * Get the event value of a notification. Only valid in Notification::Type_NodeEvent and Notification::Type_ControllerCommand notifications. * \return the event value. */ uint8 GetEvent() const { assert((Type_NodeEvent == m_type) || (Type_ControllerCommand == m_type)); return m_event; } /** * Get the button id of a notification. Only valid in Notification::Type_CreateButton, Notification::Type_DeleteButton, * Notification::Type_ButtonOn and Notification::Type_ButtonOff notifications. * \return the button id. */ uint8 GetButtonId() const { assert(Type_CreateButton == m_type || Type_DeleteButton == m_type || Type_ButtonOn == m_type || Type_ButtonOff == m_type); return m_byte; } /** * Get the scene Id of a notification. Only valid in Notification::Type_SceneEvent notifications. * The SceneActivation CC now exposes ValueID's that convey this information * \return the event value. */ DEPRECATED uint8 GetSceneId() const { assert(Type_SceneEvent == m_type); return m_byte; } /** * Get the notification code from a notification. Only valid for Notification::Type_Notification or Notification::Type_ControllerCommand notifications. * \return the notification code. */ uint8 GetNotification() const { assert((Type_Notification == m_type) || (Type_ControllerCommand == m_type)); return m_byte; } /** * Get the (controller) command from a notification. Only valid for Notification::Type_ControllerCommand notifications. * \return the (controller) command code. */ uint8 GetCommand() const { assert(Type_ControllerCommand == m_type); return m_command; } /** * Helper function to simplify wrapping the notification class. Should not normally need to be called. * \return the internal byte value of the notification. */ uint8 GetByte() const { return m_byte; } /** * Helper function to return the Timeout to wait for. Only valid for Notification::Type_UserAlerts - Notification::Alert_ApplicationStatus_Retry * \return The time to wait before retrying */ uint8 GetRetry() const { assert((Type_UserAlerts == m_type) && (Alert_ApplicationStatus_Retry == m_useralerttype)); return m_byte; } /** * Helper Function to return the Notification as a String * \return A string representation of this Notification */ string GetAsString() const; /** * Retrieve the User Alert Type Enum to determine what this message is about * \return UserAlertNotification Enum describing the Alert Type */ UserAlertNotification GetUserAlertType() const { return m_useralerttype; } ; /** * Return the Comport associated with the DriverFailed Message * \return a string representing the Comport */ string GetComPort() const { return m_comport; } ; private: Notification(NotificationType _type) : m_type(_type), m_byte(0), m_event(0), m_command(0), m_useralerttype(Alert_None) { } ~Notification() { } void SetHomeAndNodeIds(uint32 const _homeId, uint8 const _nodeId) { m_valueId = ValueID(_homeId, _nodeId); } void SetHomeNodeIdAndInstance(uint32 const _homeId, uint8 const _nodeId, uint32 const _instance) { m_valueId = ValueID(_homeId, _nodeId, _instance); } void SetValueId(ValueID const& _valueId) { m_valueId = _valueId; } void SetGroupIdx(uint8 const _groupIdx) { assert(Type_Group == m_type); m_byte = _groupIdx; } void SetEvent(uint8 const _event) { assert(Type_NodeEvent == m_type || Type_ControllerCommand == m_type); m_event = _event; } void SetSceneId(uint8 const _sceneId) { assert(Type_SceneEvent == m_type); m_byte = _sceneId; } void SetButtonId(uint8 const _buttonId) { assert(Type_CreateButton == m_type || Type_DeleteButton == m_type || Type_ButtonOn == m_type || Type_ButtonOff == m_type); m_byte = _buttonId; } void SetNotification(uint8 const _noteId) { assert((Type_Notification == m_type) || (Type_ControllerCommand == m_type)); m_byte = _noteId; } void SetUserAlertNotification(UserAlertNotification const alerttype) { assert(Type_UserAlerts == m_type); m_useralerttype = alerttype; } void SetCommand(uint8 const _command) { assert(Type_ControllerCommand == m_type); m_command = _command; } void SetComPort(string comport) { assert(Type_DriverFailed == m_type); m_comport = comport; } void SetRetry(uint8 const timeout) { assert(Type_UserAlerts == m_type); m_byte = timeout; } NotificationType m_type; ValueID m_valueId; uint8 m_byte; uint8 m_event; uint8 m_command; UserAlertNotification m_useralerttype; string m_comport; }; } //namespace OpenZWave std::ostream& operator<<(std::ostream &os, const OpenZWave::Notification &dt); std::ostream& operator<<(std::ostream &os, const OpenZWave::Notification *dt); #endif //_Notification_H openzwave-1.6.1914/cpp/src/Http.cpp0000644000175200017520000001420414032142455013715 00000000000000//----------------------------------------------------------------------------- // // Http.cpp // // Simple HTTP Client Interface to download updated config files // // Copyright (c) 2015 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include #include #include #include "Driver.h" #include "Http.h" #include "platform/HttpClient.h" #include "platform/FileOps.h" #include "Utils.h" namespace OpenZWave { namespace Internal { i_HttpClient::i_HttpClient(Driver *driver) : m_driver(driver) { } ; void i_HttpClient::FinishDownload(HttpDownload *transfer) { /* send the response back to the Driver for processing */ Driver::EventMsg *event = new Driver::EventMsg(); event->type = Driver::EventMsg::Event_Http; event->event.httpdownload = transfer; this->m_driver->SubmitEventMsg(event); } HttpClient::HttpClient(OpenZWave::Driver *drv) : i_HttpClient(drv), m_exitEvent(new Internal::Platform::Event()), m_httpThread(new Internal::Platform::Thread("HttpThread")), m_httpThreadRunning(false), m_httpMutex(new Internal::Platform::Mutex()), m_httpDownloadEvent(new Internal::Platform::Event()) { } HttpClient::~HttpClient() { m_exitEvent->Set(); m_exitEvent->Release(); m_httpThread->Stop(); m_httpThread->Release(); m_httpDownloadEvent->Release(); m_httpMutex->Release(); } bool HttpClient::StartDownload(HttpDownload *transfer) { if (!m_httpThreadRunning) m_httpThread->Start(HttpClient::HttpThreadProc, this); LockGuard LG(m_httpMutex); switch (transfer->operation) { case HttpDownload::None: Log::Write(LogLevel_Warning, "Got a Transfer Type of NONE for %s", transfer->url.c_str()); delete transfer; return false; case HttpDownload::File: case HttpDownload::Config: case HttpDownload::MFSConfig: case HttpDownload::Image: /* make sure it has everything */ if ((transfer->url.size() <= 0) || (transfer->filename.size() <= 0)) { Log::Write(LogLevel_Warning, "File Transfer had incomplete Params"); delete transfer; return false; } /* make sure the Folder Exists */ if (!Internal::Platform::FileOps::Create()->FolderExists(ozwdirname(transfer->filename))) { if (!Internal::Platform::FileOps::Create()->FolderCreate(ozwdirname(transfer->filename))) { Log::Write(LogLevel_Warning, "File Transfer Failed. Could not create Destination Folder: %s", ozwdirname(transfer->filename).c_str()); delete transfer; return false; } } /* does the file exist, if so, rotate it out (by doing a copy) */ if (Internal::Platform::FileOps::Create()->FileExists(transfer->filename)) { if (!Internal::Platform::FileOps::Create()->FileRotate(transfer->filename)) { Log::Write(LogLevel_Warning, "File Transfer Failed. Could not Rotate Existing File: %s", transfer->filename.c_str()); delete transfer; return false; } } /* make sure the target file is writeable */ if (!Internal::Platform::FileOps::Create()->FileWriteable(transfer->filename)) { Log::Write(LogLevel_Warning, "File %s is not writable", transfer->filename.c_str()); delete transfer; return false; } break; } m_httpDownlist.push_back(transfer); m_httpDownloadEvent->Set(); return true; } void HttpClient::HttpThreadProc(Internal::Platform::Event* _exitEvent, void* _context) { HttpClient *client = (HttpClient *) _context; client->m_httpThreadRunning = true; Internal::Platform::InitNetwork(); bool keepgoing = true; while (keepgoing) { const uint32 count = 2; Internal::Platform::Wait* waitObjects[count]; int32 timeout = Internal::Platform::Wait::Timeout_Infinite; timeout = 10000; waitObjects[0] = client->m_exitEvent; // Thread must exit. waitObjects[1] = client->m_httpDownloadEvent; // Http Request // Wait for something to do int32 res = Internal::Platform::Wait::Multiple(waitObjects, count, timeout); switch (res) { case -1: /* timeout */ Log::Write(LogLevel_Info, "HttpThread Exiting. No Transfers in timeout period"); keepgoing = false; break; case 0: /* exitEvent */ Log::Write(LogLevel_Info, "HttpThread Exiting."); keepgoing = false; break; case 1: /* HttpEvent */ HttpDownload *download; { LockGuard LG(client->m_httpMutex); download = client->m_httpDownlist.front(); client->m_httpDownlist.pop_front(); if (client->m_httpDownlist.empty()) client->m_httpDownloadEvent->Reset(); } Log::Write(LogLevel_Debug, "Download Starting for %s (%s)", download->url.c_str(), download->filename.c_str()); Internal::Platform::HttpSocket *ht = new Internal::Platform::HttpSocket(); ht->SetKeepAlive(0); ht->SetBufsizeIn(64 * 1024); ht->SetDownloadFile(download->filename); ht->Download(download->url); while (ht->isOpen()) ht->update(); if (ht->IsSuccess()) download->transferStatus = HttpDownload::Ok; else download->transferStatus = HttpDownload::Failed; delete ht; client->FinishDownload(download); break; } } Internal::Platform::StopNetwork(); client->m_httpThreadRunning = false; } } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/Localization.cpp0000755000175200017520000006674414032142455015451 00000000000000//----------------------------------------------------------------------------- // // Localization.cpp // // Localization for CC and Value Classes // // Copyright (c) 2018 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include "Localization.h" #include "tinyxml.h" #include "Options.h" #include "platform/Log.h" #include "value_classes/ValueBitSet.h" #include "command_classes/Configuration.h" #include "command_classes/ThermostatSetpoint.h" #include "command_classes/SoundSwitch.h" #include "command_classes/Meter.h" #include "command_classes/CentralScene.h" namespace OpenZWave { namespace Internal { Localization *Localization::m_instance = NULL; std::map > Localization::m_valueLocalizationMap; std::map > Localization::m_commandClassLocalizationMap; std::map > Localization::m_globalLabelLocalizationMap; std::string Localization::m_selectedLang = ""; uint32 Localization::m_revision = 0; LabelLocalizationEntry::LabelLocalizationEntry(uint16 _index, uint32 _pos) : m_index(_index), m_pos(_pos) { } void LabelLocalizationEntry::AddLabel(string label, string lang) { if (lang.empty()) m_defaultLabel = label; else m_Label[lang] = label; } uint64 LabelLocalizationEntry::GetIdx() { uint64 key = ((uint64) m_index << 32) | ((uint64) m_pos); return key; } std::string LabelLocalizationEntry::GetLabel(string lang) { if (lang.empty() || (m_Label.find(lang) == m_Label.end())) return m_defaultLabel; else return m_Label[lang]; } bool LabelLocalizationEntry::HasLabel(string lang) { if (m_Label.find(lang) == m_Label.end()) return false; else return true; } ValueLocalizationEntry::ValueLocalizationEntry(uint8 _commandClass, uint16 _index, uint32 _pos) : m_commandClass(_commandClass), m_index(_index), m_pos(_pos) { } uint64 ValueLocalizationEntry::GetIdx() { uint64 key = ((uint64) m_commandClass << 48) | ((uint64) m_index << 32) | ((uint64) m_pos); return key; } std::string ValueLocalizationEntry::GetHelp(string lang) { if (lang.empty() || (m_HelpText.find(lang) == m_HelpText.end())) return m_DefaultHelpText; else return m_HelpText[lang]; } bool ValueLocalizationEntry::HasHelp(string lang) { if (m_HelpText.find(lang) == m_HelpText.end()) return false; else return true; } void ValueLocalizationEntry::AddHelp(string HelpText, string lang) { if (lang.empty()) m_DefaultHelpText = HelpText; else m_HelpText[lang] = HelpText; } std::string ValueLocalizationEntry::GetLabel(string lang) { if (lang.empty() || (m_LabelText.find(lang) == m_LabelText.end())) return m_DefaultLabelText; else return m_LabelText[lang]; } bool ValueLocalizationEntry::HasLabel(string lang) { if (m_LabelText.find(lang) == m_LabelText.end()) return false; else return true; } void ValueLocalizationEntry::AddLabel(string Label, string lang) { if (lang.empty()) m_DefaultLabelText = Label; else m_LabelText[lang] = Label; } void ValueLocalizationEntry::AddItemLabel(string label, int32 itemindex, string lang) { if (lang.empty()) { m_DefaultItemLabelText[itemindex] = label; } else { m_ItemLabelText[lang][itemindex] = label; } } std::string ValueLocalizationEntry::GetItemLabel(string lang, int32 itemindex) { if (lang.empty() || (m_ItemLabelText.find(lang) == m_ItemLabelText.end()) || m_ItemLabelText[lang].find(itemindex) == m_ItemLabelText[lang].end()) { if (m_DefaultItemLabelText.find(itemindex) == m_DefaultItemLabelText.end()) { Log::Write(LogLevel_Warning, "ValueLocalizationEntry::GetItemLabel: Unable to find Default Item Label Text for Index Item %d (%s)", itemindex, m_DefaultLabelText.c_str()); return "undefined"; } return m_DefaultItemLabelText[itemindex]; } else { return m_ItemLabelText[lang][itemindex]; } } bool ValueLocalizationEntry::HasItemLabel(int32 itemIndex, string lang) { if (lang.empty() || (m_ItemLabelText.find(lang) == m_ItemLabelText.end()) || m_ItemLabelText[lang].find(itemIndex) == m_ItemLabelText[lang].end()) return false; return true; } void ValueLocalizationEntry::AddItemHelp(string label, int32 itemindex, string lang) { if (lang.empty()) { m_DefaultItemHelpText[itemindex] = label; } else { m_ItemHelpText[lang][itemindex] = label; } } std::string ValueLocalizationEntry::GetItemHelp(string lang, int32 itemindex) { if (lang.empty() && (m_DefaultItemHelpText.find(itemindex) != m_DefaultItemHelpText.end())) { return m_DefaultItemHelpText[itemindex]; } if ((m_ItemHelpText.find(lang) != m_ItemHelpText.end())) { if ((m_ItemHelpText.at(lang).find(itemindex) != m_ItemHelpText.at(lang).end())) { return m_ItemHelpText.at(lang)[itemindex]; } } if (m_DefaultItemHelpText.find(itemindex) != m_DefaultItemHelpText.end()) { return m_DefaultItemHelpText[itemindex]; } Log::Write(LogLevel_Warning, "No ItemHelp Entry for Language %s (Index %d)", lang.c_str(), itemindex); return "Undefined"; } bool ValueLocalizationEntry::HasItemHelp(int32 itemIndex, string lang) { if (lang.empty() && (m_DefaultItemHelpText.find(itemIndex) != m_DefaultItemHelpText.end())) { return true; } if ((m_ItemHelpText.find(lang) != m_ItemHelpText.end())) { if ((m_ItemHelpText.at(lang).find(itemIndex) != m_ItemHelpText.at(lang).end())) { return true; } return false; } return false; } Localization::Localization() { } bool Localization::ReadXML() { // Parse the Z-Wave manufacturer and product XML file. string configPath; Options::Get()->GetOptionAsString("ConfigPath", &configPath); string path = configPath + "Localization.xml"; TiXmlDocument* pDoc = new TiXmlDocument(); if (!pDoc->LoadFile(path.c_str(), TIXML_ENCODING_UTF8)) { Log::Write(LogLevel_Warning, "Unable to load Localization file %s: %s", path.c_str(), pDoc->ErrorDesc()); delete pDoc; return false; } pDoc->SetUserData((void*) path.c_str()); Log::Write(LogLevel_Info, "Loading Localization File %s", path.c_str()); TiXmlElement const* root = pDoc->RootElement(); char const *str = root->Value(); if (str && !strcmp(str, "Localization")) { // Read in the revision attributes str = root->Attribute("Revision"); if (!str) { Log::Write(LogLevel_Info, "Error in Product Config file at line %d - missing Revision attribute", root->Row()); delete pDoc; return false; } m_revision = atol(str); } TiXmlElement const* CCElement = root->FirstChildElement(); while (CCElement) { char const* str = CCElement->Value(); char* pStopChar; if (str && !strcmp(str, "CommandClass")) { str = CCElement->Attribute("id"); if (!str) { Log::Write(LogLevel_Warning, "Localization::ReadXML: Error in %s at line %d - missing commandclass ID attribute", CCElement->GetDocument()->GetUserData(), CCElement->Row()); CCElement = CCElement->NextSiblingElement(); continue; } uint8 ccID = (uint8) strtol(str, &pStopChar, 10); TiXmlElement const* nextElement = CCElement->FirstChildElement(); while (nextElement) { str = nextElement->Value(); if (str && !strcmp(str, "Label")) { ReadCCXMLLabel(ccID, nextElement); } if (str && !strcmp(str, "Value")) { /* when node = 0, its a Localization that applies to all nodes. */ ReadXMLValue(0, ccID, nextElement); } nextElement = nextElement->NextSiblingElement(); } } else if (str && !strcmp(str, "GlobalText")) { TiXmlElement const* nextElement = CCElement->FirstChildElement(); while (nextElement) { str = nextElement->Value(); if (str && !strcmp(str, "Label")) { ReadGlobalXMLLabel(nextElement); } nextElement = nextElement->NextSiblingElement(); } } CCElement = CCElement->NextSiblingElement(); } Log::Write(LogLevel_Info, "Loaded %s With Revision %d", pDoc->GetUserData(), m_revision); delete pDoc; return true; } void Localization::ReadGlobalXMLLabel(const TiXmlElement *labelElement) { string Language; char const *str = labelElement->Attribute("name"); if (!str) { Log::Write(LogLevel_Warning, "Localization::ReadGlobalXMLLabel: Error in %s at line %d - missing GlobalText name attribute", labelElement->GetDocument()->GetUserData(), labelElement->Row()); return; } if (labelElement->Attribute("lang")) Language = labelElement->Attribute("lang"); if (m_globalLabelLocalizationMap.find(str) == m_globalLabelLocalizationMap.end()) { m_globalLabelLocalizationMap[str] = std::shared_ptr(new LabelLocalizationEntry(0)); } else if (m_globalLabelLocalizationMap[str]->HasLabel(Language)) { Log::Write(LogLevel_Warning, "Localization::ReadGlobalXMLLabel: Error in %s at line %d - Duplicate Entry for GlobalText %s: %s (Lang: %s)", labelElement->GetDocument()->GetUserData(), labelElement->Row(), str, labelElement->GetText(), Language.c_str()); return; } if (Language.empty()) { m_globalLabelLocalizationMap[str]->AddLabel(labelElement->GetText()); } else { m_globalLabelLocalizationMap[str]->AddLabel(labelElement->GetText(), Language); } } void Localization::ReadCCXMLLabel(uint8 ccID, const TiXmlElement *labelElement) { string Language; if (labelElement->Attribute("lang")) Language = labelElement->Attribute("lang"); if (m_commandClassLocalizationMap.find(ccID) == m_commandClassLocalizationMap.end()) { m_commandClassLocalizationMap[ccID] = std::shared_ptr(new LabelLocalizationEntry(0)); } else if (m_commandClassLocalizationMap[ccID]->HasLabel(Language)) { Log::Write(LogLevel_Warning, "Localization::ReadXMLLabel: Error in %s at line %d - Duplicate Entry for CommandClass %d: %s (Lang: %s)", labelElement->GetDocument()->GetUserData(), labelElement->Row(), ccID, labelElement->GetText(), Language.c_str()); return; } if (Language.empty()) { m_commandClassLocalizationMap[ccID]->AddLabel(labelElement->GetText()); } else { m_commandClassLocalizationMap[ccID]->AddLabel(labelElement->GetText(), Language); } } void Localization::ReadXMLValue(uint8 node, uint8 ccID, const TiXmlElement *valueElement) { char const* str = valueElement->Attribute("index"); if (!str) { Log::Write(LogLevel_Info, "Localization::ReadXMLValue: Error in %s at line %d - missing Index attribute", valueElement->GetDocument()->GetUserData(), valueElement->Row()); return; } char* pStopChar; uint16 indexId = (uint16) strtol(str, &pStopChar, 10); uint32 pos = -1; str = valueElement->Attribute("pos"); if (str) { pos = (uint32) strtol(str, &pStopChar, 10); } TiXmlElement const* valueIDElement = valueElement->FirstChildElement(); while (valueIDElement) { str = valueIDElement->Value(); if (str && !strcmp(str, "Label")) { ReadXMLVIDLabel(node, ccID, indexId, pos, valueIDElement); } if (str && !strcmp(str, "Help")) { ReadXMLVIDHelp(node, ccID, indexId, pos, valueIDElement); } if (str && !strcmp(str, "ItemLabel")) { ReadXMLVIDItemLabel(node, ccID, indexId, pos, valueIDElement); } valueIDElement = valueIDElement->NextSiblingElement(); } } void Localization::ReadXMLVIDLabel(uint8 node, uint8 ccID, uint16 indexId, uint32 pos, const TiXmlElement *labelElement) { uint64 key = GetValueKey(node, ccID, indexId, pos); string Language; if (labelElement->Attribute("lang")) Language = labelElement->Attribute("lang"); if (!labelElement->GetText()) { Log::Write(LogLevel_Warning, "Localization::ReadXMLVIDLabel: Error in %s at line %d - No Label Entry for CommandClass %d, ValueID: %d (%d): %s (Lang: %s)", labelElement->GetDocument()->GetUserData(), labelElement->Row(), ccID, indexId, pos, labelElement->GetText(), Language.c_str()); return; } if (m_valueLocalizationMap.find(key) == m_valueLocalizationMap.end()) { m_valueLocalizationMap[key] = std::shared_ptr (new ValueLocalizationEntry(ccID, indexId, pos)); } else if (m_valueLocalizationMap[key]->HasLabel(Language)) { Log::Write(LogLevel_Warning, "Localization::ReadXMLVIDLabel: Error in %s at line %d - Duplicate Entry for CommandClass %d, ValueID: %d (%d): %s (Lang: %s)", labelElement->GetDocument()->GetUserData(), labelElement->Row(), ccID, indexId, pos, labelElement->GetText(), Language.c_str()); return; } if (Language.empty()) { m_valueLocalizationMap[key]->AddLabel(labelElement->GetText()); } else { m_valueLocalizationMap[key]->AddLabel(labelElement->GetText(), Language); } } void Localization::ReadXMLVIDHelp(uint8 node, uint8 ccID, uint16 indexId, uint32 pos, const TiXmlElement *labelElement) { string Language; if (labelElement->Attribute("lang")) Language = labelElement->Attribute("lang"); if (!labelElement->GetText()) { if (ccID != 112) { /* Dont Log About the Configuration CC */ Log::Write(LogLevel_Warning, "Localization::ReadXMLVIDHelp: Error in %s at line %d - No Help Entry for CommandClass %d, ValueID: %d (%d): %s (Lang: %s)", labelElement->GetDocument()->GetUserData(), labelElement->Row(), ccID, indexId, pos, labelElement->GetText(), Language.c_str()); } return; } uint64 key = GetValueKey(node, ccID, indexId, pos); if (m_valueLocalizationMap.find(key) == m_valueLocalizationMap.end()) { m_valueLocalizationMap[key] = std::shared_ptr (new ValueLocalizationEntry(ccID, indexId, pos)); } else if (m_valueLocalizationMap[key]->HasLabel(Language)) { Log::Write(LogLevel_Warning, "Localization::ReadXMLVIDHelp: Error in %s at line %d - Duplicate Entry for CommandClass %d, ValueID: %d (%d): %s (Lang: %s)", labelElement->GetDocument()->GetUserData(), labelElement->Row(), ccID, indexId, pos, labelElement->GetText(), Language.c_str()); return; } if (Language.empty()) { m_valueLocalizationMap[key]->AddHelp(labelElement->GetText()); } else { m_valueLocalizationMap[key]->AddHelp(labelElement->GetText(), Language); } } void Localization::ReadXMLVIDItemLabel(uint8 node, uint8 ccID, uint16 indexId, uint32 pos, const TiXmlElement *labelElement) { uint64 key = GetValueKey(node, ccID, indexId, pos); string Language; int32 itemIndex; if (labelElement->Attribute("lang")) Language = labelElement->Attribute("lang"); if (!labelElement->GetText()) { Log::Write(LogLevel_Warning, "Localization::ReadXMLVIDItemLabel: Error in %s at line %d - No ItemIndex Label Entry for CommandClass %d, ValueID: %d (%d): %s (Lang: %s)", labelElement->GetDocument()->GetUserData(), labelElement->Row(), ccID, indexId, pos, labelElement->GetText(), Language.c_str()); return; } if (TIXML_SUCCESS != labelElement->QueryIntAttribute("itemIndex", &itemIndex)) { Log::Write(LogLevel_Warning, "Localization::ReadXMLVIDItemLabel: Error in %s at line %d - No itemIndex Entry for CommandClass %d, ValueID: %d (%d): %s (Lang: %s)", labelElement->GetDocument()->GetUserData(), labelElement->Row(), ccID, indexId, pos, labelElement->GetText(), Language.c_str()); return; } if (m_valueLocalizationMap.find(key) == m_valueLocalizationMap.end()) { Log::Write(LogLevel_Warning, "Localization::ReadXMLVIDItemLabel: Error in %s at line %d - No Value Entry for CommandClass %d, ValueID: %d (%d): %s (Lang: %s)", labelElement->GetDocument()->GetUserData(), labelElement->Row(), ccID, indexId, pos, labelElement->GetText(), Language.c_str()); return; } else if (m_valueLocalizationMap[key]->HasItemLabel(itemIndex, Language)) { Log::Write(LogLevel_Warning, "Localization::ReadXMLVIDItemLabel: Error in %s at line %d - Duplicate ItemLabel Entry for CommandClass %d, ValueID: %d (%d): %s (Lang: %s)", labelElement->GetDocument()->GetUserData(), labelElement->Row(), ccID, indexId, pos, labelElement->GetText(), Language.c_str()); return; } if (Language.empty()) { m_valueLocalizationMap[key]->AddItemLabel(labelElement->GetText(), itemIndex); } else { m_valueLocalizationMap[key]->AddItemLabel(labelElement->GetText(), itemIndex, Language); } } uint64 Localization::GetValueKey(uint8 _node, uint8 _commandClass, uint16 _index, uint32 _pos, bool unique) { if (unique == true) { return ((uint64) _node << 56 | (uint64) _commandClass << 48) | ((uint64) _index << 32) | ((uint64) _pos); } /* configuration CC needs its own Storage per Node. */ if (_commandClass == Internal::CC::Configuration::StaticGetCommandClassId()) { return ((uint64) _node << 56 | (uint64) _commandClass << 48) | ((uint64) _index << 32) | ((uint64) _pos); } /* ThermoStatSetpoint index's above 100 are unique per node */ if ((_commandClass == Internal::CC::ThermostatSetpoint::StaticGetCommandClassId()) && (_index >= 100)) { return ((uint64) _node << 56 | (uint64) _commandClass << 48) | ((uint64) _index << 32) | ((uint64) _pos); } if (_commandClass == Internal::CC::Meter::StaticGetCommandClassId()) { return ((uint64) _node << 56 | (uint64) _commandClass << 48) | ((uint64) _index << 32) | ((uint64) _pos); } /* indexes below 256 are the Scene Labels - Unique per device */ if (_commandClass == Internal::CC::CentralScene::StaticGetCommandClassId() && (_index < 256)) { return ((uint64) _node << 56 | (uint64) _commandClass << 48 | (uint64) _index << 32 | (uint64) _pos); } return ((uint64) _commandClass << 48) | ((uint64) _index << 32) | ((uint64) _pos); } void Localization::SetupCommandClass(Internal::CC::CommandClass *cc) { uint8 ccID = cc->GetCommandClassId(); if (m_commandClassLocalizationMap.find(ccID) != m_commandClassLocalizationMap.end()) { cc->SetCommandClassLabel(m_commandClassLocalizationMap[ccID]->GetLabel(m_selectedLang)); } else { Log::Write(LogLevel_Warning, "Localization::SetupCommandClass: Localization Warning: No Entry for CommandClass - CC: %d (%s)", ccID, cc->GetCommandClassName().c_str()); cc->SetCommandClassLabel(cc->GetCommandClassName()); } } bool Localization::SetValueHelp(uint8 _node, uint8 ccID, uint16 indexId, uint32 pos, string help, string lang) { uint64 key = GetValueKey(_node, ccID, indexId, pos); if (m_valueLocalizationMap.find(key) == m_valueLocalizationMap.end()) { m_valueLocalizationMap[key] = std::shared_ptr (new ValueLocalizationEntry(ccID, indexId, pos)); } else if (m_valueLocalizationMap[key]->HasHelp(lang)) { Log::Write(LogLevel_Warning, "Localization::SetValueHelp: Duplicate Entry for CommandClass %d, ValueID: %d (%d): %s (Lang: %s)", ccID, indexId, pos, help.c_str(), lang.c_str()); } if (lang.empty()) { m_valueLocalizationMap[key]->AddHelp(help); } else { m_valueLocalizationMap[key]->AddHelp(help, lang); } return true; } bool Localization::SetValueLabel(uint8 node, uint8 ccID, uint16 indexId, uint32 pos, string label, string lang) { uint64 key = GetValueKey(node, ccID, indexId, pos); if (m_valueLocalizationMap.find(key) == m_valueLocalizationMap.end()) { m_valueLocalizationMap[key] = std::shared_ptr (new ValueLocalizationEntry(ccID, indexId, pos)); } else if (m_valueLocalizationMap[key]->HasLabel(lang)) { Log::Write(LogLevel_Warning, "Localization::SetValueLabel: Duplicate Entry for CommandClass %d, ValueID: %d (%d): %s (Lang: %s)", ccID, indexId, pos, label.c_str(), lang.c_str()); } if (lang.empty()) { m_valueLocalizationMap[key]->AddLabel(label); } else { m_valueLocalizationMap[key]->AddLabel(label, lang); } return true; } std::string const Localization::GetValueHelp(uint8 node, uint8 ccID, uint16 indexId, uint32 pos) { uint64 key = GetValueKey(node, ccID, indexId, pos); if (m_valueLocalizationMap.find(key) == m_valueLocalizationMap.end()) { Log::Write(LogLevel_Warning, "Localization::GetValueHelp: No Help for CommandClass %xd, ValueID: %d (%d)", ccID, indexId, pos); return ""; } return m_valueLocalizationMap[key]->GetHelp(m_selectedLang); } std::string const Localization::GetValueLabel(uint8 node, uint8 ccID, uint16 indexId, int32 pos) const { uint64 key = GetValueKey(node, ccID, indexId, pos); if (m_valueLocalizationMap.find(key) == m_valueLocalizationMap.end()) { Log::Write(LogLevel_Warning, "Localization::GetValueLabel: No Label for CommandClass %xd, ValueID: %d (%d)", ccID, indexId, pos); return ""; } return m_valueLocalizationMap[key]->GetLabel(m_selectedLang); } std::string const Localization::GetValueItemLabel(uint8 node, uint8 ccID, uint16 indexId, int32 pos, int32 itemIndex) const { bool unique = false; if ((ccID == Internal::CC::SoundSwitch::StaticGetCommandClassId()) && (indexId == 1 || indexId == 3)) { unique = true; } if ((ccID == Internal::CC::CentralScene::StaticGetCommandClassId()) && (indexId < 256)) { unique = true; } uint64 key = GetValueKey(node, ccID, indexId, pos, unique); if (m_valueLocalizationMap.find(key) == m_valueLocalizationMap.end()) { Log::Write(LogLevel_Warning, "Localization::GetValueItemLabel: No ValueLocalizationMap for CommandClass %xd, ValueID: %d (%d) ItemIndex %d", ccID, indexId, pos, itemIndex); return ""; } return m_valueLocalizationMap[key]->GetItemLabel(m_selectedLang, itemIndex); } bool Localization::SetValueItemLabel(uint8 node, uint8 ccID, uint16 indexId, int32 pos, int32 itemIndex, string label, string lang) { bool unique = false; if ((ccID == Internal::CC::SoundSwitch::StaticGetCommandClassId()) && (indexId == 1 || indexId == 3)) { unique = true; } if ((ccID == Internal::CC::CentralScene::StaticGetCommandClassId()) && (indexId < 256)) { unique = true; } uint64 key = GetValueKey(node, ccID, indexId, pos, unique); if (m_valueLocalizationMap.find(key) == m_valueLocalizationMap.end()) { m_valueLocalizationMap[key] = std::shared_ptr (new ValueLocalizationEntry(ccID, indexId, pos)); } else if (m_valueLocalizationMap[key]->HasItemLabel(itemIndex, lang)) { Log::Write(LogLevel_Warning, "Localization::SetValueItemLabel: Duplicate Item Entry for CommandClass %d, ValueID: %d (%d) itemIndex %d: %s (Lang: %s)", ccID, indexId, pos, itemIndex, label.c_str(), lang.c_str()); } m_valueLocalizationMap[key]->AddItemLabel(label, itemIndex, lang); return true; } std::string const Localization::GetValueItemHelp(uint8 node, uint8 ccID, uint16 indexId, int32 pos, int32 itemIndex) const { bool unique = false; if ((ccID == Internal::CC::SoundSwitch::StaticGetCommandClassId()) && (indexId == 1 || indexId == 3)) { unique = true; } if ((ccID == Internal::CC::CentralScene::StaticGetCommandClassId()) && (indexId < 256)) { unique = true; } uint64 key = GetValueKey(node, ccID, indexId, pos, unique); if (m_valueLocalizationMap.find(key) == m_valueLocalizationMap.end()) { Log::Write(LogLevel_Warning, "Localization::GetValueItemHelp: No ValueLocalizationMap for CommandClass %xd, ValueID: %d (%d) ItemIndex %d", ccID, indexId, pos, itemIndex); return ""; } return m_valueLocalizationMap[key]->GetItemHelp(m_selectedLang, itemIndex); } bool Localization::SetValueItemHelp(uint8 node, uint8 ccID, uint16 indexId, int32 pos, int32 itemIndex, string label, string lang) { bool unique = false; if ((ccID == Internal::CC::SoundSwitch::StaticGetCommandClassId()) && (indexId == 1 || indexId == 3)) { unique = true; } if ((ccID == Internal::CC::CentralScene::StaticGetCommandClassId()) && (indexId < 256)) { unique = true; } uint64 key = GetValueKey(node, ccID, indexId, pos, unique); if (m_valueLocalizationMap.find(key) == m_valueLocalizationMap.end()) { m_valueLocalizationMap[key] = std::shared_ptr (new ValueLocalizationEntry(ccID, indexId, pos)); } else if (m_valueLocalizationMap[key]->HasItemHelp(itemIndex, lang)) { Log::Write(LogLevel_Warning, "Localization::SetValueItemHelp: Duplicate Item Entry for CommandClass %d, ValueID: %d (%d) ItemIndex %d: %s (Lang: %s)", ccID, indexId, pos, itemIndex, label.c_str(), lang.c_str()); } m_valueLocalizationMap[key]->AddItemHelp(label, itemIndex, lang); return true; } std::string const Localization::GetGlobalLabel(string index) { if (m_globalLabelLocalizationMap.find(index) == m_globalLabelLocalizationMap.end()) { Log::Write(LogLevel_Warning, "Localization::GetGlobalLabel: No globalLabelLocalizationMap for Index %s", index.c_str()); return index; } return m_globalLabelLocalizationMap[index]->GetLabel(m_selectedLang); } bool Localization::SetGlobalLabel(string index, string text, string lang) { if (m_globalLabelLocalizationMap.find(index) == m_globalLabelLocalizationMap.end()) { m_globalLabelLocalizationMap[index] = std::shared_ptr(new LabelLocalizationEntry(0)); } else if (m_globalLabelLocalizationMap[index]->HasLabel(lang)) { Log::Write(LogLevel_Warning, "Localization::SetGlobalLabel: Duplicate Entry for GlobalText %s: %s (Lang: %s)", index.c_str(), text.c_str(), lang.c_str()); return false; } if (lang.empty()) { m_globalLabelLocalizationMap[index]->AddLabel(text); } else { m_globalLabelLocalizationMap[index]->AddLabel(text, lang); } return true; } bool Localization::WriteXMLVIDHelp(uint8 node, uint8 ccID, uint16 indexId, uint32 pos, TiXmlElement *valueElement) { uint64 key = GetValueKey(node, ccID, indexId, pos); if (m_valueLocalizationMap.find(key) == m_valueLocalizationMap.end()) { Log::Write(LogLevel_Warning, "Localization::WriteXMLVIDHelp: No Help for CommandClass %d, ValueID: %d (%d)", ccID, indexId, pos); return false; } TiXmlElement* helpElement = new TiXmlElement("Help"); valueElement->LinkEndChild(helpElement); TiXmlText* textElement = new TiXmlText(m_valueLocalizationMap[key]->GetHelp(m_selectedLang).c_str()); helpElement->LinkEndChild(textElement); return true; } Localization *Localization::Get() { if (m_instance != NULL) { return m_instance; } m_instance = new Localization(); if (!ReadXML()) { OZW_ERROR(OZWException::OZWEXCEPTION_CONFIG, "Cannot Create Localization Class! - Missing/Invalid Config File?"); } Options::Get()->GetOptionAsString("Language", &m_selectedLang); return m_instance; } } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/Bitfield.cpp0000644000175200017520000001072414032142455014523 00000000000000//----------------------------------------------------------------------------- // // bitfield.h // // Integer to Bits Helper Class // // Copyright (c) 2017 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Bitfield.h" namespace OpenZWave { namespace Internal { /* Note: we have our own "BitSet" class rather than using the Std Library version * as the Std Library version can not be resized at runtime. This version can. Its the basis * of the BitSet ValueID class */ Bitfield::Bitfield() : m_numSetBits(0), m_value(0) { } Bitfield::Bitfield(uint32 value) : m_numSetBits(0), m_value(value) { for (unsigned int i = 0; i < 8 * sizeof(uint32); i++) { if (m_value & (1 << i)) { Set(i); } } } Bitfield::~Bitfield() { } bool Bitfield::SetValue(uint32 val) { for (unsigned int i = 0; i < 8 * sizeof(uint32); i++) { if (val & (1 << i)) { Set(i); } else { Clear(i); } } return true; } bool Bitfield::Set(uint8 _idx) { if (_idx > 0x1F) { return false; } if (!IsSet(_idx)) { uint32 newSize = (_idx >> 5) + 1; if (newSize > m_bits.size()) { m_bits.resize(newSize, 0); } m_bits[_idx >> 5] |= (1 << (_idx & 0x1f)); ++m_numSetBits; } return true; } bool Bitfield::Clear(uint8 _idx) { if (_idx > 0x1F) { return false; } if (IsSet(_idx)) { m_bits[_idx >> 5] &= ~(1 << (_idx & 0x1f)); --m_numSetBits; } return true; } bool Bitfield::IsSet(uint8 _idx) const { if (_idx > 0x1F) { return false; } if ((unsigned int) (_idx >> 5) < (unsigned int) m_bits.size()) { return ((m_bits[_idx >> 5] & (1 << (_idx & 0x1f))) != 0); } return false; } uint32 Bitfield::GetNumSetBits() const { return m_numSetBits; } uint32 Bitfield::GetValue() const { uint32 value = 0; for (unsigned int i = 0; i < m_bits.size(); i++) { value += (m_bits[i] << (8 * i)); } return value; } uint32 Bitfield::GetSize() const { return m_bits.size() * sizeof(uint32) * 8; } Bitfield::Iterator Bitfield::Begin() const { return Iterator(this, 0); } Bitfield::Iterator Bitfield::End() const { return Iterator(this, (uint32) m_bits.size() << 5); } uint32 Bitfield::Iterator::operator *() const { return m_idx; } Bitfield::Iterator& Bitfield::Iterator::operator++() { // Search forward to next set bit NextSetBit(); return *this; } Bitfield::Iterator Bitfield::Iterator::operator++(int a) { Iterator tmp = *this; ++tmp; return tmp; } bool Bitfield::Iterator::operator ==(const Iterator &rhs) { return m_idx == rhs.m_idx; } bool Bitfield::Iterator::operator !=(const Iterator &rhs) { return m_idx != rhs.m_idx; } Bitfield::Iterator::Iterator(Bitfield const* _bitfield, uint32 _idx) : m_idx(_idx), m_bitfield(_bitfield) { // If this is a begin iterator, move it to the first set bit if ((_idx == 0) && (!m_bitfield->IsSet(0))) { NextSetBit(); } } void Bitfield::Iterator::NextSetBit() { while (((++m_idx) >> 5) < m_bitfield->m_bits.size()) { // See if there are any bits left to find in the current uint32 if ((m_bitfield->m_bits[m_idx >> 5] & ~((1 << (m_idx & 0x1f)) - 1)) == 0) { // No more bits - move on to next uint32 (or rather one less than // the next uint32 because of the preincrement in the while statement) m_idx = (m_idx & 0xffffffe0) + 31; } else { if ((m_bitfield->m_bits[m_idx >> 5] & (1 << (m_idx & 0x1f))) != 0) { // This bit is set return; } } } } } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/ZWSecurity.cpp0000644000175200017520000003114314032142455015067 00000000000000//----------------------------------------------------------------------------- // // Security.cpp // // Common Security/Encryption Routines // // Copyright (c) 2015 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "ZWSecurity.h" #include "Node.h" #include "Driver.h" #include "Manager.h" #include "Options.h" #include "Utils.h" #include "platform/Log.h" #include "command_classes/MultiInstance.h" #include "command_classes/Security.h" #include "aes/aescpp.h" namespace OpenZWave { namespace Internal { //----------------------------------------------------------------------------- // // Generate authentication data from a security-encrypted message //----------------------------------------------------------------------------- bool GenerateAuthentication(uint8 const* _data, // Starting from the command class command uint32 const _length, Driver *driver, uint8 const _sendingNode, uint8 const _receivingNode, uint8 *iv, uint8* _authentication // 8-byte buffer that will be filled with the authentication data ) { // Build a buffer containing a 4-byte header and the encrypted // message data, padded with zeros to a 16-byte boundary. uint8 buffer[256]; uint8 tmpauth[16]; memset(buffer, 0, 256); memset(tmpauth, 0, 16); buffer[0] = _data[0]; // Security command class command buffer[1] = _sendingNode; buffer[2] = _receivingNode; buffer[3] = _length - 19; // Subtract 19 to account for the 9 security command class bytes that come before and after the encrypted data memcpy(&buffer[4], &_data[9], _length - 19); // Encrypted message uint8 bufsize = _length - 19 + 4; /* the size of buffer */ #ifdef DEBUG Internal::PrintHex("Raw Auth (minus IV)", buffer, bufsize); Log::Write(LogLevel_Debug, _receivingNode, "Raw Auth (Minus IV) Size: %d (%d)", bufsize, bufsize+16); #endif aes_mode_reset(driver->GetAuthKey()); /* encrypt the IV with ecb */ if (aes_ecb_encrypt(iv, tmpauth, 16, driver->GetAuthKey()) == EXIT_FAILURE) { Log::Write(LogLevel_Warning, _receivingNode, "Failed Initial ECB Encrypt of Auth Packet"); return false; } /* our temporary holding var */ uint8 encpck[16]; int block = 0; /* reset our encpck temp var */ memset(encpck, 0, 16); /* now xor the buffer with our encrypted IV */ for (int i = 0; i < bufsize; i++) { encpck[block] = buffer[i]; block++; /* if we hit a blocksize, then encrypt */ if (block == 16) { for (int j = 0; j < 16; j++) { /* here we do our xor */ tmpauth[j] = encpck[j] ^ tmpauth[j]; /* and reset encpck for good measure */ encpck[j] = 0; } /* reset our block counter back to 0 */ block = 0; aes_mode_reset(driver->GetAuthKey()); if (aes_ecb_encrypt(tmpauth, tmpauth, 16, driver->GetAuthKey()) == EXIT_FAILURE) { Log::Write(LogLevel_Warning, _receivingNode, "Failed Subsequent (%d) ECB Encrypt of Auth Packet", i); return false; } } } /* any left over data that isn't a full block size*/ if (block > 0) { for (int i = 0; i < 16; i++) { /* encpck from block to 16 is already guaranteed to be 0 * so its safe to xor it with out tmpmac */ tmpauth[i] = encpck[i] ^ tmpauth[i]; } aes_mode_reset(driver->GetAuthKey()); if (aes_ecb_encrypt(tmpauth, tmpauth, 16, driver->GetAuthKey()) == EXIT_FAILURE) { Log::Write(LogLevel_Warning, _receivingNode, "Failed Final ECB Encrypt of Auth Packet"); return false; } } /* we only care about the first 8 bytes of tmpauth as the mac */ #ifdef DEBUG Internal::PrintHex("Computed Auth", tmpauth, 8); #endif /* so only copy 8 bytes to the _authentication var */ memcpy(_authentication, tmpauth, 8); return true; } bool EncryptBuffer(uint8 *m_buffer, uint8 m_length, Driver *driver, uint8 const _sendingNode, uint8 const _receivingNode, uint8 const m_nonce[8], uint8* e_buffer) { #if 0 m_nonce[0] = 0x09; m_nonce[1] = 0x0d; m_nonce[2] = 0x93; m_nonce[3] = 0xd3; m_nonce[4] = 0x61; m_nonce[5] = 0x61; m_nonce[6] = 0x1d; m_nonce[7] = 0xd6; #endif uint8 len = 0; e_buffer[len++] = SOF; e_buffer[len++] = m_length + 18; // length of full packet e_buffer[len++] = REQUEST; e_buffer[len++] = FUNC_ID_ZW_SEND_DATA; e_buffer[len++] = _receivingNode; e_buffer[len++] = m_length + 11; // Length of the payload e_buffer[len++] = Internal::CC::Security::StaticGetCommandClassId(); e_buffer[len++] = Internal::CC::SecurityCmd_MessageEncap; /* create our IV */ uint8 initializationVector[16]; /* the first 8 bytes of a outgoing IV are random * and we add it also to the start of the payload */ for (int i = 0; i < 8; i++) { initializationVector[i] = (uint8) (255.0 * rand() / (RAND_MAX + 1.0)); e_buffer[len++] = initializationVector[i]; } /* the remaining 8 bytes are the NONCE we got from the device */ for (int i = 0; i < 8; i++) { initializationVector[8 + i] = m_nonce[i]; } /* we need a copy b/c aes_ofb_encrypt will overwrite it */ uint8 iv_dup[16]; for (int i = 0; i < 16; i++) { iv_dup[i] = initializationVector[i]; } uint8 plaintextmsg[32]; /* add the Sequence Flag * - Since we don't currently handle multipacket encryption * just set this to 0 */ plaintextmsg[0] = 0; /* now add the actual message to be encrypted */ for (int i = 0; i < m_length - 6 - 3; i++) plaintextmsg[i + 1] = m_buffer[6 + i]; /* now encrypt */ uint8 encryptedpayload[30]; aes_mode_reset(driver->GetEncKey()); #ifdef DEBUG Internal::PrintHex("Plain Text Packet:", plaintextmsg, m_length-5-3); #endif if (aes_ofb_encrypt(plaintextmsg, encryptedpayload, m_length - 5 - 3, initializationVector, driver->GetEncKey()) == EXIT_FAILURE) { Log::Write(LogLevel_Warning, _receivingNode, "Failed to Encrypt Packet"); return false; } #ifdef DEBUG Internal::PrintHex("Encrypted Packet", encryptedpayload, m_length-5-3); #endif /* now add the Encrypted output to the packet */ for (int i = 0; i < m_length - 5 - 3; i++) { e_buffer[len++] = encryptedpayload[i]; } // Append the nonce identifier :) e_buffer[len++] = m_nonce[0]; /* now calculate the MAC and append it */ uint8 mac[8]; GenerateAuthentication(&e_buffer[7], e_buffer[5], driver, _sendingNode, _receivingNode, iv_dup, mac); for (int i = 0; i < 8; ++i) { e_buffer[len++] = mac[i]; } e_buffer[len++] = driver->GetTransmitOptions(); /* this is the same as the Actual Message */ e_buffer[len++] = m_buffer[m_length - 2]; // Calculate the checksum uint8 csum = 0xff; for (int32 i = 1; i < len; ++i) { csum ^= e_buffer[i]; } e_buffer[len++] = csum; #ifdef DEBUG Internal::PrintHex("Encrypted Packet", e_buffer, len); Log::Write(LogLevel_Info, "Length: %d", len); #endif return true; } bool createIVFromPacket_inbound(uint8 const* _data, uint8 const m_nonce[8], uint8 *iv) { for (int i = 0; i < 8; i++) { iv[i] = _data[i]; } for (int i = 0; i < 8; i++) { iv[8 + i] = m_nonce[i]; } return true; } /* To Decrypt, we start the packet at the IV (right after the command) * * Encrypted Packet Size is Packet Length - Device Nonce(8) - Receiver Nonce ID (1) - Mac (8) - CommandClass - Command * * Receiver Nonce is at Position 14 + Encrypted Packet Size * Mac is at Position 15 + Encrypted Packet Size * 0 - Command Class * 1 - Command * 2 to 9 - Device Nonce * 10 - Sequence (e) * 11 - Command Class (e) * 12 - Command (e) * 13 to EncryptedPckSize * ReceiverNonceID (1 Byte) * Mac (8 Bytes) */ bool DecryptBuffer(uint8 *e_buffer, uint8 e_length, Driver *driver, uint8 const _sendingNode, uint8 const _receivingNode, uint8 const m_nonce[8], uint8* m_buffer) { Internal::PrintHex("Raw", e_buffer, e_length); if (e_length < 19) { Log::Write(LogLevel_Warning, _sendingNode, "Received a Encrypted Message that is too Short. Dropping it"); return false; } uint8 iv[17]; createIVFromPacket_inbound(&e_buffer[2], m_nonce, iv); /* first 8 bytes of Packet are the Random Value generated by the Device * 2nd 8 bytes of the IV are our nonce we sent previously */ memset(&m_buffer[0], 0, 32); uint32 encryptedpacketsize = e_length - 8 - 8 - 2 - 2; /* if the Encrypted Packet Size is less than 3, there is probably a issue, drop it. */ if (encryptedpacketsize < 3) { Log::Write(LogLevel_Warning, _sendingNode, "Encrypted Packet Size is Less than 3 Bytes. Dropping"); return false; } uint8 encyptedpacket[32]; for (uint32 i = 0; i < 32; i++) { if (i >= encryptedpacketsize) { /* pad the remaining fields */ encyptedpacket[i] = 0; } else { encyptedpacket[i] = e_buffer[10 + i]; } } #ifdef DEBUG Log::Write(LogLevel_Debug, _sendingNode, "Encrypted Packet Sizes: %u (Total) %u (Payload)", e_length, encryptedpacketsize); Internal::PrintHex("IV", iv, 16); Internal::PrintHex("Encrypted", encyptedpacket, 32); /* Mac Starts after Encrypted Packet. */ Internal::PrintHex("Auth", &e_buffer[11+encryptedpacketsize], 8); #endif aes_mode_reset(driver->GetEncKey()); #if 0 uint8_t iv[16] = { 0x81, 0x42, 0xd1, 0x51, 0xf1, 0x59, 0x3d, 0x70, 0xd5, 0xe3, 0x6c, 0xcb, 0x02, 0xd0, 0x3f, 0x5c, /* */}; uint8_t pck[] = { 0x25, 0x68, 0x06, 0xc5, 0xb3, 0xee, 0x2c, 0x17, 0x26, 0x7e, 0xf0, 0x84, 0xd4, 0xc3, 0xba, 0xed, 0xe5, 0xb9, 0x55}; if (aes_ofb_decrypt(pck, decryptpacket, 19, iv, this->EncryptKey) == EXIT_FAILURE) { Log::Write(LogLevel_Warning, GetNodeId(), "Failed to Decrypt Packet"); return false; } Internal::PrintHex("Pck", decryptpacket, 19); #else if (aes_ofb_decrypt(encyptedpacket, m_buffer, encryptedpacketsize, iv, driver->GetEncKey()) == EXIT_FAILURE) { Log::Write(LogLevel_Warning, _sendingNode, "Failed to Decrypt Packet"); return false; } Log::Write(LogLevel_Detail, _sendingNode, "Decrypted Packet: %s", Internal::PktToString(m_buffer, encryptedpacketsize).c_str()); #endif uint8 mac[32]; /* we have to regenerate the IV as the ofb decryption routine will alter it. */ createIVFromPacket_inbound(&e_buffer[2], m_nonce, iv); GenerateAuthentication(&e_buffer[1], e_length - 1, driver, _sendingNode, _receivingNode, iv, mac); if (memcmp(&e_buffer[11 + encryptedpacketsize], mac, 8) != 0) { Log::Write(LogLevel_Warning, _sendingNode, "MAC Authentication of Packet Failed. Dropping"); return false; } /* XXX TODO: Check the Sequence Header Frame to see if this is the first part of a * message, or 2nd part, or a entire message. * * I haven't actually seen a Z-Wave Message thats too big to fit in a encrypted message * yet, so we will look at this if such a message actually exists! * * 2019-08 such a message was found, PST02 produces long multi cmd, see * https://github.com/OpenZWave/open-zwave/issues/1899 */ return true; } SecurityStrategy ShouldSecureCommandClass(uint8 CommandClass) { string securestrategy; Options::Get()->GetOptionAsString("SecurityStrategy", &securestrategy); if (Internal::ToUpper(securestrategy) == "ESSENTIAL") { return SecurityStrategy_Essential; } else if (Internal::ToUpper(securestrategy) == "SUPPORTED") { return SecurityStrategy_Supported; } else if (Internal::ToUpper(securestrategy) == "CUSTOM") { string customsecurecc; Options::Get()->GetOptionAsString("CustomSecuredCC", &customsecurecc); char* pos = const_cast(customsecurecc.c_str()); while (*pos) { if (CommandClass == (uint8) strtol(pos, &pos, 16)) { return SecurityStrategy_Supported; } if ((*pos) == ',') { ++pos; } } } return SecurityStrategy_Essential; } } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/Options.h0000644000175200017520000002542314032142455014103 00000000000000//----------------------------------------------------------------------------- // // Options.h // // Program options read from XML files or the command line. // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Options_H #define _Options_H #include #include #include #include "Defs.h" namespace OpenZWave { /** \brief Manages library options read from XML files or the command line. * * A class that manages program options read from XML files or the command line. * The OpenZWave Manager class requires a complete and locked Options * object when created. The Options are therefore one of the first things that * any OpenZWave application must deal with. * Options are first read from an XML file called options.xml located in the * User data folder (the path to which is supplied to the Options::Create method). * This is the same folder that will be used by the Manager to save the state of * each controller in the Z-Wave network, to avoid querying them for their entire * state every time the application starts up. * The second source of program options is a string, which will normally be the * command line used to launch the application. * In this way, common options can be specified in the XML, but over-ridden if * necessary by the command line. * The Options process is as follows: * 1) Create an Options object, providing paths to the OpenZWave config folder, * the User data folder and any command line string containing program options. * 2) Call Options::AddOptionBool, Options::AddOptionInt or Options::AddOptionString * to add any application-specific configurable options. In this way, the Options * class can be used for non-OpenZWave options as well. (OpenZWave options must * be specified in step #1 above (either via xml file or a command line string). * 3) Call Options::Lock. This will cause the option values to be read from * the options.xml file and the command line string, and will lock the options * so that no more calls aside from GetOptionAs may be made. * 4) Create the OpenZWave Manager object. */ class OPENZWAVE_EXPORT Options { public: enum OptionType { OptionType_Invalid = 0, OptionType_Bool, OptionType_Int, OptionType_String }; /** * Creates an object to manage the program options. * \param _configPath a string containing the path to the OpenZWave library config * folder, which contains XML descriptions of Z-Wave manufacturers and products. * \param _userPath a string containing the path to the application's user data * folder where the OpenZWave should store the Z-Wave network configuration and state. * The _userPath is also the folder where OpenZWave will look for the file Options.xml * which contains program option values. The file should be in the form outlined below, * with one or more Option elements containing a name and value attribute. Multiple * values with the same option name should be listed separately. Note that option names * are case insensitive. * \code * * * * \endcode * \param _commandLine a string containing the program's command line options. * Command line options are parsed after the options.xml file, and so take precedence. * Options are identified by a leading -- (two minus signs). The following items * in the string are treated as values for this option, until the next -- is * reached. For boolean options only, it is possible to omit the value, in which case * the value is assumed to be "true". Note that option names are case insensitive, and * that option values should be separated by a space. * \return Pointer to the newly created Options object. * \see Get, Destroy, AddOption, GetOptionAs, Lock */ static Options* Create(string const& _configPath, string const& _userPath, string const& _commandLine); /** * Deletes the Options and cleans up any associated objects. * The application is responsible for destroying the Options object, * but this must not be done until after the Manager object has been * destroyed. * \param _options Pointer to the Options object to be destroyed. * \return true if the Options object was destroyed. If the manager * object still exists, this call will return false. * \see Create, Get */ static bool Destroy(); /** * Gets a pointer to the Options singleton object. * \return a pointer to the Options singleton object. * \see Create, Destroy */ static Options* Get(); /** * Locks the options. * Reads in option values from the XML options file and command line string and * marks the options as locked. Once locked, no more calls to AddOption * can be made. * The options must be locked before the Manager::Create method is called. * \see AddOption */ bool Lock(); /** * Add a boolean option to the program. * Adds an option to the program whose value can then be read from a file or command line. * All calls to AddOptionInt must be made before Lock. * \param _name the name of the option. Option names are case insensitive and must be unique. * \param _default the default value for this option. * \see GetOptionAsBool */ bool AddOptionBool(string const& _name, bool const _default); /** * Add an integer option to the program. * Adds an option to the program whose value can then be read from a file or command line. * All calls to AddOptionInt must be made before Lock. * \param _name the name of the option. Option names are case insensitive and must be unique. * \param _default the default value for this option. * \see GetOptionAsInt */ bool AddOptionInt(string const& _name, int32 const _default); /** * Add a string option to the program. * Adds an option to the program whose value can then be read from a file or command line. * All calls to AddOptionString must be made before Lock. * \param _name the name of the option. Option names are case insensitive and must be unique. * \param _default the default value for this option. * \param _append Setting append to true will cause values read from the command line * or XML file to be concatenated into a comma delimited list. If _append is false, * newer values will overwrite older ones. * \see GetOptionAsString */ bool AddOptionString(string const& _name, string const& _default, bool const _append); /** * Get the value of a boolean option. * \param _name the name of the option. Option names are case insensitive. * \param o_value a pointer to the item that will be filled with the option value. * \return true if the option value was fetched successfully, false if the * option does not exist, or does not contain a boolean value * \see AddOptionBool, GetOptionType */ bool GetOptionAsBool(string const& _name, bool* o_value); /** * Get the value of an integer option. * \param _name the name of the option. Option names are case insensitive. * \param o_value a pointer to the item that will be filled with the option value. * \return true if the option value was fetched successfully, false if the * option does not exist, or does not contain an integer value * \see AddOptionInt, GetOptionType */ bool GetOptionAsInt(string const& _name, int32* o_value); /** * Get the value of a string option. * \param _name the name of the option. Option names are case insensitive. * \param o_value a pointer to the item that will be filled with the option value. * \return true if the option value was fetched successfully, false if the * option does not exist, or does not contain a string value * \see AddOptionString, GetOptionType */ bool GetOptionAsString(string const& _name, string* o_value); /** * Get the type of value stored in an option. * \param _name the name of the option. Option names are case insensitive. * \return An enum value representing the type of the option value. If the * option does not exist, OptionType_Invalid is returned. * \see GetOptionAsBool, GetOptionAsInt, GetOptionAsString */ OptionType GetOptionType(string const& _name); /** * Test whether the options have been locked. * \return true if the options have been locked. * \see Lock */ bool AreLocked() const { return m_locked; } private: class Option { friend class Options; public: Option(string const& _name) : m_name(_name), m_append(false) { } bool SetValueFromString(string const& _value); Options::OptionType m_type; string m_name; bool m_valueBool; int32 m_valueInt; string m_valueString; bool m_append; }; Options(string const& _configPath, string const& _userPath, string const& _commandLine); // Constructor, to be called only via the static Create method. ~Options(); // Destructor, to be called only via the static Destroy method. bool ParseOptionsString(string const& _options); // Parse a string containing program options, such as a command line. bool ParseOptionsXML(string const& _filename); // Parse an XML file containing program options. Option* AddOption(string const& _name); // check lock and create (or open existing) option Option* Find(string const& _name); map m_options; // Map of option names to values. string m_xml; // Path to XML options file. string m_commandLine; // String containing command line options. string m_SystemPath; string m_LocalPath; bool m_locked; // If true, the options are final and AddOption can no longer be called. static Options* s_instance; }; } // namespace OpenZWave #endif // _Options_H openzwave-1.6.1914/cpp/src/Driver.cpp0000644000175200017520000073343114032142455014243 00000000000000//----------------------------------------------------------------------------- // // Driver.cpp // // Communicates with a Z-Wave network // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "Driver.h" #include "Options.h" #include "Manager.h" #include "Node.h" #include "Msg.h" #include "Notification.h" #include "Scene.h" #include "ZWSecurity.h" #include "DNSThread.h" #include "TimerThread.h" #include "Http.h" #include "ManufacturerSpecificDB.h" #include "platform/Event.h" #include "platform/Mutex.h" #include "platform/SerialController.h" #ifdef USE_HID #ifdef WINRT #include "platform/winRT/HidControllerWinRT.h" #else #include "platform/HidController.h" #endif #endif #include "platform/Thread.h" #include "platform/Log.h" #include "platform/TimeStamp.h" #include "command_classes/CommandClasses.h" #include "command_classes/ApplicationStatus.h" #include "command_classes/ControllerReplication.h" #include "command_classes/Security.h" #include "command_classes/WakeUp.h" #include "command_classes/SwitchAll.h" #include "command_classes/ManufacturerSpecific.h" #include "command_classes/NoOperation.h" #include "value_classes/ValueID.h" #include "value_classes/Value.h" #include "value_classes/ValueStore.h" #include "tinyxml.h" #include "Utils.h" #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) # include #elif defined _WIN32 # include #define sleep(x) Sleep(1000 * x) #endif #include #include #include #include using namespace OpenZWave; // Version numbering for saved configurations. Any change that will invalidate // previously saved configurations must be accompanied by an increment to the // version number, and a comment explaining the date of, and reason for, the change. // // 01: 12-31-2010 - Introduced config version numbering due to ValueID format change. // 02: 01-12-2011 - Command class m_afterMark sense corrected, and attribute named to match. // 03: 08-04-2011 - Changed command class instance handling for non-sequential MultiChannel endpoints. // 04: 12-07-2019 - Changed Interview Order // 05: 10-07-2020 - Duration ValueID's changed from Byte to Int. Invalidate Any previous caches. uint32 const c_configVersion = 5; static char const* c_libraryTypeNames[] = { "Unknown", // library type 0 "Static Controller", // library type 1 "Controller", // library type 2 "Enhanced Slave", // library type 3 "Slave", // library type 4 "Installer", // library type 5 "Routing Slave", // library type 6 "Bridge Controller", // library type 7 "Device Under Test" // library type 8 }; static char const* c_controllerCommandNames[] = { "None", "Add Device", "Create New Primary", "Receive Configuration", "Remove Device", "Remove Failed Node", "Has Node Failed", "Replace Failed Node", "Transfer Primary Role", "Request Network Update", "Request Node Neighbor Update", "Assign Return Route", "Delete All Return Routes", "Send Node Information", "Replication Send", "Create Button", "Delete Button" }; static char const* c_sendQueueNames[] = { "Command", "NoOp", "Controller", "WakeUp", "Send", "Query", "Poll" }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Driver::Driver(string const& _controllerPath, ControllerInterface const& _interface) : m_driverThread(new Internal::Platform::Thread("driver")), m_dns(new Internal::DNSThread(this)), m_dnsThread(new Internal::Platform::Thread("dns")), m_initMutex(new Internal::Platform::Mutex()), m_exit(false), m_init(false), m_awakeNodesQueried(false), m_allNodesQueried(false), m_notifytransactions(false), m_timer(new Internal::TimerThread(this)), m_timerThread(new Internal::Platform::Thread("timer")), m_controllerInterfaceType(_interface), m_controllerPath(_controllerPath), m_controller( NULL), m_homeId(0), m_libraryVersion(""), m_libraryTypeName(""), m_libraryType(0), m_manufacturerId(0), m_productType(0), m_productId(0), m_initVersion(0), m_initCaps(0), m_controllerCaps(0), m_Controller_nodeId(0), m_nodeMutex(new Internal::Platform::Mutex()), m_controllerReplication( NULL), m_transmitOptions( TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE | TRANSMIT_OPTION_EXPLORE), m_waitingForAck(false), m_expectedCallbackId(0), m_expectedReply(0), m_expectedCommandClassId( 0), m_expectedNodeId(0), m_pollThread(new Internal::Platform::Thread("poll")), m_pollMutex(new Internal::Platform::Mutex()), m_pollInterval(0), m_bIntervalBetweenPolls(false), // if set to true (via SetPollInterval), the pollInterval will be interspersed between each poll (so a much smaller m_pollInterval like 100, 500, or 1,000 may be appropriate) m_currentControllerCommand( NULL), m_SUCNodeId(0), m_controllerResetEvent( NULL), m_sendMutex(new Internal::Platform::Mutex()), m_currentMsg( NULL), m_virtualNeighborsReceived(false), m_notificationsEvent(new Internal::Platform::Event()), m_SOFCnt(0), m_ACKWaiting(0), m_readAborts(0), m_badChecksum(0), m_readCnt(0), m_writeCnt(0), m_CANCnt(0), m_NAKCnt(0), m_ACKCnt(0), m_OOFCnt(0), m_dropped(0), m_retries(0), m_callbacks(0), m_badroutes(0), m_noack(0), m_netbusy(0), m_notidle(0), m_txverified( 0), m_nondelivery(0), m_routedbusy(0), m_broadcastReadCnt(0), m_broadcastWriteCnt(0), AuthKey(0), EncryptKey(0), m_nonceReportSent(0), m_nonceReportSentAttempt(0), m_queueMsgEvent(new Internal::Platform::Event()), m_eventMutex(new Internal::Platform::Mutex()) { // set a timestamp to indicate when this driver started Internal::Platform::TimeStamp m_startTime; // Create the message queue events for (int32 i = 0; i < MsgQueue_Count; ++i) { m_queueEvent[i] = new Internal::Platform::Event(); } // Clear the nodes array memset(m_nodes, 0, sizeof(Node*) * 256); // Clear the virtual neighbors array memset(m_virtualNeighbors, 0, NUM_NODE_BITFIELD_BYTES); // Initialize the Network Keys initNetworkKeys(false); #ifdef USE_HID if( ControllerInterface_Hid == _interface ) { m_controller = new Internal::Platform::HidController(); } else #endif { m_controller = new Internal::Platform::SerialController(); } m_controller->SetSignalThreshold(1); Options::Get()->GetOptionAsBool("NotifyTransactions", &m_notifytransactions); Options::Get()->GetOptionAsInt("PollInterval", &m_pollInterval); Options::Get()->GetOptionAsBool("IntervalBetweenPolls", &m_bIntervalBetweenPolls); m_httpClient = new Internal::HttpClient(this); m_mfs = Internal::ManufacturerSpecificDB::Create(); CheckMFSConfigRevision(); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- Driver::~Driver() { /* Signal that we are going away... so at least Apps know... */ Notification* notification = new Notification(Notification::Type_DriverRemoved); notification->SetHomeAndNodeIds(m_homeId, 0); QueueNotification(notification); NotifyWatchers(); // append final driver stats output to the log file LogDriverStatistics(); // Save the driver config before deleting anything else bool save; if (Options::Get()->GetOptionAsBool("SaveConfiguration", &save)) { if (save) { WriteCache(); Internal::Scene::WriteXML("zwscene.xml"); } } // The order of the statements below has been achieved by mitigating freed memory //references using a memory allocator checker. Do not rearrange unless you are //certain memory won't be referenced out of order. --Greg Satz, April 2010 m_initMutex->Lock(); m_exit = true; m_initMutex->Unlock(); m_pollThread->Stop(); m_pollThread->Release(); m_dnsThread->Stop(); m_dnsThread->Release(); m_driverThread->Stop(); m_driverThread->Release(); m_timerThread->Stop(); m_timerThread->Release(); m_sendMutex->Release(); m_controller->Close(); m_controller->Release(); m_initMutex->Release(); if (m_currentMsg != NULL) { RemoveCurrentMsg(); } // Clear the node data { Internal::LockGuard LG(m_nodeMutex); for (int i = 0; i < 256; ++i) { if (GetNodeUnsafe(i)) { delete m_nodes[i]; m_nodes[i] = NULL; Notification* notification = new Notification(Notification::Type_NodeRemoved); notification->SetHomeAndNodeIds(m_homeId, i); QueueNotification(notification); } } } // Don't release until all nodes have removed their poll values m_pollMutex->Release(); // Clear the send Queue for (int32 i = 0; i < MsgQueue_Count; ++i) { while (!m_msgQueue[i].empty()) { MsgQueueItem const& item = m_msgQueue[i].front(); if (MsgQueueCmd_SendMsg == item.m_command) { delete item.m_msg; } else if (MsgQueueCmd_Controller == item.m_command) { delete item.m_cci; } m_msgQueue[i].pop_front(); } m_queueEvent[i]->Release(); } /* Doing our Notification Call back here in the destructor is just asking for trouble * as there is a good chance that the application will do some sort of GetDriver() supported * method on the Manager Class, which by this time, most of the OZW Classes associated with the * Driver class is 99% destructed. (mainly nodes, which cascade to CC, which cascade to ValueID * classes etc). We might need a flag around the Manager::GetDriver() class that stops applications * from getting a half destructed Driver Reference, but still retain a Internal GetDriver() method * that can return half destructed Driver references for internal classes (as per Greg's note above) */ bool notify; if (Options::Get()->GetOptionAsBool("NotifyOnDriverUnload", ¬ify)) { if (notify) { NotifyWatchers(); } } list::iterator nit = m_notifications.begin(); while (nit != m_notifications.end()) { Notification* notification = m_notifications.front(); m_notifications.pop_front(); delete notification; nit = m_notifications.begin(); } if (m_controllerReplication) delete m_controllerReplication; m_notificationsEvent->Release(); m_nodeMutex->Release(); m_queueMsgEvent->Release(); m_eventMutex->Release(); delete this->AuthKey; delete this->EncryptKey; delete this->m_httpClient; delete this->m_timer; delete this->m_dns; } //----------------------------------------------------------------------------- // // Start the driver thread //----------------------------------------------------------------------------- void Driver::Start() { // Start the thread that will handle communications with the Z-Wave network m_driverThread->Start(Driver::DriverThreadEntryPoint, this); m_dnsThread->Start(Internal::DNSThread::DNSThreadEntryPoint, m_dns); m_timerThread->Start(Internal::TimerThread::TimerThreadEntryPoint, m_timer); } //----------------------------------------------------------------------------- // // Entry point of the thread for creating and managing the worker threads //----------------------------------------------------------------------------- void Driver::DriverThreadEntryPoint(Internal::Platform::Event* _exitEvent, void* _context) { Driver* driver = (Driver*) _context; if (driver) { driver->DriverThreadProc(_exitEvent); } } //----------------------------------------------------------------------------- // // Create and manage the worker threads //----------------------------------------------------------------------------- void Driver::DriverThreadProc(Internal::Platform::Event* _exitEvent) { #define WAITOBJECTCOUNT 11 uint32 attempts = 0; bool mfsisReady = false; while (true) { if (Init(attempts)) { // Driver has been initialised Internal::Platform::Wait* waitObjects[WAITOBJECTCOUNT]; waitObjects[0] = _exitEvent; // Thread must exit. waitObjects[1] = m_notificationsEvent; // Notifications waiting to be sent. waitObjects[2] = m_queueMsgEvent; ; // a DNS and HTTP Event waitObjects[3] = m_controller; // Controller has received data. waitObjects[4] = m_queueEvent[MsgQueue_Command]; // A controller command is in progress. waitObjects[5] = m_queueEvent[MsgQueue_NoOp]; // Send device probes and diagnostics messages waitObjects[6] = m_queueEvent[MsgQueue_Controller]; // A multi-part controller command is in progress waitObjects[7] = m_queueEvent[MsgQueue_WakeUp]; // A node has woken. Pending messages should be sent. waitObjects[8] = m_queueEvent[MsgQueue_Send]; // Ordinary requests to be sent. waitObjects[9] = m_queueEvent[MsgQueue_Query]; // Node queries are pending. waitObjects[10] = m_queueEvent[MsgQueue_Poll]; // Poll request is waiting. Internal::Platform::TimeStamp retryTimeStamp; int retryTimeout = RETRY_TIMEOUT; Options::Get()->GetOptionAsInt("RetryTimeout", &retryTimeout); //retryTimeout = RETRY_TIMEOUT * 10; while (true) { Log::Write(LogLevel_StreamDetail, " Top of DriverThreadProc loop."); uint32 count = WAITOBJECTCOUNT; int32 timeout = Internal::Platform::Wait::Timeout_Infinite; // if the ManufacturerDB class is setting up, we can't do anything yet if (mfsisReady == false) { count = 3; // If we're waiting for a message to complete, we can only // handle incoming data, notifications, DNS/HTTP and exit events. } else if (m_waitingForAck || m_expectedCallbackId || m_expectedReply) { count = 4; timeout = m_waitingForAck ? ACK_TIMEOUT : retryTimeStamp.TimeRemaining(); if (timeout < 0) { timeout = 0; } } else if (m_currentControllerCommand != NULL) { count = 7; } else { Log::QueueClear(); // clear the log queue when starting a new message } // Wait for something to do int32 res = Internal::Platform::Wait::Multiple(waitObjects, count, timeout); switch (res) { case -1: { // Wait has timed out - time to resend if (m_currentMsg != NULL && !m_currentMsg->isResendDuetoCANorNAK()) { Notification* notification = new Notification(Notification::Type_Notification); notification->SetHomeAndNodeIds(m_homeId, m_currentMsg->GetTargetNodeId()); notification->SetNotification(Notification::Code_Timeout); QueueNotification(notification); } if (WriteMsg("Wait Timeout")) { retryTimeStamp.SetTime(retryTimeout); } break; } case 0: { // Exit has been signalled m_initMutex->Lock(); m_exit = true; m_initMutex->Unlock(); return; } case 1: { // Notifications are waiting to be sent NotifyWatchers(); break; } case 2: { // a DNS or HTTP Event has occurred ProcessEventMsg(); if (mfsisReady == false && m_mfs->isReady()) { Notification* notification = new Notification(Notification::Type_ManufacturerSpecificDBReady); QueueNotification(notification); mfsisReady = true; } break; } case 3: { // Data has been received ReadMsg(); break; } default: { // All the other events are sending message queue items if (WriteNextMsg((MsgQueue) (res - 4))) { retryTimeStamp.SetTime(retryTimeout); } break; } } } } ++attempts; uint32 maxAttempts = 0; Options::Get()->GetOptionAsInt("DriverMaxAttempts", (int32 *) &maxAttempts); if (maxAttempts && (attempts >= maxAttempts)) { Manager::Get()->Manager::SetDriverReady(this, false); NotifyWatchers(); break; } if (attempts < 25) { // Retry every 5 seconds for the first two minutes if (Internal::Platform::Wait::Single(_exitEvent, 5000) == 0) { // Exit signalled. m_initMutex->Lock(); m_exit = true; m_initMutex->Unlock(); return; } } else { // Retry every 30 seconds after that if (Internal::Platform::Wait::Single(_exitEvent, 30000) == 0) { // Exit signalled. m_initMutex->Lock(); m_exit = true; m_initMutex->Unlock(); return; } } } } //----------------------------------------------------------------------------- // // Initialize the controller //----------------------------------------------------------------------------- bool Driver::Init(uint32 _attempts) { m_initMutex->Lock(); if (m_exit) { m_initMutex->Unlock(); return false; } m_Controller_nodeId = 255; m_waitingForAck = false; // Open the controller Log::Write(LogLevel_Info, " Opening controller %s", m_controllerPath.c_str()); if (!m_controller->Open(m_controllerPath)) { Log::Write(LogLevel_Warning, "WARNING: Failed to init the controller (attempt %d)", _attempts); m_initMutex->Unlock(); return false; } // Controller opened successfully, so we need to start all the worker threads m_pollThread->Start(Driver::PollThreadEntryPoint, this); // Send a NAK to the ZWave device uint8 nak = NAK; m_controller->Write(&nak, 1); // Purge any Messages in the Serial Buffer m_controller->Purge(); /* this kicks of the Init Sequence to get the Controller in shape. */ SendMsg(new Internal::Msg("FUNC_ID_ZW_GET_VERSION", 0xff, REQUEST, FUNC_ID_ZW_GET_VERSION, false), Driver::MsgQueue_Command); //If we ever want promiscuous mode uncomment this code. //Msg* msg = new Msg( "FUNC_ID_ZW_SET_PROMISCUOUS_MODE", 0xff, REQUEST, FUNC_ID_ZW_SET_PROMISCUOUS_MODE, false, false ); //msg->Append( 0xff ); //SendMsg( msg ); m_initMutex->Unlock(); // Init successful return true; } //----------------------------------------------------------------------------- // // Clean up any messages to a node //----------------------------------------------------------------------------- void Driver::RemoveQueues(uint8 const _nodeId) { if (m_currentMsg != NULL && m_currentMsg->GetTargetNodeId() == _nodeId) { RemoveCurrentMsg(); } // Clear the send Queue for (int32 i = 0; i < MsgQueue_Count; ++i) { list::iterator it = m_msgQueue[i].begin(); while (it != m_msgQueue[i].end()) { bool remove = false; MsgQueueItem const& item = *it; if (MsgQueueCmd_SendMsg == item.m_command && _nodeId == item.m_msg->GetTargetNodeId()) { delete item.m_msg; remove = true; } else if (MsgQueueCmd_QueryStageComplete == item.m_command && _nodeId == item.m_nodeId) { remove = true; } else if (MsgQueueCmd_Controller == item.m_command && _nodeId == item.m_cci->m_controllerCommandNode && m_currentControllerCommand != item.m_cci) { delete item.m_cci; remove = true; } else if (MsgQueueCmd_ReloadNode == item.m_command && _nodeId == item.m_nodeId) { remove = true; } if (remove) { it = m_msgQueue[i].erase(it); } else { ++it; } } if (m_msgQueue[i].empty()) { m_queueEvent[i]->Reset(); } } } //----------------------------------------------------------------------------- // Configuration //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Read our configuration from an XML document //----------------------------------------------------------------------------- bool Driver::ReadCache() { char str[32]; int32 intVal; // Load the XML document that contains the driver configuration string userPath; Options::Get()->GetOptionAsString("UserPath", &userPath); snprintf(str, sizeof(str), "ozwcache_0x%08x.xml", m_homeId); string filename = userPath + string(str); TiXmlDocument doc; doc.SetCondenseWhiteSpace(false); if (!doc.LoadFile(filename.c_str(), TIXML_ENCODING_UTF8)) { return false; } doc.SetUserData((void *) filename.c_str()); TiXmlElement const* driverElement = doc.RootElement(); char const *xmlns = driverElement->Attribute("xmlns"); if (strcmp(xmlns, "https://github.com/OpenZWave/open-zwave")) { Log::Write(LogLevel_Warning, "Invalid XML Namespace. Ignoring %s", filename.c_str()); return false; } // Version if (TIXML_SUCCESS != driverElement->QueryIntAttribute("version", &intVal) || (uint32) intVal != c_configVersion) { Log::Write(LogLevel_Warning, "WARNING: Driver::ReadCache - %s is from an older version of OpenZWave and cannot be loaded.", filename.c_str()); return false; } // Capabilities if (TIXML_SUCCESS == driverElement->QueryIntAttribute("revision", &intVal)) { m_mfs->setLatestRevision(intVal); } // Home ID char const* homeIdStr = driverElement->Attribute("home_id"); if (homeIdStr) { char* p; uint32 homeId = (uint32) strtoul(homeIdStr, &p, 0); if (homeId != m_homeId) { Log::Write(LogLevel_Warning, "WARNING: Driver::ReadCache - Home ID in file %s is incorrect", filename.c_str()); return false; } } else { Log::Write(LogLevel_Warning, "WARNING: Driver::ReadCache - Home ID is missing from file %s", filename.c_str()); return false; } // Node ID if (TIXML_SUCCESS == driverElement->QueryIntAttribute("node_id", &intVal)) { if ((uint8) intVal != m_Controller_nodeId) { Log::Write(LogLevel_Warning, "WARNING: Driver::ReadCache - Controller Node ID in file %s is incorrect", filename.c_str()); return false; } } else { Log::Write(LogLevel_Warning, "WARNING: Driver::ReadCache - Node ID is missing from file %s", filename.c_str()); return false; } // Capabilities if (TIXML_SUCCESS == driverElement->QueryIntAttribute("api_capabilities", &intVal)) { m_initCaps = (uint8) intVal; } if (TIXML_SUCCESS == driverElement->QueryIntAttribute("controller_capabilities", &intVal)) { m_controllerCaps = (uint8) intVal; } // Poll Interval if (TIXML_SUCCESS == driverElement->QueryIntAttribute("poll_interval", &intVal)) { m_pollInterval = intVal; } // Poll Interval--between polls or period for polling the entire pollList? char const* cstr = driverElement->Attribute("poll_interval_between"); if (cstr) { m_bIntervalBetweenPolls = !strcmp(cstr, "true"); } // Read the nodes Internal::LockGuard LG(m_nodeMutex); TiXmlElement const* nodeElement = driverElement->FirstChildElement(); while (nodeElement) { char const* str = nodeElement->Value(); if (str && !strcmp(str, "Node")) { // Get the node Id from the XML if (TIXML_SUCCESS == nodeElement->QueryIntAttribute("id", &intVal)) { uint8 nodeId = (uint8) intVal; Node* node = new Node(m_homeId, nodeId); m_nodes[nodeId] = node; Notification* notification = new Notification(Notification::Type_NodeAdded); notification->SetHomeAndNodeIds(m_homeId, nodeId); QueueNotification(notification); // Read the rest of the node configuration from the XML node->ReadXML(nodeElement); } } nodeElement = nodeElement->NextSiblingElement(); } LG.Unlock(); // restore the previous state (for now, polling) for the nodes/values just retrieved for (int i = 0; i < 256; i++) { if (m_nodes[i] != NULL) { Internal::VC::ValueStore* vs = m_nodes[i]->m_values; for (Internal::VC::ValueStore::Iterator it = vs->Begin(); it != vs->End(); ++it) { Internal::VC::Value* value = it->second; if (value->m_pollIntensity != 0) EnablePoll(value->GetID(), value->m_pollIntensity); } } } return true; } //----------------------------------------------------------------------------- // // Write ourselves to an XML document //----------------------------------------------------------------------------- void Driver::WriteCache() { char str[32]; if (!m_homeId) { Log::Write(LogLevel_Warning, "WARNING: Tried to write driver config with no home ID set"); return; } if (m_exit) { Log::Write(LogLevel_Info, "Skipping Cache Save as we are shutting down"); return; } Log::Write(LogLevel_Info, "Saving Cache"); // Create a new XML document to contain the driver configuration TiXmlDocument doc; TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "utf-8", ""); TiXmlElement* driverElement = new TiXmlElement("Driver"); doc.LinkEndChild(decl); doc.LinkEndChild(driverElement); driverElement->SetAttribute("xmlns", "https://github.com/OpenZWave/open-zwave"); snprintf(str, sizeof(str), "%d", c_configVersion); driverElement->SetAttribute("version", str); snprintf(str, sizeof(str), "%d", GetManufacturerSpecificDB()->getRevision()); driverElement->SetAttribute("revision", str); snprintf(str, sizeof(str), "0x%.8x", m_homeId); driverElement->SetAttribute("home_id", str); snprintf(str, sizeof(str), "%d", m_Controller_nodeId); driverElement->SetAttribute("node_id", str); snprintf(str, sizeof(str), "%d", m_initCaps); driverElement->SetAttribute("api_capabilities", str); snprintf(str, sizeof(str), "%d", m_controllerCaps); driverElement->SetAttribute("controller_capabilities", str); snprintf(str, sizeof(str), "%d", m_pollInterval); driverElement->SetAttribute("poll_interval", str); snprintf(str, sizeof(str), "%s", m_bIntervalBetweenPolls ? "true" : "false"); driverElement->SetAttribute("poll_interval_between", str); { Internal::LockGuard LG(m_nodeMutex); for (int i = 0; i < 256; ++i) { if (m_nodes[i]) { if (m_nodes[i]->GetCurrentQueryStage() >= Node::QueryStage_CacheLoad) { m_nodes[i]->WriteXML(driverElement); Log::Write(LogLevel_Info, i, "Cache Save for Node %d as its QueryStage_CacheLoad", i); } else { Log::Write(LogLevel_Info, i, "Skipping Cache Save for Node %d as its not past QueryStage_CacheLoad", i); } } } } string userPath; Options::Get()->GetOptionAsString("UserPath", &userPath); snprintf(str, sizeof(str), "ozwcache_0x%08x.xml", m_homeId); string filename = userPath + string(str); doc.SaveFile(filename.c_str()); } //----------------------------------------------------------------------------- // Controller //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Returns a pointer to the requested node without locking. // Only to be used by main thread code. //----------------------------------------------------------------------------- Node* Driver::GetNodeUnsafe(uint8 _nodeId) { if (Node* node = m_nodes[_nodeId]) { return node; } return NULL; } //----------------------------------------------------------------------------- // // Locks the nodes and returns a pointer to the requested one //----------------------------------------------------------------------------- Node* Driver::GetNode(uint8 _nodeId) { if (m_nodeMutex->IsSignalled()) { Log::Write(LogLevel_Error, _nodeId, "Driver Thread is Not Locked during Call to GetNode"); return NULL; } if (Node* node = m_nodes[_nodeId]) { return node; } return NULL; } //----------------------------------------------------------------------------- // Sending Z-Wave messages //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Queue an item on the query queue that indicates a stage is complete //----------------------------------------------------------------------------- void Driver::SendQueryStageComplete(uint8 const _nodeId, Node::QueryStage const _stage) { MsgQueueItem item; item.m_command = MsgQueueCmd_QueryStageComplete; item.m_nodeId = _nodeId; item.m_queryStage = _stage; item.m_retry = false; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { if (!node->IsListeningDevice()) { if (Internal::CC::WakeUp* wakeUp = static_cast(node->GetCommandClass(Internal::CC::WakeUp::StaticGetCommandClassId()))) { if (!wakeUp->IsAwake()) { // If the message is for a sleeping node, we queue it in the node itself. Log::Write(LogLevel_Info, ""); Log::Write(LogLevel_Detail, node->GetNodeId(), "Queuing (%s) Query Stage Complete (%s)", c_sendQueueNames[MsgQueue_WakeUp], node->GetQueryStageName(_stage).c_str()); wakeUp->QueueMsg(item); return; } } } // Non-sleeping node Log::Write(LogLevel_Detail, node->GetNodeId(), "Queuing (%s) Query Stage Complete (%s)", c_sendQueueNames[MsgQueue_Query], node->GetQueryStageName(_stage).c_str()); m_sendMutex->Lock(); m_msgQueue[MsgQueue_Query].push_back(item); m_queueEvent[MsgQueue_Query]->Set(); m_sendMutex->Unlock(); } } //----------------------------------------------------------------------------- // // Request the current stage will be repeated //----------------------------------------------------------------------------- void Driver::RetryQueryStageComplete(uint8 const _nodeId, Node::QueryStage const _stage) { MsgQueueItem item; item.m_command = MsgQueueCmd_QueryStageComplete; item.m_nodeId = _nodeId; item.m_queryStage = _stage; m_sendMutex->Lock(); for (list::iterator it = m_msgQueue[MsgQueue_Query].begin(); it != m_msgQueue[MsgQueue_Query].end(); ++it) { if (*it == item) { (*it).m_retry = true; break; } } m_sendMutex->Unlock(); } //----------------------------------------------------------------------------- // // Queue a message to be sent to the Z-Wave PC Interface //----------------------------------------------------------------------------- void Driver::SendMsg(Internal::Msg* _msg, MsgQueue const _queue) { MsgQueueItem item; item.m_command = MsgQueueCmd_SendMsg; item.m_msg = _msg; /* make sure the HomeId is Set on this message */ _msg->SetHomeId(m_homeId); _msg->Finalize(); { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_msg->GetTargetNodeId())) { /* if the node Supports the Security Class - check if this message is meant to be encapsulated */ if (node->GetCommandClass(Internal::CC::Security::StaticGetCommandClassId())) { Internal::CC::CommandClass *cc = node->GetCommandClass(_msg->GetSendingCommandClass()); if ((cc) && (cc->IsSecured())) { Log::Write(LogLevel_Detail, GetNodeNumber(_msg), "Setting Encryption Flag on Message For Command Class %s", cc->GetCommandClassName().c_str()); item.m_msg->setEncrypted(); } } // If the message is for a sleeping node, we queue it in the node itself. if (!node->IsListeningDevice()) { if (Internal::CC::WakeUp* wakeUp = static_cast(node->GetCommandClass(Internal::CC::WakeUp::StaticGetCommandClassId()))) { if (!wakeUp->IsAwake()) { Log::Write(LogLevel_Detail, ""); // Handle saving multi-step controller commands if (m_currentControllerCommand != NULL) { Log::Write(LogLevel_Detail, GetNodeNumber(_msg), "Queuing (%s) %s", c_sendQueueNames[MsgQueue_Controller], c_controllerCommandNames[m_currentControllerCommand->m_controllerCommand]); delete _msg; item.m_command = MsgQueueCmd_Controller; item.m_cci = new ControllerCommandItem(*m_currentControllerCommand); item.m_msg = NULL; UpdateControllerState(ControllerState_Sleeping); } else { Log::Write(LogLevel_Detail, GetNodeNumber(_msg), "Queuing (%s) %s", c_sendQueueNames[MsgQueue_WakeUp], _msg->GetAsString().c_str()); } wakeUp->QueueMsg(item); return; } } } } } Log::Write(LogLevel_Detail, GetNodeNumber(_msg), "Queuing (%s) %s", c_sendQueueNames[_queue], _msg->GetAsString().c_str()); m_sendMutex->Lock(); m_msgQueue[_queue].push_back(item); m_queueEvent[_queue]->Set(); m_sendMutex->Unlock(); } //----------------------------------------------------------------------------- // // Transmit a queued message to the Z-Wave controller //----------------------------------------------------------------------------- bool Driver::WriteNextMsg(MsgQueue const _queue) { // There are messages to send, so get the one at the front of the queue m_sendMutex->Lock(); MsgQueueItem item = m_msgQueue[_queue].front(); if (MsgQueueCmd_SendMsg == item.m_command) { // Send a message m_currentMsg = item.m_msg; m_currentMsgQueueSource = _queue; m_msgQueue[_queue].pop_front(); if (m_msgQueue[_queue].empty()) { m_queueEvent[_queue]->Reset(); } if (m_nonceReportSent > 0) { MsgQueueItem item_new; item_new.m_command = MsgQueueCmd_SendMsg; item_new.m_nodeId = item.m_msg->GetTargetNodeId(); item_new.m_retry = item.m_retry; item_new.m_msg = new Internal::Msg(*item.m_msg); m_msgQueue[_queue].push_front(item_new); m_queueEvent[_queue]->Set(); } m_sendMutex->Unlock(); return WriteMsg("WriteNextMsg"); } else if (MsgQueueCmd_QueryStageComplete == item.m_command) { // Move to the next query stage m_currentMsg = NULL; Node::QueryStage stage = item.m_queryStage; m_msgQueue[_queue].pop_front(); if (m_msgQueue[_queue].empty()) { m_queueEvent[_queue]->Reset(); } m_sendMutex->Unlock(); Node* node = GetNodeUnsafe(item.m_nodeId); if (node != NULL) { Log::Write(LogLevel_Detail, node->GetNodeId(), "Query Stage Complete (%s)", node->GetQueryStageName(stage).c_str()); if (!item.m_retry) { node->QueryStageComplete(stage); } node->AdvanceQueries(); return true; } } else if (MsgQueueCmd_Controller == item.m_command) { // Run a multi-step controller command m_currentControllerCommand = item.m_cci; m_sendMutex->Unlock(); // Figure out if done with command if (m_currentControllerCommand->m_controllerCommandDone) { m_sendMutex->Lock(); m_msgQueue[_queue].pop_front(); if (m_msgQueue[_queue].empty()) { m_queueEvent[_queue]->Reset(); } m_sendMutex->Unlock(); if (m_currentControllerCommand->m_controllerCallback) { m_currentControllerCommand->m_controllerCallback(m_currentControllerCommand->m_controllerState, m_currentControllerCommand->m_controllerReturnError, m_currentControllerCommand->m_controllerCallbackContext); } m_sendMutex->Lock(); delete m_currentControllerCommand; m_currentControllerCommand = NULL; m_sendMutex->Unlock(); } else if (m_currentControllerCommand->m_controllerState == ControllerState_Normal) { DoControllerCommand(); } else if (m_currentControllerCommand->m_controllerStateChanged) { if (m_currentControllerCommand->m_controllerCallback) { m_currentControllerCommand->m_controllerCallback(m_currentControllerCommand->m_controllerState, m_currentControllerCommand->m_controllerReturnError, m_currentControllerCommand->m_controllerCallbackContext); } m_currentControllerCommand->m_controllerStateChanged = false; } else { Log::Write(LogLevel_Info, "WriteNextMsg Controller nothing to do"); m_sendMutex->Lock(); m_queueEvent[_queue]->Reset(); m_sendMutex->Unlock(); } return true; } else if (MsgQueueCmd_ReloadNode == item.m_command) { m_msgQueue[_queue].pop_front(); if (m_msgQueue[_queue].empty()) { m_queueEvent[_queue]->Reset(); } m_sendMutex->Unlock(); Log::Write(LogLevel_Info, item.m_nodeId, "Reloading Sleeping Node"); /* this will reload the Node, ignoring any cache that exists etc */ ReloadNode(item.m_nodeId); return true; } return false; } //----------------------------------------------------------------------------- // // Transmit the current message to the Z-Wave controller //----------------------------------------------------------------------------- bool Driver::WriteMsg(string const &msg) { if (!m_currentMsg) { Log::Write(LogLevel_Detail, GetNodeNumber(m_currentMsg), "WriteMsg %s m_currentMsg=%08x", msg.c_str(), m_currentMsg); // We try not to hang when this happenes m_expectedCallbackId = 0; m_expectedCommandClassId = 0; m_expectedNodeId = 0; m_expectedReply = 0; m_waitingForAck = false; return false; } /* if this is called with m_nonceReportSent > 0 it means that we have * tried to send a NONCE report and it timed out or was NAK'd * */ uint8 attempts; uint8 nodeId; if (m_nonceReportSent > 0) { attempts = m_nonceReportSentAttempt++; nodeId = m_nonceReportSent; } else { attempts = m_currentMsg->GetSendAttempts(); nodeId = m_currentMsg->GetTargetNodeId(); } Internal::LockGuard LG(m_nodeMutex); Node* node = GetNode(nodeId); if (attempts >= m_currentMsg->GetMaxSendAttempts() || (node != NULL && !node->IsNodeAlive() && !m_currentMsg->IsNoOperation())) { if (node != NULL && !node->IsNodeAlive()) { Log::Write(LogLevel_Error, nodeId, "ERROR: Dropping command because node is presumed dead"); } else { // That's it - already tried to send GetMaxSendAttempt() times. Log::Write(LogLevel_Error, nodeId, "ERROR: Dropping command, expected response not received after %d attempt(s). Command: \"%s\"", m_currentMsg->GetMaxSendAttempts(), m_currentMsg->GetAsString().c_str()); } if (m_currentControllerCommand != NULL) { /* its a ControllerCommand that is failed */ UpdateControllerState(ControllerState_Error, ControllerError_Failed); } RemoveCurrentMsg(); m_dropped++; return false; } if ((attempts != 0) && (m_nonceReportSent == 0)) { // this is not the first attempt, so increment the callback id before sending m_currentMsg->UpdateCallbackId(); } /* XXX TODO: Minor Bug - Due to the post increament of the SendAttempts, it means our final NONCE_GET will go though * but the subsequent MSG send will fail (as the counter is incremented only upon a successful NONCE_GET, and Not a Send * */ if (m_nonceReportSent == 0) { if (m_currentMsg->isEncrypted() && !m_currentMsg->isNonceRecieved()) { m_currentMsg->SetSendAttempts(++attempts); } else if (!m_currentMsg->isEncrypted()) { m_currentMsg->SetSendAttempts(++attempts); } m_expectedCallbackId = m_currentMsg->GetCallbackId(); m_expectedCommandClassId = m_currentMsg->GetExpectedCommandClassId(); m_expectedNodeId = m_currentMsg->GetTargetNodeId(); m_expectedReply = m_currentMsg->GetExpectedReply(); m_waitingForAck = true; } string attemptsstr = ""; if (attempts > 1) { char buf[15]; snprintf(buf, sizeof(buf), "Attempt %d, ", attempts); attemptsstr = buf; m_retries++; if (node != NULL) { node->m_retries++; } } Log::Write(LogLevel_Detail, ""); if (m_nonceReportSent > 0 && node != NULL) { /* send a new NONCE report */ SendNonceKey(m_nonceReportSent, node->GenerateNonceKey()); } else if (m_currentMsg->isEncrypted()) { if (m_currentMsg->isNonceRecieved()) { Log::Write(LogLevel_Info, nodeId, "Processing (%s) Encrypted message (%sCallback ID=0x%.2x, Expected Reply=0x%.2x) - %s", c_sendQueueNames[m_currentMsgQueueSource], attemptsstr.c_str(), m_expectedCallbackId, m_expectedReply, m_currentMsg->GetAsString().c_str()); SendEncryptedMessage(); } else { Log::Write(LogLevel_Info, nodeId, "Processing (%s) Nonce Request message (%sCallback ID=0x%.2x, Expected Reply=0x%.2x)", c_sendQueueNames[m_currentMsgQueueSource], attemptsstr.c_str(), m_expectedCallbackId, m_expectedReply); SendNonceRequest(m_currentMsg->GetLogText()); } } else { Log::Write(LogLevel_Info, nodeId, "Sending (%s) message (%sCallback ID=0x%.2x, Expected Reply=0x%.2x) - %s", c_sendQueueNames[m_currentMsgQueueSource], attemptsstr.c_str(), m_expectedCallbackId, m_expectedReply, m_currentMsg->GetAsString().c_str()); uint32 bytesWritten = m_controller->Write(m_currentMsg->GetBuffer(), m_currentMsg->GetLength()); if (bytesWritten == 0) { //0 will be returned when the port is closed or something bad happened //so send notification Notification* notification = new Notification(Notification::Type_DriverFailed); notification->SetHomeAndNodeIds(m_homeId, m_currentMsg->GetTargetNodeId()); notification->SetComPort(m_controllerPath); QueueNotification(notification); NotifyWatchers(); m_driverThread->Stop(); return false; } } m_writeCnt++; if (nodeId == 0xff) { m_broadcastWriteCnt++; // not accurate since library uses 0xff for the controller too } else { if (node != NULL) { node->m_sentCnt++; node->m_sentTS.SetTime(); if (m_expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER) { Internal::CC::CommandClass *cc = node->GetCommandClass(m_expectedCommandClassId); if (cc != NULL) { cc->SentCntIncr(); } } } } return true; } //----------------------------------------------------------------------------- // // Delete the current message //----------------------------------------------------------------------------- void Driver::RemoveCurrentMsg() { Log::Write(LogLevel_Detail, GetNodeNumber(m_currentMsg), "Removing current message"); if (m_currentMsg != NULL) { delete m_currentMsg; m_currentMsg = NULL; } m_expectedCallbackId = 0; m_expectedCommandClassId = 0; m_expectedNodeId = 0; m_expectedReply = 0; m_waitingForAck = false; m_nonceReportSent = 0; m_nonceReportSentAttempt = 0; } //----------------------------------------------------------------------------- // // Move messages for a sleeping device to its wake-up queue //----------------------------------------------------------------------------- bool Driver::MoveMessagesToWakeUpQueue(uint8 const _targetNodeId, bool const _move) { // If the target node is one that goes to sleep, transfer // all messages for it to its Wake-Up queue. if (Node* node = GetNodeUnsafe(_targetNodeId)) { if (!node->IsListeningDevice() && !node->IsFrequentListeningDevice() && _targetNodeId != m_Controller_nodeId) { if (Internal::CC::WakeUp* wakeUp = static_cast(node->GetCommandClass(Internal::CC::WakeUp::StaticGetCommandClassId()))) { // Mark the node as asleep wakeUp->SetAwake(false); // If we need to save the messages if (_move) { // Move all messages for this node to the wake-up queue m_sendMutex->Lock(); // See if we are working on a controller command if (m_currentControllerCommand) { // Don't save controller message as it will be recreated RemoveCurrentMsg(); } // Then try the current message first if (m_currentMsg) { if (_targetNodeId == m_currentMsg->GetTargetNodeId()) { // This message is for the unresponsive node // We do not move any "Wake Up No More Information" // commands or NoOperations to the pending queue. if (!m_currentMsg->IsWakeUpNoMoreInformationCommand() && !m_currentMsg->IsNoOperation()) { Log::Write(LogLevel_Info, _targetNodeId, "Node not responding - moving message to Wake-Up queue: %s", m_currentMsg->GetAsString().c_str()); /* reset the sendAttempts */ m_currentMsg->SetSendAttempts(0); MsgQueueItem item; item.m_command = MsgQueueCmd_SendMsg; item.m_msg = m_currentMsg; wakeUp->QueueMsg(item); } else { delete m_currentMsg; } m_currentMsg = NULL; m_expectedCallbackId = 0; m_expectedCommandClassId = 0; m_expectedNodeId = 0; m_expectedReply = 0; m_waitingForAck = false; } } // Now the message queues for (int i = 0; i < MsgQueue_Count; ++i) { list::iterator it = m_msgQueue[i].begin(); while (it != m_msgQueue[i].end()) { bool remove = false; MsgQueueItem const& item = *it; if (MsgQueueCmd_SendMsg == item.m_command) { if (_targetNodeId == item.m_msg->GetTargetNodeId()) { // This message is for the unresponsive node // We do not move any "Wake Up No More Information" // commands or NoOperations to the pending queue. if (!item.m_msg->IsWakeUpNoMoreInformationCommand() && !item.m_msg->IsNoOperation()) { Log::Write(LogLevel_Info, item.m_msg->GetTargetNodeId(), "Node not responding - moving message to Wake-Up queue: %s", item.m_msg->GetAsString().c_str()); /* reset any SendAttempts */ item.m_msg->SetSendAttempts(0); wakeUp->QueueMsg(item); } else { delete item.m_msg; } remove = true; } } if (MsgQueueCmd_QueryStageComplete == item.m_command) { if (_targetNodeId == item.m_nodeId) { Log::Write(LogLevel_Info, _targetNodeId, "Node not responding - moving QueryStageComplete command to Wake-Up queue"); wakeUp->QueueMsg(item); remove = true; } } if (MsgQueueCmd_Controller == item.m_command) { if (_targetNodeId == item.m_cci->m_controllerCommandNode) { Log::Write(LogLevel_Info, _targetNodeId, "Node not responding - moving controller command to Wake-Up queue: %s", c_controllerCommandNames[item.m_cci->m_controllerCommand]); wakeUp->QueueMsg(item); remove = true; } } if (remove) { it = m_msgQueue[i].erase(it); } else { ++it; } } // If the queue is now empty, we need to clear its event if (m_msgQueue[i].empty()) { m_queueEvent[i]->Reset(); } } if (m_currentControllerCommand) { // Put command back on queue so it will be cleaned up UpdateControllerState(ControllerState_Sleeping); MsgQueueItem item; item.m_command = MsgQueueCmd_Controller; item.m_cci = new ControllerCommandItem(*m_currentControllerCommand); m_currentControllerCommand = item.m_cci; m_msgQueue[MsgQueue_Controller].push_back(item); m_queueEvent[MsgQueue_Controller]->Set(); } m_sendMutex->Unlock(); CheckCompletedNodeQueries(); // Move completed successfully return true; } } } } // Failed to move messages return false; } //----------------------------------------------------------------------------- // // For messages that return a ZW_SEND_DATA response, process the results here // If it is a non-listeing (sleeping) node return true. //----------------------------------------------------------------------------- bool Driver::HandleErrorResponse(uint8 const _error, uint8 const _nodeId, char const* _funcStr, bool _sleepCheck // = 0 ) { // Only called with a ZW_SEND_DATA error response. We count and output the message here. if (_error == TRANSMIT_COMPLETE_NOROUTE) { m_badroutes++; Log::Write(LogLevel_Info, _nodeId, "ERROR: %s failed. No route available.", _funcStr); } else if (_error == TRANSMIT_COMPLETE_NO_ACK) { m_noack++; Log::Write(LogLevel_Info, _nodeId, "WARNING: %s failed. No ACK received - device may be asleep.", _funcStr); if (m_currentMsg) { // In case the failure is due to the target being a sleeping node, we // first try to move its pending messages to its wake-up queue. if (MoveMessagesToWakeUpQueue(m_currentMsg->GetTargetNodeId(), _sleepCheck)) { return true; } Log::Write(LogLevel_Warning, _nodeId, "WARNING: Device is not a sleeping node."); } } else if (_error == TRANSMIT_COMPLETE_FAIL) { m_netbusy++; Log::Write(LogLevel_Info, _nodeId, "ERROR: %s failed. Network is busy.", _funcStr); } else if (_error == TRANSMIT_COMPLETE_NOT_IDLE) { m_notidle++; Log::Write(LogLevel_Info, _nodeId, "ERROR: %s failed. Network is busy.", _funcStr); } else if (_error == TRANSMIT_COMPLETE_VERIFIED) { m_txverified++; Log::Write(LogLevel_Info, _nodeId, "ERROR: %s failed. Transmit Verified.", _funcStr); } if (Node* node = GetNodeUnsafe(_nodeId)) { if (++node->m_errors >= 3) { node->SetNodeAlive(false); } } return false; } //----------------------------------------------------------------------------- // // Identify controller (as opposed to node) commands...especially blocking ones //----------------------------------------------------------------------------- void Driver::CheckCompletedNodeQueries() { Log::Write(LogLevel_Warning, "CheckCompletedNodeQueries m_allNodesQueried=%d m_awakeNodesQueried=%d", m_allNodesQueried, m_awakeNodesQueried); if (!m_allNodesQueried) { bool all = true; bool sleepingOnly = true; bool deadFound = false; { Internal::LockGuard LG(m_nodeMutex); for (int i = 0; i < 256; ++i) { if (m_nodes[i]) { if (m_nodes[i]->GetCurrentQueryStage() != Node::QueryStage_Complete) { if (!m_nodes[i]->IsNodeAlive()) { deadFound = true; continue; } all = false; if (m_nodes[i]->IsListeningDevice()) { sleepingOnly = false; } } } } } Log::Write(LogLevel_Warning, "CheckCompletedNodeQueries all=%d, deadFound=%d sleepingOnly=%d", all, deadFound, sleepingOnly); if (all) { if (deadFound) { // only dead nodes left to query Log::Write(LogLevel_Info, " Node query processing complete except for dead nodes."); Notification* notification = new Notification(Notification::Type_AllNodesQueriedSomeDead); notification->SetHomeAndNodeIds(m_homeId, 0xff); QueueNotification(notification); } else { // no sleeping nodes, no dead nodes and no more nodes in the queue, so...All done Log::Write(LogLevel_Info, " Node query processing complete."); Notification* notification = new Notification(Notification::Type_AllNodesQueried); notification->SetHomeAndNodeIds(m_homeId, 0xff); QueueNotification(notification); } m_awakeNodesQueried = true; m_allNodesQueried = true; } else if (sleepingOnly) { if (!m_awakeNodesQueried) { // only sleeping nodes remain, so signal awake nodes queried complete Log::Write(LogLevel_Info, " Node query processing complete except for sleeping nodes."); Notification* notification = new Notification(Notification::Type_AwakeNodesQueried); notification->SetHomeAndNodeIds(m_homeId, 0xff); QueueNotification(notification); m_awakeNodesQueried = true; } } } WriteCache(); } //----------------------------------------------------------------------------- // // Determine if the reply is from the node we are expecting. //----------------------------------------------------------------------------- bool Driver::IsExpectedReply(const uint8 _nodeId) { // Accept all controller commands or where the protocol doesn't identify the actual node if (m_expectedNodeId == 255 || _nodeId == 0) { return true; } // Accept all messages that do not convey source node identification. if (m_expectedReply == FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO || m_expectedReply == FUNC_ID_ZW_REQUEST_NODE_INFO || m_expectedReply == FUNC_ID_ZW_GET_ROUTING_INFO || m_expectedReply == FUNC_ID_ZW_ASSIGN_RETURN_ROUTE || m_expectedReply == FUNC_ID_ZW_DELETE_RETURN_ROUTE || m_expectedReply == FUNC_ID_ZW_SEND_DATA || m_expectedReply == FUNC_ID_ZW_SEND_NODE_INFORMATION || m_expectedReply == FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE || m_expectedReply == FUNC_ID_ZW_ENABLE_SUC || m_expectedReply == FUNC_ID_ZW_SET_SUC_NODE_ID || m_expectedReply == FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE_OPTIONS) { return true; } // Accept if source message contains node info and it is from the one we are expecting if (m_expectedNodeId == _nodeId) { return true; } Log::Write(LogLevel_Detail, "IsExpectedReply: m_expectedNodeId = %d m_expectedReply = %02x", m_expectedNodeId, m_expectedReply); return false; } //----------------------------------------------------------------------------- // Receiving Z-Wave messages //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Read data from the serial port //----------------------------------------------------------------------------- bool Driver::ReadMsg() { uint8 buffer[1024]; memset(buffer, 0, sizeof(uint8) * 1024); if (!m_controller->Read(buffer, 1)) { // Nothing to read return false; } switch (buffer[0]) { case SOF: { m_SOFCnt++; if (m_waitingForAck) { // This can happen on any normal network when a transmission overlaps an unexpected // reception and the data in the buffer doesn't contain the ACK. The controller will // notice and send us a CAN to retransmit. Log::Write(LogLevel_Detail, "Unsolicited message received while waiting for ACK."); m_ACKWaiting++; } // Read the length byte. Keep trying until we get it. m_controller->SetSignalThreshold(1); int32 response = Internal::Platform::Wait::Single(m_controller, 50); if (response < 0) { Log::Write(LogLevel_Warning, "WARNING: 50ms passed without finding the length byte...aborting frame read"); m_readAborts++; break; } /* this is the size of the packet */ m_controller->Read(&buffer[1], 1); m_controller->SetSignalThreshold(buffer[1]); if (Internal::Platform::Wait::Single(m_controller, 500) < 0) { Log::Write(LogLevel_Warning, "WARNING: 500ms passed without reading the rest of the frame...aborting frame read"); m_readAborts++; m_controller->SetSignalThreshold(1); break; } m_controller->Read(&buffer[2], buffer[1]); m_controller->SetSignalThreshold(1); uint32 length = buffer[1] + 2; // Log the data string str = ""; for (uint32 i = 0; i < length; ++i) { if (i) { str += ", "; } char byteStr[8]; snprintf(byteStr, sizeof(byteStr), "0x%.2x", buffer[i]); str += byteStr; } uint8 nodeId = NodeFromMessage(buffer); if (nodeId == 0) { nodeId = GetNodeNumber(m_currentMsg); } Log::Write(LogLevel_Detail, nodeId, " Received: %s", str.c_str()); // Verify checksum uint8 checksum = 0xff; for (uint32 i = 1; i < (length - 1); ++i) { checksum ^= buffer[i]; } if (buffer[length - 1] == checksum) { // Checksum correct - send ACK uint8 ack = ACK; m_controller->Write(&ack, 1); m_readCnt++; // Process the received message ProcessMsg(&buffer[2], length - 2); } else { Log::Write(LogLevel_Warning, nodeId, "WARNING: Checksum incorrect - sending NAK"); m_badChecksum++; uint8 nak = NAK; m_controller->Write(&nak, 1); m_controller->Purge(); } break; } case CAN: { // This is the other side of an unsolicited ACK. As mentioned there if we receive a message // just after we transmitted one, the controller will notice and tell us to retransmit here. // Don't increment the transmission counter as it is possible the message will never get out // on very busy networks with lots of unsolicited messages being received. Increase the amount // of retries but only up to a limit so we don't stay here forever. Log::Write(LogLevel_Detail, GetNodeNumber(m_currentMsg), "CAN received...triggering resend"); m_CANCnt++; if (m_currentMsg != NULL) { m_currentMsg->SetMaxSendAttempts(m_currentMsg->GetMaxSendAttempts() + 1); m_currentMsg->setResendDuetoCANorNAK(); } else { Log::Write(LogLevel_Warning, "m_currentMsg was NULL when trying to set MaxSendAttempts"); Log::QueueDump(); } // Don't do WriteMsg("CAN"); here, the controller has data waiting to be handled by OZW. // Instead, let the main loop handle incoming message first to flush the buffer(s) break; } case NAK: { Log::Write(LogLevel_Warning, GetNodeNumber(m_currentMsg), "WARNING: NAK received...triggering resend"); m_currentMsg->SetMaxSendAttempts(m_currentMsg->GetMaxSendAttempts() + 1); m_currentMsg->setResendDuetoCANorNAK(); m_NAKCnt++; //WriteMsg("NAK"); break; } case ACK: { m_ACKCnt++; m_waitingForAck = false; if (m_currentMsg == NULL) { Log::Write(LogLevel_StreamDetail, 255, " ACK received"); } else { Log::Write(LogLevel_StreamDetail, GetNodeNumber(m_currentMsg), " ACK received CallbackId 0x%.2x Reply 0x%.2x", m_expectedCallbackId, m_expectedReply); if ((0 == m_expectedCallbackId) && (0 == m_expectedReply)) { // Remove the message from the queue, now that it has been acknowledged. RemoveCurrentMsg(); } } break; } default: { Log::Write(LogLevel_Warning, "WARNING: Out of frame flow! (0x%.2x). Sending NAK.", buffer[0]); m_OOFCnt++; uint8 nak = NAK; m_controller->Write(&nak, 1); m_controller->Purge(); break; } } return true; } //----------------------------------------------------------------------------- // // Process data received from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::ProcessMsg(uint8* _data, uint8 _length) { bool handleCallback = true; bool wasencrypted = false; //uint8 nodeId = GetNodeNumber( m_currentMsg ); if ((REQUEST == _data[0]) && FUNC_ID_APPLICATION_COMMAND_HANDLER == _data[1] && (Internal::CC::Security::StaticGetCommandClassId() == _data[5])) { /* if this message is a NONCE Report - Then just Trigger the Encrypted Send */ if (Internal::CC::SecurityCmd_NonceReport == _data[6]) { Log::Write(LogLevel_Info, _data[3], "Received SecurityCmd_NonceReport from node %d", _data[3]); /* handle possible resends of NONCE_REPORT messages.... See Issue #931 */ if (!m_currentMsg) { Log::Write(LogLevel_Warning, _data[3], "Received a NonceReport from node, but no pending messages. Dropping.."); return; } // No Need to triger a WriteMsg here - It should be handled automatically m_currentMsg->setNonce(&_data[7]); this->SendEncryptedMessage(); return; /* if this is a NONCE Get - Then call to the CC directly, process it, and then bail out. */ } else if (Internal::CC::SecurityCmd_NonceGet == _data[6]) { Log::Write(LogLevel_Info, _data[3], "Received SecurityCmd_NonceGet from node %d", _data[3]); { uint8 *nonce = NULL; Internal::LockGuard LG(m_nodeMutex); Node* node = GetNode(_data[3]); if (node) { nonce = node->GenerateNonceKey(); } else { Log::Write(LogLevel_Warning, _data[3], "Couldn't Generate Nonce Key for Node %d", _data[3]); return; } SendNonceKey(_data[3], nonce); } /* don't continue processing */ return; /* if this message is encrypted, decrypt it first */ } else if ((Internal::CC::SecurityCmd_MessageEncap == _data[6]) || (Internal::CC::SecurityCmd_MessageEncapNonceGet == _data[6])) { uint8 _newdata[256]; uint8 SecurityCmd = _data[6]; uint8 *_nonce; /* clear out NONCE Report tracking */ m_nonceReportSent = 0; m_nonceReportSentAttempt = 0; /* make sure the Node Exists, and it has the Security CC */ { Internal::LockGuard LG(m_nodeMutex); Node* node = GetNode(_data[3]); if (node) { _nonce = node->GetNonceKey(_data[_data[4] - 4]); if (!_nonce) { Log::Write(LogLevel_Warning, _data[3], "Could Not Retrieve Nonce for Node %d", _data[3]); return; } } else { Log::Write(LogLevel_Warning, _data[3], "Can't Find Node %d for Encrypted Message", _data[3]); return; } } if (Internal::DecryptBuffer(&_data[5], _data[4] + 1, this, _data[3], this->GetControllerNodeId(), _nonce, &_newdata[0])) { /* Ok - _newdata now contains the decrypted packet */ /* copy it back to the _data packet for processing */ /* New Length - See Decrypt Packet for why these numbers*/ _data[4] = _data[4] - 8 - 8 - 2 - 2; /* now copy the decrypted packet */ memcpy(&_data[5], &_newdata[1], _data[4]); //PrintHex("Decrypted Packet", _data, _data[4]+5); /* if the Node has something else to send, it will encrypt a message and send it as a MessageEncapNonceGet */ if (Internal::CC::SecurityCmd_MessageEncapNonceGet == SecurityCmd) { Log::Write(LogLevel_Info, _data[3], "Received SecurityCmd_MessageEncapNonceGet from node %d - Sending New Nonce", _data[3]); Internal::LockGuard LG(m_nodeMutex); Node* node = GetNode(_data[3]); if (node) { _nonce = node->GenerateNonceKey(); } else { Log::Write(LogLevel_Warning, _data[3], "Couldn't Generate Nonce Key for Node %d", _data[3]); return; } SendNonceKey(_data[3], _nonce); } wasencrypted = true; } else { /* if the Node has something else to send, it will encrypt a message and send it as a MessageEncapNonceGet */ if (Internal::CC::SecurityCmd_MessageEncapNonceGet == SecurityCmd) { Log::Write(LogLevel_Info, _data[3], "Received SecurityCmd_MessageEncapNonceGet from node %d - Sending New Nonce", _data[3]); Internal::LockGuard LG(m_nodeMutex); Node* node = GetNode(_data[3]); if (node) { _nonce = node->GenerateNonceKey(); } else { Log::Write(LogLevel_Warning, _data[3], "Couldn't Generate Nonce Key for Node %d", _data[3]); return; } SendNonceKey(_data[3], _nonce); } /* it failed for some reason, lets just move on */ m_expectedReply = 0; m_expectedNodeId = 0; RemoveCurrentMsg(); return; } } } if ( RESPONSE == _data[0]) { switch (_data[1]) { case FUNC_ID_SERIAL_API_GET_INIT_DATA: { Log::Write(LogLevel_Detail, ""); HandleSerialAPIGetInitDataResponse(_data); break; } case FUNC_ID_ZW_GET_CONTROLLER_CAPABILITIES: { Log::Write(LogLevel_Detail, ""); HandleGetControllerCapabilitiesResponse(_data); break; } case FUNC_ID_SERIAL_API_GET_CAPABILITIES: { Log::Write(LogLevel_Detail, ""); HandleGetSerialAPICapabilitiesResponse(_data); break; } case FUNC_ID_SERIAL_API_SOFT_RESET: { Log::Write(LogLevel_Detail, ""); HandleSerialAPISoftResetResponse(_data); break; } case FUNC_ID_ZW_SEND_DATA: { HandleSendDataResponse(_data, false); handleCallback = false; // Skip the callback handling - a subsequent FUNC_ID_ZW_SEND_DATA request will deal with that break; } case FUNC_ID_ZW_GET_VERSION: { Log::Write(LogLevel_Detail, ""); HandleGetVersionResponse(_data); break; } case FUNC_ID_ZW_GET_RANDOM: { Log::Write(LogLevel_Detail, ""); HandleGetRandomResponse(_data); break; } case FUNC_ID_SERIAL_API_SETUP: { Log::Write(LogLevel_Detail, ""); HandleSerialAPISetupResponse(_data); break; } case FUNC_ID_ZW_MEMORY_GET_ID: { Log::Write(LogLevel_Detail, ""); HandleMemoryGetIdResponse(_data); break; } case FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO: { Log::Write(LogLevel_Detail, ""); HandleGetNodeProtocolInfoResponse(_data); break; } case FUNC_ID_ZW_REPLICATION_SEND_DATA: { HandleSendDataResponse(_data, true); handleCallback = false; // Skip the callback handling - a subsequent FUNC_ID_ZW_REPLICATION_SEND_DATA request will deal with that break; } case FUNC_ID_ZW_ASSIGN_RETURN_ROUTE: { Log::Write(LogLevel_Detail, ""); if (!HandleAssignReturnRouteResponse(_data)) { m_expectedCallbackId = _data[2]; // The callback message won't be coming, so we force the transaction to complete m_expectedReply = 0; m_expectedCommandClassId = 0; m_expectedNodeId = 0; } break; } case FUNC_ID_ZW_DELETE_RETURN_ROUTE: { Log::Write(LogLevel_Detail, ""); if (!HandleDeleteReturnRouteResponse(_data)) { m_expectedCallbackId = _data[2]; // The callback message won't be coming, so we force the transaction to complete m_expectedReply = 0; m_expectedCommandClassId = 0; m_expectedNodeId = 0; } break; } case FUNC_ID_ZW_ENABLE_SUC: { Log::Write(LogLevel_Detail, ""); HandleEnableSUCResponse(_data); break; } case FUNC_ID_ZW_REQUEST_NETWORK_UPDATE: { Log::Write(LogLevel_Detail, ""); if (!HandleNetworkUpdateResponse(_data)) { m_expectedCallbackId = _data[2]; // The callback message won't be coming, so we force the transaction to complete m_expectedReply = 0; m_expectedCommandClassId = 0; m_expectedNodeId = 0; } break; } case FUNC_ID_ZW_SET_SUC_NODE_ID: { Log::Write(LogLevel_Detail, ""); HandleSetSUCNodeIdResponse(_data); break; } case FUNC_ID_ZW_GET_SUC_NODE_ID: { Log::Write(LogLevel_Detail, ""); HandleGetSUCNodeIdResponse(_data); break; } case FUNC_ID_ZW_REQUEST_NODE_INFO: { // This code used _data[3] to log Node ID // but FUNC_ID_ZW_REQUEST_NODE_INFO reply does not report back node number. Log::Write(LogLevel_Detail, ""); if (_data[2]) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "FUNC_ID_ZW_REQUEST_NODE_INFO Request successful."); } else { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "FUNC_ID_ZW_REQUEST_NODE_INFO Request failed."); } break; } case FUNC_ID_ZW_REMOVE_FAILED_NODE_ID: { Log::Write(LogLevel_Detail, ""); if (!HandleRemoveFailedNodeResponse(_data)) { m_expectedCallbackId = _data[2]; // The callback message won't be coming, so we force the transaction to complete m_expectedReply = 0; m_expectedCommandClassId = 0; m_expectedNodeId = 0; } break; } case FUNC_ID_ZW_IS_FAILED_NODE_ID: { Log::Write(LogLevel_Detail, ""); HandleIsFailedNodeResponse(_data); break; } case FUNC_ID_ZW_REPLACE_FAILED_NODE: { Log::Write(LogLevel_Detail, ""); if (!HandleReplaceFailedNodeResponse(_data)) { m_expectedCallbackId = _data[2]; // The callback message won't be coming, so we force the transaction to complete m_expectedReply = 0; m_expectedCommandClassId = 0; m_expectedNodeId = 0; } break; } case FUNC_ID_ZW_GET_ROUTING_INFO: { Log::Write(LogLevel_Detail, ""); HandleGetRoutingInfoResponse(_data); break; } case FUNC_ID_ZW_R_F_POWER_LEVEL_SET: { Log::Write(LogLevel_Detail, ""); HandleRfPowerLevelSetResponse(_data); break; } case FUNC_ID_ZW_READ_MEMORY: { Log::Write(LogLevel_Detail, ""); HandleReadMemoryResponse(_data); break; } case FUNC_ID_SERIAL_API_SET_TIMEOUTS: { Log::Write(LogLevel_Detail, ""); HandleSerialApiSetTimeoutsResponse(_data); break; } case FUNC_ID_MEMORY_GET_BYTE: { Log::Write(LogLevel_Detail, ""); HandleMemoryGetByteResponse(_data); break; } case FUNC_ID_ZW_GET_VIRTUAL_NODES: { Log::Write(LogLevel_Detail, ""); HandleGetVirtualNodesResponse(_data); break; } case FUNC_ID_ZW_SET_SLAVE_LEARN_MODE: { Log::Write(LogLevel_Detail, ""); if (!HandleSetSlaveLearnModeResponse(_data)) { m_expectedCallbackId = _data[2]; // The callback message won't be coming, so we force the transaction to complete m_expectedReply = 0; m_expectedCommandClassId = 0; m_expectedNodeId = 0; } break; } case FUNC_ID_ZW_SEND_SLAVE_NODE_INFO: { Log::Write(LogLevel_Detail, ""); if (!HandleSendSlaveNodeInfoResponse(_data)) { m_expectedCallbackId = _data[2]; // The callback message won't be coming, so we force the transaction to complete m_expectedReply = 0; m_expectedCommandClassId = 0; m_expectedNodeId = 0; } break; } /* Ignore these. They are manufacturer proprietary */ case FUNC_ID_PROPRIETARY_0: case FUNC_ID_PROPRIETARY_1: case FUNC_ID_PROPRIETARY_2: case FUNC_ID_PROPRIETARY_3: case FUNC_ID_PROPRIETARY_4: case FUNC_ID_PROPRIETARY_5: case FUNC_ID_PROPRIETARY_6: case FUNC_ID_PROPRIETARY_7: case FUNC_ID_PROPRIETARY_8: case FUNC_ID_PROPRIETARY_9: case FUNC_ID_PROPRIETARY_A: case FUNC_ID_PROPRIETARY_B: case FUNC_ID_PROPRIETARY_C: case FUNC_ID_PROPRIETARY_D: case FUNC_ID_PROPRIETARY_E: { break; } default: { Log::Write(LogLevel_Detail, ""); Log::Write(LogLevel_Info, "**TODO: handle response for 0x%.2x** Please report this message.", _data[1]); break; } } } else if ( REQUEST == _data[0]) { switch (_data[1]) { case FUNC_ID_APPLICATION_COMMAND_HANDLER: { Log::Write(LogLevel_Detail, ""); HandleApplicationCommandHandlerRequest(_data, wasencrypted); break; } case FUNC_ID_ZW_SEND_DATA: { HandleSendDataRequest(_data, _length, false); break; } case FUNC_ID_ZW_REPLICATION_COMMAND_COMPLETE: { if (m_controllerReplication) { Log::Write(LogLevel_Detail, ""); m_controllerReplication->SendNextData(); } break; } case FUNC_ID_ZW_REPLICATION_SEND_DATA: { HandleSendDataRequest(_data, _length, true); break; } case FUNC_ID_ZW_ASSIGN_RETURN_ROUTE: { Log::Write(LogLevel_Detail, ""); HandleAssignReturnRouteRequest(_data); break; } case FUNC_ID_ZW_DELETE_RETURN_ROUTE: { Log::Write(LogLevel_Detail, ""); HandleDeleteReturnRouteRequest(_data); break; } case FUNC_ID_ZW_SEND_NODE_INFORMATION: { Log::Write(LogLevel_Detail, ""); HandleSendNodeInformationRequest(_data); break; } case FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE: case FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE_OPTIONS: { Log::Write(LogLevel_Detail, ""); HandleNodeNeighborUpdateRequest(_data); break; } case FUNC_ID_ZW_APPLICATION_UPDATE: { Log::Write(LogLevel_Detail, ""); handleCallback = !HandleApplicationUpdateRequest(_data); break; } case FUNC_ID_ZW_ADD_NODE_TO_NETWORK: { Log::Write(LogLevel_Detail, ""); HandleAddNodeToNetworkRequest(_data); break; } case FUNC_ID_ZW_REMOVE_NODE_FROM_NETWORK: { Log::Write(LogLevel_Detail, ""); HandleRemoveNodeFromNetworkRequest(_data); break; } case FUNC_ID_ZW_CREATE_NEW_PRIMARY: { Log::Write(LogLevel_Detail, ""); HandleCreateNewPrimaryRequest(_data); break; } case FUNC_ID_ZW_CONTROLLER_CHANGE: { Log::Write(LogLevel_Detail, ""); HandleControllerChangeRequest(_data); break; } case FUNC_ID_ZW_SET_LEARN_MODE: { Log::Write(LogLevel_Detail, ""); HandleSetLearnModeRequest(_data); break; } case FUNC_ID_ZW_REQUEST_NETWORK_UPDATE: { Log::Write(LogLevel_Detail, ""); HandleNetworkUpdateRequest(_data); break; } case FUNC_ID_ZW_REMOVE_FAILED_NODE_ID: { Log::Write(LogLevel_Detail, ""); HandleRemoveFailedNodeRequest(_data); break; } case FUNC_ID_ZW_REPLACE_FAILED_NODE: { Log::Write(LogLevel_Detail, ""); HandleReplaceFailedNodeRequest(_data); break; } case FUNC_ID_ZW_SET_SLAVE_LEARN_MODE: { Log::Write(LogLevel_Detail, ""); HandleSetSlaveLearnModeRequest(_data); break; } case FUNC_ID_ZW_SEND_SLAVE_NODE_INFO: { Log::Write(LogLevel_Detail, ""); HandleSendSlaveNodeInfoRequest(_data); break; } case FUNC_ID_APPLICATION_SLAVE_COMMAND_HANDLER: { Log::Write(LogLevel_Detail, ""); HandleApplicationSlaveCommandRequest(_data); break; } case FUNC_ID_PROMISCUOUS_APPLICATION_COMMAND_HANDLER: { Log::Write(LogLevel_Detail, ""); HandlePromiscuousApplicationCommandHandlerRequest(_data); break; } case FUNC_ID_ZW_SET_DEFAULT: { Log::Write(LogLevel_Detail, ""); HandleSerialAPIResetRequest(_data); break; } /* Ignore these. They are manufacturer proprietary */ case FUNC_ID_PROPRIETARY_0: case FUNC_ID_PROPRIETARY_1: case FUNC_ID_PROPRIETARY_2: case FUNC_ID_PROPRIETARY_3: case FUNC_ID_PROPRIETARY_4: case FUNC_ID_PROPRIETARY_5: case FUNC_ID_PROPRIETARY_6: case FUNC_ID_PROPRIETARY_7: case FUNC_ID_PROPRIETARY_8: case FUNC_ID_PROPRIETARY_9: case FUNC_ID_PROPRIETARY_A: case FUNC_ID_PROPRIETARY_B: case FUNC_ID_PROPRIETARY_C: case FUNC_ID_PROPRIETARY_D: case FUNC_ID_PROPRIETARY_E: { break; } default: { Log::Write(LogLevel_Detail, ""); Log::Write(LogLevel_Info, "**TODO: handle request for 0x%.2x** Please report this message.", _data[1]); break; } } } // Generic callback handling // This code used _data[3] in some parts to log Node ID, // but not all serial data frames report back node number. if (handleCallback) { if ((m_expectedCallbackId || m_expectedReply)) { if (m_expectedCallbackId) { if (m_expectedCallbackId == _data[2]) { Log::Write(LogLevel_Detail, GetNodeNumber(m_currentMsg), " Expected callbackId was received"); m_expectedCallbackId = 0; } else if (_data[2] == 0x02 || _data[2] == 0x01) { /* it was a NONCE request/reply. Drop it */ return; } } if (m_expectedReply) { if (m_expectedReply == _data[1]) { if (m_expectedCommandClassId && (m_expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER)) { if (m_expectedCallbackId == 0 && m_expectedCommandClassId == _data[5] && m_expectedNodeId == _data[3]) { Log::Write(LogLevel_Detail, _data[3], " Expected reply and command class was received"); m_waitingForAck = false; m_expectedReply = 0; m_expectedCommandClassId = 0; m_expectedNodeId = 0; } } else { if (IsExpectedReply(_data[3])) { Log::Write(LogLevel_Detail, GetNodeNumber(m_currentMsg), " Expected reply was received"); m_expectedReply = 0; m_expectedNodeId = 0; } } } } if (!(m_expectedCallbackId || m_expectedReply)) { Log::Write(LogLevel_Detail, GetNodeNumber(m_currentMsg), " Message transaction complete"); Log::Write(LogLevel_Detail, ""); if (m_notifytransactions) { Notification* notification = new Notification(Notification::Type_Notification); notification->SetHomeAndNodeIds(m_homeId, GetNodeNumber(m_currentMsg)); notification->SetNotification(Notification::Code_MsgComplete); QueueNotification(notification); } RemoveCurrentMsg(); } } } } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleGetVersionResponse(uint8* _data) { m_libraryVersion = (char*) &_data[2]; m_libraryType = _data[m_libraryVersion.size() + 3]; if (m_libraryType < 9) { m_libraryTypeName = c_libraryTypeNames[m_libraryType]; } Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to FUNC_ID_ZW_GET_VERSION:"); Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " %s library, version %s", m_libraryTypeName.c_str(), m_libraryVersion.c_str()); if (!((m_libraryType == ZW_LIB_CONTROLLER_STATIC) || (m_libraryType == ZW_LIB_CONTROLLER))) { Log::Write(LogLevel_Fatal, GetNodeNumber(m_currentMsg), "Z-Wave Interface is not a Supported Library Type: %s", m_libraryTypeName.c_str()); Log::Write(LogLevel_Fatal, GetNodeNumber(m_currentMsg), "Z-Wave Interface should be a Static Controller Library Type"); { Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetUserAlertNotification(Notification::Alert_UnsupportedController); QueueNotification(notification); } { Notification* notification = new Notification(Notification::Type_DriverFailed); notification->SetHomeAndNodeIds(m_homeId, m_currentMsg->GetTargetNodeId()); notification->SetComPort(m_controllerPath); QueueNotification(notification); } NotifyWatchers(); m_driverThread->Stop(); } /* send the Next Initilization Message */ SendMsg(new Internal::Msg("FUNC_ID_ZW_MEMORY_GET_ID", 0xff, REQUEST, FUNC_ID_ZW_MEMORY_GET_ID, false), Driver::MsgQueue_Command); return; } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleGetRandomResponse(uint8* _data) { Log::Write(LogLevel_Info, "Received reply to FUNC_ID_ZW_GET_RANDOM: %s", _data[2] ? "true" : "false"); } void Driver::HandleSerialAPISetupResponse(uint8* _data) { // See INS13954 for description of FUNC_ID_SERIAL_API_SETUP with command // SERIAL_API_SETUP_CMD_TX_STATUS_REPORT // Note: SERIAL_API_SETUP can do more things than enable this report... Log::Write(LogLevel_Info, "Received reply to FUNC_ID_SERIAL_API_SETUP"); switch (_data[0]) { case 1: Log::Write(LogLevel_Info, "Successfully enabled extended txStatusReport."); m_hasExtendedTxStatus = true; break; case 0: Log::Write(LogLevel_Info, "Failed to enable extended txStatusReport. Controller might not support it."); m_hasExtendedTxStatus = false; break; default: Log::Write(LogLevel_Info, "FUNC_ID_SERIAL_API_SETUP returned unknown status: %u", _data[0]); m_hasExtendedTxStatus = false; break; } } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleGetControllerCapabilitiesResponse(uint8* _data) { m_controllerCaps = _data[2]; Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to FUNC_ID_ZW_GET_CONTROLLER_CAPABILITIES:"); char str[256]; if (m_controllerCaps & ControllerCaps_SIS) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " There is a SUC ID Server (SIS) in this network."); snprintf(str, sizeof(str), " The PC controller is an inclusion %s%s%s", (m_controllerCaps & ControllerCaps_SUC) ? "static update controller (SUC)" : "controller", (m_controllerCaps & ControllerCaps_OnOtherNetwork) ? " which is using a Home ID from another network" : "", (m_controllerCaps & ControllerCaps_RealPrimary) ? " and was the original primary before the SIS was added." : "."); Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), str); } else { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " There is no SUC ID Server (SIS) in this network."); snprintf(str, sizeof(str), " The PC controller is a %s%s%s", (m_controllerCaps & ControllerCaps_Secondary) ? "secondary" : "primary", (m_controllerCaps & ControllerCaps_SUC) ? " static update controller (SUC)" : " controller", (m_controllerCaps & ControllerCaps_OnOtherNetwork) ? " which is using a Home ID from another network." : "."); Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), str); } SendMsg(new Internal::Msg("FUNC_ID_ZW_GET_SUC_NODE_ID", 0xff, REQUEST, FUNC_ID_ZW_GET_SUC_NODE_ID, false), Driver::MsgQueue_Command); } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleGetSerialAPICapabilitiesResponse(uint8* _data) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " Received reply to FUNC_ID_SERIAL_API_GET_CAPABILITIES"); Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " Serial API Version: %d.%d", _data[2], _data[3]); Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " Manufacturer ID: 0x%.2x%.2x", _data[4], _data[5]); Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " Product Type: 0x%.2x%.2x", _data[6], _data[7]); Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " Product ID: 0x%.2x%.2x", _data[8], _data[9]); // _data[10] to _data[41] are a 256-bit bitmask with one bit set for // each FUNC_ID_ method supported by the controller. // Bit 0 is FUNC_ID_ 1. So FUNC_ID_SERIAL_API_GET_CAPABILITIES (0x07) will be bit 6 of the first byte. m_serialAPIVersion[0] = _data[2]; m_serialAPIVersion[1] = _data[3]; m_manufacturerId = (((uint16) _data[4]) << 8) | (uint16) _data[5]; m_productType = (((uint16) _data[6]) << 8) | (uint16) _data[7]; m_productId = (((uint16) _data[8]) << 8) | (uint16) _data[9]; memcpy(m_apiMask, &_data[10], sizeof(m_apiMask)); if (IsBridgeController()) { SendMsg(new Internal::Msg("FUNC_ID_ZW_GET_VIRTUAL_NODES", 0xff, REQUEST, FUNC_ID_ZW_GET_VIRTUAL_NODES, false), MsgQueue_Command); } if (IsAPICallSupported( FUNC_ID_ZW_GET_RANDOM)) { Internal::Msg *msg = new Internal::Msg("FUNC_ID_ZW_GET_RANDOM", 0xff, REQUEST, FUNC_ID_ZW_GET_RANDOM, false); msg->Append(32); // 32 bytes SendMsg(msg, MsgQueue_Command); } if (IsAPICallSupported( FUNC_ID_SERIAL_API_SETUP)) { Internal::Msg *msg = new Internal::Msg("FUNC_ID_SERIAL_API_SETUP", 0xff, REQUEST, FUNC_ID_SERIAL_API_SETUP, false); msg->Append( SERIAL_API_SETUP_CMD_TX_STATUS_REPORT); msg->Append(1); SendMsg(msg, MsgQueue_Command); } SendMsg(new Internal::Msg("FUNC_ID_SERIAL_API_GET_INIT_DATA", 0xff, REQUEST, FUNC_ID_SERIAL_API_GET_INIT_DATA, false), MsgQueue_Command); if (!IsBridgeController()) { Internal::Msg* msg = new Internal::Msg("FUNC_ID_SERIAL_API_SET_TIMEOUTS", 0xff, REQUEST, FUNC_ID_SERIAL_API_SET_TIMEOUTS, false); msg->Append( ACK_TIMEOUT / 10); msg->Append( BYTE_TIMEOUT / 10); SendMsg(msg, MsgQueue_Command); } Internal::Msg* msg = new Internal::Msg("FUNC_ID_SERIAL_API_APPL_NODE_INFORMATION", 0xff, REQUEST, FUNC_ID_SERIAL_API_APPL_NODE_INFORMATION, false, false); msg->Append( APPLICATION_NODEINFO_LISTENING); msg->Append(0x02); // Generic Static Controller msg->Append(0x01); // Specific Static PC Controller /* get a list of Advertised Command Classes */ list advertisedCommandClasses = Internal::CC::CommandClasses::GetAdvertisedCommandClasses(); msg->Append((uint8) advertisedCommandClasses.size()); // Length for (list::iterator it = advertisedCommandClasses.begin(); it != advertisedCommandClasses.end(); ++it) msg->Append(*it); SendMsg(msg, MsgQueue_Command); } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleSerialAPISoftResetResponse(uint8* _data) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to Soft Reset."); } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleSerialAPIResetRequest(uint8* _data) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to complete Controller Reset."); if (m_controllerResetEvent != NULL) { m_controllerResetEvent->Set(); m_controllerResetEvent = NULL; } } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleEnableSUCResponse(uint8* _data) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to Enable SUC."); } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- bool Driver::HandleNetworkUpdateResponse(uint8* _data) { bool res = true; ControllerState state = ControllerState_InProgress; if (_data[2]) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to FUNC_ID_ZW_REQUEST_NETWORK_UPDATE - command in progress"); } else { // Failed Log::Write(LogLevel_Warning, GetNodeNumber(m_currentMsg), "WARNING: Received reply to FUNC_ID_ZW_REQUEST_NETWORK_UPDATE - command failed"); state = ControllerState_Failed; res = false; } UpdateControllerState(state); return res; } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleSetSUCNodeIdResponse(uint8* _data) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to SET_SUC_NODE_ID."); } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleGetSUCNodeIdResponse(uint8* _data) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to GET_SUC_NODE_ID. Node ID = %d", _data[2]); m_SUCNodeId = _data[2]; if (_data[2] == 0) { bool enableSIS = true; Options::Get()->GetOptionAsBool("EnableSIS", &enableSIS); if (enableSIS) { if (IsAPICallSupported(FUNC_ID_ZW_ENABLE_SUC) && IsAPICallSupported(FUNC_ID_ZW_SET_SUC_NODE_ID)) { Log::Write(LogLevel_Info, " No SUC, so we become SIS"); Internal::Msg* msg; msg = new Internal::Msg("Enable SUC", m_Controller_nodeId, REQUEST, FUNC_ID_ZW_ENABLE_SUC, false); msg->Append(1); msg->Append( SUC_FUNC_NODEID_SERVER); // SIS; SUC would be ZW_SUC_FUNC_BASIC_SUC SendMsg(msg, MsgQueue_Send); msg = new Internal::Msg("Set SUC node ID", m_Controller_nodeId, REQUEST, FUNC_ID_ZW_SET_SUC_NODE_ID, false); msg->Append(m_Controller_nodeId); msg->Append(1); // TRUE, we want to be SUC/SIS msg->Append(0); // no low power msg->Append( SUC_FUNC_NODEID_SERVER); SendMsg(msg, MsgQueue_Send); } else { Log::Write(LogLevel_Info, "Controller Does not Support SUC - Cannot Setup Controller as SUC Node"); } } else { Log::Write(LogLevel_Info, " No SUC, not becoming SUC as option is disabled"); } } SendMsg(new Internal::Msg("FUNC_ID_SERIAL_API_GET_CAPABILITIES", 0xff, REQUEST, FUNC_ID_SERIAL_API_GET_CAPABILITIES, false), Driver::MsgQueue_Command); } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleMemoryGetIdResponse(uint8* _data) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to FUNC_ID_ZW_MEMORY_GET_ID. Home ID = 0x%02x%02x%02x%02x. Our node ID = %d", _data[2], _data[3], _data[4], _data[5], _data[6]); m_homeId = (((uint32) _data[2]) << 24) | (((uint32) _data[3]) << 16) | (((uint32) _data[4]) << 8) | ((uint32) _data[5]); m_Controller_nodeId = _data[6]; m_controllerReplication = static_cast(Internal::CC::ControllerReplication::Create(m_homeId, m_Controller_nodeId)); SendMsg(new Internal::Msg("FUNC_ID_ZW_GET_CONTROLLER_CAPABILITIES", 0xff, REQUEST, FUNC_ID_ZW_GET_CONTROLLER_CAPABILITIES, false), Driver::MsgQueue_Command); } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleSerialAPIGetInitDataResponse(uint8* _data) { int32 i; if (m_homeId == 0 || m_Controller_nodeId == 255 || m_Controller_nodeId == 0) { Log::Write(LogLevel_Fatal, "Failed to get HomeID or Controller Node ID during Init Sequence, m_homeId = 0x%08x, m_Controller_nodeId = %d", m_homeId, m_Controller_nodeId); Notification* notification = new Notification(Notification::Type_DriverFailed); QueueNotification(notification); NotifyWatchers(); m_driverThread->Stop(); return; } if (!m_init) { // Mark the driver as ready (we have to do this first or // all the code handling notifications will go awry). Manager::Get()->SetDriverReady(this, true); // Read the config file first, to get the last known state ReadCache(); } else { // Notify the user that all node and value information has been deleted // We need to wait to do this here so we have new information to report. Notification* notification = new Notification(Notification::Type_DriverReset); notification->SetHomeAndNodeIds(m_homeId, 0); QueueNotification(notification); } Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to FUNC_ID_SERIAL_API_GET_INIT_DATA:"); m_initVersion = _data[2]; m_initCaps = _data[3]; if (_data[4] == NUM_NODE_BITFIELD_BYTES) { for (i = 0; i < NUM_NODE_BITFIELD_BYTES; ++i) { for (int32 j = 0; j < 8; ++j) { uint8 nodeId = (i * 8) + j + 1; if (_data[i + 5] & (0x01 << j)) { if (IsVirtualNode(nodeId)) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " Node %.3d - Virtual (ignored)", nodeId); } else { Internal::LockGuard LG(m_nodeMutex); Node* node = GetNode(nodeId); if (node) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " Node %.3d - Known", nodeId); if (!m_init) { // The node was read in from the config, so we // only need to get its current state node->SetQueryStage(Node::QueryStage_CacheLoad); } } else { // This node is new Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " Node %.3d - New", nodeId); Notification* notification = new Notification(Notification::Type_NodeNew); notification->SetHomeAndNodeIds(m_homeId, nodeId); QueueNotification(notification); // Create the node and request its info InitNode(nodeId); } } } else { Internal::LockGuard LG(m_nodeMutex); if (GetNode(nodeId)) { // This node no longer exists in the Z-Wave network Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " Node %.3d - Removed", nodeId); delete m_nodes[nodeId]; m_nodes[nodeId] = NULL; Notification* notification = new Notification(Notification::Type_NodeRemoved); notification->SetHomeAndNodeIds(m_homeId, nodeId); QueueNotification(notification); } } } } } m_init = true; } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleGetNodeProtocolInfoResponse(uint8* _data) { // The node that the protocol info response is for is not included in the message. // We have to assume that the node is the same one as in the most recent request. if (!m_currentMsg) { Log::Write(LogLevel_Warning, "WARNING: Received unexpected FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO message - ignoring."); return; } uint8 nodeId = m_currentMsg->GetTargetNodeId(); Log::Write(LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO"); // Update the node with the protocol info if (Node* node = GetNodeUnsafe(nodeId)) { node->UpdateProtocolInfo(&_data[2]); } } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- bool Driver::HandleAssignReturnRouteResponse(uint8* _data) { bool res = true; ControllerState state = ControllerState_InProgress; if (_data[2]) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to FUNC_ID_ZW_ASSIGN_RETURN_ROUTE - command in progress"); } else { // Failed Log::Write(LogLevel_Warning, GetNodeNumber(m_currentMsg), "WARNING: Received reply to FUNC_ID_ZW_ASSIGN_RETURN_ROUTE - command failed"); state = ControllerState_Failed; res = false; } UpdateControllerState(state); return res; } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- bool Driver::HandleDeleteReturnRouteResponse(uint8* _data) { bool res = true; ControllerState state = ControllerState_InProgress; if (_data[2]) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to FUNC_ID_ZW_DELETE_RETURN_ROUTE - command in progress"); } else { // Failed Log::Write(LogLevel_Warning, GetNodeNumber(m_currentMsg), "WARNING: Received reply to FUNC_ID_ZW_DELETE_RETURN_ROUTE - command failed"); state = ControllerState_Failed; res = false; } UpdateControllerState(state); return res; } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- bool Driver::HandleRemoveFailedNodeResponse(uint8* _data) { bool res = true; ControllerState state = ControllerState_InProgress; ControllerError error = ControllerError_None; if (_data[2]) { string reason; switch (_data[2]) { case FAILED_NODE_NOT_FOUND: { reason = "Node not found"; error = ControllerError_NotFound; break; } case FAILED_NODE_REMOVE_PROCESS_BUSY: { reason = "Remove process busy"; error = ControllerError_Busy; break; } case FAILED_NODE_REMOVE_FAIL: { reason = "Remove failed"; error = ControllerError_Failed; break; } case FAILED_NODE_NOT_PRIMARY_CONTROLLER: { reason = "Not Primary Controller"; error = ControllerError_NotPrimary; break; } default: { reason = "Command failed"; break; } } Log::Write(LogLevel_Warning, GetNodeNumber(m_currentMsg), "WARNING: Received reply to FUNC_ID_ZW_REMOVE_FAILED_NODE_ID - %s", reason.c_str()); state = ControllerState_Failed; res = false; } else { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to FUNC_ID_ZW_REMOVE_FAILED_NODE_ID - Command in progress"); } UpdateControllerState(state, error); return res; } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleIsFailedNodeResponse(uint8* _data) { ControllerState state; uint8 nodeId = m_currentControllerCommand ? m_currentControllerCommand->m_controllerCommandNode : GetNodeNumber(m_currentMsg); if (_data[2]) { Log::Write(LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_IS_FAILED_NODE_ID - node %d failed", nodeId); state = ControllerState_NodeFailed; if (Node* node = GetNodeUnsafe(nodeId)) { if (node->IsNodeReset()) { /* a DeviceReset has Occured. Remove the Node */ if (!BeginControllerCommand(Driver::ControllerCommand_RemoveFailedNode, NULL, NULL, true, nodeId, 0)) Log::Write(LogLevel_Warning, nodeId, "RemoveFailedNode for DeviceResetLocally Command Failed"); Notification* notification = new Notification(Notification::Type_NodeReset); notification->SetHomeAndNodeIds(m_homeId, nodeId); QueueNotification(notification); state = ControllerState_Completed; } else { node->SetNodeAlive(false); } } } else { Log::Write(LogLevel_Warning, nodeId, "Received reply to FUNC_ID_ZW_IS_FAILED_NODE_ID - node %d has not failed", nodeId); if (Node* node = GetNodeUnsafe(nodeId)) { node->SetNodeAlive(true); } state = ControllerState_NodeOK; } UpdateControllerState(state); } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- bool Driver::HandleReplaceFailedNodeResponse(uint8* _data) { bool res = true; ControllerState state = ControllerState_InProgress; if (_data[2]) { // Command failed Log::Write(LogLevel_Warning, GetNodeNumber(m_currentMsg), "WARNING: Received reply to FUNC_ID_ZW_REPLACE_FAILED_NODE - command failed"); state = ControllerState_Failed; res = false; } else { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to FUNC_ID_ZW_REPLACE_FAILED_NODE - command in progress"); } UpdateControllerState(state); return res; } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleSendDataResponse(uint8* _data, bool _replication) { if (_data[2]) { Log::Write(LogLevel_Detail, GetNodeNumber(m_currentMsg), " %s delivered to Z-Wave stack", _replication ? "ZW_REPLICATION_SEND_DATA" : "ZW_SEND_DATA"); } else { Log::Write(LogLevel_Error, GetNodeNumber(m_currentMsg), "ERROR: %s could not be delivered to Z-Wave stack", _replication ? "ZW_REPLICATION_SEND_DATA" : "ZW_SEND_DATA"); m_nondelivery++; if (Node* node = GetNodeUnsafe(GetNodeNumber(m_currentMsg))) { node->m_sentFailed++; } } } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleGetRoutingInfoResponse(uint8* _data) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to FUNC_ID_ZW_GET_ROUTING_INFO"); Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(GetNodeNumber(m_currentMsg))) { // copy the 29-byte bitmap received (29*8=232 possible nodes) into this node's neighbors member variable memcpy(node->m_neighbors, &_data[2], 29); Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " Neighbors of this node are:"); bool bNeighbors = false; for (int by = 0; by < 29; by++) { for (int bi = 0; bi < 8; bi++) { if ((_data[2 + by] & (0x01 << bi))) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " Node %d", (by << 3) + bi + 1); bNeighbors = true; } } } if (!bNeighbors) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), " (none reported)"); } } } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleSendDataRequest(uint8* _data, uint8 _length, bool _replication) { uint8 nodeId = GetNodeNumber(m_currentMsg); Log::Write(LogLevel_Detail, nodeId, " %s Request with callback ID 0x%.2x received (expected 0x%.2x)", _replication ? "ZW_REPLICATION_SEND_DATA" : "ZW_SEND_DATA", _data[2], _data[2] < 10 ? _data[2] : m_expectedCallbackId); /* Callback ID's below 10 are reserved for NONCE messages */ if ((_data[2] > 10) && (_data[2] != m_expectedCallbackId)) { // Wrong callback ID m_callbacks++; Log::Write(LogLevel_Warning, nodeId, "WARNING: Unexpected Callback ID received"); } else { Node* node = GetNodeUnsafe(nodeId); if (node != NULL) { if (_data[3] != TRANSMIT_COMPLETE_OK) { node->m_sentFailed++; } else { node->m_lastRequestRTT = -node->m_sentTS.TimeRemaining(); if (node->m_averageRequestRTT) { // if the average has been established, update by averaging the average and the last RTT node->m_averageRequestRTT = (node->m_averageRequestRTT + node->m_lastRequestRTT) >> 1; } else { // if this is the first observed RTT, set the average to this value node->m_averageRequestRTT = node->m_lastRequestRTT; } Log::Write(LogLevel_Info, nodeId, "Request RTT %d Average Request RTT %d", node->m_lastRequestRTT, node->m_averageRequestRTT); } /* if the frame has txStatus message, then extract it */ // petergebruers, changed test (_length > 7) to >= 23 to avoid extracting non-existent data, highest is _data[22] if (_length >= 23) { node->m_txStatusReportSupported = true; // petergebruers: // because OpenZWave uses "ms" everywhere, and wTransmitTicks // has "10 ms" as unit... multiply by 10. This wil avoid // confusion when people look at stats or log files. node->m_txTime = (_data[5] + (_data[4] << 8)) * 10; node->m_hops = _data[6]; // petergebruers: there are 5 rssi values because there are // 4 repeaters + 1 sending node strncpy(node->m_rssi_1, Internal::rssi_to_string(_data[7]), sizeof(node->m_rssi_1) - 1); strncpy(node->m_rssi_2, Internal::rssi_to_string(_data[8]), sizeof(node->m_rssi_2) - 1); strncpy(node->m_rssi_3, Internal::rssi_to_string(_data[9]), sizeof(node->m_rssi_3) - 1); strncpy(node->m_rssi_4, Internal::rssi_to_string(_data[10]), sizeof(node->m_rssi_4) - 1); strncpy(node->m_rssi_5, Internal::rssi_to_string(_data[11]), sizeof(node->m_rssi_5) - 1); node->m_ackChannel = _data[12]; node->m_lastTxChannel = _data[13]; node->m_routeScheme = (TXSTATUS_ROUTING_SCHEME) _data[14]; node->m_routeUsed[0] = _data[15]; node->m_routeUsed[1] = _data[16]; node->m_routeUsed[2] = _data[17]; node->m_routeUsed[3] = _data[18]; node->m_routeSpeed = (TXSTATUS_ROUTE_SPEED) _data[19]; node->m_routeTries = _data[20]; node->m_lastFailedLinkFrom = _data[21]; node->m_lastFailedLinkTo = _data[22]; Node::NodeData nd; node->GetNodeStatistics(&nd); // petergebruers: changed "ChannelAck" to "AckChannel", to be consistent with docs and "TxChannel" Log::Write(LogLevel_Detail, nodeId, "Extended TxStatus: Time: %d, Hops: %d, Rssi: %s %s %s %s %s, AckChannel: %d, TxChannel: %d, RouteScheme: %s, Route: %d %d %d %d, RouteSpeed: %s, RouteTries: %d, FailedLinkFrom: %d, FailedLinkTo: %d", nd.m_txTime, nd.m_hops, nd.m_rssi_1, nd.m_rssi_2, nd.m_rssi_3, nd.m_rssi_4, nd.m_rssi_4, nd.m_ackChannel, nd.m_lastTxChannel, Manager::GetNodeRouteScheme(&nd).c_str(), nd.m_routeUsed[0], nd.m_routeUsed[1], nd.m_routeUsed[2], nd.m_routeUsed[3], Manager::GetNodeRouteSpeed(&nd).c_str(), nd.m_routeTries, nd.m_lastFailedLinkFrom, nd.m_lastFailedLinkTo); } } // We do this here since HandleErrorResponse/MoveMessagesToWakeUpQueue can delete m_currentMsg if (m_currentMsg && m_currentMsg->IsNoOperation()) { Notification* notification = new Notification(Notification::Type_Notification); notification->SetHomeAndNodeIds(m_homeId, GetNodeNumber(m_currentMsg)); notification->SetNotification(Notification::Code_NoOperation); QueueNotification(notification); } // Callback ID matches our expectation if (_data[3] != TRANSMIT_COMPLETE_OK) { if (!HandleErrorResponse(_data[3], nodeId, _replication ? "ZW_REPLICATION_END_DATA" : "ZW_SEND_DATA", !_replication)) { if (m_currentMsg && m_currentMsg->IsNoOperation() && node != NULL && (node->GetCurrentQueryStage() == Node::QueryStage_Probe || node->GetCurrentQueryStage() == Node::QueryStage_CacheLoad)) { node->QueryStageRetry(node->GetCurrentQueryStage(), 3); } } } else if (node != NULL) { // If WakeUpNoMoreInformation request succeeds, update our status if (m_currentMsg && m_currentMsg->IsWakeUpNoMoreInformationCommand()) { if (Internal::CC::WakeUp* wakeUp = static_cast(node->GetCommandClass(Internal::CC::WakeUp::StaticGetCommandClassId()))) { // Mark the node as asleep wakeUp->SetAwake(false); } } // If node is not alive, mark it alive now if (!node->IsNodeAlive()) { node->SetNodeAlive(true); } } // Command reception acknowledged by node, error or not, but ignore any NONCE messages // // m_expectedCallbackId = 0; } } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleNetworkUpdateRequest(uint8* _data) { ControllerState state = ControllerState_Failed; ControllerError error = ControllerError_None; uint8 nodeId = GetNodeNumber(m_currentMsg); switch (_data[3]) { case SUC_UPDATE_DONE: { Log::Write(LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_REQUEST_NETWORK_UPDATE: Success"); state = ControllerState_Completed; break; } case SUC_UPDATE_ABORT: { Log::Write(LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_REQUEST_NETWORK_UPDATE: Failed - Error. Process aborted."); error = ControllerError_Failed; break; } case SUC_UPDATE_WAIT: { Log::Write(LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_REQUEST_NETWORK_UPDATE: Failed - SUC is busy."); error = ControllerError_Busy; break; } case SUC_UPDATE_DISABLED: { Log::Write(LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_REQUEST_NETWORK_UPDATE: Failed - SUC is disabled."); error = ControllerError_Disabled; break; } case SUC_UPDATE_OVERFLOW: { Log::Write(LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_REQUEST_NETWORK_UPDATE: Failed - Overflow. Full replication required."); error = ControllerError_Overflow; break; } default: { } } UpdateControllerState(state, error); } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleAddNodeToNetworkRequest(uint8* _data) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "FUNC_ID_ZW_ADD_NODE_TO_NETWORK:"); CommonAddNodeStatusRequestHandler( FUNC_ID_ZW_ADD_NODE_TO_NETWORK, _data); } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleRemoveNodeFromNetworkRequest(uint8* _data) { //uint8 nodeId = GetNodeNumber( m_currentMsg ); if (m_currentControllerCommand == NULL) { return; } ControllerState state = m_currentControllerCommand->m_controllerState; Log::Write(LogLevel_Info, "FUNC_ID_ZW_REMOVE_NODE_FROM_NETWORK:"); switch (_data[3]) { case REMOVE_NODE_STATUS_LEARN_READY: { Log::Write(LogLevel_Info, "REMOVE_NODE_STATUS_LEARN_READY"); state = ControllerState_Waiting; m_currentControllerCommand->m_controllerCommandNode = 0; break; } case REMOVE_NODE_STATUS_NODE_FOUND: { Log::Write(LogLevel_Info, "REMOVE_NODE_STATUS_NODE_FOUND"); state = ControllerState_InProgress; break; } case REMOVE_NODE_STATUS_REMOVING_SLAVE: { Log::Write(LogLevel_Info, "REMOVE_NODE_STATUS_REMOVING_SLAVE"); if (_data[4] != 0) { Log::Write(LogLevel_Info, "Removing node ID %d", _data[4]); m_currentControllerCommand->m_controllerCommandNode = _data[4]; } else { Log::Write(LogLevel_Warning, "Remove Node Failed - NodeID 0 Returned"); state = ControllerState_Failed; } break; } case REMOVE_NODE_STATUS_REMOVING_CONTROLLER: { Log::Write(LogLevel_Info, "REMOVE_NODE_STATUS_REMOVING_CONTROLLER"); m_currentControllerCommand->m_controllerCommandNode = _data[4]; if (m_currentControllerCommand->m_controllerCommandNode == 0) // Some controllers don't return node number { if (_data[5] >= 3) { Internal::LockGuard LG(m_nodeMutex); for (int i = 0; i < 256; i++) { if (m_nodes[i] == NULL) { continue; } // Ignore primary controller if (m_nodes[i]->m_nodeId == m_Controller_nodeId) { continue; } // See if we can match another way if (m_nodes[i]->m_basic == _data[6] && m_nodes[i]->m_generic == _data[7] && m_nodes[i]->m_specific == _data[8]) { if (m_currentControllerCommand->m_controllerCommandNode != 0) { Log::Write(LogLevel_Info, "Alternative controller lookup found more then one match. Using the first one found."); } else { m_currentControllerCommand->m_controllerCommandNode = m_nodes[i]->m_nodeId; } } } LG.Unlock(); } else { Log::Write(LogLevel_Warning, "WARNING: Node is 0 but not enough data to perform alternative match."); } } else { m_currentControllerCommand->m_controllerCommandNode = _data[4]; } WriteCache(); Log::Write(LogLevel_Info, "Removing controller ID %d", m_currentControllerCommand->m_controllerCommandNode); break; } case REMOVE_NODE_STATUS_DONE: { Log::Write(LogLevel_Info, "REMOVE_NODE_STATUS_DONE"); if (!m_currentControllerCommand->m_controllerCommandDone) { // Remove Node Stop calls back through here so make sure // we do't do it again. UpdateControllerState(ControllerState_Completed); //AddNodeStop( FUNC_ID_ZW_REMOVE_NODE_FROM_NETWORK ); if (m_currentControllerCommand->m_controllerCommandNode == 0) // never received "removing" update { if (_data[4] != 0) // but message has the clue { m_currentControllerCommand->m_controllerCommandNode = _data[4]; } } if (m_currentControllerCommand->m_controllerCommandNode != 0 && m_currentControllerCommand->m_controllerCommandNode != 0xff) { { Internal::LockGuard LG(m_nodeMutex); delete m_nodes[m_currentControllerCommand->m_controllerCommandNode]; m_nodes[m_currentControllerCommand->m_controllerCommandNode] = NULL; } WriteCache(); Notification* notification = new Notification(Notification::Type_NodeRemoved); notification->SetHomeAndNodeIds(m_homeId, m_currentControllerCommand->m_controllerCommandNode); QueueNotification(notification); } } return; } case REMOVE_NODE_STATUS_FAILED: { //AddNodeStop( FUNC_ID_ZW_REMOVE_NODE_FROM_NETWORK ); Log::Write(LogLevel_Warning, "WARNING: REMOVE_NODE_STATUS_FAILED"); state = ControllerState_Failed; break; } default: { break; } } UpdateControllerState(state); } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleControllerChangeRequest(uint8* _data) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "FUNC_ID_ZW_CONTROLLER_CHANGE:"); CommonAddNodeStatusRequestHandler( FUNC_ID_ZW_CONTROLLER_CHANGE, _data); } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleCreateNewPrimaryRequest(uint8* _data) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "FUNC_ID_ZW_CREATE_NEW_PRIMARY:"); CommonAddNodeStatusRequestHandler( FUNC_ID_ZW_CREATE_NEW_PRIMARY, _data); } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleSetLearnModeRequest(uint8* _data) { uint8 nodeId = GetNodeNumber(m_currentMsg); if (m_currentControllerCommand == NULL) { return; } ControllerState state = m_currentControllerCommand->m_controllerState; Log::Write(LogLevel_Info, nodeId, "FUNC_ID_ZW_SET_LEARN_MODE:"); switch (_data[3]) { case LEARN_MODE_STARTED: { Log::Write(LogLevel_Info, nodeId, "LEARN_MODE_STARTED"); state = ControllerState_Waiting; break; } case LEARN_MODE_DONE: { Log::Write(LogLevel_Info, nodeId, "LEARN_MODE_DONE"); state = ControllerState_Completed; // Stop learn mode Internal::Msg* msg = new Internal::Msg("End Learn Mode", 0xff, REQUEST, FUNC_ID_ZW_SET_LEARN_MODE, false, false); msg->Append(0); SendMsg(msg, MsgQueue_Command); // Rebuild all the node info. Group and scene data that we stored // during replication will be applied as we discover each node. InitAllNodes(); break; } case LEARN_MODE_FAILED: { Log::Write(LogLevel_Warning, nodeId, "WARNING: LEARN_MODE_FAILED"); state = ControllerState_Failed; // Stop learn mode Internal::Msg* msg = new Internal::Msg("End Learn Mode", 0xff, REQUEST, FUNC_ID_ZW_SET_LEARN_MODE, false, false); msg->Append(0); SendMsg(msg, MsgQueue_Command); // Rebuild all the node info, since it may have been partially // updated by the failed command. Group and scene data that we // stored during replication will be applied as we discover each node. InitAllNodes(); break; } case LEARN_MODE_DELETED: { Log::Write(LogLevel_Info, nodeId, "LEARN_MODE_DELETED"); state = ControllerState_Failed; // Stop learn mode Internal::Msg* msg = new Internal::Msg("End Learn Mode", 0xff, REQUEST, FUNC_ID_ZW_SET_LEARN_MODE, false, false); msg->Append(0); SendMsg(msg, MsgQueue_Command); break; } } UpdateControllerState(state); } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleRemoveFailedNodeRequest(uint8* _data) { ControllerState state = ControllerState_Completed; uint8 nodeId = GetNodeNumber(m_currentMsg); switch (_data[3]) { case FAILED_NODE_OK: { Log::Write(LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_REMOVE_FAILED_NODE_ID - Node %d is OK, so command failed", m_currentControllerCommand->m_controllerCommandNode); state = ControllerState_NodeOK; break; } case FAILED_NODE_REMOVED: { Log::Write(LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_REMOVE_FAILED_NODE_ID - node %d successfully moved to failed nodes list", m_currentControllerCommand->m_controllerCommandNode); state = ControllerState_Completed; { Internal::LockGuard LG(m_nodeMutex); delete m_nodes[m_currentControllerCommand->m_controllerCommandNode]; m_nodes[m_currentControllerCommand->m_controllerCommandNode] = NULL; } WriteCache(); Notification* notification = new Notification(Notification::Type_NodeRemoved); notification->SetHomeAndNodeIds(m_homeId, m_currentControllerCommand->m_controllerCommandNode); QueueNotification(notification); break; } case FAILED_NODE_NOT_REMOVED: { Log::Write(LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_REMOVE_FAILED_NODE_ID - unable to move node %d to failed nodes list", m_currentControllerCommand->m_controllerCommandNode); state = ControllerState_Failed; break; } } UpdateControllerState(state); } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleReplaceFailedNodeRequest(uint8* _data) { ControllerState state = ControllerState_Completed; uint8 nodeId = GetNodeNumber(m_currentMsg); switch (_data[3]) { case FAILED_NODE_OK: { Log::Write(LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_REPLACE_FAILED_NODE - Node is OK, so command failed"); state = ControllerState_NodeOK; break; } case FAILED_NODE_REPLACE_WAITING: { Log::Write(LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_REPLACE_FAILED_NODE - Waiting for new node"); state = ControllerState_Waiting; break; } case FAILED_NODE_REPLACE_DONE: { Log::Write(LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_REPLACE_FAILED_NODE - Node successfully replaced"); state = ControllerState_Completed; // Request new node info for this device if (m_currentControllerCommand != NULL) { InitNode(m_currentControllerCommand->m_controllerCommandNode, true); } WriteCache(); break; } case FAILED_NODE_REPLACE_FAILED: { Log::Write(LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_REPLACE_FAILED_NODE - Node replacement failed"); state = ControllerState_Failed; break; } } UpdateControllerState(state); } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleApplicationCommandHandlerRequest(uint8* _data, bool encrypted) { uint8 status = _data[2]; uint8 nodeId = _data[3]; uint8 classId = _data[5]; Node* node = GetNodeUnsafe(nodeId); if ((status & RECEIVE_STATUS_ROUTED_BUSY) != 0) { m_routedbusy++; } if ((status & RECEIVE_STATUS_TYPE_BROAD) != 0) { m_broadcastReadCnt++; } if (node != NULL) { node->m_receivedCnt++; node->m_errors = 0; int cmp = memcmp(_data, node->m_lastReceivedMessage, sizeof(node->m_lastReceivedMessage)); if (cmp == 0 && node->m_receivedTS.TimeRemaining() > -500) { // if the exact same sequence of bytes are received within 500ms node->m_receivedDups++; } else { memcpy(node->m_lastReceivedMessage, _data, sizeof(node->m_lastReceivedMessage)); } node->m_receivedTS.SetTime(); if (m_expectedReply == FUNC_ID_APPLICATION_COMMAND_HANDLER && m_expectedNodeId == nodeId) { // Need to confirm this is the correct response to the last sent request. // At least ignore any received messages prior to the send data request. node->m_lastResponseRTT = -node->m_sentTS.TimeRemaining(); if (node->m_averageResponseRTT) { // if the average has been established, update by averaging the average and the last RTT node->m_averageResponseRTT = (node->m_averageResponseRTT + node->m_lastResponseRTT) >> 1; } else { // if this is the first observed RTT, set the average to this value node->m_averageResponseRTT = node->m_lastResponseRTT; } Log::Write(LogLevel_Info, nodeId, "Response RTT %d Average Response RTT %d", node->m_lastResponseRTT, node->m_averageResponseRTT); } else { node->m_receivedUnsolicited++; } if (!node->IsNodeAlive()) { node->SetNodeAlive(true); } } if (Internal::CC::ApplicationStatus::StaticGetCommandClassId() == classId) { //TODO: Test this class function or implement } else if (Internal::CC::ControllerReplication::StaticGetCommandClassId() == classId) { if (m_controllerReplication && m_currentControllerCommand && (ControllerCommand_ReceiveConfiguration == m_currentControllerCommand->m_controllerCommand)) { m_controllerReplication->HandleMsg(&_data[6], _data[4]); UpdateControllerState(ControllerState_InProgress); } } else { // Allow the node to handle the message itself if (node != NULL) { node->ApplicationCommandHandler(_data, encrypted); } } } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface when in promiscuous mode. //----------------------------------------------------------------------------- void Driver::HandlePromiscuousApplicationCommandHandlerRequest(uint8* _data) { //uint8 nodeId = _data[3]; //uint8 len = _data[4]; //uint8 classId = _data[5]; //uint8 destNodeId = _data[5+len]; } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleAssignReturnRouteRequest(uint8* _data) { ControllerState state; uint8 nodeId = GetNodeNumber(m_currentMsg); if (m_currentControllerCommand == NULL) { return; } if (_data[3]) { // Failed HandleErrorResponse(_data[3], m_currentControllerCommand->m_controllerCommandNode, "ZW_ASSIGN_RETURN_ROUTE", true); state = ControllerState_Failed; } else { // Success Log::Write(LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_ASSIGN_RETURN_ROUTE for node %d - SUCCESS", m_currentControllerCommand->m_controllerCommandNode); state = ControllerState_Completed; } UpdateControllerState(state); } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleDeleteReturnRouteRequest(uint8* _data) { ControllerState state; uint8 nodeId = GetNodeNumber(m_currentMsg); if (m_currentControllerCommand == NULL) { return; } if (_data[3] != TRANSMIT_COMPLETE_OK) { // Failed HandleErrorResponse(_data[3], m_currentControllerCommand->m_controllerCommandNode, "ZW_DELETE_RETURN_ROUTE", true); state = ControllerState_Failed; } else { // Success Log::Write(LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_DELETE_RETURN_ROUTE for node %d - SUCCESS", m_currentControllerCommand->m_controllerCommandNode); state = ControllerState_Completed; } UpdateControllerState(state); } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleSendNodeInformationRequest(uint8* _data) { ControllerState state; uint8 nodeId = GetNodeNumber(m_currentMsg); if (m_currentControllerCommand == NULL) { return; } if (_data[3] != TRANSMIT_COMPLETE_OK) { // Failed HandleErrorResponse(_data[3], m_currentControllerCommand->m_controllerCommandNode, "ZW_SEND_NODE_INFORMATION"); state = ControllerState_Failed; } else { // Success Log::Write(LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_SEND_NODE_INFORMATION - SUCCESS"); state = ControllerState_Completed; } UpdateControllerState(state); } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleNodeNeighborUpdateRequest(uint8* _data) { uint8 nodeId = GetNodeNumber(m_currentMsg); ControllerState state = ControllerState_Normal; switch (_data[3]) { case REQUEST_NEIGHBOR_UPDATE_STARTED: { Log::Write(LogLevel_Info, nodeId, "REQUEST_NEIGHBOR_UPDATE_STARTED"); state = ControllerState_InProgress; break; } case REQUEST_NEIGHBOR_UPDATE_DONE: { Log::Write(LogLevel_Info, nodeId, "REQUEST_NEIGHBOR_UPDATE_DONE"); state = ControllerState_Completed; // We now request the neighbour information from the // controller and store it in our node object. if (m_currentControllerCommand != NULL) { RequestNodeNeighbors(m_currentControllerCommand->m_controllerCommandNode, 0); } break; } case REQUEST_NEIGHBOR_UPDATE_FAILED: { Log::Write(LogLevel_Warning, nodeId, "WARNING: REQUEST_NEIGHBOR_UPDATE_FAILED"); state = ControllerState_Failed; break; } default: { break; } } UpdateControllerState(state); } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- bool Driver::HandleApplicationUpdateRequest(uint8* _data) { bool messageRemoved = false; uint8 nodeId = _data[3]; Node* node = GetNodeUnsafe(nodeId); // If node is not alive, mark it alive now if (node != NULL && !node->IsNodeAlive()) { node->SetNodeAlive(true); } switch (_data[2]) { case UPDATE_STATE_SUC_ID: { Log::Write(LogLevel_Info, nodeId, "UPDATE_STATE_SUC_ID from node %d", nodeId); m_SUCNodeId = nodeId; // need to confirm real data here break; } case UPDATE_STATE_DELETE_DONE: { Log::Write(LogLevel_Info, nodeId, "** Network change **: Z-Wave node %d was removed", nodeId); { Internal::LockGuard LG(m_nodeMutex); delete m_nodes[nodeId]; m_nodes[nodeId] = NULL; } Notification* notification = new Notification(Notification::Type_NodeRemoved); notification->SetHomeAndNodeIds(m_homeId, nodeId); QueueNotification(notification); break; } case UPDATE_STATE_NEW_ID_ASSIGNED: { Log::Write(LogLevel_Info, nodeId, "** Network change **: ID %d was assigned to a new Z-Wave node", nodeId); // Check if the new node id is equal to the current one.... if so no operation is needed, thus no remove and add is necessary if (_data[3] != _data[6]) { // Request the node protocol info (also removes any existing node and creates a new one) InitNode(nodeId); } else { Log::Write(LogLevel_Info, nodeId, "Not Re-assigning NodeID as old and new NodeID match"); } break; } case UPDATE_STATE_ROUTING_PENDING: { Log::Write(LogLevel_Info, nodeId, "UPDATE_STATE_ROUTING_PENDING from node %d", nodeId); break; } case UPDATE_STATE_NODE_INFO_REQ_FAILED: { Log::Write(LogLevel_Warning, nodeId, "WARNING: FUNC_ID_ZW_APPLICATION_UPDATE: UPDATE_STATE_NODE_INFO_REQ_FAILED received"); // Note: Unhelpfully, the nodeId is always zero in this message. We have to // assume the message came from the last node to which we sent a request. if (m_currentMsg) { Node* tnode = GetNodeUnsafe(m_currentMsg->GetTargetNodeId()); if (tnode) { // Retry the query twice tnode->QueryStageRetry(Node::QueryStage_NodeInfo, 2); // Just in case the failure was due to the node being asleep, we try // to move its pending messages to its wakeup queue. If it is not // a sleeping device, this will have no effect. if (MoveMessagesToWakeUpQueue(tnode->GetNodeId(), true)) { messageRemoved = true; } } } break; } case UPDATE_STATE_NODE_INFO_REQ_DONE: { Log::Write(LogLevel_Info, nodeId, "UPDATE_STATE_NODE_INFO_REQ_DONE from node %d", nodeId); break; } case UPDATE_STATE_NODE_INFO_RECEIVED: { Log::Write(LogLevel_Info, nodeId, "UPDATE_STATE_NODE_INFO_RECEIVED from node %d", nodeId); if (node) { node->UpdateNodeInfo(&_data[8], _data[4] - 3); } break; } } if (messageRemoved) { m_waitingForAck = false; m_expectedCallbackId = 0; m_expectedReply = 0; m_expectedCommandClassId = 0; m_expectedNodeId = 0; } return messageRemoved; } //----------------------------------------------------------------------------- // // Handle common AddNode processing for many similar commands //----------------------------------------------------------------------------- void Driver::CommonAddNodeStatusRequestHandler(uint8 _funcId, uint8* _data) { uint8 nodeId = GetNodeNumber(m_currentMsg); ControllerState state = ControllerState_Normal; if (m_currentControllerCommand != NULL) { state = m_currentControllerCommand->m_controllerState; } switch (_data[3]) { case ADD_NODE_STATUS_LEARN_READY: { Log::Write(LogLevel_Info, nodeId, "ADD_NODE_STATUS_LEARN_READY"); m_currentControllerCommand->m_controllerAdded = false; state = ControllerState_Waiting; break; } case ADD_NODE_STATUS_NODE_FOUND: { Log::Write(LogLevel_Info, nodeId, "ADD_NODE_STATUS_NODE_FOUND"); state = ControllerState_InProgress; break; } case ADD_NODE_STATUS_ADDING_SLAVE: { Log::Write(LogLevel_Info, nodeId, "ADD_NODE_STATUS_ADDING_SLAVE"); Log::Write(LogLevel_Info, nodeId, "Adding node ID %d - %s", _data[4], m_currentControllerCommand->m_controllerCommandArg ? "Secure" : "Non-Secure"); /* Discovered all the CC's are sent in this packet as well: * position description * 4 - Node ID * 5 - Length * 6 - Basic Device Class * 7 - Generic Device Class * 8 - Specific Device Class * 9 to Length - Command Classes * Last pck - CRC */ if (m_currentControllerCommand != NULL) { m_currentControllerCommand->m_controllerAdded = false; m_currentControllerCommand->m_controllerCommandNode = _data[4]; /* make sure we dont overrun our buffer. Its ok to truncate */ uint8 length = _data[5]; if (length > 254) length = 254; memcpy(&m_currentControllerCommand->m_controllerDeviceProtocolInfo, &_data[6], length); m_currentControllerCommand->m_controllerDeviceProtocolInfoLength = length; } // AddNodeStop( _funcId ); // sleep(1); break; } case ADD_NODE_STATUS_ADDING_CONTROLLER: { Log::Write(LogLevel_Info, nodeId, "ADD_NODE_STATUS_ADDING_CONTROLLER"); Log::Write(LogLevel_Info, nodeId, "Adding controller ID %d", _data[4]); /* Discovered all the CC's are sent in this packet as well: * position description * 4 - Node ID * 5 - Length * 6 - Basic Device Class * 7 - Generic Device Class * 8 - Specific Device Class * 9 to Length - Command Classes * Last pck - CRC */ if (m_currentControllerCommand != NULL) { m_currentControllerCommand->m_controllerAdded = true; m_currentControllerCommand->m_controllerCommandNode = _data[4]; } // AddNodeStop( _funcId ); break; } case ADD_NODE_STATUS_PROTOCOL_DONE: { Log::Write(LogLevel_Info, nodeId, "ADD_NODE_STATUS_PROTOCOL_DONE"); // We added a device. // Get the controller out of add mode to avoid accidentally adding other devices. // We used to call replication here. AddNodeStop(_funcId); break; } case ADD_NODE_STATUS_DONE: { if (state == ControllerState_Failed) { /* if it was a failed add, we just move on */ state = ControllerState_Completed; break; } Log::Write(LogLevel_Info, nodeId, "ADD_NODE_STATUS_DONE"); state = ControllerState_Completed; if (m_currentControllerCommand != NULL && m_currentControllerCommand->m_controllerCommandNode != 0xff) { InitNode(m_currentControllerCommand->m_controllerCommandNode, true, m_currentControllerCommand->m_controllerCommandArg != 0, m_currentControllerCommand->m_controllerDeviceProtocolInfo, m_currentControllerCommand->m_controllerDeviceProtocolInfoLength); } // Not sure about the new controller function here. if (_funcId != FUNC_ID_ZW_ADD_NODE_TO_NETWORK && m_currentControllerCommand != NULL && m_currentControllerCommand->m_controllerAdded) { // Rebuild all the node info. Group and scene data that we stored // during replication will be applied as we discover each node. InitAllNodes(); } break; } case ADD_NODE_STATUS_FAILED: { Log::Write(LogLevel_Info, nodeId, "ADD_NODE_STATUS_FAILED"); state = ControllerState_Failed; // Remove the AddNode command from the queue RemoveCurrentMsg(); // Get the controller out of add mode to avoid accidentally adding other devices. AddNodeStop(_funcId); break; } default: { break; } } UpdateControllerState(state); } //----------------------------------------------------------------------------- // Polling Z-Wave devices //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Enable polling of a value //----------------------------------------------------------------------------- bool Driver::EnablePoll(ValueID const &_valueId, uint8 const _intensity) { // make sure the polling thread doesn't lock the node while we're in this function m_pollMutex->Lock(); // confirm that this node exists uint8 nodeId = _valueId.GetNodeId(); Internal::LockGuard LG(m_nodeMutex); Node* node = GetNode(nodeId); if (node != NULL) { // confirm that this value is in the node's value store if (Internal::VC::Value* value = node->GetValue(_valueId)) { // update the value's pollIntensity value->SetPollIntensity(_intensity); // Add the valueid to the polling list // See if the node is already in the poll list. for (list::iterator it = m_pollList.begin(); it != m_pollList.end(); ++it) { if ((*it).m_id == _valueId) { // It is already in the poll list, so we have nothing to do. Log::Write(LogLevel_Detail, "EnablePoll not required to do anything (value is already in the poll list)"); value->Release(); m_pollMutex->Unlock(); return true; } } // Not in the list, so we add it PollEntry pe; pe.m_id = _valueId; pe.m_pollCounter = value->GetPollIntensity(); m_pollList.push_back(pe); value->Release(); m_pollMutex->Unlock(); // send notification to indicate polling is enabled Notification* notification = new Notification(Notification::Type_PollingEnabled); notification->SetHomeAndNodeIds(m_homeId, _valueId.GetNodeId()); notification->SetValueId(_valueId); QueueNotification(notification); Log::Write(LogLevel_Info, nodeId, "EnablePoll for HomeID 0x%.8x, value(cc=0x%02x,in=0x%02x,id=0x%02x)--poll list has %d items", _valueId.GetHomeId(), _valueId.GetCommandClassId(), _valueId.GetIndex(), _valueId.GetInstance(), m_pollList.size()); WriteCache(); return true; } // allow the poll thread to continue m_pollMutex->Unlock(); Log::Write(LogLevel_Info, nodeId, "EnablePoll failed - value not found for node %d", nodeId); return false; } // allow the poll thread to continue m_pollMutex->Unlock(); Log::Write(LogLevel_Info, "EnablePoll failed - node %d not found", nodeId); return false; } //----------------------------------------------------------------------------- // // Disable polling of a node //----------------------------------------------------------------------------- bool Driver::DisablePoll(ValueID const &_valueId) { // make sure the polling thread doesn't lock the node while we're in this function m_pollMutex->Lock(); // confirm that this node exists uint8 nodeId = _valueId.GetNodeId(); Internal::LockGuard LG(m_nodeMutex); Node* node = GetNode(nodeId); if (node != NULL) { // See if the value is already in the poll list. for (list::iterator it = m_pollList.begin(); it != m_pollList.end(); ++it) { if ((*it).m_id == _valueId) { // Found it // remove it from the poll list m_pollList.erase(it); // get the value object and reset pollIntensity to zero (indicating no polling) Internal::VC::Value* value = GetValue(_valueId); if (!value) continue; value->SetPollIntensity(0); value->Release(); m_pollMutex->Unlock(); // send notification to indicate polling is disabled Notification* notification = new Notification(Notification::Type_PollingDisabled); notification->SetHomeAndNodeIds(m_homeId, _valueId.GetNodeId()); notification->SetValueId(_valueId); QueueNotification(notification); Log::Write(LogLevel_Info, nodeId, "DisablePoll for HomeID 0x%.8x, value(cc=0x%02x,in=0x%02x,id=0x%02x)--poll list has %d items", _valueId.GetHomeId(), _valueId.GetCommandClassId(), _valueId.GetIndex(), _valueId.GetInstance(), m_pollList.size()); WriteCache(); return true; } } // Not in the list m_pollMutex->Unlock(); Log::Write(LogLevel_Info, nodeId, "DisablePoll failed - value not on list"); return false; } // allow the poll thread to continue m_pollMutex->Unlock(); Log::Write(LogLevel_Info, "DisablePoll failed - node %d not found", nodeId); return false; } //----------------------------------------------------------------------------- // // Check polling status of a value //----------------------------------------------------------------------------- bool Driver::isPolled(ValueID const &_valueId) { bool bPolled; // make sure the polling thread doesn't lock the node while we're in this function m_pollMutex->Lock(); Internal::VC::Value* value = GetValue(_valueId); if (value && value->GetPollIntensity() != 0) { bPolled = true; } else { bPolled = false; } if (value) value->Release(); /* * This code is retained for the moment as a belt-and-suspenders test to confirm that * the pollIntensity member of each value and the pollList contents do not get out * of sync. */ // confirm that this node exists uint8 nodeId = _valueId.GetNodeId(); Internal::LockGuard LG(m_nodeMutex); Node* node = GetNode(nodeId); if (node != NULL) { // See if the value is already in the poll list. for (list::iterator it = m_pollList.begin(); it != m_pollList.end(); ++it) { if ((*it).m_id == _valueId) { // Found it if (bPolled) { m_pollMutex->Unlock(); return true; } else { Log::Write(LogLevel_Error, nodeId, "IsPolled setting for valueId 0x%016x is not consistent with the poll list", _valueId.GetId()); } } } // Not in the list if (!bPolled) { m_pollMutex->Unlock(); return false; } else { Log::Write(LogLevel_Error, nodeId, "IsPolled setting for valueId 0x%016x is not consistent with the poll list", _valueId.GetId()); } } // allow the poll thread to continue m_pollMutex->Unlock(); Log::Write(LogLevel_Info, "isPolled failed - node %d not found (the value reported that it is%s polled)", nodeId, bPolled ? "" : " not"); return false; } //----------------------------------------------------------------------------- // // Set the intensity with which this value is polled //----------------------------------------------------------------------------- void Driver::SetPollIntensity(ValueID const &_valueId, uint8 const _intensity) { // make sure the polling thread doesn't lock the value while we're in this function m_pollMutex->Lock(); Internal::VC::Value* value = GetValue(_valueId); if (!value) return; value->SetPollIntensity(_intensity); value->Release(); m_pollMutex->Unlock(); WriteCache(); } //----------------------------------------------------------------------------- // // Entry point of the thread for poll Z-Wave devices //----------------------------------------------------------------------------- void Driver::PollThreadEntryPoint(Internal::Platform::Event* _exitEvent, void* _context) { Driver* driver = (Driver*) _context; if (driver) { driver->PollThreadProc(_exitEvent); } } //----------------------------------------------------------------------------- // // Thread for poll Z-Wave devices //----------------------------------------------------------------------------- void Driver::PollThreadProc(Internal::Platform::Event* _exitEvent) { while (1) { int32 pollInterval = m_pollInterval; if (m_awakeNodesQueried && !m_pollList.empty()) { // We only bother getting the lock if the pollList is not empty m_pollMutex->Lock(); // Get the next value to be polled PollEntry pe = m_pollList.front(); m_pollList.pop_front(); ValueID valueId = pe.m_id; // only execute this poll if pe.m_pollCounter == 1; otherwise decrement the counter and process the next polled value if (pe.m_pollCounter != 1) { pe.m_pollCounter--; m_pollList.push_back(pe); m_pollMutex->Unlock(); continue; } // reset the poll counter to the full pollIntensity value and push it at the end of the list // release the value object referenced; call GetNode to ensure the node objects are locked during this period { Internal::LockGuard LG(m_nodeMutex); (void) GetNode(valueId.GetNodeId()); Internal::VC::Value* value = GetValue(valueId); if (!value) continue; pe.m_pollCounter = value->GetPollIntensity(); m_pollList.push_back(pe); value->Release(); } // If the polling interval is for the whole poll list, calculate the time before the next poll, // so that all polls can take place within the user-specified interval. if (!m_bIntervalBetweenPolls) { if (pollInterval < 100) { Log::Write(LogLevel_Info, "The pollInterval setting is only %d, which appears to be a legacy setting. Multiplying by 1000 to convert to ms.", pollInterval); pollInterval *= 1000; } pollInterval /= (int32) m_pollList.size(); } { Internal::LockGuard LG(m_nodeMutex); // Request the state of the value from the node to which it belongs if (Node* node = GetNode(valueId.GetNodeId())) { bool requestState = true; if (!node->IsListeningDevice()) { // The device is not awake all the time. If it is not awake, we mark it // as requiring a poll. The poll will be done next time the node wakes up. if (Internal::CC::WakeUp* wakeUp = static_cast(node->GetCommandClass(Internal::CC::WakeUp::StaticGetCommandClassId()))) { if (!wakeUp->IsAwake()) { wakeUp->SetPollRequired(); requestState = false; } } } if (requestState) { // Request an update of the value Internal::CC::CommandClass* cc = node->GetCommandClass(valueId.GetCommandClassId()); if (cc) { uint16_t index = valueId.GetIndex(); uint8_t instance = valueId.GetInstance(); Log::Write(LogLevel_Detail, node->m_nodeId, "Polling: %s index = %d instance = %d (poll queue has %d messages)", cc->GetCommandClassName().c_str(), index, instance, m_msgQueue[MsgQueue_Poll].size()); cc->RequestValue(0, index, instance, MsgQueue_Poll); } } } } m_pollMutex->Unlock(); // Polling messages are only sent when there are no other messages waiting to be sent // While this makes the polls much more variable and uncertain if some other activity dominates // a send queue, that may be appropriate // TODO we can have a debate about whether to test all four queues or just the Poll queue // Wait until the library isn't actively sending messages (or in the midst of a transaction) int i32; int loopCount = 0; while (!m_msgQueue[MsgQueue_Poll].empty() || !m_msgQueue[MsgQueue_Send].empty() || !m_msgQueue[MsgQueue_Command].empty() || !m_msgQueue[MsgQueue_Query].empty() || m_currentMsg != NULL) { i32 = Internal::Platform::Wait::Single(_exitEvent, 10); // test conditions every 10ms if (i32 == 0) { // Exit has been called return; } loopCount++; if (loopCount == 3000 * 10) // 300 seconds worth of delay? Something unusual is going on { Log::Write(LogLevel_Warning, "Poll queue hasn't been able to execute for 300 secs or more"); Log::QueueDump(); // assert( 0 ); } } // ready for next poll...insert the pollInterval delay i32 = Internal::Platform::Wait::Single(_exitEvent, pollInterval); if (i32 == 0) { // Exit has been called return; } } else // poll list is empty or awake nodes haven't been fully queried yet { // don't poll just yet, wait for the pollInterval or exit before re-checking to see if the pollList has elements int32 i32 = Internal::Platform::Wait::Single(_exitEvent, 500); if (i32 == 0) { // Exit has been called return; } } } } //----------------------------------------------------------------------------- // Retrieving Node information //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Delete all nodes and fetch new node data from the Z-Wave network //----------------------------------------------------------------------------- void Driver::InitAllNodes() { // Delete all the node data { Internal::LockGuard LG(m_nodeMutex); for (int i = 0; i < 256; ++i) { if (m_nodes[i]) { delete m_nodes[i]; m_nodes[i] = NULL; } } } // Kick off the Initilization Sequence again SendMsg(new Internal::Msg("FUNC_ID_ZW_GET_VERSION", 0xff, REQUEST, FUNC_ID_ZW_GET_VERSION, false), Driver::MsgQueue_Command); } //----------------------------------------------------------------------------- // // Queue a node to be interrogated for its setup details //----------------------------------------------------------------------------- void Driver::InitNode(uint8 const _nodeId, bool newNode, bool secure, uint8 const *_protocolInfo, uint8 const _length) { // Delete any existing node and replace it with a new one { Internal::LockGuard LG(m_nodeMutex); if (m_nodes[_nodeId]) { // Remove the original node delete m_nodes[_nodeId]; m_nodes[_nodeId] = NULL; WriteCache(); Notification* notification = new Notification(Notification::Type_NodeRemoved); notification->SetHomeAndNodeIds(m_homeId, _nodeId); QueueNotification(notification); } // Add the new node m_nodes[_nodeId] = new Node(m_homeId, _nodeId); if (newNode == true) static_cast(m_nodes[_nodeId])->SetAddingNode(); } Notification* notification = new Notification(Notification::Type_NodeAdded); notification->SetHomeAndNodeIds(m_homeId, _nodeId); QueueNotification(notification); if (_length == 0) { // Request the node info m_nodes[_nodeId]->SetQueryStage(Node::QueryStage_ProtocolInfo); } else { if (isNetworkKeySet()) m_nodes[_nodeId]->SetSecured(secure); else Log::Write(LogLevel_Info, _nodeId, "Network Key Not Set - Secure Option is %s", secure ? "required" : "not required"); m_nodes[_nodeId]->SetProtocolInfo(_protocolInfo, _length); } Log::Write(LogLevel_Info, _nodeId, "Initializing Node. New Node: %s (%s)", static_cast(m_nodes[_nodeId])->IsAddingNode() ? "true" : "false", newNode ? "true" : "false"); } //----------------------------------------------------------------------------- // // Get whether the node is a listening device that does not go to sleep //----------------------------------------------------------------------------- bool Driver::IsNodeListeningDevice(uint8 const _nodeId) { bool res = false; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { res = node->IsListeningDevice(); } return res; } //----------------------------------------------------------------------------- // // Get whether the node is a listening device that does not go to sleep //----------------------------------------------------------------------------- bool Driver::IsNodeFrequentListeningDevice(uint8 const _nodeId) { bool res = false; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { res = node->IsFrequentListeningDevice(); } return res; } //----------------------------------------------------------------------------- // // Get whether the node is a beam capable device. //----------------------------------------------------------------------------- bool Driver::IsNodeBeamingDevice(uint8 const _nodeId) { bool res = false; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { res = node->IsBeamingDevice(); } return res; } //----------------------------------------------------------------------------- // // Get whether the node is a routing device that passes messages to other nodes //----------------------------------------------------------------------------- bool Driver::IsNodeRoutingDevice(uint8 const _nodeId) { bool res = false; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { res = node->IsRoutingDevice(); } return res; } //----------------------------------------------------------------------------- // // Get the security attribute for a node //----------------------------------------------------------------------------- bool Driver::IsNodeSecurityDevice(uint8 const _nodeId) { bool security = false; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { security = node->IsSecurityDevice(); } return security; } //----------------------------------------------------------------------------- // // Get the maximum baud rate of a node's communications //----------------------------------------------------------------------------- uint32 Driver::GetNodeMaxBaudRate(uint8 const _nodeId) { uint32 baud = 0; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { baud = node->GetMaxBaudRate(); } return baud; } //----------------------------------------------------------------------------- // // Get the version number of a node //----------------------------------------------------------------------------- uint8 Driver::GetNodeVersion(uint8 const _nodeId) { uint8 version = 0; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { version = node->GetVersion(); } return version; } //----------------------------------------------------------------------------- // // Get the security byte of a node //----------------------------------------------------------------------------- uint8 Driver::GetNodeSecurity(uint8 const _nodeId) { uint8 security = 0; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { security = node->GetSecurity(); } return security; } //----------------------------------------------------------------------------- // // Get the basic type of a node //----------------------------------------------------------------------------- uint8 Driver::GetNodeBasic(uint8 const _nodeId) { uint8 basic = 0; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { basic = node->GetBasic(); } return basic; } //----------------------------------------------------------------------------- // // Get the basic type of a node //----------------------------------------------------------------------------- string Driver::GetNodeBasicString(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetBasicString(); } return "Unknown"; } //----------------------------------------------------------------------------- // // Get the generic type of a node //----------------------------------------------------------------------------- uint8 Driver::GetNodeGeneric(uint8 const _nodeId, uint8 const _instance) { uint8 genericType = 0; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { genericType = node->GetGeneric(_instance); } return genericType; } //----------------------------------------------------------------------------- // // Get the generic type of a node //----------------------------------------------------------------------------- string Driver::GetNodeGenericString(uint8 const _nodeId, uint8 const _instance) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetGenericString(_instance); } return "Unknown"; } //----------------------------------------------------------------------------- // // Get the specific type of a node //----------------------------------------------------------------------------- uint8 Driver::GetNodeSpecific(uint8 const _nodeId, uint8 const _instance) { uint8 specific = 0; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { specific = node->GetSpecific(_instance); } return specific; } //----------------------------------------------------------------------------- // // Get the specific type of a node //----------------------------------------------------------------------------- string Driver::GetNodeSpecificString(uint8 const _nodeId, uint8 const _instance) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetSpecificString(_instance); } return "Unknown"; } //----------------------------------------------------------------------------- // // Get the basic/generic/specific type of the specified node // Returns a copy of the string rather than a const ref for thread safety //----------------------------------------------------------------------------- string Driver::GetNodeType(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetType(); } return "Unknown"; } bool Driver::IsNodeZWavePlus(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->IsNodeZWavePlus(); } return false; } //----------------------------------------------------------------------------- // // Gets the neighbors for a node //----------------------------------------------------------------------------- uint32 Driver::GetNodeNeighbors(uint8 const _nodeId, uint8** o_neighbors) { uint32 numNeighbors = 0; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { numNeighbors = node->GetNeighbors(o_neighbors); } return numNeighbors; } //----------------------------------------------------------------------------- // // Get the manufacturer name for the node with the specified ID // Returns a copy of the string rather than a const ref for thread safety //----------------------------------------------------------------------------- string Driver::GetNodeManufacturerName(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetManufacturerName(); } return ""; } //----------------------------------------------------------------------------- // // Get the product name for the node with the specified ID // Returns a copy of the string rather than a const ref for thread safety //----------------------------------------------------------------------------- string Driver::GetNodeProductName(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetProductName(); } return ""; } //----------------------------------------------------------------------------- // // Get the user-editable name for the node with the specified ID // Returns a copy of the string rather than a const ref for thread safety //----------------------------------------------------------------------------- string Driver::GetNodeName(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetNodeName(); } return ""; } //----------------------------------------------------------------------------- // // Get the user-editable string for location of the specified node // Returns a copy of the string rather than a const ref for thread safety //----------------------------------------------------------------------------- string Driver::GetNodeLocation(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetLocation(); } return ""; } //----------------------------------------------------------------------------- // // Get the manufacturer Id string value with the specified ID // Returns a copy of the string rather than a const ref for thread safety //----------------------------------------------------------------------------- uint16 Driver::GetNodeManufacturerId(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetManufacturerId(); } return 0; } //----------------------------------------------------------------------------- // // Get the product type string value with the specified ID // Returns a copy of the string rather than a const ref for thread safety //----------------------------------------------------------------------------- uint16 Driver::GetNodeProductType(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetProductType(); } return 0; } //----------------------------------------------------------------------------- // // Get the product Id string value with the specified ID // Returns a copy of the string rather than a const ref for thread safety //----------------------------------------------------------------------------- uint16 Driver::GetNodeProductId(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetProductId(); } return 0; } //----------------------------------------------------------------------------- // // Get the node device type as reported in the Z-Wave+ Info report. //----------------------------------------------------------------------------- uint16 Driver::GetNodeDeviceType(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetDeviceType(); } return 0x00; // unknown } //----------------------------------------------------------------------------- // // Get the node DeviceType as a string as reported in the Z-Wave+ Info report. //----------------------------------------------------------------------------- string Driver::GetNodeDeviceTypeString(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetDeviceTypeString(); } return ""; // unknown } //----------------------------------------------------------------------------- // // Get the node role as reported in the Z-Wave+ Info report. //----------------------------------------------------------------------------- uint8 Driver::GetNodeRole(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetRoleType(); } return 0x00; // unknown } //----------------------------------------------------------------------------- // // Get the node role as a string as reported in the Z-Wave+ Info report. //----------------------------------------------------------------------------- string Driver::GetNodeRoleString(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetRoleTypeString(); } return ""; // unknown } //----------------------------------------------------------------------------- // // Get the node role as a string as reported in the Z-Wave+ Info report. //----------------------------------------------------------------------------- uint8 Driver::GetNodePlusType(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetNodeType(); } return 0x00; // unknown } //----------------------------------------------------------------------------- // // Get the node role as a string as reported in the Z-Wave+ Info report. //----------------------------------------------------------------------------- string Driver::GetNodePlusTypeString(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->GetNodeTypeString(); } return ""; // unknown } //----------------------------------------------------------------------------- // // Set the manufacturer name for the node with the specified ID //----------------------------------------------------------------------------- void Driver::SetNodeManufacturerName(uint8 const _nodeId, string const& _manufacturerName) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { node->SetManufacturerName(_manufacturerName); } WriteCache(); } //----------------------------------------------------------------------------- // // Set the product name string value with the specified ID //----------------------------------------------------------------------------- void Driver::SetNodeProductName(uint8 const _nodeId, string const& _productName) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { node->SetProductName(_productName); } WriteCache(); } //----------------------------------------------------------------------------- // // Set the node name string value with the specified ID //----------------------------------------------------------------------------- void Driver::SetNodeName(uint8 const _nodeId, string const& _nodeName) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { node->SetNodeName(_nodeName); } WriteCache(); } //----------------------------------------------------------------------------- // // Set the location string value with the specified ID //----------------------------------------------------------------------------- void Driver::SetNodeLocation(uint8 const _nodeId, string const& _location) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { node->SetLocation(_location); } WriteCache(); } //----------------------------------------------------------------------------- // // Helper to set the node level through the basic command class //----------------------------------------------------------------------------- void Driver::SetNodeLevel(uint8 const _nodeId, uint8 const _level) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { node->SetLevel(_level); } } //----------------------------------------------------------------------------- // // Helper to set the node on through the basic command class //----------------------------------------------------------------------------- void Driver::SetNodeOn(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { node->SetNodeOn(); } } //----------------------------------------------------------------------------- // // Helper to set the node off through the basic command class //----------------------------------------------------------------------------- void Driver::SetNodeOff(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { node->SetNodeOff(); } } //----------------------------------------------------------------------------- // // Get a pointer to a Value object for the specified ValueID //----------------------------------------------------------------------------- Internal::VC::Value* Driver::GetValue(ValueID const& _id) { // This method is only called by code that has already locked the node if (Node* node = m_nodes[_id.GetNodeId()]) { return node->GetValue(_id); } return NULL; } //----------------------------------------------------------------------------- // Controller commands //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Reset controller and erase all node information //----------------------------------------------------------------------------- void Driver::ResetController(Internal::Platform::Event* _evt) { m_controllerResetEvent = _evt; Log::Write(LogLevel_Info, "Reset controller and erase all node information"); Internal::Msg* msg = new Internal::Msg("Reset controller and erase all node information", 0xff, REQUEST, FUNC_ID_ZW_SET_DEFAULT, true); SendMsg(msg, MsgQueue_Command); } //----------------------------------------------------------------------------- // // Soft-reset the Z-Wave controller chip //----------------------------------------------------------------------------- void Driver::SoftReset() { Log::Write(LogLevel_Info, "Soft-resetting the Z-Wave controller chip"); Internal::Msg* msg = new Internal::Msg("Soft-resetting the Z-Wave controller chip", 0xff, REQUEST, FUNC_ID_SERIAL_API_SOFT_RESET, false, false); SendMsg(msg, MsgQueue_Command); } //----------------------------------------------------------------------------- // // Get the neighbour information for a node from the controller //----------------------------------------------------------------------------- void Driver::RequestNodeNeighbors(uint8 const _nodeId, uint32 const _requestFlags) { if (IsAPICallSupported( FUNC_ID_ZW_GET_ROUTING_INFO)) { // Note: This is not the same as RequestNodeNeighbourUpdate. This method // merely requests the controller's current neighbour information and // the reply will be copied into the relevant Node object for later use. Log::Write(LogLevel_Detail, GetNodeNumber(m_currentMsg), "Requesting routing info (neighbor list) for Node %d", _nodeId); Internal::Msg* msg = new Internal::Msg("Get Routing Info", _nodeId, REQUEST, FUNC_ID_ZW_GET_ROUTING_INFO, false); msg->Append(_nodeId); msg->Append(0); // don't remove bad links msg->Append(0); // don't remove non-repeaters msg->Append(3); // funcid SendMsg(msg, MsgQueue_Command); } } //----------------------------------------------------------------------------- // // Start the controller performing one of its network management functions // Create a ControllerCommand request. //----------------------------------------------------------------------------- bool Driver::BeginControllerCommand(ControllerCommand _command, pfnControllerCallback_t _callback, void* _context, bool _highPower, uint8 _nodeId, uint8 _arg) { ControllerCommandItem* cci; MsgQueueItem item; if (_command == ControllerCommand_None) { return false; } Log::Write(LogLevel_Detail, _nodeId, "Queuing (%s) %s", c_sendQueueNames[MsgQueue_Controller], c_controllerCommandNames[_command]); cci = new ControllerCommandItem(); cci->m_controllerCommand = _command; cci->m_controllerCallback = _callback; cci->m_controllerCallbackContext = _context; cci->m_highPower = _highPower; cci->m_controllerCommandNode = _nodeId; cci->m_controllerCommandArg = _arg; cci->m_controllerState = ControllerState_Normal; cci->m_controllerStateChanged = false; cci->m_controllerCommandDone = false; item.m_command = MsgQueueCmd_Controller; item.m_cci = cci; m_sendMutex->Lock(); m_msgQueue[MsgQueue_Controller].push_back(item); m_queueEvent[MsgQueue_Controller]->Set(); m_sendMutex->Unlock(); return true; } //----------------------------------------------------------------------------- // // Start the controller performing one of its network management functions //----------------------------------------------------------------------------- void Driver::DoControllerCommand() { UpdateControllerState(ControllerState_Starting); switch (m_currentControllerCommand->m_controllerCommand) { case ControllerCommand_AddDevice: { if (!IsPrimaryController()) { UpdateControllerState(ControllerState_Error, ControllerError_NotPrimary); } else { Log::Write(LogLevel_Info, 0, "Add Device"); Internal::Msg* msg = new Internal::Msg("ControllerCommand_AddDevice", 0xff, REQUEST, FUNC_ID_ZW_ADD_NODE_TO_NETWORK, true); uint8 options = ADD_NODE_ANY; if (m_currentControllerCommand->m_highPower) options |= OPTION_HIGH_POWER; if (IsAPICallSupported(FUNC_ID_ZW_EXPLORE_REQUEST_INCLUSION)) options |= OPTION_NWI; msg->Append(options); SendMsg(msg, MsgQueue_Command); } break; } case ControllerCommand_CreateNewPrimary: { if (IsPrimaryController()) { UpdateControllerState(ControllerState_Error, ControllerError_NotSecondary); } else if (!IsStaticUpdateController()) { UpdateControllerState(ControllerState_Error, ControllerError_NotSUC); } else { Log::Write(LogLevel_Info, 0, "Create New Primary"); Internal::Msg* msg = new Internal::Msg("ControllerCommand_CreateNewPrimary", 0xff, REQUEST, FUNC_ID_ZW_CREATE_NEW_PRIMARY, true); msg->Append( CREATE_PRIMARY_START); SendMsg(msg, MsgQueue_Command); } break; } case ControllerCommand_ReceiveConfiguration: { Log::Write(LogLevel_Info, 0, "Receive Configuration"); Internal::Msg* msg = new Internal::Msg("ControllerCommand_ReceiveConfiguration", 0xff, REQUEST, FUNC_ID_ZW_SET_LEARN_MODE, true); msg->Append(0xff); SendMsg(msg, MsgQueue_Command); break; } case ControllerCommand_RemoveDevice: { if (!IsPrimaryController()) { UpdateControllerState(ControllerState_Error, ControllerError_NotPrimary); } else { Log::Write(LogLevel_Info, 0, "Remove Device"); Internal::Msg* msg = new Internal::Msg("ControllerCommand_RemoveDevice", 0xff, REQUEST, FUNC_ID_ZW_REMOVE_NODE_FROM_NETWORK, true); msg->Append(m_currentControllerCommand->m_highPower ? REMOVE_NODE_ANY | OPTION_HIGH_POWER : REMOVE_NODE_ANY); SendMsg(msg, MsgQueue_Command); } break; } case ControllerCommand_HasNodeFailed: { Log::Write(LogLevel_Info, 0, "Requesting whether node %d has failed", m_currentControllerCommand->m_controllerCommandNode); Internal::Msg* msg = new Internal::Msg("ControllerCommand_HasNodeFailed", 0xff, REQUEST, FUNC_ID_ZW_IS_FAILED_NODE_ID, false); msg->Append(m_currentControllerCommand->m_controllerCommandNode); SendMsg(msg, MsgQueue_Command); break; } case ControllerCommand_RemoveFailedNode: { Log::Write(LogLevel_Info, 0, "ControllerCommand_RemoveFailedNode", m_currentControllerCommand->m_controllerCommandNode); Internal::Msg* msg = new Internal::Msg("ControllerCommand_RemoveFailedNode", 0xff, REQUEST, FUNC_ID_ZW_REMOVE_FAILED_NODE_ID, true); msg->Append(m_currentControllerCommand->m_controllerCommandNode); SendMsg(msg, MsgQueue_Command); break; } case ControllerCommand_ReplaceFailedNode: { Log::Write(LogLevel_Info, 0, "Replace Failed Node %d", m_currentControllerCommand->m_controllerCommandNode); Internal::Msg* msg = new Internal::Msg("ControllerCommand_ReplaceFailedNode", 0xff, REQUEST, FUNC_ID_ZW_REPLACE_FAILED_NODE, true); msg->Append(m_currentControllerCommand->m_controllerCommandNode); SendMsg(msg, MsgQueue_Command); break; } case ControllerCommand_TransferPrimaryRole: { if (!IsPrimaryController()) { UpdateControllerState(ControllerState_Error, ControllerError_NotPrimary); } else { Log::Write(LogLevel_Info, 0, "Transfer Primary Role"); Internal::Msg* msg = new Internal::Msg("ControllerCommand_TransferPrimaryRole", 0xff, REQUEST, FUNC_ID_ZW_CONTROLLER_CHANGE, true); msg->Append(m_currentControllerCommand->m_highPower ? CONTROLLER_CHANGE_START | OPTION_HIGH_POWER : CONTROLLER_CHANGE_START); SendMsg(msg, MsgQueue_Command); } break; } case ControllerCommand_RequestNetworkUpdate: { if (!IsStaticUpdateController()) { UpdateControllerState(ControllerState_Error, ControllerError_NotSUC); } else { Log::Write(LogLevel_Info, 0, "Request Network Update"); Internal::Msg* msg = new Internal::Msg("ControllerCommand_RequestNetworkUpdate", 0xff, REQUEST, FUNC_ID_ZW_REQUEST_NETWORK_UPDATE, true); SendMsg(msg, MsgQueue_Command); } break; } case ControllerCommand_RequestNodeNeighborUpdate: { if (!IsPrimaryController()) { UpdateControllerState(ControllerState_Error, ControllerError_NotPrimary); } else { Log::Write(LogLevel_Info, 0, "Requesting Neighbor Update for node %d", m_currentControllerCommand->m_controllerCommandNode); bool opts = IsAPICallSupported( FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE_OPTIONS); Internal::Msg* msg; if (opts) { msg = new Internal::Msg("ControllerCommand_RequestNodeNeighborUpdate", m_currentControllerCommand->m_controllerCommandNode, REQUEST, FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE_OPTIONS, true); } else { msg = new Internal::Msg("ControllerCommand_RequestNodeNeighborUpdate", m_currentControllerCommand->m_controllerCommandNode, REQUEST, FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE, true); } msg->Append(m_currentControllerCommand->m_controllerCommandNode); if (opts) { msg->Append(GetTransmitOptions()); } SendMsg(msg, MsgQueue_Command); } break; } case ControllerCommand_AssignReturnRoute: { Log::Write(LogLevel_Info, 0, "Assigning return route from node %d to node %d", m_currentControllerCommand->m_controllerCommandNode, m_currentControllerCommand->m_controllerCommandArg); Internal::Msg* msg = new Internal::Msg("ControllerCommand_AssignReturnRoute", m_currentControllerCommand->m_controllerCommandNode, REQUEST, FUNC_ID_ZW_ASSIGN_RETURN_ROUTE, true); msg->Append(m_currentControllerCommand->m_controllerCommandNode); // from the node msg->Append(m_currentControllerCommand->m_controllerCommandArg); // to the specific destination SendMsg(msg, MsgQueue_Command); break; } case ControllerCommand_DeleteAllReturnRoutes: { Log::Write(LogLevel_Info, 0, "Deleting all return routes from node %d", m_currentControllerCommand->m_controllerCommandNode); Internal::Msg* msg = new Internal::Msg("ControllerCommand_DeleteAllReturnRoutess", m_currentControllerCommand->m_controllerCommandNode, REQUEST, FUNC_ID_ZW_DELETE_RETURN_ROUTE, true); msg->Append(m_currentControllerCommand->m_controllerCommandNode); // from the node SendMsg(msg, MsgQueue_Command); break; } case ControllerCommand_SendNodeInformation: { Log::Write(LogLevel_Info, 0, "Sending a node information frame"); Internal::Msg* msg = new Internal::Msg("ControllerCommand_SendNodeInformation", m_currentControllerCommand->m_controllerCommandNode, REQUEST, FUNC_ID_ZW_SEND_NODE_INFORMATION, true); msg->Append(m_currentControllerCommand->m_controllerCommandNode); // to the node msg->Append(GetTransmitOptions()); SendMsg(msg, MsgQueue_Command); break; } case ControllerCommand_ReplicationSend: { if (!IsPrimaryController()) { UpdateControllerState(ControllerState_Error, ControllerError_NotPrimary); } else { Log::Write(LogLevel_Info, 0, "Replication Send"); Internal::Msg* msg = new Internal::Msg("ControllerCommand_ReplicationSend", 0xff, REQUEST, FUNC_ID_ZW_ADD_NODE_TO_NETWORK, true); msg->Append(m_currentControllerCommand->m_highPower ? ADD_NODE_CONTROLLER | OPTION_HIGH_POWER : ADD_NODE_CONTROLLER); SendMsg(msg, MsgQueue_Command); } break; } case ControllerCommand_CreateButton: { if (IsBridgeController()) { Node* node = GetNodeUnsafe(m_currentControllerCommand->m_controllerCommandNode); if (node != NULL) { if (node->m_buttonMap.find(m_currentControllerCommand->m_controllerCommandArg) == node->m_buttonMap.end() && m_virtualNeighborsReceived) { bool found = false; for (uint8 n = 1; n <= 232 && !found; n++) { if (!IsVirtualNode(n)) continue; map::iterator it = node->m_buttonMap.begin(); for (; it != node->m_buttonMap.end(); ++it) { // is virtual node already in map? if (it->second == n) break; } if (it == node->m_buttonMap.end()) // found unused virtual node { node->m_buttonMap[m_currentControllerCommand->m_controllerCommandArg] = n; SendVirtualNodeInfo(n, m_currentControllerCommand->m_controllerCommandNode); found = true; } } if (!found) // create a new virtual node { Log::Write(LogLevel_Info, 0, "AddVirtualNode"); Internal::Msg* msg = new Internal::Msg("FUNC_ID_SERIAL_API_SLAVE_NODE_INFO", 0xff, REQUEST, FUNC_ID_SERIAL_API_SLAVE_NODE_INFO, false, false); msg->Append(0); // node 0 msg->Append(1); // listening msg->Append(0x09); // genericType window covering msg->Append(0x00); // specificType undefined msg->Append(0); // length SendMsg(msg, MsgQueue_Command); msg = new Internal::Msg("FUNC_ID_ZW_SET_SLAVE_LEARN_MODE", 0xff, REQUEST, FUNC_ID_ZW_SET_SLAVE_LEARN_MODE, true); msg->Append(0); // node 0 to add if (IsPrimaryController() || IsInclusionController()) { msg->Append( SLAVE_LEARN_MODE_ADD); } else { msg->Append( SLAVE_LEARN_MODE_ENABLE); } SendMsg(msg, MsgQueue_Command); } } else { UpdateControllerState(ControllerState_Error, ControllerError_ButtonNotFound); } } else { UpdateControllerState(ControllerState_Error, ControllerError_NodeNotFound); } } else { UpdateControllerState(ControllerState_Error, ControllerError_NotBridge); } break; } case ControllerCommand_DeleteButton: { if (IsBridgeController()) { Node* node = GetNodeUnsafe(m_currentControllerCommand->m_controllerCommandNode); if (node != NULL) { // Make sure button is allocated to a virtual node. if (node->m_buttonMap.find(m_currentControllerCommand->m_controllerCommandArg) != node->m_buttonMap.end()) { #ifdef notdef // We would need a reference count to decide when to free virtual nodes // We could do this by making the bitmap of virtual nodes into a map that also holds a reference count. Log::Write( LogLevel_Info, 0, "RemoveVirtualNode %d", m_currentControllerCommand->m_controllerCommandNode ); Msg* msg = new Msg( "Remove Virtual Node", 0xff, REQUEST, FUNC_ID_ZW_SET_SLAVE_LEARN_MODE, true ); msg->Append( m_currentControllerCommand->m_controllerCommandNode );// from the node if( IsPrimaryController() || IsInclusionController() ) msg->Append( SLAVE_LEARN_MODE_REMOVE ); else msg->Append( SLAVE_LEARN_MODE_ENABLE ); SendMsg( msg ); #endif node->m_buttonMap.erase(m_currentControllerCommand->m_controllerCommandArg); SaveButtons(); Notification* notification = new Notification(Notification::Type_DeleteButton); notification->SetHomeAndNodeIds(m_homeId, m_currentControllerCommand->m_controllerCommandNode); notification->SetButtonId(m_currentControllerCommand->m_controllerCommandArg); QueueNotification(notification); } else { UpdateControllerState(ControllerState_Error, ControllerError_ButtonNotFound); } } else { UpdateControllerState(ControllerState_Error, ControllerError_NodeNotFound); } } else { UpdateControllerState(ControllerState_Error, ControllerError_NotBridge); } break; } case ControllerCommand_None: { // To keep gcc quiet break; } } } //----------------------------------------------------------------------------- // // Stop the current controller function //----------------------------------------------------------------------------- void Driver::UpdateControllerState(ControllerState const _state, ControllerError const _error) { if (m_currentControllerCommand != NULL) { if (_state != m_currentControllerCommand->m_controllerState) { m_currentControllerCommand->m_controllerStateChanged = true; m_currentControllerCommand->m_controllerState = _state; switch (_state) { case ControllerState_Error: case ControllerState_Cancel: case ControllerState_Failed: case ControllerState_Sleeping: case ControllerState_NodeFailed: case ControllerState_NodeOK: case ControllerState_Completed: { m_currentControllerCommand->m_controllerCommandDone = true; m_sendMutex->Lock(); m_queueEvent[MsgQueue_Controller]->Set(); m_sendMutex->Unlock(); break; } default: { break; } } } Notification* notification = new Notification(Notification::Type_ControllerCommand); // PR #1879 // The change below sets the nodeId in the notifications for controller state changes. These state changes are // caused by controller commands. Below is a list of controller commands with what the nodeId gets set to, // along with the Manager method(s) that use the controller command. // Driver::ControllerCommand_RequestNodeNeighborUpdate: supplied nodeId (Manager::HealNetworkNode, Manager::HealNetwork) // Driver::ControllerCommand_AddDevice: nodeId of an added node (Manager::AddNode) // Driver::ControllerCommand_RemoveDevice: nodeId of a removed node (Manager::RemoveNode) // Driver::ControllerCommand_RemoveFailedNode: supplied nodeId (Manager::RemoveFailedNode) // Driver::ControllerCommand_HasNodeFailed supplied nodeId (Manager::HasNodeFailed) // Driver::ControllerCommand_AssignReturnRoute: supplied nodeId (Manager::AssignReturnRoute) // Driver::ControllerCommand_RequestNodeNeighborUpdate: supplied nodeId (Manager::RequestNodeNeighborUpdate) // Driver::ControllerCommand_DeleteAllReturnRoutes supplied nodeId (Manager::DeleteAllReturnRoutes) // Driver::ControllerCommand_SendNodeInformation: supplied nodeId (Manager::SendNodeInformation) // Driver::ControllerCommand_CreateNewPrimary: unknown (Manager::CreateNewPrimary) // Driver::ControllerCommand_ReceiveConfiguration: unknown (Manager::ReceiveConfiguration) // Driver::ControllerCommand_ReplaceFailedNode: could be the supplied nodeId or the nodeId of the node that was added (Manager::ReplaceFailedNode) // Driver::ControllerCommand_TransferPrimaryRole: unknown (Manager::TransferPrimaryRole) // Driver::ControllerCommand_RequestNetworkUpdate: supplied nodeId (Manager::RequestNetworkUpdate) // Driver::ControllerCommand_ReplicationSend: supplied nodeId (Manager::ReplicationSend) // Driver::ControllerCommand_CreateButton: supplied nodeId (Manager::CreateButton) // Driver::ControllerCommand_DeleteButton: supplied nodeId (Manager::DeleteButton) notification->SetHomeAndNodeIds(m_homeId, m_currentControllerCommand->m_controllerCommandNode); notification->SetCommand(m_currentControllerCommand->m_controllerCommand); notification->SetEvent(_state); if (_error != ControllerError_None) { m_currentControllerCommand->m_controllerReturnError = _error; /* Create a new Notification Callback */ notification->SetNotification(_error); } QueueNotification(notification); } } //----------------------------------------------------------------------------- // // Stop the current controller function //----------------------------------------------------------------------------- bool Driver::CancelControllerCommand() { if (m_currentControllerCommand == NULL) { // Controller is not doing anything return false; } switch (m_currentControllerCommand->m_controllerCommand) { case ControllerCommand_AddDevice: { Log::Write(LogLevel_Info, 0, "Cancel Add Node"); m_currentControllerCommand->m_controllerCommandNode = 0xff; // identify the fact that there is no new node to initialize AddNodeStop( FUNC_ID_ZW_ADD_NODE_TO_NETWORK); break; } case ControllerCommand_CreateNewPrimary: { Log::Write(LogLevel_Info, 0, "Cancel Create New Primary"); Internal::Msg* msg = new Internal::Msg("CreateNewPrimary Stop", 0xff, REQUEST, FUNC_ID_ZW_CREATE_NEW_PRIMARY, true); msg->Append( CREATE_PRIMARY_STOP); SendMsg(msg, MsgQueue_Command); break; } case ControllerCommand_ReceiveConfiguration: { Log::Write(LogLevel_Info, 0, "Cancel Receive Configuration"); Internal::Msg* msg = new Internal::Msg("ReceiveConfiguration Stop", 0xff, REQUEST, FUNC_ID_ZW_SET_LEARN_MODE, false, false); msg->Append(0); SendMsg(msg, MsgQueue_Command); break; } case ControllerCommand_RemoveDevice: { Log::Write(LogLevel_Info, 0, "Cancel Remove Device"); m_currentControllerCommand->m_controllerCommandNode = 0xff; // identify the fact that there is no node to remove AddNodeStop( FUNC_ID_ZW_REMOVE_NODE_FROM_NETWORK); break; } case ControllerCommand_TransferPrimaryRole: { Log::Write(LogLevel_Info, 0, "Cancel Transfer Primary Role"); Internal::Msg* msg = new Internal::Msg("Transfer Primary Role Stop", 0xff, REQUEST, FUNC_ID_ZW_CONTROLLER_CHANGE, true); msg->Append( CONTROLLER_CHANGE_STOP); SendMsg(msg, MsgQueue_Command); break; } case ControllerCommand_ReplicationSend: { Log::Write(LogLevel_Info, 0, "Cancel Replication Send"); m_currentControllerCommand->m_controllerCommandNode = 0xff; // identify the fact that there is no new node to initialize AddNodeStop( FUNC_ID_ZW_ADD_NODE_TO_NETWORK); break; } case ControllerCommand_CreateButton: case ControllerCommand_DeleteButton: { if (m_currentControllerCommand->m_controllerCommandNode != 0) { SendSlaveLearnModeOff(); } break; } case ControllerCommand_None: case ControllerCommand_RequestNetworkUpdate: case ControllerCommand_RequestNodeNeighborUpdate: case ControllerCommand_AssignReturnRoute: case ControllerCommand_DeleteAllReturnRoutes: case ControllerCommand_RemoveFailedNode: case ControllerCommand_HasNodeFailed: case ControllerCommand_ReplaceFailedNode: case ControllerCommand_SendNodeInformation: { // Cannot cancel return false; } } UpdateControllerState(ControllerState_Cancel); return true; } //----------------------------------------------------------------------------- // // Stop the Add Node mode based on API of controller //----------------------------------------------------------------------------- void Driver::AddNodeStop(uint8 const _funcId) { if (m_currentControllerCommand == NULL) { // Controller is not doing anything return; } if (m_serialAPIVersion[0] == 2 && m_serialAPIVersion[1] == 76) { Internal::Msg* msg = new Internal::Msg("Add Node Stop", 0xff, REQUEST, _funcId, false, false); msg->Append( ADD_NODE_STOP); SendMsg(msg, Driver::MsgQueue_Command); } else { Internal::Msg* msg = new Internal::Msg("Add Node Stop", 0xff, REQUEST, _funcId, false, true); msg->Append( ADD_NODE_STOP); SendMsg(msg, Driver::MsgQueue_Command); } } //----------------------------------------------------------------------------- // // Run a series of messages to a single node or every node on the network. //----------------------------------------------------------------------------- void Driver::TestNetwork(uint8 const _nodeId, uint32 const _count) { Internal::LockGuard LG(m_nodeMutex); if (_nodeId == 0) // send _count messages to every node { for (int i = 0; i < 256; ++i) { if (i == m_Controller_nodeId) // ignore sending to ourself { continue; } if (m_nodes[i] != NULL) { Internal::CC::NoOperation *noop = static_cast(m_nodes[i]->GetCommandClass(Internal::CC::NoOperation::StaticGetCommandClassId())); for (int j = 0; j < (int) _count; j++) { noop->Set(true); } } } } else if (_nodeId != m_Controller_nodeId && m_nodes[_nodeId] != NULL) { Internal::CC::NoOperation *noop = static_cast(m_nodes[_nodeId]->GetCommandClass(Internal::CC::NoOperation::StaticGetCommandClassId())); for (int i = 0; i < (int) _count; i++) { noop->Set(true); } } } //----------------------------------------------------------------------------- // SwitchAll //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // All devices that support the SwitchAll command class will be turned on //----------------------------------------------------------------------------- void Driver::SwitchAllOn() { Internal::CC::SwitchAll::On(this, 0xff); Internal::LockGuard LG(m_nodeMutex); for (int i = 0; i < 256; ++i) { if (GetNodeUnsafe(i)) { if (m_nodes[i]->GetCommandClass(Internal::CC::SwitchAll::StaticGetCommandClassId())) { Internal::CC::SwitchAll::On(this, (uint8) i); } } } } //----------------------------------------------------------------------------- // // All devices that support the SwitchAll command class will be turned off //----------------------------------------------------------------------------- void Driver::SwitchAllOff() { Internal::CC::SwitchAll::Off(this, 0xff); Internal::LockGuard LG(m_nodeMutex); for (int i = 0; i < 256; ++i) { if (GetNodeUnsafe(i)) { if (m_nodes[i]->GetCommandClass(Internal::CC::SwitchAll::StaticGetCommandClassId())) { Internal::CC::SwitchAll::Off(this, (uint8) i); } } } } //----------------------------------------------------------------------------- // // Set the value of one of the configuration parameters of a device //----------------------------------------------------------------------------- bool Driver::SetConfigParam(uint8 const _nodeId, uint8 const _param, int32 _value, uint8 _size) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { return node->SetConfigParam(_param, _value, _size); } return false; } //----------------------------------------------------------------------------- // // Request the value of one of the configuration parameters of a device //----------------------------------------------------------------------------- void Driver::RequestConfigParam(uint8 const _nodeId, uint8 const _param) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { node->RequestConfigParam(_param); } } //----------------------------------------------------------------------------- // // Gets the number of association groups reported by this node //----------------------------------------------------------------------------- uint8 Driver::GetNumGroups(uint8 const _nodeId) { uint8 numGroups = 0; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { numGroups = node->GetNumGroups(); } return numGroups; } //----------------------------------------------------------------------------- // // Gets the associations for a group //----------------------------------------------------------------------------- uint32 Driver::GetAssociations(uint8 const _nodeId, uint8 const _groupIdx, uint8** o_associations) { uint32 numAssociations = 0; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { numAssociations = node->GetAssociations(_groupIdx, o_associations); } return numAssociations; } //----------------------------------------------------------------------------- // // Gets the associations for a group //----------------------------------------------------------------------------- uint32 Driver::GetAssociations(uint8 const _nodeId, uint8 const _groupIdx, InstanceAssociation** o_associations) { uint32 numAssociations = 0; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { numAssociations = node->GetAssociations(_groupIdx, o_associations); } return numAssociations; } //----------------------------------------------------------------------------- // // Gets the maximum number of associations for a group //----------------------------------------------------------------------------- uint8 Driver::GetMaxAssociations(uint8 const _nodeId, uint8 const _groupIdx) { uint8 maxAssociations = 0; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { maxAssociations = node->GetMaxAssociations(_groupIdx); } return maxAssociations; } //----------------------------------------------------------------------------- // // Returns true if group supports multi instance //----------------------------------------------------------------------------- bool Driver::IsMultiInstance(uint8 const _nodeId, uint8 const _groupIdx) { bool multiInstance = false; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { multiInstance = node->IsMultiInstance(_groupIdx); } return multiInstance; } //----------------------------------------------------------------------------- // // Gets the label for a particular group //----------------------------------------------------------------------------- string Driver::GetGroupLabel(uint8 const _nodeId, uint8 const _groupIdx) { string label = ""; Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { label = node->GetGroupLabel(_groupIdx); } return label; } //----------------------------------------------------------------------------- // // Adds a node to an association group //----------------------------------------------------------------------------- void Driver::AddAssociation(uint8 const _nodeId, uint8 const _groupIdx, uint8 const _targetNodeId, uint8 const _instance) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { node->AddAssociation(_groupIdx, _targetNodeId, _instance); } } //----------------------------------------------------------------------------- // // Removes a node from an association group //----------------------------------------------------------------------------- void Driver::RemoveAssociation(uint8 const _nodeId, uint8 const _groupIdx, uint8 const _targetNodeId, uint8 const _instance) { Internal::LockGuard LG(m_nodeMutex); if (Node* node = GetNode(_nodeId)) { node->RemoveAssociation(_groupIdx, _targetNodeId, _instance); } } //----------------------------------------------------------------------------- // // Add a notification to the queue to be sent at a later, safe time. //----------------------------------------------------------------------------- void Driver::QueueNotification(Notification* _notification) { m_notifications.push_back(_notification); m_notificationsEvent->Set(); } //----------------------------------------------------------------------------- // // Notify any watching objects of a value change //----------------------------------------------------------------------------- void Driver::NotifyWatchers() { list::iterator nit = m_notifications.begin(); while (nit != m_notifications.end()) { Notification* notification = m_notifications.front(); m_notifications.pop_front(); /* check the any ValueID's sent as part of the Notification are still valid */ switch (notification->GetType()) { case Notification::Type_ValueAdded: case Notification::Type_ValueChanged: case Notification::Type_ValueRefreshed: { Internal::VC::Value *val = GetValue(notification->GetValueID()); if (!val) { Log::Write(LogLevel_Info, notification->GetNodeId(), "Dropping Notification as ValueID does not exist"); nit = m_notifications.begin(); delete notification; continue; } val->Release(); break; } default: break; } Log::Write(LogLevel_Detail, notification->GetNodeId(), "Notification: %s", notification->GetAsString().c_str()); Manager::Get()->NotifyWatchers(notification); delete notification; nit = m_notifications.begin(); } m_notificationsEvent->Reset(); } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- bool Driver::HandleRfPowerLevelSetResponse(uint8* _data) { bool res = true; // the meaning of this command is currently unclear, and there // isn't any returned response data, so just log the function call Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to FUNC_ID_ZW_R_F_POWER_LEVEL_SET"); return res; } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- bool Driver::HandleSerialApiSetTimeoutsResponse(uint8* _data) { // the meaning of this command and its response is currently unclear bool res = true; Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to FUNC_ID_SERIAL_API_SET_TIMEOUTS"); return res; } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- bool Driver::HandleMemoryGetByteResponse(uint8* _data) { bool res = true; // the meaning of this command and its response is currently unclear // it seems to return three bytes of data, so print them out Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to FUNC_ID_ZW_MEMORY_GET_BYTE, returned data: 0x%02hx 0x%02hx 0x%02hx", _data[0], _data[1], _data[2]); return res; } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- bool Driver::HandleReadMemoryResponse(uint8* _data) { // the meaning of this command and its response is currently unclear bool res = true; Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "Received reply to FUNC_ID_MEMORY_GET_BYTE"); return res; } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleGetVirtualNodesResponse(uint8* _data) { uint8 nodeId = GetNodeNumber(m_currentMsg); Log::Write(LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_GET_VIRTUAL_NODES"); memcpy(m_virtualNeighbors, &_data[2], 29); m_virtualNeighborsReceived = true; bool bNeighbors = false; for (int by = 0; by < 29; by++) { for (int bi = 0; bi < 8; bi++) { if ((_data[2 + by] & (0x01 << bi))) { Log::Write(LogLevel_Info, nodeId, " Node %d", (by << 3) + bi + 1); bNeighbors = true; } } } if (!bNeighbors) Log::Write(LogLevel_Info, nodeId, " (none reported)"); } //----------------------------------------------------------------------------- // // Gets the virtual neighbors for a network //----------------------------------------------------------------------------- uint32 Driver::GetVirtualNeighbors(uint8** o_neighbors) { int i; uint32 numNeighbors = 0; if (!m_virtualNeighborsReceived) { *o_neighbors = NULL; return 0; } for (i = 0; i < 29; i++) { for (unsigned char mask = 0x80; mask != 0; mask >>= 1) if (m_virtualNeighbors[i] & mask) numNeighbors++; } // handle the possibility that no neighbors are reported if (!numNeighbors) { *o_neighbors = NULL; return 0; } // create and populate an array with neighbor node ids uint8* neighbors = new uint8[numNeighbors]; uint32 index = 0; for (int by = 0; by < 29; by++) { for (int bi = 0; bi < 8; bi++) { if ((m_virtualNeighbors[by] & (0x01 << bi))) neighbors[index++] = ((by << 3) + bi + 1); } } *o_neighbors = neighbors; return numNeighbors; } //----------------------------------------------------------------------------- // // Get the virtual neighbour information from the controller //----------------------------------------------------------------------------- void Driver::RequestVirtualNeighbors(MsgQueue const _queue) { Internal::Msg* msg = new Internal::Msg("Get Virtual Neighbor List", 0xff, REQUEST, FUNC_ID_ZW_GET_VIRTUAL_NODES, false); SendMsg(msg, _queue); } //----------------------------------------------------------------------------- // // Send node info frame on behalf of a virtual node. //----------------------------------------------------------------------------- void Driver::SendVirtualNodeInfo(uint8 const _FromNodeId, uint8 const _ToNodeId) { char str[80]; snprintf(str, sizeof(str), "Send Virtual Node Info from %d to %d", _FromNodeId, _ToNodeId); Internal::Msg* msg = new Internal::Msg(str, 0xff, REQUEST, FUNC_ID_ZW_SEND_SLAVE_NODE_INFO, true); msg->Append(_FromNodeId); // from the virtual node msg->Append(_ToNodeId); // to the handheld controller msg->Append( TRANSMIT_OPTION_ACK); SendMsg(msg, MsgQueue_Command); } //----------------------------------------------------------------------------- // // Disable Slave Learn Mode. //----------------------------------------------------------------------------- void Driver::SendSlaveLearnModeOff() { if (!(IsPrimaryController() || IsInclusionController())) { Internal::Msg* msg = new Internal::Msg("Set Slave Learn Mode Off ", 0xff, REQUEST, FUNC_ID_ZW_SET_SLAVE_LEARN_MODE, true); msg->Append(0); // filler node id msg->Append( SLAVE_LEARN_MODE_DISABLE); SendMsg(msg, MsgQueue_Command); } } //----------------------------------------------------------------------------- // // Save button info into file. //----------------------------------------------------------------------------- void Driver::SaveButtons() { char str[16]; // Create a new XML document to contain the driver configuration TiXmlDocument doc; TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "utf-8", ""); TiXmlElement* nodesElement = new TiXmlElement("Nodes"); doc.LinkEndChild(decl); doc.LinkEndChild(nodesElement); nodesElement->SetAttribute("xmlns", "http://code.google.com/p/open-zwave/"); snprintf(str, sizeof(str), "%d", 1); nodesElement->SetAttribute("version", str); Internal::LockGuard LG(m_nodeMutex); for (int i = 1; i < 256; i++) { if (m_nodes[i] == NULL || m_nodes[i]->m_buttonMap.empty()) { continue; } TiXmlElement* nodeElement = new TiXmlElement("Node"); snprintf(str, sizeof(str), "%d", i); nodeElement->SetAttribute("id", str); for (map::iterator it = m_nodes[i]->m_buttonMap.begin(); it != m_nodes[i]->m_buttonMap.end(); ++it) { TiXmlElement* valueElement = new TiXmlElement("Button"); snprintf(str, sizeof(str), "%d", it->first); valueElement->SetAttribute("id", str); snprintf(str, sizeof(str), "%d", it->second); TiXmlText* textElement = new TiXmlText(str); valueElement->LinkEndChild(textElement); nodeElement->LinkEndChild(valueElement); } nodesElement->LinkEndChild(nodeElement); } string userPath; Options::Get()->GetOptionAsString("UserPath", &userPath); string filename = userPath + "zwbutton.xml"; doc.SaveFile(filename.c_str()); } //----------------------------------------------------------------------------- // // Read button info per node from file. //----------------------------------------------------------------------------- void Driver::ReadButtons(uint8 const _nodeId) { int32 intVal; int32 nodeId; int32 buttonId; char const* str; // Load the XML document that contains the driver configuration string userPath; Options::Get()->GetOptionAsString("UserPath", &userPath); string filename = userPath + "zwbutton.xml"; TiXmlDocument doc; if (!doc.LoadFile(filename.c_str(), TIXML_ENCODING_UTF8)) { Log::Write(LogLevel_Debug, "Driver::ReadButtons - zwbutton.xml file not found."); return; } doc.SetUserData((void *) filename.c_str()); TiXmlElement const* nodesElement = doc.RootElement(); str = nodesElement->Value(); if (str && strcmp(str, "Nodes")) { Log::Write(LogLevel_Warning, "WARNING: Driver::ReadButtons - zwbutton.xml is malformed"); return; } // Version if (TIXML_SUCCESS == nodesElement->QueryIntAttribute("version", &intVal)) { if ((uint32) intVal != 1) { Log::Write(LogLevel_Info, "Driver::ReadButtons - %s is from an older version of OpenZWave and cannot be loaded.", "zwbutton.xml"); return; } } else { Log::Write(LogLevel_Warning, "WARNING: Driver::ReadButtons - zwbutton.xml is from an older version of OpenZWave and cannot be loaded."); return; } TiXmlElement const* nodeElement = nodesElement->FirstChildElement(); while (nodeElement) { str = nodeElement->Value(); if (str && !strcmp(str, "Node")) { Node* node = NULL; if (TIXML_SUCCESS == nodeElement->QueryIntAttribute("id", &intVal)) { if (_nodeId == intVal) { node = GetNodeUnsafe(intVal); } } if (node != NULL) { TiXmlElement const* buttonElement = nodeElement->FirstChildElement(); while (buttonElement) { str = buttonElement->Value(); if (str && !strcmp(str, "Button")) { if (TIXML_SUCCESS != buttonElement->QueryIntAttribute("id", &buttonId)) { Log::Write(LogLevel_Warning, "WARNING: Driver::ReadButtons - cannot find Button Id for node %d", _nodeId); return; } str = buttonElement->GetText(); if (str) { char *p; nodeId = (int32) strtol(str, &p, 0); } else { Log::Write(LogLevel_Info, "Driver::ReadButtons - missing virtual node value for node %d button id %d", _nodeId, buttonId); return; } node->m_buttonMap[buttonId] = nodeId; Notification* notification = new Notification(Notification::Type_CreateButton); notification->SetHomeAndNodeIds(m_homeId, nodeId); notification->SetButtonId(buttonId); QueueNotification(notification); } buttonElement = buttonElement->NextSiblingElement(); } } } nodeElement = nodeElement->NextSiblingElement(); } } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- bool Driver::HandleSetSlaveLearnModeResponse(uint8* _data) { bool res = true; ControllerState state = ControllerState_InProgress; uint8 nodeId = GetNodeNumber(m_currentMsg); if (_data[2]) { Log::Write(LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_SET_SLAVE_LEARN_MODE - command in progress"); } else { // Failed Log::Write(LogLevel_Warning, nodeId, "WARNING: Received reply to FUNC_ID_ZW_SET_SLAVE_LEARN_MODE - command failed"); state = ControllerState_Failed; res = false; SendSlaveLearnModeOff(); } UpdateControllerState(state); return res; } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleSetSlaveLearnModeRequest(uint8* _data) { ControllerState state = ControllerState_Waiting; uint8 nodeId = GetNodeNumber(m_currentMsg); if (m_currentControllerCommand == NULL) { return; } SendSlaveLearnModeOff(); switch (_data[3]) { case SLAVE_ASSIGN_COMPLETE: { Log::Write(LogLevel_Info, nodeId, "SLAVE_ASSIGN_COMPLETE"); if (_data[4] == 0) // original node is 0 so adding { Log::Write(LogLevel_Info, nodeId, "Adding virtual node ID %d", _data[5]); Node* node = GetNodeUnsafe(m_currentControllerCommand->m_controllerCommandNode); if (node != NULL) { node->m_buttonMap[m_currentControllerCommand->m_controllerCommandArg] = _data[5]; SendVirtualNodeInfo(_data[5], m_currentControllerCommand->m_controllerCommandNode); } } else if (_data[5] == 0) { Log::Write(LogLevel_Info, nodeId, "Removing virtual node ID %d", _data[4]); } break; } case SLAVE_ASSIGN_NODEID_DONE: { Log::Write(LogLevel_Info, nodeId, "SLAVE_ASSIGN_NODEID_DONE"); if (_data[4] == 0) // original node is 0 so adding { Log::Write(LogLevel_Info, nodeId, "Adding virtual node ID %d", _data[5]); Node* node = GetNodeUnsafe(m_currentControllerCommand->m_controllerCommandNode); if (node != NULL) { node->m_buttonMap[m_currentControllerCommand->m_controllerCommandArg] = _data[5]; SendVirtualNodeInfo(_data[5], m_currentControllerCommand->m_controllerCommandNode); } } else if (_data[5] == 0) { Log::Write(LogLevel_Info, nodeId, "Removing virtual node ID %d", _data[4]); } break; } case SLAVE_ASSIGN_RANGE_INFO_UPDATE: { Log::Write(LogLevel_Info, nodeId, "SLAVE_ASSIGN_RANGE_INFO_UPDATE"); break; } } m_currentControllerCommand->m_controllerAdded = false; UpdateControllerState(state); } //----------------------------------------------------------------------------- // // Process a response from the Z-Wave PC interface //----------------------------------------------------------------------------- bool Driver::HandleSendSlaveNodeInfoResponse(uint8* _data) { bool res = true; ControllerState state = ControllerState_InProgress; uint8 nodeId = GetNodeNumber(m_currentMsg); if (m_currentControllerCommand == NULL) { return false; } if (_data[2]) { Log::Write(LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_SEND_SLAVE_NODE_INFO - command in progress"); } else { // Failed Log::Write(LogLevel_Info, nodeId, "Received reply to FUNC_ID_ZW_SEND_SLAVE_NODE_INFO - command failed"); state = ControllerState_Failed; // Undo button map settings Node* node = GetNodeUnsafe(m_currentControllerCommand->m_controllerCommandNode); if (node != NULL) { node->m_buttonMap.erase(m_currentControllerCommand->m_controllerCommandArg); } res = false; } UpdateControllerState(state); return res; } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleSendSlaveNodeInfoRequest(uint8* _data) { if (m_currentControllerCommand == NULL) { return; } if (_data[3] == TRANSMIT_COMPLETE_OK) // finish up { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "SEND_SLAVE_NODE_INFO_COMPLETE OK"); SaveButtons(); Notification* notification = new Notification(Notification::Type_CreateButton); notification->SetHomeAndNodeIds(m_homeId, m_currentControllerCommand->m_controllerCommandNode); notification->SetButtonId(m_currentControllerCommand->m_controllerCommandArg); QueueNotification(notification); UpdateControllerState(ControllerState_Completed); RequestVirtualNeighbors(MsgQueue_Send); } else // error. try again { HandleErrorResponse(_data[3], m_currentControllerCommand->m_controllerCommandNode, "SLAVE_NODE_INFO_COMPLETE"); Node* node = GetNodeUnsafe(m_currentControllerCommand->m_controllerCommandNode); if (node != NULL) { SendVirtualNodeInfo(node->m_buttonMap[m_currentControllerCommand->m_controllerCommandArg], m_currentControllerCommand->m_controllerCommandNode); } } } //----------------------------------------------------------------------------- // // Process a request from the Z-Wave PC interface //----------------------------------------------------------------------------- void Driver::HandleApplicationSlaveCommandRequest(uint8* _data) { Log::Write(LogLevel_Info, GetNodeNumber(m_currentMsg), "APPLICATION_SLAVE_COMMAND_HANDLER rxStatus %x dest %d source %d len %d", _data[2], _data[3], _data[4], _data[5]); Node* node = GetNodeUnsafe(_data[4]); if (node != NULL && _data[5] == 3 && _data[6] == 0x20 && _data[7] == 0x01) // only support Basic Set for now { map::iterator it = node->m_buttonMap.begin(); for (; it != node->m_buttonMap.end(); ++it) { if (it->second == _data[3]) break; } if (it != node->m_buttonMap.end()) { Notification *notification; if (_data[8] == 0) { notification = new Notification(Notification::Type_ButtonOff); } else { notification = new Notification(Notification::Type_ButtonOn); } notification->SetHomeAndNodeIds(m_homeId, _data[4]); notification->SetButtonId(it->first); QueueNotification(notification); } } } //----------------------------------------------------------------------------- // // See if we can get node from incoming message data //----------------------------------------------------------------------------- uint8 Driver::NodeFromMessage(uint8 const* buffer) { uint8 nodeId = 0; if (buffer[1] >= 5) { switch (buffer[3]) { case FUNC_ID_APPLICATION_COMMAND_HANDLER: nodeId = buffer[5]; break; case FUNC_ID_ZW_APPLICATION_UPDATE: nodeId = buffer[5]; break; } } return nodeId; } //----------------------------------------------------------------------------- // // Update a node's routing information //----------------------------------------------------------------------------- void Driver::UpdateNodeRoutes(uint8 const _nodeId, bool _doUpdate // = false ) { // Only for routing slaves Node* node = GetNodeUnsafe(_nodeId); if (node != NULL && node->GetBasic() == 0x04) { uint8 numGroups = GetNumGroups(_nodeId); uint8 numNodes = 0; uint8 nodes[5]; InstanceAssociation* associations; uint8 i; // Determine up to 5 destinations memset(nodes, 0, sizeof(nodes)); for (i = 1; i <= numGroups && numNodes < sizeof(nodes); i++) { associations = NULL; uint32 len = GetAssociations(_nodeId, i, &associations); for (uint8 j = 0; j < len; j++) { uint8 k; /* there is a gcc bug that triggers here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 * see also https://github.com/OpenZWave/open-zwave/issues/586 */ for (k = 0; k < numNodes && k < sizeof(nodes); k++) { if (nodes[k] == associations[j].m_nodeId) { break; } } if (k >= numNodes && numNodes < sizeof(nodes)) // not in list so add it { nodes[numNodes++] = associations[j].m_nodeId; } } if (associations != NULL) { delete[] associations; } } if (_doUpdate || numNodes != node->m_numRouteNodes || memcmp(nodes, node->m_routeNodes, sizeof(node->m_routeNodes)) != 0) { // Figure out what to do if one of these fail. BeginControllerCommand(ControllerCommand_DeleteAllReturnRoutes, NULL, NULL, true, _nodeId, 0); for (i = 0; i < numNodes; i++) { BeginControllerCommand(ControllerCommand_AssignReturnRoute, NULL, NULL, true, _nodeId, nodes[i]); } node->m_numRouteNodes = numNodes; memcpy(node->m_routeNodes, nodes, sizeof(nodes)); } } } //----------------------------------------------------------------------------- // // Return driver statistics //----------------------------------------------------------------------------- void Driver::GetDriverStatistics(DriverData* _data) { _data->m_SOFCnt = m_SOFCnt; _data->m_ACKWaiting = m_ACKWaiting; _data->m_readAborts = m_readAborts; _data->m_badChecksum = m_badChecksum; _data->m_readCnt = m_readCnt; _data->m_writeCnt = m_writeCnt; _data->m_CANCnt = m_CANCnt; _data->m_NAKCnt = m_NAKCnt; _data->m_ACKCnt = m_ACKCnt; _data->m_OOFCnt = m_OOFCnt; _data->m_dropped = m_dropped; _data->m_retries = m_retries; _data->m_callbacks = m_callbacks; _data->m_badroutes = m_badroutes; _data->m_noack = m_noack; _data->m_netbusy = m_netbusy; _data->m_notidle = m_notidle; _data->m_txverified = m_txverified; _data->m_nondelivery = m_nondelivery; _data->m_routedbusy = m_routedbusy; _data->m_broadcastReadCnt = m_broadcastReadCnt; _data->m_broadcastWriteCnt = m_broadcastWriteCnt; } //----------------------------------------------------------------------------- // // Return per node statistics //----------------------------------------------------------------------------- void Driver::GetNodeStatistics(uint8 const _nodeId, Node::NodeData* _data) { Internal::LockGuard LG(m_nodeMutex); Node* node = GetNode(_nodeId); if (node != NULL) { node->GetNodeStatistics(_data); } } //----------------------------------------------------------------------------- // // Report driver statistics to the driver's log //----------------------------------------------------------------------------- void Driver::LogDriverStatistics() { DriverData data; GetDriverStatistics(&data); int32 totalElapsed = -m_startTime.TimeRemaining(); int32 days = totalElapsed / (1000 * 60 * 60 * 24); totalElapsed -= days * 1000 * 60 * 60 * 24; int32 hours = totalElapsed / (1000 * 60 * 60); totalElapsed -= hours * 1000 * 60 * 60; int32 minutes = totalElapsed / (1000 * 60); Log::Write(LogLevel_Always, "***************************************************************************"); Log::Write(LogLevel_Always, "********************* Cumulative Network Statistics *********************"); Log::Write(LogLevel_Always, "*** General"); Log::Write(LogLevel_Always, "Driver run time: . . . %ld days, %ld hours, %ld minutes", days, hours, minutes); Log::Write(LogLevel_Always, "Frames processed: . . . . . . . . . . . . . . . . . . . . %ld", data.m_SOFCnt); Log::Write(LogLevel_Always, "Total messages successfully received: . . . . . . . . . . %ld", data.m_readCnt); Log::Write(LogLevel_Always, "Total Messages successfully sent: . . . . . . . . . . . . %ld", data.m_writeCnt); Log::Write(LogLevel_Always, "ACKs received from controller: . . . . . . . . . . . . . %ld", data.m_ACKCnt); // Consider tracking and adding: // Initialization messages // Ad-hoc command messages // Polling messages // Messages inititated by network // Others? Log::Write(LogLevel_Always, "*** Errors"); Log::Write(LogLevel_Always, "Unsolicited messages received while waiting for ACK: . . %ld", data.m_ACKWaiting); Log::Write(LogLevel_Always, "Reads aborted due to timeouts: . . . . . . . . . . . . . %ld", data.m_readAborts); Log::Write(LogLevel_Always, "Bad checksum errors: . . . . . . . . . . . . . . . . . . %ld", data.m_badChecksum); Log::Write(LogLevel_Always, "CANs received from controller: . . . . . . . . . . . . . %ld", data.m_CANCnt); Log::Write(LogLevel_Always, "NAKs received from controller: . . . . . . . . . . . . . %ld", data.m_NAKCnt); Log::Write(LogLevel_Always, "Out of frame data flow errors: . . . . . . . . . . . . . %ld", data.m_OOFCnt); Log::Write(LogLevel_Always, "Messages retransmitted: . . . . . . . . . . . . . . . . . %ld", data.m_retries); Log::Write(LogLevel_Always, "Messages dropped and not delivered: . . . . . . . . . . . %ld", data.m_dropped); Log::Write(LogLevel_Always, "***************************************************************************"); } //----------------------------------------------------------------------------- // // Get the Network Key we will use for Security Command Class //----------------------------------------------------------------------------- uint8 *Driver::GetNetworkKey() { std::string networkKey; std::vector elems; unsigned int tempkey[16]; static uint8 keybytes[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static bool keySet = false; if (keySet == false) { Options::Get()->GetOptionAsString("NetworkKey", &networkKey); Internal::split(elems, networkKey, ",", true); if (elems.size() != 16) { Log::Write(LogLevel_Warning, "Invalid Network Key. Does not contain 16 Bytes - Contains %d", elems.size()); Log::Write(LogLevel_Warning, "Raw Key: %s", networkKey.c_str()); Log::Write(LogLevel_Warning, "Parsed Key:"); int i = 0; for (std::vector::iterator it = elems.begin(); it != elems.end(); it++) Log::Write(LogLevel_Warning, "%d) - %s", ++i, (*it).c_str()); OZW_FATAL_ERROR(OZWException::OZWEXCEPTION_SECURITY_FAILED, "Failed to Read Network Key"); } int i = 0; for (std::vector::iterator it = elems.begin(); it != elems.end(); it++) { if (0 == sscanf(Internal::trim(*it).c_str(), "%x", &tempkey[i])) { Log::Write(LogLevel_Warning, "Cannot Convert Network Key Byte %s to Key", (*it).c_str()); OZW_FATAL_ERROR(OZWException::OZWEXCEPTION_SECURITY_FAILED, "Failed to Convert Network Key"); } else { keybytes[i] = (tempkey[i] & 0xFF); } i++; } keySet = true; } return keybytes; } //----------------------------------------------------------------------------- // // Send either a NONCE request, or the actual encrypted message, depending what state the Message Currently is in. //----------------------------------------------------------------------------- bool Driver::SendEncryptedMessage() { uint8 *buffer = m_currentMsg->GetBuffer(); uint8 length = m_currentMsg->GetLength(); m_expectedCallbackId = m_currentMsg->GetCallbackId(); Log::Write(LogLevel_Info, m_currentMsg->GetTargetNodeId(), "Sending (%s) message (Callback ID=0x%.2x, Expected Reply=0x%.2x) - %s", c_sendQueueNames[m_currentMsgQueueSource], m_expectedCallbackId, m_expectedReply, m_currentMsg->GetAsString().c_str()); m_controller->Write(buffer, length); m_currentMsg->clearNonce(); return true; } bool Driver::SendNonceRequest(string logmsg) { uint8 m_buffer[11]; /* construct a standard NONCE_GET message */ m_buffer[0] = SOF; m_buffer[1] = 9; // Length of the entire message m_buffer[2] = REQUEST; m_buffer[3] = FUNC_ID_ZW_SEND_DATA; m_buffer[4] = m_currentMsg->GetTargetNodeId(); m_buffer[5] = 2; // Length of the payload m_buffer[6] = Internal::CC::Security::StaticGetCommandClassId(); m_buffer[7] = Internal::CC::SecurityCmd_NonceGet; //m_buffer[8] = TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE; m_buffer[8] = TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE; /* this is the same as the Actual Message */ //m_buffer[9] = m_expectedCallbackId; m_buffer[9] = 2; // Calculate the checksum m_buffer[10] = 0xff; for (uint32 i = 1; i < 10; ++i) { m_buffer[10] ^= m_buffer[i]; } Log::Write(LogLevel_Info, m_currentMsg->GetTargetNodeId(), "Sending (%s) message (Callback ID=0x%.2x, Expected Reply=0x%.2x) - Nonce_Get(%s) - %s:", c_sendQueueNames[m_currentMsgQueueSource], 2, m_expectedReply, logmsg.c_str(), Internal::PktToString(m_buffer, 10).c_str()); m_controller->Write(m_buffer, 11); return true; } bool Driver::initNetworkKeys(bool newnode) { uint8_t EncryptPassword[16] = { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA }; uint8_t AuthPassword[16] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }; uint8_t SecuritySchemes[1][16] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; this->m_inclusionkeySet = newnode; this->AuthKey = new aes_encrypt_ctx; this->EncryptKey = new aes_encrypt_ctx; Log::Write(LogLevel_Info, GetControllerNodeId(), "Setting Up %s Network Key for Secure Communications", newnode == true ? "Inclusion" : "Provided"); if (!isNetworkKeySet()) { Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed - Network Key Not Set"); return false; } if (aes_init() == EXIT_FAILURE) { Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed to Init AES Engine"); return false; } if (aes_encrypt_key128(newnode == false ? this->GetNetworkKey() : SecuritySchemes[0], this->EncryptKey) == EXIT_FAILURE) { Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed to Set Initial Network Key for Encryption"); return false; } if (aes_encrypt_key128(newnode == false ? this->GetNetworkKey() : SecuritySchemes[0], this->AuthKey) == EXIT_FAILURE) { Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed to Set Initial Network Key for Authentication"); return false; } uint8 tmpEncKey[32]; uint8 tmpAuthKey[32]; aes_mode_reset(this->EncryptKey); aes_mode_reset(this->AuthKey); if (aes_ecb_encrypt(EncryptPassword, tmpEncKey, 16, this->EncryptKey) == EXIT_FAILURE) { Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed to Generate Encrypted Network Key for Encryption"); return false; } if (aes_ecb_encrypt(AuthPassword, tmpAuthKey, 16, this->AuthKey) == EXIT_FAILURE) { Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed to Generate Encrypted Network Key for Authentication"); return false; } aes_mode_reset(this->EncryptKey); aes_mode_reset(this->AuthKey); if (aes_encrypt_key128(tmpEncKey, this->EncryptKey) == EXIT_FAILURE) { Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed to set Encrypted Network Key for Encryption"); return false; } if (aes_encrypt_key128(tmpAuthKey, this->AuthKey) == EXIT_FAILURE) { Log::Write(LogLevel_Warning, GetControllerNodeId(), "Failed to set Encrypted Network Key for Authentication"); return false; } aes_mode_reset(this->EncryptKey); aes_mode_reset(this->AuthKey); return true; } void Driver::SendNonceKey(uint8 nodeId, uint8 *nonce) { uint8 m_buffer[19]; /* construct a standard NONCE_GET message */ m_buffer[0] = SOF; m_buffer[1] = 17; // Length of the entire message m_buffer[2] = REQUEST; m_buffer[3] = FUNC_ID_ZW_SEND_DATA; m_buffer[4] = nodeId; m_buffer[5] = 10; // Length of the payload m_buffer[6] = Internal::CC::Security::StaticGetCommandClassId(); m_buffer[7] = Internal::CC::SecurityCmd_NonceReport; for (int i = 0; i < 8; ++i) { m_buffer[8 + i] = nonce[i]; } m_buffer[16] = TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_AUTO_ROUTE; /* this is the same as the Actual Message */ m_buffer[17] = 1; // Calculate the checksum m_buffer[18] = 0xff; for (uint32 i = 1; i < 18; ++i) { m_buffer[18] ^= m_buffer[i]; } Log::Write(LogLevel_Info, nodeId, "Sending (%s) message (Callback ID=0x%.2x, Expected Reply=0x%.2x) - Nonce_Report - %s:", c_sendQueueNames[m_currentMsgQueueSource], m_buffer[17], m_expectedReply, Internal::PktToString(m_buffer, 19).c_str()); m_controller->Write(m_buffer, 19); m_nonceReportSent = nodeId; } aes_encrypt_ctx *Driver::GetAuthKey() { if (m_currentControllerCommand != NULL && m_currentControllerCommand->m_controllerCommand == ControllerCommand_AddDevice && m_currentControllerCommand->m_controllerState == ControllerState_Completed) { /* we are adding a Node, so our AuthKey is different from normal comms */ initNetworkKeys(true); } else if (m_inclusionkeySet) { initNetworkKeys(false); } return this->AuthKey; } ; aes_encrypt_ctx *Driver::GetEncKey() { if (m_currentControllerCommand != NULL && m_currentControllerCommand->m_controllerCommand == ControllerCommand_AddDevice && m_currentControllerCommand->m_controllerState == ControllerState_Completed) { /* we are adding a Node, so our EncryptKey is different from normal comms */ initNetworkKeys(true); } else if (m_inclusionkeySet) { initNetworkKeys(false); } return this->EncryptKey; } ; bool Driver::isNetworkKeySet() { std::string networkKey; if (!Options::Get()->GetOptionAsString("NetworkKey", &networkKey)) { return false; } else { return networkKey.length() <= 0 ? false : true; } } bool Driver::CheckNodeConfigRevision(Node *node) { Internal::DNSLookup *lu = new Internal::DNSLookup; lu->NodeID = node->GetNodeId(); /* make up a string of what we want to look up */ std::stringstream ss; ss << std::hex << std::setw(4) << std::setfill('0') << node->GetProductId() << "."; ss << std::hex << std::setw(4) << std::setfill('0') << node->GetProductType() << "."; ss << std::hex << std::setw(4) << std::setfill('0') << node->GetManufacturerId() << ".db.openzwave.com"; lu->lookup = ss.str(); lu->type = Internal::DNS_Lookup_ConfigRevision; return m_dns->sendRequest(lu); } bool Driver::CheckMFSConfigRevision() { Internal::DNSLookup *lu = new Internal::DNSLookup; lu->NodeID = 0; lu->lookup = "mfs.db.openzwave.com"; lu->type = Internal::DNS_Lookup_ConfigRevision; return m_dns->sendRequest(lu); } void Driver::processConfigRevision(Internal::DNSLookup *result) { if (result->status == Internal::Platform::DNSError_None) { if (result->type == Internal::DNS_Lookup_ConfigRevision) { if (result->NodeID > 0) { Internal::LockGuard LG(m_nodeMutex); Node *node = this->GetNode(result->NodeID); if (!node) { Log::Write(LogLevel_Warning, result->NodeID, "Node disappeared when processing Config Revision"); return; } node->setLatestConfigRevision((unsigned long) atol(result->result.c_str())); if (node->getFileConfigRevision() < node->getLatestConfigRevision()) { Log::Write(LogLevel_Warning, node->GetNodeId(), "Config File for Device \"%s\" is out of date", node->GetProductName().c_str()); Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetHomeAndNodeIds(m_homeId, node->GetNodeId()); notification->SetUserAlertNotification(Notification::Alert_ConfigOutOfDate); QueueNotification(notification); bool update = false; Options::Get()->GetOptionAsBool("AutoUpdateConfigFile", &update); if (update) m_mfs->updateConfigFile(this, node); } } else if (result->NodeID == 0) { /* manufacturer_specific */ m_mfs->setLatestRevision((unsigned long) atol(result->result.c_str())); if (m_mfs->getRevision() < (unsigned long) atol(result->result.c_str())) { Log::Write(LogLevel_Warning, "Config Revision of ManufacturerSpecific Database is out of date"); Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetUserAlertNotification(Notification::Alert_MFSOutOfDate); QueueNotification(notification); bool update = false; Options::Get()->GetOptionAsBool("AutoUpdateConfigFile", &update); if (update) { m_mfs->updateMFSConfigFile(this); } else { m_mfs->checkInitialized(); } } else { /* its upto date - Check to make sure we have all the config files */ m_mfs->checkConfigFiles(this); } } return; } } else if (result->status == Internal::Platform::DNSError_NotFound) { Log::Write(LogLevel_Info, "Not Found for Device record %s", result->lookup.c_str()); Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetUserAlertNotification(Notification::Alert_DNSError); QueueNotification(notification); } else if (result->status == Internal::Platform::DNSError_DomainError) { Log::Write(LogLevel_Warning, "Domain Error Looking up record %s", result->lookup.c_str()); Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetUserAlertNotification(Notification::Alert_DNSError); QueueNotification(notification); } else if (result->status == Internal::Platform::DNSError_InternalError) { Log::Write(LogLevel_Warning, "Internal DNS Error looking up record %s", result->lookup.c_str()); Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetUserAlertNotification(Notification::Alert_DNSError); QueueNotification(notification); } m_mfs->checkInitialized(); } bool Driver::setHttpClient(Internal::i_HttpClient *client) { if (m_httpClient) delete m_httpClient; m_httpClient = client; return true; } bool Driver::startConfigDownload(uint16 _manufacturerId, uint16 _productType, uint16 _productId, string configfile, uint8 node) { Internal::HttpDownload *download = new Internal::HttpDownload(); std::stringstream ss; ss << std::hex << std::setw(4) << std::setfill('0') << _productId << "."; ss << std::hex << std::setw(4) << std::setfill('0') << _productType << "."; ss << std::hex << std::setw(4) << std::setfill('0') << _manufacturerId << ".xml"; download->url = "http://download.db.openzwave.com/" + ss.str(); download->filename = configfile; download->operation = Internal::HttpDownload::Config; download->node = node; Log::Write(LogLevel_Info, "Queuing download for %s (Node %d)", download->url.c_str(), download->node); return m_httpClient->StartDownload(download); } bool Driver::startMFSDownload(string configfile) { Internal::HttpDownload *download = new Internal::HttpDownload(); download->url = "http://download.db.openzwave.com/mfs.xml"; download->filename = configfile; download->operation = Internal::HttpDownload::MFSConfig; download->node = 0; Log::Write(LogLevel_Info, "Queuing download for %s", download->url.c_str()); return m_httpClient->StartDownload(download); } bool Driver::startDownload(string target, string file) { Internal::HttpDownload *download = new Internal::HttpDownload(); download->url = "http://download.db.openzwave.com/" + file; download->filename = target; download->operation = Internal::HttpDownload::Image; Log::Write(LogLevel_Info, "Queuing download for %s (Node %d)", download->url.c_str(), download->node); return m_httpClient->StartDownload(download); } bool Driver::refreshNodeConfig(uint8 _nodeId) { Internal::LockGuard LG(m_nodeMutex); string action; Options::Get()->GetOptionAsString("ReloadAfterUpdate", &action); if (Internal::ToUpper(action) == "NEVER") { Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetUserAlertNotification(Notification::Alert_NodeReloadRequired); QueueNotification(notification); return true; } else if (Internal::ToUpper(action) == "IMMEDIATE") { Log::Write(LogLevel_Info, _nodeId, "Reloading Node after new Config File loaded"); /* this will reload the Node, ignoring any cache that exists etc */ ReloadNode(_nodeId); return true; } else if (Internal::ToUpper(action) == "AWAKE") { Node *node = GetNode(_nodeId); if (!node->IsListeningDevice()) { if (Internal::CC::WakeUp* wakeUp = static_cast(node->GetCommandClass(Internal::CC::WakeUp::StaticGetCommandClassId()))) { if (!wakeUp->IsAwake()) { /* Node is Asleep. Queue it for WakeUp */ Log::Write(LogLevel_Info, _nodeId, "Queuing Sleeping Node Reload after New Config File Loaded"); MsgQueueItem item; item.m_command = MsgQueueCmd_ReloadNode; item.m_nodeId = _nodeId; wakeUp->QueueMsg(item); } else { /* Node is Awake. Reload it */ Log::Write(LogLevel_Info, _nodeId, "Reloading Awake Node after new Config File loaded"); ReloadNode(_nodeId); return true; } } } else { Log::Write(LogLevel_Info, _nodeId, "Reloading Node after new Config File Loaded"); ReloadNode(_nodeId); } } return false; } //----------------------------------------------------------------------------- // // Reload a Node - Remove it from ozwcache, and re-initilize the node from scratch (doing a full interview) //----------------------------------------------------------------------------- void Driver::ReloadNode(uint8 const _nodeId) { Internal::LockGuard LG(m_nodeMutex); Log::Write(LogLevel_Detail, _nodeId, "Reloading Node"); /* delete any cached information about this node so we start from fresh */ char str[32]; int32 intVal; string userPath; Options::Get()->GetOptionAsString("UserPath", &userPath); snprintf(str, sizeof(str), "ozwcache_0x%08x.xml", m_homeId); string filename = userPath + string(str); TiXmlDocument doc; doc.SetCondenseWhiteSpace(false); if (doc.LoadFile(filename.c_str(), TIXML_ENCODING_UTF8)) { doc.SetUserData((void *) filename.c_str()); TiXmlElement * driverElement = doc.RootElement(); TiXmlNode * nodeElement = driverElement->FirstChild(); while (nodeElement) { if (nodeElement->ToElement()) { char const* str2 = nodeElement->ToElement()->Value(); if (str2 && !strcmp(str2, "Node")) { // Get the node Id from the XML if (TIXML_SUCCESS == nodeElement->ToElement()->QueryIntAttribute("id", &intVal)) { if (intVal == _nodeId) { driverElement->RemoveChild(nodeElement); break; } } } } nodeElement = nodeElement->NextSibling(); } } doc.SaveFile(filename.c_str()); LG.Unlock(); InitNode(_nodeId); } void Driver::processDownload(Internal::HttpDownload *download) { if (download->transferStatus == Internal::HttpDownload::Ok) { Log::Write(LogLevel_Info, "Download Finished: %s (Node: %d)", download->filename.c_str(), download->node); if (download->operation == Internal::HttpDownload::Config) { m_mfs->configDownloaded(this, download->filename, download->node); } else if (download->operation == Internal::HttpDownload::MFSConfig) { m_mfs->mfsConfigDownloaded(this, download->filename); } else if (download->operation == Internal::HttpDownload::Image) { m_mfs->fileDownloaded(this, download->filename); } } else { Log::Write(LogLevel_Warning, "Download of %s Failed (Node: %d)", download->url.c_str(), download->node); if (download->operation == Internal::HttpDownload::Config) { m_mfs->configDownloaded(this, download->filename, download->node, false); } else if (download->operation == Internal::HttpDownload::MFSConfig) { m_mfs->mfsConfigDownloaded(this, download->filename, false); } else if (download->operation == Internal::HttpDownload::Image) { m_mfs->fileDownloaded(this, download->filename, false); } Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetUserAlertNotification(Notification::Alert_ConfigFileDownloadFailed); QueueNotification(notification); } } bool Driver::downloadConfigRevision(Node *node) { /* only download if the revision is 1 or higher. Revision 0's are for local testing only */ if (node->getFileConfigRevision() <= 0) { Log::Write(LogLevel_Warning, node->GetNodeId(), "Config File Revision is 0. Not Updating"); Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetUserAlertNotification(Notification::Alert_ConfigFileDownloadFailed); QueueNotification(notification); return false; } if (node->getFileConfigRevision() >= node->getLatestConfigRevision()) { Log::Write(LogLevel_Warning, node->GetNodeId(), "Config File Revision %d is equal to or greater than current revision %d", node->getFileConfigRevision(), node->getLatestConfigRevision()); Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetUserAlertNotification(Notification::Alert_ConfigFileDownloadFailed); QueueNotification(notification); return false; } else { m_mfs->updateConfigFile(this, node); return true; } } bool Driver::downloadMFSRevision() { if (m_mfs->getRevision() <= 0) { Log::Write(LogLevel_Warning, "ManufacturerSpecific Revision is 0. Not Updating"); Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetUserAlertNotification(Notification::Alert_ConfigFileDownloadFailed); QueueNotification(notification); return false; } if (m_mfs->getRevision() >= m_mfs->getLatestRevision()) { Log::Write(LogLevel_Warning, "ManufacturerSpecific Revision %d is equal to or greater than current revision %d", m_mfs->getRevision(), m_mfs->getLatestRevision()); Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetUserAlertNotification(Notification::Alert_ConfigFileDownloadFailed); QueueNotification(notification); return false; } m_mfs->updateMFSConfigFile(this); return true; } void Driver::SubmitEventMsg(EventMsg *event) { Internal::LockGuard LG(m_eventMutex); m_eventQueueMsg.push_back(event); m_queueMsgEvent->Set(); } void Driver::ProcessEventMsg() { EventMsg *event; { Internal::LockGuard LG(m_eventMutex); event = m_eventQueueMsg.front(); m_eventQueueMsg.pop_front(); if (m_eventQueueMsg.empty()) m_queueMsgEvent->Reset(); } switch (event->type) { case EventMsg::Event_DNS: processConfigRevision(event->event.lookup); delete event->event.lookup; break; case EventMsg::Event_Http: processDownload(event->event.httpdownload); delete event->event.httpdownload; break; } delete event; } //----------------------------------------------------------------------------- // // Retrieve MetaData about a Node. //----------------------------------------------------------------------------- string const Driver::GetMetaData(uint8 const _nodeId, Node::MetaDataFields _metadata) { Internal::LockGuard LG(m_nodeMutex); Node* node = GetNode(_nodeId); if (node != NULL) { return node->GetMetaData(_metadata); } return ""; } //----------------------------------------------------------------------------- // // Retrieve MetaData about a Node. //----------------------------------------------------------------------------- Node::ChangeLogEntry const Driver::GetChangeLog(uint8 const _nodeId, uint32_t revision) { Internal::LockGuard LG(m_nodeMutex); Node* node = GetNode(_nodeId); if (node != NULL) { return node->GetChangeLog(revision); } Node::ChangeLogEntry cle; cle.revision = -1; return cle; } Internal::ManufacturerSpecificDB *Driver::GetManufacturerSpecificDB() { return this->m_mfs; } openzwave-1.6.1914/cpp/src/NotificationCCTypes.h0000755000175200017520000000642214032142455016332 00000000000000//----------------------------------------------------------------------------- // // NotificationCCTypes.h // // NotificationCCTypes for Notification Command Class // // Copyright (c) 2018 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef NOTIFICATIONCCTYPES_H #define NOTIFICATIONCCTYPES_H #include #include #include #include "Defs.h" #include "Driver.h" #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { class NotificationCCTypes { public: enum NotificationEventParamTypes { NEPT_Location = 0x01, NEPT_List, NEPT_UserCodeReport, NEPT_Byte, NEPT_String, NEPT_Time }; class NotificationEventParams { public: uint32 id; string name; NotificationEventParamTypes type; std::map ListItems; }; class NotificationEvents { public: uint32 id; string name; std::map > EventParams; }; class NotificationTypes { public: uint32 id; string name; std::map > Events; }; //----------------------------------------------------------------------------- // Construction //----------------------------------------------------------------------------- private: NotificationCCTypes(); ~NotificationCCTypes(); static bool ReadXML(); public: static NotificationCCTypes* Get(); static bool Create(); static string GetEventParamNames(NotificationEventParamTypes); string GetAlarmType(uint32); string GetEventForAlarmType(uint32, uint32); const std::shared_ptr GetAlarmNotificationTypes(uint32); const std::shared_ptr GetAlarmNotificationEvents(uint32, uint32); const std::map> GetAlarmNotificationEventParams(uint32, uint32); //----------------------------------------------------------------------------- // Instance Functions //----------------------------------------------------------------------------- private: static NotificationCCTypes* m_instance; static std::map > Notifications; static uint32 m_revision; }; } // namespace Internal } // namespace OpenZWave #endif // NOTIFICATIONCCTYPES_H openzwave-1.6.1914/cpp/src/TimerThread.h0000644000175200017520000001263114032142455014655 00000000000000//----------------------------------------------------------------------------- // // TimerThread.h // // Timer for scheduling future events // // Copyright (c) 2017 h3ctrl // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _TIMERTHREAD_H_ #define _TIMERTHREAD_H_ #if __cplusplus >= 201103L || __APPLE__ || _MSC_VER #include using std::bind; using std::function; #else #include using std::tr1::bind; using std::tr1::function; #endif #include "Defs.h" #include "platform/Event.h" #include "platform/Mutex.h" #include "platform/TimeStamp.h" namespace OpenZWave { class Driver; namespace Internal { class Timer; /** \brief The TimerThread class makes it possible to schedule events to happen * at a certain time in the future. */ class OPENZWAVE_EXPORT TimerThread { friend class Timer; //----------------------------------------------------------------------------- // Timer based actions //----------------------------------------------------------------------------- public: /** A timer callback function. */ typedef function TimerCallback; /** * Constructor. */ TimerThread(Driver *_driver); /** * Destructor. */ ~TimerThread(); struct TimerEventEntry { Timer *instance; Internal::Platform::TimeStamp timestamp; TimerCallback callback; uint32 id; }; /** * Main entry point for the timer thread. Wrapper around TimerThreadProc. * \param _exitEvent Exit event indicating the thread should exit * \param _context A TimerThread object */ static void TimerThreadEntryPoint(Internal::Platform::Event* _exitEvent, void* _context); private: //Driver* m_driver; /** * Schedule an event. * \param _milliseconds The number of milliseconds before the event should happen * \param _callback The function to be called when the time is reached * \param _instance The Timer SubClass where this Event should be executed from */ TimerEventEntry* TimerSetEvent(int32 _milliseconds, TimerCallback _callback, Timer *_instance, uint32 id); /** * Remove a Event * */ void TimerDelEvent(TimerEventEntry *); /** * Main class entry point for the timer thread. Contains the main timer loop. * \param _exitEvent Exit event indicating the thread should exit */ void TimerThreadProc(Internal::Platform::Event* _exitEvent); /** A list of upcoming timer events */ list m_timerEventList; Internal::Platform::Event* m_timerEvent; // Event to signal new timed action requested Internal::Platform::Mutex* m_timerMutex; // Serialize access to class members int32 m_timerTimeout; // Time in milliseconds to wait until next event }; /** * \brief Timer SubClass for automatically registering/unregistering Timer Callbacks * if the instance goes out of scope * */ class OPENZWAVE_EXPORT Timer { public: /** * \brief Constructor with the _driver this instance is associated with * \param _driver The Driver that this instance is associated with */ Timer(Driver *_driver); /** * \brief Default Constructor */ Timer(); /** * \brief Destructor */ ~Timer(); /** * \brief Schedule an event. * \param _milliseconds The number of milliseconds before the event should happen * \param _callback The function to be called when the time is reached * \param _id The ID of the Timer */ TimerThread::TimerEventEntry* TimerSetEvent(int32 _milliseconds, TimerThread::TimerCallback _callback, uint32 id); /** * \brief Delete All Events registered to this instance */ void TimerDelEvents(); /** * \brief Delete a Specific Event Registered to this instance * \param te The TimerEventEntry Struct that was returned when Setting a Event */ void TimerDelEvent(TimerThread::TimerEventEntry *te); /** * \brief Delete a Specific Event Registered to this instance * \param id The ID of the Timer To Delete */ void TimerDelEvent(uint32 id); /** * \brief Register the Driver Associated with this Instance * \param _driver The Driver */ void SetDriver(Driver *_driver); /** * \brief Called From the TimerThread Class to execute a callback * \param te The TimerEventEntry structure for the callback to execute */ void TimerFireEvent(TimerThread::TimerEventEntry *te); private: Driver* m_driver; list m_timerEventList; }; } // namespace Internal } // namespace OpenZWave #endif // _TIMERTHREAD_H_ openzwave-1.6.1914/cpp/src/ManufacturerSpecificDB.h0000644000175200017520000001130414032142455016751 00000000000000//----------------------------------------------------------------------------- // // ManufacturerSpecificDB.h // // Interface for Handling Device Configuration Files. // // Copyright (c) 2016 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ManufacturerSpecificDB_H #define _ManufacturerSpecificDB_H #include #include #include #include "Node.h" #include "platform/Ref.h" #include "Defs.h" namespace OpenZWave { class Driver; namespace Internal { namespace Platform { class Mutex; } class ProductDescriptor { public: ProductDescriptor(uint16 _manufacturerId, uint16 _productType, uint16 _productId, string const& _productName, string const& _manufacturerName, string const& _configPath) : m_manufacturerId(_manufacturerId), m_productType(_productType), m_productId(_productId), m_productName(_productName), m_manufacturerName(_manufacturerName), m_configPath(_configPath), m_configrevision(0) { } ~ProductDescriptor() { } int64 GetKey() const { return (GetKey(m_manufacturerId, m_productType, m_productId)); } static int64 GetKey(uint16 _manufacturerId, uint16 _productType, uint16 _productId) { int64 key = (((int64) _manufacturerId) << 32) | (((int64) _productType) << 16) | (int64) _productId; return key; } uint16 GetManufacturerId() const { return m_manufacturerId; } string GetManufacturerName() const { return m_manufacturerName; } uint16 GetProductType() const { return m_productType; } uint16 GetProductId() const { return m_productId; } string GetProductName() const { return m_productName; } string GetConfigPath() const { return m_configPath; } void SetConfigRevision(uint32 revision) { m_configrevision = revision; } uint32 GetConfigRevision() const { return m_configrevision; } private: uint16 m_manufacturerId; uint16 m_productType; uint16 m_productId; string m_productName; string m_manufacturerName; string m_configPath; uint32 m_configrevision; }; /** \brief The _ManufacturerSpecificDB class handles the Config File Database * that we use to configure devices. */ class OPENZWAVE_EXPORT ManufacturerSpecificDB { public: static ManufacturerSpecificDB *Create(); static ManufacturerSpecificDB *Get() { return s_instance; } static void Destroy(); bool LoadProductXML(); void UnloadProductXML(); uint32 getRevision() { return m_revision; } uint32 getLatestRevision() { return m_latestRevision; } ; void setLatestRevision(uint32 rev) { m_latestRevision = rev; } ; void checkConfigFiles(Driver *); void configDownloaded(Driver *, string file, uint8 node, bool success = true); void mfsConfigDownloaded(Driver *, string file, bool success = true); void fileDownloaded(Driver *, string file, bool success = true); bool isReady(); bool updateConfigFile(Driver *, Node *); bool updateMFSConfigFile(Driver *); void checkInitialized(); private: void LoadConfigFileRevision(ProductDescriptor *product); ManufacturerSpecificDB(); ~ManufacturerSpecificDB(); void checkConfigFileContents(Driver *driver, string file); Internal::Platform::Mutex* m_MfsMutex; /**< Mutex to ensure its accessed by a single thread at a time */ static ManufacturerSpecificDB *s_instance; public: std::shared_ptr getProduct(uint16 _manufacturerId, uint16 _productType, uint16 _productId); private: static map s_manufacturerMap; static map > s_productMap; static bool s_bXmlLoaded; list m_downloading; uint32 m_revision; uint32 m_latestRevision; bool m_initializing; }; } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/ValueIDIndexesDefines.def0000644000175200017520000032171214032142455017066 00000000000000//----------------------------------------------------------------------------- // // ValueIDIndexes.h // // List of all Possible ValueID Indexes in OZW // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- /* This file is run through the preprocessor and output to ValueIDIndexesDefines.h to avoid problems * with MSVC not supporting enough arguments with Macro's. * If you are adding a ValueID, you should add its index ENUM to ValuIDIndexDefines.def and the run * 'make updateIndexDefines' to regenerate the the ValueIDIndexDefines.h file * Obviously the regeneration will not work on MSVC, so you need clang or gnugcc to do the preprocessing * how to do that is left to the reader to figure out on Windows. On Unix and Mac, as long as the compiler * supports more than 512 Macro arguements, all should be good. * * This also has the nice side benefit in that we only have to do the pre-processing once, and the output is * included into all the files that include ValueIDIndexes.h without having to process it again */ #ifndef _ValueIDIndexesDefines_H #define _ValueIDIndexesDefines_H /* this is good for upto 768 entries per ENUM. I shall predict that 768 entries shall be enough for any CommandClass :) */ #define MAP(macro, ...) \ IDENTITY( \ APPLY(CHOOSE_MAP_START, COUNT(__VA_ARGS__)) \ (macro, __VA_ARGS__)) #define CHOOSE_MAP_START(count) MAP ## count #define APPLY(macro, ...) IDENTITY(macro(__VA_ARGS__)) // Needed to expand __VA_ARGS__ "eagerly" on the MSVC preprocessor. #define IDENTITY(x) x #define MAP1(m, x) m(x) #define MAP2(m, x, ...) m(x) IDENTITY(MAP1(m, __VA_ARGS__)) #define MAP3(m, x, ...) m(x) IDENTITY(MAP2(m, __VA_ARGS__)) #define MAP4(m, x, ...) m(x) IDENTITY(MAP3(m, __VA_ARGS__)) #define MAP5(m, x, ...) m(x) IDENTITY(MAP4(m, __VA_ARGS__)) #define MAP6(m, x, ...) m(x) IDENTITY(MAP5(m, __VA_ARGS__)) #define MAP7(m, x, ...) m(x) IDENTITY(MAP6(m, __VA_ARGS__)) #define MAP8(m, x, ...) m(x) IDENTITY(MAP7(m, __VA_ARGS__)) #define MAP9(m, x, ...) m(x) IDENTITY(MAP8(m, __VA_ARGS__)) #define MAP10(m, x, ...) m(x) IDENTITY(MAP9(m, __VA_ARGS__)) #define MAP11(m, x, ...) m(x) IDENTITY(MAP10(m, __VA_ARGS__)) #define MAP12(m, x, ...) m(x) IDENTITY(MAP11(m, __VA_ARGS__)) #define MAP13(m, x, ...) m(x) IDENTITY(MAP12(m, __VA_ARGS__)) #define MAP14(m, x, ...) m(x) IDENTITY(MAP13(m, __VA_ARGS__)) #define MAP15(m, x, ...) m(x) IDENTITY(MAP14(m, __VA_ARGS__)) #define MAP16(m, x, ...) m(x) IDENTITY(MAP15(m, __VA_ARGS__)) #define MAP17(m, x, ...) m(x) IDENTITY(MAP16(m, __VA_ARGS__)) #define MAP18(m, x, ...) m(x) IDENTITY(MAP17(m, __VA_ARGS__)) #define MAP19(m, x, ...) m(x) IDENTITY(MAP18(m, __VA_ARGS__)) #define MAP20(m, x, ...) m(x) IDENTITY(MAP19(m, __VA_ARGS__)) #define MAP21(m, x, ...) m(x) IDENTITY(MAP20(m, __VA_ARGS__)) #define MAP22(m, x, ...) m(x) IDENTITY(MAP21(m, __VA_ARGS__)) #define MAP23(m, x, ...) m(x) IDENTITY(MAP22(m, __VA_ARGS__)) #define MAP24(m, x, ...) m(x) IDENTITY(MAP23(m, __VA_ARGS__)) #define MAP25(m, x, ...) m(x) IDENTITY(MAP24(m, __VA_ARGS__)) #define MAP26(m, x, ...) m(x) IDENTITY(MAP25(m, __VA_ARGS__)) #define MAP27(m, x, ...) m(x) IDENTITY(MAP26(m, __VA_ARGS__)) #define MAP28(m, x, ...) m(x) IDENTITY(MAP27(m, __VA_ARGS__)) #define MAP29(m, x, ...) m(x) IDENTITY(MAP28(m, __VA_ARGS__)) #define MAP30(m, x, ...) m(x) IDENTITY(MAP29(m, __VA_ARGS__)) #define MAP31(m, x, ...) m(x) IDENTITY(MAP30(m, __VA_ARGS__)) #define MAP32(m, x, ...) m(x) IDENTITY(MAP31(m, __VA_ARGS__)) #define MAP33(m, x, ...) m(x) IDENTITY(MAP32(m, __VA_ARGS__)) #define MAP34(m, x, ...) m(x) IDENTITY(MAP33(m, __VA_ARGS__)) #define MAP35(m, x, ...) m(x) IDENTITY(MAP34(m, __VA_ARGS__)) #define MAP36(m, x, ...) m(x) IDENTITY(MAP35(m, __VA_ARGS__)) #define MAP37(m, x, ...) m(x) IDENTITY(MAP36(m, __VA_ARGS__)) #define MAP38(m, x, ...) m(x) IDENTITY(MAP37(m, __VA_ARGS__)) #define MAP39(m, x, ...) m(x) IDENTITY(MAP38(m, __VA_ARGS__)) #define MAP40(m, x, ...) m(x) IDENTITY(MAP39(m, __VA_ARGS__)) #define MAP41(m, x, ...) m(x) IDENTITY(MAP40(m, __VA_ARGS__)) #define MAP42(m, x, ...) m(x) IDENTITY(MAP41(m, __VA_ARGS__)) #define MAP43(m, x, ...) m(x) IDENTITY(MAP42(m, __VA_ARGS__)) #define MAP44(m, x, ...) m(x) IDENTITY(MAP43(m, __VA_ARGS__)) #define MAP45(m, x, ...) m(x) IDENTITY(MAP44(m, __VA_ARGS__)) #define MAP46(m, x, ...) m(x) IDENTITY(MAP45(m, __VA_ARGS__)) #define MAP47(m, x, ...) m(x) IDENTITY(MAP46(m, __VA_ARGS__)) #define MAP48(m, x, ...) m(x) IDENTITY(MAP47(m, __VA_ARGS__)) #define MAP49(m, x, ...) m(x) IDENTITY(MAP48(m, __VA_ARGS__)) #define MAP50(m, x, ...) m(x) IDENTITY(MAP49(m, __VA_ARGS__)) #define MAP51(m, x, ...) m(x) IDENTITY(MAP50(m, __VA_ARGS__)) #define MAP52(m, x, ...) m(x) IDENTITY(MAP51(m, __VA_ARGS__)) #define MAP53(m, x, ...) m(x) IDENTITY(MAP52(m, __VA_ARGS__)) #define MAP54(m, x, ...) m(x) IDENTITY(MAP53(m, __VA_ARGS__)) #define MAP55(m, x, ...) m(x) IDENTITY(MAP54(m, __VA_ARGS__)) #define MAP56(m, x, ...) m(x) IDENTITY(MAP55(m, __VA_ARGS__)) #define MAP57(m, x, ...) m(x) IDENTITY(MAP56(m, __VA_ARGS__)) #define MAP58(m, x, ...) m(x) IDENTITY(MAP57(m, __VA_ARGS__)) #define MAP59(m, x, ...) m(x) IDENTITY(MAP58(m, __VA_ARGS__)) #define MAP60(m, x, ...) m(x) IDENTITY(MAP59(m, __VA_ARGS__)) #define MAP61(m, x, ...) m(x) IDENTITY(MAP60(m, __VA_ARGS__)) #define MAP62(m, x, ...) m(x) IDENTITY(MAP61(m, __VA_ARGS__)) #define MAP63(m, x, ...) m(x) IDENTITY(MAP62(m, __VA_ARGS__)) #define MAP64(m, x, ...) m(x) IDENTITY(MAP63(m, __VA_ARGS__)) #define MAP65(m, x, ...) m(x) IDENTITY(MAP64(m, __VA_ARGS__)) #define MAP66(m, x, ...) m(x) IDENTITY(MAP65(m, __VA_ARGS__)) #define MAP67(m, x, ...) m(x) IDENTITY(MAP66(m, __VA_ARGS__)) #define MAP68(m, x, ...) m(x) IDENTITY(MAP67(m, __VA_ARGS__)) #define MAP69(m, x, ...) m(x) IDENTITY(MAP68(m, __VA_ARGS__)) #define MAP70(m, x, ...) m(x) IDENTITY(MAP69(m, __VA_ARGS__)) #define MAP71(m, x, ...) m(x) IDENTITY(MAP70(m, __VA_ARGS__)) #define MAP72(m, x, ...) m(x) IDENTITY(MAP71(m, __VA_ARGS__)) #define MAP73(m, x, ...) m(x) IDENTITY(MAP72(m, __VA_ARGS__)) #define MAP74(m, x, ...) m(x) IDENTITY(MAP73(m, __VA_ARGS__)) #define MAP75(m, x, ...) m(x) IDENTITY(MAP74(m, __VA_ARGS__)) #define MAP76(m, x, ...) m(x) IDENTITY(MAP75(m, __VA_ARGS__)) #define MAP77(m, x, ...) m(x) IDENTITY(MAP76(m, __VA_ARGS__)) #define MAP78(m, x, ...) m(x) IDENTITY(MAP77(m, __VA_ARGS__)) #define MAP79(m, x, ...) m(x) IDENTITY(MAP78(m, __VA_ARGS__)) #define MAP80(m, x, ...) m(x) IDENTITY(MAP79(m, __VA_ARGS__)) #define MAP81(m, x, ...) m(x) IDENTITY(MAP80(m, __VA_ARGS__)) #define MAP82(m, x, ...) m(x) IDENTITY(MAP81(m, __VA_ARGS__)) #define MAP83(m, x, ...) m(x) IDENTITY(MAP82(m, __VA_ARGS__)) #define MAP84(m, x, ...) m(x) IDENTITY(MAP83(m, __VA_ARGS__)) #define MAP85(m, x, ...) m(x) IDENTITY(MAP84(m, __VA_ARGS__)) #define MAP86(m, x, ...) m(x) IDENTITY(MAP85(m, __VA_ARGS__)) #define MAP87(m, x, ...) m(x) IDENTITY(MAP86(m, __VA_ARGS__)) #define MAP88(m, x, ...) m(x) IDENTITY(MAP87(m, __VA_ARGS__)) #define MAP89(m, x, ...) m(x) IDENTITY(MAP88(m, __VA_ARGS__)) #define MAP90(m, x, ...) m(x) IDENTITY(MAP89(m, __VA_ARGS__)) #define MAP91(m, x, ...) m(x) IDENTITY(MAP90(m, __VA_ARGS__)) #define MAP92(m, x, ...) m(x) IDENTITY(MAP91(m, __VA_ARGS__)) #define MAP93(m, x, ...) m(x) IDENTITY(MAP92(m, __VA_ARGS__)) #define MAP94(m, x, ...) m(x) IDENTITY(MAP93(m, __VA_ARGS__)) #define MAP95(m, x, ...) m(x) IDENTITY(MAP94(m, __VA_ARGS__)) #define MAP96(m, x, ...) m(x) IDENTITY(MAP95(m, __VA_ARGS__)) #define MAP97(m, x, ...) m(x) IDENTITY(MAP96(m, __VA_ARGS__)) #define MAP98(m, x, ...) m(x) IDENTITY(MAP97(m, __VA_ARGS__)) #define MAP99(m, x, ...) m(x) IDENTITY(MAP98(m, __VA_ARGS__)) #define MAP100(m, x, ...) m(x) IDENTITY(MAP99(m, __VA_ARGS__)) #define MAP101(m, x, ...) m(x) IDENTITY(MAP100(m, __VA_ARGS__)) #define MAP102(m, x, ...) m(x) IDENTITY(MAP101(m, __VA_ARGS__)) #define MAP103(m, x, ...) m(x) IDENTITY(MAP102(m, __VA_ARGS__)) #define MAP104(m, x, ...) m(x) IDENTITY(MAP103(m, __VA_ARGS__)) #define MAP105(m, x, ...) m(x) IDENTITY(MAP104(m, __VA_ARGS__)) #define MAP106(m, x, ...) m(x) IDENTITY(MAP105(m, __VA_ARGS__)) #define MAP107(m, x, ...) m(x) IDENTITY(MAP106(m, __VA_ARGS__)) #define MAP108(m, x, ...) m(x) IDENTITY(MAP107(m, __VA_ARGS__)) #define MAP109(m, x, ...) m(x) IDENTITY(MAP108(m, __VA_ARGS__)) #define MAP110(m, x, ...) m(x) IDENTITY(MAP109(m, __VA_ARGS__)) #define MAP111(m, x, ...) m(x) IDENTITY(MAP110(m, __VA_ARGS__)) #define MAP112(m, x, ...) m(x) IDENTITY(MAP111(m, __VA_ARGS__)) #define MAP113(m, x, ...) m(x) IDENTITY(MAP112(m, __VA_ARGS__)) #define MAP114(m, x, ...) m(x) IDENTITY(MAP113(m, __VA_ARGS__)) #define MAP115(m, x, ...) m(x) IDENTITY(MAP114(m, __VA_ARGS__)) #define MAP116(m, x, ...) m(x) IDENTITY(MAP115(m, __VA_ARGS__)) #define MAP117(m, x, ...) m(x) IDENTITY(MAP116(m, __VA_ARGS__)) #define MAP118(m, x, ...) m(x) IDENTITY(MAP117(m, __VA_ARGS__)) #define MAP119(m, x, ...) m(x) IDENTITY(MAP118(m, __VA_ARGS__)) #define MAP120(m, x, ...) m(x) IDENTITY(MAP119(m, __VA_ARGS__)) #define MAP121(m, x, ...) m(x) IDENTITY(MAP120(m, __VA_ARGS__)) #define MAP122(m, x, ...) m(x) IDENTITY(MAP121(m, __VA_ARGS__)) #define MAP123(m, x, ...) m(x) IDENTITY(MAP122(m, __VA_ARGS__)) #define MAP124(m, x, ...) m(x) IDENTITY(MAP123(m, __VA_ARGS__)) #define MAP125(m, x, ...) m(x) IDENTITY(MAP124(m, __VA_ARGS__)) #define MAP126(m, x, ...) m(x) IDENTITY(MAP125(m, __VA_ARGS__)) #define MAP127(m, x, ...) m(x) IDENTITY(MAP126(m, __VA_ARGS__)) #define MAP128(m, x, ...) m(x) IDENTITY(MAP127(m, __VA_ARGS__)) #define MAP129(m, x, ...) m(x) IDENTITY(MAP128(m, __VA_ARGS__)) #define MAP130(m, x, ...) m(x) IDENTITY(MAP129(m, __VA_ARGS__)) #define MAP131(m, x, ...) m(x) IDENTITY(MAP130(m, __VA_ARGS__)) #define MAP132(m, x, ...) m(x) IDENTITY(MAP131(m, __VA_ARGS__)) #define MAP133(m, x, ...) m(x) IDENTITY(MAP132(m, __VA_ARGS__)) #define MAP134(m, x, ...) m(x) IDENTITY(MAP133(m, __VA_ARGS__)) #define MAP135(m, x, ...) m(x) IDENTITY(MAP134(m, __VA_ARGS__)) #define MAP136(m, x, ...) m(x) IDENTITY(MAP135(m, __VA_ARGS__)) #define MAP137(m, x, ...) m(x) IDENTITY(MAP136(m, __VA_ARGS__)) #define MAP138(m, x, ...) m(x) IDENTITY(MAP137(m, __VA_ARGS__)) #define MAP139(m, x, ...) m(x) IDENTITY(MAP138(m, __VA_ARGS__)) #define MAP140(m, x, ...) m(x) IDENTITY(MAP139(m, __VA_ARGS__)) #define MAP141(m, x, ...) m(x) IDENTITY(MAP140(m, __VA_ARGS__)) #define MAP142(m, x, ...) m(x) IDENTITY(MAP141(m, __VA_ARGS__)) #define MAP143(m, x, ...) m(x) IDENTITY(MAP142(m, __VA_ARGS__)) #define MAP144(m, x, ...) m(x) IDENTITY(MAP143(m, __VA_ARGS__)) #define MAP145(m, x, ...) m(x) IDENTITY(MAP144(m, __VA_ARGS__)) #define MAP146(m, x, ...) m(x) IDENTITY(MAP145(m, __VA_ARGS__)) #define MAP147(m, x, ...) m(x) IDENTITY(MAP146(m, __VA_ARGS__)) #define MAP148(m, x, ...) m(x) IDENTITY(MAP147(m, __VA_ARGS__)) #define MAP149(m, x, ...) m(x) IDENTITY(MAP148(m, __VA_ARGS__)) #define MAP150(m, x, ...) m(x) IDENTITY(MAP149(m, __VA_ARGS__)) #define MAP151(m, x, ...) m(x) IDENTITY(MAP150(m, __VA_ARGS__)) #define MAP152(m, x, ...) m(x) IDENTITY(MAP151(m, __VA_ARGS__)) #define MAP153(m, x, ...) m(x) IDENTITY(MAP152(m, __VA_ARGS__)) #define MAP154(m, x, ...) m(x) IDENTITY(MAP153(m, __VA_ARGS__)) #define MAP155(m, x, ...) m(x) IDENTITY(MAP154(m, __VA_ARGS__)) #define MAP156(m, x, ...) m(x) IDENTITY(MAP155(m, __VA_ARGS__)) #define MAP157(m, x, ...) m(x) IDENTITY(MAP156(m, __VA_ARGS__)) #define MAP158(m, x, ...) m(x) IDENTITY(MAP157(m, __VA_ARGS__)) #define MAP159(m, x, ...) m(x) IDENTITY(MAP158(m, __VA_ARGS__)) #define MAP160(m, x, ...) m(x) IDENTITY(MAP159(m, __VA_ARGS__)) #define MAP161(m, x, ...) m(x) IDENTITY(MAP160(m, __VA_ARGS__)) #define MAP162(m, x, ...) m(x) IDENTITY(MAP161(m, __VA_ARGS__)) #define MAP163(m, x, ...) m(x) IDENTITY(MAP162(m, __VA_ARGS__)) #define MAP164(m, x, ...) m(x) IDENTITY(MAP163(m, __VA_ARGS__)) #define MAP165(m, x, ...) m(x) IDENTITY(MAP164(m, __VA_ARGS__)) #define MAP166(m, x, ...) m(x) IDENTITY(MAP165(m, __VA_ARGS__)) #define MAP167(m, x, ...) m(x) IDENTITY(MAP166(m, __VA_ARGS__)) #define MAP168(m, x, ...) m(x) IDENTITY(MAP167(m, __VA_ARGS__)) #define MAP169(m, x, ...) m(x) IDENTITY(MAP168(m, __VA_ARGS__)) #define MAP170(m, x, ...) m(x) IDENTITY(MAP169(m, __VA_ARGS__)) #define MAP171(m, x, ...) m(x) IDENTITY(MAP170(m, __VA_ARGS__)) #define MAP172(m, x, ...) m(x) IDENTITY(MAP171(m, __VA_ARGS__)) #define MAP173(m, x, ...) m(x) IDENTITY(MAP172(m, __VA_ARGS__)) #define MAP174(m, x, ...) m(x) IDENTITY(MAP173(m, __VA_ARGS__)) #define MAP175(m, x, ...) m(x) IDENTITY(MAP174(m, __VA_ARGS__)) #define MAP176(m, x, ...) m(x) IDENTITY(MAP175(m, __VA_ARGS__)) #define MAP177(m, x, ...) m(x) IDENTITY(MAP176(m, __VA_ARGS__)) #define MAP178(m, x, ...) m(x) IDENTITY(MAP177(m, __VA_ARGS__)) #define MAP179(m, x, ...) m(x) IDENTITY(MAP178(m, __VA_ARGS__)) #define MAP180(m, x, ...) m(x) IDENTITY(MAP179(m, __VA_ARGS__)) #define MAP181(m, x, ...) m(x) IDENTITY(MAP180(m, __VA_ARGS__)) #define MAP182(m, x, ...) m(x) IDENTITY(MAP181(m, __VA_ARGS__)) #define MAP183(m, x, ...) m(x) IDENTITY(MAP182(m, __VA_ARGS__)) #define MAP184(m, x, ...) m(x) IDENTITY(MAP183(m, __VA_ARGS__)) #define MAP185(m, x, ...) m(x) IDENTITY(MAP184(m, __VA_ARGS__)) #define MAP186(m, x, ...) m(x) IDENTITY(MAP185(m, __VA_ARGS__)) #define MAP187(m, x, ...) m(x) IDENTITY(MAP186(m, __VA_ARGS__)) #define MAP188(m, x, ...) m(x) IDENTITY(MAP187(m, __VA_ARGS__)) #define MAP189(m, x, ...) m(x) IDENTITY(MAP188(m, __VA_ARGS__)) #define MAP190(m, x, ...) m(x) IDENTITY(MAP189(m, __VA_ARGS__)) #define MAP191(m, x, ...) m(x) IDENTITY(MAP190(m, __VA_ARGS__)) #define MAP192(m, x, ...) m(x) IDENTITY(MAP191(m, __VA_ARGS__)) #define MAP193(m, x, ...) m(x) IDENTITY(MAP192(m, __VA_ARGS__)) #define MAP194(m, x, ...) m(x) IDENTITY(MAP193(m, __VA_ARGS__)) #define MAP195(m, x, ...) m(x) IDENTITY(MAP194(m, __VA_ARGS__)) #define MAP196(m, x, ...) m(x) IDENTITY(MAP195(m, __VA_ARGS__)) #define MAP197(m, x, ...) m(x) IDENTITY(MAP196(m, __VA_ARGS__)) #define MAP198(m, x, ...) m(x) IDENTITY(MAP197(m, __VA_ARGS__)) #define MAP199(m, x, ...) m(x) IDENTITY(MAP198(m, __VA_ARGS__)) #define MAP200(m, x, ...) m(x) IDENTITY(MAP199(m, __VA_ARGS__)) #define MAP201(m, x, ...) m(x) IDENTITY(MAP200(m, __VA_ARGS__)) #define MAP202(m, x, ...) m(x) IDENTITY(MAP201(m, __VA_ARGS__)) #define MAP203(m, x, ...) m(x) IDENTITY(MAP202(m, __VA_ARGS__)) #define MAP204(m, x, ...) m(x) IDENTITY(MAP203(m, __VA_ARGS__)) #define MAP205(m, x, ...) m(x) IDENTITY(MAP204(m, __VA_ARGS__)) #define MAP206(m, x, ...) m(x) IDENTITY(MAP205(m, __VA_ARGS__)) #define MAP207(m, x, ...) m(x) IDENTITY(MAP206(m, __VA_ARGS__)) #define MAP208(m, x, ...) m(x) IDENTITY(MAP207(m, __VA_ARGS__)) #define MAP209(m, x, ...) m(x) IDENTITY(MAP208(m, __VA_ARGS__)) #define MAP210(m, x, ...) m(x) IDENTITY(MAP209(m, __VA_ARGS__)) #define MAP211(m, x, ...) m(x) IDENTITY(MAP210(m, __VA_ARGS__)) #define MAP212(m, x, ...) m(x) IDENTITY(MAP211(m, __VA_ARGS__)) #define MAP213(m, x, ...) m(x) IDENTITY(MAP212(m, __VA_ARGS__)) #define MAP214(m, x, ...) m(x) IDENTITY(MAP213(m, __VA_ARGS__)) #define MAP215(m, x, ...) m(x) IDENTITY(MAP214(m, __VA_ARGS__)) #define MAP216(m, x, ...) m(x) IDENTITY(MAP215(m, __VA_ARGS__)) #define MAP217(m, x, ...) m(x) IDENTITY(MAP216(m, __VA_ARGS__)) #define MAP218(m, x, ...) m(x) IDENTITY(MAP217(m, __VA_ARGS__)) #define MAP219(m, x, ...) m(x) IDENTITY(MAP218(m, __VA_ARGS__)) #define MAP220(m, x, ...) m(x) IDENTITY(MAP219(m, __VA_ARGS__)) #define MAP221(m, x, ...) m(x) IDENTITY(MAP220(m, __VA_ARGS__)) #define MAP222(m, x, ...) m(x) IDENTITY(MAP221(m, __VA_ARGS__)) #define MAP223(m, x, ...) m(x) IDENTITY(MAP222(m, __VA_ARGS__)) #define MAP224(m, x, ...) m(x) IDENTITY(MAP223(m, __VA_ARGS__)) #define MAP225(m, x, ...) m(x) IDENTITY(MAP224(m, __VA_ARGS__)) #define MAP226(m, x, ...) m(x) IDENTITY(MAP225(m, __VA_ARGS__)) #define MAP227(m, x, ...) m(x) IDENTITY(MAP226(m, __VA_ARGS__)) #define MAP228(m, x, ...) m(x) IDENTITY(MAP227(m, __VA_ARGS__)) #define MAP229(m, x, ...) m(x) IDENTITY(MAP228(m, __VA_ARGS__)) #define MAP230(m, x, ...) m(x) IDENTITY(MAP229(m, __VA_ARGS__)) #define MAP231(m, x, ...) m(x) IDENTITY(MAP230(m, __VA_ARGS__)) #define MAP232(m, x, ...) m(x) IDENTITY(MAP231(m, __VA_ARGS__)) #define MAP233(m, x, ...) m(x) IDENTITY(MAP232(m, __VA_ARGS__)) #define MAP234(m, x, ...) m(x) IDENTITY(MAP233(m, __VA_ARGS__)) #define MAP235(m, x, ...) m(x) IDENTITY(MAP234(m, __VA_ARGS__)) #define MAP236(m, x, ...) m(x) IDENTITY(MAP235(m, __VA_ARGS__)) #define MAP237(m, x, ...) m(x) IDENTITY(MAP236(m, __VA_ARGS__)) #define MAP238(m, x, ...) m(x) IDENTITY(MAP237(m, __VA_ARGS__)) #define MAP239(m, x, ...) m(x) IDENTITY(MAP238(m, __VA_ARGS__)) #define MAP240(m, x, ...) m(x) IDENTITY(MAP239(m, __VA_ARGS__)) #define MAP241(m, x, ...) m(x) IDENTITY(MAP240(m, __VA_ARGS__)) #define MAP242(m, x, ...) m(x) IDENTITY(MAP241(m, __VA_ARGS__)) #define MAP243(m, x, ...) m(x) IDENTITY(MAP242(m, __VA_ARGS__)) #define MAP244(m, x, ...) m(x) IDENTITY(MAP243(m, __VA_ARGS__)) #define MAP245(m, x, ...) m(x) IDENTITY(MAP244(m, __VA_ARGS__)) #define MAP246(m, x, ...) m(x) IDENTITY(MAP245(m, __VA_ARGS__)) #define MAP247(m, x, ...) m(x) IDENTITY(MAP246(m, __VA_ARGS__)) #define MAP248(m, x, ...) m(x) IDENTITY(MAP247(m, __VA_ARGS__)) #define MAP249(m, x, ...) m(x) IDENTITY(MAP248(m, __VA_ARGS__)) #define MAP250(m, x, ...) m(x) IDENTITY(MAP249(m, __VA_ARGS__)) #define MAP251(m, x, ...) m(x) IDENTITY(MAP250(m, __VA_ARGS__)) #define MAP252(m, x, ...) m(x) IDENTITY(MAP251(m, __VA_ARGS__)) #define MAP253(m, x, ...) m(x) IDENTITY(MAP252(m, __VA_ARGS__)) #define MAP254(m, x, ...) m(x) IDENTITY(MAP253(m, __VA_ARGS__)) #define MAP255(m, x, ...) m(x) IDENTITY(MAP254(m, __VA_ARGS__)) #define MAP256(m, x, ...) m(x) IDENTITY(MAP255(m, __VA_ARGS__)) #define MAP257(m, x, ...) m(x) IDENTITY(MAP256(m, __VA_ARGS__)) #define MAP258(m, x, ...) m(x) IDENTITY(MAP257(m, __VA_ARGS__)) #define MAP259(m, x, ...) m(x) IDENTITY(MAP258(m, __VA_ARGS__)) #define MAP260(m, x, ...) m(x) IDENTITY(MAP259(m, __VA_ARGS__)) #define MAP261(m, x, ...) m(x) IDENTITY(MAP260(m, __VA_ARGS__)) #define MAP262(m, x, ...) m(x) IDENTITY(MAP261(m, __VA_ARGS__)) #define MAP263(m, x, ...) m(x) IDENTITY(MAP262(m, __VA_ARGS__)) #define MAP264(m, x, ...) m(x) IDENTITY(MAP263(m, __VA_ARGS__)) #define MAP265(m, x, ...) m(x) IDENTITY(MAP264(m, __VA_ARGS__)) #define MAP266(m, x, ...) m(x) IDENTITY(MAP265(m, __VA_ARGS__)) #define MAP267(m, x, ...) m(x) IDENTITY(MAP266(m, __VA_ARGS__)) #define MAP268(m, x, ...) m(x) IDENTITY(MAP267(m, __VA_ARGS__)) #define MAP269(m, x, ...) m(x) IDENTITY(MAP268(m, __VA_ARGS__)) #define MAP270(m, x, ...) m(x) IDENTITY(MAP269(m, __VA_ARGS__)) #define MAP271(m, x, ...) m(x) IDENTITY(MAP270(m, __VA_ARGS__)) #define MAP272(m, x, ...) m(x) IDENTITY(MAP271(m, __VA_ARGS__)) #define MAP273(m, x, ...) m(x) IDENTITY(MAP272(m, __VA_ARGS__)) #define MAP274(m, x, ...) m(x) IDENTITY(MAP273(m, __VA_ARGS__)) #define MAP275(m, x, ...) m(x) IDENTITY(MAP274(m, __VA_ARGS__)) #define MAP276(m, x, ...) m(x) IDENTITY(MAP275(m, __VA_ARGS__)) #define MAP277(m, x, ...) m(x) IDENTITY(MAP276(m, __VA_ARGS__)) #define MAP278(m, x, ...) m(x) IDENTITY(MAP277(m, __VA_ARGS__)) #define MAP279(m, x, ...) m(x) IDENTITY(MAP278(m, __VA_ARGS__)) #define MAP280(m, x, ...) m(x) IDENTITY(MAP279(m, __VA_ARGS__)) #define MAP281(m, x, ...) m(x) IDENTITY(MAP280(m, __VA_ARGS__)) #define MAP282(m, x, ...) m(x) IDENTITY(MAP281(m, __VA_ARGS__)) #define MAP283(m, x, ...) m(x) IDENTITY(MAP282(m, __VA_ARGS__)) #define MAP284(m, x, ...) m(x) IDENTITY(MAP283(m, __VA_ARGS__)) #define MAP285(m, x, ...) m(x) IDENTITY(MAP284(m, __VA_ARGS__)) #define MAP286(m, x, ...) m(x) IDENTITY(MAP285(m, __VA_ARGS__)) #define MAP287(m, x, ...) m(x) IDENTITY(MAP286(m, __VA_ARGS__)) #define MAP288(m, x, ...) m(x) IDENTITY(MAP287(m, __VA_ARGS__)) #define MAP289(m, x, ...) m(x) IDENTITY(MAP288(m, __VA_ARGS__)) #define MAP290(m, x, ...) m(x) IDENTITY(MAP289(m, __VA_ARGS__)) #define MAP291(m, x, ...) m(x) IDENTITY(MAP290(m, __VA_ARGS__)) #define MAP292(m, x, ...) m(x) IDENTITY(MAP291(m, __VA_ARGS__)) #define MAP293(m, x, ...) m(x) IDENTITY(MAP292(m, __VA_ARGS__)) #define MAP294(m, x, ...) m(x) IDENTITY(MAP293(m, __VA_ARGS__)) #define MAP295(m, x, ...) m(x) IDENTITY(MAP294(m, __VA_ARGS__)) #define MAP296(m, x, ...) m(x) IDENTITY(MAP295(m, __VA_ARGS__)) #define MAP297(m, x, ...) m(x) IDENTITY(MAP296(m, __VA_ARGS__)) #define MAP298(m, x, ...) m(x) IDENTITY(MAP297(m, __VA_ARGS__)) #define MAP299(m, x, ...) m(x) IDENTITY(MAP298(m, __VA_ARGS__)) #define MAP300(m, x, ...) m(x) IDENTITY(MAP299(m, __VA_ARGS__)) #define MAP301(m, x, ...) m(x) IDENTITY(MAP300(m, __VA_ARGS__)) #define MAP302(m, x, ...) m(x) IDENTITY(MAP301(m, __VA_ARGS__)) #define MAP303(m, x, ...) m(x) IDENTITY(MAP302(m, __VA_ARGS__)) #define MAP304(m, x, ...) m(x) IDENTITY(MAP303(m, __VA_ARGS__)) #define MAP305(m, x, ...) m(x) IDENTITY(MAP304(m, __VA_ARGS__)) #define MAP306(m, x, ...) m(x) IDENTITY(MAP305(m, __VA_ARGS__)) #define MAP307(m, x, ...) m(x) IDENTITY(MAP306(m, __VA_ARGS__)) #define MAP308(m, x, ...) m(x) IDENTITY(MAP307(m, __VA_ARGS__)) #define MAP309(m, x, ...) m(x) IDENTITY(MAP308(m, __VA_ARGS__)) #define MAP310(m, x, ...) m(x) IDENTITY(MAP309(m, __VA_ARGS__)) #define MAP311(m, x, ...) m(x) IDENTITY(MAP310(m, __VA_ARGS__)) #define MAP312(m, x, ...) m(x) IDENTITY(MAP311(m, __VA_ARGS__)) #define MAP313(m, x, ...) m(x) IDENTITY(MAP312(m, __VA_ARGS__)) #define MAP314(m, x, ...) m(x) IDENTITY(MAP313(m, __VA_ARGS__)) #define MAP315(m, x, ...) m(x) IDENTITY(MAP314(m, __VA_ARGS__)) #define MAP316(m, x, ...) m(x) IDENTITY(MAP315(m, __VA_ARGS__)) #define MAP317(m, x, ...) m(x) IDENTITY(MAP316(m, __VA_ARGS__)) #define MAP318(m, x, ...) m(x) IDENTITY(MAP317(m, __VA_ARGS__)) #define MAP319(m, x, ...) m(x) IDENTITY(MAP318(m, __VA_ARGS__)) #define MAP320(m, x, ...) m(x) IDENTITY(MAP319(m, __VA_ARGS__)) #define MAP321(m, x, ...) m(x) IDENTITY(MAP320(m, __VA_ARGS__)) #define MAP322(m, x, ...) m(x) IDENTITY(MAP321(m, __VA_ARGS__)) #define MAP323(m, x, ...) m(x) IDENTITY(MAP322(m, __VA_ARGS__)) #define MAP324(m, x, ...) m(x) IDENTITY(MAP323(m, __VA_ARGS__)) #define MAP325(m, x, ...) m(x) IDENTITY(MAP324(m, __VA_ARGS__)) #define MAP326(m, x, ...) m(x) IDENTITY(MAP325(m, __VA_ARGS__)) #define MAP327(m, x, ...) m(x) IDENTITY(MAP326(m, __VA_ARGS__)) #define MAP328(m, x, ...) m(x) IDENTITY(MAP327(m, __VA_ARGS__)) #define MAP329(m, x, ...) m(x) IDENTITY(MAP328(m, __VA_ARGS__)) #define MAP330(m, x, ...) m(x) IDENTITY(MAP329(m, __VA_ARGS__)) #define MAP331(m, x, ...) m(x) IDENTITY(MAP330(m, __VA_ARGS__)) #define MAP332(m, x, ...) m(x) IDENTITY(MAP331(m, __VA_ARGS__)) #define MAP333(m, x, ...) m(x) IDENTITY(MAP332(m, __VA_ARGS__)) #define MAP334(m, x, ...) m(x) IDENTITY(MAP333(m, __VA_ARGS__)) #define MAP335(m, x, ...) m(x) IDENTITY(MAP334(m, __VA_ARGS__)) #define MAP336(m, x, ...) m(x) IDENTITY(MAP335(m, __VA_ARGS__)) #define MAP337(m, x, ...) m(x) IDENTITY(MAP336(m, __VA_ARGS__)) #define MAP338(m, x, ...) m(x) IDENTITY(MAP337(m, __VA_ARGS__)) #define MAP339(m, x, ...) m(x) IDENTITY(MAP338(m, __VA_ARGS__)) #define MAP340(m, x, ...) m(x) IDENTITY(MAP339(m, __VA_ARGS__)) #define MAP341(m, x, ...) m(x) IDENTITY(MAP340(m, __VA_ARGS__)) #define MAP342(m, x, ...) m(x) IDENTITY(MAP341(m, __VA_ARGS__)) #define MAP343(m, x, ...) m(x) IDENTITY(MAP342(m, __VA_ARGS__)) #define MAP344(m, x, ...) m(x) IDENTITY(MAP343(m, __VA_ARGS__)) #define MAP345(m, x, ...) m(x) IDENTITY(MAP344(m, __VA_ARGS__)) #define MAP346(m, x, ...) m(x) IDENTITY(MAP345(m, __VA_ARGS__)) #define MAP347(m, x, ...) m(x) IDENTITY(MAP346(m, __VA_ARGS__)) #define MAP348(m, x, ...) m(x) IDENTITY(MAP347(m, __VA_ARGS__)) #define MAP349(m, x, ...) m(x) IDENTITY(MAP348(m, __VA_ARGS__)) #define MAP350(m, x, ...) m(x) IDENTITY(MAP349(m, __VA_ARGS__)) #define MAP351(m, x, ...) m(x) IDENTITY(MAP350(m, __VA_ARGS__)) #define MAP352(m, x, ...) m(x) IDENTITY(MAP351(m, __VA_ARGS__)) #define MAP353(m, x, ...) m(x) IDENTITY(MAP352(m, __VA_ARGS__)) #define MAP354(m, x, ...) m(x) IDENTITY(MAP353(m, __VA_ARGS__)) #define MAP355(m, x, ...) m(x) IDENTITY(MAP354(m, __VA_ARGS__)) #define MAP356(m, x, ...) m(x) IDENTITY(MAP355(m, __VA_ARGS__)) #define MAP357(m, x, ...) m(x) IDENTITY(MAP356(m, __VA_ARGS__)) #define MAP358(m, x, ...) m(x) IDENTITY(MAP357(m, __VA_ARGS__)) #define MAP359(m, x, ...) m(x) IDENTITY(MAP358(m, __VA_ARGS__)) #define MAP360(m, x, ...) m(x) IDENTITY(MAP359(m, __VA_ARGS__)) #define MAP361(m, x, ...) m(x) IDENTITY(MAP360(m, __VA_ARGS__)) #define MAP362(m, x, ...) m(x) IDENTITY(MAP361(m, __VA_ARGS__)) #define MAP363(m, x, ...) m(x) IDENTITY(MAP362(m, __VA_ARGS__)) #define MAP364(m, x, ...) m(x) IDENTITY(MAP363(m, __VA_ARGS__)) #define MAP365(m, x, ...) m(x) IDENTITY(MAP364(m, __VA_ARGS__)) #define MAP366(m, x, ...) m(x) IDENTITY(MAP365(m, __VA_ARGS__)) #define MAP367(m, x, ...) m(x) IDENTITY(MAP366(m, __VA_ARGS__)) #define MAP368(m, x, ...) m(x) IDENTITY(MAP367(m, __VA_ARGS__)) #define MAP369(m, x, ...) m(x) IDENTITY(MAP368(m, __VA_ARGS__)) #define MAP370(m, x, ...) m(x) IDENTITY(MAP369(m, __VA_ARGS__)) #define MAP371(m, x, ...) m(x) IDENTITY(MAP370(m, __VA_ARGS__)) #define MAP372(m, x, ...) m(x) IDENTITY(MAP371(m, __VA_ARGS__)) #define MAP373(m, x, ...) m(x) IDENTITY(MAP372(m, __VA_ARGS__)) #define MAP374(m, x, ...) m(x) IDENTITY(MAP373(m, __VA_ARGS__)) #define MAP375(m, x, ...) m(x) IDENTITY(MAP374(m, __VA_ARGS__)) #define MAP376(m, x, ...) m(x) IDENTITY(MAP375(m, __VA_ARGS__)) #define MAP377(m, x, ...) m(x) IDENTITY(MAP376(m, __VA_ARGS__)) #define MAP378(m, x, ...) m(x) IDENTITY(MAP377(m, __VA_ARGS__)) #define MAP379(m, x, ...) m(x) IDENTITY(MAP378(m, __VA_ARGS__)) #define MAP380(m, x, ...) m(x) IDENTITY(MAP379(m, __VA_ARGS__)) #define MAP381(m, x, ...) m(x) IDENTITY(MAP380(m, __VA_ARGS__)) #define MAP382(m, x, ...) m(x) IDENTITY(MAP381(m, __VA_ARGS__)) #define MAP383(m, x, ...) m(x) IDENTITY(MAP382(m, __VA_ARGS__)) #define MAP384(m, x, ...) m(x) IDENTITY(MAP383(m, __VA_ARGS__)) #define MAP385(m, x, ...) m(x) IDENTITY(MAP384(m, __VA_ARGS__)) #define MAP386(m, x, ...) m(x) IDENTITY(MAP385(m, __VA_ARGS__)) #define MAP387(m, x, ...) m(x) IDENTITY(MAP386(m, __VA_ARGS__)) #define MAP388(m, x, ...) m(x) IDENTITY(MAP387(m, __VA_ARGS__)) #define MAP389(m, x, ...) m(x) IDENTITY(MAP388(m, __VA_ARGS__)) #define MAP390(m, x, ...) m(x) IDENTITY(MAP389(m, __VA_ARGS__)) #define MAP391(m, x, ...) m(x) IDENTITY(MAP390(m, __VA_ARGS__)) #define MAP392(m, x, ...) m(x) IDENTITY(MAP391(m, __VA_ARGS__)) #define MAP393(m, x, ...) m(x) IDENTITY(MAP392(m, __VA_ARGS__)) #define MAP394(m, x, ...) m(x) IDENTITY(MAP393(m, __VA_ARGS__)) #define MAP395(m, x, ...) m(x) IDENTITY(MAP394(m, __VA_ARGS__)) #define MAP396(m, x, ...) m(x) IDENTITY(MAP395(m, __VA_ARGS__)) #define MAP397(m, x, ...) m(x) IDENTITY(MAP396(m, __VA_ARGS__)) #define MAP398(m, x, ...) m(x) IDENTITY(MAP397(m, __VA_ARGS__)) #define MAP399(m, x, ...) m(x) IDENTITY(MAP398(m, __VA_ARGS__)) #define MAP400(m, x, ...) m(x) IDENTITY(MAP399(m, __VA_ARGS__)) #define MAP401(m, x, ...) m(x) IDENTITY(MAP400(m, __VA_ARGS__)) #define MAP402(m, x, ...) m(x) IDENTITY(MAP401(m, __VA_ARGS__)) #define MAP403(m, x, ...) m(x) IDENTITY(MAP402(m, __VA_ARGS__)) #define MAP404(m, x, ...) m(x) IDENTITY(MAP403(m, __VA_ARGS__)) #define MAP405(m, x, ...) m(x) IDENTITY(MAP404(m, __VA_ARGS__)) #define MAP406(m, x, ...) m(x) IDENTITY(MAP405(m, __VA_ARGS__)) #define MAP407(m, x, ...) m(x) IDENTITY(MAP406(m, __VA_ARGS__)) #define MAP408(m, x, ...) m(x) IDENTITY(MAP407(m, __VA_ARGS__)) #define MAP409(m, x, ...) m(x) IDENTITY(MAP408(m, __VA_ARGS__)) #define MAP410(m, x, ...) m(x) IDENTITY(MAP409(m, __VA_ARGS__)) #define MAP411(m, x, ...) m(x) IDENTITY(MAP410(m, __VA_ARGS__)) #define MAP412(m, x, ...) m(x) IDENTITY(MAP411(m, __VA_ARGS__)) #define MAP413(m, x, ...) m(x) IDENTITY(MAP412(m, __VA_ARGS__)) #define MAP414(m, x, ...) m(x) IDENTITY(MAP413(m, __VA_ARGS__)) #define MAP415(m, x, ...) m(x) IDENTITY(MAP414(m, __VA_ARGS__)) #define MAP416(m, x, ...) m(x) IDENTITY(MAP415(m, __VA_ARGS__)) #define MAP417(m, x, ...) m(x) IDENTITY(MAP416(m, __VA_ARGS__)) #define MAP418(m, x, ...) m(x) IDENTITY(MAP417(m, __VA_ARGS__)) #define MAP419(m, x, ...) m(x) IDENTITY(MAP418(m, __VA_ARGS__)) #define MAP420(m, x, ...) m(x) IDENTITY(MAP419(m, __VA_ARGS__)) #define MAP421(m, x, ...) m(x) IDENTITY(MAP420(m, __VA_ARGS__)) #define MAP422(m, x, ...) m(x) IDENTITY(MAP421(m, __VA_ARGS__)) #define MAP423(m, x, ...) m(x) IDENTITY(MAP422(m, __VA_ARGS__)) #define MAP424(m, x, ...) m(x) IDENTITY(MAP423(m, __VA_ARGS__)) #define MAP425(m, x, ...) m(x) IDENTITY(MAP424(m, __VA_ARGS__)) #define MAP426(m, x, ...) m(x) IDENTITY(MAP425(m, __VA_ARGS__)) #define MAP427(m, x, ...) m(x) IDENTITY(MAP426(m, __VA_ARGS__)) #define MAP428(m, x, ...) m(x) IDENTITY(MAP427(m, __VA_ARGS__)) #define MAP429(m, x, ...) m(x) IDENTITY(MAP428(m, __VA_ARGS__)) #define MAP430(m, x, ...) m(x) IDENTITY(MAP429(m, __VA_ARGS__)) #define MAP431(m, x, ...) m(x) IDENTITY(MAP430(m, __VA_ARGS__)) #define MAP432(m, x, ...) m(x) IDENTITY(MAP431(m, __VA_ARGS__)) #define MAP433(m, x, ...) m(x) IDENTITY(MAP432(m, __VA_ARGS__)) #define MAP434(m, x, ...) m(x) IDENTITY(MAP433(m, __VA_ARGS__)) #define MAP435(m, x, ...) m(x) IDENTITY(MAP434(m, __VA_ARGS__)) #define MAP436(m, x, ...) m(x) IDENTITY(MAP435(m, __VA_ARGS__)) #define MAP437(m, x, ...) m(x) IDENTITY(MAP436(m, __VA_ARGS__)) #define MAP438(m, x, ...) m(x) IDENTITY(MAP437(m, __VA_ARGS__)) #define MAP439(m, x, ...) m(x) IDENTITY(MAP438(m, __VA_ARGS__)) #define MAP440(m, x, ...) m(x) IDENTITY(MAP439(m, __VA_ARGS__)) #define MAP441(m, x, ...) m(x) IDENTITY(MAP440(m, __VA_ARGS__)) #define MAP442(m, x, ...) m(x) IDENTITY(MAP441(m, __VA_ARGS__)) #define MAP443(m, x, ...) m(x) IDENTITY(MAP442(m, __VA_ARGS__)) #define MAP444(m, x, ...) m(x) IDENTITY(MAP443(m, __VA_ARGS__)) #define MAP445(m, x, ...) m(x) IDENTITY(MAP444(m, __VA_ARGS__)) #define MAP446(m, x, ...) m(x) IDENTITY(MAP445(m, __VA_ARGS__)) #define MAP447(m, x, ...) m(x) IDENTITY(MAP446(m, __VA_ARGS__)) #define MAP448(m, x, ...) m(x) IDENTITY(MAP447(m, __VA_ARGS__)) #define MAP449(m, x, ...) m(x) IDENTITY(MAP448(m, __VA_ARGS__)) #define MAP450(m, x, ...) m(x) IDENTITY(MAP449(m, __VA_ARGS__)) #define MAP451(m, x, ...) m(x) IDENTITY(MAP450(m, __VA_ARGS__)) #define MAP452(m, x, ...) m(x) IDENTITY(MAP451(m, __VA_ARGS__)) #define MAP453(m, x, ...) m(x) IDENTITY(MAP452(m, __VA_ARGS__)) #define MAP454(m, x, ...) m(x) IDENTITY(MAP453(m, __VA_ARGS__)) #define MAP455(m, x, ...) m(x) IDENTITY(MAP454(m, __VA_ARGS__)) #define MAP456(m, x, ...) m(x) IDENTITY(MAP455(m, __VA_ARGS__)) #define MAP457(m, x, ...) m(x) IDENTITY(MAP456(m, __VA_ARGS__)) #define MAP458(m, x, ...) m(x) IDENTITY(MAP457(m, __VA_ARGS__)) #define MAP459(m, x, ...) m(x) IDENTITY(MAP458(m, __VA_ARGS__)) #define MAP460(m, x, ...) m(x) IDENTITY(MAP459(m, __VA_ARGS__)) #define MAP461(m, x, ...) m(x) IDENTITY(MAP460(m, __VA_ARGS__)) #define MAP462(m, x, ...) m(x) IDENTITY(MAP461(m, __VA_ARGS__)) #define MAP463(m, x, ...) m(x) IDENTITY(MAP462(m, __VA_ARGS__)) #define MAP464(m, x, ...) m(x) IDENTITY(MAP463(m, __VA_ARGS__)) #define MAP465(m, x, ...) m(x) IDENTITY(MAP464(m, __VA_ARGS__)) #define MAP466(m, x, ...) m(x) IDENTITY(MAP465(m, __VA_ARGS__)) #define MAP467(m, x, ...) m(x) IDENTITY(MAP466(m, __VA_ARGS__)) #define MAP468(m, x, ...) m(x) IDENTITY(MAP467(m, __VA_ARGS__)) #define MAP469(m, x, ...) m(x) IDENTITY(MAP468(m, __VA_ARGS__)) #define MAP470(m, x, ...) m(x) IDENTITY(MAP469(m, __VA_ARGS__)) #define MAP471(m, x, ...) m(x) IDENTITY(MAP470(m, __VA_ARGS__)) #define MAP472(m, x, ...) m(x) IDENTITY(MAP471(m, __VA_ARGS__)) #define MAP473(m, x, ...) m(x) IDENTITY(MAP472(m, __VA_ARGS__)) #define MAP474(m, x, ...) m(x) IDENTITY(MAP473(m, __VA_ARGS__)) #define MAP475(m, x, ...) m(x) IDENTITY(MAP474(m, __VA_ARGS__)) #define MAP476(m, x, ...) m(x) IDENTITY(MAP475(m, __VA_ARGS__)) #define MAP477(m, x, ...) m(x) IDENTITY(MAP476(m, __VA_ARGS__)) #define MAP478(m, x, ...) m(x) IDENTITY(MAP477(m, __VA_ARGS__)) #define MAP479(m, x, ...) m(x) IDENTITY(MAP478(m, __VA_ARGS__)) #define MAP480(m, x, ...) m(x) IDENTITY(MAP479(m, __VA_ARGS__)) #define MAP481(m, x, ...) m(x) IDENTITY(MAP480(m, __VA_ARGS__)) #define MAP482(m, x, ...) m(x) IDENTITY(MAP481(m, __VA_ARGS__)) #define MAP483(m, x, ...) m(x) IDENTITY(MAP482(m, __VA_ARGS__)) #define MAP484(m, x, ...) m(x) IDENTITY(MAP483(m, __VA_ARGS__)) #define MAP485(m, x, ...) m(x) IDENTITY(MAP484(m, __VA_ARGS__)) #define MAP486(m, x, ...) m(x) IDENTITY(MAP485(m, __VA_ARGS__)) #define MAP487(m, x, ...) m(x) IDENTITY(MAP486(m, __VA_ARGS__)) #define MAP488(m, x, ...) m(x) IDENTITY(MAP487(m, __VA_ARGS__)) #define MAP489(m, x, ...) m(x) IDENTITY(MAP488(m, __VA_ARGS__)) #define MAP490(m, x, ...) m(x) IDENTITY(MAP489(m, __VA_ARGS__)) #define MAP491(m, x, ...) m(x) IDENTITY(MAP490(m, __VA_ARGS__)) #define MAP492(m, x, ...) m(x) IDENTITY(MAP491(m, __VA_ARGS__)) #define MAP493(m, x, ...) m(x) IDENTITY(MAP492(m, __VA_ARGS__)) #define MAP494(m, x, ...) m(x) IDENTITY(MAP493(m, __VA_ARGS__)) #define MAP495(m, x, ...) m(x) IDENTITY(MAP494(m, __VA_ARGS__)) #define MAP496(m, x, ...) m(x) IDENTITY(MAP495(m, __VA_ARGS__)) #define MAP497(m, x, ...) m(x) IDENTITY(MAP496(m, __VA_ARGS__)) #define MAP498(m, x, ...) m(x) IDENTITY(MAP497(m, __VA_ARGS__)) #define MAP499(m, x, ...) m(x) IDENTITY(MAP498(m, __VA_ARGS__)) #define MAP500(m, x, ...) m(x) IDENTITY(MAP499(m, __VA_ARGS__)) #define MAP501(m, x, ...) m(x) IDENTITY(MAP500(m, __VA_ARGS__)) #define MAP502(m, x, ...) m(x) IDENTITY(MAP501(m, __VA_ARGS__)) #define MAP503(m, x, ...) m(x) IDENTITY(MAP502(m, __VA_ARGS__)) #define MAP504(m, x, ...) m(x) IDENTITY(MAP503(m, __VA_ARGS__)) #define MAP505(m, x, ...) m(x) IDENTITY(MAP504(m, __VA_ARGS__)) #define MAP506(m, x, ...) m(x) IDENTITY(MAP505(m, __VA_ARGS__)) #define MAP507(m, x, ...) m(x) IDENTITY(MAP506(m, __VA_ARGS__)) #define MAP508(m, x, ...) m(x) IDENTITY(MAP507(m, __VA_ARGS__)) #define MAP509(m, x, ...) m(x) IDENTITY(MAP508(m, __VA_ARGS__)) #define MAP510(m, x, ...) m(x) IDENTITY(MAP509(m, __VA_ARGS__)) #define MAP511(m, x, ...) m(x) IDENTITY(MAP510(m, __VA_ARGS__)) #define MAP512(m, x, ...) m(x) IDENTITY(MAP511(m, __VA_ARGS__)) #define MAP513(m, x, ...) m(x) IDENTITY(MAP512(m, __VA_ARGS__)) #define MAP514(m, x, ...) m(x) IDENTITY(MAP513(m, __VA_ARGS__)) #define MAP515(m, x, ...) m(x) IDENTITY(MAP514(m, __VA_ARGS__)) #define MAP516(m, x, ...) m(x) IDENTITY(MAP515(m, __VA_ARGS__)) #define MAP517(m, x, ...) m(x) IDENTITY(MAP516(m, __VA_ARGS__)) #define MAP518(m, x, ...) m(x) IDENTITY(MAP517(m, __VA_ARGS__)) #define MAP519(m, x, ...) m(x) IDENTITY(MAP518(m, __VA_ARGS__)) #define MAP520(m, x, ...) m(x) IDENTITY(MAP519(m, __VA_ARGS__)) #define MAP521(m, x, ...) m(x) IDENTITY(MAP520(m, __VA_ARGS__)) #define MAP522(m, x, ...) m(x) IDENTITY(MAP521(m, __VA_ARGS__)) #define MAP523(m, x, ...) m(x) IDENTITY(MAP522(m, __VA_ARGS__)) #define MAP524(m, x, ...) m(x) IDENTITY(MAP523(m, __VA_ARGS__)) #define MAP525(m, x, ...) m(x) IDENTITY(MAP524(m, __VA_ARGS__)) #define MAP526(m, x, ...) m(x) IDENTITY(MAP525(m, __VA_ARGS__)) #define MAP527(m, x, ...) m(x) IDENTITY(MAP526(m, __VA_ARGS__)) #define MAP528(m, x, ...) m(x) IDENTITY(MAP527(m, __VA_ARGS__)) #define MAP529(m, x, ...) m(x) IDENTITY(MAP528(m, __VA_ARGS__)) #define MAP530(m, x, ...) m(x) IDENTITY(MAP529(m, __VA_ARGS__)) #define MAP531(m, x, ...) m(x) IDENTITY(MAP530(m, __VA_ARGS__)) #define MAP532(m, x, ...) m(x) IDENTITY(MAP531(m, __VA_ARGS__)) #define MAP533(m, x, ...) m(x) IDENTITY(MAP532(m, __VA_ARGS__)) #define MAP534(m, x, ...) m(x) IDENTITY(MAP533(m, __VA_ARGS__)) #define MAP535(m, x, ...) m(x) IDENTITY(MAP534(m, __VA_ARGS__)) #define MAP536(m, x, ...) m(x) IDENTITY(MAP535(m, __VA_ARGS__)) #define MAP537(m, x, ...) m(x) IDENTITY(MAP536(m, __VA_ARGS__)) #define MAP538(m, x, ...) m(x) IDENTITY(MAP537(m, __VA_ARGS__)) #define MAP539(m, x, ...) m(x) IDENTITY(MAP538(m, __VA_ARGS__)) #define MAP540(m, x, ...) m(x) IDENTITY(MAP539(m, __VA_ARGS__)) #define MAP541(m, x, ...) m(x) IDENTITY(MAP540(m, __VA_ARGS__)) #define MAP542(m, x, ...) m(x) IDENTITY(MAP541(m, __VA_ARGS__)) #define MAP543(m, x, ...) m(x) IDENTITY(MAP542(m, __VA_ARGS__)) #define MAP544(m, x, ...) m(x) IDENTITY(MAP543(m, __VA_ARGS__)) #define MAP545(m, x, ...) m(x) IDENTITY(MAP544(m, __VA_ARGS__)) #define MAP546(m, x, ...) m(x) IDENTITY(MAP545(m, __VA_ARGS__)) #define MAP547(m, x, ...) m(x) IDENTITY(MAP546(m, __VA_ARGS__)) #define MAP548(m, x, ...) m(x) IDENTITY(MAP547(m, __VA_ARGS__)) #define MAP549(m, x, ...) m(x) IDENTITY(MAP548(m, __VA_ARGS__)) #define MAP550(m, x, ...) m(x) IDENTITY(MAP549(m, __VA_ARGS__)) #define MAP551(m, x, ...) m(x) IDENTITY(MAP550(m, __VA_ARGS__)) #define MAP552(m, x, ...) m(x) IDENTITY(MAP551(m, __VA_ARGS__)) #define MAP553(m, x, ...) m(x) IDENTITY(MAP552(m, __VA_ARGS__)) #define MAP554(m, x, ...) m(x) IDENTITY(MAP553(m, __VA_ARGS__)) #define MAP555(m, x, ...) m(x) IDENTITY(MAP554(m, __VA_ARGS__)) #define MAP556(m, x, ...) m(x) IDENTITY(MAP555(m, __VA_ARGS__)) #define MAP557(m, x, ...) m(x) IDENTITY(MAP556(m, __VA_ARGS__)) #define MAP558(m, x, ...) m(x) IDENTITY(MAP557(m, __VA_ARGS__)) #define MAP559(m, x, ...) m(x) IDENTITY(MAP558(m, __VA_ARGS__)) #define MAP560(m, x, ...) m(x) IDENTITY(MAP559(m, __VA_ARGS__)) #define MAP561(m, x, ...) m(x) IDENTITY(MAP560(m, __VA_ARGS__)) #define MAP562(m, x, ...) m(x) IDENTITY(MAP561(m, __VA_ARGS__)) #define MAP563(m, x, ...) m(x) IDENTITY(MAP562(m, __VA_ARGS__)) #define MAP564(m, x, ...) m(x) IDENTITY(MAP563(m, __VA_ARGS__)) #define MAP565(m, x, ...) m(x) IDENTITY(MAP564(m, __VA_ARGS__)) #define MAP566(m, x, ...) m(x) IDENTITY(MAP565(m, __VA_ARGS__)) #define MAP567(m, x, ...) m(x) IDENTITY(MAP566(m, __VA_ARGS__)) #define MAP568(m, x, ...) m(x) IDENTITY(MAP567(m, __VA_ARGS__)) #define MAP569(m, x, ...) m(x) IDENTITY(MAP568(m, __VA_ARGS__)) #define MAP570(m, x, ...) m(x) IDENTITY(MAP569(m, __VA_ARGS__)) #define MAP571(m, x, ...) m(x) IDENTITY(MAP570(m, __VA_ARGS__)) #define MAP572(m, x, ...) m(x) IDENTITY(MAP571(m, __VA_ARGS__)) #define MAP573(m, x, ...) m(x) IDENTITY(MAP572(m, __VA_ARGS__)) #define MAP574(m, x, ...) m(x) IDENTITY(MAP573(m, __VA_ARGS__)) #define MAP575(m, x, ...) m(x) IDENTITY(MAP574(m, __VA_ARGS__)) #define MAP576(m, x, ...) m(x) IDENTITY(MAP575(m, __VA_ARGS__)) #define MAP577(m, x, ...) m(x) IDENTITY(MAP576(m, __VA_ARGS__)) #define MAP578(m, x, ...) m(x) IDENTITY(MAP577(m, __VA_ARGS__)) #define MAP579(m, x, ...) m(x) IDENTITY(MAP578(m, __VA_ARGS__)) #define MAP580(m, x, ...) m(x) IDENTITY(MAP579(m, __VA_ARGS__)) #define MAP581(m, x, ...) m(x) IDENTITY(MAP580(m, __VA_ARGS__)) #define MAP582(m, x, ...) m(x) IDENTITY(MAP581(m, __VA_ARGS__)) #define MAP583(m, x, ...) m(x) IDENTITY(MAP582(m, __VA_ARGS__)) #define MAP584(m, x, ...) m(x) IDENTITY(MAP583(m, __VA_ARGS__)) #define MAP585(m, x, ...) m(x) IDENTITY(MAP584(m, __VA_ARGS__)) #define MAP586(m, x, ...) m(x) IDENTITY(MAP585(m, __VA_ARGS__)) #define MAP587(m, x, ...) m(x) IDENTITY(MAP586(m, __VA_ARGS__)) #define MAP588(m, x, ...) m(x) IDENTITY(MAP587(m, __VA_ARGS__)) #define MAP589(m, x, ...) m(x) IDENTITY(MAP588(m, __VA_ARGS__)) #define MAP590(m, x, ...) m(x) IDENTITY(MAP589(m, __VA_ARGS__)) #define MAP591(m, x, ...) m(x) IDENTITY(MAP590(m, __VA_ARGS__)) #define MAP592(m, x, ...) m(x) IDENTITY(MAP591(m, __VA_ARGS__)) #define MAP593(m, x, ...) m(x) IDENTITY(MAP592(m, __VA_ARGS__)) #define MAP594(m, x, ...) m(x) IDENTITY(MAP593(m, __VA_ARGS__)) #define MAP595(m, x, ...) m(x) IDENTITY(MAP594(m, __VA_ARGS__)) #define MAP596(m, x, ...) m(x) IDENTITY(MAP595(m, __VA_ARGS__)) #define MAP597(m, x, ...) m(x) IDENTITY(MAP596(m, __VA_ARGS__)) #define MAP598(m, x, ...) m(x) IDENTITY(MAP597(m, __VA_ARGS__)) #define MAP599(m, x, ...) m(x) IDENTITY(MAP598(m, __VA_ARGS__)) #define MAP600(m, x, ...) m(x) IDENTITY(MAP499(m, __VA_ARGS__)) #define MAP601(m, x, ...) m(x) IDENTITY(MAP600(m, __VA_ARGS__)) #define MAP602(m, x, ...) m(x) IDENTITY(MAP601(m, __VA_ARGS__)) #define MAP603(m, x, ...) m(x) IDENTITY(MAP602(m, __VA_ARGS__)) #define MAP604(m, x, ...) m(x) IDENTITY(MAP603(m, __VA_ARGS__)) #define MAP605(m, x, ...) m(x) IDENTITY(MAP604(m, __VA_ARGS__)) #define MAP606(m, x, ...) m(x) IDENTITY(MAP605(m, __VA_ARGS__)) #define MAP607(m, x, ...) m(x) IDENTITY(MAP606(m, __VA_ARGS__)) #define MAP608(m, x, ...) m(x) IDENTITY(MAP607(m, __VA_ARGS__)) #define MAP609(m, x, ...) m(x) IDENTITY(MAP608(m, __VA_ARGS__)) #define MAP610(m, x, ...) m(x) IDENTITY(MAP609(m, __VA_ARGS__)) #define MAP611(m, x, ...) m(x) IDENTITY(MAP610(m, __VA_ARGS__)) #define MAP612(m, x, ...) m(x) IDENTITY(MAP611(m, __VA_ARGS__)) #define MAP613(m, x, ...) m(x) IDENTITY(MAP612(m, __VA_ARGS__)) #define MAP614(m, x, ...) m(x) IDENTITY(MAP613(m, __VA_ARGS__)) #define MAP615(m, x, ...) m(x) IDENTITY(MAP614(m, __VA_ARGS__)) #define MAP616(m, x, ...) m(x) IDENTITY(MAP615(m, __VA_ARGS__)) #define MAP617(m, x, ...) m(x) IDENTITY(MAP616(m, __VA_ARGS__)) #define MAP618(m, x, ...) m(x) IDENTITY(MAP617(m, __VA_ARGS__)) #define MAP619(m, x, ...) m(x) IDENTITY(MAP618(m, __VA_ARGS__)) #define MAP620(m, x, ...) m(x) IDENTITY(MAP619(m, __VA_ARGS__)) #define MAP621(m, x, ...) m(x) IDENTITY(MAP620(m, __VA_ARGS__)) #define MAP622(m, x, ...) m(x) IDENTITY(MAP621(m, __VA_ARGS__)) #define MAP623(m, x, ...) m(x) IDENTITY(MAP622(m, __VA_ARGS__)) #define MAP624(m, x, ...) m(x) IDENTITY(MAP623(m, __VA_ARGS__)) #define MAP625(m, x, ...) m(x) IDENTITY(MAP624(m, __VA_ARGS__)) #define MAP626(m, x, ...) m(x) IDENTITY(MAP625(m, __VA_ARGS__)) #define MAP627(m, x, ...) m(x) IDENTITY(MAP626(m, __VA_ARGS__)) #define MAP628(m, x, ...) m(x) IDENTITY(MAP627(m, __VA_ARGS__)) #define MAP629(m, x, ...) m(x) IDENTITY(MAP628(m, __VA_ARGS__)) #define MAP630(m, x, ...) m(x) IDENTITY(MAP629(m, __VA_ARGS__)) #define MAP631(m, x, ...) m(x) IDENTITY(MAP630(m, __VA_ARGS__)) #define MAP632(m, x, ...) m(x) IDENTITY(MAP631(m, __VA_ARGS__)) #define MAP633(m, x, ...) m(x) IDENTITY(MAP632(m, __VA_ARGS__)) #define MAP634(m, x, ...) m(x) IDENTITY(MAP633(m, __VA_ARGS__)) #define MAP635(m, x, ...) m(x) IDENTITY(MAP634(m, __VA_ARGS__)) #define MAP636(m, x, ...) m(x) IDENTITY(MAP635(m, __VA_ARGS__)) #define MAP637(m, x, ...) m(x) IDENTITY(MAP636(m, __VA_ARGS__)) #define MAP638(m, x, ...) m(x) IDENTITY(MAP637(m, __VA_ARGS__)) #define MAP639(m, x, ...) m(x) IDENTITY(MAP638(m, __VA_ARGS__)) #define MAP640(m, x, ...) m(x) IDENTITY(MAP639(m, __VA_ARGS__)) #define MAP641(m, x, ...) m(x) IDENTITY(MAP640(m, __VA_ARGS__)) #define MAP642(m, x, ...) m(x) IDENTITY(MAP641(m, __VA_ARGS__)) #define MAP643(m, x, ...) m(x) IDENTITY(MAP642(m, __VA_ARGS__)) #define MAP644(m, x, ...) m(x) IDENTITY(MAP643(m, __VA_ARGS__)) #define MAP645(m, x, ...) m(x) IDENTITY(MAP644(m, __VA_ARGS__)) #define MAP646(m, x, ...) m(x) IDENTITY(MAP645(m, __VA_ARGS__)) #define MAP647(m, x, ...) m(x) IDENTITY(MAP646(m, __VA_ARGS__)) #define MAP648(m, x, ...) m(x) IDENTITY(MAP647(m, __VA_ARGS__)) #define MAP649(m, x, ...) m(x) IDENTITY(MAP648(m, __VA_ARGS__)) #define MAP650(m, x, ...) m(x) IDENTITY(MAP649(m, __VA_ARGS__)) #define MAP651(m, x, ...) m(x) IDENTITY(MAP650(m, __VA_ARGS__)) #define MAP652(m, x, ...) m(x) IDENTITY(MAP651(m, __VA_ARGS__)) #define MAP653(m, x, ...) m(x) IDENTITY(MAP652(m, __VA_ARGS__)) #define MAP654(m, x, ...) m(x) IDENTITY(MAP653(m, __VA_ARGS__)) #define MAP655(m, x, ...) m(x) IDENTITY(MAP654(m, __VA_ARGS__)) #define MAP656(m, x, ...) m(x) IDENTITY(MAP655(m, __VA_ARGS__)) #define MAP657(m, x, ...) m(x) IDENTITY(MAP656(m, __VA_ARGS__)) #define MAP658(m, x, ...) m(x) IDENTITY(MAP657(m, __VA_ARGS__)) #define MAP659(m, x, ...) m(x) IDENTITY(MAP658(m, __VA_ARGS__)) #define MAP660(m, x, ...) m(x) IDENTITY(MAP659(m, __VA_ARGS__)) #define MAP661(m, x, ...) m(x) IDENTITY(MAP660(m, __VA_ARGS__)) #define MAP662(m, x, ...) m(x) IDENTITY(MAP661(m, __VA_ARGS__)) #define MAP663(m, x, ...) m(x) IDENTITY(MAP662(m, __VA_ARGS__)) #define MAP664(m, x, ...) m(x) IDENTITY(MAP663(m, __VA_ARGS__)) #define MAP665(m, x, ...) m(x) IDENTITY(MAP664(m, __VA_ARGS__)) #define MAP666(m, x, ...) m(x) IDENTITY(MAP665(m, __VA_ARGS__)) #define MAP667(m, x, ...) m(x) IDENTITY(MAP666(m, __VA_ARGS__)) #define MAP668(m, x, ...) m(x) IDENTITY(MAP667(m, __VA_ARGS__)) #define MAP669(m, x, ...) m(x) IDENTITY(MAP668(m, __VA_ARGS__)) #define MAP670(m, x, ...) m(x) IDENTITY(MAP669(m, __VA_ARGS__)) #define MAP671(m, x, ...) m(x) IDENTITY(MAP670(m, __VA_ARGS__)) #define MAP672(m, x, ...) m(x) IDENTITY(MAP671(m, __VA_ARGS__)) #define MAP673(m, x, ...) m(x) IDENTITY(MAP672(m, __VA_ARGS__)) #define MAP674(m, x, ...) m(x) IDENTITY(MAP673(m, __VA_ARGS__)) #define MAP675(m, x, ...) m(x) IDENTITY(MAP674(m, __VA_ARGS__)) #define MAP676(m, x, ...) m(x) IDENTITY(MAP675(m, __VA_ARGS__)) #define MAP677(m, x, ...) m(x) IDENTITY(MAP676(m, __VA_ARGS__)) #define MAP678(m, x, ...) m(x) IDENTITY(MAP677(m, __VA_ARGS__)) #define MAP679(m, x, ...) m(x) IDENTITY(MAP678(m, __VA_ARGS__)) #define MAP680(m, x, ...) m(x) IDENTITY(MAP679(m, __VA_ARGS__)) #define MAP681(m, x, ...) m(x) IDENTITY(MAP680(m, __VA_ARGS__)) #define MAP682(m, x, ...) m(x) IDENTITY(MAP681(m, __VA_ARGS__)) #define MAP683(m, x, ...) m(x) IDENTITY(MAP682(m, __VA_ARGS__)) #define MAP684(m, x, ...) m(x) IDENTITY(MAP683(m, __VA_ARGS__)) #define MAP685(m, x, ...) m(x) IDENTITY(MAP684(m, __VA_ARGS__)) #define MAP686(m, x, ...) m(x) IDENTITY(MAP685(m, __VA_ARGS__)) #define MAP687(m, x, ...) m(x) IDENTITY(MAP686(m, __VA_ARGS__)) #define MAP688(m, x, ...) m(x) IDENTITY(MAP687(m, __VA_ARGS__)) #define MAP689(m, x, ...) m(x) IDENTITY(MAP688(m, __VA_ARGS__)) #define MAP690(m, x, ...) m(x) IDENTITY(MAP689(m, __VA_ARGS__)) #define MAP691(m, x, ...) m(x) IDENTITY(MAP690(m, __VA_ARGS__)) #define MAP692(m, x, ...) m(x) IDENTITY(MAP691(m, __VA_ARGS__)) #define MAP693(m, x, ...) m(x) IDENTITY(MAP692(m, __VA_ARGS__)) #define MAP694(m, x, ...) m(x) IDENTITY(MAP693(m, __VA_ARGS__)) #define MAP695(m, x, ...) m(x) IDENTITY(MAP694(m, __VA_ARGS__)) #define MAP696(m, x, ...) m(x) IDENTITY(MAP695(m, __VA_ARGS__)) #define MAP697(m, x, ...) m(x) IDENTITY(MAP696(m, __VA_ARGS__)) #define MAP698(m, x, ...) m(x) IDENTITY(MAP697(m, __VA_ARGS__)) #define MAP699(m, x, ...) m(x) IDENTITY(MAP698(m, __VA_ARGS__)) #define MAP700(m, x, ...) m(x) IDENTITY(MAP499(m, __VA_ARGS__)) #define MAP701(m, x, ...) m(x) IDENTITY(MAP700(m, __VA_ARGS__)) #define MAP702(m, x, ...) m(x) IDENTITY(MAP701(m, __VA_ARGS__)) #define MAP703(m, x, ...) m(x) IDENTITY(MAP702(m, __VA_ARGS__)) #define MAP704(m, x, ...) m(x) IDENTITY(MAP703(m, __VA_ARGS__)) #define MAP705(m, x, ...) m(x) IDENTITY(MAP704(m, __VA_ARGS__)) #define MAP706(m, x, ...) m(x) IDENTITY(MAP705(m, __VA_ARGS__)) #define MAP707(m, x, ...) m(x) IDENTITY(MAP706(m, __VA_ARGS__)) #define MAP708(m, x, ...) m(x) IDENTITY(MAP707(m, __VA_ARGS__)) #define MAP709(m, x, ...) m(x) IDENTITY(MAP708(m, __VA_ARGS__)) #define MAP710(m, x, ...) m(x) IDENTITY(MAP709(m, __VA_ARGS__)) #define MAP711(m, x, ...) m(x) IDENTITY(MAP710(m, __VA_ARGS__)) #define MAP712(m, x, ...) m(x) IDENTITY(MAP711(m, __VA_ARGS__)) #define MAP713(m, x, ...) m(x) IDENTITY(MAP712(m, __VA_ARGS__)) #define MAP714(m, x, ...) m(x) IDENTITY(MAP713(m, __VA_ARGS__)) #define MAP715(m, x, ...) m(x) IDENTITY(MAP714(m, __VA_ARGS__)) #define MAP716(m, x, ...) m(x) IDENTITY(MAP715(m, __VA_ARGS__)) #define MAP717(m, x, ...) m(x) IDENTITY(MAP716(m, __VA_ARGS__)) #define MAP718(m, x, ...) m(x) IDENTITY(MAP717(m, __VA_ARGS__)) #define MAP719(m, x, ...) m(x) IDENTITY(MAP718(m, __VA_ARGS__)) #define MAP720(m, x, ...) m(x) IDENTITY(MAP719(m, __VA_ARGS__)) #define MAP721(m, x, ...) m(x) IDENTITY(MAP720(m, __VA_ARGS__)) #define MAP722(m, x, ...) m(x) IDENTITY(MAP721(m, __VA_ARGS__)) #define MAP723(m, x, ...) m(x) IDENTITY(MAP722(m, __VA_ARGS__)) #define MAP724(m, x, ...) m(x) IDENTITY(MAP723(m, __VA_ARGS__)) #define MAP725(m, x, ...) m(x) IDENTITY(MAP724(m, __VA_ARGS__)) #define MAP726(m, x, ...) m(x) IDENTITY(MAP725(m, __VA_ARGS__)) #define MAP727(m, x, ...) m(x) IDENTITY(MAP726(m, __VA_ARGS__)) #define MAP728(m, x, ...) m(x) IDENTITY(MAP727(m, __VA_ARGS__)) #define MAP729(m, x, ...) m(x) IDENTITY(MAP728(m, __VA_ARGS__)) #define MAP730(m, x, ...) m(x) IDENTITY(MAP729(m, __VA_ARGS__)) #define MAP731(m, x, ...) m(x) IDENTITY(MAP730(m, __VA_ARGS__)) #define MAP732(m, x, ...) m(x) IDENTITY(MAP731(m, __VA_ARGS__)) #define MAP733(m, x, ...) m(x) IDENTITY(MAP732(m, __VA_ARGS__)) #define MAP734(m, x, ...) m(x) IDENTITY(MAP733(m, __VA_ARGS__)) #define MAP735(m, x, ...) m(x) IDENTITY(MAP734(m, __VA_ARGS__)) #define MAP736(m, x, ...) m(x) IDENTITY(MAP735(m, __VA_ARGS__)) #define MAP737(m, x, ...) m(x) IDENTITY(MAP736(m, __VA_ARGS__)) #define MAP738(m, x, ...) m(x) IDENTITY(MAP737(m, __VA_ARGS__)) #define MAP739(m, x, ...) m(x) IDENTITY(MAP738(m, __VA_ARGS__)) #define MAP740(m, x, ...) m(x) IDENTITY(MAP739(m, __VA_ARGS__)) #define MAP741(m, x, ...) m(x) IDENTITY(MAP740(m, __VA_ARGS__)) #define MAP742(m, x, ...) m(x) IDENTITY(MAP741(m, __VA_ARGS__)) #define MAP743(m, x, ...) m(x) IDENTITY(MAP742(m, __VA_ARGS__)) #define MAP744(m, x, ...) m(x) IDENTITY(MAP743(m, __VA_ARGS__)) #define MAP745(m, x, ...) m(x) IDENTITY(MAP744(m, __VA_ARGS__)) #define MAP746(m, x, ...) m(x) IDENTITY(MAP745(m, __VA_ARGS__)) #define MAP747(m, x, ...) m(x) IDENTITY(MAP746(m, __VA_ARGS__)) #define MAP748(m, x, ...) m(x) IDENTITY(MAP747(m, __VA_ARGS__)) #define MAP749(m, x, ...) m(x) IDENTITY(MAP748(m, __VA_ARGS__)) #define MAP750(m, x, ...) m(x) IDENTITY(MAP749(m, __VA_ARGS__)) #define MAP751(m, x, ...) m(x) IDENTITY(MAP750(m, __VA_ARGS__)) #define MAP752(m, x, ...) m(x) IDENTITY(MAP751(m, __VA_ARGS__)) #define MAP753(m, x, ...) m(x) IDENTITY(MAP752(m, __VA_ARGS__)) #define MAP754(m, x, ...) m(x) IDENTITY(MAP753(m, __VA_ARGS__)) #define MAP755(m, x, ...) m(x) IDENTITY(MAP754(m, __VA_ARGS__)) #define MAP756(m, x, ...) m(x) IDENTITY(MAP755(m, __VA_ARGS__)) #define MAP757(m, x, ...) m(x) IDENTITY(MAP756(m, __VA_ARGS__)) #define MAP758(m, x, ...) m(x) IDENTITY(MAP757(m, __VA_ARGS__)) #define MAP759(m, x, ...) m(x) IDENTITY(MAP758(m, __VA_ARGS__)) #define MAP760(m, x, ...) m(x) IDENTITY(MAP759(m, __VA_ARGS__)) #define MAP761(m, x, ...) m(x) IDENTITY(MAP760(m, __VA_ARGS__)) #define MAP762(m, x, ...) m(x) IDENTITY(MAP761(m, __VA_ARGS__)) #define MAP763(m, x, ...) m(x) IDENTITY(MAP762(m, __VA_ARGS__)) #define MAP764(m, x, ...) m(x) IDENTITY(MAP763(m, __VA_ARGS__)) #define MAP765(m, x, ...) m(x) IDENTITY(MAP764(m, __VA_ARGS__)) #define MAP766(m, x, ...) m(x) IDENTITY(MAP765(m, __VA_ARGS__)) #define MAP767(m, x, ...) m(x) IDENTITY(MAP766(m, __VA_ARGS__)) #define MAP768(m, x, ...) m(x) IDENTITY(MAP767(m, __VA_ARGS__)) #define EVALUATE_COUNT(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, \ _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, \ _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, \ _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, \ _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, \ _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, \ _121, _122, _123, _124, _125, _126, _127, _128, _129, _130, \ _131, _132, _133, _134, _135, _136, _137, _138, _139, _140, \ _141, _142, _143, _144, _145, _146, _147, _148, _149, _150, \ _151, _152, _153, _154, _155, _156, _157, _158, _159, _160, \ _161, _162, _163, _164, _165, _166, _167, _168, _169, _170, \ _171, _172, _173, _174, _175, _176, _177, _178, _179, _180, \ _181, _182, _183, _184, _185, _186, _187, _188, _189, _190, \ _191, _192, _193, _194, _195, _196, _197, _198, _199, _200, \ _201, _202, _203, _204, _205, _206, _207, _208, _209, _210, \ _211, _212, _213, _214, _215, _216, _217, _218, _219, _220, \ _221, _222, _223, _224, _225, _226, _227, _228, _229, _230, \ _231, _232, _233, _234, _235, _236, _237, _238, _239, _240, \ _241, _242, _243, _244, _245, _246, _247, _248, _249, _250, \ _251, _252, _253, _254, _255, _256, _257, _258, _259, _260, \ _261, _262, _263, _264, _265, _266, _267, _268, _269, _270, \ _271, _272, _273, _274, _275, _276, _277, _278, _279, _280, \ _281, _282, _283, _284, _285, _286, _287, _288, _289, _290, \ _291, _292, _293, _294, _295, _296, _297, _298, _299, _300, \ _301, _302, _303, _304, _305, _306, _307, _308, _309, _310, \ _311, _312, _313, _314, _315, _316, _317, _318, _319, _320, \ _321, _322, _323, _324, _325, _326, _327, _328, _329, _330, \ _331, _332, _333, _334, _335, _336, _337, _338, _339, _340, \ _341, _342, _343, _344, _345, _346, _347, _348, _349, _350, \ _351, _352, _353, _354, _355, _356, _357, _358, _359, _360, \ _361, _362, _363, _364, _365, _366, _367, _368, _369, _370, \ _371, _372, _373, _374, _375, _376, _377, _378, _379, _380, \ _381, _382, _383, _384, _385, _386, _387, _388, _389, _390, \ _391, _392, _393, _394, _395, _396, _397, _398, _399, _400, \ _401, _402, _403, _404, _405, _406, _407, _408, _409, _410, \ _411, _412, _413, _414, _415, _416, _417, _418, _419, _420, \ _421, _422, _423, _424, _425, _426, _427, _428, _429, _430, \ _431, _432, _433, _434, _435, _436, _437, _438, _439, _440, \ _441, _442, _443, _444, _445, _446, _447, _448, _449, _450, \ _451, _452, _453, _454, _455, _456, _457, _458, _459, _460, \ _461, _462, _463, _464, _465, _466, _467, _468, _469, _470, \ _471, _472, _473, _474, _475, _476, _477, _478, _479, _480, \ _481, _482, _483, _484, _485, _486, _487, _488, _489, _490, \ _491, _492, _493, _494, _495, _496, _497, _498, _499, _500, \ _501, _502, _503, _504, _505, _506, _507, _508, _509, _510, \ _511, _512, _513, _514, _515, _516, _517, _518, _519, _520, \ _521, _522, _523, _524, _525, _526, _527, _528, _529, _530, \ _531, _532, _533, _534, _535, _536, _537, _538, _539, _540, \ _541, _542, _543, _544, _545, _546, _547, _548, _549, _550, \ _551, _552, _553, _554, _555, _556, _557, _558, _559, _560, \ _561, _562, _563, _564, _565, _566, _567, _568, _569, _570, \ _571, _572, _573, _574, _575, _576, _577, _578, _579, _580, \ _581, _582, _583, _584, _585, _586, _587, _588, _589, _590, \ _591, _592, _593, _594, _595, _596, _597, _598, _599, _600, \ _601, _602, _603, _604, _605, _606, _607, _608, _609, _610, \ _611, _612, _613, _614, _615, _616, _617, _618, _619, _620, \ _621, _622, _623, _624, _625, _626, _627, _628, _629, _630, \ _631, _632, _633, _634, _635, _636, _637, _638, _639, _640, \ _641, _642, _643, _644, _645, _646, _647, _648, _649, _650, \ _651, _652, _653, _654, _655, _656, _657, _658, _659, _660, \ _661, _662, _663, _664, _665, _666, _667, _668, _669, _670, \ _671, _672, _673, _674, _675, _676, _677, _678, _679, _680, \ _681, _682, _683, _684, _685, _686, _687, _688, _689, _690, \ _691, _692, _693, _694, _695, _696, _697, _698, _699, _700, \ _701, _702, _703, _704, _705, _706, _707, _708, _709, _710, \ _711, _712, _713, _714, _715, _716, _717, _718, _719, _720, \ _721, _722, _723, _724, _725, _726, _727, _728, _729, _730, \ _731, _732, _733, _734, _735, _736, _737, _738, _739, _740, \ _741, _742, _743, _744, _745, _746, _747, _748, _749, _750, \ _751, _752, _753, _754, _755, _756, _757, _758, _759, _760, \ _761, _762, _763, _764, _765, _766, _767, _768, \ count, ...) count #define COUNT(...) \ IDENTITY(EVALUATE_COUNT(__VA_ARGS__, 768, 767, 766, 765, 764, 763, 762, 761, \ 760, 759, 758, 757, 756, 755, 754, 753, 752, 751, \ 750, 749, 748, 747, 746, 745, 744, 743, 742, 741, \ 740, 739, 738, 737, 736, 735, 734, 733, 732, 731, \ 730, 729, 728, 727, 726, 725, 724, 723, 722, 721, \ 720, 719, 718, 717, 716, 715, 714, 713, 712, 711, \ 710, 709, 708, 707, 706, 705, 704, 703, 702, 701, \ 700, 699, 698, 697, 696, 695, 694, 693, 692, 691, \ 690, 689, 688, 687, 686, 685, 684, 683, 682, 681, \ 680, 679, 678, 677, 676, 675, 674, 673, 672, 671, \ 670, 669, 668, 667, 666, 665, 664, 663, 662, 661, \ 660, 659, 658, 657, 656, 655, 654, 653, 652, 651, \ 650, 649, 648, 647, 646, 645, 644, 643, 642, 641, \ 640, 639, 638, 637, 636, 635, 634, 633, 632, 631, \ 630, 629, 628, 627, 626, 625, 624, 623, 622, 621, \ 620, 619, 618, 617, 616, 615, 614, 613, 612, 611, \ 610, 609, 608, 607, 606, 605, 604, 603, 602, 601, \ 600, 599, 598, 597, 596, 595, 594, 593, 592, 591, \ 590, 589, 588, 587, 586, 585, 584, 583, 582, 581, \ 580, 579, 578, 577, 576, 575, 574, 573, 572, 571, \ 570, 569, 568, 567, 566, 565, 564, 563, 562, 561, \ 560, 559, 558, 557, 556, 555, 554, 553, 552, 551, \ 550, 549, 548, 547, 546, 545, 544, 543, 542, 541, \ 540, 539, 538, 537, 536, 535, 534, 533, 532, 531, \ 530, 529, 528, 527, 526, 525, 524, 523, 522, 521, \ 520, 519, 518, 517, 516, 515, 514, 513, 512, 511, \ 510, 509, 508, 507, 506, 505, 504, 503, 502, 501, \ 500, 499, 498, 497, 496, 495, 494, 493, 492, 491, \ 490, 489, 488, 487, 486, 485, 484, 483, 482, 481, \ 480, 479, 478, 477, 476, 475, 474, 473, 472, 471, \ 470, 469, 468, 467, 466, 465, 464, 463, 462, 461, \ 460, 459, 458, 457, 456, 455, 454, 453, 452, 451, \ 450, 449, 448, 447, 446, 445, 444, 443, 442, 441, \ 440, 439, 438, 437, 436, 435, 434, 433, 432, 431, \ 430, 429, 428, 427, 426, 425, 424, 423, 422, 421, \ 420, 419, 418, 417, 416, 415, 414, 413, 412, 411, \ 410, 409, 408, 407, 406, 405, 404, 403, 402, 401, \ 400, 399, 398, 397, 396, 395, 394, 393, 392, 391, \ 390, 389, 388, 387, 386, 385, 384, 383, 382, 381, \ 380, 379, 378, 377, 376, 375, 374, 373, 372, 371, \ 370, 369, 368, 367, 366, 365, 364, 363, 362, 361, \ 360, 359, 358, 357, 356, 355, 354, 353, 352, 351, \ 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, \ 340, 339, 338, 337, 336, 335, 334, 333, 332, 331, \ 330, 329, 328, 327, 326, 325, 324, 323, 322, 321, \ 320, 319, 318, 317, 316, 315, 314, 313, 312, 311, \ 310, 309, 308, 307, 306, 305, 304, 303, 302, 301, \ 300, 299, 298, 297, 296, 295, 294, 293, 292, 291, \ 290, 289, 288, 287, 286, 285, 284, 283, 282, 281, \ 280, 279, 278, 277, 276, 275, 274, 273, 272, 271, \ 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, \ 260, 259, 258, 257, 256, 255, 254, 253, 252, 251, \ 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, \ 240, 239, 238, 237, 236, 235, 234, 233, 232, 231, \ 230, 229, 228, 227, 226, 225, 224, 223, 222, 221, \ 220, 219, 218, 217, 216, 215, 214, 213, 212, 211, \ 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, \ 200, 199, 198, 197, 196, 195, 194, 193, 192, 191, \ 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, \ 180, 179, 178, 177, 176, 175, 174, 173, 172, 171, \ 170, 169, 168, 167, 166, 165, 164, 163, 162, 161, \ 160, 159, 158, 157, 156, 155, 154, 153, 152, 151, \ 150, 149, 148, 147, 146, 145, 144, 143, 142, 141, \ 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, \ 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, \ 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, \ 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, \ 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, \ 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, \ 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, \ 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, \ 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, \ 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \ 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \ 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \ 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)) struct ignore_assign { ignore_assign(int value) : _value(value) { } operator int() const { return _value; } const ignore_assign& operator =(int dummy) { (void)dummy; return *this; } int _value; }; #define IGNORE_ASSIGN_SINGLE(expression) (ignore_assign)expression, #define IGNORE_ASSIGN(...) IDENTITY(MAP(IGNORE_ASSIGN_SINGLE, __VA_ARGS__)) #define STRINGIZE_SINGLE(expression) #expression, #define STRINGIZE(...) IDENTITY(MAP(STRINGIZE_SINGLE, __VA_ARGS__)) #define ENUM(EnumName, ...) \ struct EnumName { \ enum _enumerated { __VA_ARGS__ }; \ \ _enumerated _value; \ \ EnumName(_enumerated value) : _value(value) { } \ operator _enumerated() const { return _value; } \ \ const char* _to_string() const \ { \ for (size_t index = 0; index < _count; ++index) { \ if (_values()[index] == _value) \ return _names()[index]; \ } \ \ return NULL; \ } \ \ static const size_t _count = IDENTITY(COUNT(__VA_ARGS__)); \ \ static const int* _values() \ { \ static const int values[] = \ { IDENTITY(IGNORE_ASSIGN(__VA_ARGS__)) }; \ return values; \ } \ \ static const char* const* _names() \ { \ static const char* const raw_names[] = \ { IDENTITY(STRINGIZE(__VA_ARGS__)) }; \ \ static char* processed_names[_count]; \ static bool initialized = false; \ \ if (!initialized) { \ for (size_t index = 0; index < _count; ++index) { \ size_t length = \ std::strcspn(raw_names[index], " =\t\n\r"); \ \ processed_names[index] = new char[length + 1]; \ \ strncpy( \ processed_names[index], raw_names[index], length); \ processed_names[index][length] = '\0'; \ } \ } \ \ return processed_names; \ } \ }; /* !!! If you are adding new Enums for Events or Params * Please keep the existing Type_Event_XXX definition (and assign it a value) * and add your new definition such like Type_NewNotification = XX */ ENUM(ValueID_Index_Alarm, Type_Start = 0, Type_Smoke_Alarm = 1, Type_Carbon_Monoxide = 2, Type_Carbon_Dioxide = 3, Type_Heat = 4, Type_Water = 5, Type_Access_Control = 6, Type_Home_Security = 7, Type_Power_Management = 8, Type_System = 9, Type_Emergency = 10, Type_Clock = 11, Type_Appliance = 12, Type_Home_Health = 13, Type_Siren = 14, Type_Water_Valve = 15, Type_Weather = 16, Type_Irrigation = 17, Type_Gas = 18, Type_Event_19, Type_Event_20, Type_Event_21, Type_Event_22, Type_Event_23, Type_Event_24, Type_Event_25, Type_Event_26, Type_Event_27, Type_Event_28, Type_Event_29, Type_Event_30, Type_Event_31, Type_Event_32, Type_Event_33, Type_Event_34, Type_Event_35, Type_Event_36, Type_Event_37, Type_Event_38, Type_Event_39, Type_Event_40, Type_Event_41, Type_Event_42, Type_Event_43, Type_Event_44, Type_Event_45, Type_Event_46, Type_Event_47, Type_Event_48, Type_Event_49, Type_Event_50, Type_Event_51, Type_Event_52, Type_Event_53, Type_Event_54, Type_Event_55, Type_Event_56, Type_Event_57, Type_Event_58, Type_Event_59, Type_Event_60, Type_Event_61, Type_Event_62, Type_Event_63, Type_Event_64, Type_Event_65, Type_Event_66, Type_Event_67, Type_Event_68, Type_Event_69, Type_Event_70, Type_Event_71, Type_Event_72, Type_Event_73, Type_Event_74, Type_Event_75, Type_Event_76, Type_Event_77, Type_Event_78, Type_Event_79, Type_Event_80, Type_Event_81, Type_Event_82, Type_Event_83, Type_Event_84, Type_Event_85, Type_Event_86, Type_Event_87, Type_Event_88, Type_Event_89, Type_Event_90, Type_Event_91, Type_Event_92, Type_Event_93, Type_Event_94, Type_Event_95, Type_Event_96, Type_Event_97, Type_Event_98, Type_Event_99, Type_Event_100, Type_Event_101, Type_Event_102, Type_Event_103, Type_Event_104, Type_Event_105, Type_Event_106, Type_Event_107, Type_Event_108, Type_Event_109, Type_Event_110, Type_Event_111, Type_Event_112, Type_Event_113, Type_Event_114, Type_Event_115, Type_Event_116, Type_Event_117, Type_Event_118, Type_Event_119, Type_Event_120, Type_Event_121, Type_Event_122, Type_Event_123, Type_Event_124, Type_Event_125, Type_Event_126, Type_Event_127, Type_Event_128, Type_Event_129, Type_Event_130, Type_Event_131, Type_Event_132, Type_Event_133, Type_Event_134, Type_Event_135, Type_Event_136, Type_Event_137, Type_Event_138, Type_Event_139, Type_Event_140, Type_Event_141, Type_Event_142, Type_Event_143, Type_Event_144, Type_Event_145, Type_Event_146, Type_Event_147, Type_Event_148, Type_Event_149, Type_Event_150, Type_Event_151, Type_Event_152, Type_Event_153, Type_Event_154, Type_Event_155, Type_Event_156, Type_Event_157, Type_Event_158, Type_Event_159, Type_Event_160, Type_Event_161, Type_Event_162, Type_Event_163, Type_Event_164, Type_Event_165, Type_Event_166, Type_Event_167, Type_Event_168, Type_Event_169, Type_Event_170, Type_Event_171, Type_Event_172, Type_Event_173, Type_Event_174, Type_Event_175, Type_Event_176, Type_Event_177, Type_Event_178, Type_Event_179, Type_Event_180, Type_Event_181, Type_Event_182, Type_Event_183, Type_Event_184, Type_Event_185, Type_Event_186, Type_Event_187, Type_Event_188, Type_Event_189, Type_Event_190, Type_Event_191, Type_Event_192, Type_Event_193, Type_Event_194, Type_Event_195, Type_Event_196, Type_Event_197, Type_Event_198, Type_Event_199, Type_Event_200, Type_Event_201, Type_Event_202, Type_Event_203, Type_Event_204, Type_Event_205, Type_Event_206, Type_Event_207, Type_Event_208, Type_Event_209, Type_Event_210, Type_Event_211, Type_Event_212, Type_Event_213, Type_Event_214, Type_Event_215, Type_Event_216, Type_Event_217, Type_Event_218, Type_Event_219, Type_Event_220, Type_Event_221, Type_Event_222, Type_Event_223, Type_Event_224, Type_Event_225, Type_Event_226, Type_Event_227, Type_Event_228, Type_Event_229, Type_Event_230, Type_Event_231, Type_Event_232, Type_Event_233, Type_Event_234, Type_Event_235, Type_Event_236, Type_Event_237, Type_Event_238, Type_Event_239, Type_Event_240, Type_Event_241, Type_Event_242, Type_Event_243, Type_Event_244, Type_Event_245, Type_Event_246, Type_Event_247, Type_Event_248, Type_Event_249, Type_Event_250, Type_Event_251, Type_Event_252, Type_Event_253, Type_Event_254, Type_Event_255, Type_Event_Param_Previous_Event = 256, Type_Event_Param_Location = 257, Type_Event_Param_Result = 258, Type_Event_Param_Threshold = 259, Type_Event_Param_UserCode = 260, Type_Event_Param_261 = 261, Type_Event_Param_Progress = 262, Type_Event_Param_Mode = 263, Type_Event_Param_Obstruction = 264, Type_Event_Param_Sensor_ID = 265, Type_Event_Param_Error_Code = 266, Type_Event_Param_Duration = 267, Type_Event_Param_Pollution_Level = 268, Type_Event_Param_Status = 269, Type_Event_Param_Schedule_ID = 270, Type_Event_Param_Valve_Table_ID = 271, Type_Event_Param_272, Type_Event_Param_273, Type_Event_Param_274, Type_Event_Param_275, Type_Event_Param_276, Type_Event_Param_277, Type_Event_Param_278, Type_Event_Param_279, Type_Event_Param_280, Type_Event_Param_281, Type_Event_Param_282, Type_Event_Param_283, Type_Event_Param_284, Type_Event_Param_285, Type_Event_Param_286, Type_Event_Param_287, Type_Event_Param_288, Type_Event_Param_289, Type_Event_Param_290, Type_Event_Param_291, Type_Event_Param_292, Type_Event_Param_293, Type_Event_Param_294, Type_Event_Param_295, Type_Event_Param_296, Type_Event_Param_297, Type_Event_Param_298, Type_Event_Param_299, Type_Event_Param_300, Type_Event_Param_301, Type_Event_Param_302, Type_Event_Param_303, Type_Event_Param_304, Type_Event_Param_305, Type_Event_Param_306, Type_Event_Param_307, Type_Event_Param_308, Type_Event_Param_309, Type_Event_Param_310, Type_Event_Param_311, Type_Event_Param_312, Type_Event_Param_313, Type_Event_Param_314, Type_Event_Param_315, Type_Event_Param_316, Type_Event_Param_317, Type_Event_Param_318, Type_Event_Param_319, Type_Event_Param_320, Type_Event_Param_321, Type_Event_Param_322, Type_Event_Param_323, Type_Event_Param_324, Type_Event_Param_325, Type_Event_Param_326, Type_Event_Param_327, Type_Event_Param_328, Type_Event_Param_329, Type_Event_Param_330, Type_Event_Param_331, Type_Event_Param_332, Type_Event_Param_333, Type_Event_Param_334, Type_Event_Param_335, Type_Event_Param_336, Type_Event_Param_337, Type_Event_Param_338, Type_Event_Param_339, Type_Event_Param_340, Type_Event_Param_341, Type_Event_Param_342, Type_Event_Param_343, Type_Event_Param_344, Type_Event_Param_345, Type_Event_Param_346, Type_Event_Param_347, Type_Event_Param_348, Type_Event_Param_349, Type_Event_Param_350, Type_Event_Param_351, Type_Event_Param_352, Type_Event_Param_353, Type_Event_Param_354, Type_Event_Param_355, Type_Event_Param_356, Type_Event_Param_357, Type_Event_Param_358, Type_Event_Param_359, Type_Event_Param_360, Type_Event_Param_361, Type_Event_Param_362, Type_Event_Param_363, Type_Event_Param_364, Type_Event_Param_365, Type_Event_Param_366, Type_Event_Param_367, Type_Event_Param_368, Type_Event_Param_369, Type_Event_Param_370, Type_Event_Param_371, Type_Event_Param_372, Type_Event_Param_373, Type_Event_Param_374, Type_Event_Param_375, Type_Event_Param_376, Type_Event_Param_377, Type_Event_Param_378, Type_Event_Param_379, Type_Event_Param_380, Type_Event_Param_381, Type_Event_Param_382, Type_Event_Param_383, Type_Event_Param_384, Type_Event_Param_385, Type_Event_Param_386, Type_Event_Param_387, Type_Event_Param_388, Type_Event_Param_389, Type_Event_Param_390, Type_Event_Param_391, Type_Event_Param_392, Type_Event_Param_393, Type_Event_Param_394, Type_Event_Param_395, Type_Event_Param_396, Type_Event_Param_397, Type_Event_Param_398, Type_Event_Param_399, Type_Event_Param_400, Type_Event_Param_401, Type_Event_Param_402, Type_Event_Param_403, Type_Event_Param_404, Type_Event_Param_405, Type_Event_Param_406, Type_Event_Param_407, Type_Event_Param_408, Type_Event_Param_409, Type_Event_Param_410, Type_Event_Param_411, Type_Event_Param_412, Type_Event_Param_413, Type_Event_Param_414, Type_Event_Param_415, Type_Event_Param_416, Type_Event_Param_417, Type_Event_Param_418, Type_Event_Param_419, Type_Event_Param_420, Type_Event_Param_421, Type_Event_Param_422, Type_Event_Param_423, Type_Event_Param_424, Type_Event_Param_425, Type_Event_Param_426, Type_Event_Param_427, Type_Event_Param_428, Type_Event_Param_429, Type_Event_Param_430, Type_Event_Param_431, Type_Event_Param_432, Type_Event_Param_433, Type_Event_Param_434, Type_Event_Param_435, Type_Event_Param_436, Type_Event_Param_437, Type_Event_Param_438, Type_Event_Param_439, Type_Event_Param_440, Type_Event_Param_441, Type_Event_Param_442, Type_Event_Param_443, Type_Event_Param_444, Type_Event_Param_445, Type_Event_Param_446, Type_Event_Param_447, Type_Event_Param_448, Type_Event_Param_449, Type_Event_Param_450, Type_Event_Param_451, Type_Event_Param_452, Type_Event_Param_453, Type_Event_Param_454, Type_Event_Param_455, Type_Event_Param_456, Type_Event_Param_457, Type_Event_Param_458, Type_Event_Param_459, Type_Event_Param_460, Type_Event_Param_461, Type_Event_Param_462, Type_Event_Param_463, Type_Event_Param_464, Type_Event_Param_465, Type_Event_Param_466, Type_Event_Param_467, Type_Event_Param_468, Type_Event_Param_469, Type_Event_Param_470, Type_Event_Param_471, Type_Event_Param_472, Type_Event_Param_473, Type_Event_Param_474, Type_Event_Param_475, Type_Event_Param_476, Type_Event_Param_477, Type_Event_Param_478, Type_Event_Param_479, Type_Event_Param_480, Type_Event_Param_481, Type_Event_Param_482, Type_Event_Param_483, Type_Event_Param_484, Type_Event_Param_485, Type_Event_Param_486, Type_Event_Param_487, Type_Event_Param_488, Type_Event_Param_489, Type_Event_Param_490, Type_Event_Param_491, Type_Event_Param_492, Type_Event_Param_493, Type_Event_Param_494, Type_Event_Param_495, Type_Event_Param_496, Type_Event_Param_497, Type_Event_Param_498, Type_Event_Param_499, Type_Event_Param_500, Type_Event_Param_501, Type_Event_Param_502, Type_Event_Param_503, Type_Event_Param_504, Type_Event_Param_505, Type_Event_Param_506, Type_Event_Param_507, Type_Event_Param_508, Type_Event_Param_509, Type_Event_Param_510, Type_Event_Param_511, Type_v1 = 512, Level_v1 = 513, AutoClearEvents = 514 ); ENUM(ValueID_Index_AssociationCommandConfiguration, MaxCommandLength = 0, CommandsAreValues = 1, CommandsAreConfigurable = 2, NumFreeCommands = 3, MaxCommands = 4 ); ENUM(ValueID_Index_BarrierOperator, Command = 0, Label = 1, SupportedSignals = 2, Audible = 3, Visual = 4 ); ENUM(ValueID_Index_Basic, Set = 0, Target = 1, Duration = 2 ); ENUM(ValueID_Index_BasicWindowCovering, Open = 0, Close = 1 ); ENUM(ValueID_Index_Battery, Level = 0 ); ENUM(ValueID_Index_CentralScene, Scene_1 = 1, Scene_2, Scene_3, Scene_4, Scene_5, Scene_6, Scene_7, Scene_8, Scene_9, Scene_10, Scene_11, Scene_12, Scene_13, Scene_14, Scene_15, Scene_16, Scene_17, Scene_18, Scene_19, Scene_20, Scene_21, Scene_22, Scene_23, Scene_24, Scene_25, Scene_26, Scene_27, Scene_28, Scene_29, Scene_30, Scene_31, Scene_32, Scene_33, Scene_34, Scene_35, Scene_36, Scene_37, Scene_38, Scene_39, Scene_40, Scene_41, Scene_42, Scene_43, Scene_44, Scene_45, Scene_46, Scene_47, Scene_48, Scene_49, Scene_50, Scene_51, Scene_52, Scene_53, Scene_54, Scene_55, Scene_56, Scene_57, Scene_58, Scene_59, Scene_60, Scene_61, Scene_62, Scene_63, Scene_64, Scene_65, Scene_66, Scene_67, Scene_68, Scene_69, Scene_70, Scene_71, Scene_72, Scene_73, Scene_74, Scene_75, Scene_76, Scene_77, Scene_78, Scene_79, Scene_80, Scene_81, Scene_82, Scene_83, Scene_84, Scene_85, Scene_86, Scene_87, Scene_88, Scene_89, Scene_90, Scene_91, Scene_92, Scene_93, Scene_94, Scene_95, Scene_96, Scene_97, Scene_98, Scene_99, Scene_100, Scene_101, Scene_102, Scene_103, Scene_104, Scene_105, Scene_106, Scene_107, Scene_108, Scene_109, Scene_110, Scene_111, Scene_112, Scene_113, Scene_114, Scene_115, Scene_116, Scene_117, Scene_118, Scene_119, Scene_120, Scene_121, Scene_122, Scene_123, Scene_124, Scene_125, Scene_126, Scene_127, Scene_128, Scene_129, Scene_130, Scene_131, Scene_132, Scene_133, Scene_134, Scene_135, Scene_136, Scene_137, Scene_138, Scene_139, Scene_140, Scene_141, Scene_142, Scene_143, Scene_144, Scene_145, Scene_146, Scene_147, Scene_148, Scene_149, Scene_150, Scene_151, Scene_152, Scene_153, Scene_154, Scene_155, Scene_156, Scene_157, Scene_158, Scene_159, Scene_160, Scene_161, Scene_162, Scene_163, Scene_164, Scene_165, Scene_166, Scene_167, Scene_168, Scene_169, Scene_170, Scene_171, Scene_172, Scene_173, Scene_174, Scene_175, Scene_176, Scene_177, Scene_178, Scene_179, Scene_180, Scene_181, Scene_182, Scene_183, Scene_184, Scene_185, Scene_186, Scene_187, Scene_188, Scene_189, Scene_190, Scene_191, Scene_192, Scene_193, Scene_194, Scene_195, Scene_196, Scene_197, Scene_198, Scene_199, Scene_200, Scene_201, Scene_202, Scene_203, Scene_204, Scene_205, Scene_206, Scene_207, Scene_208, Scene_209, Scene_210, Scene_211, Scene_212, Scene_213, Scene_214, Scene_215, Scene_216, Scene_217, Scene_218, Scene_219, Scene_220, Scene_221, Scene_222, Scene_223, Scene_224, Scene_225, Scene_226, Scene_227, Scene_228, Scene_229, Scene_230, Scene_231, Scene_232, Scene_233, Scene_234, Scene_235, Scene_236, Scene_237, Scene_238, Scene_239, Scene_240, Scene_241, Scene_242, Scene_243, Scene_244, Scene_245, Scene_246, Scene_247, Scene_248, Scene_249, Scene_250, Scene_251, Scene_252, Scene_253, Scene_254, Scene_255, SceneCount = 256, ClearSceneTimeout = 257 ); ENUM(ValueID_Index_ClimateControlSchedule, DOW_Monday = 1, DOW_Tuesday = 2, DOW_Wednesday = 3, DOW_Thursday = 4, DOW_Friday = 5, DOW_Saturday = 6, DOW_Sunday = 7, OverrideState = 8, OverrideSetback = 9 ); ENUM(ValueID_Index_Clock, Day = 0, Hour = 1, Minute = 2 ); ENUM(ValueID_Index_Color, Color = 0, Index = 1, Channels_Capabilities = 2, Duration = 4, Target = 5 ); ENUM(ValueID_Index_Configuration, Parameter_1 = 1, Parameter_2, Parameter_3, Parameter_4, Parameter_5, Parameter_6, Parameter_7, Parameter_8, Parameter_9, Parameter_10, Parameter_11, Parameter_12, Parameter_13, Parameter_14, Parameter_15, Parameter_16, Parameter_17, Parameter_18, Parameter_19, Parameter_20, Parameter_21, Parameter_22, Parameter_23, Parameter_24, Parameter_25, Parameter_26, Parameter_27, Parameter_28, Parameter_29, Parameter_30, Parameter_31, Parameter_32, Parameter_33, Parameter_34, Parameter_35, Parameter_36, Parameter_37, Parameter_38, Parameter_39, Parameter_40, Parameter_41, Parameter_42, Parameter_43, Parameter_44, Parameter_45, Parameter_46, Parameter_47, Parameter_48, Parameter_49, Parameter_50, Parameter_51, Parameter_52, Parameter_53, Parameter_54, Parameter_55, Parameter_56, Parameter_57, Parameter_58, Parameter_59, Parameter_60, Parameter_61, Parameter_62, Parameter_63, Parameter_64, Parameter_65, Parameter_66, Parameter_67, Parameter_68, Parameter_69, Parameter_70, Parameter_71, Parameter_72, Parameter_73, Parameter_74, Parameter_75, Parameter_76, Parameter_77, Parameter_78, Parameter_79, Parameter_80, Parameter_81, Parameter_82, Parameter_83, Parameter_84, Parameter_85, Parameter_86, Parameter_87, Parameter_88, Parameter_89, Parameter_90, Parameter_91, Parameter_92, Parameter_93, Parameter_94, Parameter_95, Parameter_96, Parameter_97, Parameter_98, Parameter_99, Parameter_100, Parameter_101, Parameter_102, Parameter_103, Parameter_104, Parameter_105, Parameter_106, Parameter_107, Parameter_108, Parameter_109, Parameter_110, Parameter_111, Parameter_112, Parameter_113, Parameter_114, Parameter_115, Parameter_116, Parameter_117, Parameter_118, Parameter_119, Parameter_120, Parameter_121, Parameter_122, Parameter_123, Parameter_124, Parameter_125, Parameter_126, Parameter_127, Parameter_128, Parameter_129, Parameter_130, Parameter_131, Parameter_132, Parameter_133, Parameter_134, Parameter_135, Parameter_136, Parameter_137, Parameter_138, Parameter_139, Parameter_140, Parameter_141, Parameter_142, Parameter_143, Parameter_144, Parameter_145, Parameter_146, Parameter_147, Parameter_148, Parameter_149, Parameter_150, Parameter_151, Parameter_152, Parameter_153, Parameter_154, Parameter_155, Parameter_156, Parameter_157, Parameter_158, Parameter_159, Parameter_160, Parameter_161, Parameter_162, Parameter_163, Parameter_164, Parameter_165, Parameter_166, Parameter_167, Parameter_168, Parameter_169, Parameter_170, Parameter_171, Parameter_172, Parameter_173, Parameter_174, Parameter_175, Parameter_176, Parameter_177, Parameter_178, Parameter_179, Parameter_180, Parameter_181, Parameter_182, Parameter_183, Parameter_184, Parameter_185, Parameter_186, Parameter_187, Parameter_188, Parameter_189, Parameter_190, Parameter_191, Parameter_192, Parameter_193, Parameter_194, Parameter_195, Parameter_196, Parameter_197, Parameter_198, Parameter_199, Parameter_200, Parameter_201, Parameter_202, Parameter_203, Parameter_204, Parameter_205, Parameter_206, Parameter_207, Parameter_208, Parameter_209, Parameter_210, Parameter_211, Parameter_212, Parameter_213, Parameter_214, Parameter_215, Parameter_216, Parameter_217, Parameter_218, Parameter_219, Parameter_220, Parameter_221, Parameter_222, Parameter_223, Parameter_224, Parameter_225, Parameter_226, Parameter_227, Parameter_228, Parameter_229, Parameter_230, Parameter_231, Parameter_232, Parameter_233, Parameter_234, Parameter_235, Parameter_236, Parameter_237, Parameter_238, Parameter_239, Parameter_240, Parameter_241, Parameter_242, Parameter_243, Parameter_244, Parameter_245, Parameter_246, Parameter_247, Parameter_248, Parameter_249, Parameter_250, Parameter_251, Parameter_252, Parameter_253, Parameter_254, Parameter_255 ); ENUM(ValueID_Index_ControllerReplication, NodeId = 0, Function = 1, Replicate = 2 ); ENUM(ValueID_Index_DoorLock, Lock = 0, Lock_Mode = 1, System_Config_Mode = 2, System_Config_Minutes = 3, System_Config_Seconds = 4, System_Config_OutsideHandles = 5, System_Config_InsideHandles = 6 ); ENUM(ValueID_Index_DoorLockLogging, System_Config_MaxRecords = 0, GetRecordNo = 1, LogRecord = 2 ); ENUM(ValueID_Index_EnergyProduction, Instant = 0, Total = 1, Today = 2, Time = 3 ); ENUM(ValueID_Index_Indicator, Indicator = 0, Armed = 1, Not_Armed, Ready, Fault, Busy, Enter_ID, Enter_PIN, Code_Accepted, Code_Not_Accepted, Armed_Stay, Armed_Away, Alarming, Alarming_Burglar, Alarming_Smoke_Fire, Alarming_Carbon_Monoxide, Bypass_Challenge, Entry_Delay, Exit_Delay, Alarming_Medical, Alarming_Freeze_Warning, Alarming_Water_Leak, Alarming_Panic, Zone_1_Armed = 0x20, Zone_2_Armed, Zone_3_Armed, Zone_4_Armed, Zone_5_Armed, Zone_6_Armed, Zone_7_Armed, Zone_8_Armed, LCD_Backlight = 0x30, Button_Backlight_Letters = 0x40, Button_Backlight_Digits, Button_Backlight_Command, Button_1_Indication, Button_2_Indication, Button_3_Indication, Button_4_Indication, Button_5_Indication, Button_6_Indication, Button_7_Indication, Button_8_Indication, Button_9_Indication, Button_10_Indication, Button_11_Indication, Button_12_Indication, Node_Identify = 0x50, Generic_Event_Sound_Notification_1 = 0x60, Generic_Event_Sound_Notification_2, Generic_Event_Sound_Notification_3, Generic_Event_Sound_Notification_4, Generic_Event_Sound_Notification_5, Generic_Event_Sound_Notification_6, Generic_Event_Sound_Notification_7, Generic_Event_Sound_Notification_8, Generic_Event_Sound_Notification_9, Generic_Event_Sound_Notification_10, Generic_Event_Sound_Notification_11, Generic_Event_Sound_Notification_12, Generic_Event_Sound_Notification_13, Generic_Event_Sound_Notification_14, Generic_Event_Sound_Notification_15, Generic_Event_Sound_Notification_16, Generic_Event_Sound_Notification_17, Generic_Event_Sound_Notification_18, Generic_Event_Sound_Notification_19, Generic_Event_Sound_Notification_20, Generic_Event_Sound_Notification_21, Generic_Event_Sound_Notification_22, Generic_Event_Sound_Notification_23, Generic_Event_Sound_Notification_24, Generic_Event_Sound_Notification_25, Generic_Event_Sound_Notification_26, Generic_Event_Sound_Notification_27, Generic_Event_Sound_Notification_28, Generic_Event_Sound_Notification_29, Generic_Event_Sound_Notification_30, Generic_Event_Sound_Notification_31, Generic_Event_Sound_Notification_32, Manufacturer_Defined_Indicator_1 = 0x80, Manufacturer_Defined_Indicator_2, Manufacturer_Defined_Indicator_3, Manufacturer_Defined_Indicator_4, Manufacturer_Defined_Indicator_5, Manufacturer_Defined_Indicator_6, Manufacturer_Defined_Indicator_7, Manufacturer_Defined_Indicator_8, Manufacturer_Defined_Indicator_9, Manufacturer_Defined_Indicator_10, Manufacturer_Defined_Indicator_11, Manufacturer_Defined_Indicator_12, Manufacturer_Defined_Indicator_13, Manufacturer_Defined_Indicator_14, Manufacturer_Defined_Indicator_15, Manufacturer_Defined_Indicator_16, Manufacturer_Defined_Indicator_17, Manufacturer_Defined_Indicator_18, Manufacturer_Defined_Indicator_19, Manufacturer_Defined_Indicator_20, Manufacturer_Defined_Indicator_21, Manufacturer_Defined_Indicator_22, Manufacturer_Defined_Indicator_23, Manufacturer_Defined_Indicator_24, Manufacturer_Defined_Indicator_25, Manufacturer_Defined_Indicator_26, Manufacturer_Defined_Indicator_27, Manufacturer_Defined_Indicator_28, Manufacturer_Defined_Indicator_29, Manufacturer_Defined_Indicator_30, Manufacturer_Defined_Indicator_31, Manufacturer_Defined_Indicator_32, Buzzer = 0xF0 ); ENUM(ValueID_Index_Language, Language = 0, Country = 1 ); ENUM(ValueID_Index_Lock, Locked = 0 ); ENUM(ValueID_Index_ManufacturerProprietary, FibaroVenetianBlinds_Blinds = 0, FibaroVenetianBlinds_Tilt = 1 ); ENUM(ValueID_Index_ManufacturerSpecific, LoadedConfig = 0, LocalConfig = 1, LatestConfig = 2, DeviceID = 3, SerialNumber = 4 ); ENUM(ValueID_Index_Meter, Electric_kWh = 0, Electric_kVah, Electric_W, Electric_Pulse, Electric_V, Electric_A, Electric_PowerFactor, Electric_Unknown_1, Electric_kVar, Electric_kVarh, Electric_Unknown_2, Electric_Unknown_3, Electric_Unknown_4, Electric_Unknown_5, Electric_Unknown_6, Electric_Unknown_7, Gas_Cubic_Meters, Gas_Cubic_Feet, Gas_Unknown_1, Gas_Pulse, Gas_Unknown_2, Gas_Unknown_3, Gas_Unknown_4, Gas_Unknown_5, Gas_Unknown_6, Gas_Unknown_7, Gas_Unknown_8, Gas_Unknown_9, Gas_Unknown_10, Gas_Unknown_11, Gas_Unknown_12, Gas_Unknown_13, Water_Cubic_Meters, Water_Cubic_Feet, Water_Cubic_US_Gallons, Water_Cubic_Pulse, Water_Unknown_1, Water_Unknown_2, Water_Unknown_3, Water_Unknown_4, Water_Unknown_5, Water_Unknown_6, Water_Unknown_7, Water_Unknown_8, Water_Unknown_9, Water_Unknown_10, Water_Unknown_11, Water_Unknown_12, Heating_kWh, Heating_Unknown_1, Heating_Unknown_2, Heating_Unknown_3, Heating_Unknown_4, Heating_Unknown_5, Heating_Unknown_6, Heating_Unknown_7, Heating_Unknown_8, Heating_Unknown_9, Heating_Unknown_10, Heating_Unknown_11, Heating_Unknown_12, Heating_Unknown_13, Heating_Unknown_14, Heating_Unknown_15, Cooling_kWh, Cooling_Unknown_1, Cooling_Unknown_2, Cooling_Unknown_3, Cooling_Unknown_4, Cooling_Unknown_5, Cooling_Unknown_6, Cooling_Unknown_7, Cooling_Unknown_8, Cooling_Unknown_9, Cooling_Unknown_10, Cooling_Unknown_11, Cooling_Unknown_12, Cooling_Unknown_13, Cooling_Unknown_14, Cooling_Unknown_15, Exporting = 256, Reset = 257 ); ENUM(ValueID_Index_MeterPulse, Count = 0 ); ENUM(ValueID_Index_PowerLevel, Powerlevel = 0, Timeout = 1, Set = 2, TestNode = 3, TestPowerlevel = 4, TestFrames = 5, Test = 6, Report = 7, TestStatus = 8, TestAckFrames = 9 ); ENUM(ValueID_Index_Protection, Protection = 0 ); ENUM(ValueID_Index_SceneActivation, SceneID = 0, Duration = 1 ); ENUM(ValueID_Index_Security, Secured = 0 ); ENUM(ValueID_Index_SensorAlarm, Sensor_1, Sensor_2, Sensor_3, Sensor_4, Sensor_5, Sensor_6, Sensor_7, Sensor_8, Sensor_9, Sensor_10, Sensor_11, Sensor_12, Sensor_13, Sensor_14, Sensor_15, Sensor_16, Sensor_17, Sensor_18, Sensor_19, Sensor_20, Sensor_21, Sensor_22, Sensor_23, Sensor_24, Sensor_25, Sensor_26, Sensor_27, Sensor_28, Sensor_29, Sensor_30, Sensor_31, Sensor_32, Sensor_33, Sensor_34, Sensor_35, Sensor_36, Sensor_37, Sensor_38, Sensor_39, Sensor_40, Sensor_41, Sensor_42, Sensor_43, Sensor_44, Sensor_45, Sensor_46, Sensor_47, Sensor_48, Sensor_49, Sensor_50, Sensor_51, Sensor_52, Sensor_53, Sensor_54, Sensor_55, Sensor_56, Sensor_57, Sensor_58, Sensor_59, Sensor_60, Sensor_61, Sensor_62, Sensor_63, Sensor_64, Sensor_65, Sensor_66, Sensor_67, Sensor_68, Sensor_69, Sensor_70, Sensor_71, Sensor_72, Sensor_73, Sensor_74, Sensor_75, Sensor_76, Sensor_77, Sensor_78, Sensor_79, Sensor_80, Sensor_81, Sensor_82, Sensor_83, Sensor_84, Sensor_85, Sensor_86, Sensor_87, Sensor_88, Sensor_89, Sensor_90, Sensor_91, Sensor_92, Sensor_93, Sensor_94, Sensor_95, Sensor_96, Sensor_97, Sensor_98, Sensor_99, Sensor_100, Sensor_101, Sensor_102, Sensor_103, Sensor_104, Sensor_105, Sensor_106, Sensor_107, Sensor_108, Sensor_109, Sensor_110, Sensor_111, Sensor_112, Sensor_113, Sensor_114, Sensor_115, Sensor_116, Sensor_117, Sensor_118, Sensor_119, Sensor_120, Sensor_121, Sensor_122, Sensor_123, Sensor_124, Sensor_125, Sensor_126, Sensor_127, Sensor_128, Sensor_129, Sensor_130, Sensor_131, Sensor_132, Sensor_133, Sensor_134, Sensor_135, Sensor_136, Sensor_137, Sensor_138, Sensor_139, Sensor_140, Sensor_141, Sensor_142, Sensor_143, Sensor_144, Sensor_145, Sensor_146, Sensor_147, Sensor_148, Sensor_149, Sensor_150, Sensor_151, Sensor_152, Sensor_153, Sensor_154, Sensor_155, Sensor_156, Sensor_157, Sensor_158, Sensor_159, Sensor_160, Sensor_161, Sensor_162, Sensor_163, Sensor_164, Sensor_165, Sensor_166, Sensor_167, Sensor_168, Sensor_169, Sensor_170, Sensor_171, Sensor_172, Sensor_173, Sensor_174, Sensor_175, Sensor_176, Sensor_177, Sensor_178, Sensor_179, Sensor_180, Sensor_181, Sensor_182, Sensor_183, Sensor_184, Sensor_185, Sensor_186, Sensor_187, Sensor_188, Sensor_189, Sensor_190, Sensor_191, Sensor_192, Sensor_193, Sensor_194, Sensor_195, Sensor_196, Sensor_197, Sensor_198, Sensor_199, Sensor_200, Sensor_201, Sensor_202, Sensor_203, Sensor_204, Sensor_205, Sensor_206, Sensor_207, Sensor_208, Sensor_209, Sensor_210, Sensor_211, Sensor_212, Sensor_213, Sensor_214, Sensor_215, Sensor_216, Sensor_217, Sensor_218, Sensor_219, Sensor_220, Sensor_221, Sensor_222, Sensor_223, Sensor_224, Sensor_225, Sensor_226, Sensor_227, Sensor_228, Sensor_229, Sensor_230, Sensor_231, Sensor_232, Sensor_233, Sensor_234, Sensor_235, Sensor_236, Sensor_237, Sensor_238, Sensor_239, Sensor_240, Sensor_241, Sensor_242, Sensor_243, Sensor_244, Sensor_245, Sensor_246, Sensor_247, Sensor_248, Sensor_249, Sensor_250, Sensor_251, Sensor_252, Sensor_253, Sensor_254, Sensor_255 ); ENUM(ValueID_Index_SensorBinary, Sensor_1, Sensor_2, Sensor_3, Sensor_4, Sensor_5, Sensor_6, Sensor_7, Sensor_8, Sensor_9, Sensor_10, Sensor_11, Sensor_12, Sensor_13, Sensor_14, Sensor_15, Sensor_16, Sensor_17, Sensor_18, Sensor_19, Sensor_20, Sensor_21, Sensor_22, Sensor_23, Sensor_24, Sensor_25, Sensor_26, Sensor_27, Sensor_28, Sensor_29, Sensor_30, Sensor_31, Sensor_32, Sensor_33, Sensor_34, Sensor_35, Sensor_36, Sensor_37, Sensor_38, Sensor_39, Sensor_40, Sensor_41, Sensor_42, Sensor_43, Sensor_44, Sensor_45, Sensor_46, Sensor_47, Sensor_48, Sensor_49, Sensor_50, Sensor_51, Sensor_52, Sensor_53, Sensor_54, Sensor_55, Sensor_56, Sensor_57, Sensor_58, Sensor_59, Sensor_60, Sensor_61, Sensor_62, Sensor_63, Sensor_64, Sensor_65, Sensor_66, Sensor_67, Sensor_68, Sensor_69, Sensor_70, Sensor_71, Sensor_72, Sensor_73, Sensor_74, Sensor_75, Sensor_76, Sensor_77, Sensor_78, Sensor_79, Sensor_80, Sensor_81, Sensor_82, Sensor_83, Sensor_84, Sensor_85, Sensor_86, Sensor_87, Sensor_88, Sensor_89, Sensor_90, Sensor_91, Sensor_92, Sensor_93, Sensor_94, Sensor_95, Sensor_96, Sensor_97, Sensor_98, Sensor_99, Sensor_100, Sensor_101, Sensor_102, Sensor_103, Sensor_104, Sensor_105, Sensor_106, Sensor_107, Sensor_108, Sensor_109, Sensor_110, Sensor_111, Sensor_112, Sensor_113, Sensor_114, Sensor_115, Sensor_116, Sensor_117, Sensor_118, Sensor_119, Sensor_120, Sensor_121, Sensor_122, Sensor_123, Sensor_124, Sensor_125, Sensor_126, Sensor_127, Sensor_128, Sensor_129, Sensor_130, Sensor_131, Sensor_132, Sensor_133, Sensor_134, Sensor_135, Sensor_136, Sensor_137, Sensor_138, Sensor_139, Sensor_140, Sensor_141, Sensor_142, Sensor_143, Sensor_144, Sensor_145, Sensor_146, Sensor_147, Sensor_148, Sensor_149, Sensor_150, Sensor_151, Sensor_152, Sensor_153, Sensor_154, Sensor_155, Sensor_156, Sensor_157, Sensor_158, Sensor_159, Sensor_160, Sensor_161, Sensor_162, Sensor_163, Sensor_164, Sensor_165, Sensor_166, Sensor_167, Sensor_168, Sensor_169, Sensor_170, Sensor_171, Sensor_172, Sensor_173, Sensor_174, Sensor_175, Sensor_176, Sensor_177, Sensor_178, Sensor_179, Sensor_180, Sensor_181, Sensor_182, Sensor_183, Sensor_184, Sensor_185, Sensor_186, Sensor_187, Sensor_188, Sensor_189, Sensor_190, Sensor_191, Sensor_192, Sensor_193, Sensor_194, Sensor_195, Sensor_196, Sensor_197, Sensor_198, Sensor_199, Sensor_200, Sensor_201, Sensor_202, Sensor_203, Sensor_204, Sensor_205, Sensor_206, Sensor_207, Sensor_208, Sensor_209, Sensor_210, Sensor_211, Sensor_212, Sensor_213, Sensor_214, Sensor_215, Sensor_216, Sensor_217, Sensor_218, Sensor_219, Sensor_220, Sensor_221, Sensor_222, Sensor_223, Sensor_224, Sensor_225, Sensor_226, Sensor_227, Sensor_228, Sensor_229, Sensor_230, Sensor_231, Sensor_232, Sensor_233, Sensor_234, Sensor_235, Sensor_236, Sensor_237, Sensor_238, Sensor_239, Sensor_240, Sensor_241, Sensor_242, Sensor_243, Sensor_244, Sensor_245, Sensor_246, Sensor_247, Sensor_248, Sensor_249, Sensor_250, Sensor_251, Sensor_252, Sensor_253, Sensor_254, Sensor_255 ); ENUM(ValueID_Index_SensorMultiLevel, Air_Temperature = 1, General_Purpose, Luminance, Power, Humidity, Velocity, Direction, Atmospheric_Pressure, Barometric_Pressure, Solar_Radiation, Dew_Point, Rain_Rate, Tide_Level, Weight, Voltage, Current, Carbon_Dioxide, Air_Flow, Tank_Capacity, Distance, Angle_Position, Rotation, Water_Temperature, Soil_Temperature, Seismic_Intensity, Seismic_Magnitude, Ultraviolet, Electrical_Resistivity, Electrical_Conductivity, Loudness, Moisture, Frequency, Time, Target_Temperature, Particulate_Mater_2_5, Formaldehyde_CH20_Level, Radon_Concentration, Methane_Density, Volatile_Organic_Compound, Carbon_Monoxide, Soil_Humidity, Soil_Reactivity, Soil_Salinity, Heart_Beat, Blood_Pressure, Muscle_Mass, Fat_Mass, Bone_Mass, Total_Body_Water, Basic_Metabolic_Rate, Body_Mass_Index, X_Axis_Acceleration, Y_Axis_Acceleration, Z_Axis_Acceleration, Smoke_Density, Water_Flow, Water_Pressure, RF_Signal_Strength, Particulate_Matter, Respiratory_Rate, Relative_Modulation, Boiler_Water_Temperature, Domestic_Hot_Water_Temperature, Outside_Temperature, Exhaust_Temperature, Water_Chlorine, Water_Acidity, Water_Oxidation_Reduction_Potential, Heart_Rate_LF_HF_Ratio, Motion_Direction, Applied_Force, Return_Air_Temperature, Supply_Air_Temperature, Condenser_Coil_Temperature, Evaporator_Coil_Temperature, Liquid_Line_Temperature, Discharge_Line_Temperature, Suction, Discharge, Defrost_Temperature, Ozone, Sulfur_Dioxide, Nitrogen_Dioxide, Ammonia, Lead, Particulate_Matter_v2, Air_Temperature_Units = 256, General_Purpose_Units, Luminance_Units, Power_Units, Humidity_Units, Velocity_Units, Direction_Units, Atmospheric_Pressure_Units, Barometric_Pressure_Units, Solar_Radiation_Units, Dew_Point_Units, Rain_Rate_Units, Tide_Level_Units, Weight_Units, Voltage_Units, Current_Units, Carbon_Dioxide_Units, Air_Flow_Units, Tank_Capacity_Units, Distance_Units, Angle_Position_Units, Rotation_Units, Water_Temperature_Units, Soil_Temperature_Units, Seismic_Intensity_Units, Seismic_Magnitude_Units, Ultraviolet_Units, Electrical_Resistivity_Units, Electrical_Conductivity_Units, Loudness_Units, Moisture_Units, Frequency_Units, Time_Units, Target_Temperature_Units, Particulate_Mater_2_5_Units, Formaldehyde_CH20_Level_Units, Radon_Concentration_Units, Methane_Density_Units, Volatile_Organic_Compound_Units, Carbon_Monoxide_Units, Soil_Humidity_Units, Soil_Reactivity_Units, Soil_Salinity_Units, Heart_Beat_Units, Blood_Pressure_Units, Muscle_Mass_Units, Fat_Mass_Units, Bone_Mass_Units, Total_Body_Water_Units, Basic_Metabolic_Rate_Units, Body_Mass_Index_Units, X_Axis_Acceleration_Units, Y_Axis_Acceleration_Units, Z_Axis_Acceleration_Units, Smoke_Density_Units, Water_Flow_Units, Water_Pressure_Units, RF_Signal_Strength_Units, Particulate_Matter_Units, Respiratory_Rate_Units, Relative_Modulation_Units, Boiler_Water_Temperature_Units, Domestic_Hot_Water_Temperature_Units, Outside_Temperature_Units, Exhaust_Temperature_Units, Water_Chlorine_Units, Water_Acidity_Units, Water_Oxidation_Reduction_Potential_Units, Heart_Rate_LF_HF_Ratio_Units, Motion_Direction_Units, Applied_Force_Units, Return_Air_Temperature_Units, Supply_Air_Temperature_Units, Condenser_Coil_Temperature_Units, Evaporator_Coil_Temperature_Units, Liquid_Line_Temperature_Units, Discharge_Line_Temperature_Units, Suction_Units, Discharge_Units, Defrost_Temperature_Units, Ozone_Units, Sulfur_Dioxide_Units, Nitrogen_Dioxide_Units, Ammonia_Units, Lead_Units, Particulate_Matter_v2_Units ); ENUM(ValueID_Index_SimpleAV, Command = 0 ); ENUM(ValueID_Index_SoundSwitch, Tone_Count = 0, Tones = 1, Volume = 2, Default_Tone = 3 ); ENUM(ValueID_Index_SwitchAll, SwitchAll = 0 ); ENUM(ValueID_Index_SwitchBinary, Level = 0, TargetState = 1, Duration = 2 ); ENUM(ValueID_Index_SwitchMultiLevel, Level = 0, Bright = 1, Dim = 2, IgnoreStartLevel = 3, StartLevel = 4, Duration = 5, Step = 6, Inc = 7, Dec = 8, TargetValue = 9 ); ENUM(ValueID_Index_SwitchToggleBinary, ToggleSwitch = 0 ); ENUM(ValueID_Index_SwitchToggleMultilevel, Level = 0 ); ENUM(ValueID_Index_ThermostatFanMode, FanMode = 0 ); ENUM(ValueID_Index_ThermostatFanState, FanState = 0 ); ENUM(ValueID_Index_ThermostatMode, Mode = 0 ); ENUM(ValueID_Index_ThermostatOperatingState, OperatingState = 0 ); ENUM(ValueID_Index_ThermostatSetpoint, Unused_0 = 0, Heating, Cooling, Unused_3, Unused_4, Unused_5, Unused_6, Furnace, DryAir, MoistAir, AutoChangeover, HeatingEcon, CoolingEcon, AwayHeating, CoolingHeating, Unused_0_Minimum = 100, Heating_Minimum, Cooling_Minimum, Unused_3_Minimum, Unused_4_Minimum, Unused_5_Minimum, Unused_6_Minimum, Furnace_Minimum, DryAir_Minimum, MoistAir_Minimum, AutoChangeOver_Minimum, Heating_Econ_Minimum, Cooling_Econ_Minimum, Away_Heating_Minimum, Cooling_Heating_Minimum, Unused_0_Maximum = 200, Heating_Maximum, Cooling_Maximum, Unused_3_Maximum, Unused_4_Maximum, Unused_5_Maximum, Unused_6_Maximum, Furnace_Maximum, DryAir_Maximum, MoistAir_Maximum, AutoChangeOver_Maximum, Heating_Econ_Maximum, Cooling_Econ_Maximum, Away_Heating_Maximum, Cooling_Heating_Maximum ); ENUM(ValueID_Index_TimeParameters, Date = 0, Time = 1, Set = 2, Refresh = 3 ); ENUM(ValueID_Index_UserCode, Enrollment_Code = 0, Code_1, Code_2, Code_3, Code_4, Code_5, Code_6, Code_7, Code_8, Code_9, Code_10, Code_11, Code_12, Code_13, Code_14, Code_15, Code_16, Code_17, Code_18, Code_19, Code_20, Code_21, Code_22, Code_23, Code_24, Code_25, Code_26, Code_27, Code_28, Code_29, Code_30, Code_31, Code_32, Code_33, Code_34, Code_35, Code_36, Code_37, Code_38, Code_39, Code_40, Code_41, Code_42, Code_43, Code_44, Code_45, Code_46, Code_47, Code_48, Code_49, Code_50, Code_51, Code_52, Code_53, Code_54, Code_55, Code_56, Code_57, Code_58, Code_59, Code_60, Code_61, Code_62, Code_63, Code_64, Code_65, Code_66, Code_67, Code_68, Code_69, Code_70, Code_71, Code_72, Code_73, Code_74, Code_75, Code_76, Code_77, Code_78, Code_79, Code_80, Code_81, Code_82, Code_83, Code_84, Code_85, Code_86, Code_87, Code_88, Code_89, Code_90, Code_91, Code_92, Code_93, Code_94, Code_95, Code_96, Code_97, Code_98, Code_99, Code_100, Code_101, Code_102, Code_103, Code_104, Code_105, Code_106, Code_107, Code_108, Code_109, Code_110, Code_111, Code_112, Code_113, Code_114, Code_115, Code_116, Code_117, Code_118, Code_119, Code_120, Code_121, Code_122, Code_123, Code_124, Code_125, Code_126, Code_127, Code_128, Code_129, Code_130, Code_131, Code_132, Code_133, Code_134, Code_135, Code_136, Code_137, Code_138, Code_139, Code_140, Code_141, Code_142, Code_143, Code_144, Code_145, Code_146, Code_147, Code_148, Code_149, Code_150, Code_151, Code_152, Code_153, Code_154, Code_155, Code_156, Code_157, Code_158, Code_159, Code_160, Code_161, Code_162, Code_163, Code_164, Code_165, Code_166, Code_167, Code_168, Code_169, Code_170, Code_171, Code_172, Code_173, Code_174, Code_175, Code_176, Code_177, Code_178, Code_179, Code_180, Code_181, Code_182, Code_183, Code_184, Code_185, Code_186, Code_187, Code_188, Code_189, Code_190, Code_191, Code_192, Code_193, Code_194, Code_195, Code_196, Code_197, Code_198, Code_199, Code_200, Code_201, Code_202, Code_203, Code_204, Code_205, Code_206, Code_207, Code_208, Code_209, Code_210, Code_211, Code_212, Code_213, Code_214, Code_215, Code_216, Code_217, Code_218, Code_219, Code_220, Code_221, Code_222, Code_223, Code_224, Code_225, Code_226, Code_227, Code_228, Code_229, Code_230, Code_231, Code_232, Code_233, Code_234, Code_235, Code_236, Code_237, Code_238, Code_239, Code_240, Code_241, Code_242, Code_243, Code_244, Code_245, Code_246, Code_247, Code_248, Code_249, Code_250, Code_251, Code_252, Code_253, Refresh = 255, RemoveCode = 256, Count = 257, RawValue = 258, RawValueIndex = 259 ); ENUM(ValueID_Index_Version, Library = 0, Protocol = 1, Application = 2 ); ENUM(ValueID_Index_WakeUp, Interval = 0, Min_Interval = 1, Max_Interval = 2, Default_Interval = 3, Interval_Step = 4 ); ENUM(ValueID_Index_ZWavePlusInfo, Version = 0, InstallerIcon = 1, UserIcon = 2 ); #endif openzwave-1.6.1914/cpp/src/OZWException.h0000644000175200017520000000747514032142455015015 00000000000000//----------------------------------------------------------------------------- // // FatalErrorException.h // // Exception Handling Code // // Copyright (c) 2014 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _FatalErrorException_H #define _FatalErrorException_H #include #include #include #include namespace OpenZWave { /** \brief Exception Handling Interface. * * This class is for exporting errors etc when using the OpenZWave API. It can report incorrect API usage * (such as passing incorrect ValueID's to the Manager::SetValue methods) or */ class OPENZWAVE_EXPORT OZWException : public std::runtime_error { public: enum ExceptionType { OZWEXCEPTION_OPTIONS, OZWEXCEPTION_CONFIG, OZWEXCEPTION_INVALID_HOMEID = 100, OZWEXCEPTION_INVALID_VALUEID, OZWEXCEPTION_CANNOT_CONVERT_VALUEID, OZWEXCEPTION_SECURITY_FAILED, OZWEXCEPTION_INVALID_NODEID }; //----------------------------------------------------------------------------- // Construction //----------------------------------------------------------------------------- OZWException(std::string file, int line, ExceptionType exitCode, std::string msg) : std::runtime_error(OZWException::GetExceptionText(file, line, exitCode, msg)), m_exitCode(exitCode), m_file(file), m_line(line), m_msg(msg) { } ~OZWException() throw() { } //----------------------------------------------------------------------------- // Accessor methods //----------------------------------------------------------------------------- ExceptionType GetType() { return m_exitCode;} std::string GetFile() { return m_file;} uint32 GetLine() { return m_line;} std::string GetMsg() { return m_msg;} private: static std::string GetExceptionText(std::string file, int line, ExceptionType exitCode, std::string msg) { std::stringstream ss; ss << file.substr(file.find_last_of("/\\") + 1) << ":" << line; switch (exitCode) { case OZWEXCEPTION_OPTIONS: ss << " - OptionsError (" << exitCode << ") Msg: " << msg; break; case OZWEXCEPTION_CONFIG: ss << " - ConfigError (" << exitCode << ") Msg: " << msg; break; case OZWEXCEPTION_INVALID_HOMEID: ss << " - InvalidHomeIDError (" << exitCode << ") Msg: " << msg; break; case OZWEXCEPTION_INVALID_VALUEID: ss << " - InvalidValueIDError (" << exitCode << ") Msg: " << msg; break; case OZWEXCEPTION_CANNOT_CONVERT_VALUEID: ss << " - CannotConvertValueIDError (" << exitCode << ") Msg: " << msg; break; case OZWEXCEPTION_SECURITY_FAILED: ss << " - Security Initialization Failed (" << exitCode << ") Msg: " << msg; break; case OZWEXCEPTION_INVALID_NODEID: ss << " - InvalidNodeIDError (" << exitCode << ") Msg: " << msg; break; } return ss.str(); } //----------------------------------------------------------------------------- // Member variables //----------------------------------------------------------------------------- ExceptionType m_exitCode; std::string m_file; uint32 m_line; std::string m_msg; }; } #endif // _FatalErrorException_H openzwave-1.6.1914/cpp/src/CompatOptionManager.h0000644000175200017520000001237614032142455016362 00000000000000//----------------------------------------------------------------------------- // // CompatOptionManager.h // // Handles Compatibility Flags in Config Files // // Copyright (c) 2019 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef CPP_SRC_COMPATOPTIONMANAGER_H_ #define CPP_SRC_COMPATOPTIONMANAGER_H_ #include "Defs.h" #include "tinyxml.h" #include namespace OpenZWave { namespace Internal { namespace CC { class CommandClass; } enum CompatOptionFlags { COMPAT_FLAG_GETSUPPORTED, COMPAT_FLAG_OVERRIDEPRECISION, COMPAT_FLAG_FORCEVERSION, COMPAT_FLAG_CREATEVARS, COMPAT_FLAG_REFRESHONWAKEUP, COMPAT_FLAG_BASIC_IGNOREREMAPPING, COMPAT_FLAG_BASIC_SETASREPORT, COMPAT_FLAG_BASIC_MAPPING, COMPAT_FLAG_COLOR_IDXBUG, COMPAT_FLAG_MCA_FORCEINSTANCES, COMPAT_FLAG_MI_MAPROOTTOENDPOINT, COMPAT_FLAG_MI_FORCEUNIQUEENDPOINTS, COMPAT_FLAG_MI_IGNMCCAPREPORTS, COMPAT_FLAG_MI_ENDPOINTHINT, COMPAT_FLAG_TSSP_BASE, COMPAT_FLAG_TSSP_ALTTYPEINTERPRETATION, COMPAT_FLAG_UC_EXPOSERAWVALUE, COMPAT_FLAG_VERSION_GETCLASSVERSION, COMPAT_FLAG_WAKEUP_DELAYNMI, COMPAT_FLAG_MI_REMOVECC, COMPAT_FLAG_VERIFYCHANGED, COMPAT_FLAG_NOT_ENABLECLEAR, COMPAT_FLAG_NOT_V1ALARMTYPES_ENABLED, COMPAT_FLAG_NO_REFRESH_AFTER_SET, STATE_FLAG_CCVERSION, STATE_FLAG_STATIC_REQUESTS, STATE_FLAG_AFTERMARK, STATE_FLAG_ENCRYPTED, STATE_FLAG_INNIF, STATE_FLAG_CS_SCENECOUNT, STATE_FLAG_CS_CLEARTIMEOUT, STATE_FLAG_CCS_CHANGECOUNTER, STATE_FLAG_COLOR_CHANNELS, STATE_FLAG_DOORLOCK_TIMEOUT, STATE_FLAG_DOORLOCK_INSIDEMODE, STATE_FLAG_DOORLOCK_OUTSIDEMODE, STATE_FLAG_DOORLOCK_TIMEOUTMINS, STATE_FLAG_DOORLOCK_TIMEOUTSECS, STATE_FLAG_DOORLOCKLOG_MAXRECORDS, STATE_FLAG_USERCODE_COUNT, }; enum CompatOptionFlagType { COMPAT_FLAG_TYPE_BOOL, COMPAT_FLAG_TYPE_BYTE, COMPAT_FLAG_TYPE_SHORT, COMPAT_FLAG_TYPE_INT, COMPAT_FLAG_TYPE_BOOL_ARRAY, COMPAT_FLAG_TYPE_BYTE_ARRAY, COMPAT_FLAG_TYPE_SHORT_ARRAY, COMPAT_FLAG_TYPE_INT_ARRAY }; enum CompatOptionType { CompatOptionType_Compatibility, CompatOptionType_Discovery }; struct CompatOptionFlagStorage { CompatOptionFlags flag; CompatOptionFlagType type; bool changed; /* when a single Value (not a FLAG_TYPE_*_ARRAY) this union holds the actual value * but when its a FLAG_*_ARRAY, this union holds the default value */ union { bool valBool; uint8_t valByte; uint16_t valShort; uint32_t valInt; }; /* Only when FLAG_TYPE_*_ARRAY is this union used, and holds * individual values for each key. Default Value is taken from * the above Union */ /* oh - And we can't use a Union here with a non-POD type */ std::map valBoolArray; std::map valByteArray; std::map valShortArray; std::map valIntArray; }; struct CompatOptionFlagDefintions { string name; CompatOptionFlags flag; CompatOptionFlagType type; }; class CompatOptionManager { public: CompatOptionManager(CompatOptionType type, Internal::CC::CommandClass *cc); virtual ~CompatOptionManager(); void SetNodeAndCC(uint8_t node, uint8_t cc); void EnableFlag(CompatOptionFlags flag, uint32_t defaultval); void ReadXML(TiXmlElement const* _ccElement); void WriteXML(TiXmlElement* _ccElement); bool GetFlagBool(CompatOptionFlags flag, uint32_t index = -1) const; uint8_t GetFlagByte(CompatOptionFlags flag, uint32_t index = -1) const; uint16_t GetFlagShort(CompatOptionFlags flag, uint32_t index = -1) const; uint32_t GetFlagInt(CompatOptionFlags flag, uint32_t index = -1) const; bool SetFlagBool(CompatOptionFlags flag, bool value, uint32_t index = -1); bool SetFlagByte(CompatOptionFlags flag, uint8_t value, uint32_t index = -1); bool SetFlagShort(CompatOptionFlags flag, uint16_t value, uint32_t index = -1); bool SetFlagInt(CompatOptionFlags flag, uint32_t value, uint32_t index = -1); private: string GetFlagName(CompatOptionFlags flag) const; string GetXMLTagName(); map m_CompatVals; map m_enabledCompatFlags; Internal::CC::CommandClass *m_owner; CompatOptionType m_comtype; CompatOptionFlagDefintions *m_availableFlags; uint32_t m_availableFlagsCount; }; } // namespace Internal } /* namespace OpenZWave */ #endif /* CPP_SRC_COMPATOPTIONMANAGER_H_ */ openzwave-1.6.1914/cpp/src/value_classes/0000777000175200017520000000000014032143201015174 500000000000000openzwave-1.6.1914/cpp/src/value_classes/ValueID.cpp0000644000175200017520000000513314032142455017121 00000000000000//----------------------------------------------------------------------------- // // ValueID.cpp // // Represents a Device Variable in OZW // // Copyright (c) 2019 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "ValueID.h" #include "Value.h" #include #include namespace OpenZWave { //----------------------------------------------------------------------------- // // Get the Genre as a String //----------------------------------------------------------------------------- string ValueID::GetGenreAsString() const { return Internal::VC::Value::GetGenreNameFromEnum(GetGenre()); } //----------------------------------------------------------------------------- // // Get the Type as a String //----------------------------------------------------------------------------- string ValueID::GetTypeAsString() const { return Internal::VC::Value::GetTypeNameFromEnum(GetType()); } string const ValueID::GetAsString() const { // Match constructor order // ValueID(uint32 const _homeId, uint8 const _nodeId, ValueGenre const _genre, uint8 const _commandClassId, // uint8 const _instance, uint16 const _valueIndex, ValueType const _type) std::ostringstream s; s << "HomeID: 0x" << hex << setfill('0') << setw(8) << GetHomeId() << ", ValueID: (Id 0x" << setw(16) << GetId() << dec << setfill(' ') << ", NodeID " << static_cast(GetNodeId()) << ", Genre " << GetGenreAsString() << ", CC 0x" << hex << setfill('0') << setw(2) << static_cast(GetCommandClassId()) << dec << setfill(' ') << ", Instance " << static_cast(GetInstance()) << ", Index " << static_cast(GetIndex()) << ", Type " << GetTypeAsString() << ')'; return s.str(); } }// namespace OpenZWave openzwave-1.6.1914/cpp/src/value_classes/ValueButton.cpp0000644000175200017520000000652114032142455020102 00000000000000//----------------------------------------------------------------------------- // // ValueButton.h // // Represents a write-only value that triggers activity in a device // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "tinyxml.h" #include "value_classes/ValueButton.h" #include "Manager.h" #include "Driver.h" #include "Node.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace VC { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ValueButton::ValueButton(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, uint8 const _pollIntensity) : Value(_homeId, _nodeId, _genre, _commandClassId, _instance, _index, ValueID::ValueType_Button, _label, "", false, true, true, _pollIntensity), m_pressed(false) { } //----------------------------------------------------------------------------- // // Apply settings from XML //----------------------------------------------------------------------------- void ValueButton::ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement) { Value::ReadXML(_homeId, _nodeId, _commandClassId, _valueElement); } //----------------------------------------------------------------------------- // // Write ourselves to an XML document //----------------------------------------------------------------------------- void ValueButton::WriteXML(TiXmlElement* _valueElement) { Value::WriteXML(_valueElement); } //----------------------------------------------------------------------------- // // Start an activity in a device //----------------------------------------------------------------------------- bool ValueButton::PressButton() { // Set the value in the device. m_pressed = true; return Value::Set(); } //----------------------------------------------------------------------------- // // Stop an activity in a device //----------------------------------------------------------------------------- bool ValueButton::ReleaseButton() { // Set the value in the device. m_pressed = false; return Value::Set(); } } // namespace VC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/value_classes/ValueBitSet.h0000644000175200017520000000634414032142455017471 00000000000000//----------------------------------------------------------------------------- // // ValueBitSet.h // // Represents a Range of Bits // // Copyright (c) 2017 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ValueBitSet_H #define _ValueBitSet_H #include #include #include "Defs.h" #include "value_classes/Value.h" #include "Bitfield.h" class TiXmlElement; namespace OpenZWave { namespace Internal { namespace VC { /** \brief BitSet value sent to/received from a node. * \ingroup ValueID */ class ValueBitSet: public Value { public: ValueBitSet(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint32 const _value, uint8 const _pollIntensity); ValueBitSet() { } virtual ~ValueBitSet() { } bool Set(uint32 const _value); uint32 GetValue() const; void SetTargetValue(uint32 const _target, uint32 _duration = 0); bool SetBit(uint8 const _idx); bool ClearBit(uint8 const _idx); bool GetBit(uint8 _idx) const; bool SetBitMask(uint32 _bitMask); uint32 GetBitMask() const; void OnValueRefreshed(uint32 const _value); // From Value virtual string const GetAsString() const; virtual string const GetAsBinaryString() const; virtual bool SetFromString(string const& _value); virtual void ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement); virtual void WriteXML(TiXmlElement* _valueElement); string GetBitHelp(uint8 _idx); bool SetBitHelp(uint8 _idx, string help); string GetBitLabel(uint8 _idx); bool SetBitLabel(uint8 _idx, string label); uint8 GetSize() const; void SetSize(uint8 size); private: bool isValidBit(uint8 _idx) const; Bitfield m_value; // the current index in the m_items vector Bitfield m_valueCheck; // the previous value (used for double-checking spurious value reads) Bitfield m_newValue; // a new value to be set on the appropriate device uint32 m_BitMask; // Valid Bits uint8 m_size; // Number of bytes in size vector m_bits; uint32 m_targetValue; // Target Value, if Supported; }; } // namespace VC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/value_classes/ValueRaw.cpp0000644000175200017520000002011514032142455017353 00000000000000//----------------------------------------------------------------------------- // // ValueRaw.cpp // // Represents a collection of 8-bit values // // Copyright (c) 2012 Greg Satz // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "tinyxml.h" #include "value_classes/ValueRaw.h" #include "Msg.h" #include "platform/Log.h" #include "Manager.h" #include namespace OpenZWave { namespace Internal { namespace VC { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ValueRaw::ValueRaw(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const* _value, uint8 const _length, uint8 const _pollIntensity) : Value(_homeId, _nodeId, _genre, _commandClassId, _instance, _index, ValueID::ValueType_Raw, _label, _units, _readOnly, _writeOnly, false, _pollIntensity), m_value( NULL), m_valueLength(_length), m_valueCheck( NULL), m_valueCheckLength(0), m_targetValue(NULL), m_targetValueLength(0) { m_value = new uint8[_length]; memcpy(m_value, _value, _length); m_min = 0; m_max = 0; } //----------------------------------------------------------------------------- // // Constructor (from XML) //----------------------------------------------------------------------------- ValueRaw::ValueRaw() : m_value( NULL), m_valueLength(0), m_valueCheck( NULL), m_valueCheckLength(0) { m_min = 0; m_max = 0; } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- ValueRaw::~ValueRaw() { delete[] m_value; if (m_valueCheck != NULL) delete[] m_valueCheck; } std::string const ValueRaw::GetAsString() const { string str = ""; char bstr[10]; for (uint32 i = 0; i < m_valueLength; ++i) { if (i) { str += " "; } snprintf(bstr, sizeof(bstr), "0x%.2x", m_value[i]); str += bstr; } return str; } bool ValueRaw::SetFromString(string const& _value) { char const* p = _value.c_str(); uint8 index = 0; uint8* value = new uint8[m_valueLength]; while (1) { char *ep = NULL; uint32 val = (uint32) strtol(p, &ep, 16); if (p == ep || val >= 256) { break; } if (index < m_valueLength) { value[index] = (uint8) val; } index++; if (ep != NULL && *ep == '\0') { break; } p = ep + 1; } bool bRet = false; if (index <= m_valueLength) { bRet = Set(value, index); } delete[] value; return bRet; } //----------------------------------------------------------------------------- // // Apply settings from XML //----------------------------------------------------------------------------- void ValueRaw::ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement) { Value::ReadXML(_homeId, _nodeId, _commandClassId, _valueElement); int intVal; if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("length", &intVal)) { m_valueLength = (uint8) intVal; } m_value = new uint8[m_valueLength]; char const* str = _valueElement->Attribute("value"); if (str) { uint8 index = 0; while (1) { char *ep = NULL; uint32 val = (uint32) strtol(str, &ep, 16); if (str == ep || val >= 256) { break; } if (index < m_valueLength) { m_value[index] = (uint8) val; } index++; if (ep != NULL && *ep == '\0') { break; } str = ep + 1; } if (index > m_valueLength) { Log::Write(LogLevel_Info, "Data length mismatch for raw data. Got %d but expected %d.", index, m_valueLength); } } else { Log::Write(LogLevel_Info, "Missing default raw value from xml configuration: node %d, class 0x%02x, instance %d, index %d", _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex()); } } //----------------------------------------------------------------------------- // // Write ourselves to an XML document //----------------------------------------------------------------------------- void ValueRaw::WriteXML(TiXmlElement* _valueElement) { Value::WriteXML(_valueElement); _valueElement->SetAttribute("value", GetAsString().c_str()); char str[8]; snprintf(str, sizeof(str), "%d", GetLength()); _valueElement->SetAttribute("length", str); } //----------------------------------------------------------------------------- // // Set a new value in the device //----------------------------------------------------------------------------- bool ValueRaw::Set(uint8 const* _value, uint8 const _length) { // create a temporary copy of this value to be submitted to the Set() call and set its value to the function param ValueRaw* tempValue = new ValueRaw(*this); tempValue->m_value = new uint8[_length]; memcpy(tempValue->m_value, _value, _length); tempValue->m_valueLength = _length; // Set the value in the device. bool ret = ((Value*) tempValue)->Set(); // clean up the temporary value delete tempValue; return ret; } //----------------------------------------------------------------------------- // // Set the Value Target (Used for Automatic Refresh) //----------------------------------------------------------------------------- void ValueRaw::SetTargetValue(uint8 const* _target, uint8 const _length, int32 _duration) { m_targetValueSet = true; memcpy(m_targetValue, _target, _length); m_targetValueLength = _length; m_duration = _duration; } //----------------------------------------------------------------------------- // // A value in a device has been refreshed //----------------------------------------------------------------------------- void ValueRaw::OnValueRefreshed(uint8 const* _value, uint8 const _length) { switch (VerifyRefreshedValue((void*) m_value, (void*) m_valueCheck, (void*) _value, (void*) m_targetValue, ValueID::ValueType_Raw, m_valueLength, m_valueCheckLength, _length, m_targetValueLength)) { case 0: // value hasn't changed, nothing to do break; case 1: // value has changed (not confirmed yet), save _value in m_valueCheck if (m_valueCheck != NULL) { delete[] m_valueCheck; } m_valueCheck = new uint8[_length]; m_valueCheckLength = _length; memcpy(m_valueCheck, _value, _length); break; case 2: // value has changed (confirmed), save _value in m_value if (m_value != NULL) { delete[] m_value; } m_value = new uint8[_length]; m_valueLength = _length; memcpy(m_value, _value, _length); break; case 3: // all three values are different, so wait for next refresh to try again break; } } } // namespace VC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/value_classes/ValueBitSet.cpp0000644000175200017520000003165514032142455020027 00000000000000//----------------------------------------------------------------------------- // // ValueBitSet.cpp // // Represents a boolean value // // Copyright (c) 2017 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "tinyxml.h" #include "value_classes/ValueBitSet.h" #include "Driver.h" #include "Node.h" #include "platform/Log.h" #include "Manager.h" #include "Localization.h" #include namespace OpenZWave { namespace Internal { namespace VC { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ValueBitSet::ValueBitSet(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint32 const _value, uint8 const _pollIntensity) : Value(_homeId, _nodeId, _genre, _commandClassId, _instance, _index, ValueID::ValueType_BitSet, _label, _units, _readOnly, _writeOnly, false, _pollIntensity), m_value(_value), m_valueCheck(false), m_newValue(false), m_BitMask(0xFFFFFFFF), m_size(0), m_targetValue(0) { } bool ValueBitSet::SetFromString(string const& _value) { int32 val = atoi(_value.c_str()); return Set(val); } std::string const ValueBitSet::GetAsString() const { stringstream ss; ss << GetValue(); return ss.str(); } std::string const ValueBitSet::GetAsBinaryString() const { uint32 n = GetValue(); std::string r; while (n != 0) { r = (n % 2 == 0 ? "0" : "1") + r; n /= 2; } return "0b" + r; } uint32 ValueBitSet::GetValue() const { return m_value.GetValue(); } bool ValueBitSet::GetBit(uint8 _idx) const { if (isValidBit(_idx)) return m_value.IsSet(_idx - 1); Log::Write(LogLevel_Warning, m_id.GetNodeId(), "GetBit Index %d is not valid with BitMask %d", _idx, m_BitMask); return false; } //----------------------------------------------------------------------------- // // Apply settings from XML //----------------------------------------------------------------------------- void ValueBitSet::ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement) { Value::ReadXML(_homeId, _nodeId, _commandClassId, _valueElement); int intVal; if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("bitmask", &intVal)) { m_BitMask = (uint32) intVal; } else { Log::Write(LogLevel_Info, "Missing BitMask value from xml configuration: node %d, class 0x%02x, instance %d, index %d", _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex()); } if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("value", &intVal)) { m_value.SetValue((uint32) intVal); } else { Log::Write(LogLevel_Info, "Missing default integer value from xml configuration: node %d, class 0x%02x, instance %d, index %d", _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex()); } // Get size of values int intSize; if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("size", &intSize)) { if (intSize == 1 || intSize == 2 || intSize == 4) { m_size = intSize; } else { Log::Write(LogLevel_Info, "Value size is invalid. Only 1, 2 & 4 supported for node %d, class 0x%02x, instance %d, index %d", _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex()); m_size = 1; } } else { Log::Write(LogLevel_Info, "Value list size is not set, assuming 1 bytes for node %d, class 0x%02x, instance %d, index %d", _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex()); m_size = 1; } TiXmlElement const *BitSetElement = _valueElement->FirstChildElement("BitSet"); while (BitSetElement) { uint32 id = 0; if (TIXML_SUCCESS == BitSetElement->QueryIntAttribute("id", &intVal)) { id = (uint32) intVal; TiXmlElement const *BitSetLabelElement = BitSetElement->FirstChildElement("Label"); while (BitSetLabelElement) { char const* lang = BitSetLabelElement->Attribute("lang"); Localization::Get()->SetValueItemLabel(m_id.GetNodeId(), m_id.GetCommandClassId(), m_id.GetIndex(), -1, id, BitSetLabelElement->GetText(), lang ? lang : ""); BitSetLabelElement = BitSetLabelElement->NextSiblingElement("Label"); } TiXmlElement const *BitSetHelpElement = BitSetElement->FirstChildElement("Help"); while (BitSetHelpElement) { char const* lang = BitSetHelpElement->Attribute("lang"); Localization::Get()->SetValueItemHelp(m_id.GetNodeId(), m_id.GetCommandClassId(), m_id.GetIndex(), -1, id, BitSetHelpElement->GetText(), lang ? lang : ""); BitSetHelpElement = BitSetHelpElement->NextSiblingElement("Help"); } m_bits.push_back(id); } BitSetElement = BitSetElement->NextSiblingElement("BitSet"); } } //----------------------------------------------------------------------------- // // Write ourselves to an XML document //----------------------------------------------------------------------------- void ValueBitSet::WriteXML(TiXmlElement* _valueElement) { Value::WriteXML(_valueElement); char str[16]; snprintf(str, sizeof(str), "%d", m_BitMask); _valueElement->SetAttribute("bitmask", str); snprintf(str, sizeof(str), "%d", m_value.GetValue()); _valueElement->SetAttribute("value", str); snprintf(str, sizeof(str), "%d", m_size); _valueElement->SetAttribute("size", str); TiXmlElement *helpElement = _valueElement->FirstChildElement("Help"); if (!helpElement) { helpElement = new TiXmlElement("Help"); _valueElement->LinkEndChild(helpElement); } for (std::vector::iterator it = m_bits.begin(); it != m_bits.end(); ++it) { TiXmlElement* BitSetElement = new TiXmlElement("BitSet"); BitSetElement->SetAttribute("id", *it); _valueElement->LinkEndChild(BitSetElement); TiXmlElement* BitSetLabelElement = new TiXmlElement("Label"); TiXmlText* labeltextElement = new TiXmlText(Localization::Get()->GetValueItemLabel(m_id.GetNodeId(), m_id.GetCommandClassId(), m_id.GetIndex(), -1, *it).c_str()); BitSetLabelElement->LinkEndChild(labeltextElement); BitSetElement->LinkEndChild(BitSetLabelElement); TiXmlElement* BitSetHelpElement = new TiXmlElement("Help"); TiXmlText* helptextElement = new TiXmlText(Localization::Get()->GetValueItemHelp(m_id.GetNodeId(), m_id.GetCommandClassId(), m_id.GetIndex(), -1, *it).c_str()); BitSetHelpElement->LinkEndChild(helptextElement); BitSetElement->LinkEndChild(BitSetHelpElement); } } //----------------------------------------------------------------------------- // // Set a new value in the device //----------------------------------------------------------------------------- bool ValueBitSet::Set(uint32 const _value) { if (_value & ~m_BitMask) { Log::Write(LogLevel_Warning, m_id.GetNodeId(), "Set: Value %d is not valid with BitMask %d", _value, m_BitMask); return false; } // create a temporary copy of this value to be submitted to the Set() call and set its value to the function param ValueBitSet* tempValue = new ValueBitSet(*this); tempValue->m_value.SetValue(_value); // Set the value in the device. bool ret = ((Value*) tempValue)->Set(); // clean up the temporary value delete tempValue; return ret; } bool ValueBitSet::SetBit(uint8 const _idx) { /* is the bits valid */ if (!isValidBit(_idx)) { Log::Write(LogLevel_Warning, m_id.GetNodeId(), "SetBit: Bit %d is not valid with BitMask %d", _idx, m_BitMask); return false; } // create a temporary copy of this value to be submitted to the Set() call and set its value to the function param ValueBitSet* tempValue = new ValueBitSet(*this); tempValue->m_value.Set(_idx - 1); // Set the value in the device. bool ret = ((Value*) tempValue)->Set(); // clean up the temporary value delete tempValue; return ret; } bool ValueBitSet::ClearBit(uint8 const _idx) { /* is the bits valid */ if (!isValidBit(_idx)) { Log::Write(LogLevel_Warning, m_id.GetNodeId(), "ClearBit: Bit %d is not valid with BitMask %d", _idx, m_BitMask); return false; } // create a temporary copy of this value to be submitted to the Set() call and set its value to the function param ValueBitSet* tempValue = new ValueBitSet(*this); tempValue->m_value.Clear(_idx - 1); // Set the value in the device. bool ret = ((Value*) tempValue)->Set(); // clean up the temporary value delete tempValue; return ret; } bool ValueBitSet::SetBitMask(uint32 _bitMask) { m_BitMask = _bitMask; return true; } uint32 ValueBitSet::GetBitMask() const { return m_BitMask; } std::string ValueBitSet::GetBitHelp(uint8 _idx) { if (isValidBit(_idx)) { return Localization::Get()->GetValueItemHelp(m_id.GetNodeId(), m_id.GetCommandClassId(), m_id.GetIndex(), -1, _idx); } Log::Write(LogLevel_Warning, m_id.GetNodeId(), "SetBitHelp: Bit %d is not valid with BitMask %d", _idx, m_BitMask); return ""; } bool ValueBitSet::SetBitHelp(uint8 _idx, string help) { if (isValidBit(_idx)) { return Localization::Get()->SetValueItemHelp(m_id.GetNodeId(), m_id.GetCommandClassId(), m_id.GetIndex(), -1, _idx, help, Localization::Get()->GetSelectedLang()); } Log::Write(LogLevel_Warning, m_id.GetNodeId(), "SetBitHelp: Bit %d is not valid with BitMask %d", _idx, m_BitMask); return false; } bool ValueBitSet::isValidBit(uint8 _idx) const { if (((m_BitMask) & (1 << (_idx - 1))) == 0) return false; return true; } std::string ValueBitSet::GetBitLabel(uint8 _idx) { if (isValidBit(_idx)) { return Localization::Get()->GetValueItemLabel(m_id.GetNodeId(), m_id.GetCommandClassId(), m_id.GetIndex(), -1, _idx); } Log::Write(LogLevel_Warning, m_id.GetNodeId(), "GetBitLabel: Bit %d is not valid with BitMask %d", _idx, m_BitMask); return "Reserved"; } bool ValueBitSet::SetBitLabel(uint8 _idx, string label) { if (isValidBit(_idx)) { Localization::Get()->SetValueItemLabel(m_id.GetNodeId(), m_id.GetCommandClassId(), m_id.GetIndex(), -1, _idx, label, Localization::Get()->GetSelectedLang()); return true; } Log::Write(LogLevel_Warning, m_id.GetNodeId(), "SetBitLabel: Bit %d is not valid with BitMask %d", _idx, m_BitMask); return false; } uint8 ValueBitSet::GetSize() const { return m_size; } void ValueBitSet::SetSize(uint8 size) { m_size = size; } //----------------------------------------------------------------------------- // // Set the Value Target (Used for Automatic Refresh) //----------------------------------------------------------------------------- void ValueBitSet::SetTargetValue(uint32 const _target, uint32 _duration) { m_targetValueSet = true; m_targetValue = _target; m_duration = _duration; } //----------------------------------------------------------------------------- // // A value in a device has been refreshed //----------------------------------------------------------------------------- void ValueBitSet::OnValueRefreshed(uint32 const _value) { switch (VerifyRefreshedValue((void*) &m_value, (void*) &m_valueCheck, (void*) &_value, (void*) &m_targetValue, ValueID::ValueType_BitSet)) { case 0: // value hasn't changed, nothing to do break; case 1: // value has changed (not confirmed yet), save _value in m_valueCheck m_valueCheck.SetValue(_value); break; case 2: // value has changed (confirmed), save _value in m_value m_value.SetValue(_value); break; case 3: // all three values are different, so wait for next refresh to try again break; } } } // namespace VC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/value_classes/ValueInt.h0000644000175200017520000000472214032142455017027 00000000000000//----------------------------------------------------------------------------- // // ValueInt.h // // Represents a 32-bit value // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ValueInt_H #define _ValueInt_H #include #include "Defs.h" #include "value_classes/Value.h" class TiXmlElement; namespace OpenZWave { namespace Internal { namespace VC { /** \brief Integer value sent to/received from a node. * \ingroup ValueID */ class ValueInt: public Value { public: ValueInt(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, int32 const _value, uint8 const _pollIntensity); ValueInt(); virtual ~ValueInt() { } bool Set(int32 const _value); void OnValueRefreshed(int32 const _value); void SetTargetValue(int32 const _target, uint32 _duration = 0); // From Value virtual string const GetAsString() const; virtual bool SetFromString(string const& _value); virtual void ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement); virtual void WriteXML(TiXmlElement* _valueElement); int32 GetValue() const { return m_value; } private: int32 m_value; // the current value int32 m_valueCheck; // the previous value (used for double-checking spurious value reads) int32 m_targetValue; // Target Value }; } // namespace VC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/value_classes/Value.cpp0000644000175200017520000007405614032142455016716 00000000000000//----------------------------------------------------------------------------- // // Value.cpp // // Base class for all OpenZWave Value Classes // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "tinyxml.h" #include "Manager.h" #include "Driver.h" #include "Localization.h" #include "Node.h" #include "Notification.h" #include "Msg.h" #include "Bitfield.h" #include "value_classes/Value.h" #include "platform/Log.h" #include "command_classes/CommandClass.h" #include #include "Options.h" namespace OpenZWave { namespace Internal { namespace VC { static char const* c_genreName[] = { "basic", "user", "config", "system", "invalid" }; static char const* c_typeName[] = { "bool", "byte", "decimal", "int", "list", "schedule", "short", "string", "button", "raw", "bitset", "invalid type" }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Value::Value(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, ValueID::ValueType const _type, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, bool const _isSet, uint8 const _pollIntensity) : m_min(0), m_max(0), m_refreshTime(0), m_verifyChanges(false), m_refreshAfterSet(true), m_id(_homeId, _nodeId, _genre, _commandClassId, _instance, _index, _type), m_targetValueSet(false), m_duration(0), m_units(_units), m_readOnly(_readOnly), m_writeOnly(_writeOnly), m_isSet(_isSet), m_affectsLength(0), m_affects(), m_affectsAll(false), m_checkChange(false), m_pollIntensity(_pollIntensity) { SetLabel(_label); if (Driver* driver = Manager::Get()->GetDriver(m_id.GetHomeId())) { Timer::SetDriver(driver); } } //----------------------------------------------------------------------------- // // Constructor (from XML) //----------------------------------------------------------------------------- Value::Value() : m_min(0), m_max(0), m_refreshTime(0), m_verifyChanges(false), m_refreshAfterSet(true), m_targetValueSet(false), m_duration(0), m_readOnly(false), m_writeOnly(false), m_isSet(false), m_affectsLength(0), m_affects(), m_affectsAll(false), m_checkChange(false), m_pollIntensity(0) { } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- Value::~Value() { if (m_affectsLength > 0) { delete[] m_affects; } } //----------------------------------------------------------------------------- // // Apply settings from XML //----------------------------------------------------------------------------- void Value::ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement) { int intVal; ValueID::ValueGenre genre = Value::GetGenreEnumFromName(_valueElement->Attribute("genre")); ValueID::ValueType type = Value::GetTypeEnumFromName(_valueElement->Attribute("type")); uint8 instance = 1; if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("instance", &intVal)) { instance = (uint8) intVal; } uint16 index = 0; if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("index", &intVal)) { /* index is only 16 bytes in the ValueID class */ index = (uint16) (intVal & 0xFFFF); } m_id = ValueID(_homeId, _nodeId, genre, _commandClassId, instance, index, type); /* For Values Loaded from a XML File - We Need to load the Timer Driver here, as the default * constructor doens't have a m_id set, hence we can't get the HomeID */ if (Driver* driver = Manager::Get()->GetDriver(m_id.GetHomeId())) { Timer::SetDriver(driver); } char const* label = _valueElement->Attribute("label"); if (label) { SetLabel(label); } char const* units = _valueElement->Attribute("units"); if (units) { m_units = units; } char const* readOnly = _valueElement->Attribute("read_only"); if (readOnly) { m_readOnly = !strcmp(readOnly, "true"); } char const* writeOnly = _valueElement->Attribute("write_only"); if (writeOnly) { m_writeOnly = !strcmp(writeOnly, "true"); } if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("poll_intensity", &intVal)) { m_pollIntensity = (uint8) intVal; } char const* affects = _valueElement->Attribute("affects"); if (affects) { if (m_affectsLength != 0) { delete[] m_affects; } m_affectsLength = 0; if (!strcmp(affects, "all")) { m_affectsAll = true; } else { size_t len = strlen(affects); if (len > 0) { for (size_t i = 0; i < len; i++) { if (affects[i] == ',') { m_affectsLength++; } else if (affects[i] < '0' || affects[i] > '9') { Log::Write(LogLevel_Info, "Improperly formatted affects data: \"%s\"", affects); break; } } m_affectsLength++; m_affects = new uint8[m_affectsLength]; unsigned int j = 0; for (int i = 0; i < m_affectsLength; i++) { m_affects[i] = atoi(&affects[j]); while (j < len && affects[j] != ',') { j++; } j++; } } } } char const* verifyChanges = _valueElement->Attribute("verify_changes"); if (verifyChanges) { m_verifyChanges = !strcmp(verifyChanges, "true"); } if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("min", &intVal)) { m_min = intVal; } if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("max", &intVal)) { m_max = intVal; } TiXmlElement const* helpElement = _valueElement->FirstChildElement(); while (helpElement) { char const* str = helpElement->Value(); if (str && !strcmp(str, "Help")) { Localization::Get()->ReadXMLVIDHelp(m_id.GetNodeId(), _commandClassId, index, -1, helpElement); } if (str && !strcmp(str, "Label")) { Localization::Get()->ReadXMLVIDLabel(m_id.GetNodeId(), _commandClassId, index, -1, helpElement); } helpElement = helpElement->NextSiblingElement(); } } //----------------------------------------------------------------------------- // // Write ourselves to an XML document //----------------------------------------------------------------------------- void Value::WriteXML(TiXmlElement* _valueElement) { char str[16]; _valueElement->SetAttribute("type", GetTypeNameFromEnum(m_id.GetType())); _valueElement->SetAttribute("genre", GetGenreNameFromEnum(m_id.GetGenre())); snprintf(str, sizeof(str), "%d", m_id.GetInstance()); _valueElement->SetAttribute("instance", str); snprintf(str, sizeof(str), "%d", (m_id.GetIndex() & 0xFFFF)); _valueElement->SetAttribute("index", str); _valueElement->SetAttribute("label", GetLabel().c_str()); _valueElement->SetAttribute("units", m_units.c_str()); _valueElement->SetAttribute("read_only", m_readOnly ? "true" : "false"); _valueElement->SetAttribute("write_only", m_writeOnly ? "true" : "false"); _valueElement->SetAttribute("verify_changes", m_verifyChanges ? "true" : "false"); snprintf(str, sizeof(str), "%d", m_pollIntensity); _valueElement->SetAttribute("poll_intensity", str); snprintf(str, sizeof(str), "%d", m_min); _valueElement->SetAttribute("min", str); snprintf(str, sizeof(str), "%d", m_max); _valueElement->SetAttribute("max", str); if (m_affectsAll) { _valueElement->SetAttribute("affects", "all"); } else if (m_affectsLength > 0) { string s; for (int i = 0; i < m_affectsLength; i++) { snprintf(str, sizeof(str), "%d", m_affects[i]); s = s + str; if (i + 1 < m_affectsLength) { s = s + ","; } } _valueElement->SetAttribute("affects", s.c_str()); } Localization::Get()->WriteXMLVIDHelp(m_id.GetNodeId(), m_id.GetCommandClassId(), m_id.GetIndex(), -1, _valueElement); } //----------------------------------------------------------------------------- // // Set a new value in the device //----------------------------------------------------------------------------- bool Value::Set() { // nothing to do if this is a read-only value (return false to indicate an error) if (IsReadOnly()) { return false; } // retrieve the driver, node and commandclass object for this value bool res = false; Node* node = NULL; if (Driver* driver = Manager::Get()->GetDriver(m_id.GetHomeId())) { node = driver->GetNodeUnsafe(m_id.GetNodeId()); if (node != NULL) { if (Internal::CC::CommandClass* cc = node->GetCommandClass(m_id.GetCommandClassId())) { Log::Write(LogLevel_Info, m_id.GetNodeId(), "Value::Set - %s - %s - %d - %d - %s", cc->GetCommandClassName().c_str(), this->GetLabel().c_str(), m_id.GetIndex(), m_id.GetInstance(), this->GetAsString().c_str()); // flag value as set and queue a "Set Value" message for transmission to the device res = cc->SetValue(*this); if (res) { if (!IsWriteOnly()) { // queue a "RequestValue" message to update the value if (m_refreshAfterSet) { cc->RequestValue( 0, m_id.GetIndex(), m_id.GetInstance(), Driver::MsgQueue_Send ); } } else { // There is a "bug" here in that write only values // never send a notification about the value changing. // For sleeping devices it may not change until the // device wakes up at some point in the future. // So when is the right time to change it? if (m_affectsAll) { node->RequestAllConfigParams(0); } else if (m_affectsLength > 0) { for (int i = 0; i < m_affectsLength; i++) { node->RequestConfigParam(m_affects[i]); } } } } } } } return res; } //----------------------------------------------------------------------------- // // A value in a device has been refreshed //----------------------------------------------------------------------------- void Value::OnValueRefreshed() { if (IsWriteOnly()) { return; } if (Driver* driver = Manager::Get()->GetDriver(m_id.GetHomeId())) { m_isSet = true; bool bSuppress; Options::Get()->GetOptionAsBool("SuppressValueRefresh", &bSuppress); if (!bSuppress) { // Notify the watchers Notification* notification = new Notification(Notification::Type_ValueRefreshed); notification->SetValueId(m_id); driver->QueueNotification(notification); } } } //----------------------------------------------------------------------------- // // A value in a device has changed //----------------------------------------------------------------------------- void Value::OnValueChanged() { if (IsWriteOnly()) { return; } if (Driver* driver = Manager::Get()->GetDriver(m_id.GetHomeId())) { m_isSet = true; // Notify the watchers Notification* notification = new Notification(Notification::Type_ValueChanged); notification->SetValueId(m_id); driver->QueueNotification(notification); } /* Call Back to the Command Class that this Value has changed, so we can search the * TriggerRefreshValue vector to see if we should request any other values to be * refreshed. */ Node* node = NULL; if (Driver* driver = Manager::Get()->GetDriver(m_id.GetHomeId())) { node = driver->GetNodeUnsafe(m_id.GetNodeId()); if (node != NULL) { if (Internal::CC::CommandClass* cc = node->GetCommandClass(m_id.GetCommandClassId())) { cc->CheckForRefreshValues(this); } } } } //----------------------------------------------------------------------------- // // Static helper to get a genre enum from a string //----------------------------------------------------------------------------- OpenZWave::ValueID::ValueGenre Value::GetGenreEnumFromName(char const* _name) { ValueID::ValueGenre genre = ValueID::ValueGenre_System; if (_name) { for (int i = 0; i < (int) ValueID::ValueGenre_Count; ++i) { if (!strcmp(_name, c_genreName[i])) { genre = (ValueID::ValueGenre) i; break; } } } return genre; } //----------------------------------------------------------------------------- // // Static helper to get a genre enum as a string //----------------------------------------------------------------------------- char const* Value::GetGenreNameFromEnum(ValueID::ValueGenre _genre) { return c_genreName[_genre]; } //----------------------------------------------------------------------------- // // Static helper to get a type enum from a string //----------------------------------------------------------------------------- OpenZWave::ValueID::ValueType Value::GetTypeEnumFromName(char const* _name) { ValueID::ValueType type = ValueID::ValueType_Bool; if (_name) { for (int i = 0; i <= (int) ValueID::ValueType_Max; ++i) { if (!strcmp(_name, c_typeName[i])) { type = (ValueID::ValueType) i; break; } } } return type; } //----------------------------------------------------------------------------- // // Static helper to get a type enum as a string //----------------------------------------------------------------------------- char const* Value::GetTypeNameFromEnum(ValueID::ValueType _type) { if (_type > (int) ValueID::ValueType_Max) { Log::Write(LogLevel_Warning, "Value::GetTypeNameFromEnum is out of range: %d", (int) _type); return c_typeName[ValueID::ValueType_Max + 1]; } return c_typeName[_type]; } //----------------------------------------------------------------------------- // // Check a refreshed value //----------------------------------------------------------------------------- int Value::VerifyRefreshedValue( void* _originalValue, void* _checkValue, void* _newValue, void* _targetValue, ValueID::ValueType _type, int _originalValueLength, // = 0, int _checkValueLength, // = 0, int _newValueLength, // = 0, int _targetValueLength // = 0, ) { // TODO: this is pretty rough code, but it's reused by each value type. It would be // better if the actions were taken (m_value = _value, etc.) in this code rather than // in the calling routine as a result of the return value. In particular, it's messy // to be setting these values after the refesh or notification is sent. With some // focus on the actual variable storage, we should be able to accomplish this with // memory functions. It's really the strings that make things complicated(?). // if this is the first read of a value, assume it is valid (and notify as a change) if (!IsSet()) { Log::Write(LogLevel_Detail, m_id.GetNodeId(), "Initial read of value"); Value::OnValueChanged(); return 2; // confirmed change of value } else { switch (_type) { case ValueID::ValueType_Button: // Button is stored as a bool case ValueID::ValueType_Bool: // bool { Log::Write(LogLevel_Detail, m_id.GetNodeId(), "Value Updated: old value=%s, new value=%s, type=%s", *((bool*) _originalValue) ? "true" : "false", *((uint8*) _newValue) ? "true" : "false", GetTypeNameFromEnum(_type)); if (m_targetValueSet) Log::Write(LogLevel_Detail, m_id.GetNodeId(), "\tTarget Value is Set to %s", *((bool*) _targetValue) ? "true" : "false" ); break; } case ValueID::ValueType_Byte: // byte { Log::Write(LogLevel_Detail, m_id.GetNodeId(), "Value Updated: old value=%d, new value=%d, type=%s", *((uint8*) _originalValue), *((uint8*) _newValue), GetTypeNameFromEnum(_type)); if (m_targetValueSet) Log::Write(LogLevel_Detail, m_id.GetNodeId(), "\tTarget Value is Set to %d", *((uint8*) _targetValue)); break; } case ValueID::ValueType_Decimal: // decimal is stored as a string, so treat it as a string here case ValueID::ValueType_String: // string { Log::Write(LogLevel_Detail, m_id.GetNodeId(), "Value Updated: old value=%s, new value=%s, type=%s", ((string*) _originalValue)->c_str(), ((string*) _newValue)->c_str(), GetTypeNameFromEnum(_type)); if (m_targetValueSet) Log::Write(LogLevel_Detail, m_id.GetNodeId(), "\tTarget Value is Set to %d", *((string*) _targetValue)->c_str()); break; } case ValueID::ValueType_Short: // short { Log::Write(LogLevel_Detail, m_id.GetNodeId(), "Value Updated: old value=%d, new value=%d, type=%s", *((short*) _originalValue), *((short*) _newValue), GetTypeNameFromEnum(_type)); if (m_targetValueSet) Log::Write(LogLevel_Detail, m_id.GetNodeId(), "\tTarget Value is Set to %d", *((short*) _targetValue)); break; } case ValueID::ValueType_List: // List Type is treated as a int32 case ValueID::ValueType_Int: // int32 case ValueID::ValueType_BitSet: // BitSet { Log::Write(LogLevel_Detail, m_id.GetNodeId(), "Value Updated: old value=%d, new value=%d, type=%s", *((int32*) _originalValue), *((int32*) _newValue), GetTypeNameFromEnum(_type)); if (m_targetValueSet) Log::Write(LogLevel_Detail, m_id.GetNodeId(), "\tTarget Value is Set to %d", *((int32*) _targetValue)); break; } case ValueID::ValueType_Raw: // raw { Log::Write(LogLevel_Detail, m_id.GetNodeId(), "Value Updated: old value=%x, new value=%x, type=%s", _originalValue, _newValue, GetTypeNameFromEnum(_type)); if (m_targetValueSet) Log::Write(LogLevel_Detail, m_id.GetNodeId(), "\tTarget Value is Set to %x", _targetValue); break; } case ValueID::ValueType_Schedule: // Schedule Type { Log::Write(LogLevel_Detail, m_id.GetNodeId(), "Value Updated: old value=%s, new value=%s, type=%s", _originalValue, _newValue, GetTypeNameFromEnum(_type)); if (m_targetValueSet) Log::Write(LogLevel_Detail, m_id.GetNodeId(), "\tTarget Value is Set to %x", _targetValue); /* we cant support verifyChanges yet... so always unset this */ m_verifyChanges = false; break; } } } m_refreshTime = time( NULL); // update value refresh time /* if this is a Value that has a Target Value Set, then lets compare the reported value against the Target Value * and Trigger a Refresh (based on the Duration, if necessary) */ if (m_targetValueSet) { return CheckTargetValue(_newValue, _targetValue, _type, _newValueLength, _targetValueLength); } // check whether changes in this value should be verified (since some devices will report values that always // change, where confirming changes is difficult or impossible) Log::Write(LogLevel_Detail, m_id.GetNodeId(), "Changes to this value are %sverified", m_verifyChanges ? "" : "not "); // see if the value has changed (result is used whether checking change or not) bool bOriginalEqual = false; switch (_type) { case ValueID::ValueType_Decimal: // Decimal is stored as a string case ValueID::ValueType_String: // string bOriginalEqual = (strcmp(((string*) _originalValue)->c_str(), ((string*) _newValue)->c_str()) == 0); break; case ValueID::ValueType_Short: // short bOriginalEqual = (*((short*) _originalValue) == *((short*) _newValue)); break; case ValueID::ValueType_List: // List Type is treated as a int32 case ValueID::ValueType_Int: // int bOriginalEqual = (*((int32*) _originalValue) == *((int32*) _newValue)); break; case ValueID::ValueType_Byte: // uint8 bOriginalEqual = (*((uint8*) _originalValue) == *((uint8*) _newValue)); break; case ValueID::ValueType_Button: // Button is stored as a bool case ValueID::ValueType_Bool: // bool bOriginalEqual = (*((bool*) _originalValue) == *((bool*) _newValue)); break; case ValueID::ValueType_Raw: // raw bOriginalEqual = (_originalValueLength == _newValueLength); // first check length of arrays if (bOriginalEqual) bOriginalEqual = (memcmp(_originalValue, _newValue, _newValueLength) == 0); // if length is the same, then check content break; case ValueID::ValueType_Schedule: // Schedule /* Should not get here */ break; case ValueID::ValueType_BitSet: // BitSet bOriginalEqual = (((Bitfield *) _originalValue)->GetValue() == ((Bitfield *) _newValue)->GetValue()); break; } if (!m_verifyChanges) { if (bOriginalEqual) Value::OnValueRefreshed(); else Value::OnValueChanged(); return 2; // confirmed change of value } // if this is the first refresh of the value, test to see if the value has changed if (!IsCheckingChange()) { if (bOriginalEqual) { // values are the same, so signal a refresh and return Value::OnValueRefreshed(); return 0; // value hasn't changed } // values are different, so flag this as a verification refresh and queue it Log::Write(LogLevel_Info, m_id.GetNodeId(), "Changed value (possible)--rechecking"); SetCheckingChange(true); TimerThread::TimerCallback callback = bind(&Value::sendValueRefresh, this, 1); TimerSetEvent(250, callback, 1); return 1; // value has changed (to be confirmed) } else // IsCheckingChange is true if this is the second read of a potentially changed value { // if the second read is the same as the first read, the value really changed bool bCheckEqual = false; switch (_type) { case ValueID::ValueType_Decimal: // Decimal is stored as a string case ValueID::ValueType_String: // string bCheckEqual = (strcmp(((string*) _checkValue)->c_str(), ((string*) _newValue)->c_str()) == 0); break; case ValueID::ValueType_Short: // short bCheckEqual = (*((short*) _checkValue) == *((short*) _newValue)); break; case ValueID::ValueType_List: // List Type is treated as a int32 case ValueID::ValueType_Int: // int32 bCheckEqual = (*((int32*) _checkValue) == *((int32*) _newValue)); break; case ValueID::ValueType_Byte: // uint8 bCheckEqual = (*((uint8*) _checkValue) == *((uint8*) _newValue)); break; case ValueID::ValueType_Button: // Button is stored as a bool case ValueID::ValueType_Bool: // bool bCheckEqual = (*((bool*) _checkValue) == *((bool*) _newValue)); break; case ValueID::ValueType_Raw: bCheckEqual = (_checkValueLength == _newValueLength); // first check length of arrays if (bCheckEqual) bCheckEqual = (memcmp(_checkValue, _newValue, _newValueLength) == 0); // if length is the same, then check content break; case ValueID::ValueType_Schedule: /* Should not get here */ break; case ValueID::ValueType_BitSet: // BitSet bCheckEqual = (((Bitfield *) _checkValue)->GetValue() == ((Bitfield *) _newValue)->GetValue()); ; break; } if (bCheckEqual) { Log::Write(LogLevel_Info, m_id.GetNodeId(), "Changed value--confirmed"); SetCheckingChange(false); // update the saved value and send notification Value::OnValueChanged(); return 2; } // if the second read is the same as the original value, the first read is assumed to have been in error // log this situation, but don't change the value or send a ValueChanged Notification if (bOriginalEqual) { Log::Write(LogLevel_Info, m_id.GetNodeId(), "Spurious value change was noted."); SetCheckingChange(false); Value::OnValueRefreshed(); return 0; } // the second read is different than both the original value and the checked value...retry // keep trying until we get the same value twice Log::Write(LogLevel_Info, m_id.GetNodeId(), "Changed value (changed again)--rechecking"); SetCheckingChange(true); // save a temporary copy of value and re-read value from device //Manager::Get()->RefreshValue(GetID()); TimerThread::TimerCallback callback = bind(&Value::sendValueRefresh, this, 1); TimerSetEvent(250, callback, 1); return 1; } } std::string const Value::GetHelp() const { return Localization::Get()->GetValueHelp(m_id.GetNodeId(), m_id.GetCommandClassId(), m_id.GetIndex(), -1); } void Value::SetHelp(string const& _help, string const lang) { Localization::Get()->SetValueHelp(m_id.GetNodeId(), m_id.GetCommandClassId(), m_id.GetIndex(), -1, _help, lang); } std::string const Value::GetLabel() const { return Localization::Get()->GetValueLabel(m_id.GetNodeId(), m_id.GetCommandClassId(), m_id.GetIndex(), -1); } void Value::SetLabel(string const& _label, string const lang) { Localization::Get()->SetValueLabel(m_id.GetNodeId(), m_id.GetCommandClassId(), m_id.GetIndex(), -1, _label, lang); } //----------------------------------------------------------------------------- // // Check the reported value against the Target Value //----------------------------------------------------------------------------- int Value::CheckTargetValue(void* _newValue, void* _targetValue, ValueID::ValueType _type, int _newValueLength, int _targetValueLength) { // see if the value has changed (result is used whether checking change or not) bool bOriginalEqual = false; switch (_type) { case ValueID::ValueType_Decimal: // Decimal is stored as a string case ValueID::ValueType_String: // string bOriginalEqual = (strcmp(((string*) _targetValue)->c_str(), ((string*) _newValue)->c_str()) == 0); break; case ValueID::ValueType_Short: // short bOriginalEqual = (*((short*) _targetValue) == *((short*) _newValue)); break; case ValueID::ValueType_List: // List Type is treated as a int32 case ValueID::ValueType_Int: // int bOriginalEqual = (*((int32*) _targetValue) == *((int32*) _newValue)); break; case ValueID::ValueType_Byte: // uint8 bOriginalEqual = (*((uint8*) _targetValue) == *((uint8*) _newValue)); break; case ValueID::ValueType_Button: // Button is stored as a bool case ValueID::ValueType_Bool: // bool bOriginalEqual = (*((bool*) _targetValue) == *((bool*) _newValue)); break; case ValueID::ValueType_Raw: // raw bOriginalEqual = (_targetValueLength == _newValueLength); // first check length of arrays if (bOriginalEqual) bOriginalEqual = (memcmp(_targetValue, _newValue, _newValueLength) == 0); // if length is the same, then check content break; case ValueID::ValueType_Schedule: // Schedule /* Should not get here */ break; case ValueID::ValueType_BitSet: // BitSet bOriginalEqual = (((Bitfield *) _targetValue)->GetValue() == ((Bitfield *) _newValue)->GetValue()); break; } if (bOriginalEqual) { /* reset the Bool around TargetValueSet so we * can handle situations where Target Value is not supplied in the future */ m_targetValueSet = false; Value::OnValueChanged(); return 2; // confirmed change of value } /* They are not equal - So we need to issue a Get, But lets pace the timing of the Get based on Duration * - Caveat here is that if the outgoing queue is large, then this will be additionally delayed */ int32 timeout; if (m_duration <= 2) { timeout = 250; } else if (m_duration <= 5) { /* for Durations less than 5 seconds, lets refresh every 1/2 seconds */ timeout = 500; } else { /* Everything else is 1 second */ timeout = 1000; } TimerThread::TimerCallback callback = bind(&Value::sendValueRefresh, this, 1); TimerSetEvent(timeout, callback, 1); /* signal that the value hasn't changed */ return 0; } //----------------------------------------------------------------------------- // // Callback from the Timer to send a Get value to refresh a value from the // CheckTargetValue function //----------------------------------------------------------------------------- void Value::sendValueRefresh(uint32 _unused) { Log::Write(LogLevel_Info, m_id.GetNodeId(), "Sending Get to Refresh Value after Target Check"); if (Driver* driver = Manager::Get()->GetDriver(m_id.GetHomeId())) { Node* node = driver->GetNodeUnsafe(m_id.GetNodeId()); if (node != NULL) { if (Internal::CC::CommandClass* cc = node->GetCommandClass(m_id.GetCommandClassId())) { cc->RequestValue( 0, m_id.GetIndex(), m_id.GetInstance(), Driver::MsgQueue_Send ); } } } } } // namespace VC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/value_classes/ValueList.cpp0000644000175200017520000003476114032142455017551 00000000000000//----------------------------------------------------------------------------- // // ValueList.cpp // // Represents a list of items // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "tinyxml.h" #include "value_classes/ValueList.h" #include "Msg.h" #include "platform/Log.h" #include "Manager.h" #include "Localization.h" #include namespace OpenZWave { namespace Internal { namespace VC { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ValueList::ValueList(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, vector const& _items, int32 const _valueIdx, uint8 const _pollIntensity, uint8 const _size // = 4 ) : Value(_homeId, _nodeId, _genre, _commandClassId, _instance, _index, ValueID::ValueType_List, _label, _units, _readOnly, _writeOnly, false, _pollIntensity), m_items(_items), m_valueIdx(_valueIdx), m_valueIdxCheck(0), m_size(_size), m_targetValue(0) { for (vector::iterator it = m_items.begin(); it != m_items.end(); ++it) { /* first what is currently in m_label is the default text for a Item, so set it */ Localization::Get()->SetValueItemLabel(m_id.GetNodeId(), _commandClassId, _index, -1, it->m_value, it->m_label, ""); /* now set to the Localized Value */ it->m_label = Localization::Get()->GetValueItemLabel(m_id.GetNodeId(), _commandClassId, _index, -1, it->m_value); } } //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ValueList::ValueList() : Value(), m_items(), m_valueIdx(), m_valueIdxCheck(0), m_size(0) { } //----------------------------------------------------------------------------- // // Apply settings from XML //----------------------------------------------------------------------------- void ValueList::ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement) { Value::ReadXML(_homeId, _nodeId, _commandClassId, _valueElement); // Get size of values int intSize; if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("size", &intSize)) { if (intSize == 1 || intSize == 2 || intSize == 4) { m_size = intSize; } else { Log::Write(LogLevel_Warning, "Value size is invalid (%d). Only 1, 2 & 4 supported for node %d, class 0x%02x, instance %d, index %d - %s", intSize, _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex(), GetID().GetAsString().c_str()); } } else { Log::Write(LogLevel_Warning, "Value list size is not set, assuming 4 bytes for node %d, class 0x%02x, instance %d, index %d - %s", _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex(), GetID().GetAsString().c_str()); } TiXmlElement const* itemElement = _valueElement->FirstChildElement(); bool shouldclearlist = true; while (itemElement) { char const* str = itemElement->Value(); if (str && !strcmp(str, "Item")) { /* clear the existing list, if we have Item entries. (static list entries are created in the constructor * here, we load up any localized labels */ if (shouldclearlist) { m_items.clear(); shouldclearlist = false; } bool AddItem = true; char const* labelStr = itemElement->Attribute("label"); char const* lang = ""; if (itemElement->Attribute("lang")) { lang = itemElement->Attribute("lang"); AddItem = false; } else { AddItem = true; } int value = 0; if (itemElement->QueryIntAttribute("value", &value) != TIXML_SUCCESS) { Log::Write(LogLevel_Warning, "Item value %s is wrong type or does not exist in xml configuration for node %d, class 0x%02x, instance %d, index %d - %s", labelStr, _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex(), GetID().GetAsString().c_str()); } else if ((m_size == 1 && value > 255) || (m_size == 2 && value > 65535)) { Log::Write(LogLevel_Warning, "Item value %s is incorrect size in xml configuration for node %d, class 0x%02x, instance %d, index %d - %s", labelStr, _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex(), GetID().GetAsString().c_str()); } else { Localization::Get()->SetValueItemLabel(m_id.GetNodeId(), m_id.GetCommandClassId(), m_id.GetIndex(), -1, value, labelStr, lang); if (AddItem) { Item item; item.m_label = labelStr; item.m_value = value; m_items.push_back(item); } } } itemElement = itemElement->NextSiblingElement(); } /* setup any Localization now as we should have read all available languages already */ for (vector::iterator it = m_items.begin(); it != m_items.end(); ++it) { it->m_label = Localization::Get()->GetValueItemLabel(m_id.GetNodeId(), m_id.GetCommandClassId(), m_id.GetIndex(), -1, it->m_value); } // Set the value bool valSet = false; int intVal; m_valueIdx = 0; if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("value", &intVal)) { valSet = true; intVal = GetItemIdxByValue(intVal); if (intVal != -1) { m_valueIdx = (int32) intVal; } else { Log::Write(LogLevel_Warning, "Value is not found in xml configuration for node %d, class 0x%02x, instance %d, index %d - %s", _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex(), GetID().GetAsString().c_str()); } } // Set the index bool indSet = false; int intInd = 0; if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("vindex", &intInd)) { indSet = true; if (intInd >= 0 && intInd < (int32) m_items.size()) { m_valueIdx = (int32) intInd; } else { Log::Write(LogLevel_Warning, "Vindex is out of range for index in xml configuration for node %d, class 0x%02x, instance %d, index %d - %s", _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex(), GetID().GetAsString().c_str()); } } if (!valSet && !indSet) { Log::Write(LogLevel_Warning, "Missing default list value or vindex from xml configuration: node %d, class 0x%02x, instance %d, index %d - %s", _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex(), GetID().GetAsString().c_str()); } } //----------------------------------------------------------------------------- // // Write ourselves to an XML document //----------------------------------------------------------------------------- void ValueList::WriteXML(TiXmlElement* _valueElement) { Value::WriteXML(_valueElement); char str[16]; snprintf(str, sizeof(str), "%d", m_valueIdx); _valueElement->SetAttribute("vindex", str); snprintf(str, sizeof(str), "%d", m_size); _valueElement->SetAttribute("size", str); for (vector::iterator it = m_items.begin(); it != m_items.end(); ++it) { TiXmlElement* pItemElement = new TiXmlElement("Item"); pItemElement->SetAttribute("label", (*it).m_label.c_str()); snprintf(str, sizeof(str), "%d", (*it).m_value); pItemElement->SetAttribute("value", str); _valueElement->LinkEndChild(pItemElement); } } //----------------------------------------------------------------------------- // // Set a new value in the device, selected by item index //----------------------------------------------------------------------------- bool ValueList::SetByValue(int32 const _value) { // create a temporary copy of this value to be submitted to the Set() call and set its value to the function param ValueList* tempValue = new ValueList(*this); tempValue->m_valueIdx = _value; // Set the value in the device. bool ret = ((Value*) tempValue)->Set(); // clean up the temporary value delete tempValue; return ret; } //----------------------------------------------------------------------------- // // Set a new value in the device, selected by item label //----------------------------------------------------------------------------- bool ValueList::SetByLabel(string const& _label) { // Ensure the value is one of the options int index = GetItemIdxByLabel(_label); if (index < 0) { // Item not found Log::Write(LogLevel_Warning, "Attempt to Set a Invalid Label %s for ValueList in OnValueRefreshed %s", _label.c_str(), GetID().GetAsString().c_str()); return false; } return SetByValue(index); } //----------------------------------------------------------------------------- // // Set the Value Target (Used for Automatic Refresh) //----------------------------------------------------------------------------- void ValueList::SetTargetValue(int32 const _target, uint32 _duration) { m_targetValueSet = true; m_targetValue = _target; m_duration = _duration; } //----------------------------------------------------------------------------- // // A value in a device has been refreshed //----------------------------------------------------------------------------- void ValueList::OnValueRefreshed(int32 const _value) { // Ensure the value is one of the options int32 index = GetItemIdxByValue(_value); if (index < 0) { // Item not found Log::Write(LogLevel_Warning, "Attempt to Set a Invalid Index %d for ValueList in OnValueRefreshed %s", _value, GetID().GetAsString().c_str()); return; } switch (VerifyRefreshedValue((void*) &m_valueIdx, (void*) &m_valueIdxCheck, (void*) &index, (void*) &m_targetValue, ValueID::ValueType_List)) { case 0: // value hasn't changed, nothing to do break; case 1: // value has changed (not confirmed yet), save _value in m_valueCheck m_valueIdxCheck = index; break; case 2: // value has changed (confirmed), save _value in m_value m_valueIdx = index; break; case 3: // all three values are different, so wait for next refresh to try again break; } } //----------------------------------------------------------------------------- // // Get the index of an item from its label //----------------------------------------------------------------------------- int32 ValueList::GetItemIdxByLabel(string const& _label) const { for (int32 i = 0; i < (int32) m_items.size(); ++i) { if (_label == m_items[i].m_label) { return i; } } Log::Write(LogLevel_Warning, "Attempt to get a Invalid Label %s from ValueList %s", _label.c_str(), GetID().GetAsString().c_str()); return -1; } //----------------------------------------------------------------------------- // // Get the index of an item from its value //----------------------------------------------------------------------------- int32 ValueList::GetItemIdxByValue(int32 const _value) const { for (int32 i = 0; i < (int32) m_items.size(); ++i) { if (_value == m_items[i].m_value) { return i; } } Log::Write(LogLevel_Warning, "Attempt to get a Invalid Index %d on ValueList %s", _value, GetID().GetAsString().c_str()); return -1; } //----------------------------------------------------------------------------- // // Fill a vector with the item labels //----------------------------------------------------------------------------- bool ValueList::GetItemLabels(vector* o_items) { if (o_items) { for (vector::iterator it = m_items.begin(); it != m_items.end(); ++it) { o_items->push_back((*it).m_label); } return true; } Log::Write(LogLevel_Error, "o_items passed to ValueList::GetItemLabels is null: %s", GetID().GetAsString().c_str()); return false; } //----------------------------------------------------------------------------- // // Fill a vector with the item values //----------------------------------------------------------------------------- bool ValueList::GetItemValues(vector* o_values) { if (o_values) { for (vector::iterator it = m_items.begin(); it != m_items.end(); ++it) { o_values->push_back((*it).m_value); } return true; } Log::Write(LogLevel_Error, "o_values passed to ValueList::GetItemLabels is null: %s", GetID().GetAsString().c_str()); return false; } //----------------------------------------------------------------------------- // // Get the Item at the Currently selected Index //----------------------------------------------------------------------------- ValueList::Item const *ValueList::GetItem() const { try { /* very strange - We throw a exception if its out of range, but its not caught? */ if (m_items.size() < (uint32)m_valueIdx) { Log::Write(LogLevel_Warning, "Invalid Index Set on ValueList %s: %d", GetID().GetAsString().c_str(), m_valueIdx); return NULL; } return &m_items.at(m_valueIdx); } catch (std::out_of_range const& oor) { Log::Write(LogLevel_Warning, "Invalid Index Set on ValueList %s: %s", GetID().GetAsString().c_str(), oor.what()); return NULL; } } } // namespace VC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/value_classes/ValueInt.cpp0000644000175200017520000001323214032142455017356 00000000000000//----------------------------------------------------------------------------- // // ValueInt.cpp // // Represents a 32-bit value // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include "tinyxml.h" #include "value_classes/ValueInt.h" #include "Msg.h" #include "platform/Log.h" #include "Manager.h" #include namespace OpenZWave { namespace Internal { namespace VC { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ValueInt::ValueInt(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, int32 const _value, uint8 const _pollIntensity) : Value(_homeId, _nodeId, _genre, _commandClassId, _instance, _index, ValueID::ValueType_Int, _label, _units, _readOnly, _writeOnly, false, _pollIntensity), m_value(_value), m_valueCheck(0), m_targetValue(0) { m_min = INT_MIN; m_max = INT_MAX; } //----------------------------------------------------------------------------- // // Constructor (from XML) //----------------------------------------------------------------------------- ValueInt::ValueInt() : Value(), m_value(0), m_valueCheck(0) { m_min = INT_MIN; m_max = INT_MAX; } std::string const ValueInt::GetAsString() const { stringstream ss; ss << GetValue(); return ss.str(); } bool ValueInt::SetFromString(string const& _value) { int32 val = atoi(_value.c_str()); return Set(val); } //----------------------------------------------------------------------------- // // Apply settings from XML //----------------------------------------------------------------------------- void ValueInt::ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement) { Value::ReadXML(_homeId, _nodeId, _commandClassId, _valueElement); int intVal; if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("value", &intVal)) { m_value = (int32) intVal; } else { Log::Write(LogLevel_Info, "Missing default integer value from xml configuration: node %d, class 0x%02x, instance %d, index %d", _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex()); } } //----------------------------------------------------------------------------- // // Write ourselves to an XML document //----------------------------------------------------------------------------- void ValueInt::WriteXML(TiXmlElement* _valueElement) { Value::WriteXML(_valueElement); char str[16]; snprintf(str, sizeof(str), "%d", m_value); _valueElement->SetAttribute("value", str); } //----------------------------------------------------------------------------- // // Set a new value in the device //----------------------------------------------------------------------------- bool ValueInt::Set(int32 const _value) { // create a temporary copy of this value to be submitted to the Set() call and set its value to the function param ValueInt* tempValue = new ValueInt(*this); tempValue->m_value = _value; // Set the value in the device. bool ret = ((Value*) tempValue)->Set(); // clean up the temporary value delete tempValue; return ret; } //----------------------------------------------------------------------------- // // Set the Value Target (Used for Automatic Refresh) //----------------------------------------------------------------------------- void ValueInt::SetTargetValue(int32 const _target, uint32 _duration) { m_targetValueSet = true; m_targetValue = _target; m_duration = _duration; } //----------------------------------------------------------------------------- // // A value in a device has been refreshed //----------------------------------------------------------------------------- void ValueInt::OnValueRefreshed(int32 const _value) { switch (VerifyRefreshedValue((void*) &m_value, (void*) &m_valueCheck, (void*) &_value, (void *) &m_targetValue, ValueID::ValueType_Int)) { case 0: // value hasn't changed, nothing to do break; case 1: // value has changed (not confirmed yet), save _value in m_valueCheck m_valueCheck = _value; break; case 2: // value has changed (confirmed), save _value in m_value m_value = _value; break; case 3: // all three values are different, so wait for next refresh to try again break; } } } // namespace VC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/value_classes/ValueDecimal.cpp0000644000175200017520000001210314032142455020156 00000000000000//----------------------------------------------------------------------------- // // ValueDecimal.cpp // // Represents a value that may have a fractional component // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "tinyxml.h" #include "value_classes/ValueDecimal.h" #include "Msg.h" #include "platform/Log.h" #include "Manager.h" #include namespace OpenZWave { namespace Internal { namespace VC { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ValueDecimal::ValueDecimal(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, string const& _value, uint8 const _pollIntensity) : Value(_homeId, _nodeId, _genre, _commandClassId, _instance, _index, ValueID::ValueType_Decimal, _label, _units, _readOnly, _writeOnly, false, _pollIntensity), m_value(_value), m_valueCheck(""), m_newValue(""), m_precision(0), m_targetValue("") { } //----------------------------------------------------------------------------- // // Apply settings from XML //----------------------------------------------------------------------------- void ValueDecimal::ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement) { Value::ReadXML(_homeId, _nodeId, _commandClassId, _valueElement); char const* str = _valueElement->Attribute("value"); if (str) { m_value = str; } else { Log::Write(LogLevel_Info, "Missing default decimal value from xml configuration: node %d, class 0x%02x, instance %d, index %d", _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex()); } } //----------------------------------------------------------------------------- // // Write ourselves to an XML document //----------------------------------------------------------------------------- void ValueDecimal::WriteXML(TiXmlElement* _valueElement) { Value::WriteXML(_valueElement); _valueElement->SetAttribute("value", m_value.c_str()); } //----------------------------------------------------------------------------- // // Set a new value in the device //----------------------------------------------------------------------------- bool ValueDecimal::Set(string const& _value) { // create a temporary copy of this value to be submitted to the Set() call and set its value to the function param ValueDecimal* tempValue = new ValueDecimal(*this); tempValue->m_value = _value; // Set the value in the device. bool ret = ((Value*) tempValue)->Set(); // clean up the temporary value delete tempValue; return ret; } //----------------------------------------------------------------------------- // // Set the Value Target (Used for Automatic Refresh) //----------------------------------------------------------------------------- void ValueDecimal::SetTargetValue(string const _target, uint32 _duration) { m_targetValueSet = true; m_targetValue = _target; m_duration = _duration; } //----------------------------------------------------------------------------- // // A value in a device has been refreshed //----------------------------------------------------------------------------- void ValueDecimal::OnValueRefreshed(string const& _value) { switch (VerifyRefreshedValue((void*) &m_value, (void*) &m_valueCheck, (void*) &_value, (void *) &m_targetValue, ValueID::ValueType_Decimal)) { case 0: // value hasn't changed, nothing to do break; case 1: // value has changed (not confirmed yet), save _value in m_valueCheck m_valueCheck = _value; break; case 2: // value has changed (confirmed), save _value in m_value m_value = _value; break; case 3: // all three values are different, so wait for next refresh to try again break; } } } // namespace VC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/value_classes/ValueButton.h0000644000175200017520000000427714032142455017555 00000000000000//----------------------------------------------------------------------------- // // ValueButton.h // // Represents a write-only value that triggers activity in a device // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ValueButton_H #define _ValueButton_H #include #include "Defs.h" #include "value_classes/Value.h" class TiXmlElement; namespace OpenZWave { namespace Internal { namespace VC { /** \brief Button value * \ingroup ValueID */ class ValueButton: public Value { public: ValueButton(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, uint8 const _pollIntensity); ValueButton() : m_pressed(false) { } virtual ~ValueButton() { } bool PressButton(); bool ReleaseButton(); virtual string const GetAsString() const { return (IsPressed() ? "true" : "false"); } // From Value virtual void ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement); virtual void WriteXML(TiXmlElement* _valueElement); bool IsPressed() const { return m_pressed; } private: bool m_pressed; }; } // namespace VC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/value_classes/ValueShort.h0000644000175200017520000000473514032142455017400 00000000000000//----------------------------------------------------------------------------- // // ValueShort.h // // Represents a 16-bit value // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ValueShort_H #define _ValueShort_H #include #include "Defs.h" #include "value_classes/Value.h" class TiXmlElement; namespace OpenZWave { namespace Internal { namespace VC { /** \brief Short value sent to/received from a node. * \ingroup ValueID */ class ValueShort: public Value { public: ValueShort(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, int16 const _value, uint8 const _pollIntensity); ValueShort(); virtual ~ValueShort() { } bool Set(int16 const _value); void OnValueRefreshed(int16 const _value); void SetTargetValue(int16 const _target, uint32 _duration = 0); // From Value virtual string const GetAsString() const; virtual bool SetFromString(string const& _value); virtual void ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement); virtual void WriteXML(TiXmlElement* _valueElement); int16 GetValue() const { return m_value; } private: int16 m_value; // the current value int16 m_valueCheck; // the previous value (used for double-checking spurious value reads) int16 m_targetValue; // Target Value }; } // namespace VC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/value_classes/ValueBool.cpp0000644000175200017520000001236014032142455017520 00000000000000//----------------------------------------------------------------------------- // // ValueBool.cpp // // Represents a boolean value // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "tinyxml.h" #include "value_classes/ValueBool.h" #include "Driver.h" #include "Node.h" #include "platform/Log.h" #include "Manager.h" #include namespace OpenZWave { namespace Internal { namespace VC { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ValueBool::ValueBool(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, bool const _value, uint8 const _pollIntensity) : Value(_homeId, _nodeId, _genre, _commandClassId, _instance, _index, ValueID::ValueType_Bool, _label, _units, _readOnly, _writeOnly, false, _pollIntensity), m_value(_value), m_valueCheck(false), m_targetValue(false) { } bool ValueBool::SetFromString(string const& _value) { if (!strcasecmp("true", _value.c_str())) { return Set(true); } else if (!strcasecmp("false", _value.c_str())) { return Set(false); } return false; } //----------------------------------------------------------------------------- // // Apply settings from XML //----------------------------------------------------------------------------- void ValueBool::ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement) { Value::ReadXML(_homeId, _nodeId, _commandClassId, _valueElement); char const* str = _valueElement->Attribute("value"); if (str) { m_value = !strcmp(str, "True"); } else { Log::Write(LogLevel_Info, "Missing default boolean value from xml configuration: node %d, class 0x%02x, instance %d, index %d", _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex()); } } //----------------------------------------------------------------------------- // // Write ourselves to an XML document //----------------------------------------------------------------------------- void ValueBool::WriteXML(TiXmlElement* _valueElement) { Value::WriteXML(_valueElement); _valueElement->SetAttribute("value", m_value ? "True" : "False"); } //----------------------------------------------------------------------------- // // Set a new value in the device //----------------------------------------------------------------------------- bool ValueBool::Set(bool const _value) { // create a temporary copy of this value to be submitted to the Set() call and set its value to the function param ValueBool* tempValue = new ValueBool(*this); tempValue->m_value = _value; // Set the value in the device. bool ret = ((Value*) tempValue)->Set(); // clean up the temporary value delete tempValue; return ret; } //----------------------------------------------------------------------------- // // Set the Value Target (Used for Automatic Refresh) //----------------------------------------------------------------------------- void ValueBool::SetTargetValue(bool const _target, uint32 _duration) { m_targetValueSet = true; m_targetValue = _target; m_duration = _duration; } //----------------------------------------------------------------------------- // // A value in a device has been refreshed //----------------------------------------------------------------------------- void ValueBool::OnValueRefreshed(bool const _value) { switch (VerifyRefreshedValue((void*) &m_value, (void*) &m_valueCheck, (void*) &_value, (void *) &m_targetValue, ValueID::ValueType_Bool)) { case 0: // value hasn't changed, nothing to do break; case 1: // value has changed (not confirmed yet), save _value in m_valueCheck m_valueCheck = _value; break; case 2: // value has changed (confirmed), save _value in m_value m_value = _value; break; case 3: // all three values are different, so wait for next refresh to try again break; } } } // namespace VC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/value_classes/ValueByte.cpp0000644000175200017520000001325314032142455017532 00000000000000//----------------------------------------------------------------------------- // // ValueByte.cpp // // Represents an 8-bit value // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "tinyxml.h" #include "value_classes/ValueByte.h" #include "Msg.h" #include "platform/Log.h" #include "Manager.h" #include namespace OpenZWave { namespace Internal { namespace VC { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ValueByte::ValueByte(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _value, uint8 const _pollIntensity) : Value(_homeId, _nodeId, _genre, _commandClassId, _instance, _index, ValueID::ValueType_Byte, _label, _units, _readOnly, _writeOnly, false, _pollIntensity), m_value(_value), m_valueCheck(false), m_targetValue(0) { m_min = 0; m_max = 255; } //----------------------------------------------------------------------------- // // Constructor (from XML) //----------------------------------------------------------------------------- ValueByte::ValueByte() { m_min = 0; m_max = 255; } std::string const ValueByte::GetAsString() const { stringstream ss; ss << (uint32) GetValue(); return ss.str(); } bool ValueByte::SetFromString(string const& _value) { uint32 val = (uint32) atoi(_value.c_str()); if (val < 256) { return Set((uint8) val); } return false; } //----------------------------------------------------------------------------- // // Apply settings from XML //----------------------------------------------------------------------------- void ValueByte::ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement) { Value::ReadXML(_homeId, _nodeId, _commandClassId, _valueElement); int intVal; if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("value", &intVal)) { m_value = (uint8) intVal; } else { Log::Write(LogLevel_Info, "Missing default byte value from xml configuration: node %d, class 0x%02x, instance %d, index %d", _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex()); } } //----------------------------------------------------------------------------- // // Write ourselves to an XML document //----------------------------------------------------------------------------- void ValueByte::WriteXML(TiXmlElement* _valueElement) { Value::WriteXML(_valueElement); char str[8]; snprintf(str, sizeof(str), "%d", m_value); _valueElement->SetAttribute("value", str); } //----------------------------------------------------------------------------- // // Set a new value in the device //----------------------------------------------------------------------------- bool ValueByte::Set(uint8 const _value) { // create a temporary copy of this value to be submitted to the Set() call and set its value to the function param ValueByte* tempValue = new ValueByte(*this); tempValue->m_value = _value; // Set the value in the device. bool ret = ((Value*) tempValue)->Set(); // clean up the temporary value delete tempValue; return ret; } //----------------------------------------------------------------------------- // // Set the Value Target (Used for Automatic Refresh) //----------------------------------------------------------------------------- void ValueByte::SetTargetValue(uint8 const _target, uint32 _duration) { m_targetValueSet = true; m_targetValue = _target; m_duration = _duration; } //----------------------------------------------------------------------------- // // A value in a device has been refreshed //----------------------------------------------------------------------------- void ValueByte::OnValueRefreshed(uint8 const _value) { switch (VerifyRefreshedValue((void*) &m_value, (void*) &m_valueCheck, (void*) &_value, (void*) &m_targetValue, ValueID::ValueType_Byte)) { case 0: // value hasn't changed, nothing to do break; case 1: // value has changed (not confirmed yet), save _value in m_valueCheck m_valueCheck = _value; break; case 2: // value has changed (confirmed), save _value in m_value m_value = _value; break; case 3: // all three values are different, so wait for next refresh to try again break; } } } // namespace VC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/value_classes/ValueStore.h0000644000175200017520000000372714032142455017375 00000000000000//----------------------------------------------------------------------------- // // ValueStore.h // // Container for Value objects // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ValueStore_H #define _ValueStore_H #include #include "Defs.h" #include "value_classes/ValueID.h" class TiXmlElement; namespace OpenZWave { namespace Internal { namespace VC { class Value; /** \brief Container that holds all of the values associated with a given node. * \ingroup ValueID */ class ValueStore { public: typedef map::const_iterator Iterator; Iterator Begin() { return m_values.begin(); } Iterator End() { return m_values.end(); } ValueStore() { } ~ValueStore(); bool AddValue(Value* _value); bool RemoveValue(uint32 const& _key); Value* GetValue(uint32 const& _key) const; void RemoveCommandClassValues(uint8 const _commandClassId); // Remove all the values associated with a command class private: map m_values; }; } // namespace VC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/value_classes/ValueString.cpp0000644000175200017520000001203614032142455020073 00000000000000//----------------------------------------------------------------------------- // // ValueStore.cpp // // Represents a string value // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "tinyxml.h" #include "value_classes/ValueString.h" #include "Msg.h" #include "platform/Log.h" #include "Manager.h" namespace OpenZWave { namespace Internal { namespace VC { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ValueString::ValueString(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, string const& _value, uint8 const _pollIntensity) : Value(_homeId, _nodeId, _genre, _commandClassId, _instance, _index, ValueID::ValueType_String, _label, _units, _readOnly, _writeOnly, false, _pollIntensity), m_value(_value), m_valueCheck(""), m_newValue(""), m_targetValue("") { } //----------------------------------------------------------------------------- // // Apply settings from XML //----------------------------------------------------------------------------- void ValueString::ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement) { Value::ReadXML(_homeId, _nodeId, _commandClassId, _valueElement); char const* str = _valueElement->Attribute("value"); if (str) { m_value = str; } else { Log::Write(LogLevel_Alert, "Missing default string value from xml configuration: node %d, class 0x%02x, instance %d, index %d", _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex()); } } //----------------------------------------------------------------------------- // // Write ourselves to an XML document //----------------------------------------------------------------------------- void ValueString::WriteXML(TiXmlElement* _valueElement) { Value::WriteXML(_valueElement); _valueElement->SetAttribute("value", m_value.c_str()); } //----------------------------------------------------------------------------- // // Set a new value in the device and queue a "RequestValue" to confirm it worked //----------------------------------------------------------------------------- bool ValueString::Set(string const& _value) { // create a temporary copy of this value to be submitted to the Set() call and set its value to the function param ValueString* tempValue = new ValueString(*this); tempValue->m_value = _value; // Set the value in the device. bool ret = ((Value*) tempValue)->Set(); // clean up the temporary value delete tempValue; return ret; } //----------------------------------------------------------------------------- // // Set the Value Target (Used for Automatic Refresh) //----------------------------------------------------------------------------- void ValueString::SetTargetValue(string const _target, uint32 _duration) { m_targetValueSet = true; m_targetValue = _target; m_duration = _duration; } //----------------------------------------------------------------------------- // // A value in a device has been refreshed //----------------------------------------------------------------------------- void ValueString::OnValueRefreshed(string const& _value) { switch (VerifyRefreshedValue((void*) &m_value, (void*) &m_valueCheck, (void*) &_value, (void *) &m_targetValue, ValueID::ValueType_String)) { case 0: // value hasn't changed, nothing to do break; case 1: // value has changed (not confirmed yet), save _value in m_valueCheck m_valueCheck = _value; break; case 2: // value has changed (confirmed), save _value in m_value m_value = _value; break; case 3: // all three values are different, so wait for next refresh to try again break; } } } // namespace VC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/value_classes/ValueShort.cpp0000644000175200017520000001341214032142455017723 00000000000000//----------------------------------------------------------------------------- // // ValueShort.cpp // // Represents a 16-bit value // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include "tinyxml.h" #include "value_classes/ValueShort.h" #include "Msg.h" #include "platform/Log.h" #include "Manager.h" #include namespace OpenZWave { namespace Internal { namespace VC { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ValueShort::ValueShort(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, int16 const _value, uint8 const _pollIntensity) : Value(_homeId, _nodeId, _genre, _commandClassId, _instance, _index, ValueID::ValueType_Short, _label, _units, _readOnly, _writeOnly, false, _pollIntensity), m_value(_value), m_valueCheck(0), m_targetValue(0) { m_min = SHRT_MIN; m_max = SHRT_MAX; } //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ValueShort::ValueShort() : Value(), m_value(0), m_valueCheck(0) { m_min = SHRT_MIN; m_max = SHRT_MAX; } std::string const ValueShort::GetAsString() const { stringstream ss; ss << GetValue(); return ss.str(); } bool ValueShort::SetFromString(string const& _value) { uint32 val = (uint32) atoi(_value.c_str()); if (val < 32768) { return Set((int16) val); } return false; } //----------------------------------------------------------------------------- // // Apply settings from XML //----------------------------------------------------------------------------- void ValueShort::ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement) { Value::ReadXML(_homeId, _nodeId, _commandClassId, _valueElement); int intVal; if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("value", &intVal)) { m_value = (int16) intVal; } else { Log::Write(LogLevel_Info, "Missing default short value from xml configuration: node %d, class 0x%02x, instance %d, index %d", _nodeId, _commandClassId, GetID().GetInstance(), GetID().GetIndex()); } } //----------------------------------------------------------------------------- // // Write ourselves to an XML document //----------------------------------------------------------------------------- void ValueShort::WriteXML(TiXmlElement* _valueElement) { Value::WriteXML(_valueElement); char str[16]; snprintf(str, sizeof(str), "%d", m_value); _valueElement->SetAttribute("value", str); } //----------------------------------------------------------------------------- // // Set a new value in the device //----------------------------------------------------------------------------- bool ValueShort::Set(int16 const _value) { // create a temporary copy of this value to be submitted to the Set() call and set its value to the function param ValueShort* tempValue = new ValueShort(*this); tempValue->m_value = _value; // Set the value in the device. bool ret = ((Value*) tempValue)->Set(); // clean up the temporary value delete tempValue; return ret; } //----------------------------------------------------------------------------- // // Set the Value Target (Used for Automatic Refresh) //----------------------------------------------------------------------------- void ValueShort::SetTargetValue(int16 const _target, uint32 _duration) { m_targetValueSet = true; m_targetValue = _target; m_duration = _duration; } //----------------------------------------------------------------------------- // // A value in a device has been refreshed //----------------------------------------------------------------------------- void ValueShort::OnValueRefreshed(int16 const _value) { switch (VerifyRefreshedValue((void*) &m_value, (void*) &m_valueCheck, (void*) &_value, (void *) &m_targetValue, ValueID::ValueType_Short)) { case 0: // value hasn't changed, nothing to do break; case 1: // value has changed (not confirmed yet), save _value in m_valueCheck m_valueCheck = _value; break; case 2: // value has changed (confirmed), save _value in m_value m_value = _value; break; case 3: // all three values are different, so wait for next refresh to try again break; } } } // namespace VC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/value_classes/ValueString.h0000644000175200017520000000523014032142455017536 00000000000000//----------------------------------------------------------------------------- // // ValueString.h // // Represents a string value // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ValueString_H #define _ValueString_H #include #include "Defs.h" #include "value_classes/Value.h" class TiXmlElement; namespace OpenZWave { namespace Internal { namespace VC { /** \brief String value sent to/received from a node. * \ingroup ValueID */ class ValueString: public Value { public: ValueString(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, string const& _value, uint8 const _pollIntensity); ValueString() { } virtual ~ValueString() { } bool Set(string const& _value); void OnValueRefreshed(string const& _value); void SetTargetValue(string const _target, uint32 _duration = 0); // From Value virtual string const GetAsString() const { return GetValue(); } virtual bool SetFromString(string const& _value) { return Set(_value); } virtual void ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement); virtual void WriteXML(TiXmlElement* _valueElement); string GetValue() const { return m_value; } private: string m_value; // the current value string m_valueCheck; // the previous value (used for double-checking spurious value reads) string m_newValue; // a new value to be set on the appropriate device string m_targetValue; // Target Value }; } // namespace VC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/value_classes/ValueSchedule.h0000644000175200017520000000537514032142455020036 00000000000000//----------------------------------------------------------------------------- // // ValueSchedule.h // // A one day schedule for the Climate Control Schedule command class // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ValueSchedule_H #define _ValueSchedule_H #include #include "Defs.h" #include "value_classes/Value.h" class TiXmlElement; namespace OpenZWave { namespace Internal { namespace VC { /** \brief Schedule sent to/received from a node. * \ingroup ValueID */ class ValueSchedule: public Value { public: ValueSchedule(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _pollIntensity); ValueSchedule(); virtual ~ValueSchedule() { } bool SetSwitchPoint(uint8 const _hours, uint8 const _minutes, int8 const _setback); bool RemoveSwitchPoint(uint8 const _idx); void ClearSwitchPoints() { m_numSwitchPoints = 0; } bool GetSwitchPoint(uint8 const _idx, uint8* o_hours, uint8* o_minutes, int8* o_setback) const; bool FindSwitchPoint(uint8 const _hours, uint8 const _minutes, uint8* o_idx) const; uint8 GetNumSwitchPoints() const { return m_numSwitchPoints; } bool Set(); void OnValueRefreshed(); virtual string const GetAsString() const; // From Value virtual void ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement); virtual void WriteXML(TiXmlElement* _valueElement); private: struct SwitchPoint { uint8 m_hours; uint8 m_minutes; int8 m_setback; }; SwitchPoint m_switchPoints[9]; uint8 m_numSwitchPoints; }; } // namespace VC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/value_classes/ValueID.h0000644000175200017520000003076414032142455016576 00000000000000//----------------------------------------------------------------------------- // // ValueID.h // // Unique identifier for a Value object // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ValueID_H #define _ValueID_H #include #include #include "ValueIDIndexes.h" #include "Defs.h" class TiXmlElement; namespace OpenZWave { namespace Internal { namespace VC { class Value; class ValueStore; } ; } ; /** \defgroup ValueID ValueID Support * * ValueID's in OZW expose device functionality to the application. Many different * types of ValueID's are exposed, and they represent the state of a device (such as a * switch on or off) or configuration parameters of a device. */ /** \brief Provides a unique ID for a value reported by a Z-Wave device. * \ingroup ValueID * * The ValueID is used to uniquely identify a value reported by a * Z-Wave device. *

* The ID is built by packing various identifying characteristics into a single * 32-bit number - the Z-Wave driver index, device node ID, the command class and * command class instance that handles the value, plus an index for the value * to distinguish it among all the other values managed by that command class * instance. The type (bool, byte, string etc) of the value is also stored. *

* The packing of the ID is such that a list of Values sorted by ValueID * will be in a sensible order for display to the user. */ class OPENZWAVE_EXPORT ValueID { public: /** * Value Genres * The classification of a value to enable low level system or configuration parameters to be filtered by the application. * \see GetGenre */ enum ValueGenre { ValueGenre_Basic = 0, /**< The 'level' as controlled by basic commands. Usually duplicated by another command class. */ ValueGenre_User, /**< Basic values an ordinary user would be interested in. */ ValueGenre_Config, /**< Device-specific configuration parameters. These cannot be automatically discovered via Z-Wave, and are usually described in the user manual instead. */ ValueGenre_System, /**< Values of significance only to users who understand the Z-Wave protocol */ ValueGenre_Count /**< A count of the number of genres defined. Not to be used as a genre itself. */ }; /** * Value Types * The type of data represented by the value object. * \see GetType */ enum ValueType { ValueType_Bool = 0, /**< Boolean, true or false */ ValueType_Byte, /**< 8-bit unsigned value */ ValueType_Decimal, /**< Represents a non-integer value as a string, to avoid floating point accuracy issues. */ ValueType_Int, /**< 32-bit signed value */ ValueType_List, /**< List from which one item can be selected */ ValueType_Schedule, /**< Complex type used with the Climate Control Schedule command class */ ValueType_Short, /**< 16-bit signed value */ ValueType_String, /**< Text string */ ValueType_Button, /**< A write-only value that is the equivalent of pressing a button to send a command to a device */ ValueType_Raw, /**< A collection of bytes */ ValueType_BitSet, /**< A collection of Bits */ ValueType_Max = ValueType_BitSet /**< The highest-number type defined. Not to be used as a type itself. */ }; /** * Get the Home ID of the driver that controls the node containing the value. * \return the Home ID. */ uint32 GetHomeId() const { return m_homeId; } /** * Get the Home ID of the driver that controls the node containing the value. * \return the node id. */ uint8 GetNodeId() const { return ((uint8) ((m_id & 0xff000000) >> 24)); } /** * Get the genre of the value. The genre classifies a value to enable * low-level system or configuration parameters to be filtered out by the application * \return the value's genre. * \see ValueGenre */ ValueGenre GetGenre() const { return ((ValueGenre) ((m_id & 0x00c00000) >> 22)); } /** * Get the genre of the value as a String. The genre classifies a value to enable * low-level system or configuration parameters to be filtered out by the application * \return the value's genre. * \see ValueGenre, ValueID::GetGenre */ string GetGenreAsString() const; /** * Get the Z-Wave command class that created and manages this value. Knowledge of * command classes is not required to use OpenZWave, but this information is * exposed in case it is of interest. * \return the value's command class. */ uint8 GetCommandClassId() const { return ((uint8) ((m_id & 0x003fc000) >> 14)); } /** * Get the command class instance of this value. It is possible for there to be * multiple instances of a command class, although currently it appears that * only the SensorMultilevel command class ever does this. Knowledge of * instances and command classes is not required to use OpenZWave, but this * information is exposed in case it is of interest. * \return the instance of the value's command class. */ uint8 GetInstance() const { return ((uint8) (((m_id & 0xff0)) >> 4)); } /** * Get the value index. The index is used to identify one of multiple * values created and managed by a command class. In the case of configurable * parameters (handled by the configuration command class), the index is the * same as the parameter ID. Knowledge of command classes is not required * to use OpenZWave, but this information is exposed in case it is of interest. * \return the value index within the command class. */ uint16 GetIndex() const { return ((uint16) ((m_id1 & 0xFFFF0000) >> 16)); } /** * Get the type of the value. The type describes the data held by the value * and enables the user to select the correct value accessor method in the * Manager class. * \return the value's type. * \see ValueType, Manager::GetValueAsBool, Manager::GetValueAsByte, Manager::GetValueAsFloat, Manager::GetValueAsInt, Manager::GetValueAsShort, Manager::GetValueAsString, Manager::GetValueListSelection. */ ValueType GetType() const { return ((ValueType) (m_id & 0x0000000f)); } /** * Get the type of the value as a String. The type describes the data held by the value * and enables the user to select the correct value accessor method in the * Manager class. * \return the value's type. * \see ValueType, Manager::GetValueAsBool, Manager::GetValueAsByte, Manager::GetValueAsFloat, Manager::GetValueAsInt, Manager::GetValueAsShort, Manager::GetValueAsString, Manager::GetValueListSelection, ValueID::GetType */ string GetTypeAsString() const; /** * Get a 64Bit Integer that represents this ValueID. This Integer is not guaranteed to be the same * across restarts of OpenZWave. * \return a uint64 integer */ uint64 GetId() const { return (uint64) (((uint64) m_id1 << 32) | m_id); } /** * GetAsString returns a string representing the ValueID in human readable form * \return a std::string */ string const GetAsString() const; // Comparison Operators bool operator ==(ValueID const& _other) const { return ((m_homeId == _other.m_homeId) && (m_id == _other.m_id) && (m_id1 == _other.m_id1)); } bool operator !=(ValueID const& _other) const { return ((m_homeId != _other.m_homeId) || (m_id != _other.m_id) || (m_id1 != _other.m_id1)); } bool operator <(ValueID const& _other) const { if (m_homeId == _other.m_homeId) { if (m_id == _other.m_id) { return (m_id1 < _other.m_id1); } else { return (m_id < _other.m_id); } } else { return (m_homeId < _other.m_homeId); } } bool operator >(ValueID const& _other) const { if (m_homeId == _other.m_homeId) { if (m_id == _other.m_id) { return (m_id1 > _other.m_id1); } else { return (m_id > _other.m_id); } } else { return (m_homeId > _other.m_homeId); } } /** * Construct a value ID from its component parts. * This method is public only to allow ValueIDs to be saved and recreated by the application. * Only ValueIDs that have been reported by OpenZWave notifications should ever be used. * \param _homeId Home ID of the PC Z-Wave Controller that manages the device. * \param _nodeId Node ID of the device reporting the value. * \param _genre classification of the value to enable low level system or configuration parameters to be filtered out. * \param _commandClassId ID of command class that creates and manages this value. * \param _instance Instance index of the command class. * \param _valueIndex Index of the value within all the values created by the command class instance. * \param _type Type of value (bool, byte, string etc). * \return The ValueID. * \see ValueID */ ValueID(uint32 const _homeId, uint8 const _nodeId, ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, ValueType const _type) : m_homeId(_homeId) { m_id = (((uint32) _nodeId) << 24) | (((uint32) _genre) << 22) | (((uint32) _commandClassId) << 14) | (((uint32) (_instance & 0xFF)) << 4) | ((uint32) _type); m_id1 = (((uint32) _valueIndex) << 16); } /* construct a ValueID based on the HomeID and the unit64 returned from GetID * \param _homeId - The HomeID * \param id - The ID returned from ValueID::GetID * \see ValueID::GetId */ ValueID(uint32 _homeId, uint64 id) : m_homeId(_homeId) { m_id = ((uint32) (id & 0xFFFFFFFF)); m_id1 = (uint32) (id >> 32); } // Construct a value id for use in notifications ValueID(uint32 const _homeId, uint8 const _nodeId) : m_id1(0), m_homeId(_homeId) { m_id = ((uint32) _nodeId) << 24; } ValueID(uint32 const _homeId, uint8 const _nodeId, uint32 const _instance) : m_homeId(_homeId) { m_id = (((uint32) _nodeId) << 24) | (((uint32) _instance) << 4); m_id1 = 0; } // Default constructor ValueID() : m_id(0), m_id1(0), m_homeId(0) { } // Not all parts of the ValueID are necessary to uniquely identify the value. In the case of a // Node's ValueStore, we can ignore the home ID, node ID, genre and type and still be left with // a unique integer than can be used as a key to look up values. The two GetValueStoreKey methods // below are helpers to enable command classes to easily access their values from the ValueStore. // Get the key from our own m_id uint32 GetValueStoreKey() const { /* 0xIIIICCii * I = Index * C = CC * i = Instance */ /* CC Index Instance */ return (((m_id & 0x003fc000) >> 6) | (m_id1 & 0xffff0000) | ((m_id & 0xFF0) >> 4)); } // Generate a key from its component parts static uint32 GetValueStoreKey(uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex) { uint32 key = (((uint32) _instance)) | (((uint32) _commandClassId) << 8) | (((uint32) (_valueIndex & 0xFFFF)) << 16); return key; } private: // ID Packing: // Bits // 24-31: 8 bits. Node ID of device // 22-23: 2 bits. genre of value (see ValueGenre enum). // 14-21: 8 bits. ID of command class that created and manages this value. // 12-13 Unused. // 04-11: 8 bits. Instance of the Value // 00-03: 4 bits. Type of value (bool, byte, string etc). uint32 m_id; // ID1 Packing: // Bits // 16-31 16 bits. Instance Index of the command class. uint32 m_id1; // Unique PC interface identifier uint32 m_homeId; }; } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/value_classes/ValueSchedule.cpp0000644000175200017520000002361514032142455020366 00000000000000//----------------------------------------------------------------------------- // // ValueSchedule.cpp // // A one day schedule for the Climate Control Schedule command class // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include "tinyxml.h" #include "value_classes/ValueSchedule.h" #include "Msg.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace VC { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ValueSchedule::ValueSchedule(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _pollIntensity) : Value(_homeId, _nodeId, _genre, _commandClassId, _instance, _index, ValueID::ValueType_Schedule, _label, _units, _readOnly, _writeOnly, false, _pollIntensity), m_numSwitchPoints(0) { } //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ValueSchedule::ValueSchedule() : Value(), m_numSwitchPoints(0) { } //----------------------------------------------------------------------------- // // Apply settings from XML //----------------------------------------------------------------------------- void ValueSchedule::ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement) { Value::ReadXML(_homeId, _nodeId, _commandClassId, _valueElement); // Read in the switch points TiXmlElement const* child = _valueElement->FirstChildElement(); while (child) { char const* str = child->Value(); if (str) { if (!strcmp(str, "SwitchPoint")) { int intVal; uint8 hours = 0; if (TIXML_SUCCESS == child->QueryIntAttribute("hours", &intVal)) { hours = (uint8) intVal; } uint8 minutes = 0; if (TIXML_SUCCESS == child->QueryIntAttribute("minutes", &intVal)) { minutes = (uint8) intVal; } int8 setback = 0; if (TIXML_SUCCESS == child->QueryIntAttribute("setback", &intVal)) { setback = (int8) intVal; } SetSwitchPoint(hours, minutes, setback); } } child = child->NextSiblingElement(); } } //----------------------------------------------------------------------------- // // Write ourselves to an XML document //----------------------------------------------------------------------------- void ValueSchedule::WriteXML(TiXmlElement* _valueElement) { Value::WriteXML(_valueElement); for (uint8 i = 0; i < GetNumSwitchPoints(); ++i) { uint8 hours; uint8 minutes; int8 setback; if (GetSwitchPoint(i, &hours, &minutes, &setback)) { char str[8]; TiXmlElement* switchPointElement = new TiXmlElement("SwitchPoint"); _valueElement->LinkEndChild(switchPointElement); snprintf(str, sizeof(str), "%d", hours); switchPointElement->SetAttribute("hours", str); snprintf(str, sizeof(str), "%d", minutes); switchPointElement->SetAttribute("minutes", str); snprintf(str, sizeof(str), "%d", setback); switchPointElement->SetAttribute("setback", str); } } } //----------------------------------------------------------------------------- // // Set a new value in the device //----------------------------------------------------------------------------- bool ValueSchedule::Set() { // Set the value in the device. // TODO this needs to be checked to make sure it works as intended return Value::Set(); } //----------------------------------------------------------------------------- // // A value in a device has been refreshed //----------------------------------------------------------------------------- void ValueSchedule::OnValueRefreshed() { /* Value::VerifyRefreshedValue doesn't handle Schedule Properly yet, but still do this so we can do it eventually */ switch (VerifyRefreshedValue((void*) "Schedule", (void*) "Schedule", (void*) "Schedule", (void *) "Schedule", ValueID::ValueType_Schedule)) { case 0: // value hasn't changed, nothing to do break; case 1: // value has changed (not confirmed yet), save _value in m_valueCheck break; case 2: // value has changed (confirmed), save _value in m_value break; case 3: // all three values are different, so wait for next refresh to try again break; } } //----------------------------------------------------------------------------- // // A value in a device has changed //----------------------------------------------------------------------------- bool ValueSchedule::SetSwitchPoint(uint8 const _hours, uint8 const _minutes, int8 const _setback) { // Find where to insert this switch point. They must be sorted by ascending time value. uint8 i; uint8 insertAt = 0; for (i = 0; i < m_numSwitchPoints; ++i) { if (m_switchPoints[i].m_hours == _hours) { if (m_switchPoints[i].m_minutes == _minutes) { // There is already a switch point with this time, so we // just update its setback value m_switchPoints[i].m_setback = _setback; return true; } if (m_switchPoints[i].m_minutes > _minutes) { break; } } else if (m_switchPoints[i].m_hours > _hours) { break; } ++insertAt; } if (m_numSwitchPoints >= 9) { // The schedule is full return false; } // Shuffle any later switch points out of the way for (i = m_numSwitchPoints; i > insertAt; --i) { m_switchPoints[i].m_hours = m_switchPoints[i - 1].m_hours; m_switchPoints[i].m_minutes = m_switchPoints[i - 1].m_minutes; m_switchPoints[i].m_setback = m_switchPoints[i - 1].m_setback; } // Insert the new switch point m_switchPoints[insertAt].m_hours = _hours; m_switchPoints[insertAt].m_minutes = _minutes; m_switchPoints[insertAt].m_setback = _setback; ++m_numSwitchPoints; return true; } //----------------------------------------------------------------------------- // // A value in a device has changed //----------------------------------------------------------------------------- bool ValueSchedule::RemoveSwitchPoint(uint8 const _idx) { if (_idx >= m_numSwitchPoints) { // _idx is out of range return false; } // Shuffle any later switch points down to fill the gap for (uint8 i = _idx; i < (m_numSwitchPoints - 1); ++i) { m_switchPoints[i].m_hours = m_switchPoints[i + 1].m_hours; m_switchPoints[i].m_minutes = m_switchPoints[i + 1].m_minutes; m_switchPoints[i].m_setback = m_switchPoints[i + 1].m_setback; } --m_numSwitchPoints; return true; } //----------------------------------------------------------------------------- // // Get the values of a switch point //----------------------------------------------------------------------------- bool ValueSchedule::GetSwitchPoint(uint8 const _idx, uint8* o_hours, uint8* o_minutes, int8* o_setback) const { if (_idx >= m_numSwitchPoints) { // _idx is out of range return false; } if (o_hours) { *o_hours = m_switchPoints[_idx].m_hours; } if (o_minutes) { *o_minutes = m_switchPoints[_idx].m_minutes; } if (o_setback) { *o_setback = m_switchPoints[_idx].m_setback; } return true; } //----------------------------------------------------------------------------- // // Get the index of the switch point at the specified time //----------------------------------------------------------------------------- bool ValueSchedule::FindSwitchPoint(uint8 const _hours, uint8 const _minutes, uint8* o_idx) const { for (uint8 i = 0; i < m_numSwitchPoints; ++i) { if (m_switchPoints[i].m_hours == _hours) { if (m_switchPoints[i].m_minutes == _minutes) { // Found a match if (o_idx) { *o_idx = i; } return true; } if (m_switchPoints[i].m_minutes > _minutes) { // Gone past any possible match return false; } } else if (m_switchPoints[i].m_hours > _hours) { // Gone past any possible match return false; } } // No match found return false; } std::string const ValueSchedule::GetAsString() const { /* we should actuall find a way to return the arrays of switchpoints nicely */ return "SwitchPoint"; } } // namespace VC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/value_classes/ValueDecimal.h0000644000175200017520000000563714032142455017641 00000000000000//----------------------------------------------------------------------------- // // ValueDecimal.h // // Represents a value that may have a fractional component // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ValueDecimal_H #define _ValueDecimal_H #include #include "Defs.h" #include "value_classes/Value.h" class TiXmlElement; namespace OpenZWave { namespace Internal { namespace VC { /** \brief Decimal value sent to/received from a node. * \ingroup ValueID */ class ValueDecimal: public Value { public: ValueDecimal(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, string const& _value, uint8 const _pollIntensity); ValueDecimal() : m_precision(0) { } virtual ~ValueDecimal() { } bool Set(string const& _value); void OnValueRefreshed(string const& _value); void SetTargetValue(string const _target, uint32 _duration = 0); // From Value virtual string const GetAsString() const { return GetValue(); } virtual bool SetFromString(string const& _value) { return Set(_value); } virtual void ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement); virtual void WriteXML(TiXmlElement* _valueElement); string GetValue() const { return m_value; } uint8 GetPrecision() const { return m_precision; } void SetPrecision(uint8 _precision) { m_precision = _precision; } private: string m_value; // the current value string m_valueCheck; // the previous value (used for double-checking spurious value reads) string m_newValue; // a new value to be set on the appropriate device uint8 m_precision; string m_targetValue; // Target Value if supported. }; } // namespace VC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/value_classes/ValueRaw.h0000644000175200017520000000546014032142455017026 00000000000000//----------------------------------------------------------------------------- // // ValueRaw.h // // Represents a collection of 8-bit values // // Copyright (c) 2013 Greg Satz // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ValueRaw_H #define _ValueRaw_H #include #include "Defs.h" #include "value_classes/Value.h" class TiXmlElement; namespace OpenZWave { namespace Internal { namespace VC { /** \brief A collection of bytes sent to/received from a node. * \ingroup ValueID */ class ValueRaw: public Value { public: ValueRaw(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const* _value, uint8 const _length, uint8 const _pollIntensity); ValueRaw(); virtual ~ValueRaw(); bool Set(uint8 const* _value, uint8 const _length); void OnValueRefreshed(uint8 const* _value, uint8 const _length); void SetTargetValue(uint8 const* _target, uint8 const _length, int32 _duration = 0); // From Value virtual string const GetAsString() const; virtual bool SetFromString(string const& _value); virtual void ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement); virtual void WriteXML(TiXmlElement* _valueElement); uint8* GetValue() const { return m_value; } uint8 GetLength() const { return m_valueLength; } private: uint8* m_value; // the current value uint8 m_valueLength; // fixed length for this instance uint8* m_valueCheck; // the previous value (used for double-checking spurious value reads) uint8 m_valueCheckLength; // m_valueCheck array length uint8* m_targetValue; // Target Value uint8 m_targetValueLength; // Target Value Array Length }; } // namespace VC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/value_classes/ValueList.h0000644000175200017520000000627414032142455017214 00000000000000//----------------------------------------------------------------------------- // // ValueList.h // // Represents a list of items // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ValueList_H #define _ValueList_H #include #include #include "Defs.h" #include "value_classes/Value.h" class TiXmlElement; namespace OpenZWave { namespace Internal { namespace VC { /** \brief List of values sent to/received from a node. * \ingroup ValueID */ class ValueList: public Value { public: /** \brief An item (element) in the list of values. */ struct Item { string m_label; int32 m_value; }; ValueList(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, vector const& _items, int32 const _valueIdx, uint8 const _pollIntensity, uint8 const _size = 4); ValueList(); virtual ~ValueList() { } bool SetByLabel(string const& _label); bool SetByValue(int32 const _value); void OnValueRefreshed(int32 const _valueIdx); // From Value virtual string const GetAsString() const { return GetItem()->m_label; } virtual bool SetFromString(string const& _value) { return SetByLabel(_value); } void SetTargetValue(int32 const _target, uint32 _duration = 0); virtual void ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement); virtual void WriteXML(TiXmlElement* _valueElement); Item const* GetItem() const; int32 GetItemIdxByLabel(string const& _label) const; int32 GetItemIdxByValue(int32 const _value) const; bool GetItemLabels(vector* o_items); bool GetItemValues(vector* o_values); uint8 GetSize() const { return m_size; } private: vector m_items; int32 m_valueIdx; // the current index in the m_items vector int32 m_valueIdxCheck; // the previous index in the m_items vector (used for double-checking spurious value reads) uint8 m_size; int32 m_targetValue; // the Target Value, if the CC support it }; } // namespace VC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/value_classes/Value.h0000644000175200017520000001371314032142455016354 00000000000000//----------------------------------------------------------------------------- // // Value.h // // Base class for all OpenZWave Value Classes // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Value_H #define _Value_H #include #ifdef __FreeBSD__ #include #endif #include "Defs.h" #include "TimerThread.h" #include "platform/Ref.h" #include "value_classes/ValueID.h" #include "platform/Log.h" class TiXmlElement; namespace OpenZWave { class Driver; namespace Internal { namespace VC { /** \brief Base class for values associated with a node. * \ingroup ValueID */ class Value: public Internal::Platform::Ref, private Timer { friend class OpenZWave::Driver; friend class ValueStore; public: Value(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, ValueID::ValueType const _type, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, bool const _isset, uint8 const _pollIntensity); Value(); virtual void ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement); virtual void WriteXML(TiXmlElement* _valueElement); ValueID const& GetID() const { return m_id; } bool IsReadOnly() const { return m_readOnly; } bool IsWriteOnly() const { return m_writeOnly; } bool IsSet() const { return m_isSet; } bool IsPolled() const { return m_pollIntensity != 0; } string const GetLabel() const; void SetLabel(string const& _label, string const lang = ""); string const& GetUnits() const { return m_units; } void SetUnits(string const& _units) { m_units = _units; } string const GetHelp() const; void SetHelp(string const& _help, string const lang = ""); uint8 const& GetPollIntensity() const { return m_pollIntensity; } void SetPollIntensity(uint8 const& _intensity) { m_pollIntensity = _intensity; } int32 GetMin() const { return m_min; } int32 GetMax() const { return m_max; } void SetChangeVerified(bool _verify) { m_verifyChanges = _verify; } bool GetChangeVerified() { return m_verifyChanges; } void SetRefreshAfterSet(bool _refreshAfterSet) { m_refreshAfterSet = _refreshAfterSet; } bool GetRefreshAfterSet() { return m_refreshAfterSet; } virtual string const GetAsString() const { return ""; } virtual bool SetFromString(string const&) { return false; } bool Set(); // For the user to change a value in a device // Helpers static OpenZWave::ValueID::ValueGenre GetGenreEnumFromName(char const* _name); static char const* GetGenreNameFromEnum(ValueID::ValueGenre _genre); static OpenZWave::ValueID::ValueType GetTypeEnumFromName(char const* _name); static char const* GetTypeNameFromEnum(ValueID::ValueType _type); #if 0 inline void AddRef() { Ref::AddRef(); Log::Write(LogLevel_Warning, "Add Ref %d - %d %s", m_refs, m_id.GetId(), __func__); Internal::StackTraceGenerator::GetTrace(); } inline int32 Release() { Log::Write(LogLevel_Warning, "Del Ref %d - %d %s", m_refs -1, m_id.GetId(), __func__); Internal::StackTraceGenerator::GetTrace(); return Ref::Release(); } #endif void sendValueRefresh(uint32 _unused); protected: virtual ~Value(); bool IsCheckingChange() const { return m_checkChange; } void SetCheckingChange(bool _check) { m_checkChange = _check; } bool IsTargetValueSet() const { return m_targetValueSet; } void OnValueRefreshed(); // A value in a device has been refreshed void OnValueChanged(); // The refreshed value actually changed int VerifyRefreshedValue(void* _originalValue, void* _checkValue, void* _newValue, void* _targetValue, ValueID::ValueType _type, int _originalValueLength = 0, int _checkValueLength = 0, int _newValueLength = 0, int _targetValueLength = 0); int CheckTargetValue(void* _newValue, void* _targetValue, ValueID::ValueType _type, int _newValueLength, int _targetValueLength); int32 m_min; int32 m_max; time_t m_refreshTime; // time_t identifying when this value was last refreshed bool m_verifyChanges; // if true, apparent changes are verified; otherwise, they're not bool m_refreshAfterSet; // if true, all value sets are followed by a get to refresh the value manually ValueID m_id; bool m_targetValueSet; // If the Target Value is Set uint32 m_duration; // The Duration, if the CC supports it private: string m_units; bool m_readOnly; bool m_writeOnly; bool m_isSet; uint8 m_affectsLength; uint8* m_affects; bool m_affectsAll; bool m_checkChange; uint8 m_pollIntensity; }; } // namespace VC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/value_classes/ValueStore.cpp0000644000175200017520000001546114032142455017726 00000000000000//----------------------------------------------------------------------------- // // ValueStore.cpp // // Container for Value objects // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "value_classes/ValueStore.h" #include "value_classes/Value.h" #include "Manager.h" #include "Notification.h" #include "Localization.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace VC { //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- ValueStore::~ValueStore() { map::iterator it = m_values.begin(); while (!m_values.empty()) { ValueID const& valueId = it->second->GetID(); RemoveValue(valueId.GetValueStoreKey()); it = m_values.begin(); } } //----------------------------------------------------------------------------- // // Add a value to the store //----------------------------------------------------------------------------- bool ValueStore::AddValue(Value* _value) { if (!_value) { return false; } uint32 key = _value->GetID().GetValueStoreKey(); map::iterator it = m_values.find(key); if (it != m_values.end()) { // There is already a value in the store with this key, so we give up. return false; } m_values[key] = _value; _value->AddRef(); // Notify the watchers of the new value and Check our GetChangeVerified Flag if (Driver* driver = Manager::Get()->GetDriver(_value->GetID().GetHomeId())) { Node *node = driver->GetNodeUnsafe(_value->GetID().GetNodeId()); if (node) { Internal::CC::CommandClass *cc = node->GetCommandClass(_value->GetID().GetCommandClassId()); if (cc) { if (cc->m_com.GetFlagBool(COMPAT_FLAG_VERIFYCHANGED, _value->GetID().GetIndex())) { Log::Write(LogLevel_Info, _value->GetID().GetNodeId(), "Setting VerifiedChanged Flag on Value %d for CC %s", _value->GetID().GetIndex(), cc->GetCommandClassName().c_str()); _value->SetChangeVerified(true); } if (cc->m_com.GetFlagBool(COMPAT_FLAG_NO_REFRESH_AFTER_SET, _value->GetID().GetIndex())) { Log::Write(LogLevel_Info, _value->GetID().GetNodeId(), "Setting NoRefreshAfterSet Flag on Value %d for CC %s", _value->GetID().GetIndex(), cc->GetCommandClassName().c_str()); _value->SetRefreshAfterSet(false); } } } Notification* notification = new Notification(Notification::Type_ValueAdded); notification->SetValueId(_value->GetID()); driver->QueueNotification(notification); } return true; } //----------------------------------------------------------------------------- // // Remove a value from the store //----------------------------------------------------------------------------- bool ValueStore::RemoveValue(uint32 const& _key) { map::iterator it = m_values.find(_key); if (it != m_values.end()) { Value* value = it->second; ValueID const& valueId = value->GetID(); // First notify the watchers if (Driver* driver = Manager::Get()->GetDriver(valueId.GetHomeId())) { Notification* notification = new Notification(Notification::Type_ValueRemoved); notification->SetValueId(valueId); driver->QueueNotification(notification); } // Now release and remove the value from the store int32 references = value->Release(); if (references > 0) Log::Write(LogLevel_Warning, "Value Not Deleted - Still in use %d times: CC: %d - %s - %s - %d", references, valueId.GetCommandClassId(), valueId.GetTypeAsString().c_str(), value->GetLabel().c_str(), value->GetID()); else Log::Write(LogLevel_Debug, "Value Deleted"); m_values.erase(it); return true; } // Value not found in the store return false; } ////----------------------------------------------------------------------------- //// //// Remove a value from the store ////----------------------------------------------------------------------------- //bool ValueStore::RemoveValue //( // ValueID const& _id //) //----------------------------------------------------------------------------- // // Remove all the values associated with a command class from the store //----------------------------------------------------------------------------- void ValueStore::RemoveCommandClassValues(uint8 const _commandClassId) { map::iterator it = m_values.begin(); while (it != m_values.end()) { Value* value = it->second; ValueID const& valueId = value->GetID(); if (_commandClassId == valueId.GetCommandClassId()) { // The value belongs to the specified command class // First notify the watchers if (Driver* driver = Manager::Get()->GetDriver(valueId.GetHomeId())) { Notification* notification = new Notification(Notification::Type_ValueRemoved); notification->SetValueId(valueId); driver->QueueNotification(notification); } // Now release and remove the value from the store value->Release(); it = m_values.erase(it); } else { ++it; } } } //----------------------------------------------------------------------------- // // Get a value from the store //----------------------------------------------------------------------------- Value* ValueStore::GetValue(uint32 const& _key) const { Value* value = NULL; map::const_iterator it = m_values.find(_key); if (it != m_values.end()) { value = it->second; if (value) { // Add a reference to the value. The caller must // call Release on the value when they are done with it. value->AddRef(); } } return value; } } // namespace VC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/value_classes/ValueByte.h0000644000175200017520000000476014032142455017202 00000000000000//----------------------------------------------------------------------------- // // ValueByte.h // // Represents an 8-bit value // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ValueByte_H #define _ValueByte_H #include #include "Defs.h" #include "value_classes/Value.h" class TiXmlElement; namespace OpenZWave { namespace Internal { namespace VC { /** \brief Byte value sent to/received from a node. * \ingroup ValueID */ class ValueByte: public Value { public: ValueByte(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _value, uint8 const _pollIntensity); ValueByte(); virtual ~ValueByte() { } bool Set(uint8 const _value); void OnValueRefreshed(uint8 const _value); void SetTargetValue(uint8 const _target, uint32 _duration = 0); // From Value virtual string const GetAsString() const; virtual bool SetFromString(string const& _value); virtual void ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement); virtual void WriteXML(TiXmlElement* _valueElement); uint8 GetValue() const { return m_value; } private: uint8 m_value; // the current value uint8 m_valueCheck; // the previous value (used for double-checking spurious value reads) uint8 m_targetValue; // the Target Value, if the CC support it }; } // namespace VC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/value_classes/ValueBool.h0000644000175200017520000000506514032142455017171 00000000000000//----------------------------------------------------------------------------- // // ValueBool.h // // Represents a boolean value // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ValueBool_H #define _ValueBool_H #include #include "Defs.h" #include "value_classes/Value.h" class TiXmlElement; namespace OpenZWave { namespace Internal { namespace VC { /** \brief Boolean value sent to/received from a node. * \ingroup ValueID */ class ValueBool: public Value { public: ValueBool(uint32 const _homeId, uint8 const _nodeId, ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _index, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, bool const _value, uint8 const _pollIntensity); ValueBool() { } virtual ~ValueBool() { } bool Set(bool const _value); void OnValueRefreshed(bool const _value); void SetTargetValue(bool const _target, uint32 _duration = 0); // From Value virtual string const GetAsString() const { return (GetValue() ? "True" : "False"); } virtual bool SetFromString(string const& _value); virtual void ReadXML(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, TiXmlElement const* _valueElement); virtual void WriteXML(TiXmlElement* _valueElement); bool GetValue() const { return m_value; } private: bool m_value; // the current index in the m_items vector bool m_valueCheck; // the previous value (used for double-checking spurious value reads) bool m_targetValue; // The Target Value }; } // namespace VC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/ValueIDIndexesDefines.h0000644000175200017520000056045414032142455016567 00000000000000struct ignore_assign { ignore_assign(int value) : _value(value) { } operator int() const { return _value; } const ignore_assign& operator =(int dummy) { (void)dummy; return *this; } int _value; }; struct ValueID_Index_Alarm { enum _enumerated { Type_Start = 0, Type_Smoke_Alarm = 1, Type_Carbon_Monoxide = 2, Type_Carbon_Dioxide = 3, Type_Heat = 4, Type_Water = 5, Type_Access_Control = 6, Type_Home_Security = 7, Type_Power_Management = 8, Type_System = 9, Type_Emergency = 10, Type_Clock = 11, Type_Appliance = 12, Type_Home_Health = 13, Type_Siren = 14, Type_Water_Valve = 15, Type_Weather = 16, Type_Irrigation = 17, Type_Gas = 18, Type_Event_19, Type_Event_20, Type_Event_21, Type_Event_22, Type_Event_23, Type_Event_24, Type_Event_25, Type_Event_26, Type_Event_27, Type_Event_28, Type_Event_29, Type_Event_30, Type_Event_31, Type_Event_32, Type_Event_33, Type_Event_34, Type_Event_35, Type_Event_36, Type_Event_37, Type_Event_38, Type_Event_39, Type_Event_40, Type_Event_41, Type_Event_42, Type_Event_43, Type_Event_44, Type_Event_45, Type_Event_46, Type_Event_47, Type_Event_48, Type_Event_49, Type_Event_50, Type_Event_51, Type_Event_52, Type_Event_53, Type_Event_54, Type_Event_55, Type_Event_56, Type_Event_57, Type_Event_58, Type_Event_59, Type_Event_60, Type_Event_61, Type_Event_62, Type_Event_63, Type_Event_64, Type_Event_65, Type_Event_66, Type_Event_67, Type_Event_68, Type_Event_69, Type_Event_70, Type_Event_71, Type_Event_72, Type_Event_73, Type_Event_74, Type_Event_75, Type_Event_76, Type_Event_77, Type_Event_78, Type_Event_79, Type_Event_80, Type_Event_81, Type_Event_82, Type_Event_83, Type_Event_84, Type_Event_85, Type_Event_86, Type_Event_87, Type_Event_88, Type_Event_89, Type_Event_90, Type_Event_91, Type_Event_92, Type_Event_93, Type_Event_94, Type_Event_95, Type_Event_96, Type_Event_97, Type_Event_98, Type_Event_99, Type_Event_100, Type_Event_101, Type_Event_102, Type_Event_103, Type_Event_104, Type_Event_105, Type_Event_106, Type_Event_107, Type_Event_108, Type_Event_109, Type_Event_110, Type_Event_111, Type_Event_112, Type_Event_113, Type_Event_114, Type_Event_115, Type_Event_116, Type_Event_117, Type_Event_118, Type_Event_119, Type_Event_120, Type_Event_121, Type_Event_122, Type_Event_123, Type_Event_124, Type_Event_125, Type_Event_126, Type_Event_127, Type_Event_128, Type_Event_129, Type_Event_130, Type_Event_131, Type_Event_132, Type_Event_133, Type_Event_134, Type_Event_135, Type_Event_136, Type_Event_137, Type_Event_138, Type_Event_139, Type_Event_140, Type_Event_141, Type_Event_142, Type_Event_143, Type_Event_144, Type_Event_145, Type_Event_146, Type_Event_147, Type_Event_148, Type_Event_149, Type_Event_150, Type_Event_151, Type_Event_152, Type_Event_153, Type_Event_154, Type_Event_155, Type_Event_156, Type_Event_157, Type_Event_158, Type_Event_159, Type_Event_160, Type_Event_161, Type_Event_162, Type_Event_163, Type_Event_164, Type_Event_165, Type_Event_166, Type_Event_167, Type_Event_168, Type_Event_169, Type_Event_170, Type_Event_171, Type_Event_172, Type_Event_173, Type_Event_174, Type_Event_175, Type_Event_176, Type_Event_177, Type_Event_178, Type_Event_179, Type_Event_180, Type_Event_181, Type_Event_182, Type_Event_183, Type_Event_184, Type_Event_185, Type_Event_186, Type_Event_187, Type_Event_188, Type_Event_189, Type_Event_190, Type_Event_191, Type_Event_192, Type_Event_193, Type_Event_194, Type_Event_195, Type_Event_196, Type_Event_197, Type_Event_198, Type_Event_199, Type_Event_200, Type_Event_201, Type_Event_202, Type_Event_203, Type_Event_204, Type_Event_205, Type_Event_206, Type_Event_207, Type_Event_208, Type_Event_209, Type_Event_210, Type_Event_211, Type_Event_212, Type_Event_213, Type_Event_214, Type_Event_215, Type_Event_216, Type_Event_217, Type_Event_218, Type_Event_219, Type_Event_220, Type_Event_221, Type_Event_222, Type_Event_223, Type_Event_224, Type_Event_225, Type_Event_226, Type_Event_227, Type_Event_228, Type_Event_229, Type_Event_230, Type_Event_231, Type_Event_232, Type_Event_233, Type_Event_234, Type_Event_235, Type_Event_236, Type_Event_237, Type_Event_238, Type_Event_239, Type_Event_240, Type_Event_241, Type_Event_242, Type_Event_243, Type_Event_244, Type_Event_245, Type_Event_246, Type_Event_247, Type_Event_248, Type_Event_249, Type_Event_250, Type_Event_251, Type_Event_252, Type_Event_253, Type_Event_254, Type_Event_255, Type_Event_Param_Previous_Event = 256, Type_Event_Param_Location = 257, Type_Event_Param_Result = 258, Type_Event_Param_Threshold = 259, Type_Event_Param_UserCode = 260, Type_Event_Param_261 = 261, Type_Event_Param_Progress = 262, Type_Event_Param_Mode = 263, Type_Event_Param_Obstruction = 264, Type_Event_Param_Sensor_ID = 265, Type_Event_Param_Error_Code = 266, Type_Event_Param_Duration = 267, Type_Event_Param_Pollution_Level = 268, Type_Event_Param_Status = 269, Type_Event_Param_Schedule_ID = 270, Type_Event_Param_Valve_Table_ID = 271, Type_Event_Param_272, Type_Event_Param_273, Type_Event_Param_274, Type_Event_Param_275, Type_Event_Param_276, Type_Event_Param_277, Type_Event_Param_278, Type_Event_Param_279, Type_Event_Param_280, Type_Event_Param_281, Type_Event_Param_282, Type_Event_Param_283, Type_Event_Param_284, Type_Event_Param_285, Type_Event_Param_286, Type_Event_Param_287, Type_Event_Param_288, Type_Event_Param_289, Type_Event_Param_290, Type_Event_Param_291, Type_Event_Param_292, Type_Event_Param_293, Type_Event_Param_294, Type_Event_Param_295, Type_Event_Param_296, Type_Event_Param_297, Type_Event_Param_298, Type_Event_Param_299, Type_Event_Param_300, Type_Event_Param_301, Type_Event_Param_302, Type_Event_Param_303, Type_Event_Param_304, Type_Event_Param_305, Type_Event_Param_306, Type_Event_Param_307, Type_Event_Param_308, Type_Event_Param_309, Type_Event_Param_310, Type_Event_Param_311, Type_Event_Param_312, Type_Event_Param_313, Type_Event_Param_314, Type_Event_Param_315, Type_Event_Param_316, Type_Event_Param_317, Type_Event_Param_318, Type_Event_Param_319, Type_Event_Param_320, Type_Event_Param_321, Type_Event_Param_322, Type_Event_Param_323, Type_Event_Param_324, Type_Event_Param_325, Type_Event_Param_326, Type_Event_Param_327, Type_Event_Param_328, Type_Event_Param_329, Type_Event_Param_330, Type_Event_Param_331, Type_Event_Param_332, Type_Event_Param_333, Type_Event_Param_334, Type_Event_Param_335, Type_Event_Param_336, Type_Event_Param_337, Type_Event_Param_338, Type_Event_Param_339, Type_Event_Param_340, Type_Event_Param_341, Type_Event_Param_342, Type_Event_Param_343, Type_Event_Param_344, Type_Event_Param_345, Type_Event_Param_346, Type_Event_Param_347, Type_Event_Param_348, Type_Event_Param_349, Type_Event_Param_350, Type_Event_Param_351, Type_Event_Param_352, Type_Event_Param_353, Type_Event_Param_354, Type_Event_Param_355, Type_Event_Param_356, Type_Event_Param_357, Type_Event_Param_358, Type_Event_Param_359, Type_Event_Param_360, Type_Event_Param_361, Type_Event_Param_362, Type_Event_Param_363, Type_Event_Param_364, Type_Event_Param_365, Type_Event_Param_366, Type_Event_Param_367, Type_Event_Param_368, Type_Event_Param_369, Type_Event_Param_370, Type_Event_Param_371, Type_Event_Param_372, Type_Event_Param_373, Type_Event_Param_374, Type_Event_Param_375, Type_Event_Param_376, Type_Event_Param_377, Type_Event_Param_378, Type_Event_Param_379, Type_Event_Param_380, Type_Event_Param_381, Type_Event_Param_382, Type_Event_Param_383, Type_Event_Param_384, Type_Event_Param_385, Type_Event_Param_386, Type_Event_Param_387, Type_Event_Param_388, Type_Event_Param_389, Type_Event_Param_390, Type_Event_Param_391, Type_Event_Param_392, Type_Event_Param_393, Type_Event_Param_394, Type_Event_Param_395, Type_Event_Param_396, Type_Event_Param_397, Type_Event_Param_398, Type_Event_Param_399, Type_Event_Param_400, Type_Event_Param_401, Type_Event_Param_402, Type_Event_Param_403, Type_Event_Param_404, Type_Event_Param_405, Type_Event_Param_406, Type_Event_Param_407, Type_Event_Param_408, Type_Event_Param_409, Type_Event_Param_410, Type_Event_Param_411, Type_Event_Param_412, Type_Event_Param_413, Type_Event_Param_414, Type_Event_Param_415, Type_Event_Param_416, Type_Event_Param_417, Type_Event_Param_418, Type_Event_Param_419, Type_Event_Param_420, Type_Event_Param_421, Type_Event_Param_422, Type_Event_Param_423, Type_Event_Param_424, Type_Event_Param_425, Type_Event_Param_426, Type_Event_Param_427, Type_Event_Param_428, Type_Event_Param_429, Type_Event_Param_430, Type_Event_Param_431, Type_Event_Param_432, Type_Event_Param_433, Type_Event_Param_434, Type_Event_Param_435, Type_Event_Param_436, Type_Event_Param_437, Type_Event_Param_438, Type_Event_Param_439, Type_Event_Param_440, Type_Event_Param_441, Type_Event_Param_442, Type_Event_Param_443, Type_Event_Param_444, Type_Event_Param_445, Type_Event_Param_446, Type_Event_Param_447, Type_Event_Param_448, Type_Event_Param_449, Type_Event_Param_450, Type_Event_Param_451, Type_Event_Param_452, Type_Event_Param_453, Type_Event_Param_454, Type_Event_Param_455, Type_Event_Param_456, Type_Event_Param_457, Type_Event_Param_458, Type_Event_Param_459, Type_Event_Param_460, Type_Event_Param_461, Type_Event_Param_462, Type_Event_Param_463, Type_Event_Param_464, Type_Event_Param_465, Type_Event_Param_466, Type_Event_Param_467, Type_Event_Param_468, Type_Event_Param_469, Type_Event_Param_470, Type_Event_Param_471, Type_Event_Param_472, Type_Event_Param_473, Type_Event_Param_474, Type_Event_Param_475, Type_Event_Param_476, Type_Event_Param_477, Type_Event_Param_478, Type_Event_Param_479, Type_Event_Param_480, Type_Event_Param_481, Type_Event_Param_482, Type_Event_Param_483, Type_Event_Param_484, Type_Event_Param_485, Type_Event_Param_486, Type_Event_Param_487, Type_Event_Param_488, Type_Event_Param_489, Type_Event_Param_490, Type_Event_Param_491, Type_Event_Param_492, Type_Event_Param_493, Type_Event_Param_494, Type_Event_Param_495, Type_Event_Param_496, Type_Event_Param_497, Type_Event_Param_498, Type_Event_Param_499, Type_Event_Param_500, Type_Event_Param_501, Type_Event_Param_502, Type_Event_Param_503, Type_Event_Param_504, Type_Event_Param_505, Type_Event_Param_506, Type_Event_Param_507, Type_Event_Param_508, Type_Event_Param_509, Type_Event_Param_510, Type_Event_Param_511, Type_v1 = 512, Level_v1 = 513, AutoClearEvents = 514 }; _enumerated _value; ValueID_Index_Alarm(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 515; static const int* _values() { static const int values[] = { (ignore_assign)Type_Start = 0, (ignore_assign)Type_Smoke_Alarm = 1, (ignore_assign)Type_Carbon_Monoxide = 2, (ignore_assign)Type_Carbon_Dioxide = 3, (ignore_assign)Type_Heat = 4, (ignore_assign)Type_Water = 5, (ignore_assign)Type_Access_Control = 6, (ignore_assign)Type_Home_Security = 7, (ignore_assign)Type_Power_Management = 8, (ignore_assign)Type_System = 9, (ignore_assign)Type_Emergency = 10, (ignore_assign)Type_Clock = 11, (ignore_assign)Type_Appliance = 12, (ignore_assign)Type_Home_Health = 13, (ignore_assign)Type_Siren = 14, (ignore_assign)Type_Water_Valve = 15, (ignore_assign)Type_Weather = 16, (ignore_assign)Type_Irrigation = 17, (ignore_assign)Type_Gas = 18, (ignore_assign)Type_Event_19, (ignore_assign)Type_Event_20, (ignore_assign)Type_Event_21, (ignore_assign)Type_Event_22, (ignore_assign)Type_Event_23, (ignore_assign)Type_Event_24, (ignore_assign)Type_Event_25, (ignore_assign)Type_Event_26, (ignore_assign)Type_Event_27, (ignore_assign)Type_Event_28, (ignore_assign)Type_Event_29, (ignore_assign)Type_Event_30, (ignore_assign)Type_Event_31, (ignore_assign)Type_Event_32, (ignore_assign)Type_Event_33, (ignore_assign)Type_Event_34, (ignore_assign)Type_Event_35, (ignore_assign)Type_Event_36, (ignore_assign)Type_Event_37, (ignore_assign)Type_Event_38, (ignore_assign)Type_Event_39, (ignore_assign)Type_Event_40, (ignore_assign)Type_Event_41, (ignore_assign)Type_Event_42, (ignore_assign)Type_Event_43, (ignore_assign)Type_Event_44, (ignore_assign)Type_Event_45, (ignore_assign)Type_Event_46, (ignore_assign)Type_Event_47, (ignore_assign)Type_Event_48, (ignore_assign)Type_Event_49, (ignore_assign)Type_Event_50, (ignore_assign)Type_Event_51, (ignore_assign)Type_Event_52, (ignore_assign)Type_Event_53, (ignore_assign)Type_Event_54, (ignore_assign)Type_Event_55, (ignore_assign)Type_Event_56, (ignore_assign)Type_Event_57, (ignore_assign)Type_Event_58, (ignore_assign)Type_Event_59, (ignore_assign)Type_Event_60, (ignore_assign)Type_Event_61, (ignore_assign)Type_Event_62, (ignore_assign)Type_Event_63, (ignore_assign)Type_Event_64, (ignore_assign)Type_Event_65, (ignore_assign)Type_Event_66, (ignore_assign)Type_Event_67, (ignore_assign)Type_Event_68, (ignore_assign)Type_Event_69, (ignore_assign)Type_Event_70, (ignore_assign)Type_Event_71, (ignore_assign)Type_Event_72, (ignore_assign)Type_Event_73, (ignore_assign)Type_Event_74, (ignore_assign)Type_Event_75, (ignore_assign)Type_Event_76, (ignore_assign)Type_Event_77, (ignore_assign)Type_Event_78, (ignore_assign)Type_Event_79, (ignore_assign)Type_Event_80, (ignore_assign)Type_Event_81, (ignore_assign)Type_Event_82, (ignore_assign)Type_Event_83, (ignore_assign)Type_Event_84, (ignore_assign)Type_Event_85, (ignore_assign)Type_Event_86, (ignore_assign)Type_Event_87, (ignore_assign)Type_Event_88, (ignore_assign)Type_Event_89, (ignore_assign)Type_Event_90, (ignore_assign)Type_Event_91, (ignore_assign)Type_Event_92, (ignore_assign)Type_Event_93, (ignore_assign)Type_Event_94, (ignore_assign)Type_Event_95, (ignore_assign)Type_Event_96, (ignore_assign)Type_Event_97, (ignore_assign)Type_Event_98, (ignore_assign)Type_Event_99, (ignore_assign)Type_Event_100, (ignore_assign)Type_Event_101, (ignore_assign)Type_Event_102, (ignore_assign)Type_Event_103, (ignore_assign)Type_Event_104, (ignore_assign)Type_Event_105, (ignore_assign)Type_Event_106, (ignore_assign)Type_Event_107, (ignore_assign)Type_Event_108, (ignore_assign)Type_Event_109, (ignore_assign)Type_Event_110, (ignore_assign)Type_Event_111, (ignore_assign)Type_Event_112, (ignore_assign)Type_Event_113, (ignore_assign)Type_Event_114, (ignore_assign)Type_Event_115, (ignore_assign)Type_Event_116, (ignore_assign)Type_Event_117, (ignore_assign)Type_Event_118, (ignore_assign)Type_Event_119, (ignore_assign)Type_Event_120, (ignore_assign)Type_Event_121, (ignore_assign)Type_Event_122, (ignore_assign)Type_Event_123, (ignore_assign)Type_Event_124, (ignore_assign)Type_Event_125, (ignore_assign)Type_Event_126, (ignore_assign)Type_Event_127, (ignore_assign)Type_Event_128, (ignore_assign)Type_Event_129, (ignore_assign)Type_Event_130, (ignore_assign)Type_Event_131, (ignore_assign)Type_Event_132, (ignore_assign)Type_Event_133, (ignore_assign)Type_Event_134, (ignore_assign)Type_Event_135, (ignore_assign)Type_Event_136, (ignore_assign)Type_Event_137, (ignore_assign)Type_Event_138, (ignore_assign)Type_Event_139, (ignore_assign)Type_Event_140, (ignore_assign)Type_Event_141, (ignore_assign)Type_Event_142, (ignore_assign)Type_Event_143, (ignore_assign)Type_Event_144, (ignore_assign)Type_Event_145, (ignore_assign)Type_Event_146, (ignore_assign)Type_Event_147, (ignore_assign)Type_Event_148, (ignore_assign)Type_Event_149, (ignore_assign)Type_Event_150, (ignore_assign)Type_Event_151, (ignore_assign)Type_Event_152, (ignore_assign)Type_Event_153, (ignore_assign)Type_Event_154, (ignore_assign)Type_Event_155, (ignore_assign)Type_Event_156, (ignore_assign)Type_Event_157, (ignore_assign)Type_Event_158, (ignore_assign)Type_Event_159, (ignore_assign)Type_Event_160, (ignore_assign)Type_Event_161, (ignore_assign)Type_Event_162, (ignore_assign)Type_Event_163, (ignore_assign)Type_Event_164, (ignore_assign)Type_Event_165, (ignore_assign)Type_Event_166, (ignore_assign)Type_Event_167, (ignore_assign)Type_Event_168, (ignore_assign)Type_Event_169, (ignore_assign)Type_Event_170, (ignore_assign)Type_Event_171, (ignore_assign)Type_Event_172, (ignore_assign)Type_Event_173, (ignore_assign)Type_Event_174, (ignore_assign)Type_Event_175, (ignore_assign)Type_Event_176, (ignore_assign)Type_Event_177, (ignore_assign)Type_Event_178, (ignore_assign)Type_Event_179, (ignore_assign)Type_Event_180, (ignore_assign)Type_Event_181, (ignore_assign)Type_Event_182, (ignore_assign)Type_Event_183, (ignore_assign)Type_Event_184, (ignore_assign)Type_Event_185, (ignore_assign)Type_Event_186, (ignore_assign)Type_Event_187, (ignore_assign)Type_Event_188, (ignore_assign)Type_Event_189, (ignore_assign)Type_Event_190, (ignore_assign)Type_Event_191, (ignore_assign)Type_Event_192, (ignore_assign)Type_Event_193, (ignore_assign)Type_Event_194, (ignore_assign)Type_Event_195, (ignore_assign)Type_Event_196, (ignore_assign)Type_Event_197, (ignore_assign)Type_Event_198, (ignore_assign)Type_Event_199, (ignore_assign)Type_Event_200, (ignore_assign)Type_Event_201, (ignore_assign)Type_Event_202, (ignore_assign)Type_Event_203, (ignore_assign)Type_Event_204, (ignore_assign)Type_Event_205, (ignore_assign)Type_Event_206, (ignore_assign)Type_Event_207, (ignore_assign)Type_Event_208, (ignore_assign)Type_Event_209, (ignore_assign)Type_Event_210, (ignore_assign)Type_Event_211, (ignore_assign)Type_Event_212, (ignore_assign)Type_Event_213, (ignore_assign)Type_Event_214, (ignore_assign)Type_Event_215, (ignore_assign)Type_Event_216, (ignore_assign)Type_Event_217, (ignore_assign)Type_Event_218, (ignore_assign)Type_Event_219, (ignore_assign)Type_Event_220, (ignore_assign)Type_Event_221, (ignore_assign)Type_Event_222, (ignore_assign)Type_Event_223, (ignore_assign)Type_Event_224, (ignore_assign)Type_Event_225, (ignore_assign)Type_Event_226, (ignore_assign)Type_Event_227, (ignore_assign)Type_Event_228, (ignore_assign)Type_Event_229, (ignore_assign)Type_Event_230, (ignore_assign)Type_Event_231, (ignore_assign)Type_Event_232, (ignore_assign)Type_Event_233, (ignore_assign)Type_Event_234, (ignore_assign)Type_Event_235, (ignore_assign)Type_Event_236, (ignore_assign)Type_Event_237, (ignore_assign)Type_Event_238, (ignore_assign)Type_Event_239, (ignore_assign)Type_Event_240, (ignore_assign)Type_Event_241, (ignore_assign)Type_Event_242, (ignore_assign)Type_Event_243, (ignore_assign)Type_Event_244, (ignore_assign)Type_Event_245, (ignore_assign)Type_Event_246, (ignore_assign)Type_Event_247, (ignore_assign)Type_Event_248, (ignore_assign)Type_Event_249, (ignore_assign)Type_Event_250, (ignore_assign)Type_Event_251, (ignore_assign)Type_Event_252, (ignore_assign)Type_Event_253, (ignore_assign)Type_Event_254, (ignore_assign)Type_Event_255, (ignore_assign)Type_Event_Param_Previous_Event = 256, (ignore_assign)Type_Event_Param_Location = 257, (ignore_assign)Type_Event_Param_Result = 258, (ignore_assign)Type_Event_Param_Threshold = 259, (ignore_assign)Type_Event_Param_UserCode = 260, (ignore_assign)Type_Event_Param_261 = 261, (ignore_assign)Type_Event_Param_Progress = 262, (ignore_assign)Type_Event_Param_Mode = 263, (ignore_assign)Type_Event_Param_Obstruction = 264, (ignore_assign)Type_Event_Param_Sensor_ID = 265, (ignore_assign)Type_Event_Param_Error_Code = 266, (ignore_assign)Type_Event_Param_Duration = 267, (ignore_assign)Type_Event_Param_Pollution_Level = 268, (ignore_assign)Type_Event_Param_Status = 269, (ignore_assign)Type_Event_Param_Schedule_ID = 270, (ignore_assign)Type_Event_Param_Valve_Table_ID = 271, (ignore_assign)Type_Event_Param_272, (ignore_assign)Type_Event_Param_273, (ignore_assign)Type_Event_Param_274, (ignore_assign)Type_Event_Param_275, (ignore_assign)Type_Event_Param_276, (ignore_assign)Type_Event_Param_277, (ignore_assign)Type_Event_Param_278, (ignore_assign)Type_Event_Param_279, (ignore_assign)Type_Event_Param_280, (ignore_assign)Type_Event_Param_281, (ignore_assign)Type_Event_Param_282, (ignore_assign)Type_Event_Param_283, (ignore_assign)Type_Event_Param_284, (ignore_assign)Type_Event_Param_285, (ignore_assign)Type_Event_Param_286, (ignore_assign)Type_Event_Param_287, (ignore_assign)Type_Event_Param_288, (ignore_assign)Type_Event_Param_289, (ignore_assign)Type_Event_Param_290, (ignore_assign)Type_Event_Param_291, (ignore_assign)Type_Event_Param_292, (ignore_assign)Type_Event_Param_293, (ignore_assign)Type_Event_Param_294, (ignore_assign)Type_Event_Param_295, (ignore_assign)Type_Event_Param_296, (ignore_assign)Type_Event_Param_297, (ignore_assign)Type_Event_Param_298, (ignore_assign)Type_Event_Param_299, (ignore_assign)Type_Event_Param_300, (ignore_assign)Type_Event_Param_301, (ignore_assign)Type_Event_Param_302, (ignore_assign)Type_Event_Param_303, (ignore_assign)Type_Event_Param_304, (ignore_assign)Type_Event_Param_305, (ignore_assign)Type_Event_Param_306, (ignore_assign)Type_Event_Param_307, (ignore_assign)Type_Event_Param_308, (ignore_assign)Type_Event_Param_309, (ignore_assign)Type_Event_Param_310, (ignore_assign)Type_Event_Param_311, (ignore_assign)Type_Event_Param_312, (ignore_assign)Type_Event_Param_313, (ignore_assign)Type_Event_Param_314, (ignore_assign)Type_Event_Param_315, (ignore_assign)Type_Event_Param_316, (ignore_assign)Type_Event_Param_317, (ignore_assign)Type_Event_Param_318, (ignore_assign)Type_Event_Param_319, (ignore_assign)Type_Event_Param_320, (ignore_assign)Type_Event_Param_321, (ignore_assign)Type_Event_Param_322, (ignore_assign)Type_Event_Param_323, (ignore_assign)Type_Event_Param_324, (ignore_assign)Type_Event_Param_325, (ignore_assign)Type_Event_Param_326, (ignore_assign)Type_Event_Param_327, (ignore_assign)Type_Event_Param_328, (ignore_assign)Type_Event_Param_329, (ignore_assign)Type_Event_Param_330, (ignore_assign)Type_Event_Param_331, (ignore_assign)Type_Event_Param_332, (ignore_assign)Type_Event_Param_333, (ignore_assign)Type_Event_Param_334, (ignore_assign)Type_Event_Param_335, (ignore_assign)Type_Event_Param_336, (ignore_assign)Type_Event_Param_337, (ignore_assign)Type_Event_Param_338, (ignore_assign)Type_Event_Param_339, (ignore_assign)Type_Event_Param_340, (ignore_assign)Type_Event_Param_341, (ignore_assign)Type_Event_Param_342, (ignore_assign)Type_Event_Param_343, (ignore_assign)Type_Event_Param_344, (ignore_assign)Type_Event_Param_345, (ignore_assign)Type_Event_Param_346, (ignore_assign)Type_Event_Param_347, (ignore_assign)Type_Event_Param_348, (ignore_assign)Type_Event_Param_349, (ignore_assign)Type_Event_Param_350, (ignore_assign)Type_Event_Param_351, (ignore_assign)Type_Event_Param_352, (ignore_assign)Type_Event_Param_353, (ignore_assign)Type_Event_Param_354, (ignore_assign)Type_Event_Param_355, (ignore_assign)Type_Event_Param_356, (ignore_assign)Type_Event_Param_357, (ignore_assign)Type_Event_Param_358, (ignore_assign)Type_Event_Param_359, (ignore_assign)Type_Event_Param_360, (ignore_assign)Type_Event_Param_361, (ignore_assign)Type_Event_Param_362, (ignore_assign)Type_Event_Param_363, (ignore_assign)Type_Event_Param_364, (ignore_assign)Type_Event_Param_365, (ignore_assign)Type_Event_Param_366, (ignore_assign)Type_Event_Param_367, (ignore_assign)Type_Event_Param_368, (ignore_assign)Type_Event_Param_369, (ignore_assign)Type_Event_Param_370, (ignore_assign)Type_Event_Param_371, (ignore_assign)Type_Event_Param_372, (ignore_assign)Type_Event_Param_373, (ignore_assign)Type_Event_Param_374, (ignore_assign)Type_Event_Param_375, (ignore_assign)Type_Event_Param_376, (ignore_assign)Type_Event_Param_377, (ignore_assign)Type_Event_Param_378, (ignore_assign)Type_Event_Param_379, (ignore_assign)Type_Event_Param_380, (ignore_assign)Type_Event_Param_381, (ignore_assign)Type_Event_Param_382, (ignore_assign)Type_Event_Param_383, (ignore_assign)Type_Event_Param_384, (ignore_assign)Type_Event_Param_385, (ignore_assign)Type_Event_Param_386, (ignore_assign)Type_Event_Param_387, (ignore_assign)Type_Event_Param_388, (ignore_assign)Type_Event_Param_389, (ignore_assign)Type_Event_Param_390, (ignore_assign)Type_Event_Param_391, (ignore_assign)Type_Event_Param_392, (ignore_assign)Type_Event_Param_393, (ignore_assign)Type_Event_Param_394, (ignore_assign)Type_Event_Param_395, (ignore_assign)Type_Event_Param_396, (ignore_assign)Type_Event_Param_397, (ignore_assign)Type_Event_Param_398, (ignore_assign)Type_Event_Param_399, (ignore_assign)Type_Event_Param_400, (ignore_assign)Type_Event_Param_401, (ignore_assign)Type_Event_Param_402, (ignore_assign)Type_Event_Param_403, (ignore_assign)Type_Event_Param_404, (ignore_assign)Type_Event_Param_405, (ignore_assign)Type_Event_Param_406, (ignore_assign)Type_Event_Param_407, (ignore_assign)Type_Event_Param_408, (ignore_assign)Type_Event_Param_409, (ignore_assign)Type_Event_Param_410, (ignore_assign)Type_Event_Param_411, (ignore_assign)Type_Event_Param_412, (ignore_assign)Type_Event_Param_413, (ignore_assign)Type_Event_Param_414, (ignore_assign)Type_Event_Param_415, (ignore_assign)Type_Event_Param_416, (ignore_assign)Type_Event_Param_417, (ignore_assign)Type_Event_Param_418, (ignore_assign)Type_Event_Param_419, (ignore_assign)Type_Event_Param_420, (ignore_assign)Type_Event_Param_421, (ignore_assign)Type_Event_Param_422, (ignore_assign)Type_Event_Param_423, (ignore_assign)Type_Event_Param_424, (ignore_assign)Type_Event_Param_425, (ignore_assign)Type_Event_Param_426, (ignore_assign)Type_Event_Param_427, (ignore_assign)Type_Event_Param_428, (ignore_assign)Type_Event_Param_429, (ignore_assign)Type_Event_Param_430, (ignore_assign)Type_Event_Param_431, (ignore_assign)Type_Event_Param_432, (ignore_assign)Type_Event_Param_433, (ignore_assign)Type_Event_Param_434, (ignore_assign)Type_Event_Param_435, (ignore_assign)Type_Event_Param_436, (ignore_assign)Type_Event_Param_437, (ignore_assign)Type_Event_Param_438, (ignore_assign)Type_Event_Param_439, (ignore_assign)Type_Event_Param_440, (ignore_assign)Type_Event_Param_441, (ignore_assign)Type_Event_Param_442, (ignore_assign)Type_Event_Param_443, (ignore_assign)Type_Event_Param_444, (ignore_assign)Type_Event_Param_445, (ignore_assign)Type_Event_Param_446, (ignore_assign)Type_Event_Param_447, (ignore_assign)Type_Event_Param_448, (ignore_assign)Type_Event_Param_449, (ignore_assign)Type_Event_Param_450, (ignore_assign)Type_Event_Param_451, (ignore_assign)Type_Event_Param_452, (ignore_assign)Type_Event_Param_453, (ignore_assign)Type_Event_Param_454, (ignore_assign)Type_Event_Param_455, (ignore_assign)Type_Event_Param_456, (ignore_assign)Type_Event_Param_457, (ignore_assign)Type_Event_Param_458, (ignore_assign)Type_Event_Param_459, (ignore_assign)Type_Event_Param_460, (ignore_assign)Type_Event_Param_461, (ignore_assign)Type_Event_Param_462, (ignore_assign)Type_Event_Param_463, (ignore_assign)Type_Event_Param_464, (ignore_assign)Type_Event_Param_465, (ignore_assign)Type_Event_Param_466, (ignore_assign)Type_Event_Param_467, (ignore_assign)Type_Event_Param_468, (ignore_assign)Type_Event_Param_469, (ignore_assign)Type_Event_Param_470, (ignore_assign)Type_Event_Param_471, (ignore_assign)Type_Event_Param_472, (ignore_assign)Type_Event_Param_473, (ignore_assign)Type_Event_Param_474, (ignore_assign)Type_Event_Param_475, (ignore_assign)Type_Event_Param_476, (ignore_assign)Type_Event_Param_477, (ignore_assign)Type_Event_Param_478, (ignore_assign)Type_Event_Param_479, (ignore_assign)Type_Event_Param_480, (ignore_assign)Type_Event_Param_481, (ignore_assign)Type_Event_Param_482, (ignore_assign)Type_Event_Param_483, (ignore_assign)Type_Event_Param_484, (ignore_assign)Type_Event_Param_485, (ignore_assign)Type_Event_Param_486, (ignore_assign)Type_Event_Param_487, (ignore_assign)Type_Event_Param_488, (ignore_assign)Type_Event_Param_489, (ignore_assign)Type_Event_Param_490, (ignore_assign)Type_Event_Param_491, (ignore_assign)Type_Event_Param_492, (ignore_assign)Type_Event_Param_493, (ignore_assign)Type_Event_Param_494, (ignore_assign)Type_Event_Param_495, (ignore_assign)Type_Event_Param_496, (ignore_assign)Type_Event_Param_497, (ignore_assign)Type_Event_Param_498, (ignore_assign)Type_Event_Param_499, (ignore_assign)Type_Event_Param_500, (ignore_assign)Type_Event_Param_501, (ignore_assign)Type_Event_Param_502, (ignore_assign)Type_Event_Param_503, (ignore_assign)Type_Event_Param_504, (ignore_assign)Type_Event_Param_505, (ignore_assign)Type_Event_Param_506, (ignore_assign)Type_Event_Param_507, (ignore_assign)Type_Event_Param_508, (ignore_assign)Type_Event_Param_509, (ignore_assign)Type_Event_Param_510, (ignore_assign)Type_Event_Param_511, (ignore_assign)Type_v1 = 512, (ignore_assign)Level_v1 = 513, (ignore_assign)AutoClearEvents = 514, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Type_Start = 0", "Type_Smoke_Alarm = 1", "Type_Carbon_Monoxide = 2", "Type_Carbon_Dioxide = 3", "Type_Heat = 4", "Type_Water = 5", "Type_Access_Control = 6", "Type_Home_Security = 7", "Type_Power_Management = 8", "Type_System = 9", "Type_Emergency = 10", "Type_Clock = 11", "Type_Appliance = 12", "Type_Home_Health = 13", "Type_Siren = 14", "Type_Water_Valve = 15", "Type_Weather = 16", "Type_Irrigation = 17", "Type_Gas = 18", "Type_Event_19", "Type_Event_20", "Type_Event_21", "Type_Event_22", "Type_Event_23", "Type_Event_24", "Type_Event_25", "Type_Event_26", "Type_Event_27", "Type_Event_28", "Type_Event_29", "Type_Event_30", "Type_Event_31", "Type_Event_32", "Type_Event_33", "Type_Event_34", "Type_Event_35", "Type_Event_36", "Type_Event_37", "Type_Event_38", "Type_Event_39", "Type_Event_40", "Type_Event_41", "Type_Event_42", "Type_Event_43", "Type_Event_44", "Type_Event_45", "Type_Event_46", "Type_Event_47", "Type_Event_48", "Type_Event_49", "Type_Event_50", "Type_Event_51", "Type_Event_52", "Type_Event_53", "Type_Event_54", "Type_Event_55", "Type_Event_56", "Type_Event_57", "Type_Event_58", "Type_Event_59", "Type_Event_60", "Type_Event_61", "Type_Event_62", "Type_Event_63", "Type_Event_64", "Type_Event_65", "Type_Event_66", "Type_Event_67", "Type_Event_68", "Type_Event_69", "Type_Event_70", "Type_Event_71", "Type_Event_72", "Type_Event_73", "Type_Event_74", "Type_Event_75", "Type_Event_76", "Type_Event_77", "Type_Event_78", "Type_Event_79", "Type_Event_80", "Type_Event_81", "Type_Event_82", "Type_Event_83", "Type_Event_84", "Type_Event_85", "Type_Event_86", "Type_Event_87", "Type_Event_88", "Type_Event_89", "Type_Event_90", "Type_Event_91", "Type_Event_92", "Type_Event_93", "Type_Event_94", "Type_Event_95", "Type_Event_96", "Type_Event_97", "Type_Event_98", "Type_Event_99", "Type_Event_100", "Type_Event_101", "Type_Event_102", "Type_Event_103", "Type_Event_104", "Type_Event_105", "Type_Event_106", "Type_Event_107", "Type_Event_108", "Type_Event_109", "Type_Event_110", "Type_Event_111", "Type_Event_112", "Type_Event_113", "Type_Event_114", "Type_Event_115", "Type_Event_116", "Type_Event_117", "Type_Event_118", "Type_Event_119", "Type_Event_120", "Type_Event_121", "Type_Event_122", "Type_Event_123", "Type_Event_124", "Type_Event_125", "Type_Event_126", "Type_Event_127", "Type_Event_128", "Type_Event_129", "Type_Event_130", "Type_Event_131", "Type_Event_132", "Type_Event_133", "Type_Event_134", "Type_Event_135", "Type_Event_136", "Type_Event_137", "Type_Event_138", "Type_Event_139", "Type_Event_140", "Type_Event_141", "Type_Event_142", "Type_Event_143", "Type_Event_144", "Type_Event_145", "Type_Event_146", "Type_Event_147", "Type_Event_148", "Type_Event_149", "Type_Event_150", "Type_Event_151", "Type_Event_152", "Type_Event_153", "Type_Event_154", "Type_Event_155", "Type_Event_156", "Type_Event_157", "Type_Event_158", "Type_Event_159", "Type_Event_160", "Type_Event_161", "Type_Event_162", "Type_Event_163", "Type_Event_164", "Type_Event_165", "Type_Event_166", "Type_Event_167", "Type_Event_168", "Type_Event_169", "Type_Event_170", "Type_Event_171", "Type_Event_172", "Type_Event_173", "Type_Event_174", "Type_Event_175", "Type_Event_176", "Type_Event_177", "Type_Event_178", "Type_Event_179", "Type_Event_180", "Type_Event_181", "Type_Event_182", "Type_Event_183", "Type_Event_184", "Type_Event_185", "Type_Event_186", "Type_Event_187", "Type_Event_188", "Type_Event_189", "Type_Event_190", "Type_Event_191", "Type_Event_192", "Type_Event_193", "Type_Event_194", "Type_Event_195", "Type_Event_196", "Type_Event_197", "Type_Event_198", "Type_Event_199", "Type_Event_200", "Type_Event_201", "Type_Event_202", "Type_Event_203", "Type_Event_204", "Type_Event_205", "Type_Event_206", "Type_Event_207", "Type_Event_208", "Type_Event_209", "Type_Event_210", "Type_Event_211", "Type_Event_212", "Type_Event_213", "Type_Event_214", "Type_Event_215", "Type_Event_216", "Type_Event_217", "Type_Event_218", "Type_Event_219", "Type_Event_220", "Type_Event_221", "Type_Event_222", "Type_Event_223", "Type_Event_224", "Type_Event_225", "Type_Event_226", "Type_Event_227", "Type_Event_228", "Type_Event_229", "Type_Event_230", "Type_Event_231", "Type_Event_232", "Type_Event_233", "Type_Event_234", "Type_Event_235", "Type_Event_236", "Type_Event_237", "Type_Event_238", "Type_Event_239", "Type_Event_240", "Type_Event_241", "Type_Event_242", "Type_Event_243", "Type_Event_244", "Type_Event_245", "Type_Event_246", "Type_Event_247", "Type_Event_248", "Type_Event_249", "Type_Event_250", "Type_Event_251", "Type_Event_252", "Type_Event_253", "Type_Event_254", "Type_Event_255", "Type_Event_Param_Previous_Event = 256", "Type_Event_Param_Location = 257", "Type_Event_Param_Result = 258", "Type_Event_Param_Threshold = 259", "Type_Event_Param_UserCode = 260", "Type_Event_Param_261 = 261", "Type_Event_Param_Progress = 262", "Type_Event_Param_Mode = 263", "Type_Event_Param_Obstruction = 264", "Type_Event_Param_Sensor_ID = 265", "Type_Event_Param_Error_Code = 266", "Type_Event_Param_Duration = 267", "Type_Event_Param_Pollution_Level = 268", "Type_Event_Param_Status = 269", "Type_Event_Param_Schedule_ID = 270", "Type_Event_Param_Valve_Table_ID = 271", "Type_Event_Param_272", "Type_Event_Param_273", "Type_Event_Param_274", "Type_Event_Param_275", "Type_Event_Param_276", "Type_Event_Param_277", "Type_Event_Param_278", "Type_Event_Param_279", "Type_Event_Param_280", "Type_Event_Param_281", "Type_Event_Param_282", "Type_Event_Param_283", "Type_Event_Param_284", "Type_Event_Param_285", "Type_Event_Param_286", "Type_Event_Param_287", "Type_Event_Param_288", "Type_Event_Param_289", "Type_Event_Param_290", "Type_Event_Param_291", "Type_Event_Param_292", "Type_Event_Param_293", "Type_Event_Param_294", "Type_Event_Param_295", "Type_Event_Param_296", "Type_Event_Param_297", "Type_Event_Param_298", "Type_Event_Param_299", "Type_Event_Param_300", "Type_Event_Param_301", "Type_Event_Param_302", "Type_Event_Param_303", "Type_Event_Param_304", "Type_Event_Param_305", "Type_Event_Param_306", "Type_Event_Param_307", "Type_Event_Param_308", "Type_Event_Param_309", "Type_Event_Param_310", "Type_Event_Param_311", "Type_Event_Param_312", "Type_Event_Param_313", "Type_Event_Param_314", "Type_Event_Param_315", "Type_Event_Param_316", "Type_Event_Param_317", "Type_Event_Param_318", "Type_Event_Param_319", "Type_Event_Param_320", "Type_Event_Param_321", "Type_Event_Param_322", "Type_Event_Param_323", "Type_Event_Param_324", "Type_Event_Param_325", "Type_Event_Param_326", "Type_Event_Param_327", "Type_Event_Param_328", "Type_Event_Param_329", "Type_Event_Param_330", "Type_Event_Param_331", "Type_Event_Param_332", "Type_Event_Param_333", "Type_Event_Param_334", "Type_Event_Param_335", "Type_Event_Param_336", "Type_Event_Param_337", "Type_Event_Param_338", "Type_Event_Param_339", "Type_Event_Param_340", "Type_Event_Param_341", "Type_Event_Param_342", "Type_Event_Param_343", "Type_Event_Param_344", "Type_Event_Param_345", "Type_Event_Param_346", "Type_Event_Param_347", "Type_Event_Param_348", "Type_Event_Param_349", "Type_Event_Param_350", "Type_Event_Param_351", "Type_Event_Param_352", "Type_Event_Param_353", "Type_Event_Param_354", "Type_Event_Param_355", "Type_Event_Param_356", "Type_Event_Param_357", "Type_Event_Param_358", "Type_Event_Param_359", "Type_Event_Param_360", "Type_Event_Param_361", "Type_Event_Param_362", "Type_Event_Param_363", "Type_Event_Param_364", "Type_Event_Param_365", "Type_Event_Param_366", "Type_Event_Param_367", "Type_Event_Param_368", "Type_Event_Param_369", "Type_Event_Param_370", "Type_Event_Param_371", "Type_Event_Param_372", "Type_Event_Param_373", "Type_Event_Param_374", "Type_Event_Param_375", "Type_Event_Param_376", "Type_Event_Param_377", "Type_Event_Param_378", "Type_Event_Param_379", "Type_Event_Param_380", "Type_Event_Param_381", "Type_Event_Param_382", "Type_Event_Param_383", "Type_Event_Param_384", "Type_Event_Param_385", "Type_Event_Param_386", "Type_Event_Param_387", "Type_Event_Param_388", "Type_Event_Param_389", "Type_Event_Param_390", "Type_Event_Param_391", "Type_Event_Param_392", "Type_Event_Param_393", "Type_Event_Param_394", "Type_Event_Param_395", "Type_Event_Param_396", "Type_Event_Param_397", "Type_Event_Param_398", "Type_Event_Param_399", "Type_Event_Param_400", "Type_Event_Param_401", "Type_Event_Param_402", "Type_Event_Param_403", "Type_Event_Param_404", "Type_Event_Param_405", "Type_Event_Param_406", "Type_Event_Param_407", "Type_Event_Param_408", "Type_Event_Param_409", "Type_Event_Param_410", "Type_Event_Param_411", "Type_Event_Param_412", "Type_Event_Param_413", "Type_Event_Param_414", "Type_Event_Param_415", "Type_Event_Param_416", "Type_Event_Param_417", "Type_Event_Param_418", "Type_Event_Param_419", "Type_Event_Param_420", "Type_Event_Param_421", "Type_Event_Param_422", "Type_Event_Param_423", "Type_Event_Param_424", "Type_Event_Param_425", "Type_Event_Param_426", "Type_Event_Param_427", "Type_Event_Param_428", "Type_Event_Param_429", "Type_Event_Param_430", "Type_Event_Param_431", "Type_Event_Param_432", "Type_Event_Param_433", "Type_Event_Param_434", "Type_Event_Param_435", "Type_Event_Param_436", "Type_Event_Param_437", "Type_Event_Param_438", "Type_Event_Param_439", "Type_Event_Param_440", "Type_Event_Param_441", "Type_Event_Param_442", "Type_Event_Param_443", "Type_Event_Param_444", "Type_Event_Param_445", "Type_Event_Param_446", "Type_Event_Param_447", "Type_Event_Param_448", "Type_Event_Param_449", "Type_Event_Param_450", "Type_Event_Param_451", "Type_Event_Param_452", "Type_Event_Param_453", "Type_Event_Param_454", "Type_Event_Param_455", "Type_Event_Param_456", "Type_Event_Param_457", "Type_Event_Param_458", "Type_Event_Param_459", "Type_Event_Param_460", "Type_Event_Param_461", "Type_Event_Param_462", "Type_Event_Param_463", "Type_Event_Param_464", "Type_Event_Param_465", "Type_Event_Param_466", "Type_Event_Param_467", "Type_Event_Param_468", "Type_Event_Param_469", "Type_Event_Param_470", "Type_Event_Param_471", "Type_Event_Param_472", "Type_Event_Param_473", "Type_Event_Param_474", "Type_Event_Param_475", "Type_Event_Param_476", "Type_Event_Param_477", "Type_Event_Param_478", "Type_Event_Param_479", "Type_Event_Param_480", "Type_Event_Param_481", "Type_Event_Param_482", "Type_Event_Param_483", "Type_Event_Param_484", "Type_Event_Param_485", "Type_Event_Param_486", "Type_Event_Param_487", "Type_Event_Param_488", "Type_Event_Param_489", "Type_Event_Param_490", "Type_Event_Param_491", "Type_Event_Param_492", "Type_Event_Param_493", "Type_Event_Param_494", "Type_Event_Param_495", "Type_Event_Param_496", "Type_Event_Param_497", "Type_Event_Param_498", "Type_Event_Param_499", "Type_Event_Param_500", "Type_Event_Param_501", "Type_Event_Param_502", "Type_Event_Param_503", "Type_Event_Param_504", "Type_Event_Param_505", "Type_Event_Param_506", "Type_Event_Param_507", "Type_Event_Param_508", "Type_Event_Param_509", "Type_Event_Param_510", "Type_Event_Param_511", "Type_v1 = 512", "Level_v1 = 513", "AutoClearEvents = 514", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_AssociationCommandConfiguration { enum _enumerated { MaxCommandLength = 0, CommandsAreValues = 1, CommandsAreConfigurable = 2, NumFreeCommands = 3, MaxCommands = 4 }; _enumerated _value; ValueID_Index_AssociationCommandConfiguration(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 5; static const int* _values() { static const int values[] = { (ignore_assign)MaxCommandLength = 0, (ignore_assign)CommandsAreValues = 1, (ignore_assign)CommandsAreConfigurable = 2, (ignore_assign)NumFreeCommands = 3, (ignore_assign)MaxCommands = 4, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "MaxCommandLength = 0", "CommandsAreValues = 1", "CommandsAreConfigurable = 2", "NumFreeCommands = 3", "MaxCommands = 4", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_BarrierOperator { enum _enumerated { Command = 0, Label = 1, SupportedSignals = 2, Audible = 3, Visual = 4 }; _enumerated _value; ValueID_Index_BarrierOperator(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 5; static const int* _values() { static const int values[] = { (ignore_assign)Command = 0, (ignore_assign)Label = 1, (ignore_assign)SupportedSignals = 2, (ignore_assign)Audible = 3, (ignore_assign)Visual = 4, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Command = 0", "Label = 1", "SupportedSignals = 2", "Audible = 3", "Visual = 4", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_Basic { enum _enumerated { Set = 0, Target = 1, Duration = 2 }; _enumerated _value; ValueID_Index_Basic(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 3; static const int* _values() { static const int values[] = { (ignore_assign)Set = 0, (ignore_assign)Target = 1, (ignore_assign)Duration = 2, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Set = 0", "Target = 1", "Duration = 2", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_BasicWindowCovering { enum _enumerated { Open = 0, Close = 1 }; _enumerated _value; ValueID_Index_BasicWindowCovering(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 2; static const int* _values() { static const int values[] = { (ignore_assign)Open = 0, (ignore_assign)Close = 1, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Open = 0", "Close = 1", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_Battery { enum _enumerated { Level = 0 }; _enumerated _value; ValueID_Index_Battery(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 1; static const int* _values() { static const int values[] = { (ignore_assign)Level = 0, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Level = 0", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_CentralScene { enum _enumerated { Scene_1 = 1, Scene_2, Scene_3, Scene_4, Scene_5, Scene_6, Scene_7, Scene_8, Scene_9, Scene_10, Scene_11, Scene_12, Scene_13, Scene_14, Scene_15, Scene_16, Scene_17, Scene_18, Scene_19, Scene_20, Scene_21, Scene_22, Scene_23, Scene_24, Scene_25, Scene_26, Scene_27, Scene_28, Scene_29, Scene_30, Scene_31, Scene_32, Scene_33, Scene_34, Scene_35, Scene_36, Scene_37, Scene_38, Scene_39, Scene_40, Scene_41, Scene_42, Scene_43, Scene_44, Scene_45, Scene_46, Scene_47, Scene_48, Scene_49, Scene_50, Scene_51, Scene_52, Scene_53, Scene_54, Scene_55, Scene_56, Scene_57, Scene_58, Scene_59, Scene_60, Scene_61, Scene_62, Scene_63, Scene_64, Scene_65, Scene_66, Scene_67, Scene_68, Scene_69, Scene_70, Scene_71, Scene_72, Scene_73, Scene_74, Scene_75, Scene_76, Scene_77, Scene_78, Scene_79, Scene_80, Scene_81, Scene_82, Scene_83, Scene_84, Scene_85, Scene_86, Scene_87, Scene_88, Scene_89, Scene_90, Scene_91, Scene_92, Scene_93, Scene_94, Scene_95, Scene_96, Scene_97, Scene_98, Scene_99, Scene_100, Scene_101, Scene_102, Scene_103, Scene_104, Scene_105, Scene_106, Scene_107, Scene_108, Scene_109, Scene_110, Scene_111, Scene_112, Scene_113, Scene_114, Scene_115, Scene_116, Scene_117, Scene_118, Scene_119, Scene_120, Scene_121, Scene_122, Scene_123, Scene_124, Scene_125, Scene_126, Scene_127, Scene_128, Scene_129, Scene_130, Scene_131, Scene_132, Scene_133, Scene_134, Scene_135, Scene_136, Scene_137, Scene_138, Scene_139, Scene_140, Scene_141, Scene_142, Scene_143, Scene_144, Scene_145, Scene_146, Scene_147, Scene_148, Scene_149, Scene_150, Scene_151, Scene_152, Scene_153, Scene_154, Scene_155, Scene_156, Scene_157, Scene_158, Scene_159, Scene_160, Scene_161, Scene_162, Scene_163, Scene_164, Scene_165, Scene_166, Scene_167, Scene_168, Scene_169, Scene_170, Scene_171, Scene_172, Scene_173, Scene_174, Scene_175, Scene_176, Scene_177, Scene_178, Scene_179, Scene_180, Scene_181, Scene_182, Scene_183, Scene_184, Scene_185, Scene_186, Scene_187, Scene_188, Scene_189, Scene_190, Scene_191, Scene_192, Scene_193, Scene_194, Scene_195, Scene_196, Scene_197, Scene_198, Scene_199, Scene_200, Scene_201, Scene_202, Scene_203, Scene_204, Scene_205, Scene_206, Scene_207, Scene_208, Scene_209, Scene_210, Scene_211, Scene_212, Scene_213, Scene_214, Scene_215, Scene_216, Scene_217, Scene_218, Scene_219, Scene_220, Scene_221, Scene_222, Scene_223, Scene_224, Scene_225, Scene_226, Scene_227, Scene_228, Scene_229, Scene_230, Scene_231, Scene_232, Scene_233, Scene_234, Scene_235, Scene_236, Scene_237, Scene_238, Scene_239, Scene_240, Scene_241, Scene_242, Scene_243, Scene_244, Scene_245, Scene_246, Scene_247, Scene_248, Scene_249, Scene_250, Scene_251, Scene_252, Scene_253, Scene_254, Scene_255, SceneCount = 256, ClearSceneTimeout = 257 }; _enumerated _value; ValueID_Index_CentralScene(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 257; static const int* _values() { static const int values[] = { (ignore_assign)Scene_1 = 1, (ignore_assign)Scene_2, (ignore_assign)Scene_3, (ignore_assign)Scene_4, (ignore_assign)Scene_5, (ignore_assign)Scene_6, (ignore_assign)Scene_7, (ignore_assign)Scene_8, (ignore_assign)Scene_9, (ignore_assign)Scene_10, (ignore_assign)Scene_11, (ignore_assign)Scene_12, (ignore_assign)Scene_13, (ignore_assign)Scene_14, (ignore_assign)Scene_15, (ignore_assign)Scene_16, (ignore_assign)Scene_17, (ignore_assign)Scene_18, (ignore_assign)Scene_19, (ignore_assign)Scene_20, (ignore_assign)Scene_21, (ignore_assign)Scene_22, (ignore_assign)Scene_23, (ignore_assign)Scene_24, (ignore_assign)Scene_25, (ignore_assign)Scene_26, (ignore_assign)Scene_27, (ignore_assign)Scene_28, (ignore_assign)Scene_29, (ignore_assign)Scene_30, (ignore_assign)Scene_31, (ignore_assign)Scene_32, (ignore_assign)Scene_33, (ignore_assign)Scene_34, (ignore_assign)Scene_35, (ignore_assign)Scene_36, (ignore_assign)Scene_37, (ignore_assign)Scene_38, (ignore_assign)Scene_39, (ignore_assign)Scene_40, (ignore_assign)Scene_41, (ignore_assign)Scene_42, (ignore_assign)Scene_43, (ignore_assign)Scene_44, (ignore_assign)Scene_45, (ignore_assign)Scene_46, (ignore_assign)Scene_47, (ignore_assign)Scene_48, (ignore_assign)Scene_49, (ignore_assign)Scene_50, (ignore_assign)Scene_51, (ignore_assign)Scene_52, (ignore_assign)Scene_53, (ignore_assign)Scene_54, (ignore_assign)Scene_55, (ignore_assign)Scene_56, (ignore_assign)Scene_57, (ignore_assign)Scene_58, (ignore_assign)Scene_59, (ignore_assign)Scene_60, (ignore_assign)Scene_61, (ignore_assign)Scene_62, (ignore_assign)Scene_63, (ignore_assign)Scene_64, (ignore_assign)Scene_65, (ignore_assign)Scene_66, (ignore_assign)Scene_67, (ignore_assign)Scene_68, (ignore_assign)Scene_69, (ignore_assign)Scene_70, (ignore_assign)Scene_71, (ignore_assign)Scene_72, (ignore_assign)Scene_73, (ignore_assign)Scene_74, (ignore_assign)Scene_75, (ignore_assign)Scene_76, (ignore_assign)Scene_77, (ignore_assign)Scene_78, (ignore_assign)Scene_79, (ignore_assign)Scene_80, (ignore_assign)Scene_81, (ignore_assign)Scene_82, (ignore_assign)Scene_83, (ignore_assign)Scene_84, (ignore_assign)Scene_85, (ignore_assign)Scene_86, (ignore_assign)Scene_87, (ignore_assign)Scene_88, (ignore_assign)Scene_89, (ignore_assign)Scene_90, (ignore_assign)Scene_91, (ignore_assign)Scene_92, (ignore_assign)Scene_93, (ignore_assign)Scene_94, (ignore_assign)Scene_95, (ignore_assign)Scene_96, (ignore_assign)Scene_97, (ignore_assign)Scene_98, (ignore_assign)Scene_99, (ignore_assign)Scene_100, (ignore_assign)Scene_101, (ignore_assign)Scene_102, (ignore_assign)Scene_103, (ignore_assign)Scene_104, (ignore_assign)Scene_105, (ignore_assign)Scene_106, (ignore_assign)Scene_107, (ignore_assign)Scene_108, (ignore_assign)Scene_109, (ignore_assign)Scene_110, (ignore_assign)Scene_111, (ignore_assign)Scene_112, (ignore_assign)Scene_113, (ignore_assign)Scene_114, (ignore_assign)Scene_115, (ignore_assign)Scene_116, (ignore_assign)Scene_117, (ignore_assign)Scene_118, (ignore_assign)Scene_119, (ignore_assign)Scene_120, (ignore_assign)Scene_121, (ignore_assign)Scene_122, (ignore_assign)Scene_123, (ignore_assign)Scene_124, (ignore_assign)Scene_125, (ignore_assign)Scene_126, (ignore_assign)Scene_127, (ignore_assign)Scene_128, (ignore_assign)Scene_129, (ignore_assign)Scene_130, (ignore_assign)Scene_131, (ignore_assign)Scene_132, (ignore_assign)Scene_133, (ignore_assign)Scene_134, (ignore_assign)Scene_135, (ignore_assign)Scene_136, (ignore_assign)Scene_137, (ignore_assign)Scene_138, (ignore_assign)Scene_139, (ignore_assign)Scene_140, (ignore_assign)Scene_141, (ignore_assign)Scene_142, (ignore_assign)Scene_143, (ignore_assign)Scene_144, (ignore_assign)Scene_145, (ignore_assign)Scene_146, (ignore_assign)Scene_147, (ignore_assign)Scene_148, (ignore_assign)Scene_149, (ignore_assign)Scene_150, (ignore_assign)Scene_151, (ignore_assign)Scene_152, (ignore_assign)Scene_153, (ignore_assign)Scene_154, (ignore_assign)Scene_155, (ignore_assign)Scene_156, (ignore_assign)Scene_157, (ignore_assign)Scene_158, (ignore_assign)Scene_159, (ignore_assign)Scene_160, (ignore_assign)Scene_161, (ignore_assign)Scene_162, (ignore_assign)Scene_163, (ignore_assign)Scene_164, (ignore_assign)Scene_165, (ignore_assign)Scene_166, (ignore_assign)Scene_167, (ignore_assign)Scene_168, (ignore_assign)Scene_169, (ignore_assign)Scene_170, (ignore_assign)Scene_171, (ignore_assign)Scene_172, (ignore_assign)Scene_173, (ignore_assign)Scene_174, (ignore_assign)Scene_175, (ignore_assign)Scene_176, (ignore_assign)Scene_177, (ignore_assign)Scene_178, (ignore_assign)Scene_179, (ignore_assign)Scene_180, (ignore_assign)Scene_181, (ignore_assign)Scene_182, (ignore_assign)Scene_183, (ignore_assign)Scene_184, (ignore_assign)Scene_185, (ignore_assign)Scene_186, (ignore_assign)Scene_187, (ignore_assign)Scene_188, (ignore_assign)Scene_189, (ignore_assign)Scene_190, (ignore_assign)Scene_191, (ignore_assign)Scene_192, (ignore_assign)Scene_193, (ignore_assign)Scene_194, (ignore_assign)Scene_195, (ignore_assign)Scene_196, (ignore_assign)Scene_197, (ignore_assign)Scene_198, (ignore_assign)Scene_199, (ignore_assign)Scene_200, (ignore_assign)Scene_201, (ignore_assign)Scene_202, (ignore_assign)Scene_203, (ignore_assign)Scene_204, (ignore_assign)Scene_205, (ignore_assign)Scene_206, (ignore_assign)Scene_207, (ignore_assign)Scene_208, (ignore_assign)Scene_209, (ignore_assign)Scene_210, (ignore_assign)Scene_211, (ignore_assign)Scene_212, (ignore_assign)Scene_213, (ignore_assign)Scene_214, (ignore_assign)Scene_215, (ignore_assign)Scene_216, (ignore_assign)Scene_217, (ignore_assign)Scene_218, (ignore_assign)Scene_219, (ignore_assign)Scene_220, (ignore_assign)Scene_221, (ignore_assign)Scene_222, (ignore_assign)Scene_223, (ignore_assign)Scene_224, (ignore_assign)Scene_225, (ignore_assign)Scene_226, (ignore_assign)Scene_227, (ignore_assign)Scene_228, (ignore_assign)Scene_229, (ignore_assign)Scene_230, (ignore_assign)Scene_231, (ignore_assign)Scene_232, (ignore_assign)Scene_233, (ignore_assign)Scene_234, (ignore_assign)Scene_235, (ignore_assign)Scene_236, (ignore_assign)Scene_237, (ignore_assign)Scene_238, (ignore_assign)Scene_239, (ignore_assign)Scene_240, (ignore_assign)Scene_241, (ignore_assign)Scene_242, (ignore_assign)Scene_243, (ignore_assign)Scene_244, (ignore_assign)Scene_245, (ignore_assign)Scene_246, (ignore_assign)Scene_247, (ignore_assign)Scene_248, (ignore_assign)Scene_249, (ignore_assign)Scene_250, (ignore_assign)Scene_251, (ignore_assign)Scene_252, (ignore_assign)Scene_253, (ignore_assign)Scene_254, (ignore_assign)Scene_255, (ignore_assign)SceneCount = 256, (ignore_assign)ClearSceneTimeout = 257, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Scene_1 = 1", "Scene_2", "Scene_3", "Scene_4", "Scene_5", "Scene_6", "Scene_7", "Scene_8", "Scene_9", "Scene_10", "Scene_11", "Scene_12", "Scene_13", "Scene_14", "Scene_15", "Scene_16", "Scene_17", "Scene_18", "Scene_19", "Scene_20", "Scene_21", "Scene_22", "Scene_23", "Scene_24", "Scene_25", "Scene_26", "Scene_27", "Scene_28", "Scene_29", "Scene_30", "Scene_31", "Scene_32", "Scene_33", "Scene_34", "Scene_35", "Scene_36", "Scene_37", "Scene_38", "Scene_39", "Scene_40", "Scene_41", "Scene_42", "Scene_43", "Scene_44", "Scene_45", "Scene_46", "Scene_47", "Scene_48", "Scene_49", "Scene_50", "Scene_51", "Scene_52", "Scene_53", "Scene_54", "Scene_55", "Scene_56", "Scene_57", "Scene_58", "Scene_59", "Scene_60", "Scene_61", "Scene_62", "Scene_63", "Scene_64", "Scene_65", "Scene_66", "Scene_67", "Scene_68", "Scene_69", "Scene_70", "Scene_71", "Scene_72", "Scene_73", "Scene_74", "Scene_75", "Scene_76", "Scene_77", "Scene_78", "Scene_79", "Scene_80", "Scene_81", "Scene_82", "Scene_83", "Scene_84", "Scene_85", "Scene_86", "Scene_87", "Scene_88", "Scene_89", "Scene_90", "Scene_91", "Scene_92", "Scene_93", "Scene_94", "Scene_95", "Scene_96", "Scene_97", "Scene_98", "Scene_99", "Scene_100", "Scene_101", "Scene_102", "Scene_103", "Scene_104", "Scene_105", "Scene_106", "Scene_107", "Scene_108", "Scene_109", "Scene_110", "Scene_111", "Scene_112", "Scene_113", "Scene_114", "Scene_115", "Scene_116", "Scene_117", "Scene_118", "Scene_119", "Scene_120", "Scene_121", "Scene_122", "Scene_123", "Scene_124", "Scene_125", "Scene_126", "Scene_127", "Scene_128", "Scene_129", "Scene_130", "Scene_131", "Scene_132", "Scene_133", "Scene_134", "Scene_135", "Scene_136", "Scene_137", "Scene_138", "Scene_139", "Scene_140", "Scene_141", "Scene_142", "Scene_143", "Scene_144", "Scene_145", "Scene_146", "Scene_147", "Scene_148", "Scene_149", "Scene_150", "Scene_151", "Scene_152", "Scene_153", "Scene_154", "Scene_155", "Scene_156", "Scene_157", "Scene_158", "Scene_159", "Scene_160", "Scene_161", "Scene_162", "Scene_163", "Scene_164", "Scene_165", "Scene_166", "Scene_167", "Scene_168", "Scene_169", "Scene_170", "Scene_171", "Scene_172", "Scene_173", "Scene_174", "Scene_175", "Scene_176", "Scene_177", "Scene_178", "Scene_179", "Scene_180", "Scene_181", "Scene_182", "Scene_183", "Scene_184", "Scene_185", "Scene_186", "Scene_187", "Scene_188", "Scene_189", "Scene_190", "Scene_191", "Scene_192", "Scene_193", "Scene_194", "Scene_195", "Scene_196", "Scene_197", "Scene_198", "Scene_199", "Scene_200", "Scene_201", "Scene_202", "Scene_203", "Scene_204", "Scene_205", "Scene_206", "Scene_207", "Scene_208", "Scene_209", "Scene_210", "Scene_211", "Scene_212", "Scene_213", "Scene_214", "Scene_215", "Scene_216", "Scene_217", "Scene_218", "Scene_219", "Scene_220", "Scene_221", "Scene_222", "Scene_223", "Scene_224", "Scene_225", "Scene_226", "Scene_227", "Scene_228", "Scene_229", "Scene_230", "Scene_231", "Scene_232", "Scene_233", "Scene_234", "Scene_235", "Scene_236", "Scene_237", "Scene_238", "Scene_239", "Scene_240", "Scene_241", "Scene_242", "Scene_243", "Scene_244", "Scene_245", "Scene_246", "Scene_247", "Scene_248", "Scene_249", "Scene_250", "Scene_251", "Scene_252", "Scene_253", "Scene_254", "Scene_255", "SceneCount = 256", "ClearSceneTimeout = 257", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_ClimateControlSchedule { enum _enumerated { DOW_Monday = 1, DOW_Tuesday = 2, DOW_Wednesday = 3, DOW_Thursday = 4, DOW_Friday = 5, DOW_Saturday = 6, DOW_Sunday = 7, OverrideState = 8, OverrideSetback = 9 }; _enumerated _value; ValueID_Index_ClimateControlSchedule(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 9; static const int* _values() { static const int values[] = { (ignore_assign)DOW_Monday = 1, (ignore_assign)DOW_Tuesday = 2, (ignore_assign)DOW_Wednesday = 3, (ignore_assign)DOW_Thursday = 4, (ignore_assign)DOW_Friday = 5, (ignore_assign)DOW_Saturday = 6, (ignore_assign)DOW_Sunday = 7, (ignore_assign)OverrideState = 8, (ignore_assign)OverrideSetback = 9, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "DOW_Monday = 1", "DOW_Tuesday = 2", "DOW_Wednesday = 3", "DOW_Thursday = 4", "DOW_Friday = 5", "DOW_Saturday = 6", "DOW_Sunday = 7", "OverrideState = 8", "OverrideSetback = 9", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_Clock { enum _enumerated { Day = 0, Hour = 1, Minute = 2 }; _enumerated _value; ValueID_Index_Clock(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 3; static const int* _values() { static const int values[] = { (ignore_assign)Day = 0, (ignore_assign)Hour = 1, (ignore_assign)Minute = 2, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Day = 0", "Hour = 1", "Minute = 2", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_Color { enum _enumerated { Color = 0, Index = 1, Channels_Capabilities = 2, Duration = 4, Target = 5 }; _enumerated _value; ValueID_Index_Color(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 5; static const int* _values() { static const int values[] = { (ignore_assign)Color = 0, (ignore_assign)Index = 1, (ignore_assign)Channels_Capabilities = 2, (ignore_assign)Duration = 4, (ignore_assign)Target = 5, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Color = 0", "Index = 1", "Channels_Capabilities = 2", "Duration = 4", "Target = 5", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_Configuration { enum _enumerated { Parameter_1 = 1, Parameter_2, Parameter_3, Parameter_4, Parameter_5, Parameter_6, Parameter_7, Parameter_8, Parameter_9, Parameter_10, Parameter_11, Parameter_12, Parameter_13, Parameter_14, Parameter_15, Parameter_16, Parameter_17, Parameter_18, Parameter_19, Parameter_20, Parameter_21, Parameter_22, Parameter_23, Parameter_24, Parameter_25, Parameter_26, Parameter_27, Parameter_28, Parameter_29, Parameter_30, Parameter_31, Parameter_32, Parameter_33, Parameter_34, Parameter_35, Parameter_36, Parameter_37, Parameter_38, Parameter_39, Parameter_40, Parameter_41, Parameter_42, Parameter_43, Parameter_44, Parameter_45, Parameter_46, Parameter_47, Parameter_48, Parameter_49, Parameter_50, Parameter_51, Parameter_52, Parameter_53, Parameter_54, Parameter_55, Parameter_56, Parameter_57, Parameter_58, Parameter_59, Parameter_60, Parameter_61, Parameter_62, Parameter_63, Parameter_64, Parameter_65, Parameter_66, Parameter_67, Parameter_68, Parameter_69, Parameter_70, Parameter_71, Parameter_72, Parameter_73, Parameter_74, Parameter_75, Parameter_76, Parameter_77, Parameter_78, Parameter_79, Parameter_80, Parameter_81, Parameter_82, Parameter_83, Parameter_84, Parameter_85, Parameter_86, Parameter_87, Parameter_88, Parameter_89, Parameter_90, Parameter_91, Parameter_92, Parameter_93, Parameter_94, Parameter_95, Parameter_96, Parameter_97, Parameter_98, Parameter_99, Parameter_100, Parameter_101, Parameter_102, Parameter_103, Parameter_104, Parameter_105, Parameter_106, Parameter_107, Parameter_108, Parameter_109, Parameter_110, Parameter_111, Parameter_112, Parameter_113, Parameter_114, Parameter_115, Parameter_116, Parameter_117, Parameter_118, Parameter_119, Parameter_120, Parameter_121, Parameter_122, Parameter_123, Parameter_124, Parameter_125, Parameter_126, Parameter_127, Parameter_128, Parameter_129, Parameter_130, Parameter_131, Parameter_132, Parameter_133, Parameter_134, Parameter_135, Parameter_136, Parameter_137, Parameter_138, Parameter_139, Parameter_140, Parameter_141, Parameter_142, Parameter_143, Parameter_144, Parameter_145, Parameter_146, Parameter_147, Parameter_148, Parameter_149, Parameter_150, Parameter_151, Parameter_152, Parameter_153, Parameter_154, Parameter_155, Parameter_156, Parameter_157, Parameter_158, Parameter_159, Parameter_160, Parameter_161, Parameter_162, Parameter_163, Parameter_164, Parameter_165, Parameter_166, Parameter_167, Parameter_168, Parameter_169, Parameter_170, Parameter_171, Parameter_172, Parameter_173, Parameter_174, Parameter_175, Parameter_176, Parameter_177, Parameter_178, Parameter_179, Parameter_180, Parameter_181, Parameter_182, Parameter_183, Parameter_184, Parameter_185, Parameter_186, Parameter_187, Parameter_188, Parameter_189, Parameter_190, Parameter_191, Parameter_192, Parameter_193, Parameter_194, Parameter_195, Parameter_196, Parameter_197, Parameter_198, Parameter_199, Parameter_200, Parameter_201, Parameter_202, Parameter_203, Parameter_204, Parameter_205, Parameter_206, Parameter_207, Parameter_208, Parameter_209, Parameter_210, Parameter_211, Parameter_212, Parameter_213, Parameter_214, Parameter_215, Parameter_216, Parameter_217, Parameter_218, Parameter_219, Parameter_220, Parameter_221, Parameter_222, Parameter_223, Parameter_224, Parameter_225, Parameter_226, Parameter_227, Parameter_228, Parameter_229, Parameter_230, Parameter_231, Parameter_232, Parameter_233, Parameter_234, Parameter_235, Parameter_236, Parameter_237, Parameter_238, Parameter_239, Parameter_240, Parameter_241, Parameter_242, Parameter_243, Parameter_244, Parameter_245, Parameter_246, Parameter_247, Parameter_248, Parameter_249, Parameter_250, Parameter_251, Parameter_252, Parameter_253, Parameter_254, Parameter_255 }; _enumerated _value; ValueID_Index_Configuration(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 255; static const int* _values() { static const int values[] = { (ignore_assign)Parameter_1 = 1, (ignore_assign)Parameter_2, (ignore_assign)Parameter_3, (ignore_assign)Parameter_4, (ignore_assign)Parameter_5, (ignore_assign)Parameter_6, (ignore_assign)Parameter_7, (ignore_assign)Parameter_8, (ignore_assign)Parameter_9, (ignore_assign)Parameter_10, (ignore_assign)Parameter_11, (ignore_assign)Parameter_12, (ignore_assign)Parameter_13, (ignore_assign)Parameter_14, (ignore_assign)Parameter_15, (ignore_assign)Parameter_16, (ignore_assign)Parameter_17, (ignore_assign)Parameter_18, (ignore_assign)Parameter_19, (ignore_assign)Parameter_20, (ignore_assign)Parameter_21, (ignore_assign)Parameter_22, (ignore_assign)Parameter_23, (ignore_assign)Parameter_24, (ignore_assign)Parameter_25, (ignore_assign)Parameter_26, (ignore_assign)Parameter_27, (ignore_assign)Parameter_28, (ignore_assign)Parameter_29, (ignore_assign)Parameter_30, (ignore_assign)Parameter_31, (ignore_assign)Parameter_32, (ignore_assign)Parameter_33, (ignore_assign)Parameter_34, (ignore_assign)Parameter_35, (ignore_assign)Parameter_36, (ignore_assign)Parameter_37, (ignore_assign)Parameter_38, (ignore_assign)Parameter_39, (ignore_assign)Parameter_40, (ignore_assign)Parameter_41, (ignore_assign)Parameter_42, (ignore_assign)Parameter_43, (ignore_assign)Parameter_44, (ignore_assign)Parameter_45, (ignore_assign)Parameter_46, (ignore_assign)Parameter_47, (ignore_assign)Parameter_48, (ignore_assign)Parameter_49, (ignore_assign)Parameter_50, (ignore_assign)Parameter_51, (ignore_assign)Parameter_52, (ignore_assign)Parameter_53, (ignore_assign)Parameter_54, (ignore_assign)Parameter_55, (ignore_assign)Parameter_56, (ignore_assign)Parameter_57, (ignore_assign)Parameter_58, (ignore_assign)Parameter_59, (ignore_assign)Parameter_60, (ignore_assign)Parameter_61, (ignore_assign)Parameter_62, (ignore_assign)Parameter_63, (ignore_assign)Parameter_64, (ignore_assign)Parameter_65, (ignore_assign)Parameter_66, (ignore_assign)Parameter_67, (ignore_assign)Parameter_68, (ignore_assign)Parameter_69, (ignore_assign)Parameter_70, (ignore_assign)Parameter_71, (ignore_assign)Parameter_72, (ignore_assign)Parameter_73, (ignore_assign)Parameter_74, (ignore_assign)Parameter_75, (ignore_assign)Parameter_76, (ignore_assign)Parameter_77, (ignore_assign)Parameter_78, (ignore_assign)Parameter_79, (ignore_assign)Parameter_80, (ignore_assign)Parameter_81, (ignore_assign)Parameter_82, (ignore_assign)Parameter_83, (ignore_assign)Parameter_84, (ignore_assign)Parameter_85, (ignore_assign)Parameter_86, (ignore_assign)Parameter_87, (ignore_assign)Parameter_88, (ignore_assign)Parameter_89, (ignore_assign)Parameter_90, (ignore_assign)Parameter_91, (ignore_assign)Parameter_92, (ignore_assign)Parameter_93, (ignore_assign)Parameter_94, (ignore_assign)Parameter_95, (ignore_assign)Parameter_96, (ignore_assign)Parameter_97, (ignore_assign)Parameter_98, (ignore_assign)Parameter_99, (ignore_assign)Parameter_100, (ignore_assign)Parameter_101, (ignore_assign)Parameter_102, (ignore_assign)Parameter_103, (ignore_assign)Parameter_104, (ignore_assign)Parameter_105, (ignore_assign)Parameter_106, (ignore_assign)Parameter_107, (ignore_assign)Parameter_108, (ignore_assign)Parameter_109, (ignore_assign)Parameter_110, (ignore_assign)Parameter_111, (ignore_assign)Parameter_112, (ignore_assign)Parameter_113, (ignore_assign)Parameter_114, (ignore_assign)Parameter_115, (ignore_assign)Parameter_116, (ignore_assign)Parameter_117, (ignore_assign)Parameter_118, (ignore_assign)Parameter_119, (ignore_assign)Parameter_120, (ignore_assign)Parameter_121, (ignore_assign)Parameter_122, (ignore_assign)Parameter_123, (ignore_assign)Parameter_124, (ignore_assign)Parameter_125, (ignore_assign)Parameter_126, (ignore_assign)Parameter_127, (ignore_assign)Parameter_128, (ignore_assign)Parameter_129, (ignore_assign)Parameter_130, (ignore_assign)Parameter_131, (ignore_assign)Parameter_132, (ignore_assign)Parameter_133, (ignore_assign)Parameter_134, (ignore_assign)Parameter_135, (ignore_assign)Parameter_136, (ignore_assign)Parameter_137, (ignore_assign)Parameter_138, (ignore_assign)Parameter_139, (ignore_assign)Parameter_140, (ignore_assign)Parameter_141, (ignore_assign)Parameter_142, (ignore_assign)Parameter_143, (ignore_assign)Parameter_144, (ignore_assign)Parameter_145, (ignore_assign)Parameter_146, (ignore_assign)Parameter_147, (ignore_assign)Parameter_148, (ignore_assign)Parameter_149, (ignore_assign)Parameter_150, (ignore_assign)Parameter_151, (ignore_assign)Parameter_152, (ignore_assign)Parameter_153, (ignore_assign)Parameter_154, (ignore_assign)Parameter_155, (ignore_assign)Parameter_156, (ignore_assign)Parameter_157, (ignore_assign)Parameter_158, (ignore_assign)Parameter_159, (ignore_assign)Parameter_160, (ignore_assign)Parameter_161, (ignore_assign)Parameter_162, (ignore_assign)Parameter_163, (ignore_assign)Parameter_164, (ignore_assign)Parameter_165, (ignore_assign)Parameter_166, (ignore_assign)Parameter_167, (ignore_assign)Parameter_168, (ignore_assign)Parameter_169, (ignore_assign)Parameter_170, (ignore_assign)Parameter_171, (ignore_assign)Parameter_172, (ignore_assign)Parameter_173, (ignore_assign)Parameter_174, (ignore_assign)Parameter_175, (ignore_assign)Parameter_176, (ignore_assign)Parameter_177, (ignore_assign)Parameter_178, (ignore_assign)Parameter_179, (ignore_assign)Parameter_180, (ignore_assign)Parameter_181, (ignore_assign)Parameter_182, (ignore_assign)Parameter_183, (ignore_assign)Parameter_184, (ignore_assign)Parameter_185, (ignore_assign)Parameter_186, (ignore_assign)Parameter_187, (ignore_assign)Parameter_188, (ignore_assign)Parameter_189, (ignore_assign)Parameter_190, (ignore_assign)Parameter_191, (ignore_assign)Parameter_192, (ignore_assign)Parameter_193, (ignore_assign)Parameter_194, (ignore_assign)Parameter_195, (ignore_assign)Parameter_196, (ignore_assign)Parameter_197, (ignore_assign)Parameter_198, (ignore_assign)Parameter_199, (ignore_assign)Parameter_200, (ignore_assign)Parameter_201, (ignore_assign)Parameter_202, (ignore_assign)Parameter_203, (ignore_assign)Parameter_204, (ignore_assign)Parameter_205, (ignore_assign)Parameter_206, (ignore_assign)Parameter_207, (ignore_assign)Parameter_208, (ignore_assign)Parameter_209, (ignore_assign)Parameter_210, (ignore_assign)Parameter_211, (ignore_assign)Parameter_212, (ignore_assign)Parameter_213, (ignore_assign)Parameter_214, (ignore_assign)Parameter_215, (ignore_assign)Parameter_216, (ignore_assign)Parameter_217, (ignore_assign)Parameter_218, (ignore_assign)Parameter_219, (ignore_assign)Parameter_220, (ignore_assign)Parameter_221, (ignore_assign)Parameter_222, (ignore_assign)Parameter_223, (ignore_assign)Parameter_224, (ignore_assign)Parameter_225, (ignore_assign)Parameter_226, (ignore_assign)Parameter_227, (ignore_assign)Parameter_228, (ignore_assign)Parameter_229, (ignore_assign)Parameter_230, (ignore_assign)Parameter_231, (ignore_assign)Parameter_232, (ignore_assign)Parameter_233, (ignore_assign)Parameter_234, (ignore_assign)Parameter_235, (ignore_assign)Parameter_236, (ignore_assign)Parameter_237, (ignore_assign)Parameter_238, (ignore_assign)Parameter_239, (ignore_assign)Parameter_240, (ignore_assign)Parameter_241, (ignore_assign)Parameter_242, (ignore_assign)Parameter_243, (ignore_assign)Parameter_244, (ignore_assign)Parameter_245, (ignore_assign)Parameter_246, (ignore_assign)Parameter_247, (ignore_assign)Parameter_248, (ignore_assign)Parameter_249, (ignore_assign)Parameter_250, (ignore_assign)Parameter_251, (ignore_assign)Parameter_252, (ignore_assign)Parameter_253, (ignore_assign)Parameter_254, (ignore_assign)Parameter_255, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Parameter_1 = 1", "Parameter_2", "Parameter_3", "Parameter_4", "Parameter_5", "Parameter_6", "Parameter_7", "Parameter_8", "Parameter_9", "Parameter_10", "Parameter_11", "Parameter_12", "Parameter_13", "Parameter_14", "Parameter_15", "Parameter_16", "Parameter_17", "Parameter_18", "Parameter_19", "Parameter_20", "Parameter_21", "Parameter_22", "Parameter_23", "Parameter_24", "Parameter_25", "Parameter_26", "Parameter_27", "Parameter_28", "Parameter_29", "Parameter_30", "Parameter_31", "Parameter_32", "Parameter_33", "Parameter_34", "Parameter_35", "Parameter_36", "Parameter_37", "Parameter_38", "Parameter_39", "Parameter_40", "Parameter_41", "Parameter_42", "Parameter_43", "Parameter_44", "Parameter_45", "Parameter_46", "Parameter_47", "Parameter_48", "Parameter_49", "Parameter_50", "Parameter_51", "Parameter_52", "Parameter_53", "Parameter_54", "Parameter_55", "Parameter_56", "Parameter_57", "Parameter_58", "Parameter_59", "Parameter_60", "Parameter_61", "Parameter_62", "Parameter_63", "Parameter_64", "Parameter_65", "Parameter_66", "Parameter_67", "Parameter_68", "Parameter_69", "Parameter_70", "Parameter_71", "Parameter_72", "Parameter_73", "Parameter_74", "Parameter_75", "Parameter_76", "Parameter_77", "Parameter_78", "Parameter_79", "Parameter_80", "Parameter_81", "Parameter_82", "Parameter_83", "Parameter_84", "Parameter_85", "Parameter_86", "Parameter_87", "Parameter_88", "Parameter_89", "Parameter_90", "Parameter_91", "Parameter_92", "Parameter_93", "Parameter_94", "Parameter_95", "Parameter_96", "Parameter_97", "Parameter_98", "Parameter_99", "Parameter_100", "Parameter_101", "Parameter_102", "Parameter_103", "Parameter_104", "Parameter_105", "Parameter_106", "Parameter_107", "Parameter_108", "Parameter_109", "Parameter_110", "Parameter_111", "Parameter_112", "Parameter_113", "Parameter_114", "Parameter_115", "Parameter_116", "Parameter_117", "Parameter_118", "Parameter_119", "Parameter_120", "Parameter_121", "Parameter_122", "Parameter_123", "Parameter_124", "Parameter_125", "Parameter_126", "Parameter_127", "Parameter_128", "Parameter_129", "Parameter_130", "Parameter_131", "Parameter_132", "Parameter_133", "Parameter_134", "Parameter_135", "Parameter_136", "Parameter_137", "Parameter_138", "Parameter_139", "Parameter_140", "Parameter_141", "Parameter_142", "Parameter_143", "Parameter_144", "Parameter_145", "Parameter_146", "Parameter_147", "Parameter_148", "Parameter_149", "Parameter_150", "Parameter_151", "Parameter_152", "Parameter_153", "Parameter_154", "Parameter_155", "Parameter_156", "Parameter_157", "Parameter_158", "Parameter_159", "Parameter_160", "Parameter_161", "Parameter_162", "Parameter_163", "Parameter_164", "Parameter_165", "Parameter_166", "Parameter_167", "Parameter_168", "Parameter_169", "Parameter_170", "Parameter_171", "Parameter_172", "Parameter_173", "Parameter_174", "Parameter_175", "Parameter_176", "Parameter_177", "Parameter_178", "Parameter_179", "Parameter_180", "Parameter_181", "Parameter_182", "Parameter_183", "Parameter_184", "Parameter_185", "Parameter_186", "Parameter_187", "Parameter_188", "Parameter_189", "Parameter_190", "Parameter_191", "Parameter_192", "Parameter_193", "Parameter_194", "Parameter_195", "Parameter_196", "Parameter_197", "Parameter_198", "Parameter_199", "Parameter_200", "Parameter_201", "Parameter_202", "Parameter_203", "Parameter_204", "Parameter_205", "Parameter_206", "Parameter_207", "Parameter_208", "Parameter_209", "Parameter_210", "Parameter_211", "Parameter_212", "Parameter_213", "Parameter_214", "Parameter_215", "Parameter_216", "Parameter_217", "Parameter_218", "Parameter_219", "Parameter_220", "Parameter_221", "Parameter_222", "Parameter_223", "Parameter_224", "Parameter_225", "Parameter_226", "Parameter_227", "Parameter_228", "Parameter_229", "Parameter_230", "Parameter_231", "Parameter_232", "Parameter_233", "Parameter_234", "Parameter_235", "Parameter_236", "Parameter_237", "Parameter_238", "Parameter_239", "Parameter_240", "Parameter_241", "Parameter_242", "Parameter_243", "Parameter_244", "Parameter_245", "Parameter_246", "Parameter_247", "Parameter_248", "Parameter_249", "Parameter_250", "Parameter_251", "Parameter_252", "Parameter_253", "Parameter_254", "Parameter_255", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_ControllerReplication { enum _enumerated { NodeId = 0, Function = 1, Replicate = 2 }; _enumerated _value; ValueID_Index_ControllerReplication(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 3; static const int* _values() { static const int values[] = { (ignore_assign)NodeId = 0, (ignore_assign)Function = 1, (ignore_assign)Replicate = 2, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "NodeId = 0", "Function = 1", "Replicate = 2", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_DoorLock { enum _enumerated { Lock = 0, Lock_Mode = 1, System_Config_Mode = 2, System_Config_Minutes = 3, System_Config_Seconds = 4, System_Config_OutsideHandles = 5, System_Config_InsideHandles = 6 }; _enumerated _value; ValueID_Index_DoorLock(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 7; static const int* _values() { static const int values[] = { (ignore_assign)Lock = 0, (ignore_assign)Lock_Mode = 1, (ignore_assign)System_Config_Mode = 2, (ignore_assign)System_Config_Minutes = 3, (ignore_assign)System_Config_Seconds = 4, (ignore_assign)System_Config_OutsideHandles = 5, (ignore_assign)System_Config_InsideHandles = 6, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Lock = 0", "Lock_Mode = 1", "System_Config_Mode = 2", "System_Config_Minutes = 3", "System_Config_Seconds = 4", "System_Config_OutsideHandles = 5", "System_Config_InsideHandles = 6", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_DoorLockLogging { enum _enumerated { System_Config_MaxRecords = 0, GetRecordNo = 1, LogRecord = 2 }; _enumerated _value; ValueID_Index_DoorLockLogging(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 3; static const int* _values() { static const int values[] = { (ignore_assign)System_Config_MaxRecords = 0, (ignore_assign)GetRecordNo = 1, (ignore_assign)LogRecord = 2, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "System_Config_MaxRecords = 0", "GetRecordNo = 1", "LogRecord = 2", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_EnergyProduction { enum _enumerated { Instant = 0, Total = 1, Today = 2, Time = 3 }; _enumerated _value; ValueID_Index_EnergyProduction(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 4; static const int* _values() { static const int values[] = { (ignore_assign)Instant = 0, (ignore_assign)Total = 1, (ignore_assign)Today = 2, (ignore_assign)Time = 3, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Instant = 0", "Total = 1", "Today = 2", "Time = 3", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_Indicator { enum _enumerated { Indicator = 0, Armed = 1, Not_Armed, Ready, Fault, Busy, Enter_ID, Enter_PIN, Code_Accepted, Code_Not_Accepted, Armed_Stay, Armed_Away, Alarming, Alarming_Burglar, Alarming_Smoke_Fire, Alarming_Carbon_Monoxide, Bypass_Challenge, Entry_Delay, Exit_Delay, Alarming_Medical, Alarming_Freeze_Warning, Alarming_Water_Leak, Alarming_Panic, Zone_1_Armed = 0x20, Zone_2_Armed, Zone_3_Armed, Zone_4_Armed, Zone_5_Armed, Zone_6_Armed, Zone_7_Armed, Zone_8_Armed, LCD_Backlight = 0x30, Button_Backlight_Letters = 0x40, Button_Backlight_Digits, Button_Backlight_Command, Button_1_Indication, Button_2_Indication, Button_3_Indication, Button_4_Indication, Button_5_Indication, Button_6_Indication, Button_7_Indication, Button_8_Indication, Button_9_Indication, Button_10_Indication, Button_11_Indication, Button_12_Indication, Node_Identify = 0x50, Generic_Event_Sound_Notification_1 = 0x60, Generic_Event_Sound_Notification_2, Generic_Event_Sound_Notification_3, Generic_Event_Sound_Notification_4, Generic_Event_Sound_Notification_5, Generic_Event_Sound_Notification_6, Generic_Event_Sound_Notification_7, Generic_Event_Sound_Notification_8, Generic_Event_Sound_Notification_9, Generic_Event_Sound_Notification_10, Generic_Event_Sound_Notification_11, Generic_Event_Sound_Notification_12, Generic_Event_Sound_Notification_13, Generic_Event_Sound_Notification_14, Generic_Event_Sound_Notification_15, Generic_Event_Sound_Notification_16, Generic_Event_Sound_Notification_17, Generic_Event_Sound_Notification_18, Generic_Event_Sound_Notification_19, Generic_Event_Sound_Notification_20, Generic_Event_Sound_Notification_21, Generic_Event_Sound_Notification_22, Generic_Event_Sound_Notification_23, Generic_Event_Sound_Notification_24, Generic_Event_Sound_Notification_25, Generic_Event_Sound_Notification_26, Generic_Event_Sound_Notification_27, Generic_Event_Sound_Notification_28, Generic_Event_Sound_Notification_29, Generic_Event_Sound_Notification_30, Generic_Event_Sound_Notification_31, Generic_Event_Sound_Notification_32, Manufacturer_Defined_Indicator_1 = 0x80, Manufacturer_Defined_Indicator_2, Manufacturer_Defined_Indicator_3, Manufacturer_Defined_Indicator_4, Manufacturer_Defined_Indicator_5, Manufacturer_Defined_Indicator_6, Manufacturer_Defined_Indicator_7, Manufacturer_Defined_Indicator_8, Manufacturer_Defined_Indicator_9, Manufacturer_Defined_Indicator_10, Manufacturer_Defined_Indicator_11, Manufacturer_Defined_Indicator_12, Manufacturer_Defined_Indicator_13, Manufacturer_Defined_Indicator_14, Manufacturer_Defined_Indicator_15, Manufacturer_Defined_Indicator_16, Manufacturer_Defined_Indicator_17, Manufacturer_Defined_Indicator_18, Manufacturer_Defined_Indicator_19, Manufacturer_Defined_Indicator_20, Manufacturer_Defined_Indicator_21, Manufacturer_Defined_Indicator_22, Manufacturer_Defined_Indicator_23, Manufacturer_Defined_Indicator_24, Manufacturer_Defined_Indicator_25, Manufacturer_Defined_Indicator_26, Manufacturer_Defined_Indicator_27, Manufacturer_Defined_Indicator_28, Manufacturer_Defined_Indicator_29, Manufacturer_Defined_Indicator_30, Manufacturer_Defined_Indicator_31, Manufacturer_Defined_Indicator_32, Buzzer = 0xF0 }; _enumerated _value; ValueID_Index_Indicator(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 113; static const int* _values() { static const int values[] = { (ignore_assign)Indicator = 0, (ignore_assign)Armed = 1, (ignore_assign)Not_Armed, (ignore_assign)Ready, (ignore_assign)Fault, (ignore_assign)Busy, (ignore_assign)Enter_ID, (ignore_assign)Enter_PIN, (ignore_assign)Code_Accepted, (ignore_assign)Code_Not_Accepted, (ignore_assign)Armed_Stay, (ignore_assign)Armed_Away, (ignore_assign)Alarming, (ignore_assign)Alarming_Burglar, (ignore_assign)Alarming_Smoke_Fire, (ignore_assign)Alarming_Carbon_Monoxide, (ignore_assign)Bypass_Challenge, (ignore_assign)Entry_Delay, (ignore_assign)Exit_Delay, (ignore_assign)Alarming_Medical, (ignore_assign)Alarming_Freeze_Warning, (ignore_assign)Alarming_Water_Leak, (ignore_assign)Alarming_Panic, (ignore_assign)Zone_1_Armed = 0x20, (ignore_assign)Zone_2_Armed, (ignore_assign)Zone_3_Armed, (ignore_assign)Zone_4_Armed, (ignore_assign)Zone_5_Armed, (ignore_assign)Zone_6_Armed, (ignore_assign)Zone_7_Armed, (ignore_assign)Zone_8_Armed, (ignore_assign)LCD_Backlight = 0x30, (ignore_assign)Button_Backlight_Letters = 0x40, (ignore_assign)Button_Backlight_Digits, (ignore_assign)Button_Backlight_Command, (ignore_assign)Button_1_Indication, (ignore_assign)Button_2_Indication, (ignore_assign)Button_3_Indication, (ignore_assign)Button_4_Indication, (ignore_assign)Button_5_Indication, (ignore_assign)Button_6_Indication, (ignore_assign)Button_7_Indication, (ignore_assign)Button_8_Indication, (ignore_assign)Button_9_Indication, (ignore_assign)Button_10_Indication, (ignore_assign)Button_11_Indication, (ignore_assign)Button_12_Indication, (ignore_assign)Node_Identify = 0x50, (ignore_assign)Generic_Event_Sound_Notification_1 = 0x60, (ignore_assign)Generic_Event_Sound_Notification_2, (ignore_assign)Generic_Event_Sound_Notification_3, (ignore_assign)Generic_Event_Sound_Notification_4, (ignore_assign)Generic_Event_Sound_Notification_5, (ignore_assign)Generic_Event_Sound_Notification_6, (ignore_assign)Generic_Event_Sound_Notification_7, (ignore_assign)Generic_Event_Sound_Notification_8, (ignore_assign)Generic_Event_Sound_Notification_9, (ignore_assign)Generic_Event_Sound_Notification_10, (ignore_assign)Generic_Event_Sound_Notification_11, (ignore_assign)Generic_Event_Sound_Notification_12, (ignore_assign)Generic_Event_Sound_Notification_13, (ignore_assign)Generic_Event_Sound_Notification_14, (ignore_assign)Generic_Event_Sound_Notification_15, (ignore_assign)Generic_Event_Sound_Notification_16, (ignore_assign)Generic_Event_Sound_Notification_17, (ignore_assign)Generic_Event_Sound_Notification_18, (ignore_assign)Generic_Event_Sound_Notification_19, (ignore_assign)Generic_Event_Sound_Notification_20, (ignore_assign)Generic_Event_Sound_Notification_21, (ignore_assign)Generic_Event_Sound_Notification_22, (ignore_assign)Generic_Event_Sound_Notification_23, (ignore_assign)Generic_Event_Sound_Notification_24, (ignore_assign)Generic_Event_Sound_Notification_25, (ignore_assign)Generic_Event_Sound_Notification_26, (ignore_assign)Generic_Event_Sound_Notification_27, (ignore_assign)Generic_Event_Sound_Notification_28, (ignore_assign)Generic_Event_Sound_Notification_29, (ignore_assign)Generic_Event_Sound_Notification_30, (ignore_assign)Generic_Event_Sound_Notification_31, (ignore_assign)Generic_Event_Sound_Notification_32, (ignore_assign)Manufacturer_Defined_Indicator_1 = 0x80, (ignore_assign)Manufacturer_Defined_Indicator_2, (ignore_assign)Manufacturer_Defined_Indicator_3, (ignore_assign)Manufacturer_Defined_Indicator_4, (ignore_assign)Manufacturer_Defined_Indicator_5, (ignore_assign)Manufacturer_Defined_Indicator_6, (ignore_assign)Manufacturer_Defined_Indicator_7, (ignore_assign)Manufacturer_Defined_Indicator_8, (ignore_assign)Manufacturer_Defined_Indicator_9, (ignore_assign)Manufacturer_Defined_Indicator_10, (ignore_assign)Manufacturer_Defined_Indicator_11, (ignore_assign)Manufacturer_Defined_Indicator_12, (ignore_assign)Manufacturer_Defined_Indicator_13, (ignore_assign)Manufacturer_Defined_Indicator_14, (ignore_assign)Manufacturer_Defined_Indicator_15, (ignore_assign)Manufacturer_Defined_Indicator_16, (ignore_assign)Manufacturer_Defined_Indicator_17, (ignore_assign)Manufacturer_Defined_Indicator_18, (ignore_assign)Manufacturer_Defined_Indicator_19, (ignore_assign)Manufacturer_Defined_Indicator_20, (ignore_assign)Manufacturer_Defined_Indicator_21, (ignore_assign)Manufacturer_Defined_Indicator_22, (ignore_assign)Manufacturer_Defined_Indicator_23, (ignore_assign)Manufacturer_Defined_Indicator_24, (ignore_assign)Manufacturer_Defined_Indicator_25, (ignore_assign)Manufacturer_Defined_Indicator_26, (ignore_assign)Manufacturer_Defined_Indicator_27, (ignore_assign)Manufacturer_Defined_Indicator_28, (ignore_assign)Manufacturer_Defined_Indicator_29, (ignore_assign)Manufacturer_Defined_Indicator_30, (ignore_assign)Manufacturer_Defined_Indicator_31, (ignore_assign)Manufacturer_Defined_Indicator_32, (ignore_assign)Buzzer = 0xF0, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Indicator = 0", "Armed = 1", "Not_Armed", "Ready", "Fault", "Busy", "Enter_ID", "Enter_PIN", "Code_Accepted", "Code_Not_Accepted", "Armed_Stay", "Armed_Away", "Alarming", "Alarming_Burglar", "Alarming_Smoke_Fire", "Alarming_Carbon_Monoxide", "Bypass_Challenge", "Entry_Delay", "Exit_Delay", "Alarming_Medical", "Alarming_Freeze_Warning", "Alarming_Water_Leak", "Alarming_Panic", "Zone_1_Armed = 0x20", "Zone_2_Armed", "Zone_3_Armed", "Zone_4_Armed", "Zone_5_Armed", "Zone_6_Armed", "Zone_7_Armed", "Zone_8_Armed", "LCD_Backlight = 0x30", "Button_Backlight_Letters = 0x40", "Button_Backlight_Digits", "Button_Backlight_Command", "Button_1_Indication", "Button_2_Indication", "Button_3_Indication", "Button_4_Indication", "Button_5_Indication", "Button_6_Indication", "Button_7_Indication", "Button_8_Indication", "Button_9_Indication", "Button_10_Indication", "Button_11_Indication", "Button_12_Indication", "Node_Identify = 0x50", "Generic_Event_Sound_Notification_1 = 0x60", "Generic_Event_Sound_Notification_2", "Generic_Event_Sound_Notification_3", "Generic_Event_Sound_Notification_4", "Generic_Event_Sound_Notification_5", "Generic_Event_Sound_Notification_6", "Generic_Event_Sound_Notification_7", "Generic_Event_Sound_Notification_8", "Generic_Event_Sound_Notification_9", "Generic_Event_Sound_Notification_10", "Generic_Event_Sound_Notification_11", "Generic_Event_Sound_Notification_12", "Generic_Event_Sound_Notification_13", "Generic_Event_Sound_Notification_14", "Generic_Event_Sound_Notification_15", "Generic_Event_Sound_Notification_16", "Generic_Event_Sound_Notification_17", "Generic_Event_Sound_Notification_18", "Generic_Event_Sound_Notification_19", "Generic_Event_Sound_Notification_20", "Generic_Event_Sound_Notification_21", "Generic_Event_Sound_Notification_22", "Generic_Event_Sound_Notification_23", "Generic_Event_Sound_Notification_24", "Generic_Event_Sound_Notification_25", "Generic_Event_Sound_Notification_26", "Generic_Event_Sound_Notification_27", "Generic_Event_Sound_Notification_28", "Generic_Event_Sound_Notification_29", "Generic_Event_Sound_Notification_30", "Generic_Event_Sound_Notification_31", "Generic_Event_Sound_Notification_32", "Manufacturer_Defined_Indicator_1 = 0x80", "Manufacturer_Defined_Indicator_2", "Manufacturer_Defined_Indicator_3", "Manufacturer_Defined_Indicator_4", "Manufacturer_Defined_Indicator_5", "Manufacturer_Defined_Indicator_6", "Manufacturer_Defined_Indicator_7", "Manufacturer_Defined_Indicator_8", "Manufacturer_Defined_Indicator_9", "Manufacturer_Defined_Indicator_10", "Manufacturer_Defined_Indicator_11", "Manufacturer_Defined_Indicator_12", "Manufacturer_Defined_Indicator_13", "Manufacturer_Defined_Indicator_14", "Manufacturer_Defined_Indicator_15", "Manufacturer_Defined_Indicator_16", "Manufacturer_Defined_Indicator_17", "Manufacturer_Defined_Indicator_18", "Manufacturer_Defined_Indicator_19", "Manufacturer_Defined_Indicator_20", "Manufacturer_Defined_Indicator_21", "Manufacturer_Defined_Indicator_22", "Manufacturer_Defined_Indicator_23", "Manufacturer_Defined_Indicator_24", "Manufacturer_Defined_Indicator_25", "Manufacturer_Defined_Indicator_26", "Manufacturer_Defined_Indicator_27", "Manufacturer_Defined_Indicator_28", "Manufacturer_Defined_Indicator_29", "Manufacturer_Defined_Indicator_30", "Manufacturer_Defined_Indicator_31", "Manufacturer_Defined_Indicator_32", "Buzzer = 0xF0", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_Language { enum _enumerated { Language = 0, Country = 1 }; _enumerated _value; ValueID_Index_Language(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 2; static const int* _values() { static const int values[] = { (ignore_assign)Language = 0, (ignore_assign)Country = 1, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Language = 0", "Country = 1", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_Lock { enum _enumerated { Locked = 0 }; _enumerated _value; ValueID_Index_Lock(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 1; static const int* _values() { static const int values[] = { (ignore_assign)Locked = 0, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Locked = 0", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_ManufacturerProprietary { enum _enumerated { FibaroVenetianBlinds_Blinds = 0, FibaroVenetianBlinds_Tilt = 1 }; _enumerated _value; ValueID_Index_ManufacturerProprietary(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 2; static const int* _values() { static const int values[] = { (ignore_assign)FibaroVenetianBlinds_Blinds = 0, (ignore_assign)FibaroVenetianBlinds_Tilt = 1, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "FibaroVenetianBlinds_Blinds = 0", "FibaroVenetianBlinds_Tilt = 1", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_ManufacturerSpecific { enum _enumerated { LoadedConfig = 0, LocalConfig = 1, LatestConfig = 2, DeviceID = 3, SerialNumber = 4 }; _enumerated _value; ValueID_Index_ManufacturerSpecific(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 5; static const int* _values() { static const int values[] = { (ignore_assign)LoadedConfig = 0, (ignore_assign)LocalConfig = 1, (ignore_assign)LatestConfig = 2, (ignore_assign)DeviceID = 3, (ignore_assign)SerialNumber = 4, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "LoadedConfig = 0", "LocalConfig = 1", "LatestConfig = 2", "DeviceID = 3", "SerialNumber = 4", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_Meter { enum _enumerated { Electric_kWh = 0, Electric_kVah, Electric_W, Electric_Pulse, Electric_V, Electric_A, Electric_PowerFactor, Electric_Unknown_1, Electric_kVar, Electric_kVarh, Electric_Unknown_2, Electric_Unknown_3, Electric_Unknown_4, Electric_Unknown_5, Electric_Unknown_6, Electric_Unknown_7, Gas_Cubic_Meters, Gas_Cubic_Feet, Gas_Unknown_1, Gas_Pulse, Gas_Unknown_2, Gas_Unknown_3, Gas_Unknown_4, Gas_Unknown_5, Gas_Unknown_6, Gas_Unknown_7, Gas_Unknown_8, Gas_Unknown_9, Gas_Unknown_10, Gas_Unknown_11, Gas_Unknown_12, Gas_Unknown_13, Water_Cubic_Meters, Water_Cubic_Feet, Water_Cubic_US_Gallons, Water_Cubic_Pulse, Water_Unknown_1, Water_Unknown_2, Water_Unknown_3, Water_Unknown_4, Water_Unknown_5, Water_Unknown_6, Water_Unknown_7, Water_Unknown_8, Water_Unknown_9, Water_Unknown_10, Water_Unknown_11, Water_Unknown_12, Heating_kWh, Heating_Unknown_1, Heating_Unknown_2, Heating_Unknown_3, Heating_Unknown_4, Heating_Unknown_5, Heating_Unknown_6, Heating_Unknown_7, Heating_Unknown_8, Heating_Unknown_9, Heating_Unknown_10, Heating_Unknown_11, Heating_Unknown_12, Heating_Unknown_13, Heating_Unknown_14, Heating_Unknown_15, Cooling_kWh, Cooling_Unknown_1, Cooling_Unknown_2, Cooling_Unknown_3, Cooling_Unknown_4, Cooling_Unknown_5, Cooling_Unknown_6, Cooling_Unknown_7, Cooling_Unknown_8, Cooling_Unknown_9, Cooling_Unknown_10, Cooling_Unknown_11, Cooling_Unknown_12, Cooling_Unknown_13, Cooling_Unknown_14, Cooling_Unknown_15, Exporting = 256, Reset = 257 }; _enumerated _value; ValueID_Index_Meter(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 82; static const int* _values() { static const int values[] = { (ignore_assign)Electric_kWh = 0, (ignore_assign)Electric_kVah, (ignore_assign)Electric_W, (ignore_assign)Electric_Pulse, (ignore_assign)Electric_V, (ignore_assign)Electric_A, (ignore_assign)Electric_PowerFactor, (ignore_assign)Electric_Unknown_1, (ignore_assign)Electric_kVar, (ignore_assign)Electric_kVarh, (ignore_assign)Electric_Unknown_2, (ignore_assign)Electric_Unknown_3, (ignore_assign)Electric_Unknown_4, (ignore_assign)Electric_Unknown_5, (ignore_assign)Electric_Unknown_6, (ignore_assign)Electric_Unknown_7, (ignore_assign)Gas_Cubic_Meters, (ignore_assign)Gas_Cubic_Feet, (ignore_assign)Gas_Unknown_1, (ignore_assign)Gas_Pulse, (ignore_assign)Gas_Unknown_2, (ignore_assign)Gas_Unknown_3, (ignore_assign)Gas_Unknown_4, (ignore_assign)Gas_Unknown_5, (ignore_assign)Gas_Unknown_6, (ignore_assign)Gas_Unknown_7, (ignore_assign)Gas_Unknown_8, (ignore_assign)Gas_Unknown_9, (ignore_assign)Gas_Unknown_10, (ignore_assign)Gas_Unknown_11, (ignore_assign)Gas_Unknown_12, (ignore_assign)Gas_Unknown_13, (ignore_assign)Water_Cubic_Meters, (ignore_assign)Water_Cubic_Feet, (ignore_assign)Water_Cubic_US_Gallons, (ignore_assign)Water_Cubic_Pulse, (ignore_assign)Water_Unknown_1, (ignore_assign)Water_Unknown_2, (ignore_assign)Water_Unknown_3, (ignore_assign)Water_Unknown_4, (ignore_assign)Water_Unknown_5, (ignore_assign)Water_Unknown_6, (ignore_assign)Water_Unknown_7, (ignore_assign)Water_Unknown_8, (ignore_assign)Water_Unknown_9, (ignore_assign)Water_Unknown_10, (ignore_assign)Water_Unknown_11, (ignore_assign)Water_Unknown_12, (ignore_assign)Heating_kWh, (ignore_assign)Heating_Unknown_1, (ignore_assign)Heating_Unknown_2, (ignore_assign)Heating_Unknown_3, (ignore_assign)Heating_Unknown_4, (ignore_assign)Heating_Unknown_5, (ignore_assign)Heating_Unknown_6, (ignore_assign)Heating_Unknown_7, (ignore_assign)Heating_Unknown_8, (ignore_assign)Heating_Unknown_9, (ignore_assign)Heating_Unknown_10, (ignore_assign)Heating_Unknown_11, (ignore_assign)Heating_Unknown_12, (ignore_assign)Heating_Unknown_13, (ignore_assign)Heating_Unknown_14, (ignore_assign)Heating_Unknown_15, (ignore_assign)Cooling_kWh, (ignore_assign)Cooling_Unknown_1, (ignore_assign)Cooling_Unknown_2, (ignore_assign)Cooling_Unknown_3, (ignore_assign)Cooling_Unknown_4, (ignore_assign)Cooling_Unknown_5, (ignore_assign)Cooling_Unknown_6, (ignore_assign)Cooling_Unknown_7, (ignore_assign)Cooling_Unknown_8, (ignore_assign)Cooling_Unknown_9, (ignore_assign)Cooling_Unknown_10, (ignore_assign)Cooling_Unknown_11, (ignore_assign)Cooling_Unknown_12, (ignore_assign)Cooling_Unknown_13, (ignore_assign)Cooling_Unknown_14, (ignore_assign)Cooling_Unknown_15, (ignore_assign)Exporting = 256, (ignore_assign)Reset = 257, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Electric_kWh = 0", "Electric_kVah", "Electric_W", "Electric_Pulse", "Electric_V", "Electric_A", "Electric_PowerFactor", "Electric_Unknown_1", "Electric_kVar", "Electric_kVarh", "Electric_Unknown_2", "Electric_Unknown_3", "Electric_Unknown_4", "Electric_Unknown_5", "Electric_Unknown_6", "Electric_Unknown_7", "Gas_Cubic_Meters", "Gas_Cubic_Feet", "Gas_Unknown_1", "Gas_Pulse", "Gas_Unknown_2", "Gas_Unknown_3", "Gas_Unknown_4", "Gas_Unknown_5", "Gas_Unknown_6", "Gas_Unknown_7", "Gas_Unknown_8", "Gas_Unknown_9", "Gas_Unknown_10", "Gas_Unknown_11", "Gas_Unknown_12", "Gas_Unknown_13", "Water_Cubic_Meters", "Water_Cubic_Feet", "Water_Cubic_US_Gallons", "Water_Cubic_Pulse", "Water_Unknown_1", "Water_Unknown_2", "Water_Unknown_3", "Water_Unknown_4", "Water_Unknown_5", "Water_Unknown_6", "Water_Unknown_7", "Water_Unknown_8", "Water_Unknown_9", "Water_Unknown_10", "Water_Unknown_11", "Water_Unknown_12", "Heating_kWh", "Heating_Unknown_1", "Heating_Unknown_2", "Heating_Unknown_3", "Heating_Unknown_4", "Heating_Unknown_5", "Heating_Unknown_6", "Heating_Unknown_7", "Heating_Unknown_8", "Heating_Unknown_9", "Heating_Unknown_10", "Heating_Unknown_11", "Heating_Unknown_12", "Heating_Unknown_13", "Heating_Unknown_14", "Heating_Unknown_15", "Cooling_kWh", "Cooling_Unknown_1", "Cooling_Unknown_2", "Cooling_Unknown_3", "Cooling_Unknown_4", "Cooling_Unknown_5", "Cooling_Unknown_6", "Cooling_Unknown_7", "Cooling_Unknown_8", "Cooling_Unknown_9", "Cooling_Unknown_10", "Cooling_Unknown_11", "Cooling_Unknown_12", "Cooling_Unknown_13", "Cooling_Unknown_14", "Cooling_Unknown_15", "Exporting = 256", "Reset = 257", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_MeterPulse { enum _enumerated { Count = 0 }; _enumerated _value; ValueID_Index_MeterPulse(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 1; static const int* _values() { static const int values[] = { (ignore_assign)Count = 0, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Count = 0", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_PowerLevel { enum _enumerated { Powerlevel = 0, Timeout = 1, Set = 2, TestNode = 3, TestPowerlevel = 4, TestFrames = 5, Test = 6, Report = 7, TestStatus = 8, TestAckFrames = 9 }; _enumerated _value; ValueID_Index_PowerLevel(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 10; static const int* _values() { static const int values[] = { (ignore_assign)Powerlevel = 0, (ignore_assign)Timeout = 1, (ignore_assign)Set = 2, (ignore_assign)TestNode = 3, (ignore_assign)TestPowerlevel = 4, (ignore_assign)TestFrames = 5, (ignore_assign)Test = 6, (ignore_assign)Report = 7, (ignore_assign)TestStatus = 8, (ignore_assign)TestAckFrames = 9, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Powerlevel = 0", "Timeout = 1", "Set = 2", "TestNode = 3", "TestPowerlevel = 4", "TestFrames = 5", "Test = 6", "Report = 7", "TestStatus = 8", "TestAckFrames = 9", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_Protection { enum _enumerated { Protection = 0 }; _enumerated _value; ValueID_Index_Protection(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 1; static const int* _values() { static const int values[] = { (ignore_assign)Protection = 0, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Protection = 0", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_SceneActivation { enum _enumerated { SceneID = 0, Duration = 1 }; _enumerated _value; ValueID_Index_SceneActivation(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 2; static const int* _values() { static const int values[] = { (ignore_assign)SceneID = 0, (ignore_assign)Duration = 1, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "SceneID = 0", "Duration = 1", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_Security { enum _enumerated { Secured = 0 }; _enumerated _value; ValueID_Index_Security(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 1; static const int* _values() { static const int values[] = { (ignore_assign)Secured = 0, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Secured = 0", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_SensorAlarm { enum _enumerated { Sensor_1, Sensor_2, Sensor_3, Sensor_4, Sensor_5, Sensor_6, Sensor_7, Sensor_8, Sensor_9, Sensor_10, Sensor_11, Sensor_12, Sensor_13, Sensor_14, Sensor_15, Sensor_16, Sensor_17, Sensor_18, Sensor_19, Sensor_20, Sensor_21, Sensor_22, Sensor_23, Sensor_24, Sensor_25, Sensor_26, Sensor_27, Sensor_28, Sensor_29, Sensor_30, Sensor_31, Sensor_32, Sensor_33, Sensor_34, Sensor_35, Sensor_36, Sensor_37, Sensor_38, Sensor_39, Sensor_40, Sensor_41, Sensor_42, Sensor_43, Sensor_44, Sensor_45, Sensor_46, Sensor_47, Sensor_48, Sensor_49, Sensor_50, Sensor_51, Sensor_52, Sensor_53, Sensor_54, Sensor_55, Sensor_56, Sensor_57, Sensor_58, Sensor_59, Sensor_60, Sensor_61, Sensor_62, Sensor_63, Sensor_64, Sensor_65, Sensor_66, Sensor_67, Sensor_68, Sensor_69, Sensor_70, Sensor_71, Sensor_72, Sensor_73, Sensor_74, Sensor_75, Sensor_76, Sensor_77, Sensor_78, Sensor_79, Sensor_80, Sensor_81, Sensor_82, Sensor_83, Sensor_84, Sensor_85, Sensor_86, Sensor_87, Sensor_88, Sensor_89, Sensor_90, Sensor_91, Sensor_92, Sensor_93, Sensor_94, Sensor_95, Sensor_96, Sensor_97, Sensor_98, Sensor_99, Sensor_100, Sensor_101, Sensor_102, Sensor_103, Sensor_104, Sensor_105, Sensor_106, Sensor_107, Sensor_108, Sensor_109, Sensor_110, Sensor_111, Sensor_112, Sensor_113, Sensor_114, Sensor_115, Sensor_116, Sensor_117, Sensor_118, Sensor_119, Sensor_120, Sensor_121, Sensor_122, Sensor_123, Sensor_124, Sensor_125, Sensor_126, Sensor_127, Sensor_128, Sensor_129, Sensor_130, Sensor_131, Sensor_132, Sensor_133, Sensor_134, Sensor_135, Sensor_136, Sensor_137, Sensor_138, Sensor_139, Sensor_140, Sensor_141, Sensor_142, Sensor_143, Sensor_144, Sensor_145, Sensor_146, Sensor_147, Sensor_148, Sensor_149, Sensor_150, Sensor_151, Sensor_152, Sensor_153, Sensor_154, Sensor_155, Sensor_156, Sensor_157, Sensor_158, Sensor_159, Sensor_160, Sensor_161, Sensor_162, Sensor_163, Sensor_164, Sensor_165, Sensor_166, Sensor_167, Sensor_168, Sensor_169, Sensor_170, Sensor_171, Sensor_172, Sensor_173, Sensor_174, Sensor_175, Sensor_176, Sensor_177, Sensor_178, Sensor_179, Sensor_180, Sensor_181, Sensor_182, Sensor_183, Sensor_184, Sensor_185, Sensor_186, Sensor_187, Sensor_188, Sensor_189, Sensor_190, Sensor_191, Sensor_192, Sensor_193, Sensor_194, Sensor_195, Sensor_196, Sensor_197, Sensor_198, Sensor_199, Sensor_200, Sensor_201, Sensor_202, Sensor_203, Sensor_204, Sensor_205, Sensor_206, Sensor_207, Sensor_208, Sensor_209, Sensor_210, Sensor_211, Sensor_212, Sensor_213, Sensor_214, Sensor_215, Sensor_216, Sensor_217, Sensor_218, Sensor_219, Sensor_220, Sensor_221, Sensor_222, Sensor_223, Sensor_224, Sensor_225, Sensor_226, Sensor_227, Sensor_228, Sensor_229, Sensor_230, Sensor_231, Sensor_232, Sensor_233, Sensor_234, Sensor_235, Sensor_236, Sensor_237, Sensor_238, Sensor_239, Sensor_240, Sensor_241, Sensor_242, Sensor_243, Sensor_244, Sensor_245, Sensor_246, Sensor_247, Sensor_248, Sensor_249, Sensor_250, Sensor_251, Sensor_252, Sensor_253, Sensor_254, Sensor_255 }; _enumerated _value; ValueID_Index_SensorAlarm(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 255; static const int* _values() { static const int values[] = { (ignore_assign)Sensor_1, (ignore_assign)Sensor_2, (ignore_assign)Sensor_3, (ignore_assign)Sensor_4, (ignore_assign)Sensor_5, (ignore_assign)Sensor_6, (ignore_assign)Sensor_7, (ignore_assign)Sensor_8, (ignore_assign)Sensor_9, (ignore_assign)Sensor_10, (ignore_assign)Sensor_11, (ignore_assign)Sensor_12, (ignore_assign)Sensor_13, (ignore_assign)Sensor_14, (ignore_assign)Sensor_15, (ignore_assign)Sensor_16, (ignore_assign)Sensor_17, (ignore_assign)Sensor_18, (ignore_assign)Sensor_19, (ignore_assign)Sensor_20, (ignore_assign)Sensor_21, (ignore_assign)Sensor_22, (ignore_assign)Sensor_23, (ignore_assign)Sensor_24, (ignore_assign)Sensor_25, (ignore_assign)Sensor_26, (ignore_assign)Sensor_27, (ignore_assign)Sensor_28, (ignore_assign)Sensor_29, (ignore_assign)Sensor_30, (ignore_assign)Sensor_31, (ignore_assign)Sensor_32, (ignore_assign)Sensor_33, (ignore_assign)Sensor_34, (ignore_assign)Sensor_35, (ignore_assign)Sensor_36, (ignore_assign)Sensor_37, (ignore_assign)Sensor_38, (ignore_assign)Sensor_39, (ignore_assign)Sensor_40, (ignore_assign)Sensor_41, (ignore_assign)Sensor_42, (ignore_assign)Sensor_43, (ignore_assign)Sensor_44, (ignore_assign)Sensor_45, (ignore_assign)Sensor_46, (ignore_assign)Sensor_47, (ignore_assign)Sensor_48, (ignore_assign)Sensor_49, (ignore_assign)Sensor_50, (ignore_assign)Sensor_51, (ignore_assign)Sensor_52, (ignore_assign)Sensor_53, (ignore_assign)Sensor_54, (ignore_assign)Sensor_55, (ignore_assign)Sensor_56, (ignore_assign)Sensor_57, (ignore_assign)Sensor_58, (ignore_assign)Sensor_59, (ignore_assign)Sensor_60, (ignore_assign)Sensor_61, (ignore_assign)Sensor_62, (ignore_assign)Sensor_63, (ignore_assign)Sensor_64, (ignore_assign)Sensor_65, (ignore_assign)Sensor_66, (ignore_assign)Sensor_67, (ignore_assign)Sensor_68, (ignore_assign)Sensor_69, (ignore_assign)Sensor_70, (ignore_assign)Sensor_71, (ignore_assign)Sensor_72, (ignore_assign)Sensor_73, (ignore_assign)Sensor_74, (ignore_assign)Sensor_75, (ignore_assign)Sensor_76, (ignore_assign)Sensor_77, (ignore_assign)Sensor_78, (ignore_assign)Sensor_79, (ignore_assign)Sensor_80, (ignore_assign)Sensor_81, (ignore_assign)Sensor_82, (ignore_assign)Sensor_83, (ignore_assign)Sensor_84, (ignore_assign)Sensor_85, (ignore_assign)Sensor_86, (ignore_assign)Sensor_87, (ignore_assign)Sensor_88, (ignore_assign)Sensor_89, (ignore_assign)Sensor_90, (ignore_assign)Sensor_91, (ignore_assign)Sensor_92, (ignore_assign)Sensor_93, (ignore_assign)Sensor_94, (ignore_assign)Sensor_95, (ignore_assign)Sensor_96, (ignore_assign)Sensor_97, (ignore_assign)Sensor_98, (ignore_assign)Sensor_99, (ignore_assign)Sensor_100, (ignore_assign)Sensor_101, (ignore_assign)Sensor_102, (ignore_assign)Sensor_103, (ignore_assign)Sensor_104, (ignore_assign)Sensor_105, (ignore_assign)Sensor_106, (ignore_assign)Sensor_107, (ignore_assign)Sensor_108, (ignore_assign)Sensor_109, (ignore_assign)Sensor_110, (ignore_assign)Sensor_111, (ignore_assign)Sensor_112, (ignore_assign)Sensor_113, (ignore_assign)Sensor_114, (ignore_assign)Sensor_115, (ignore_assign)Sensor_116, (ignore_assign)Sensor_117, (ignore_assign)Sensor_118, (ignore_assign)Sensor_119, (ignore_assign)Sensor_120, (ignore_assign)Sensor_121, (ignore_assign)Sensor_122, (ignore_assign)Sensor_123, (ignore_assign)Sensor_124, (ignore_assign)Sensor_125, (ignore_assign)Sensor_126, (ignore_assign)Sensor_127, (ignore_assign)Sensor_128, (ignore_assign)Sensor_129, (ignore_assign)Sensor_130, (ignore_assign)Sensor_131, (ignore_assign)Sensor_132, (ignore_assign)Sensor_133, (ignore_assign)Sensor_134, (ignore_assign)Sensor_135, (ignore_assign)Sensor_136, (ignore_assign)Sensor_137, (ignore_assign)Sensor_138, (ignore_assign)Sensor_139, (ignore_assign)Sensor_140, (ignore_assign)Sensor_141, (ignore_assign)Sensor_142, (ignore_assign)Sensor_143, (ignore_assign)Sensor_144, (ignore_assign)Sensor_145, (ignore_assign)Sensor_146, (ignore_assign)Sensor_147, (ignore_assign)Sensor_148, (ignore_assign)Sensor_149, (ignore_assign)Sensor_150, (ignore_assign)Sensor_151, (ignore_assign)Sensor_152, (ignore_assign)Sensor_153, (ignore_assign)Sensor_154, (ignore_assign)Sensor_155, (ignore_assign)Sensor_156, (ignore_assign)Sensor_157, (ignore_assign)Sensor_158, (ignore_assign)Sensor_159, (ignore_assign)Sensor_160, (ignore_assign)Sensor_161, (ignore_assign)Sensor_162, (ignore_assign)Sensor_163, (ignore_assign)Sensor_164, (ignore_assign)Sensor_165, (ignore_assign)Sensor_166, (ignore_assign)Sensor_167, (ignore_assign)Sensor_168, (ignore_assign)Sensor_169, (ignore_assign)Sensor_170, (ignore_assign)Sensor_171, (ignore_assign)Sensor_172, (ignore_assign)Sensor_173, (ignore_assign)Sensor_174, (ignore_assign)Sensor_175, (ignore_assign)Sensor_176, (ignore_assign)Sensor_177, (ignore_assign)Sensor_178, (ignore_assign)Sensor_179, (ignore_assign)Sensor_180, (ignore_assign)Sensor_181, (ignore_assign)Sensor_182, (ignore_assign)Sensor_183, (ignore_assign)Sensor_184, (ignore_assign)Sensor_185, (ignore_assign)Sensor_186, (ignore_assign)Sensor_187, (ignore_assign)Sensor_188, (ignore_assign)Sensor_189, (ignore_assign)Sensor_190, (ignore_assign)Sensor_191, (ignore_assign)Sensor_192, (ignore_assign)Sensor_193, (ignore_assign)Sensor_194, (ignore_assign)Sensor_195, (ignore_assign)Sensor_196, (ignore_assign)Sensor_197, (ignore_assign)Sensor_198, (ignore_assign)Sensor_199, (ignore_assign)Sensor_200, (ignore_assign)Sensor_201, (ignore_assign)Sensor_202, (ignore_assign)Sensor_203, (ignore_assign)Sensor_204, (ignore_assign)Sensor_205, (ignore_assign)Sensor_206, (ignore_assign)Sensor_207, (ignore_assign)Sensor_208, (ignore_assign)Sensor_209, (ignore_assign)Sensor_210, (ignore_assign)Sensor_211, (ignore_assign)Sensor_212, (ignore_assign)Sensor_213, (ignore_assign)Sensor_214, (ignore_assign)Sensor_215, (ignore_assign)Sensor_216, (ignore_assign)Sensor_217, (ignore_assign)Sensor_218, (ignore_assign)Sensor_219, (ignore_assign)Sensor_220, (ignore_assign)Sensor_221, (ignore_assign)Sensor_222, (ignore_assign)Sensor_223, (ignore_assign)Sensor_224, (ignore_assign)Sensor_225, (ignore_assign)Sensor_226, (ignore_assign)Sensor_227, (ignore_assign)Sensor_228, (ignore_assign)Sensor_229, (ignore_assign)Sensor_230, (ignore_assign)Sensor_231, (ignore_assign)Sensor_232, (ignore_assign)Sensor_233, (ignore_assign)Sensor_234, (ignore_assign)Sensor_235, (ignore_assign)Sensor_236, (ignore_assign)Sensor_237, (ignore_assign)Sensor_238, (ignore_assign)Sensor_239, (ignore_assign)Sensor_240, (ignore_assign)Sensor_241, (ignore_assign)Sensor_242, (ignore_assign)Sensor_243, (ignore_assign)Sensor_244, (ignore_assign)Sensor_245, (ignore_assign)Sensor_246, (ignore_assign)Sensor_247, (ignore_assign)Sensor_248, (ignore_assign)Sensor_249, (ignore_assign)Sensor_250, (ignore_assign)Sensor_251, (ignore_assign)Sensor_252, (ignore_assign)Sensor_253, (ignore_assign)Sensor_254, (ignore_assign)Sensor_255, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Sensor_1", "Sensor_2", "Sensor_3", "Sensor_4", "Sensor_5", "Sensor_6", "Sensor_7", "Sensor_8", "Sensor_9", "Sensor_10", "Sensor_11", "Sensor_12", "Sensor_13", "Sensor_14", "Sensor_15", "Sensor_16", "Sensor_17", "Sensor_18", "Sensor_19", "Sensor_20", "Sensor_21", "Sensor_22", "Sensor_23", "Sensor_24", "Sensor_25", "Sensor_26", "Sensor_27", "Sensor_28", "Sensor_29", "Sensor_30", "Sensor_31", "Sensor_32", "Sensor_33", "Sensor_34", "Sensor_35", "Sensor_36", "Sensor_37", "Sensor_38", "Sensor_39", "Sensor_40", "Sensor_41", "Sensor_42", "Sensor_43", "Sensor_44", "Sensor_45", "Sensor_46", "Sensor_47", "Sensor_48", "Sensor_49", "Sensor_50", "Sensor_51", "Sensor_52", "Sensor_53", "Sensor_54", "Sensor_55", "Sensor_56", "Sensor_57", "Sensor_58", "Sensor_59", "Sensor_60", "Sensor_61", "Sensor_62", "Sensor_63", "Sensor_64", "Sensor_65", "Sensor_66", "Sensor_67", "Sensor_68", "Sensor_69", "Sensor_70", "Sensor_71", "Sensor_72", "Sensor_73", "Sensor_74", "Sensor_75", "Sensor_76", "Sensor_77", "Sensor_78", "Sensor_79", "Sensor_80", "Sensor_81", "Sensor_82", "Sensor_83", "Sensor_84", "Sensor_85", "Sensor_86", "Sensor_87", "Sensor_88", "Sensor_89", "Sensor_90", "Sensor_91", "Sensor_92", "Sensor_93", "Sensor_94", "Sensor_95", "Sensor_96", "Sensor_97", "Sensor_98", "Sensor_99", "Sensor_100", "Sensor_101", "Sensor_102", "Sensor_103", "Sensor_104", "Sensor_105", "Sensor_106", "Sensor_107", "Sensor_108", "Sensor_109", "Sensor_110", "Sensor_111", "Sensor_112", "Sensor_113", "Sensor_114", "Sensor_115", "Sensor_116", "Sensor_117", "Sensor_118", "Sensor_119", "Sensor_120", "Sensor_121", "Sensor_122", "Sensor_123", "Sensor_124", "Sensor_125", "Sensor_126", "Sensor_127", "Sensor_128", "Sensor_129", "Sensor_130", "Sensor_131", "Sensor_132", "Sensor_133", "Sensor_134", "Sensor_135", "Sensor_136", "Sensor_137", "Sensor_138", "Sensor_139", "Sensor_140", "Sensor_141", "Sensor_142", "Sensor_143", "Sensor_144", "Sensor_145", "Sensor_146", "Sensor_147", "Sensor_148", "Sensor_149", "Sensor_150", "Sensor_151", "Sensor_152", "Sensor_153", "Sensor_154", "Sensor_155", "Sensor_156", "Sensor_157", "Sensor_158", "Sensor_159", "Sensor_160", "Sensor_161", "Sensor_162", "Sensor_163", "Sensor_164", "Sensor_165", "Sensor_166", "Sensor_167", "Sensor_168", "Sensor_169", "Sensor_170", "Sensor_171", "Sensor_172", "Sensor_173", "Sensor_174", "Sensor_175", "Sensor_176", "Sensor_177", "Sensor_178", "Sensor_179", "Sensor_180", "Sensor_181", "Sensor_182", "Sensor_183", "Sensor_184", "Sensor_185", "Sensor_186", "Sensor_187", "Sensor_188", "Sensor_189", "Sensor_190", "Sensor_191", "Sensor_192", "Sensor_193", "Sensor_194", "Sensor_195", "Sensor_196", "Sensor_197", "Sensor_198", "Sensor_199", "Sensor_200", "Sensor_201", "Sensor_202", "Sensor_203", "Sensor_204", "Sensor_205", "Sensor_206", "Sensor_207", "Sensor_208", "Sensor_209", "Sensor_210", "Sensor_211", "Sensor_212", "Sensor_213", "Sensor_214", "Sensor_215", "Sensor_216", "Sensor_217", "Sensor_218", "Sensor_219", "Sensor_220", "Sensor_221", "Sensor_222", "Sensor_223", "Sensor_224", "Sensor_225", "Sensor_226", "Sensor_227", "Sensor_228", "Sensor_229", "Sensor_230", "Sensor_231", "Sensor_232", "Sensor_233", "Sensor_234", "Sensor_235", "Sensor_236", "Sensor_237", "Sensor_238", "Sensor_239", "Sensor_240", "Sensor_241", "Sensor_242", "Sensor_243", "Sensor_244", "Sensor_245", "Sensor_246", "Sensor_247", "Sensor_248", "Sensor_249", "Sensor_250", "Sensor_251", "Sensor_252", "Sensor_253", "Sensor_254", "Sensor_255", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_SensorBinary { enum _enumerated { Sensor_1, Sensor_2, Sensor_3, Sensor_4, Sensor_5, Sensor_6, Sensor_7, Sensor_8, Sensor_9, Sensor_10, Sensor_11, Sensor_12, Sensor_13, Sensor_14, Sensor_15, Sensor_16, Sensor_17, Sensor_18, Sensor_19, Sensor_20, Sensor_21, Sensor_22, Sensor_23, Sensor_24, Sensor_25, Sensor_26, Sensor_27, Sensor_28, Sensor_29, Sensor_30, Sensor_31, Sensor_32, Sensor_33, Sensor_34, Sensor_35, Sensor_36, Sensor_37, Sensor_38, Sensor_39, Sensor_40, Sensor_41, Sensor_42, Sensor_43, Sensor_44, Sensor_45, Sensor_46, Sensor_47, Sensor_48, Sensor_49, Sensor_50, Sensor_51, Sensor_52, Sensor_53, Sensor_54, Sensor_55, Sensor_56, Sensor_57, Sensor_58, Sensor_59, Sensor_60, Sensor_61, Sensor_62, Sensor_63, Sensor_64, Sensor_65, Sensor_66, Sensor_67, Sensor_68, Sensor_69, Sensor_70, Sensor_71, Sensor_72, Sensor_73, Sensor_74, Sensor_75, Sensor_76, Sensor_77, Sensor_78, Sensor_79, Sensor_80, Sensor_81, Sensor_82, Sensor_83, Sensor_84, Sensor_85, Sensor_86, Sensor_87, Sensor_88, Sensor_89, Sensor_90, Sensor_91, Sensor_92, Sensor_93, Sensor_94, Sensor_95, Sensor_96, Sensor_97, Sensor_98, Sensor_99, Sensor_100, Sensor_101, Sensor_102, Sensor_103, Sensor_104, Sensor_105, Sensor_106, Sensor_107, Sensor_108, Sensor_109, Sensor_110, Sensor_111, Sensor_112, Sensor_113, Sensor_114, Sensor_115, Sensor_116, Sensor_117, Sensor_118, Sensor_119, Sensor_120, Sensor_121, Sensor_122, Sensor_123, Sensor_124, Sensor_125, Sensor_126, Sensor_127, Sensor_128, Sensor_129, Sensor_130, Sensor_131, Sensor_132, Sensor_133, Sensor_134, Sensor_135, Sensor_136, Sensor_137, Sensor_138, Sensor_139, Sensor_140, Sensor_141, Sensor_142, Sensor_143, Sensor_144, Sensor_145, Sensor_146, Sensor_147, Sensor_148, Sensor_149, Sensor_150, Sensor_151, Sensor_152, Sensor_153, Sensor_154, Sensor_155, Sensor_156, Sensor_157, Sensor_158, Sensor_159, Sensor_160, Sensor_161, Sensor_162, Sensor_163, Sensor_164, Sensor_165, Sensor_166, Sensor_167, Sensor_168, Sensor_169, Sensor_170, Sensor_171, Sensor_172, Sensor_173, Sensor_174, Sensor_175, Sensor_176, Sensor_177, Sensor_178, Sensor_179, Sensor_180, Sensor_181, Sensor_182, Sensor_183, Sensor_184, Sensor_185, Sensor_186, Sensor_187, Sensor_188, Sensor_189, Sensor_190, Sensor_191, Sensor_192, Sensor_193, Sensor_194, Sensor_195, Sensor_196, Sensor_197, Sensor_198, Sensor_199, Sensor_200, Sensor_201, Sensor_202, Sensor_203, Sensor_204, Sensor_205, Sensor_206, Sensor_207, Sensor_208, Sensor_209, Sensor_210, Sensor_211, Sensor_212, Sensor_213, Sensor_214, Sensor_215, Sensor_216, Sensor_217, Sensor_218, Sensor_219, Sensor_220, Sensor_221, Sensor_222, Sensor_223, Sensor_224, Sensor_225, Sensor_226, Sensor_227, Sensor_228, Sensor_229, Sensor_230, Sensor_231, Sensor_232, Sensor_233, Sensor_234, Sensor_235, Sensor_236, Sensor_237, Sensor_238, Sensor_239, Sensor_240, Sensor_241, Sensor_242, Sensor_243, Sensor_244, Sensor_245, Sensor_246, Sensor_247, Sensor_248, Sensor_249, Sensor_250, Sensor_251, Sensor_252, Sensor_253, Sensor_254, Sensor_255 }; _enumerated _value; ValueID_Index_SensorBinary(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 255; static const int* _values() { static const int values[] = { (ignore_assign)Sensor_1, (ignore_assign)Sensor_2, (ignore_assign)Sensor_3, (ignore_assign)Sensor_4, (ignore_assign)Sensor_5, (ignore_assign)Sensor_6, (ignore_assign)Sensor_7, (ignore_assign)Sensor_8, (ignore_assign)Sensor_9, (ignore_assign)Sensor_10, (ignore_assign)Sensor_11, (ignore_assign)Sensor_12, (ignore_assign)Sensor_13, (ignore_assign)Sensor_14, (ignore_assign)Sensor_15, (ignore_assign)Sensor_16, (ignore_assign)Sensor_17, (ignore_assign)Sensor_18, (ignore_assign)Sensor_19, (ignore_assign)Sensor_20, (ignore_assign)Sensor_21, (ignore_assign)Sensor_22, (ignore_assign)Sensor_23, (ignore_assign)Sensor_24, (ignore_assign)Sensor_25, (ignore_assign)Sensor_26, (ignore_assign)Sensor_27, (ignore_assign)Sensor_28, (ignore_assign)Sensor_29, (ignore_assign)Sensor_30, (ignore_assign)Sensor_31, (ignore_assign)Sensor_32, (ignore_assign)Sensor_33, (ignore_assign)Sensor_34, (ignore_assign)Sensor_35, (ignore_assign)Sensor_36, (ignore_assign)Sensor_37, (ignore_assign)Sensor_38, (ignore_assign)Sensor_39, (ignore_assign)Sensor_40, (ignore_assign)Sensor_41, (ignore_assign)Sensor_42, (ignore_assign)Sensor_43, (ignore_assign)Sensor_44, (ignore_assign)Sensor_45, (ignore_assign)Sensor_46, (ignore_assign)Sensor_47, (ignore_assign)Sensor_48, (ignore_assign)Sensor_49, (ignore_assign)Sensor_50, (ignore_assign)Sensor_51, (ignore_assign)Sensor_52, (ignore_assign)Sensor_53, (ignore_assign)Sensor_54, (ignore_assign)Sensor_55, (ignore_assign)Sensor_56, (ignore_assign)Sensor_57, (ignore_assign)Sensor_58, (ignore_assign)Sensor_59, (ignore_assign)Sensor_60, (ignore_assign)Sensor_61, (ignore_assign)Sensor_62, (ignore_assign)Sensor_63, (ignore_assign)Sensor_64, (ignore_assign)Sensor_65, (ignore_assign)Sensor_66, (ignore_assign)Sensor_67, (ignore_assign)Sensor_68, (ignore_assign)Sensor_69, (ignore_assign)Sensor_70, (ignore_assign)Sensor_71, (ignore_assign)Sensor_72, (ignore_assign)Sensor_73, (ignore_assign)Sensor_74, (ignore_assign)Sensor_75, (ignore_assign)Sensor_76, (ignore_assign)Sensor_77, (ignore_assign)Sensor_78, (ignore_assign)Sensor_79, (ignore_assign)Sensor_80, (ignore_assign)Sensor_81, (ignore_assign)Sensor_82, (ignore_assign)Sensor_83, (ignore_assign)Sensor_84, (ignore_assign)Sensor_85, (ignore_assign)Sensor_86, (ignore_assign)Sensor_87, (ignore_assign)Sensor_88, (ignore_assign)Sensor_89, (ignore_assign)Sensor_90, (ignore_assign)Sensor_91, (ignore_assign)Sensor_92, (ignore_assign)Sensor_93, (ignore_assign)Sensor_94, (ignore_assign)Sensor_95, (ignore_assign)Sensor_96, (ignore_assign)Sensor_97, (ignore_assign)Sensor_98, (ignore_assign)Sensor_99, (ignore_assign)Sensor_100, (ignore_assign)Sensor_101, (ignore_assign)Sensor_102, (ignore_assign)Sensor_103, (ignore_assign)Sensor_104, (ignore_assign)Sensor_105, (ignore_assign)Sensor_106, (ignore_assign)Sensor_107, (ignore_assign)Sensor_108, (ignore_assign)Sensor_109, (ignore_assign)Sensor_110, (ignore_assign)Sensor_111, (ignore_assign)Sensor_112, (ignore_assign)Sensor_113, (ignore_assign)Sensor_114, (ignore_assign)Sensor_115, (ignore_assign)Sensor_116, (ignore_assign)Sensor_117, (ignore_assign)Sensor_118, (ignore_assign)Sensor_119, (ignore_assign)Sensor_120, (ignore_assign)Sensor_121, (ignore_assign)Sensor_122, (ignore_assign)Sensor_123, (ignore_assign)Sensor_124, (ignore_assign)Sensor_125, (ignore_assign)Sensor_126, (ignore_assign)Sensor_127, (ignore_assign)Sensor_128, (ignore_assign)Sensor_129, (ignore_assign)Sensor_130, (ignore_assign)Sensor_131, (ignore_assign)Sensor_132, (ignore_assign)Sensor_133, (ignore_assign)Sensor_134, (ignore_assign)Sensor_135, (ignore_assign)Sensor_136, (ignore_assign)Sensor_137, (ignore_assign)Sensor_138, (ignore_assign)Sensor_139, (ignore_assign)Sensor_140, (ignore_assign)Sensor_141, (ignore_assign)Sensor_142, (ignore_assign)Sensor_143, (ignore_assign)Sensor_144, (ignore_assign)Sensor_145, (ignore_assign)Sensor_146, (ignore_assign)Sensor_147, (ignore_assign)Sensor_148, (ignore_assign)Sensor_149, (ignore_assign)Sensor_150, (ignore_assign)Sensor_151, (ignore_assign)Sensor_152, (ignore_assign)Sensor_153, (ignore_assign)Sensor_154, (ignore_assign)Sensor_155, (ignore_assign)Sensor_156, (ignore_assign)Sensor_157, (ignore_assign)Sensor_158, (ignore_assign)Sensor_159, (ignore_assign)Sensor_160, (ignore_assign)Sensor_161, (ignore_assign)Sensor_162, (ignore_assign)Sensor_163, (ignore_assign)Sensor_164, (ignore_assign)Sensor_165, (ignore_assign)Sensor_166, (ignore_assign)Sensor_167, (ignore_assign)Sensor_168, (ignore_assign)Sensor_169, (ignore_assign)Sensor_170, (ignore_assign)Sensor_171, (ignore_assign)Sensor_172, (ignore_assign)Sensor_173, (ignore_assign)Sensor_174, (ignore_assign)Sensor_175, (ignore_assign)Sensor_176, (ignore_assign)Sensor_177, (ignore_assign)Sensor_178, (ignore_assign)Sensor_179, (ignore_assign)Sensor_180, (ignore_assign)Sensor_181, (ignore_assign)Sensor_182, (ignore_assign)Sensor_183, (ignore_assign)Sensor_184, (ignore_assign)Sensor_185, (ignore_assign)Sensor_186, (ignore_assign)Sensor_187, (ignore_assign)Sensor_188, (ignore_assign)Sensor_189, (ignore_assign)Sensor_190, (ignore_assign)Sensor_191, (ignore_assign)Sensor_192, (ignore_assign)Sensor_193, (ignore_assign)Sensor_194, (ignore_assign)Sensor_195, (ignore_assign)Sensor_196, (ignore_assign)Sensor_197, (ignore_assign)Sensor_198, (ignore_assign)Sensor_199, (ignore_assign)Sensor_200, (ignore_assign)Sensor_201, (ignore_assign)Sensor_202, (ignore_assign)Sensor_203, (ignore_assign)Sensor_204, (ignore_assign)Sensor_205, (ignore_assign)Sensor_206, (ignore_assign)Sensor_207, (ignore_assign)Sensor_208, (ignore_assign)Sensor_209, (ignore_assign)Sensor_210, (ignore_assign)Sensor_211, (ignore_assign)Sensor_212, (ignore_assign)Sensor_213, (ignore_assign)Sensor_214, (ignore_assign)Sensor_215, (ignore_assign)Sensor_216, (ignore_assign)Sensor_217, (ignore_assign)Sensor_218, (ignore_assign)Sensor_219, (ignore_assign)Sensor_220, (ignore_assign)Sensor_221, (ignore_assign)Sensor_222, (ignore_assign)Sensor_223, (ignore_assign)Sensor_224, (ignore_assign)Sensor_225, (ignore_assign)Sensor_226, (ignore_assign)Sensor_227, (ignore_assign)Sensor_228, (ignore_assign)Sensor_229, (ignore_assign)Sensor_230, (ignore_assign)Sensor_231, (ignore_assign)Sensor_232, (ignore_assign)Sensor_233, (ignore_assign)Sensor_234, (ignore_assign)Sensor_235, (ignore_assign)Sensor_236, (ignore_assign)Sensor_237, (ignore_assign)Sensor_238, (ignore_assign)Sensor_239, (ignore_assign)Sensor_240, (ignore_assign)Sensor_241, (ignore_assign)Sensor_242, (ignore_assign)Sensor_243, (ignore_assign)Sensor_244, (ignore_assign)Sensor_245, (ignore_assign)Sensor_246, (ignore_assign)Sensor_247, (ignore_assign)Sensor_248, (ignore_assign)Sensor_249, (ignore_assign)Sensor_250, (ignore_assign)Sensor_251, (ignore_assign)Sensor_252, (ignore_assign)Sensor_253, (ignore_assign)Sensor_254, (ignore_assign)Sensor_255, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Sensor_1", "Sensor_2", "Sensor_3", "Sensor_4", "Sensor_5", "Sensor_6", "Sensor_7", "Sensor_8", "Sensor_9", "Sensor_10", "Sensor_11", "Sensor_12", "Sensor_13", "Sensor_14", "Sensor_15", "Sensor_16", "Sensor_17", "Sensor_18", "Sensor_19", "Sensor_20", "Sensor_21", "Sensor_22", "Sensor_23", "Sensor_24", "Sensor_25", "Sensor_26", "Sensor_27", "Sensor_28", "Sensor_29", "Sensor_30", "Sensor_31", "Sensor_32", "Sensor_33", "Sensor_34", "Sensor_35", "Sensor_36", "Sensor_37", "Sensor_38", "Sensor_39", "Sensor_40", "Sensor_41", "Sensor_42", "Sensor_43", "Sensor_44", "Sensor_45", "Sensor_46", "Sensor_47", "Sensor_48", "Sensor_49", "Sensor_50", "Sensor_51", "Sensor_52", "Sensor_53", "Sensor_54", "Sensor_55", "Sensor_56", "Sensor_57", "Sensor_58", "Sensor_59", "Sensor_60", "Sensor_61", "Sensor_62", "Sensor_63", "Sensor_64", "Sensor_65", "Sensor_66", "Sensor_67", "Sensor_68", "Sensor_69", "Sensor_70", "Sensor_71", "Sensor_72", "Sensor_73", "Sensor_74", "Sensor_75", "Sensor_76", "Sensor_77", "Sensor_78", "Sensor_79", "Sensor_80", "Sensor_81", "Sensor_82", "Sensor_83", "Sensor_84", "Sensor_85", "Sensor_86", "Sensor_87", "Sensor_88", "Sensor_89", "Sensor_90", "Sensor_91", "Sensor_92", "Sensor_93", "Sensor_94", "Sensor_95", "Sensor_96", "Sensor_97", "Sensor_98", "Sensor_99", "Sensor_100", "Sensor_101", "Sensor_102", "Sensor_103", "Sensor_104", "Sensor_105", "Sensor_106", "Sensor_107", "Sensor_108", "Sensor_109", "Sensor_110", "Sensor_111", "Sensor_112", "Sensor_113", "Sensor_114", "Sensor_115", "Sensor_116", "Sensor_117", "Sensor_118", "Sensor_119", "Sensor_120", "Sensor_121", "Sensor_122", "Sensor_123", "Sensor_124", "Sensor_125", "Sensor_126", "Sensor_127", "Sensor_128", "Sensor_129", "Sensor_130", "Sensor_131", "Sensor_132", "Sensor_133", "Sensor_134", "Sensor_135", "Sensor_136", "Sensor_137", "Sensor_138", "Sensor_139", "Sensor_140", "Sensor_141", "Sensor_142", "Sensor_143", "Sensor_144", "Sensor_145", "Sensor_146", "Sensor_147", "Sensor_148", "Sensor_149", "Sensor_150", "Sensor_151", "Sensor_152", "Sensor_153", "Sensor_154", "Sensor_155", "Sensor_156", "Sensor_157", "Sensor_158", "Sensor_159", "Sensor_160", "Sensor_161", "Sensor_162", "Sensor_163", "Sensor_164", "Sensor_165", "Sensor_166", "Sensor_167", "Sensor_168", "Sensor_169", "Sensor_170", "Sensor_171", "Sensor_172", "Sensor_173", "Sensor_174", "Sensor_175", "Sensor_176", "Sensor_177", "Sensor_178", "Sensor_179", "Sensor_180", "Sensor_181", "Sensor_182", "Sensor_183", "Sensor_184", "Sensor_185", "Sensor_186", "Sensor_187", "Sensor_188", "Sensor_189", "Sensor_190", "Sensor_191", "Sensor_192", "Sensor_193", "Sensor_194", "Sensor_195", "Sensor_196", "Sensor_197", "Sensor_198", "Sensor_199", "Sensor_200", "Sensor_201", "Sensor_202", "Sensor_203", "Sensor_204", "Sensor_205", "Sensor_206", "Sensor_207", "Sensor_208", "Sensor_209", "Sensor_210", "Sensor_211", "Sensor_212", "Sensor_213", "Sensor_214", "Sensor_215", "Sensor_216", "Sensor_217", "Sensor_218", "Sensor_219", "Sensor_220", "Sensor_221", "Sensor_222", "Sensor_223", "Sensor_224", "Sensor_225", "Sensor_226", "Sensor_227", "Sensor_228", "Sensor_229", "Sensor_230", "Sensor_231", "Sensor_232", "Sensor_233", "Sensor_234", "Sensor_235", "Sensor_236", "Sensor_237", "Sensor_238", "Sensor_239", "Sensor_240", "Sensor_241", "Sensor_242", "Sensor_243", "Sensor_244", "Sensor_245", "Sensor_246", "Sensor_247", "Sensor_248", "Sensor_249", "Sensor_250", "Sensor_251", "Sensor_252", "Sensor_253", "Sensor_254", "Sensor_255", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_SensorMultiLevel { enum _enumerated { Air_Temperature = 1, General_Purpose, Luminance, Power, Humidity, Velocity, Direction, Atmospheric_Pressure, Barometric_Pressure, Solar_Radiation, Dew_Point, Rain_Rate, Tide_Level, Weight, Voltage, Current, Carbon_Dioxide, Air_Flow, Tank_Capacity, Distance, Angle_Position, Rotation, Water_Temperature, Soil_Temperature, Seismic_Intensity, Seismic_Magnitude, Ultraviolet, Electrical_Resistivity, Electrical_Conductivity, Loudness, Moisture, Frequency, Time, Target_Temperature, Particulate_Mater_2_5, Formaldehyde_CH20_Level, Radon_Concentration, Methane_Density, Volatile_Organic_Compound, Carbon_Monoxide, Soil_Humidity, Soil_Reactivity, Soil_Salinity, Heart_Beat, Blood_Pressure, Muscle_Mass, Fat_Mass, Bone_Mass, Total_Body_Water, Basic_Metabolic_Rate, Body_Mass_Index, X_Axis_Acceleration, Y_Axis_Acceleration, Z_Axis_Acceleration, Smoke_Density, Water_Flow, Water_Pressure, RF_Signal_Strength, Particulate_Matter, Respiratory_Rate, Relative_Modulation, Boiler_Water_Temperature, Domestic_Hot_Water_Temperature, Outside_Temperature, Exhaust_Temperature, Water_Chlorine, Water_Acidity, Water_Oxidation_Reduction_Potential, Heart_Rate_LF_HF_Ratio, Motion_Direction, Applied_Force, Return_Air_Temperature, Supply_Air_Temperature, Condenser_Coil_Temperature, Evaporator_Coil_Temperature, Liquid_Line_Temperature, Discharge_Line_Temperature, Suction, Discharge, Defrost_Temperature, Ozone, Sulfur_Dioxide, Nitrogen_Dioxide, Ammonia, Lead, Particulate_Matter_v2, Air_Temperature_Units = 256, General_Purpose_Units, Luminance_Units, Power_Units, Humidity_Units, Velocity_Units, Direction_Units, Atmospheric_Pressure_Units, Barometric_Pressure_Units, Solar_Radiation_Units, Dew_Point_Units, Rain_Rate_Units, Tide_Level_Units, Weight_Units, Voltage_Units, Current_Units, Carbon_Dioxide_Units, Air_Flow_Units, Tank_Capacity_Units, Distance_Units, Angle_Position_Units, Rotation_Units, Water_Temperature_Units, Soil_Temperature_Units, Seismic_Intensity_Units, Seismic_Magnitude_Units, Ultraviolet_Units, Electrical_Resistivity_Units, Electrical_Conductivity_Units, Loudness_Units, Moisture_Units, Frequency_Units, Time_Units, Target_Temperature_Units, Particulate_Mater_2_5_Units, Formaldehyde_CH20_Level_Units, Radon_Concentration_Units, Methane_Density_Units, Volatile_Organic_Compound_Units, Carbon_Monoxide_Units, Soil_Humidity_Units, Soil_Reactivity_Units, Soil_Salinity_Units, Heart_Beat_Units, Blood_Pressure_Units, Muscle_Mass_Units, Fat_Mass_Units, Bone_Mass_Units, Total_Body_Water_Units, Basic_Metabolic_Rate_Units, Body_Mass_Index_Units, X_Axis_Acceleration_Units, Y_Axis_Acceleration_Units, Z_Axis_Acceleration_Units, Smoke_Density_Units, Water_Flow_Units, Water_Pressure_Units, RF_Signal_Strength_Units, Particulate_Matter_Units, Respiratory_Rate_Units, Relative_Modulation_Units, Boiler_Water_Temperature_Units, Domestic_Hot_Water_Temperature_Units, Outside_Temperature_Units, Exhaust_Temperature_Units, Water_Chlorine_Units, Water_Acidity_Units, Water_Oxidation_Reduction_Potential_Units, Heart_Rate_LF_HF_Ratio_Units, Motion_Direction_Units, Applied_Force_Units, Return_Air_Temperature_Units, Supply_Air_Temperature_Units, Condenser_Coil_Temperature_Units, Evaporator_Coil_Temperature_Units, Liquid_Line_Temperature_Units, Discharge_Line_Temperature_Units, Suction_Units, Discharge_Units, Defrost_Temperature_Units, Ozone_Units, Sulfur_Dioxide_Units, Nitrogen_Dioxide_Units, Ammonia_Units, Lead_Units, Particulate_Matter_v2_Units }; _enumerated _value; ValueID_Index_SensorMultiLevel(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 172; static const int* _values() { static const int values[] = { (ignore_assign)Air_Temperature = 1, (ignore_assign)General_Purpose, (ignore_assign)Luminance, (ignore_assign)Power, (ignore_assign)Humidity, (ignore_assign)Velocity, (ignore_assign)Direction, (ignore_assign)Atmospheric_Pressure, (ignore_assign)Barometric_Pressure, (ignore_assign)Solar_Radiation, (ignore_assign)Dew_Point, (ignore_assign)Rain_Rate, (ignore_assign)Tide_Level, (ignore_assign)Weight, (ignore_assign)Voltage, (ignore_assign)Current, (ignore_assign)Carbon_Dioxide, (ignore_assign)Air_Flow, (ignore_assign)Tank_Capacity, (ignore_assign)Distance, (ignore_assign)Angle_Position, (ignore_assign)Rotation, (ignore_assign)Water_Temperature, (ignore_assign)Soil_Temperature, (ignore_assign)Seismic_Intensity, (ignore_assign)Seismic_Magnitude, (ignore_assign)Ultraviolet, (ignore_assign)Electrical_Resistivity, (ignore_assign)Electrical_Conductivity, (ignore_assign)Loudness, (ignore_assign)Moisture, (ignore_assign)Frequency, (ignore_assign)Time, (ignore_assign)Target_Temperature, (ignore_assign)Particulate_Mater_2_5, (ignore_assign)Formaldehyde_CH20_Level, (ignore_assign)Radon_Concentration, (ignore_assign)Methane_Density, (ignore_assign)Volatile_Organic_Compound, (ignore_assign)Carbon_Monoxide, (ignore_assign)Soil_Humidity, (ignore_assign)Soil_Reactivity, (ignore_assign)Soil_Salinity, (ignore_assign)Heart_Beat, (ignore_assign)Blood_Pressure, (ignore_assign)Muscle_Mass, (ignore_assign)Fat_Mass, (ignore_assign)Bone_Mass, (ignore_assign)Total_Body_Water, (ignore_assign)Basic_Metabolic_Rate, (ignore_assign)Body_Mass_Index, (ignore_assign)X_Axis_Acceleration, (ignore_assign)Y_Axis_Acceleration, (ignore_assign)Z_Axis_Acceleration, (ignore_assign)Smoke_Density, (ignore_assign)Water_Flow, (ignore_assign)Water_Pressure, (ignore_assign)RF_Signal_Strength, (ignore_assign)Particulate_Matter, (ignore_assign)Respiratory_Rate, (ignore_assign)Relative_Modulation, (ignore_assign)Boiler_Water_Temperature, (ignore_assign)Domestic_Hot_Water_Temperature, (ignore_assign)Outside_Temperature, (ignore_assign)Exhaust_Temperature, (ignore_assign)Water_Chlorine, (ignore_assign)Water_Acidity, (ignore_assign)Water_Oxidation_Reduction_Potential, (ignore_assign)Heart_Rate_LF_HF_Ratio, (ignore_assign)Motion_Direction, (ignore_assign)Applied_Force, (ignore_assign)Return_Air_Temperature, (ignore_assign)Supply_Air_Temperature, (ignore_assign)Condenser_Coil_Temperature, (ignore_assign)Evaporator_Coil_Temperature, (ignore_assign)Liquid_Line_Temperature, (ignore_assign)Discharge_Line_Temperature, (ignore_assign)Suction, (ignore_assign)Discharge, (ignore_assign)Defrost_Temperature, (ignore_assign)Ozone, (ignore_assign)Sulfur_Dioxide, (ignore_assign)Nitrogen_Dioxide, (ignore_assign)Ammonia, (ignore_assign)Lead, (ignore_assign)Particulate_Matter_v2, (ignore_assign)Air_Temperature_Units = 256, (ignore_assign)General_Purpose_Units, (ignore_assign)Luminance_Units, (ignore_assign)Power_Units, (ignore_assign)Humidity_Units, (ignore_assign)Velocity_Units, (ignore_assign)Direction_Units, (ignore_assign)Atmospheric_Pressure_Units, (ignore_assign)Barometric_Pressure_Units, (ignore_assign)Solar_Radiation_Units, (ignore_assign)Dew_Point_Units, (ignore_assign)Rain_Rate_Units, (ignore_assign)Tide_Level_Units, (ignore_assign)Weight_Units, (ignore_assign)Voltage_Units, (ignore_assign)Current_Units, (ignore_assign)Carbon_Dioxide_Units, (ignore_assign)Air_Flow_Units, (ignore_assign)Tank_Capacity_Units, (ignore_assign)Distance_Units, (ignore_assign)Angle_Position_Units, (ignore_assign)Rotation_Units, (ignore_assign)Water_Temperature_Units, (ignore_assign)Soil_Temperature_Units, (ignore_assign)Seismic_Intensity_Units, (ignore_assign)Seismic_Magnitude_Units, (ignore_assign)Ultraviolet_Units, (ignore_assign)Electrical_Resistivity_Units, (ignore_assign)Electrical_Conductivity_Units, (ignore_assign)Loudness_Units, (ignore_assign)Moisture_Units, (ignore_assign)Frequency_Units, (ignore_assign)Time_Units, (ignore_assign)Target_Temperature_Units, (ignore_assign)Particulate_Mater_2_5_Units, (ignore_assign)Formaldehyde_CH20_Level_Units, (ignore_assign)Radon_Concentration_Units, (ignore_assign)Methane_Density_Units, (ignore_assign)Volatile_Organic_Compound_Units, (ignore_assign)Carbon_Monoxide_Units, (ignore_assign)Soil_Humidity_Units, (ignore_assign)Soil_Reactivity_Units, (ignore_assign)Soil_Salinity_Units, (ignore_assign)Heart_Beat_Units, (ignore_assign)Blood_Pressure_Units, (ignore_assign)Muscle_Mass_Units, (ignore_assign)Fat_Mass_Units, (ignore_assign)Bone_Mass_Units, (ignore_assign)Total_Body_Water_Units, (ignore_assign)Basic_Metabolic_Rate_Units, (ignore_assign)Body_Mass_Index_Units, (ignore_assign)X_Axis_Acceleration_Units, (ignore_assign)Y_Axis_Acceleration_Units, (ignore_assign)Z_Axis_Acceleration_Units, (ignore_assign)Smoke_Density_Units, (ignore_assign)Water_Flow_Units, (ignore_assign)Water_Pressure_Units, (ignore_assign)RF_Signal_Strength_Units, (ignore_assign)Particulate_Matter_Units, (ignore_assign)Respiratory_Rate_Units, (ignore_assign)Relative_Modulation_Units, (ignore_assign)Boiler_Water_Temperature_Units, (ignore_assign)Domestic_Hot_Water_Temperature_Units, (ignore_assign)Outside_Temperature_Units, (ignore_assign)Exhaust_Temperature_Units, (ignore_assign)Water_Chlorine_Units, (ignore_assign)Water_Acidity_Units, (ignore_assign)Water_Oxidation_Reduction_Potential_Units, (ignore_assign)Heart_Rate_LF_HF_Ratio_Units, (ignore_assign)Motion_Direction_Units, (ignore_assign)Applied_Force_Units, (ignore_assign)Return_Air_Temperature_Units, (ignore_assign)Supply_Air_Temperature_Units, (ignore_assign)Condenser_Coil_Temperature_Units, (ignore_assign)Evaporator_Coil_Temperature_Units, (ignore_assign)Liquid_Line_Temperature_Units, (ignore_assign)Discharge_Line_Temperature_Units, (ignore_assign)Suction_Units, (ignore_assign)Discharge_Units, (ignore_assign)Defrost_Temperature_Units, (ignore_assign)Ozone_Units, (ignore_assign)Sulfur_Dioxide_Units, (ignore_assign)Nitrogen_Dioxide_Units, (ignore_assign)Ammonia_Units, (ignore_assign)Lead_Units, (ignore_assign)Particulate_Matter_v2_Units, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Air_Temperature = 1", "General_Purpose", "Luminance", "Power", "Humidity", "Velocity", "Direction", "Atmospheric_Pressure", "Barometric_Pressure", "Solar_Radiation", "Dew_Point", "Rain_Rate", "Tide_Level", "Weight", "Voltage", "Current", "Carbon_Dioxide", "Air_Flow", "Tank_Capacity", "Distance", "Angle_Position", "Rotation", "Water_Temperature", "Soil_Temperature", "Seismic_Intensity", "Seismic_Magnitude", "Ultraviolet", "Electrical_Resistivity", "Electrical_Conductivity", "Loudness", "Moisture", "Frequency", "Time", "Target_Temperature", "Particulate_Mater_2_5", "Formaldehyde_CH20_Level", "Radon_Concentration", "Methane_Density", "Volatile_Organic_Compound", "Carbon_Monoxide", "Soil_Humidity", "Soil_Reactivity", "Soil_Salinity", "Heart_Beat", "Blood_Pressure", "Muscle_Mass", "Fat_Mass", "Bone_Mass", "Total_Body_Water", "Basic_Metabolic_Rate", "Body_Mass_Index", "X_Axis_Acceleration", "Y_Axis_Acceleration", "Z_Axis_Acceleration", "Smoke_Density", "Water_Flow", "Water_Pressure", "RF_Signal_Strength", "Particulate_Matter", "Respiratory_Rate", "Relative_Modulation", "Boiler_Water_Temperature", "Domestic_Hot_Water_Temperature", "Outside_Temperature", "Exhaust_Temperature", "Water_Chlorine", "Water_Acidity", "Water_Oxidation_Reduction_Potential", "Heart_Rate_LF_HF_Ratio", "Motion_Direction", "Applied_Force", "Return_Air_Temperature", "Supply_Air_Temperature", "Condenser_Coil_Temperature", "Evaporator_Coil_Temperature", "Liquid_Line_Temperature", "Discharge_Line_Temperature", "Suction", "Discharge", "Defrost_Temperature", "Ozone", "Sulfur_Dioxide", "Nitrogen_Dioxide", "Ammonia", "Lead", "Particulate_Matter_v2", "Air_Temperature_Units = 256", "General_Purpose_Units", "Luminance_Units", "Power_Units", "Humidity_Units", "Velocity_Units", "Direction_Units", "Atmospheric_Pressure_Units", "Barometric_Pressure_Units", "Solar_Radiation_Units", "Dew_Point_Units", "Rain_Rate_Units", "Tide_Level_Units", "Weight_Units", "Voltage_Units", "Current_Units", "Carbon_Dioxide_Units", "Air_Flow_Units", "Tank_Capacity_Units", "Distance_Units", "Angle_Position_Units", "Rotation_Units", "Water_Temperature_Units", "Soil_Temperature_Units", "Seismic_Intensity_Units", "Seismic_Magnitude_Units", "Ultraviolet_Units", "Electrical_Resistivity_Units", "Electrical_Conductivity_Units", "Loudness_Units", "Moisture_Units", "Frequency_Units", "Time_Units", "Target_Temperature_Units", "Particulate_Mater_2_5_Units", "Formaldehyde_CH20_Level_Units", "Radon_Concentration_Units", "Methane_Density_Units", "Volatile_Organic_Compound_Units", "Carbon_Monoxide_Units", "Soil_Humidity_Units", "Soil_Reactivity_Units", "Soil_Salinity_Units", "Heart_Beat_Units", "Blood_Pressure_Units", "Muscle_Mass_Units", "Fat_Mass_Units", "Bone_Mass_Units", "Total_Body_Water_Units", "Basic_Metabolic_Rate_Units", "Body_Mass_Index_Units", "X_Axis_Acceleration_Units", "Y_Axis_Acceleration_Units", "Z_Axis_Acceleration_Units", "Smoke_Density_Units", "Water_Flow_Units", "Water_Pressure_Units", "RF_Signal_Strength_Units", "Particulate_Matter_Units", "Respiratory_Rate_Units", "Relative_Modulation_Units", "Boiler_Water_Temperature_Units", "Domestic_Hot_Water_Temperature_Units", "Outside_Temperature_Units", "Exhaust_Temperature_Units", "Water_Chlorine_Units", "Water_Acidity_Units", "Water_Oxidation_Reduction_Potential_Units", "Heart_Rate_LF_HF_Ratio_Units", "Motion_Direction_Units", "Applied_Force_Units", "Return_Air_Temperature_Units", "Supply_Air_Temperature_Units", "Condenser_Coil_Temperature_Units", "Evaporator_Coil_Temperature_Units", "Liquid_Line_Temperature_Units", "Discharge_Line_Temperature_Units", "Suction_Units", "Discharge_Units", "Defrost_Temperature_Units", "Ozone_Units", "Sulfur_Dioxide_Units", "Nitrogen_Dioxide_Units", "Ammonia_Units", "Lead_Units", "Particulate_Matter_v2_Units", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_SimpleAV { enum _enumerated { Command = 0 }; _enumerated _value; ValueID_Index_SimpleAV(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 1; static const int* _values() { static const int values[] = { (ignore_assign)Command = 0, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Command = 0", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_SoundSwitch { enum _enumerated { Tone_Count = 0, Tones = 1, Volume = 2, Default_Tone = 3 }; _enumerated _value; ValueID_Index_SoundSwitch(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 4; static const int* _values() { static const int values[] = { (ignore_assign)Tone_Count = 0, (ignore_assign)Tones = 1, (ignore_assign)Volume = 2, (ignore_assign)Default_Tone = 3, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Tone_Count = 0", "Tones = 1", "Volume = 2", "Default_Tone = 3", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_SwitchAll { enum _enumerated { SwitchAll = 0 }; _enumerated _value; ValueID_Index_SwitchAll(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 1; static const int* _values() { static const int values[] = { (ignore_assign)SwitchAll = 0, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "SwitchAll = 0", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_SwitchBinary { enum _enumerated { Level = 0, TargetState = 1, Duration = 2 }; _enumerated _value; ValueID_Index_SwitchBinary(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 3; static const int* _values() { static const int values[] = { (ignore_assign)Level = 0, (ignore_assign)TargetState = 1, (ignore_assign)Duration = 2, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Level = 0", "TargetState = 1", "Duration = 2", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_SwitchMultiLevel { enum _enumerated { Level = 0, Bright = 1, Dim = 2, IgnoreStartLevel = 3, StartLevel = 4, Duration = 5, Step = 6, Inc = 7, Dec = 8, TargetValue = 9 }; _enumerated _value; ValueID_Index_SwitchMultiLevel(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 10; static const int* _values() { static const int values[] = { (ignore_assign)Level = 0, (ignore_assign)Bright = 1, (ignore_assign)Dim = 2, (ignore_assign)IgnoreStartLevel = 3, (ignore_assign)StartLevel = 4, (ignore_assign)Duration = 5, (ignore_assign)Step = 6, (ignore_assign)Inc = 7, (ignore_assign)Dec = 8, (ignore_assign)TargetValue = 9, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Level = 0", "Bright = 1", "Dim = 2", "IgnoreStartLevel = 3", "StartLevel = 4", "Duration = 5", "Step = 6", "Inc = 7", "Dec = 8", "TargetValue = 9", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_SwitchToggleBinary { enum _enumerated { ToggleSwitch = 0 }; _enumerated _value; ValueID_Index_SwitchToggleBinary(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 1; static const int* _values() { static const int values[] = { (ignore_assign)ToggleSwitch = 0, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "ToggleSwitch = 0", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_SwitchToggleMultilevel { enum _enumerated { Level = 0 }; _enumerated _value; ValueID_Index_SwitchToggleMultilevel(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 1; static const int* _values() { static const int values[] = { (ignore_assign)Level = 0, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Level = 0", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_ThermostatFanMode { enum _enumerated { FanMode = 0 }; _enumerated _value; ValueID_Index_ThermostatFanMode(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 1; static const int* _values() { static const int values[] = { (ignore_assign)FanMode = 0, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "FanMode = 0", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_ThermostatFanState { enum _enumerated { FanState = 0 }; _enumerated _value; ValueID_Index_ThermostatFanState(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 1; static const int* _values() { static const int values[] = { (ignore_assign)FanState = 0, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "FanState = 0", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_ThermostatMode { enum _enumerated { Mode = 0 }; _enumerated _value; ValueID_Index_ThermostatMode(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 1; static const int* _values() { static const int values[] = { (ignore_assign)Mode = 0, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Mode = 0", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_ThermostatOperatingState { enum _enumerated { OperatingState = 0 }; _enumerated _value; ValueID_Index_ThermostatOperatingState(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 1; static const int* _values() { static const int values[] = { (ignore_assign)OperatingState = 0, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "OperatingState = 0", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_ThermostatSetpoint { enum _enumerated { Unused_0 = 0, Heating, Cooling, Unused_3, Unused_4, Unused_5, Unused_6, Furnace, DryAir, MoistAir, AutoChangeover, HeatingEcon, CoolingEcon, AwayHeating, CoolingHeating, Unused_0_Minimum = 100, Heating_Minimum, Cooling_Minimum, Unused_3_Minimum, Unused_4_Minimum, Unused_5_Minimum, Unused_6_Minimum, Furnace_Minimum, DryAir_Minimum, MoistAir_Minimum, AutoChangeOver_Minimum, Heating_Econ_Minimum, Cooling_Econ_Minimum, Away_Heating_Minimum, Cooling_Heating_Minimum, Unused_0_Maximum = 200, Heating_Maximum, Cooling_Maximum, Unused_3_Maximum, Unused_4_Maximum, Unused_5_Maximum, Unused_6_Maximum, Furnace_Maximum, DryAir_Maximum, MoistAir_Maximum, AutoChangeOver_Maximum, Heating_Econ_Maximum, Cooling_Econ_Maximum, Away_Heating_Maximum, Cooling_Heating_Maximum }; _enumerated _value; ValueID_Index_ThermostatSetpoint(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 45; static const int* _values() { static const int values[] = { (ignore_assign)Unused_0 = 0, (ignore_assign)Heating, (ignore_assign)Cooling, (ignore_assign)Unused_3, (ignore_assign)Unused_4, (ignore_assign)Unused_5, (ignore_assign)Unused_6, (ignore_assign)Furnace, (ignore_assign)DryAir, (ignore_assign)MoistAir, (ignore_assign)AutoChangeover, (ignore_assign)HeatingEcon, (ignore_assign)CoolingEcon, (ignore_assign)AwayHeating, (ignore_assign)CoolingHeating, (ignore_assign)Unused_0_Minimum = 100, (ignore_assign)Heating_Minimum, (ignore_assign)Cooling_Minimum, (ignore_assign)Unused_3_Minimum, (ignore_assign)Unused_4_Minimum, (ignore_assign)Unused_5_Minimum, (ignore_assign)Unused_6_Minimum, (ignore_assign)Furnace_Minimum, (ignore_assign)DryAir_Minimum, (ignore_assign)MoistAir_Minimum, (ignore_assign)AutoChangeOver_Minimum, (ignore_assign)Heating_Econ_Minimum, (ignore_assign)Cooling_Econ_Minimum, (ignore_assign)Away_Heating_Minimum, (ignore_assign)Cooling_Heating_Minimum, (ignore_assign)Unused_0_Maximum = 200, (ignore_assign)Heating_Maximum, (ignore_assign)Cooling_Maximum, (ignore_assign)Unused_3_Maximum, (ignore_assign)Unused_4_Maximum, (ignore_assign)Unused_5_Maximum, (ignore_assign)Unused_6_Maximum, (ignore_assign)Furnace_Maximum, (ignore_assign)DryAir_Maximum, (ignore_assign)MoistAir_Maximum, (ignore_assign)AutoChangeOver_Maximum, (ignore_assign)Heating_Econ_Maximum, (ignore_assign)Cooling_Econ_Maximum, (ignore_assign)Away_Heating_Maximum, (ignore_assign)Cooling_Heating_Maximum, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Unused_0 = 0", "Heating", "Cooling", "Unused_3", "Unused_4", "Unused_5", "Unused_6", "Furnace", "DryAir", "MoistAir", "AutoChangeover", "HeatingEcon", "CoolingEcon", "AwayHeating", "CoolingHeating", "Unused_0_Minimum = 100", "Heating_Minimum", "Cooling_Minimum", "Unused_3_Minimum", "Unused_4_Minimum", "Unused_5_Minimum", "Unused_6_Minimum", "Furnace_Minimum", "DryAir_Minimum", "MoistAir_Minimum", "AutoChangeOver_Minimum", "Heating_Econ_Minimum", "Cooling_Econ_Minimum", "Away_Heating_Minimum", "Cooling_Heating_Minimum", "Unused_0_Maximum = 200", "Heating_Maximum", "Cooling_Maximum", "Unused_3_Maximum", "Unused_4_Maximum", "Unused_5_Maximum", "Unused_6_Maximum", "Furnace_Maximum", "DryAir_Maximum", "MoistAir_Maximum", "AutoChangeOver_Maximum", "Heating_Econ_Maximum", "Cooling_Econ_Maximum", "Away_Heating_Maximum", "Cooling_Heating_Maximum", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_TimeParameters { enum _enumerated { Date = 0, Time = 1, Set = 2, Refresh = 3 }; _enumerated _value; ValueID_Index_TimeParameters(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 4; static const int* _values() { static const int values[] = { (ignore_assign)Date = 0, (ignore_assign)Time = 1, (ignore_assign)Set = 2, (ignore_assign)Refresh = 3, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Date = 0", "Time = 1", "Set = 2", "Refresh = 3", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_UserCode { enum _enumerated { Enrollment_Code = 0, Code_1, Code_2, Code_3, Code_4, Code_5, Code_6, Code_7, Code_8, Code_9, Code_10, Code_11, Code_12, Code_13, Code_14, Code_15, Code_16, Code_17, Code_18, Code_19, Code_20, Code_21, Code_22, Code_23, Code_24, Code_25, Code_26, Code_27, Code_28, Code_29, Code_30, Code_31, Code_32, Code_33, Code_34, Code_35, Code_36, Code_37, Code_38, Code_39, Code_40, Code_41, Code_42, Code_43, Code_44, Code_45, Code_46, Code_47, Code_48, Code_49, Code_50, Code_51, Code_52, Code_53, Code_54, Code_55, Code_56, Code_57, Code_58, Code_59, Code_60, Code_61, Code_62, Code_63, Code_64, Code_65, Code_66, Code_67, Code_68, Code_69, Code_70, Code_71, Code_72, Code_73, Code_74, Code_75, Code_76, Code_77, Code_78, Code_79, Code_80, Code_81, Code_82, Code_83, Code_84, Code_85, Code_86, Code_87, Code_88, Code_89, Code_90, Code_91, Code_92, Code_93, Code_94, Code_95, Code_96, Code_97, Code_98, Code_99, Code_100, Code_101, Code_102, Code_103, Code_104, Code_105, Code_106, Code_107, Code_108, Code_109, Code_110, Code_111, Code_112, Code_113, Code_114, Code_115, Code_116, Code_117, Code_118, Code_119, Code_120, Code_121, Code_122, Code_123, Code_124, Code_125, Code_126, Code_127, Code_128, Code_129, Code_130, Code_131, Code_132, Code_133, Code_134, Code_135, Code_136, Code_137, Code_138, Code_139, Code_140, Code_141, Code_142, Code_143, Code_144, Code_145, Code_146, Code_147, Code_148, Code_149, Code_150, Code_151, Code_152, Code_153, Code_154, Code_155, Code_156, Code_157, Code_158, Code_159, Code_160, Code_161, Code_162, Code_163, Code_164, Code_165, Code_166, Code_167, Code_168, Code_169, Code_170, Code_171, Code_172, Code_173, Code_174, Code_175, Code_176, Code_177, Code_178, Code_179, Code_180, Code_181, Code_182, Code_183, Code_184, Code_185, Code_186, Code_187, Code_188, Code_189, Code_190, Code_191, Code_192, Code_193, Code_194, Code_195, Code_196, Code_197, Code_198, Code_199, Code_200, Code_201, Code_202, Code_203, Code_204, Code_205, Code_206, Code_207, Code_208, Code_209, Code_210, Code_211, Code_212, Code_213, Code_214, Code_215, Code_216, Code_217, Code_218, Code_219, Code_220, Code_221, Code_222, Code_223, Code_224, Code_225, Code_226, Code_227, Code_228, Code_229, Code_230, Code_231, Code_232, Code_233, Code_234, Code_235, Code_236, Code_237, Code_238, Code_239, Code_240, Code_241, Code_242, Code_243, Code_244, Code_245, Code_246, Code_247, Code_248, Code_249, Code_250, Code_251, Code_252, Code_253, Refresh = 255, RemoveCode = 256, Count = 257, RawValue = 258, RawValueIndex = 259 }; _enumerated _value; ValueID_Index_UserCode(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 259; static const int* _values() { static const int values[] = { (ignore_assign)Enrollment_Code = 0, (ignore_assign)Code_1, (ignore_assign)Code_2, (ignore_assign)Code_3, (ignore_assign)Code_4, (ignore_assign)Code_5, (ignore_assign)Code_6, (ignore_assign)Code_7, (ignore_assign)Code_8, (ignore_assign)Code_9, (ignore_assign)Code_10, (ignore_assign)Code_11, (ignore_assign)Code_12, (ignore_assign)Code_13, (ignore_assign)Code_14, (ignore_assign)Code_15, (ignore_assign)Code_16, (ignore_assign)Code_17, (ignore_assign)Code_18, (ignore_assign)Code_19, (ignore_assign)Code_20, (ignore_assign)Code_21, (ignore_assign)Code_22, (ignore_assign)Code_23, (ignore_assign)Code_24, (ignore_assign)Code_25, (ignore_assign)Code_26, (ignore_assign)Code_27, (ignore_assign)Code_28, (ignore_assign)Code_29, (ignore_assign)Code_30, (ignore_assign)Code_31, (ignore_assign)Code_32, (ignore_assign)Code_33, (ignore_assign)Code_34, (ignore_assign)Code_35, (ignore_assign)Code_36, (ignore_assign)Code_37, (ignore_assign)Code_38, (ignore_assign)Code_39, (ignore_assign)Code_40, (ignore_assign)Code_41, (ignore_assign)Code_42, (ignore_assign)Code_43, (ignore_assign)Code_44, (ignore_assign)Code_45, (ignore_assign)Code_46, (ignore_assign)Code_47, (ignore_assign)Code_48, (ignore_assign)Code_49, (ignore_assign)Code_50, (ignore_assign)Code_51, (ignore_assign)Code_52, (ignore_assign)Code_53, (ignore_assign)Code_54, (ignore_assign)Code_55, (ignore_assign)Code_56, (ignore_assign)Code_57, (ignore_assign)Code_58, (ignore_assign)Code_59, (ignore_assign)Code_60, (ignore_assign)Code_61, (ignore_assign)Code_62, (ignore_assign)Code_63, (ignore_assign)Code_64, (ignore_assign)Code_65, (ignore_assign)Code_66, (ignore_assign)Code_67, (ignore_assign)Code_68, (ignore_assign)Code_69, (ignore_assign)Code_70, (ignore_assign)Code_71, (ignore_assign)Code_72, (ignore_assign)Code_73, (ignore_assign)Code_74, (ignore_assign)Code_75, (ignore_assign)Code_76, (ignore_assign)Code_77, (ignore_assign)Code_78, (ignore_assign)Code_79, (ignore_assign)Code_80, (ignore_assign)Code_81, (ignore_assign)Code_82, (ignore_assign)Code_83, (ignore_assign)Code_84, (ignore_assign)Code_85, (ignore_assign)Code_86, (ignore_assign)Code_87, (ignore_assign)Code_88, (ignore_assign)Code_89, (ignore_assign)Code_90, (ignore_assign)Code_91, (ignore_assign)Code_92, (ignore_assign)Code_93, (ignore_assign)Code_94, (ignore_assign)Code_95, (ignore_assign)Code_96, (ignore_assign)Code_97, (ignore_assign)Code_98, (ignore_assign)Code_99, (ignore_assign)Code_100, (ignore_assign)Code_101, (ignore_assign)Code_102, (ignore_assign)Code_103, (ignore_assign)Code_104, (ignore_assign)Code_105, (ignore_assign)Code_106, (ignore_assign)Code_107, (ignore_assign)Code_108, (ignore_assign)Code_109, (ignore_assign)Code_110, (ignore_assign)Code_111, (ignore_assign)Code_112, (ignore_assign)Code_113, (ignore_assign)Code_114, (ignore_assign)Code_115, (ignore_assign)Code_116, (ignore_assign)Code_117, (ignore_assign)Code_118, (ignore_assign)Code_119, (ignore_assign)Code_120, (ignore_assign)Code_121, (ignore_assign)Code_122, (ignore_assign)Code_123, (ignore_assign)Code_124, (ignore_assign)Code_125, (ignore_assign)Code_126, (ignore_assign)Code_127, (ignore_assign)Code_128, (ignore_assign)Code_129, (ignore_assign)Code_130, (ignore_assign)Code_131, (ignore_assign)Code_132, (ignore_assign)Code_133, (ignore_assign)Code_134, (ignore_assign)Code_135, (ignore_assign)Code_136, (ignore_assign)Code_137, (ignore_assign)Code_138, (ignore_assign)Code_139, (ignore_assign)Code_140, (ignore_assign)Code_141, (ignore_assign)Code_142, (ignore_assign)Code_143, (ignore_assign)Code_144, (ignore_assign)Code_145, (ignore_assign)Code_146, (ignore_assign)Code_147, (ignore_assign)Code_148, (ignore_assign)Code_149, (ignore_assign)Code_150, (ignore_assign)Code_151, (ignore_assign)Code_152, (ignore_assign)Code_153, (ignore_assign)Code_154, (ignore_assign)Code_155, (ignore_assign)Code_156, (ignore_assign)Code_157, (ignore_assign)Code_158, (ignore_assign)Code_159, (ignore_assign)Code_160, (ignore_assign)Code_161, (ignore_assign)Code_162, (ignore_assign)Code_163, (ignore_assign)Code_164, (ignore_assign)Code_165, (ignore_assign)Code_166, (ignore_assign)Code_167, (ignore_assign)Code_168, (ignore_assign)Code_169, (ignore_assign)Code_170, (ignore_assign)Code_171, (ignore_assign)Code_172, (ignore_assign)Code_173, (ignore_assign)Code_174, (ignore_assign)Code_175, (ignore_assign)Code_176, (ignore_assign)Code_177, (ignore_assign)Code_178, (ignore_assign)Code_179, (ignore_assign)Code_180, (ignore_assign)Code_181, (ignore_assign)Code_182, (ignore_assign)Code_183, (ignore_assign)Code_184, (ignore_assign)Code_185, (ignore_assign)Code_186, (ignore_assign)Code_187, (ignore_assign)Code_188, (ignore_assign)Code_189, (ignore_assign)Code_190, (ignore_assign)Code_191, (ignore_assign)Code_192, (ignore_assign)Code_193, (ignore_assign)Code_194, (ignore_assign)Code_195, (ignore_assign)Code_196, (ignore_assign)Code_197, (ignore_assign)Code_198, (ignore_assign)Code_199, (ignore_assign)Code_200, (ignore_assign)Code_201, (ignore_assign)Code_202, (ignore_assign)Code_203, (ignore_assign)Code_204, (ignore_assign)Code_205, (ignore_assign)Code_206, (ignore_assign)Code_207, (ignore_assign)Code_208, (ignore_assign)Code_209, (ignore_assign)Code_210, (ignore_assign)Code_211, (ignore_assign)Code_212, (ignore_assign)Code_213, (ignore_assign)Code_214, (ignore_assign)Code_215, (ignore_assign)Code_216, (ignore_assign)Code_217, (ignore_assign)Code_218, (ignore_assign)Code_219, (ignore_assign)Code_220, (ignore_assign)Code_221, (ignore_assign)Code_222, (ignore_assign)Code_223, (ignore_assign)Code_224, (ignore_assign)Code_225, (ignore_assign)Code_226, (ignore_assign)Code_227, (ignore_assign)Code_228, (ignore_assign)Code_229, (ignore_assign)Code_230, (ignore_assign)Code_231, (ignore_assign)Code_232, (ignore_assign)Code_233, (ignore_assign)Code_234, (ignore_assign)Code_235, (ignore_assign)Code_236, (ignore_assign)Code_237, (ignore_assign)Code_238, (ignore_assign)Code_239, (ignore_assign)Code_240, (ignore_assign)Code_241, (ignore_assign)Code_242, (ignore_assign)Code_243, (ignore_assign)Code_244, (ignore_assign)Code_245, (ignore_assign)Code_246, (ignore_assign)Code_247, (ignore_assign)Code_248, (ignore_assign)Code_249, (ignore_assign)Code_250, (ignore_assign)Code_251, (ignore_assign)Code_252, (ignore_assign)Code_253, (ignore_assign)Refresh = 255, (ignore_assign)RemoveCode = 256, (ignore_assign)Count = 257, (ignore_assign)RawValue = 258, (ignore_assign)RawValueIndex = 259, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Enrollment_Code = 0", "Code_1", "Code_2", "Code_3", "Code_4", "Code_5", "Code_6", "Code_7", "Code_8", "Code_9", "Code_10", "Code_11", "Code_12", "Code_13", "Code_14", "Code_15", "Code_16", "Code_17", "Code_18", "Code_19", "Code_20", "Code_21", "Code_22", "Code_23", "Code_24", "Code_25", "Code_26", "Code_27", "Code_28", "Code_29", "Code_30", "Code_31", "Code_32", "Code_33", "Code_34", "Code_35", "Code_36", "Code_37", "Code_38", "Code_39", "Code_40", "Code_41", "Code_42", "Code_43", "Code_44", "Code_45", "Code_46", "Code_47", "Code_48", "Code_49", "Code_50", "Code_51", "Code_52", "Code_53", "Code_54", "Code_55", "Code_56", "Code_57", "Code_58", "Code_59", "Code_60", "Code_61", "Code_62", "Code_63", "Code_64", "Code_65", "Code_66", "Code_67", "Code_68", "Code_69", "Code_70", "Code_71", "Code_72", "Code_73", "Code_74", "Code_75", "Code_76", "Code_77", "Code_78", "Code_79", "Code_80", "Code_81", "Code_82", "Code_83", "Code_84", "Code_85", "Code_86", "Code_87", "Code_88", "Code_89", "Code_90", "Code_91", "Code_92", "Code_93", "Code_94", "Code_95", "Code_96", "Code_97", "Code_98", "Code_99", "Code_100", "Code_101", "Code_102", "Code_103", "Code_104", "Code_105", "Code_106", "Code_107", "Code_108", "Code_109", "Code_110", "Code_111", "Code_112", "Code_113", "Code_114", "Code_115", "Code_116", "Code_117", "Code_118", "Code_119", "Code_120", "Code_121", "Code_122", "Code_123", "Code_124", "Code_125", "Code_126", "Code_127", "Code_128", "Code_129", "Code_130", "Code_131", "Code_132", "Code_133", "Code_134", "Code_135", "Code_136", "Code_137", "Code_138", "Code_139", "Code_140", "Code_141", "Code_142", "Code_143", "Code_144", "Code_145", "Code_146", "Code_147", "Code_148", "Code_149", "Code_150", "Code_151", "Code_152", "Code_153", "Code_154", "Code_155", "Code_156", "Code_157", "Code_158", "Code_159", "Code_160", "Code_161", "Code_162", "Code_163", "Code_164", "Code_165", "Code_166", "Code_167", "Code_168", "Code_169", "Code_170", "Code_171", "Code_172", "Code_173", "Code_174", "Code_175", "Code_176", "Code_177", "Code_178", "Code_179", "Code_180", "Code_181", "Code_182", "Code_183", "Code_184", "Code_185", "Code_186", "Code_187", "Code_188", "Code_189", "Code_190", "Code_191", "Code_192", "Code_193", "Code_194", "Code_195", "Code_196", "Code_197", "Code_198", "Code_199", "Code_200", "Code_201", "Code_202", "Code_203", "Code_204", "Code_205", "Code_206", "Code_207", "Code_208", "Code_209", "Code_210", "Code_211", "Code_212", "Code_213", "Code_214", "Code_215", "Code_216", "Code_217", "Code_218", "Code_219", "Code_220", "Code_221", "Code_222", "Code_223", "Code_224", "Code_225", "Code_226", "Code_227", "Code_228", "Code_229", "Code_230", "Code_231", "Code_232", "Code_233", "Code_234", "Code_235", "Code_236", "Code_237", "Code_238", "Code_239", "Code_240", "Code_241", "Code_242", "Code_243", "Code_244", "Code_245", "Code_246", "Code_247", "Code_248", "Code_249", "Code_250", "Code_251", "Code_252", "Code_253", "Refresh = 255", "RemoveCode = 256", "Count = 257", "RawValue = 258", "RawValueIndex = 259", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_Version { enum _enumerated { Library = 0, Protocol = 1, Application = 2 }; _enumerated _value; ValueID_Index_Version(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 3; static const int* _values() { static const int values[] = { (ignore_assign)Library = 0, (ignore_assign)Protocol = 1, (ignore_assign)Application = 2, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Library = 0", "Protocol = 1", "Application = 2", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_WakeUp { enum _enumerated { Interval = 0, Min_Interval = 1, Max_Interval = 2, Default_Interval = 3, Interval_Step = 4 }; _enumerated _value; ValueID_Index_WakeUp(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 5; static const int* _values() { static const int values[] = { (ignore_assign)Interval = 0, (ignore_assign)Min_Interval = 1, (ignore_assign)Max_Interval = 2, (ignore_assign)Default_Interval = 3, (ignore_assign)Interval_Step = 4, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Interval = 0", "Min_Interval = 1", "Max_Interval = 2", "Default_Interval = 3", "Interval_Step = 4", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; struct ValueID_Index_ZWavePlusInfo { enum _enumerated { Version = 0, InstallerIcon = 1, UserIcon = 2 }; _enumerated _value; ValueID_Index_ZWavePlusInfo(_enumerated value) : _value(value) { } operator _enumerated() const { return _value; } const char* _to_string() const { for (size_t index = 0; index < _count; ++index) { if (_values()[index] == _value) return _names()[index]; } return NULL; } static const size_t _count = 3; static const int* _values() { static const int values[] = { (ignore_assign)Version = 0, (ignore_assign)InstallerIcon = 1, (ignore_assign)UserIcon = 2, }; return values; } static const char* const* _names() { static const char* const raw_names[] = { "Version = 0", "InstallerIcon = 1", "UserIcon = 2", }; static char* processed_names[_count]; static bool initialized = false; if (!initialized) { for (size_t index = 0; index < _count; ++index) { size_t length = std::strcspn(raw_names[index], " =\t\n\r"); processed_names[index] = new char[length + 1]; strncpy( processed_names[index], raw_names[index], length); processed_names[index][length] = '\0'; } } return processed_names; } };; openzwave-1.6.1914/cpp/src/SensorMultiLevelCCTypes.h0000755000175200017520000000524014032142455017155 00000000000000//----------------------------------------------------------------------------- // // SensorMultiLevelCCTypes.h // // SensorMultiLevelCCTypes for SensorMultiLevel Command Class // // Copyright (c) 2019 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef SENSORMULTILEVELCCTYPES_H #define SENSORMULTILEVELCCTYPES_H #include #include #include #include "Defs.h" #include "Driver.h" #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { class SensorMultiLevelCCTypes { public: class SensorMultiLevelScales { public: uint8 id; string name; string unit; }; typedef std::map > SensorScales; class SensorMultiLevelTypes { public: uint32 id; string name; SensorScales allSensorScales; }; //----------------------------------------------------------------------------- // Construction //----------------------------------------------------------------------------- private: SensorMultiLevelCCTypes(); ~SensorMultiLevelCCTypes(); static bool ReadXML(); public: static SensorMultiLevelCCTypes* Get(); static bool Create(); string GetSensorName(uint32); string GetSensorUnit(uint32, uint8); string GetSensorUnitName(uint32, uint8); const SensorScales GetSensorScales(uint32); //----------------------------------------------------------------------------- // Instance Functions //----------------------------------------------------------------------------- private: static SensorMultiLevelCCTypes* m_instance; static std::map > SensorTypes; static uint32 m_revision; }; } // namespace Internal } // namespace OpenZWave #endif // SENSORMULTILEVELCCTYPES_H openzwave-1.6.1914/cpp/src/Utils.h0000644000175200017520000001720714032142455013551 00000000000000//----------------------------------------------------------------------------- // // Utils.h // // Miscellaneous helper functions // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Utils_H #define _Utils_H #include "platform/Mutex.h" #include "platform/Log.h" #include #include #include #include #include #ifndef WIN32 #ifndef WINRT #ifdef DEBUG #include #include #endif #endif #endif namespace OpenZWave { namespace Internal { /** * Convert a string to all upper-case. * \param _str the string to be converted. * \return the upper-case string. * \see ToLower, Trim */ std::string ToUpper(string const& _str); /** * Convert a string to all lower-case. * \param _str the string to be converted. * \return the lower-case string. * \see ToUpper, Trim */ std::string ToLower(string const& _str); /** * Split a String into a Vector, separated by separators * \param lst the vector to store the results in * \param input the input string to split * \param separators a string containing a list of valid separators * \param remove_empty if after splitting a string, the any of the results are a empty string, should we preserve them or not */ void split(std::vector& lst, const std::string& input, const std::string& separators, bool remove_empty = true); /** * remove all Whitespace from of a string. * \param s the string to trim * \return the trimmed string */ std::string &removewhitespace(std::string &s); /** * @brief Left Trim * * Trims whitespace from the left end of the provided std::string * * @param[out] s The std::string to trim * * @return The modified std::string& */ std::string& ltrim(std::string& s); /** * @brief Right Trim * * Trims whitespace from the right end of the provided std::string * * @param[out] s The std::string to trim * * @return The modified std::string& */ std::string& rtrim(std::string& s); /** * @brief Trim * * Trims whitespace from both ends of the provided std::string * * @param[out] s The std::string to trim * * @return The modified std::string& */ std::string& trim(std::string& s); void PrintHex(std::string prefix, uint8_t const *data, uint32 const length); string PktToString(uint8 const *data, uint32 const length); struct LockGuard { LockGuard(Internal::Platform::Mutex* mutex) : _ref(mutex) { //std::cout << "Locking" << std::endl; _ref->Lock(); } ; ~LockGuard() { #if 0 if (_ref->IsSignalled()) std::cout << "Already Unlocked" << std::endl; else std::cout << "Unlocking" << std::endl; #endif if (!_ref->IsSignalled()) _ref->Unlock(); } void Unlock() { // std::cout << "Unlocking" << std::endl; _ref->Unlock(); } private: LockGuard(const LockGuard&); LockGuard& operator =(LockGuard const&); Internal::Platform::Mutex* _ref; }; string ozwdirname(string); string intToString(int x); const char* rssi_to_string(uint8 _data); #ifndef WIN32 #ifndef WINRT #ifdef DEBUG class StackTraceGenerator { private: // this is a pure utils class // cannot be instantiated // StackTraceGenerator() = delete; StackTraceGenerator(const StackTraceGenerator&) = delete; StackTraceGenerator& operator=(const StackTraceGenerator&) = delete; ~StackTraceGenerator() = delete; public: static std::vector GetTrace() { // record stack trace upto 128 frames int callstack[128] = {}; // collect stack frames int frames = backtrace((void**) callstack, 5); // get the human-readable symbols (mangled) char** strs = backtrace_symbols((void**) callstack, frames); std::vector stackFrames; stackFrames.reserve(frames); for (int i = 2; i < frames; ++i) { char functionSymbol[1024] = {}; char moduleName[1024] = {}; int offset = 0; char addr[48] = {}; /* Typically this is how the backtrace looks like: 0 0x0000000100000e98 _Z5tracev + 72 1 0x00000001000015c1 _ZNK7functorclEv + 17 2 0x0000000100000f71 _Z3fn0v + 17 3 0x0000000100000f89 _Z3fn1v + 9 4 0x0000000100000f99 _Z3fn2v + 9 5 0x0000000100000fa9 _Z3fn3v + 9 6 0x0000000100000fb9 _Z3fn4v + 9 7 0x0000000100000fc9 _Z3fn5v + 9 8 0x0000000100000fd9 _Z3fn6v + 9 9 0x0000000100001018 main + 56 10 libdyld.dylib 0x00007fff91b647e1 start + 0 */ // split the string, take out chunks out of stack trace // we are primarily interested in module, function and address sscanf(strs[i], "%*s %s %s %s %*s %d", moduleName, addr, functionSymbol, &offset); int validCppName = 0; // if this is a C++ library, symbol will be demangled // on success function returns 0 // char* functionName = abi::__cxa_demangle(functionSymbol, NULL, 0, &validCppName); char stackFrame[4096] = {}; if (validCppName == 0) // success { sprintf(stackFrame, "(%s)\t0x%s — %s + %d", moduleName, addr, functionName, offset); } else { // in the above traceback (in comments) last entry is not // from C++ binary, last frame, libdyld.dylib, is printed // from here sprintf(stackFrame, "(%s)\t0x%s — %s + %d", moduleName, addr, functionName, offset); } if (functionName) { free(functionName); } Log::Write(LogLevel_Warning, "Stack: %s", stackFrame); std::string frameStr(stackFrame); stackFrames.push_back(frameStr); } free(strs); return stackFrames; } }; #endif #endif #endif } // namespace Internal } // namespace OpenZWave /* keep this outside of the namespace */ #if (defined _WINDOWS || defined WIN32 || defined _MSC_VER) && (!defined MINGW && !defined __MINGW32__ && !defined __MINGW64__) #include struct tm *localtime_r(const time_t *_clock, struct tm *_result); #endif #endif openzwave-1.6.1914/cpp/src/Http.h0000644000175200017520000000536214032142455013367 00000000000000//----------------------------------------------------------------------------- // // Http.h // // Simple HTTP Client Interface to download updated config files // // Copyright (c) 2015 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Http_H #define _Http_H #include "Defs.h" #include "platform/Event.h" #include "platform/Thread.h" #include "platform/Mutex.h" namespace OpenZWave { class Driver; namespace Internal { /* This is a abstract class you can implement if you wish to override the built in HTTP Client * Code in OZW with your own code. * * The built in Code uses threads to download updated files to a temporary file * and then this class moves the files into the correct place. * */ struct HttpDownload { string filename; string url; uint8 node; enum DownloadType { None, File, Config, MFSConfig, Image }; DownloadType operation; enum Status { Ok, Failed }; Status transferStatus; }; class i_HttpClient { public: i_HttpClient(Driver *); virtual ~i_HttpClient() { } ; virtual bool StartDownload(HttpDownload *transfer) = 0; void FinishDownload(HttpDownload *transfer); private: Driver* m_driver; }; /* this is OZW's implementation of a Http Client. It uses threads to download Config Files in the background. * */ class HttpClient: public i_HttpClient { public: HttpClient(Driver *); ~HttpClient(); bool StartDownload(HttpDownload *transfer); private: static void HttpThreadProc(Internal::Platform::Event* _exitEvent, void* _context); //Driver* m_driver; Internal::Platform::Event* m_exitEvent; Internal::Platform::Thread* m_httpThread; bool m_httpThreadRunning; Internal::Platform::Mutex* m_httpMutex; list m_httpDownlist; Internal::Platform::Event* m_httpDownloadEvent; }; } // namespace Internal } /* namespace OpenZWave */ #endif openzwave-1.6.1914/cpp/src/Msg.h0000644000175200017520000001651414032142455013177 00000000000000//----------------------------------------------------------------------------- // // Msg.h // // Represents a Z-Wave message // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Msg_H #define _Msg_H #include #include #include #include "Defs.h" //#include "Driver.h" namespace OpenZWave { class Driver; namespace Internal { namespace CC { class CommandClass; } /** \brief Message object to be passed to and from devices on the Z-Wave network. */ class OPENZWAVE_EXPORT Msg { public: enum MessageFlags { m_MultiChannel = 0x01, // Indicate MultiChannel encapsulation m_MultiInstance = 0x02, // Indicate MultiInstance encapsulation }; Msg(string const& _logtext, uint8 _targetNodeId, uint8 const _msgType, uint8 const _function, bool const _bCallbackRequired, bool const _bReplyRequired = true, uint8 const _expectedReply = 0, uint8 const _expectedCommandClassId = 0); ~Msg() { } void SetInstance(OpenZWave::Internal::CC::CommandClass * _cc, uint8 const _instance); // Used to enable wrapping with MultiInstance/MultiChannel during finalize. void Append(uint8 const _data); void AppendArray(const uint8* const _data, const uint8 _length); void Finalize(); void UpdateCallbackId(); /** * \brief Identifies the Node ID of the "target" node (if any) for this function. * \return Node ID of the target. */ uint8 GetTargetNodeId() const { return m_targetNodeId; } /** * \brief Identifies the Callback ID (if any) for this message. Callback ID is a value (OpenZWave uses sequential IDs) that * helps the application associate message responses with the original message request. * \return Callback ID for this message. */ uint8 GetCallbackId() const { return m_callbackId; } /** * \brief Identifies the expected reply type (if any) for this message. The expected reply is a function code...one * of the FUNC_ID... values defined in Defs.h. Many Z-Wave functions generate responses with the same function code * (for example, a FUNC_ID_ZW_GET_VERSION message generates a FUNC_ID_ZW_GET_VERSION response. But other functions * generate a different response. FUNC_ID_ZW_SEND_DATA triggers several responses, but ultimately, a "Get" sent with * this function should result in a FUNC_ID_APPLICATION_COMMAND_HANDLER response. * \return Expected reply (function code) for this message. */ uint8 GetExpectedReply() const { return m_expectedReply; } /** * \brief Identifies the expected Command Class ID (if any) for this message. * \return Expected command class ID for this message. */ uint8 GetExpectedCommandClassId() const { return m_expectedCommandClassId; } /** * \brief For messages that request a Report for a specified command class, identifies the expected Instance * for the variable being obtained in the report. * \return Expected Instance value for this message. */ uint8 GetExpectedInstance() const { return m_instance; } /** * \brief For messages that request a Report for a specified command class, identifies the expected Index * for the variable being obtained in the report. * \return Expected Index value for this message. */ // uint8 GetExpectedIndex()const{ return m_expectedIndex; } /** * \brief get the LogText Associated with this message * \return the LogText used during the constructor */ string GetLogText() const { return m_logText; } uint32 GetLength() const { return m_encrypted == true ? m_length + 20 + 6 : m_length; } uint8* GetBuffer(); string GetAsString(); uint8 GetSendAttempts() const { return m_sendAttempts; } void SetSendAttempts(uint8 _count) { m_sendAttempts = _count; } uint8 GetMaxSendAttempts() const { return m_maxSendAttempts; } void SetMaxSendAttempts(uint8 _count) { if (_count < MAX_MAX_TRIES) m_maxSendAttempts = _count; } bool IsWakeUpNoMoreInformationCommand() { return (m_bFinal && (m_length == 11) && (m_buffer[3] == 0x13) && (m_buffer[6] == 0x84) && (m_buffer[7] == 0x08)); } bool IsNoOperation() { return (m_bFinal && (m_length == 11) && (m_buffer[3] == 0x13) && (m_buffer[6] == 0x00) && (m_buffer[7] == 0x00)); } bool operator ==(Msg const& _other) const { if (m_bFinal && _other.m_bFinal) { // Do not include the callback Id or checksum in the comparison. uint8 length = m_length - (m_bCallbackRequired ? 2 : 1); return (!memcmp(m_buffer, _other.m_buffer, length)); } return false; } uint8 GetSendingCommandClass() { if (m_buffer[3] == 0x13) { return m_buffer[6]; } return 0; } bool isEncrypted() { return m_encrypted; } void setEncrypted() { m_encrypted = true; } bool isNonceRecieved() { return m_noncerecvd; } void setNonce(uint8 nonce[8]) { memcpy(m_nonce, nonce, 8); m_noncerecvd = true; UpdateCallbackId(); } void clearNonce() { memset((m_nonce), '\0', 8); m_noncerecvd = false; } void SetHomeId(uint32 homeId) { m_homeId = homeId; } void setResendDuetoCANorNAK() { m_resendDuetoCANorNAK = true; } bool isResendDuetoCANorNAK() { return m_resendDuetoCANorNAK; } /** Returns a pointer to the driver (interface with a Z-Wave controller) * associated with this node. */ Driver* GetDriver() const; private: void MultiEncap(); // Encapsulate the data inside a MultiInstance/Multicommand message string m_logText; bool m_bFinal; bool m_bCallbackRequired; uint8 m_callbackId; uint8 m_expectedReply; uint8 m_expectedCommandClassId; uint8 m_length; uint8 m_buffer[256]; uint8 e_buffer[256]; uint8 m_targetNodeId; uint8 m_sendAttempts; uint8 m_maxSendAttempts; uint8 m_instance; uint8 m_endPoint; // Endpoint to use if the message must be wrapped in a multiInstance or multiChannel command class uint8 m_flags; bool m_encrypted; bool m_noncerecvd; uint8 m_nonce[8]; uint32 m_homeId; static uint8 s_nextCallbackId; // counter to get a unique callback id /* we are resending this message due to CAN or NAK messages */ bool m_resendDuetoCANorNAK; }; } // namespace Internal } // namespace OpenZWave #endif //_Msg_H openzwave-1.6.1914/cpp/src/DNSThread.h0000644000175200017520000000512214032142455014216 00000000000000//----------------------------------------------------------------------------- // // DNSThread.h // // Async DNS Lookups // // Copyright (c) 2016 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _DNSThread_H #define _DNSThread_H #include #include #include #include "Defs.h" #include "Driver.h" #include "platform/Event.h" #include "platform/Mutex.h" #include "platform/TimeStamp.h" #include "platform/DNS.h" namespace OpenZWave { namespace Internal { namespace Platform { class Event; class Mutex; class Thread; } enum LookupType { DNS_Lookup_ConfigRevision = 1 }; struct DNSLookup { uint8 NodeID; string lookup; string result; Internal::Platform::DNSError status; LookupType type; }; /** \brief the DNSThread provides Async DNS lookups for checking revision numbers of * Config Files against the official database */ class OPENZWAVE_EXPORT DNSThread { friend class OpenZWave::Driver; private: DNSThread(Driver *); virtual ~DNSThread(); /** * Entry point for DNSThread */ static void DNSThreadEntryPoint(Internal::Platform::Event* _exitEvent, void* _context); /** * DNSThreadProc for DNSThread. This is where all the "action" takes place. */ void DNSThreadProc(Internal::Platform::Event* _exitEvent); /* submit a Request to the DNS List */ bool sendRequest(DNSLookup *); /* process the most recent request recieved */ void processResult(); Driver* m_driver; Internal::Platform::Mutex* m_dnsMutex; list m_dnslist; list m_dnslistinprogress; Internal::Platform::Event* m_dnsRequestEvent; Internal::Platform::DNS m_dnsresolver; }; /* class DNSThread */ } // namespace Internal } /* namespace OpenZWave */ #endif openzwave-1.6.1914/cpp/src/Group.h0000644000175200017520000001270714032142455013545 00000000000000//----------------------------------------------------------------------------- // // Group.h // // A set of associations in a Z-Wave device. // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Group_H #define _Group_H #include #include #include #include "Defs.h" class TiXmlElement; namespace OpenZWave { namespace Internal { namespace CC { class Association; class MultiChannelAssociation; } } class Node; // When dealing with MultiInstance Devices, // OpenZWave uses "Instance" to identify a subdevice. // The public interface maps an Instance ID to an "End Point", which in turn // gets used to build Z-Wave packets. // Config files and by extension ozwcache store this map per CC, for example: // // The Group Aka Association commands, however, expect "End Points" // It would make sense to change "Instance" to "End Point" in all related code but... // InstanceAssociation is exposed by the API in Manager::GetAssociations // Because of its exposure, m_instance cannot be renamed to m_endPoint without // breaking existing code. typedef struct InstanceAssociation { uint8 m_nodeId; uint8 m_instance; // "End Point" as defined in SDS13782-11B, Multi Channel Association Command Class. } InstanceAssociation; /** \brief Manages a group of devices (various nodes associated with each other). */ class Group { friend class Node; friend class Internal::CC::Association; friend class Internal::CC::MultiChannelAssociation; //----------------------------------------------------------------------------- // Construction //----------------------------------------------------------------------------- public: Group(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx, uint8 const _maxAssociations); Group(uint32 const _homeId, uint8 const _nodeId, TiXmlElement const* _valueElement); ~Group() { } void WriteXML(TiXmlElement* _groupElement); //----------------------------------------------------------------------------- // Association methods (COMMAND_CLASS_ASSOCIATION) //----------------------------------------------------------------------------- public: string const& GetLabel() const { return m_label; } uint32 GetAssociations(uint8** o_associations); uint32 GetAssociations(InstanceAssociation** o_associations); uint8 GetMaxAssociations() const { return m_maxAssociations; } uint8 GetIdx() const { return m_groupIdx; } bool Contains(uint8 const _nodeId, uint8 const _endPoint= 0x00); bool IsMultiInstance() const { return m_multiInstance; } private: bool IsAuto() const { return m_auto; } void SetAuto(bool const _state) { m_auto = _state; } void CheckAuto(); void SetMultiInstance(bool const _state) { m_multiInstance = _state; } void AddAssociation(uint8 const _nodeId, uint8 const endPoint = 0x00); void RemoveAssociation(uint8 const _nodeId, uint8 const _endPoint = 0x00); void OnGroupChanged(vector const& _associations); void OnGroupChanged(vector const& _associations); //----------------------------------------------------------------------------- // Command methods (COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION) //----------------------------------------------------------------------------- public: bool ClearCommands(uint8 const _nodeId, uint8 const _endPoint = 0x00); bool AddCommand(uint8 const _nodeId, uint8 const _length, uint8 const* _data, uint8 const _endPoint = 0x00); private: class AssociationCommand { public: AssociationCommand(uint8 const _length, uint8 const* _data); ~AssociationCommand(); private: uint8* m_data; }; typedef vector AssociationCommandVec; struct classcomp { bool operator()(const InstanceAssociation& lhs, const InstanceAssociation& rhs) const { return lhs.m_nodeId == rhs.m_nodeId ? lhs.m_instance < rhs.m_instance : lhs.m_nodeId < rhs.m_nodeId; } }; //----------------------------------------------------------------------------- // Member variables //----------------------------------------------------------------------------- private: string m_label; uint32 m_homeId; uint8 m_nodeId; uint8 m_groupIdx; uint8 m_maxAssociations; bool m_auto; // If true, the controller will automatically be associated with the group bool m_multiInstance; // If true, the group is MultiInstance capable map m_associations; }; } //namespace OpenZWave #endif //_Group_H openzwave-1.6.1914/cpp/src/Manager.h0000644000175200017520000045740114032142455014027 00000000000000//----------------------------------------------------------------------------- // // Manager.h // // The main public interface to OpenZWave. // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Manager_H #define _Manager_H #include #include #include #include #include #include #include "Defs.h" #include "Driver.h" #include "Group.h" #include "value_classes/ValueID.h" namespace OpenZWave { namespace Internal { namespace CC { class CommandClass; } namespace VC { class Value; class ValueStore; } class Msg; } class Options; class Node; class Notification; /** \brief * The main public interface to OpenZWave. * * \nosubgrouping * A singleton class providing the main public interface to OpenZWave. * The Manager class exposes all the functionality required to add * Z-Wave support to an application. It handles the sending and receiving * of Z-Wave messages as well as the configuration of a Z-Wave network * and its devices, freeing the library user from the burden of learning * the low-level details of the Z-Wave protocol. *

* All Z-Wave functionality is accessed via the Manager class. While this * does not make for the most efficient code structure, it does enable * the library to handle potentially complex and hard-to-debug issues * such as multi-threading and object lifespans behind the scenes. * Application development is therefore simplified and less prone to bugs. *

* There can be only one instance of the Manager class, and all applications * will start by calling Manager::Create static method to create that instance. * From then on, a call to the Manager::Get static method will return the * pointer to the Manager object. On application exit, Manager::Destroy * should be called to allow OpenZWave to clean up and delete any other * objects it has created. *

* Once the Manager has been created, a call should be made to Manager::AddWatcher * to install a notification callback handler. This handler will receive * notifications of Z-Wave network changes and updates to device values, and is * an essential element of OpenZWave. *

* Next, a call should be made to Manager::AddDriver for each Z-Wave controller * attached to the PC. Each Driver will handle the sending and receiving of * messages for all the devices in its controller's Z-Wave network. The Driver * will read any previously saved configuration and then query the Z-Wave controller * for any missing information. Once that process is complete, a DriverReady * notification callback will be sent containing the Home ID of the controller, * which is required by most of the other Manager class methods. *

* [After the DriverReady notification is sent, the Driver will poll each node on * the network to update information about each node. After all "awake" nodes * have been polled, an "AllAwakeNodesQueried" notification is sent. This is when * a client application can expect all of the node information (both static * information, like the physical device's capabilities, session information * (like [associations and/or names] and dynamic information (like temperature or * on/off state) to be available. Finally, after all nodes (whether listening or * sleeping) have been polled, an "AllNodesQueried" notification is sent.] */ class OPENZWAVE_EXPORT Manager { friend class Driver; friend class Internal::CC::CommandClass; friend class Group; friend class Node; friend class Internal::VC::Value; friend class Internal::VC::ValueStore; friend class Internal::Msg; public: typedef void (*pfnOnNotification_t)(Notification const* _pNotification, void* _context); //----------------------------------------------------------------------------- // Construction //----------------------------------------------------------------------------- /** \name Construction * For creating and destroying the Manager singleton. */ /*@{*/ public: /** * \brief Creates the Manager singleton object. * The Manager provides the public interface to OpenZWave, exposing all the functionality required * to add Z-Wave support to an application. There can be only one Manager in an OpenZWave application. * An Options object must be created and Locked first, otherwise the call to Manager::Create will * fail. Once the Manager has been created, call AddWatcher to install a notification callback handler, * and then call the AddDriver method for each attached PC Z-Wave controller in turn. * \param _options a locked Options object containing all the application's configurable option values. * \return a pointer to the newly created Manager object, or NULL if creation failed. * \throws OZWException with Type OZWException::OZWEXCEPTION_OPTIONS if the Options Class is not setup and Locked * \see Options, Get, Destroy, AddWatcher, AddDriver */ static Manager* Create(); /** * \brief Gets a pointer to the Manager object. * \return pointer to the Manager object, or NULL if Create has not yet been called. * \see Create, Destroy */ static Manager* Get() { return s_instance; } /** * \brief Deletes the Manager and cleans up any associated objects. * \see Create, Get */ static void Destroy(); /** * \brief Get the Version Number of OZW as a string * \return a String representing the version number as MAJOR.MINOR.REVISION */ static std::string getVersionAsString(); /** * \brief Get the Version Number including Git commit of OZW as a string * \return a String representing the version number as MAJOR.MINOR.REVISION-gCOMMIT */ static std::string getVersionLongAsString(); /** * \brief Get the Version Number as the Version Struct (Only Major/Minor returned) * \return the version struct representing the version */ static ozwversion getVersion(); /*@}*/ private: Manager(); // Constructor, to be called only via the static Create method. virtual ~Manager(); // Destructor, to be called only via the static Destroy method. bool m_exit; // Flag indicating that program exit is in progress. static Manager* s_instance; // Pointer to the instance of the Manager singleton. //----------------------------------------------------------------------------- // Configuration //----------------------------------------------------------------------------- /** \name Configuration * For saving the Z-Wave network configuration so that the entire network does not need to be * polled every time the application starts. */ /*@{*/ public: /** * \brief Saves a cache of a PC Controller's Z-Wave network to the application's user data folder. * This method does not normally need to be called, since OpenZWave will save the state automatically * during the shutdown process. It is provided here only as an aid to development. * The configuration of each PC Controller's Z-Wave network is stored in a separate file. The filename * consists of the 8 digit hexadecimal version of the controller's Home ID, prefixed with the string 'ozwcache_'. * This convention allows OpenZWave to find the correct configuration file for a controller, even if it is * attached to a different serial port, USB device path, etc. * \deprecated OZW handles writing out the cache automatically. This does not need to be called anymore. * \param _homeId The Home ID of the Z-Wave controller to save. */ DEPRECATED void WriteConfig(uint32 const _homeId); /** * \brief Gets a pointer to the locked Options object. * \return pointer to the Options object. * \see Create */ Options* GetOptions() const { return m_options; } /*@}*/ private: Options* m_options; // Pointer to the locked Options object that was passed in during creation. //----------------------------------------------------------------------------- // Drivers //----------------------------------------------------------------------------- /** \name Drivers * Methods for adding and removing drivers and obtaining basic controller information. */ /*@{*/ public: /** * \brief Creates a new driver for a Z-Wave controller. * This method creates a Driver object for handling communications with a single Z-Wave controller. In the background, the * driver first tries to read configuration data saved during a previous run. It then queries the controller directly for any * missing information, and a refresh of the list of nodes that it controls. Once this information * has been received, a DriverReady notification callback is sent, containing the Home ID of the controller. This Home ID is * required by most of the OpenZWave Manager class methods. * @param _controllerPath The string used to open the controller. On Windows this might be something like * "\\.\COM3", or on Linux "/dev/ttyUSB0". * \return True if a new driver was created, false if a driver for the controller already exists. * \see Create, Get, RemoveDriver */ bool AddDriver(string const& _controllerPath, Driver::ControllerInterface const& _interface = Driver::ControllerInterface_Serial); /** * \brief Removes the driver for a Z-Wave controller, and closes the controller. * Drivers do not need to be explicitly removed before calling Destroy - this is handled automatically. * \warning You should NOT call any Manager methods that require the Driver Reference (eg, in response to * Notifications received about NodeRemoved etc) once you call this, as your application will most likely * break * @param _controllerPath The same string as was passed in the original call to AddDriver. * @returns True if the driver was removed, false if it could not be found. * @see Destroy, AddDriver */ bool RemoveDriver(string const& _controllerPath); /** * \brief Get the node ID of the Z-Wave controller. * \param _homeId The Home ID of the Z-Wave controller. * \return the node ID of the Z-Wave controller. */ uint8 GetControllerNodeId(uint32 const _homeId); /** * \brief Get the node ID of the Static Update Controller. * \param _homeId The Home ID of the Z-Wave controller. * \return the node ID of the Z-Wave controller. */ uint8 GetSUCNodeId(uint32 const _homeId); /** * \brief Query if the controller is a primary controller. * The primary controller is the main device used to configure and control a Z-Wave network. * There can only be one primary controller - all other controllers are secondary controllers. *

* The only difference between a primary and secondary controller is that the primary is the * only one that can be used to add or remove other devices. For this reason, it is usually * better for the primary controller to be portable, since most devices must be added when * installed in their final location. *

* Calls to BeginControllerCommand will fail if the controller is not the primary. * \param _homeId The Home ID of the Z-Wave controller. * \return true if it is a primary controller, false if not. */ bool IsPrimaryController(uint32 const _homeId); /** * \brief Query if the controller is a static update controller. * A Static Update Controller (SUC) is a controller that must never be moved in normal operation * and which can be used by other nodes to receive information about network changes. * \param _homeId The Home ID of the Z-Wave controller. * \return true if it is a static update controller, false if not. */ bool IsStaticUpdateController(uint32 const _homeId); /** * \brief Query if the controller is using the bridge controller library. * A bridge controller is able to create virtual nodes that can be associated * with other controllers to enable events to be passed on. * \param _homeId The Home ID of the Z-Wave controller. * \return true if it is a bridge controller, false if not. */ bool IsBridgeController(uint32 const _homeId); /** * \brief Query if the controller support "extended status information" * On IMA enabled targets build on SDK >= 6.60.00 * ZW_SendData can return information about TX time, route tries and more. * \param _homeId The Home ID of the Z-Wave controller. * \return true if the controller accepted to turn on extended status. */ bool HasExtendedTxStatus(uint32 const _homeId); /** * \brief Get the version of the Z-Wave API library used by a controller. * \param _homeId The Home ID of the Z-Wave controller. * \return a string containing the library version. For example, "Z-Wave 2.48". */ string GetLibraryVersion(uint32 const _homeId); /** * \brief Get a string containing the Z-Wave API library type used by a controller. * The possible library types are: * - Static Controller * - Controller * - Enhanced Slave * - Slave * - Installer * - Routing Slave * - Bridge Controller * - Device Under Test * * The controller should never return a slave library type. * For a more efficient test of whether a controller is a Bridge Controller, use * the IsBridgeController method. * \param _homeId The Home ID of the Z-Wave controller. * \return a string containing the library type. * \see GetLibraryVersion, IsBridgeController */ string GetLibraryTypeName(uint32 const _homeId); /** * \brief Get count of messages in the outgoing send queue. * \param _homeId The Home ID of the Z-Wave controller. * \return a integer message count */ int32 GetSendQueueCount(uint32 const _homeId); /** * \brief Send current driver statistics to the log file * \param _homeId The Home ID of the Z-Wave controller. */ void LogDriverStatistics(uint32 const _homeId); /** * \brief Obtain controller interface type * \param _homeId The Home ID of the Z-Wave controller. */ Driver::ControllerInterface GetControllerInterfaceType(uint32 const _homeId); /** * \brief Obtain controller interface path * \param _homeId The Home ID of the Z-Wave controller. */ string GetControllerPath(uint32 const _homeId); /*@}*/ private: Driver* GetDriver(uint32 const _homeId); /**< Get a pointer to a Driver object from the HomeID. Only to be used by OpenZWave. */ void SetDriverReady(Driver* _driver, bool success); /**< Indicate that the Driver is ready to be used, and send the notification callback. */ list m_pendingDrivers; /**< Drivers that are in the process of reading saved data and querying their Z-Wave network for basic information. */ map m_readyDrivers; /**< Drivers that are ready to be used by the application. */ //----------------------------------------------------------------------------- // Polling Z-Wave devices //----------------------------------------------------------------------------- /** \name Polling Z-Wave devices * Methods for controlling the polling of Z-Wave devices. Modern devices will not * require polling. Some old devices need to be polled as the only way to detect * status changes. */ /*@{*/ public: /** * \brief Get the time period between polls of a node's state. */ int32 GetPollInterval(); /** * \brief Set the time period between polls of a node's state. * Due to patent concerns, some devices do not report state changes automatically to the controller. * These devices need to have their state polled at regular intervals. The length of the interval * is the same for all devices. To even out the Z-Wave network traffic generated by polling, OpenZWave * divides the polling interval by the number of devices that have polling enabled, and polls each * in turn. It is recommended that if possible, the interval should not be set shorter than the * number of polled devices in seconds (so that the network does not have to cope with more than one * poll per second). * \param _seconds The length of the polling interval in seconds. */ void SetPollInterval(int32 _milliseconds, bool _bIntervalBetweenPolls); /** * \brief Enable the polling of a device's state. * \param _valueId The ID of the value to start polling. * \param _intensity, number of polling for one polling interval. * \return True if polling was enabled. */ bool EnablePoll(ValueID const &_valueId, uint8 const _intensity = 1); /** * \brief Disable the polling of a device's state. * \param _valueId The ID of the value to stop polling. * \return True if polling was disabled. */ bool DisablePoll(ValueID const &_valueId); /** * \brief Determine the polling of a device's state. * \param _valueId The ID of the value to check polling. * \return True if polling is active. */ bool isPolled(ValueID const &_valueId); /** * \brief Set the frequency of polling (0=none, 1=every time through the list, 2-every other time, etc) * \param _valueId The ID of the value whose intensity should be set */ void SetPollIntensity(ValueID const &_valueId, uint8 const _intensity); /** * \brief Get the polling intensity of a device's state. * \param _valueId The ID of the value to check polling. * \return Intensity, number of polling for one polling interval. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ uint8 GetPollIntensity(ValueID const &_valueId); /*@}*/ //----------------------------------------------------------------------------- // Node information //----------------------------------------------------------------------------- /** \name Node information * Methods for accessing information on individual nodes. */ /*@{*/ public: /** * \brief Refresh a Node and Reload it into OZW * Causes the node's Supported CommandClasses and Capabilities to be obtained from the Z-Wave network * This method would normally be called automatically by OpenZWave, but if you know that a node's capabilities or command classes * has been changed, calling this method will force a refresh of that information. * This call shouldn't be needed except in special circumstances. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return True if the request was sent successfully. */ bool RefreshNodeInfo(uint32 const _homeId, uint8 const _nodeId); /** * \brief Trigger the fetching of dynamic value data for a node. * Causes the node's values to be requested from the Z-Wave network. This is the * same as the query state starting from the associations state. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return True if the request was sent successfully. */ bool RequestNodeState(uint32 const _homeId, uint8 const _nodeId); /** * \brief Trigger the fetching of just the dynamic value data for a node. * Causes the node's values to be requested from the Z-Wave network. This is the * same as the query state starting from the dynamic state. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return True if the request was sent successfully. */ bool RequestNodeDynamic(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get whether the node is a listening device that does not go to sleep * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return True if it is a listening node. */ bool IsNodeListeningDevice(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get whether the node is a frequent listening device that goes to sleep but * can be woken up by a beam. Useful to determine node and controller consistency. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return True if it is a frequent listening node. */ bool IsNodeFrequentListeningDevice(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get whether the node is a beam capable device. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return True if it is a beam capable node. */ bool IsNodeBeamingDevice(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get whether the node is a routing device that passes messages to other nodes * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return True if the node is a routing device */ bool IsNodeRoutingDevice(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the security attribute for a node. True if node supports security features. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return true if security features implemented. */ bool IsNodeSecurityDevice(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the maximum baud rate of a node's communications * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return the baud rate in bits per second. */ uint32 GetNodeMaxBaudRate(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the version number of a node * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return the node's version number */ uint8 GetNodeVersion(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the security byte of a node * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return the node's security byte */ uint8 GetNodeSecurity(uint32 const _homeId, uint8 const _nodeId); /** * \brief Is this a ZWave+ Supported Node? * \param _homeId the HomeID of the Z-Wave controller that managed the node. * \param _nodeId the ID of the node to query. * \return If this node is a Z-Wave Plus Node */ bool IsNodeZWavePlus(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the basic type of a node. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return the node's basic type. */ uint8 GetNodeBasic(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the basic type of a node. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return the node's basic type. */ string GetNodeBasicString(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the generic type of a node. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \param _instance If Specified, Get the Generic Type for a Instance * \return the node's generic type. */ uint8 GetNodeGeneric(uint32 const _homeId, uint8 const _nodeId, uint8 const _instance = 0); /** * \brief Get the generic type of a node as a String * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \param _instance If Specified, Get the Generic Type for a Instance * \return the node's generic type. */ string GetNodeGenericString(uint32 const _homeId, uint8 const _nodeId, uint8 const _instance = 0); /** * \brief Get the specific type of a node. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \param _instance If Specified, Get the Specific Type for a Instance * \return the node's specific type. */ uint8 GetNodeSpecific(uint32 const _homeId, uint8 const _nodeId, uint8 const _instance = 0); /** * \brief Get the specific type of a node as a string * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \param _instance If Specified, Get the Specific Type for a Instance * \return the node's specific type. */ string GetNodeSpecificString(uint32 const _homeId, uint8 const _nodeId, uint8 const _instance = 0); /** * \brief Get a human-readable label describing the node * The label is taken from the Z-Wave specific, generic or basic type, depending on which of those values are specified by the node. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return A string containing the label text. */ string GetNodeType(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the bitmap of this node's neighbors * * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \param _nodeNeighbors An array of 29 uint8s to hold the neighbor bitmap * \sa SyncronizeNodeNeighbors */ uint32 GetNodeNeighbors(uint32 const _homeId, uint8 const _nodeId, uint8** _nodeNeighbors); /** * \brief Update the List of Neighbors on a particular node * * This retrieves the latest copy of the Neighbor lists for a particular node and should be called * before calling GetNodeNeighbors to ensure OZW returns the most recent list of Neighbors * * \param _homeId The HomeID of the Z-Wave controller than manages the node. * \param _nodeId The ID of the node to get a updated list of Neighbors from * \sa GetNodeNeighbors */ void SyncronizeNodeNeighbors(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the manufacturer name of a device * The manufacturer name would normally be handled by the Manufacturer Specific command class, * taking the manufacturer ID reported by the device and using it to look up the name from the * manufacturer_specific.xml file in the OpenZWave config folder. * However, there are some devices that do not support the command class, so to enable the user * to manually set the name, it is stored with the node data and accessed via this method rather * than being reported via a command class Value object. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return A string containing the node's manufacturer name. * \see SetNodeManufacturerName, GetNodeProductName, SetNodeProductName */ string GetNodeManufacturerName(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the product name of a device * The product name would normally be handled by the Manufacturer Specific command class, * taking the product Type and ID reported by the device and using it to look up the name from the * manufacturer_specific.xml file in the OpenZWave config folder. * However, there are some devices that do not support the command class, so to enable the user * to manually set the name, it is stored with the node data and accessed via this method rather * than being reported via a command class Value object. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return A string containing the node's product name. * \see SetNodeProductName, GetNodeManufacturerName, SetNodeManufacturerName */ string GetNodeProductName(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the name of a node * The node name is a user-editable label for the node that would normally be handled by the * Node Naming command class, but many devices do not support it. So that a node can always * be named, OpenZWave stores it with the node data, and provides access through this method * and SetNodeName, rather than reporting it via a command class Value object. * The maximum length of a node name is 16 characters. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return A string containing the node's name. * \see SetNodeName, GetNodeLocation, SetNodeLocation */ string GetNodeName(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the location of a node * The node location is a user-editable string that would normally be handled by the Node Naming * command class, but many devices do not support it. So that a node can always report its * location, OpenZWave stores it with the node data, and provides access through this method * and SetNodeLocation, rather than reporting it via a command class Value object. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return A string containing the node's location. * \see SetNodeLocation, GetNodeName, SetNodeName */ string GetNodeLocation(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the manufacturer ID of a device * The manufacturer ID is a four digit hex code and would normally be handled by the Manufacturer * Specific command class, but not all devices support it. Although the value reported by this * method will be an empty string if the command class is not supported and cannot be set by the * user, the manufacturer ID is still stored with the node data (rather than being reported via a * command class Value object) to retain a consistent approach with the other manufacturer specific data. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return A string containing the node's manufacturer ID, or an empty string if the manufacturer * specific command class is not supported by the device. * \see GetNodeProductType, GetNodeProductId, GetNodeManufacturerName, GetNodeProductName * \todo Change the return to uint16 in 2.0 time frame */ string GetNodeManufacturerId(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the product type of a device * The product type is a four digit hex code and would normally be handled by the Manufacturer Specific * command class, but not all devices support it. Although the value reported by this method will * be an empty string if the command class is not supported and cannot be set by the user, the product * type is still stored with the node data (rather than being reported via a command class Value object) * to retain a consistent approach with the other manufacturer specific data. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return A string containing the node's product type, or an empty string if the manufacturer * specific command class is not supported by the device. * \see GetNodeManufacturerId, GetNodeProductId, GetNodeManufacturerName, GetNodeProductName * \todo Change the return to uint16 in 2.0 time frame */ string GetNodeProductType(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the product ID of a device * The product ID is a four digit hex code and would normally be handled by the Manufacturer Specific * command class, but not all devices support it. Although the value reported by this method will * be an empty string if the command class is not supported and cannot be set by the user, the product * ID is still stored with the node data (rather than being reported via a command class Value object) * to retain a consistent approach with the other manufacturer specific data. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return A string containing the node's product ID, or an empty string if the manufacturer * specific command class is not supported by the device. * \see GetNodeManufacturerId, GetNodeProductType, GetNodeManufacturerName, GetNodeProductName * \todo Change the return to uint16 in 2.0 time frame */ string GetNodeProductId(uint32 const _homeId, uint8 const _nodeId); /** * \brief Set the manufacturer name of a device * The manufacturer name would normally be handled by the Manufacturer Specific command class, * taking the manufacturer ID reported by the device and using it to look up the name from the * manufacturer_specific.xml file in the OpenZWave config folder. * However, there are some devices that do not support the command class, so to enable the user * to manually set the name, it is stored with the node data and accessed via this method rather * than being reported via a command class Value object. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \param _manufacturerName A string containing the node's manufacturer name. * \see GetNodeManufacturerName, GetNodeProductName, SetNodeProductName */ void SetNodeManufacturerName(uint32 const _homeId, uint8 const _nodeId, string const& _manufacturerName); /** * \brief Set the product name of a device * The product name would normally be handled by the Manufacturer Specific command class, * taking the product Type and ID reported by the device and using it to look up the name from the * manufacturer_specific.xml file in the OpenZWave config folder. * However, there are some devices that do not support the command class, so to enable the user * to manually set the name, it is stored with the node data and accessed via this method rather * than being reported via a command class Value object. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \param _productName A string containing the node's product name. * \see GetNodeProductName, GetNodeManufacturerName, SetNodeManufacturerName */ void SetNodeProductName(uint32 const _homeId, uint8 const _nodeId, string const& _productName); /** * \brief Set the name of a node * The node name is a user-editable label for the node that would normally be handled by the * Node Naming command class, but many devices do not support it. So that a node can always * be named, OpenZWave stores it with the node data, and provides access through this method * and GetNodeName, rather than reporting it via a command class Value object. * If the device does support the Node Naming command class, the new name will be sent to the node. * The maximum length of a node name is 16 characters. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \param _nodeName A string containing the node's name. * \see GetNodeName, GetNodeLocation, SetNodeLocation */ void SetNodeName(uint32 const _homeId, uint8 const _nodeId, string const& _nodeName); /** * \brief Set the location of a node * The node location is a user-editable string that would normally be handled by the Node Naming * command class, but many devices do not support it. So that a node can always report its * location, OpenZWave stores it with the node data, and provides access through this method * and GetNodeLocation, rather than reporting it via a command class Value object. * If the device does support the Node Naming command class, the new location will be sent to the node. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \param _location A string containing the node's location. * \see GetNodeLocation, GetNodeName, SetNodeName */ void SetNodeLocation(uint32 const _homeId, uint8 const _nodeId, string const& _location); /** * \brief Turns a node on * This is a helper method to simplify basic control of a node. It is the equivalent of * changing the level reported by the node's Basic command class to 255, and will generate a * ValueChanged notification from that class. This command will turn on the device at its * last known level, if supported by the device, otherwise it will turn it on at 100%. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to be changed. * \deprecated This method has been depreciated in setting the ValueID's directly (Remove in 1.8) * * \see SetNodeOff, SetNodeLevel */ DEPRECATED void SetNodeOn(uint32 const _homeId, uint8 const _nodeId); /** * \brief Turns a node off * This is a helper method to simplify basic control of a node. It is the equivalent of * changing the level reported by the node's Basic command class to zero, and will generate * a ValueChanged notification from that class. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to be changed. * \deprecated This method has been depreciated in setting the ValueID's directly (Remove in 1.8) * \see SetNodeOn, SetNodeLevel */ DEPRECATED void SetNodeOff(uint32 const _homeId, uint8 const _nodeId); /** * \brief Sets the basic level of a node * This is a helper method to simplify basic control of a node. It is the equivalent of * changing the value reported by the node's Basic command class and will generate a * ValueChanged notification from that class. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to be changed. * \param _level The level to set the node. Valid values are 0-99 and 255. Zero is off and * 99 is fully on. 255 will turn on the device at its last known level (if supported). * \deprecated This method has been depreciated in setting the ValueID's directly (Remove in 1.8) * \see SetNodeOn, SetNodeOff */ DEPRECATED void SetNodeLevel(uint32 const _homeId, uint8 const _nodeId, uint8 const _level); /** * \brief Get whether the node information has been received * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return True if the node information has been received yet */ bool IsNodeInfoReceived(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get whether the node has the defined class available or not * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \param _commandClassId Id of the class to test for * \return True if the node does have the class instantiated, will return name & version */ bool GetNodeClassInformation(uint32 const _homeId, uint8 const _nodeId, uint8 const _commandClassId, string *_className = NULL, uint8 *_classVersion = NULL); /** * \brief Get a friendly name for the CommandClass ID * \param _commandClassId Id of the class to test for * \return String returning the CommandClass Name */ string GetCommandClassName(uint8 const _commandClassId); /** * \brief Get whether the node is awake or asleep * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return True if the node is awake */ bool IsNodeAwake(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get whether the node is working or has failed * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return True if the node has failed and is no longer part of the network */ bool IsNodeFailed(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get whether the node's query stage as a string * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return name of current query stage as a string. */ string GetNodeQueryStage(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the node device type as reported in the Z-Wave+ Info report. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return the node's DeviceType */ uint16 GetNodeDeviceType(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the node device type as reported in the Z-Wave+ Info report. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return the node's Device Type as a string. */ string GetNodeDeviceTypeString(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the node role as reported in the Z-Wave+ Info report. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return the node's user icon. */ uint8 GetNodeRole(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the node role as reported in the Z-Wave+ Info report. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return the node's role type as a string */ string GetNodeRoleString(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the node PlusType as reported in the Z-Wave+ Info report. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return the node's PlusType */ uint8 GetNodePlusType(uint32 const _homeId, uint8 const _nodeId); /** * \brief Get the node PlusType as reported in the Z-Wave+ Info report. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to query. * \return the node's PlusType as a string */ string GetNodePlusTypeString(uint32 const _homeId, uint8 const _nodeId); /*@}*/ //----------------------------------------------------------------------------- // Instances //----------------------------------------------------------------------------- /** \name Instances * Methods for accessing Instance Information. */ /*@{*/ public: /** *\brief Get the Instance Label for a specific ValueID * returns the Instance Label for a Specific ValueID on a CommandClass, or the Global Instance Label * if there is no specific label for the CommandClass *\param _id The unique identifier of the value *\return The Instance Label * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ string GetInstanceLabel(ValueID const &_id); /** *\brief Get the Instance Label for a specific CommandClass * returns the Label for a Specific Instance on a Specific CommandClass, or the Global Instance Label * if there is no specific label for the CommandClass *\param _homeId the HomeID for the network you are querying *\param _node The Node you are interested in. *\param _cc The CommandClass for the Label you are interested in *\param _instance the Instance you are querying for *\return The Instance Label * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ string GetInstanceLabel(uint32 const _homeId, uint8 const _node, uint8 const _cc, uint8 const _instance); /*@}*/ //----------------------------------------------------------------------------- // Values //----------------------------------------------------------------------------- /** \name Values * Methods for accessing device values. All the methods require a ValueID, which will have been provided * in the ValueAdded Notification callback when the the value was first discovered by OpenZWave. */ /*@{*/ public: /** * \brief Gets the user-friendly label for the value. * \param _id The unique identifier of the value. * \param _pos the Bit To Get the Label for if its a BitSet ValueID * \return The value label. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID */ string GetValueLabel(ValueID const& _id, int32 _pos = -1); /** * \brief Sets the user-friendly label for the value. * \param _id The unique identifier of the value. * \param _pos the Bit To set the Label for if its a BitSet ValueID * \param _value The new value of the label. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID */ void SetValueLabel(ValueID const& _id, string const& _value, int32 _pos = -1); /** * \brief Gets the units that the value is measured in. * \param _id The unique identifier of the value. * \return The value units. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID */ string GetValueUnits(ValueID const& _id); /** * \brief Sets the units that the value is measured in. * \param _id The unique identifier of the value. * \param _value The new value of the units. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID */ void SetValueUnits(ValueID const& _id, string const& _value); /** * \brief Gets a help string describing the value's purpose and usage. * \param _id The unique identifier of the value. * \param _pos Get the Help for associated Bits (Valid with ValueBitSet only) * \return The value help text. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID */ string GetValueHelp(ValueID const& _id, int32 _pos = -1); /** * \brief Sets a help string describing the value's purpose and usage. * \param _id The unique identifier of the value. * \param _value The new value of the help text. * \param __pos Set the Help for a associated Bit (Valid with ValueBitSet Only) * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID */ void SetValueHelp(ValueID const& _id, string const& _value, int32 _pos = -1); /** * \brief Gets the minimum that this value may contain. * \param _id The unique identifier of the value. * \return The value minimum. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID */ int32 GetValueMin(ValueID const& _id); /** * \brief Gets the maximum that this value may contain. * \param _id The unique identifier of the value. * \return The value maximum. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID */ int32 GetValueMax(ValueID const& _id); /** * \brief Test whether the value is read-only. * \param _id The unique identifier of the value. * \return true if the value cannot be changed by the user. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID */ bool IsValueReadOnly(ValueID const& _id); /** * \brief Test whether the value is write-only. * \param _id The unique identifier of the value. * \return true if the value can only be written to and not read. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID */ bool IsValueWriteOnly(ValueID const& _id); /** * \brief Test whether the value has been set. * \param _id The unique identifier of the value. * \return true if the value has actually been set by a status message from the device, rather than simply being the default. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID */ bool IsValueSet(ValueID const& _id); /** * \brief Test whether the value is currently being polled. * \param _id The unique identifier of the value. * \return true if the value is being polled, otherwise false. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID */ bool IsValuePolled(ValueID const& _id); /** * \brief Test whether the ValueID is valid. * \param _id The unique identifier of the value. * \return true if the valueID is valid, otherwise false. * \see ValueID */ bool IsValueValid(ValueID const& _id); /** * \brief Gets a the value of a Bit from a BitSet ValueID * \param _id The unique identifier of the value. * \param _pos the Bit you want to test for * \param o_value Pointer to a bool that will be filled with the value. * \return true if the value was obtained. Returns false if the value is not a ValueID::ValueType_BitSet. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID::GetType, GetValueAsBitSet, GetValueAsByte, GetValueAsFloat, GetValueAsInt, GetValueAsShort, GetValueAsString, GetValueListSelection, GetValueListItems, GetValueAsRaw */ bool GetValueAsBitSet(ValueID const& _id, uint8 _pos, bool* o_value); /** * \brief Gets a value as a bool. * \param _id The unique identifier of the value. * \param o_value Pointer to a bool that will be filled with the value. * \return true if the value was obtained. Returns false if the value is not a ValueID::ValueType_Bool. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID::GetType, GetValueAsBitSet, GetValueAsByte, GetValueAsFloat, GetValueAsInt, GetValueAsShort, GetValueAsString, GetValueListSelection, GetValueListItems, GetValueAsRaw */ bool GetValueAsBool(ValueID const& _id, bool* o_value); /** * \brief Gets a value as an 8-bit unsigned integer. * \param _id The unique identifier of the value. * \param o_value Pointer to a uint8 that will be filled with the value. * \return true if the value was obtained. Returns false if the value is not a ValueID::ValueType_Byte. The type can be tested with a call to ValueID::GetType * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID::GetType, GetValueAsBitSet, GetValueAsBool, GetValueAsFloat, GetValueAsInt, GetValueAsShort, GetValueAsString, GetValueListSelection, GetValueListItems, GetValueAsRaw */ bool GetValueAsByte(ValueID const& _id, uint8* o_value); /** * \brief Gets a value as a float. * \param _id The unique identifier of the value. * \param o_value Pointer to a float that will be filled with the value. * \return true if the value was obtained. Returns false if the value is not a ValueID::ValueType_Decimal. The type can be tested with a call to ValueID::GetType * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID::GetType, GetValueAsBitSet, GetValueAsBool, GetValueAsByte, GetValueAsInt, GetValueAsShort, GetValueAsString, GetValueListSelection, GetValueListItems, GetValueAsRaw */ bool GetValueAsFloat(ValueID const& _id, float* o_value); /** * \brief Gets a value as a 32-bit signed integer. * \param _id The unique identifier of the value. * \param o_value Pointer to an int32 that will be filled with the value. * \return true if the value was obtained. Returns false if the value is not a ValueID::ValueType_Int. The type can be tested with a call to ValueID::GetType * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID::GetType, GetValueAsBitSet, GetValueAsBool, GetValueAsByte, GetValueAsFloat, GetValueAsShort, GetValueAsString, GetValueListSelection, GetValueListItems, GetValueAsRaw */ bool GetValueAsInt(ValueID const& _id, int32* o_value); /** * \brief Gets a value as a 16-bit signed integer. * \param _id The unique identifier of the value. * \param o_value Pointer to an int16 that will be filled with the value. * \return true if the value was obtained. Returns false if the value is not a ValueID::ValueType_Short. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID::GetType, GetValueAsBitSet, GetValueAsBool, GetValueAsByte, GetValueAsFloat, GetValueAsInt, GetValueAsString, GetValueListSelection, GetValueListItems, GetValueAsRaw */ bool GetValueAsShort(ValueID const& _id, int16* o_value); /** * \brief Gets a value as a string. * Creates a string representation of a value, regardless of type. * \param _id The unique identifier of the value. * \param o_value Pointer to a string that will be filled with the value. * \return true if the value was obtained. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID::GetType, GetValueAsBitSet, GetValueAsBool, GetValueAsByte, GetValueAsFloat, GetValueAsInt, GetValueAsShort, GetValueListSelection, GetValueListItems, GetValueAsRaw */ bool GetValueAsString(ValueID const& _id, string* o_value); /** * \brief Gets a value as a collection of bytes. * \param _id The unique identifier of the value. * \param o_value Pointer to a uint8* that will be filled with the value. This return value will need to be freed as it was dynamically allocated. * \param o_length Pointer to a uint8 that will be fill with the data length. * \return true if the value was obtained. Returns false if the value is not a ValueID::ValueType_Raw. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID::GetType, GetValueAsBitSet, GetValueAsBool, GetValueAsByte, GetValueAsFloat, GetValueAsInt, GetValueAsShort, GetValueListSelection, GetValueListItems, GetValueAsRaw */ bool GetValueAsRaw(ValueID const& _id, uint8** o_value, uint8* o_length); /** * \brief Gets the selected item from a list (as a string). * \param _id The unique identifier of the value. * \param o_value Pointer to a string that will be filled with the selected item. * \return True if the value was obtained. Returns false if the value is not a ValueID::ValueType_List. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID::GetType, GetValueAsBitSet, GetValueAsBool, GetValueAsByte, GetValueAsFloat, GetValueAsInt, GetValueAsShort, GetValueAsString, GetValueListItems, GetValueAsRaw */ bool GetValueListSelection(ValueID const& _id, string* o_value); /** * \brief Gets the selected item from a list (as an integer). * \param _id The unique identifier of the value. * \param o_value Pointer to an integer that will be filled with the selected item. * \return True if the value was obtained. Returns false if the value is not a ValueID::ValueType_List. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID::GetType, GetValueAsBitSet, GetValueAsBool, GetValueAsByte, GetValueAsFloat, GetValueAsInt, GetValueAsShort, GetValueAsString, GetValueListItems, GetValueAsRaw */ bool GetValueListSelection(ValueID const& _id, int32* o_value); /** * \brief Gets the list of items from a list value. * \param _id The unique identifier of the value. * \param o_value Pointer to a vector of strings that will be filled with list items. The vector will be cleared before the items are added. * \return true if the list items were obtained. Returns false if the value is not a ValueID::ValueType_List. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID::GetType, GetValueAsBitSet, GetValueAsBool, GetValueAsByte, GetValueAsFloat, GetValueAsInt, GetValueAsShort, GetValueAsString, GetValueListSelection, GetValueAsRaw */ bool GetValueListItems(ValueID const& _id, vector* o_value); /** * \brief Gets the list of values from a list value. * \param _id The unique identifier of the value. * \param o_value Pointer to a vector of integers that will be filled with list items. The vector will be cleared before the items are added. * \return true if the list values were obtained. Returns false if the value is not a ValueID::ValueType_List. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID::GetType, GetValueAsBitSet, GetValueAsBool, GetValueAsByte, GetValueAsFloat, GetValueAsInt, GetValueAsShort, GetValueAsString, GetValueListSelection, GetValueAsRaw */ bool GetValueListValues(ValueID const& _id, vector* o_value); /** * \brief Gets a float value's precision. * \param _id The unique identifier of the value. * \param o_value Pointer to a uint8 that will be filled with the precision value. * \return true if the value was obtained. Returns false if the value is not a ValueID::ValueType_Decimal. The type can be tested with a call to ValueID::GetType * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see ValueID::GetType, GetValueAsBitSet, GetValueAsBool, GetValueAsByte, GetValueAsInt, GetValueAsShort, GetValueAsString, GetValueListSelection, GetValueListItems */ bool GetValueFloatPrecision(ValueID const& _id, uint8* o_value); /** * \brief Sets the state of a bit in a BitSet ValueID. * Due to the possibility of a device being asleep, the command is assumed to succeed, and the value * held by the node is updated directly. This will be reverted by a future status message from the device * if the Z-Wave message actually failed to get through. Notification callbacks will be sent in both cases. * \param _id The unique identifier of the BitSet value. * \param _pos the Position of the Bit you want to Set * \param _value The new value of the Bitset at the _pos position. * \return true if the value was set. Returns false if the value is not a ValueID::ValueType_Bool. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * */ bool SetValue(ValueID const& _id, uint8 _pos, bool const _value); /** * \brief Sets the state of a bool. * Due to the possibility of a device being asleep, the command is assumed to succeed, and the value * held by the node is updated directly. This will be reverted by a future status message from the device * if the Z-Wave message actually failed to get through. Notification callbacks will be sent in both cases. * \param _id The unique identifier of the bool value. * \param _value The new value of the bool. * \return true if the value was set. Returns false if the value is not a ValueID::ValueType_Bool. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * */ bool SetValue(ValueID const& _id, bool const _value); /** * \brief Sets the value of a byte. * Due to the possibility of a device being asleep, the command is assumed to succeed, and the value * held by the node is updated directly. This will be reverted by a future status message from the device * if the Z-Wave message actually failed to get through. Notification callbacks will be sent in both cases. * \param _id The unique identifier of the byte value. * \param _value The new value of the byte. * \return true if the value was set. Returns false if the value is not a ValueID::ValueType_Byte. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ bool SetValue(ValueID const& _id, uint8 const _value); /** * \brief Sets the value of a decimal. * It is usually better to handle decimal values using strings rather than floats, to avoid floating point accuracy issues. * Due to the possibility of a device being asleep, the command is assumed to succeed, and the value * held by the node is updated directly. This will be reverted by a future status message from the device * if the Z-Wave message actually failed to get through. Notification callbacks will be sent in both cases. * \param _id The unique identifier of the decimal value. * \param _value The new value of the decimal. * \return true if the value was set. Returns false if the value is not a ValueID::ValueType_Decimal. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ bool SetValue(ValueID const& _id, float const _value); /** * \brief Sets the value of a 32-bit signed integer. * Due to the possibility of a device being asleep, the command is assumed to succeed, and the value * held by the node is updated directly. This will be reverted by a future status message from the device * if the Z-Wave message actually failed to get through. Notification callbacks will be sent in both cases. * \param _id The unique identifier of the integer value. * \param _value The new value of the integer. * \return true if the value was set. Returns false if the value is not a ValueID::ValueType_Int. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ bool SetValue(ValueID const& _id, int32 const _value); /** * \brief Sets the value of a 16-bit signed integer. * Due to the possibility of a device being asleep, the command is assumed to succeed, and the value * held by the node is updated directly. This will be reverted by a future status message from the device * if the Z-Wave message actually failed to get through. Notification callbacks will be sent in both cases. * \param _id The unique identifier of the integer value. * \param _value The new value of the integer. * \return true if the value was set. Returns false if the value is not a ValueID::ValueType_Short. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ bool SetValue(ValueID const& _id, int16 const _value); /** * \brief Sets the value of a collection of bytes. * Due to the possibility of a device being asleep, the command is assumed to succeed, and the value * held by the node is updated directly. This will be reverted by a future status message from the device * if the Z-Wave message actually failed to get through. Notification callbacks will be sent in both cases. * \param _id The unique identifier of the raw value. * \param _value The new collection of bytes. * \return true if the value was set. Returns false if the value is not a ValueID::ValueType_Raw. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ bool SetValue(ValueID const& _id, uint8 const* _value, uint8 const _length); /** * \brief Sets the value from a string, regardless of type. * Due to the possibility of a device being asleep, the command is assumed to succeed, and the value * held by the node is updated directly. This will be reverted by a future status message from the device * if the Z-Wave message actually failed to get through. Notification callbacks will be sent in both cases. * \param _id The unique identifier of the integer value. * \param _value The new value of the string. * \return true if the value was set. Returns false if the value could not be parsed into the correct type for the value. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ bool SetValue(ValueID const& _id, string const& _value); /** * \brief Sets the selected item in a list. * Due to the possibility of a device being asleep, the command is assumed to succeed, and the value * held by the node is updated directly. This will be reverted by a future status message from the device * if the Z-Wave message actually failed to get through. Notification callbacks will be sent in both cases. * \param _id The unique identifier of the list value. * \param _selectedItem A string matching the new selected item in the list. * \return true if the value was set. Returns false if the selection is not in the list, or if the value is not a ValueID::ValueType_List. * The type can be tested with a call to ValueID::GetType * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ bool SetValueListSelection(ValueID const& _id, string const& _selectedItem); /** * \brief Refreshes the specified value from the Z-Wave network. * A call to this function causes the library to send a message to the network to retrieve the current value * of the specified ValueID (just like a poll, except only one-time, not recurring). * \param _id The unique identifier of the value to be refreshed. * \return true if the driver and node were found; false otherwise * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ bool RefreshValue(ValueID const& _id); /** * \brief Sets a flag indicating whether value changes noted upon a refresh should be verified. If so, the * library will immediately refresh the value a second time whenever a change is observed. This helps to filter * out spurious data reported occasionally by some devices. * \param _id The unique identifier of the value whose changes should or should not be verified. * \param _verify if true, verify changes; if false, don't verify changes. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \sa Manager::GetChangeVerified */ void SetChangeVerified(ValueID const& _id, bool _verify); /** * \brief determine if value changes upon a refresh should be verified. If so, the * library will immediately refresh the value a second time whenever a change is observed. This helps to filter * out spurious data reported occasionally by some devices. * \param _id The unique identifier of the value whose changes should or should not be verified. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \sa Manager::SetChangeVerified */ bool GetChangeVerified(ValueID const& _id); /** * \brief Starts an activity in a device. * Since buttons are write-only values that do not report a state, no notification callbacks are sent. * \param _id The unique identifier of the integer value. * \return true if the activity was started. Returns false if the value is not a ValueID::ValueType_Button. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ bool PressButton(ValueID const& _id); /** * \brief Stops an activity in a device. * Since buttons are write-only values that do not report a state, no notification callbacks are sent. * \param _id The unique identifier of the integer value. * \return true if the activity was stopped. Returns false if the value is not a ValueID::ValueType_Button. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ bool ReleaseButton(ValueID const& _id); /** * \brief Sets the Valid BitMask for a BitSet ValueID * Sets a BitMask of Valid Bits for a BitSet ValueID * \param _id The unique identifier of the integer value. * \param _mask The Mask to set * \return true if the mask was applied. Returns false if the value is not a ValueID::ValueType_BitSet or the Mask was invalid. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ bool SetBitMask(ValueID const& _id, uint32 _mask); /** * \brief Gets the Valid BitMask for a BitSet ValueID * Gets a BitMask of Valid Bits for a BitSet ValueID * \param _id The unique identifier of the integer value. * \param o_mask The Mask to for the BitSet * \return true if the mask was retrieved. Returns false if the value is not a ValueID::ValueType_BitSet or the Mask was invalid. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ bool GetBitMask(ValueID const& _id, int32* o_mask); /** * \brief Gets the size of a BitMask ValueID * Gets the size of a BitMask ValueID - Either 1, 2 or 4 * \param _id The unique identifier of the integer value. * \param o_size The Size of the BitSet * \return true if the size was retrieved. Returns false if the value is not a ValueID::ValueType_BitSet or the Mask was invalid. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ bool GetBitSetSize(ValueID const& _id, uint8* o_size); /*@}*/ //----------------------------------------------------------------------------- // Climate Control Schedules //----------------------------------------------------------------------------- /** \name Climate Control Schedules * Methods for accessing schedule values. All the methods require a ValueID, which will have been provided * in the ValueAdded Notification callback when the the value was first discovered by OpenZWave. *

The ValueType_Schedule is a specialized Value used to simplify access to the switch point schedule * information held by a setback thermostat that supports the Climate Control Schedule command class. * Each schedule contains up to nine switch points for a single day, consisting of a time in * hours and minutes (24 hour clock) and a setback in tenths of a degree Celsius. The setback value can * range from -128 (-12.8C) to 120 (12.0C). There are two special setback values - 121 is used to set * Frost Protection mode, and 122 is used to set Energy Saving mode. *

The switch point methods only modify OpenZWave's copy of the schedule information. Once all changes * have been made, they are sent to the device by calling SetSchedule. */ /*@{*/ /** * \brief Get the number of switch points defined in a schedule. * \param _id The unique identifier of the schedule value. * \return the number of switch points defined in this schedule. Returns zero if the value is not a ValueID::ValueType_Schedule. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found */ uint8 GetNumSwitchPoints(ValueID const& _id); /** * \brief Set a switch point in the schedule. * Inserts a new switch point into the schedule, unless a switch point already exists at the specified * time in which case that switch point is updated with the new setback value instead. * A maximum of nine switch points can be set in the schedule. * \param _id The unique identifier of the schedule value. * \param _hours The hours part of the time when the switch point will trigger. The time is set using * the 24-hour clock, so this value must be between 0 and 23. * \param _minutes The minutes part of the time when the switch point will trigger. This value must be * between 0 and 59. * \param _setback The setback in tenths of a degree Celsius. The setback value can range from -128 (-12.8C) * to 120 (12.0C). There are two special setback values - 121 is used to set Frost Protection mode, and * 122 is used to set Energy Saving mode. * \return true if successful. Returns false if the value is not a ValueID::ValueType_Schedule. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see GetNumSwitchPoints, RemoveSwitchPoint, ClearSwitchPoints */ bool SetSwitchPoint(ValueID const& _id, uint8 const _hours, uint8 const _minutes, int8 const _setback); /** * \brief Remove a switch point from the schedule. * Removes the switch point at the specified time from the schedule. * \param _id The unique identifier of the schedule value. * \param _hours The hours part of the time when the switch point will trigger. The time is set using * the 24-hour clock, so this value must be between 0 and 23. * \param _minutes The minutes part of the time when the switch point will trigger. This value must be * between 0 and 59. * \return true if successful. Returns false if the value is not a ValueID::ValueType_Schedule or if there * is not switch point with the specified time values. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see GetNumSwitchPoints, SetSwitchPoint, ClearSwitchPoints */ bool RemoveSwitchPoint(ValueID const& _id, uint8 const _hours, uint8 const _minutes); /** * \brief Clears all switch points from the schedule. * \param _id The unique identifier of the schedule value. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see GetNumSwitchPoints, SetSwitchPoint, RemoveSwitchPoint */ void ClearSwitchPoints(ValueID const& _id); /** * \brief Gets switch point data from the schedule. * Retrieves the time and setback values from a switch point in the schedule. * \param _id The unique identifier of the schedule value. * \param _idx The index of the switch point, between zero and one less than the value * returned by GetNumSwitchPoints. * \param o_hours a pointer to a uint8 that will be filled with the hours part of the switch point data. * \param o_minutes a pointer to a uint8 that will be filled with the minutes part of the switch point data. * \param o_setback a pointer to an int8 that will be filled with the setback value. This can range from -128 * (-12.8C)to 120 (12.0C). There are two special setback values - 121 is used to set Frost Protection mode, and * 122 is used to set Energy Saving mode. * \return true if successful. Returns false if the value is not a ValueID::ValueType_Schedule. The type can be tested with a call to ValueID::GetType. * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid * \throws OZWException with Type OZWException::OZWEXCEPTION_CANNOT_CONVERT_VALUEID if the Actual Value is off a different type * \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found * \see GetNumSwitchPoints */ bool GetSwitchPoint(ValueID const& _id, uint8 const _idx, uint8* o_hours, uint8* o_minutes, int8* o_setback); /*@}*/ //----------------------------------------------------------------------------- // SwitchAll //----------------------------------------------------------------------------- /** \name SwitchAll * Methods for switching all devices on or off together. The devices must support * the SwitchAll command class. The command is first broadcast to all nodes, and * then followed up with individual commands to each node (because broadcasts are * not routed, the message might not otherwise reach all the nodes). */ /*@{*/ /** * \brief Switch all devices on. * All devices that support the SwitchAll command class will be turned on. * \deprecated This method has been depreciated. Please use the ValueID interface instead. */ DEPRECATED void SwitchAllOn(uint32 const _homeId); /** * \brief Switch all devices off. * All devices that support the SwitchAll command class will be turned off. * \deprecated This method has been depreciated. Please use the ValueID interface instead. */ DEPRECATED void SwitchAllOff(uint32 const _homeId); /*@}*/ //----------------------------------------------------------------------------- // Configuration Parameters //----------------------------------------------------------------------------- /** \name Configuration Parameters * Methods for accessing device configuration parameters. * Configuration parameters are values that are managed by the Configuration command class. * The values are device-specific and are not reported by the devices. Information on parameters * is provided only in the device user manual. *

An ongoing task for the OpenZWave project is to create XML files describing the available * parameters for every Z-Wave. See the config folder in the project source code for examples. */ /*@{*/ public: /** * \brief Set the value of a configurable parameter in a device. * Some devices have various parameters that can be configured to control the device behavior. * These are not reported by the device over the Z-Wave network, but can usually be found in * the device's user manual. * This method returns immediately, without waiting for confirmation from the device that the * change has been made. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to configure. * \param _param The index of the parameter. * \param _value The value to which the parameter should be set. * \param _size Is an optional number of bytes to be sent for the parameter _value. Defaults to 2. * \return true if the a message setting the value was sent to the device. * \see RequestConfigParam */ bool SetConfigParam(uint32 const _homeId, uint8 const _nodeId, uint8 const _param, int32 _value, uint8 const _size = 2); /** * \brief Request the value of a configurable parameter from a device. * Some devices have various parameters that can be configured to control the device behavior. * These are not reported by the device over the Z-Wave network, but can usually be found in * the device's user manual. * This method requests the value of a parameter from the device, and then returns immediately, * without waiting for a response. If the parameter index is valid for this device, and the * device is awake, the value will eventually be reported via a ValueChanged notification callback. * The ValueID reported in the callback will have an index set the same as _param and a command class * set to the same value as returned by a call to Configuration::StaticGetCommandClassId. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to configure. * \param _param The index of the parameter. * \see SetConfigParam, ValueID, Notification */ void RequestConfigParam(uint32 const _homeId, uint8 const _nodeId, uint8 const _param); /** * \brief Request the values of all known configurable parameters from a device. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node to configure. * \see SetConfigParam, ValueID, Notification */ void RequestAllConfigParams(uint32 const _homeId, uint8 const _nodeId); /*@}*/ //----------------------------------------------------------------------------- // Groups (wrappers for the Node methods) //----------------------------------------------------------------------------- /** \name Groups * Methods for accessing device association groups. */ /*@{*/ public: /** * \brief Gets the number of association groups reported by this node * In Z-Wave, groups are numbered starting from one. For example, if a call to GetNumGroups returns 4, the _groupIdx * value to use in calls to GetAssociations, AddAssociation and RemoveAssociation will be a number between 1 and 4. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node whose groups we are interested in. * \return The number of groups. * \see GetAssociations, GetMaxAssociations, AddAssociation, RemoveAssociation */ uint8 GetNumGroups(uint32 const _homeId, uint8 const _nodeId); /** * \brief Gets the associations for a group. * Makes a copy of the list of associated nodes in the group, and returns it in an array of uint8's. * The caller is responsible for freeing the array memory with a call to delete []. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node whose associations we are interested in. * \param _groupIdx One-based index of the group (because Z-Wave product manuals use one-based group numbering). * \param o_associations If the number of associations returned is greater than zero, o_associations will be set to point to an array containing the IDs of the associated nodes. * \return The number of nodes in the associations array. If zero, the array will point to NULL, and does not need to be deleted. * \see GetNumGroups, AddAssociation, RemoveAssociation, GetMaxAssociations */ uint32 GetAssociations(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx, uint8** o_associations); /** * \brief Gets the associations for a group. * Makes a copy of the list of associated nodes in the group, and returns it in an array of InstanceAssociation's. * struct InstanceAssociation is defined in Group.h and contains * a (NodeID, End Point) pair. See SDS13783-11B Z-Wave Transport-Encapsulation Command Class Specification * chapter 2.3.1 Terminology for the definition of "End Point" and "Multi Channel Encapsulation" * The caller is responsible for freeing the array memory with a call to delete []. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node whose associations we are interested in. * \param _groupIdx One-based index of the group (because Z-Wave product manuals use one-based group numbering). * \param o_associations If the number of associations returned is greater than zero, o_associations will be set to point to an array containing the IDs and instances of the associated nodes. * \return The number of items in the associations array. If zero, the array will point to NULL, and does not need to be deleted. * \see GetNumGroups, AddAssociation, RemoveAssociation, GetMaxAssociations */ uint32 GetAssociations(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx, InstanceAssociation** o_associations); /** * \brief Gets the maximum number of associations for a group. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node whose associations we are interested in. * \param _groupIdx one-based index of the group (because Z-Wave product manuals use one-based group numbering). * \return The maximum number of nodes that can be associated into the group. * \see GetNumGroups, AddAssociation, RemoveAssociation, GetAssociations */ uint8 GetMaxAssociations(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx); /** * \brief Returns true is group supports multi instance. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node whose associations we are interested in. * \param _groupIdx one-based index of the group (because Z-Wave product manuals use one-based group numbering). * \return True if group supports multi instance. * \see GetNumGroups, AddAssociation, RemoveAssociation, GetAssociations, GetMaxAssociations */ bool IsMultiInstance(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx); /** * \brief Returns a label for the particular group of a node. * This label is populated by the device specific configuration files. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node whose associations are to be changed. * \param _groupIdx One-based index of the group (because Z-Wave product manuals use one-based group numbering). * \see GetNumGroups, GetAssociations, GetMaxAssociations, AddAssociation */ string GetGroupLabel(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx); /** * \brief Adds a node to an association group. * Due to the possibility of a device being asleep, the command is assumed to succeed, and the association data * held in this class is updated directly. This will be reverted by a future Association message from the device * if the Z-Wave message actually failed to get through. Notification callbacks will be sent in both cases. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node whose associations are to be changed. * \param _groupIdx One-based index of the group (because Z-Wave product manuals use one-based group numbering). * \param _targetNodeId Identifier for the node that will be added to the association group. * \param _instance Identifier for the instance that will be added to the association group. * \see GetNumGroups, GetAssociations, GetMaxAssociations, RemoveAssociation */ void AddAssociation(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx, uint8 const _targetNodeId, uint8 const _instance = 0x00); /** * \brief Removes a node from an association group. * Due to the possibility of a device being asleep, the command is assumed to succeed, and the association data * held in this class is updated directly. This will be reverted by a future Association message from the device * if the Z-Wave message actually failed to get through. Notification callbacks will be sent in both cases. * \param _homeId The Home ID of the Z-Wave controller that manages the node. * \param _nodeId The ID of the node whose associations are to be changed. * \param _groupIdx One-based index of the group (because Z-Wave product manuals use one-based group numbering). * \param _targetNodeId Identifier for the node that will be removed from the association group. * \param _instance Identifier for the instance that will be removed to the association group. * \see GetNumGroups, GetAssociations, GetMaxAssociations, AddAssociation */ void RemoveAssociation(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx, uint8 const _targetNodeId, uint8 const _instance = 0x00); /*@}*/ //----------------------------------------------------------------------------- // Notifications //----------------------------------------------------------------------------- /** \name Notifications * For notification of changes to the Z-Wave network or device values and associations. */ /*@{*/ public: /** * \brief Add a notification watcher. * In OpenZWave, all feedback from the Z-Wave network is sent to the application via callbacks. * This method allows the application to add a notification callback handler, known as a "watcher" to OpenZWave. * An application needs only add a single watcher - all notifications will be reported to it. * \param _watcher pointer to a function that will be called by the notification system. * \param _context pointer to user defined data that will be passed to the watcher function with each notification. * \return true if the watcher was successfully added. * \see RemoveWatcher, Notification */ bool AddWatcher(pfnOnNotification_t _watcher, void* _context); /** * \brief Remove a notification watcher. * \param _watcher pointer to a function that must match that passed to a previous call to AddWatcher * \param _context pointer to user defined data that must match the one passed in that same previous call to AddWatcher. * \return true if the watcher was successfully removed. * \see AddWatcher, Notification */ bool RemoveWatcher(pfnOnNotification_t _watcher, void* _context); /*@}*/ private: void NotifyWatchers(Notification* _notification); // Passes the notifications to all the registered watcher callbacks in turn. struct Watcher { pfnOnNotification_t m_callback; void* m_context; Watcher(pfnOnNotification_t _callback, void* _context) : m_callback(_callback), m_context(_context) { } }; list m_watchers; // List of all the registered watchers. list::iterator*> m_watcherIterators; // Iterators currently operating on the list of watchers Internal::Platform::Mutex* m_notificationMutex; //----------------------------------------------------------------------------- // Controller commands //----------------------------------------------------------------------------- /** \name Controller Commands * Commands for Z-Wave network management using the PC Controller. */ /*@{*/ public: /** * \brief Hard Reset a PC Z-Wave Controller. * Resets a controller and erases its network configuration settings. The controller becomes a primary controller ready to add devices to a new network. * \param _homeId The Home ID of the Z-Wave controller to be reset. * \see SoftReset */ void ResetController(uint32 const _homeId); /** * \brief Soft Reset a PC Z-Wave Controller. * Resets a controller without erasing its network configuration settings. * \param _homeId The Home ID of the Z-Wave controller to be reset. * \see SoftReset */ void SoftReset(uint32 const _homeId); /** * \brief Start a controller command process. * Most Controller Commands are implemented via Other Manager methods, you should * only use this method if you need advanced control over a existing Controller Command * or if a ControllerCommand is not implemented. * * \param _homeId The Home ID of the Z-Wave controller. * \param _command The command to be sent to the controller. * \param _callback pointer to a function that will be called at various stages during the command process * to notify the user of progress or to request actions on the user's part. Defaults to NULL. Callbacks are also sent * via Notification mechanism with type of Notification::Type_ControllerCommand * \param _context pointer to user defined data that will be passed into to the callback function. Defaults to NULL. * \param _highPower used only with the AddDevice, AddController, RemoveDevice and RemoveController commands. * Usually when adding or removing devices, the controller operates at low power so that the controller must * be physically close to the device for security reasons. If _highPower is true, the controller will * operate at normal power levels instead. Defaults to false. * \param _nodeId is the node ID used by the command if necessary. * \param _arg is an optional argument, usually another node ID, that is used by the command. * \return true if the command was accepted and has queued to be executed. * \see CancelControllerCommand, HasNodeFailed, RemoveFailedNode, Driver::ControllerCommand, Driver::pfnControllerCallback_t, *

Commands * - Driver::ControllerCommand_AddDevice - Add a new device or controller to the Z-Wave network. * - Driver::ControllerCommand_CreateNewPrimary - Create a new primary controller when old primary fails. Requires SUC. * - Driver::ControllerCommand_ReceiveConfiguration - Receive network configuration information from primary controller. Requires secondary. * - Driver::ControllerCommand_RemoveDevice - Remove a device or controller from the Z-Wave network. * - Driver::ControllerCommand_RemoveFailedNode - Remove a node from the network. The node must not be responding * and be on the controller's failed node list. * - Driver::ControllerCommand_HasNodeFailed - Check whether a node is in the controller's failed nodes list. * - Driver::ControllerCommand_ReplaceFailedNode - Replace a failed device with another. If the node is not in * the controller's failed nodes list, or the node responds, this command will fail. * - Driver:: ControllerCommand_TransferPrimaryRole - Add a new controller to the network and * make it the primary. The existing primary will become a secondary controller. * - Driver::ControllerCommand_RequestNetworkUpdate - Update the controller with network information from the SUC/SIS. * - Driver::ControllerCommand_RequestNodeNeighborUpdate - Get a node to rebuild its neighbour list. This method also does RequestNodeNeighbors afterwards. * - Driver::ControllerCommand_AssignReturnRoute - Assign a network return route to a device. * - Driver::ControllerCommand_DeleteAllReturnRoutes - Delete all network return routes from a device. * - Driver::ControllerCommand_SendNodeInformation - Send a node information frame. * - Driver::ControllerCommand_ReplicationSend - Send information from primary to secondary * - Driver::ControllerCommand_CreateButton - Create a handheld button id. * - Driver::ControllerCommand_DeleteButton - Delete a handheld button id. *

Callbacks * - Driver::ControllerState_Starting, the controller command has begun * - Driver::ControllerState_Waiting, the controller is waiting for a user action. A notice should be displayed * to the user at this point, telling them what to do next. * For the add, remove, replace and transfer primary role commands, the user needs to be told to press the * inclusion button on the device that is going to be added or removed. For ControllerCommand_ReceiveConfiguration, * they must set their other controller to send its data, and for ControllerCommand_CreateNewPrimary, set the other * controller to learn new data. * - Driver::ControllerState_InProgress - the controller is in the process of adding or removing the chosen node. It is now too late to cancel the command. * - Driver::ControllerState_Complete - the controller has finished adding or removing the node, and the command is complete. * - Driver::ControllerState_Failed - will be sent if the command fails for any reason. * \deprecated This method has been depreciated in favour of the methods in the \ref Network_Commands section (Remove in 1.8) * * \see AddNode RemoveNode RemoveFailedNode HasNodeFailed RequestNodeNeighborUpdate AssignReturnRoute DeleteAllReturnRoutes SendNodeInformation CreateNewPrimary ReceiveConfiguration ReplaceFailedNode TransferPrimaryRole RequestNetworkUpdate ReplicationSend CreateButton DeleteButton * */ DEPRECATED bool BeginControllerCommand(uint32 const _homeId, Driver::ControllerCommand _command, Driver::pfnControllerCallback_t _callback = NULL, void* _context = NULL, bool _highPower = false, uint8 _nodeId = 0xff, uint8 _arg = 0); /** * \brief Cancels any in-progress command running on a controller. * \param _homeId The Home ID of the Z-Wave controller. * \return true if a command was running and was cancelled. * \see BeginControllerCommand */ bool CancelControllerCommand(uint32 const _homeId); /*@}*/ //----------------------------------------------------------------------------- // Network commands //----------------------------------------------------------------------------- /** \name Network Commands * Commands for Z-Wave network for testing, routing and other internal * operations. */ /*@{*/ public: /** * \brief Test network node. * Sends a series of messages to a network node for testing network reliability. * \param _homeId The Home ID of the Z-Wave controller to be reset. * \param _count This is the number of test messages to send. * \see TestNetwork */ void TestNetworkNode(uint32 const _homeId, uint8 const _nodeId, uint32 const _count); /** * \brief Test network. * Sends a series of messages to every node on the network for testing network reliability. * \param _homeId The Home ID of the Z-Wave controller to be reset. * \param _count This is the number of test messages to send. * \see TestNetwork */ void TestNetwork(uint32 const _homeId, uint32 const _count); /** * \brief Heal network node by requesting the node rediscover their neighbors. * Sends a ControllerCommand_RequestNodeNeighborUpdate to the node. * \param _homeId The Home ID of the Z-Wave network to be healed. * \param _nodeId The node to heal. * \param _doRR Whether to perform return routes initialization. */ void HealNetworkNode(uint32 const _homeId, uint8 const _nodeId, bool _doRR); /** * \brief Heal network by requesting node's rediscover their neighbors. * Sends a ControllerCommand_RequestNodeNeighborUpdate to every node. * Can take a while on larger networks. * \param _homeId The Home ID of the Z-Wave network to be healed. * \param _doRR Whether to perform return routes initialization. */ void HealNetwork(uint32 const _homeId, bool _doRR); /** * \brief Start the Inclusion Process to add a Node to the Network. * The Status of the Node Inclusion is communicated via Notifications. Specifically, you should * monitor ControllerCommand Notifications. * * Results of the AddNode Command will be send as a Notification with the Notification type as * Notification::Type_ControllerCommand * * \param _homeId The Home ID of the Z-Wave network where the device should be added. * \param _doSecurity Whether to initialize the Network Key on the device if it supports the Security CC * \return if the Command was sent successfully to the Controller * \sa CancelControllerCommand */ bool AddNode(uint32 const _homeId, bool _doSecurity = true); /** * \brief Remove a Device from the Z-Wave Network * The Status of the Node Removal is communicated via Notifications. Specifically, you should * monitor ControllerCommand Notifications. * * Results of the RemoveNode Command will be send as a Notification with the Notification type as * Notification::Type_ControllerCommand * * \param _homeId The HomeID of the Z-Wave network where you want to remove the device * \return if the Command was send successfully to the Controller * \sa CancelControllerCommand */ bool RemoveNode(uint32 const _homeId); /** * \brief Remove a Failed Device from the Z-Wave Network * This Command will remove a failed node from the network. The Node should be on the Controllers Failed * Node List, otherwise this command will fail. You can use the HasNodeFailed function below to test if the Controller * believes the Node has Failed. * The Status of the Node Removal is communicated via Notifications. Specifically, you should * monitor ControllerCommand Notifications. * * Results of the RemoveFailedNode Command will be send as a Notification with the Notification type as * Notification::Type_ControllerCommand * * \param _homeId The HomeID of the Z-Wave network where you want to remove the device * \param _nodeId The NodeID of the Failed Node. * \return if the Command was send successfully to the Controller * \sa CancelControllerCommand */ bool RemoveFailedNode(uint32 const _homeId, uint8 const _nodeId); /** * \brief Check if the Controller Believes a Node has Failed. * This is different from the IsNodeFailed call in that we test the Controllers Failed Node List, whereas the IsNodeFailed is testing * our list of Failed Nodes, which might be different. * The Results will be communicated via Notifications. Specifically, you should monitor the ControllerCommand notifications * * Results of the HasNodeFailed Command will be send as a Notification with the Notification type as * Notification::Type_ControllerCommand * * \param _homeId The HomeID of the Z-Wave network where you want to test the device * \param _nodeId The NodeID of the Failed Node. * \return if the RemoveDevice Command was send successfully to the Controller * \sa CancelControllerCommand */ bool HasNodeFailed(uint32 const _homeId, uint8 const _nodeId); /** * \brief Ask a Node to update its Neighbor Tables * This command will ask a Node to update its Neighbor Tables. * * Results of the RequestNodeNeighborUpdate Command will be send as a Notification with the Notification type as * Notification::Type_ControllerCommand * * \param _homeId The HomeID of the Z-Wave network where you want to update the device * \param _nodeId The NodeID of the Node. * \return if the Command was send successfully to the Controller * \sa CancelControllerCommand */ bool RequestNodeNeighborUpdate(uint32 const _homeId, uint8 const _nodeId); /** * \brief Ask a Node to update its update its Return Route to the Controller * This command will ask a Node to update its Return Route to the Controller * * Results of the AssignReturnRoute Command will be send as a Notification with the Notification type as * Notification::Type_ControllerCommand * * \param _homeId The HomeID of the Z-Wave network where you want to update the device * \param _nodeId The NodeID of the Node. * \return if the Command was send successfully to the Controller * \sa CancelControllerCommand */ bool AssignReturnRoute(uint32 const _homeId, uint8 const _nodeId); /** * \brief Ask a Node to delete all Return Route. * This command will ask a Node to delete all its return routes, and will rediscover when needed. * * Results of the DeleteAllReturnRoutes Command will be send as a Notification with the Notification type as * Notification::Type_ControllerCommand * * \param _homeId The HomeID of the Z-Wave network where you want to update the device * \param _nodeId The NodeID of the Node. * \return if the Command was send successfully to the Controller * \sa CancelControllerCommand */ bool DeleteAllReturnRoutes(uint32 const _homeId, uint8 const _nodeId); /** * \brief Send a NIF frame from the Controller to a Node. * This command send a NIF frame from the Controller to a Node * * \param _homeId The HomeID of the Z-Wave network * \param _nodeId The NodeID of the Node to receive the NIF * \return if the sendNIF Command was send successfully to the Controller * \sa CancelControllerCommand */ bool SendNodeInformation(uint32 const _homeId, uint8 const _nodeId); /** * \brief Create a new primary controller when old primary fails. Requires SUC. * This command Creates a new Primary Controller when the Old Primary has Failed. Requires a SUC on the network to function * * Results of the CreateNewPrimary Command will be send as a Notification with the Notification type as * Notification::Type_ControllerCommand * * \param _homeId The HomeID of the Z-Wave network * \return if the CreateNewPrimary Command was send successfully to the Controller * \sa CancelControllerCommand */ bool CreateNewPrimary(uint32 const _homeId); /** * \brief Receive network configuration information from primary controller. Requires secondary. * This command prepares the controller to receive Network Configuration from a Secondary Controller. * * Results of the ReceiveConfiguration Command will be send as a Notification with the Notification type as * Notification::Type_ControllerCommand * * \param _homeId The HomeID of the Z-Wave network * \return if the ReceiveConfiguration Command was send successfully to the Controller * \sa CancelControllerCommand */ bool ReceiveConfiguration(uint32 const _homeId); /** * \brief Replace a failed device with another. * If the node is not in the controller's failed nodes list, or the node responds, this command will fail. * You can check if a Node is in the Controllers Failed node list by using the HasNodeFailed method * * Results of the ReplaceFailedNode Command will be send as a Notification with the Notification type as * Notification::Type_ControllerCommand * * \param _homeId The HomeID of the Z-Wave network * \param _nodeId the ID of the Failed Node * \return if the ReplaceFailedNode Command was send successfully to the Controller * \sa HasNodeFailed * \sa CancelControllerCommand */ bool ReplaceFailedNode(uint32 const _homeId, uint8 const _nodeId); /** * \brief Add a new controller to the network and make it the primary. * The existing primary will become a secondary controller. * * Results of the TransferPrimaryRole Command will be send as a Notification with the Notification type as * Notification::Type_ControllerCommand * * \param _homeId The HomeID of the Z-Wave network * \return if the TransferPrimaryRole Command was send successfully to the Controller * \sa CancelControllerCommand */ bool TransferPrimaryRole(uint32 const _homeId); /** * \brief Update the controller with network information from the SUC/SIS. * * Results of the RequestNetworkUpdate Command will be send as a Notification with the Notification type as * Notification::Type_ControllerCommand * * \param _homeId The HomeID of the Z-Wave network * \param _nodeId the ID of the Node * \return if the RequestNetworkUpdate Command was send successfully to the Controller * \sa CancelControllerCommand */ bool RequestNetworkUpdate(uint32 const _homeId, uint8 const _nodeId); /** * \brief Send information from primary to secondary * * Results of the ReplicationSend Command will be send as a Notification with the Notification type as * Notification::Type_ControllerCommand * * \param _homeId The HomeID of the Z-Wave network * \param _nodeId the ID of the Node * \return if the ReplicationSend Command was send successfully to the Controller * \sa CancelControllerCommand */ bool ReplicationSend(uint32 const _homeId, uint8 const _nodeId); /** * \brief Create a handheld button id. * * Only intended for Bridge Firmware Controllers. * * Results of the CreateButton Command will be send as a Notification with the Notification type as * Notification::Type_ControllerCommand * * \param _homeId The HomeID of the Z-Wave network * \param _nodeId the ID of the Virtual Node * \param _buttonId the ID of the Button to create * \return if the CreateButton Command was send successfully to the Controller * \sa CancelControllerCommand */ bool CreateButton(uint32 const _homeId, uint8 const _nodeId, uint8 const _buttonid); /** * \brief Delete a handheld button id. * * Only intended for Bridge Firmware Controllers. * * Results of the DeleteButton Command will be send as a Notification with the Notification type as * Notification::Type_ControllerCommand * * \param _homeId The HomeID of the Z-Wave network * \param _nodeId the ID of the Virtual Node * \param _buttonId the ID of the Button to delete * \return if the DeleteButton Command was send successfully to the Controller * \sa CancelControllerCommand */ bool DeleteButton(uint32 const _homeId, uint8 const _nodeId, uint8 const _buttonid); /** * \brief Send a raw packet to a node. * * Send a Raw Packet to a Node. No confirmation that the node accepted the packet etc will be available. * This is for testing only and should not be used for anything production * * \param _homeId the HomeID of the Z-Wave Network * \param _nodeId the ID of the Node * \param _logText Text to Log when sending the packet * \param _msgType The Type of Message to Send * \param _sendSecure if we should attempt to encrypt the packet * \param _content A array of bytes to send * \param _length the length of the array */ void SendRawData(uint32 const _homeId, uint8 const _nodeId, string const& _logText, uint8 const _msgType, const bool _sendSecure, uint8 const* _content, uint8 const _length); /*@}*/ //----------------------------------------------------------------------------- // Scene commands //----------------------------------------------------------------------------- /** \name Scene Commands * Commands for Z-Wave scene interface. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * */ /*@{*/ public: /** * \brief Gets the number of scenes that have been defined. * \return The number of scenes. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetAllScenes, RemoveAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED uint8 GetNumScenes(); /** * \brief Gets a list of all the SceneIds. * \param _sceneIds is a pointer to an array of integers. * \return The number of scenes. If zero, _sceneIds will be NULL and doesn't need to be freed. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED uint8 GetAllScenes(uint8** _sceneIds); /** * \brief Remove all the SceneIds. * \param _homeId The Home ID of the Z-Wave controller. 0 for all devices from all scenes. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetAllScenes, GetNumScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED void RemoveAllScenes(uint32 const _homeId); /** * \brief Create a new Scene passing in Scene ID * \return uint8 Scene ID used to reference the scene. 0 is failure result. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED uint8 CreateScene(); /** * \brief Remove an existing Scene. * \param _sceneId is an integer representing the unique Scene ID to be removed. * \return true if scene was removed. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool RemoveScene(uint8 const _sceneId); /** * \brief Add a bool Value ID to an existing scene. * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the bool value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool AddSceneValue(uint8 const _sceneId, ValueID const& _valueId, bool const _value); /** * \brief Add a byte Value ID to an existing scene. * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the byte value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool AddSceneValue(uint8 const _sceneId, ValueID const& _valueId, uint8 const _value); /** * \brief Add a decimal Value ID to an existing scene. * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the float value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool AddSceneValue(uint8 const _sceneId, ValueID const& _valueId, float const _value); /** * \brief Add a 32-bit signed integer Value ID to an existing scene. * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the int32 value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool AddSceneValue(uint8 const _sceneId, ValueID const& _valueId, int32 const _value); /** * \brief Add a 16-bit signed integer Value ID to an existing scene. * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the int16 value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool AddSceneValue(uint8 const _sceneId, ValueID const& _valueId, int16 const _value); /** * \brief Add a string Value ID to an existing scene. * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the string value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool AddSceneValue(uint8 const _sceneId, ValueID const& _valueId, string const& _value); /** * \brief Add the selected item list Value ID to an existing scene (as a string). * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the string value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool AddSceneValueListSelection(uint8 const _sceneId, ValueID const& _valueId, string const& _value); /** * \brief Add the selected item list Value ID to an existing scene (as a integer). * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the integer value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool AddSceneValueListSelection(uint8 const _sceneId, ValueID const& _valueId, int32 const _value); /** * \brief Remove the Value ID from an existing scene. * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be removed. * \return true if Value ID was removed. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool RemoveSceneValue(uint8 const _sceneId, ValueID const& _valueId); /** * \brief Retrieves the scene's list of values. * \param _sceneId The Scene ID of the scene to retrieve the value from. * \param o_value Pointer to an array of ValueIDs if return is non-zero. * \return The number of nodes in the o_value array. If zero, the array will point to NULL and does not need to be deleted. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED int SceneGetValues(uint8 const _sceneId, vector* o_value); /** * \brief Retrieves a scene's value as a bool. * \param _sceneId The Scene ID of the scene to retrieve the value from. * \param _valueId The Value ID of the value to retrieve. * \param o_value Pointer to a bool that will be filled with the returned value. * \return true if the value was obtained. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SceneGetValueAsBool(uint8 const _sceneId, ValueID const& _valueId, bool* o_value); /** * \brief Retrieves a scene's value as an 8-bit unsigned integer. * \param _sceneId The Scene ID of the scene to retrieve the value from. * \param _valueId The Value ID of the value to retrieve. * \param o_value Pointer to a uint8 that will be filled with the returned value. * \return true if the value was obtained. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SceneGetValueAsByte(uint8 const _sceneId, ValueID const& _valueId, uint8* o_value); /** * \brief Retrieves a scene's value as a float. * \param _sceneId The Scene ID of the scene to retrieve the value from. * \param _valueId The Value ID of the value to retrieve. * \param o_value Pointer to a float that will be filled with the returned value. * \return true if the value was obtained. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SceneGetValueAsFloat(uint8 const _sceneId, ValueID const& _valueId, float* o_value); /** * \brief Retrieves a scene's value as a 32-bit signed integer. * \param _sceneId The Scene ID of the scene to retrieve the value from. * \param _valueId The Value ID of the value to retrieve. * \param o_value Pointer to a int32 that will be filled with the returned value. * \return true if the value was obtained. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SceneGetValueAsInt(uint8 const _sceneId, ValueID const& _valueId, int32* o_value); /** * \brief Retrieves a scene's value as a 16-bit signed integer. * \param _sceneId The Scene ID of the scene to retrieve the value from. * \param _valueId The Value ID of the value to retrieve. * \param o_value Pointer to a int16 that will be filled with the returned value. * \return true if the value was obtained. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SceneGetValueAsShort(uint8 const _sceneId, ValueID const& _valueId, int16* o_value); /** * \brief Retrieves a scene's value as a string. * \param _sceneId The Scene ID of the scene to retrieve the value from. * \param _valueId The Value ID of the value to retrieve. * \param o_value Pointer to a string that will be filled with the returned value. * \return true if the value was obtained. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SceneGetValueAsString(uint8 const _sceneId, ValueID const& _valueId, string* o_value); /** * \brief Retrieves a scene's value as a list (as a string). * \param _sceneId The Scene ID of the scene to retrieve the value from. * \param _valueId The Value ID of the value to retrieve. * \param o_value Pointer to a string that will be filled with the returned value. * \return true if the value was obtained. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SceneGetValueListSelection(uint8 const _sceneId, ValueID const& _valueId, string* o_value); /** * \brief Retrieves a scene's value as a list (as a integer). * \param _sceneId The Scene ID of the scene to retrieve the value from. * \param _valueId The Value ID of the value to retrieve. * \param o_value Pointer to a integer that will be filled with the returned value. * \return true if the value was obtained. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SceneGetValueListSelection(uint8 const _sceneId, ValueID const& _valueId, int32* o_value); /** * \brief Set a bool Value ID to an existing scene's ValueID * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the bool value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SetSceneValue(uint8 const _sceneId, ValueID const& _valueId, bool const _value); /** * \brief Set a byte Value ID to an existing scene's ValueID * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the byte value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SetSceneValue(uint8 const _sceneId, ValueID const& _valueId, uint8 const _value); /** * \brief Set a decimal Value ID to an existing scene's ValueID * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the float value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SetSceneValue(uint8 const _sceneId, ValueID const& _valueId, float const _value); /** * \brief Set a 32-bit signed integer Value ID to an existing scene's ValueID * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the int32 value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SetSceneValue(uint8 const _sceneId, ValueID const& _valueId, int32 const _value); /** * \brief Set a 16-bit integer Value ID to an existing scene's ValueID * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the int16 value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SetSceneValue(uint8 const _sceneId, ValueID const& _valueId, int16 const _value); /** * \brief Set a string Value ID to an existing scene's ValueID * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the string value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SetSceneValue(uint8 const _sceneId, ValueID const& _valueId, string const& _value); /** * \brief Set the list selected item Value ID to an existing scene's ValueID (as a string). * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the string value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SetSceneValueListSelection(uint8 const _sceneId, ValueID const& _valueId, string const& _value); /** * \brief Set the list selected item Value ID to an existing scene's ValueID (as a integer). * \param _sceneId is an integer representing the unique Scene ID. * \param _valueId is the Value ID to be added. * \param _value is the integer value to be saved. * \return true if Value ID was added. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED bool SetSceneValueListSelection(uint8 const _sceneId, ValueID const& _valueId, int32 const _value); /** * \brief Returns a label for the particular scene. * \param _sceneId The Scene ID * \return The label string. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, SetSceneLabel, SceneExists, ActivateScene */ DEPRECATED string GetSceneLabel(uint8 const _sceneId); /** * \brief Sets a label for the particular scene. * \param _sceneId The Scene ID * \param _value The new value of the label. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SceneExists, ActivateScene */ DEPRECATED void SetSceneLabel(uint8 const _sceneId, string const& _value); /** * \brief Check if a Scene ID is defined. * \param _sceneId The Scene ID. * \return true if Scene ID exists. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, ActivateScene */ DEPRECATED bool SceneExists(uint8 const _sceneId); /** * \brief Activate given scene to perform all its actions. * \param _sceneId The Scene ID. * \return true if it is successful. * \deprecated The Scene Methods have been depreciated. (This is not the same as the CENTRAL_SCENE CommandClass) * \see GetNumScenes, GetAllScenes, CreateScene, RemoveScene, AddSceneValue, RemoveSceneValue, SceneGetValues, SceneGetValueAsBool, SceneGetValueAsByte, SceneGetValueAsFloat, SceneGetValueAsInt, SceneGetValueAsShort, SceneGetValueAsString, SetSceneValue, GetSceneLabel, SetSceneLabel, SceneExists */ DEPRECATED bool ActivateScene(uint8 const _sceneId); /*@}*/ //----------------------------------------------------------------------------- // Statistics interface //----------------------------------------------------------------------------- /** \name Statistics retrieval interface * Commands for Z-Wave statistics interface. */ /*@{*/ public: /** * \brief Retrieve statistics from driver * \param _homeId The Home ID of the driver to obtain counters * \param _data Pointer to structure DriverData to return values */ void GetDriverStatistics(uint32 const _homeId, Driver::DriverData* _data); /** * \brief Retrieve statistics per node * \param _homeId The Home ID of the driver for the node * \param _nodeId The node number * \param _data Pointer to structure NodeData to return values */ void GetNodeStatistics(uint32 const _homeId, uint8 const _nodeId, Node::NodeData* _data); /** * \brief Get a Human Readable String for the RouteScheme in the Extended TX Status Frame * \param _data Pointer to the structure Node::NodeData return from GetNodeStatistics * \return String containing the Route Scheme Used */ static string GetNodeRouteScheme(Node::NodeData *_data); /** * \brief Get Humand Readable String for the RouteSpeed in the Extended TX Status Frame * \param _data Pointer to the structure Node::NodeData returned from GetNodeStatistics * \return String containing the Speed */ static string GetNodeRouteSpeed(Node::NodeData *_data); /*@}*/ //----------------------------------------------------------------------------- // MetaData interface //----------------------------------------------------------------------------- /** \name MetaData Interface * Commands for retrieving information about Devices. */ /*@{*/ public: /** * \brief Retrieve metadata about a node * \param _homeId The Home ID of the driver for the node * \param _nodeId The node number * \param _metadata the MetadataFields you are requesting. * \return a string containing the requested metadata */ string const GetMetaData(uint32 const _homeId, uint8 const _nodeId, Node::MetaDataFields _metadata); /** * \brief Retrieve ChangeLogs about a configuration revision * \param _homeId The Home ID of the driver for the node * \param _nodeId The node number * \param revision the revision you are requesting * \return a Node::ChangeLogEntry struct with the ChangeLog Details. if the revision paramater is -1, then then revision passed to this function is invalid */ Node::ChangeLogEntry const GetChangeLog(uint32 const _homeId, uint8 const _nodeId, uint32_t revision); /*@}*/ //----------------------------------------------------------------------------- // Config File Revision interface //----------------------------------------------------------------------------- /** \name Config File Revision Methods * These commands deal with checking/updating Config File's from the OZW master repository */ /*@{*/ public: /** * \brief Check the Latest Revision of the Config File for this device * * and optionally update the local database with the latest version * Config Revisions are exposed on the ManufacturerSpecific CC. (both the latest and loaded version) * * Outdated Config Revisions are signaled via Notifications * * \param _homeId The Home ID of the driver for the node * \param _nodeId The node number * \return Success/Failure of submitting the request. */ bool checkLatestConfigFileRevision(uint32 const _homeId, uint8 const _nodeId); /** * \brief Check the Latest Revision of the Manufacturer_Specific.xml file * * and optionally update to the latest version. * * Outdated Config Revisions are signaled via Notifications * * \param _homeId The Home ID of the driver for the node * \return Success/Failure of submitting the request. */ bool checkLatestMFSRevision(uint32 const _homeId); /** * \brief Download the latest Config File Revision * * The Node will be reloaded depending upon the Option "ReloadAfterUpdate" * Valid Options include: * * Never - Never Reload a Node after updating the Config File. Manual Reload is Required. * * Immediate - Reload the Node Immediately after downloading the latest revision * * Awake - Reload Nodes only when they are awake (Always-On Nodes will reload immediately, Sleeping Nodes will reload * when they wake up * * Errors are signaled via Notifications * * \param _homeId The Home ID of the driver for the node * \param _nodeId The Node ID of the Node to update the Config File for * \return Success/Failure of submitting the request. */ bool downloadLatestConfigFileRevision(uint32 const _homeId, uint8 const _nodeId); /** * \brief Download the latest Config File Revision * * The ManufacturerSpecific File will be updated, and any new Config Files will also be downloaded. * Existing Config Files will not be checked/updated. * * Errors are signaled via Notifications * * \param _homeId The Home ID of the driver for the node * \return Success/Failure of submitting the request. */ bool downloadLatestMFSRevision(uint32 const _homeId); /*@}*/ }; /*@}*/ } // namespace OpenZWave #endif // _Manager_H openzwave-1.6.1914/cpp/src/CompatOptionManager.cpp0000644000175200017520000007215614032142455016717 00000000000000//----------------------------------------------------------------------------- // // CompatOptionManager.cpp // // Handles Compatibility Flags in Config Files // // Copyright (c) 2019 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClass.h" #include "CompatOptionManager.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { CompatOptionFlagDefintions availableCompatFlags[] = { { "GetSupported", COMPAT_FLAG_GETSUPPORTED, COMPAT_FLAG_TYPE_BOOL }, { "OverridePrecision", COMPAT_FLAG_OVERRIDEPRECISION, COMPAT_FLAG_TYPE_BYTE }, { "ForceVersion", COMPAT_FLAG_FORCEVERSION, COMPAT_FLAG_TYPE_BYTE }, { "CreateVars", COMPAT_FLAG_CREATEVARS, COMPAT_FLAG_TYPE_BOOL }, { "RefreshOnWakeup", COMPAT_FLAG_REFRESHONWAKEUP, COMPAT_FLAG_TYPE_BOOL }, { "IgnoreMapping", COMPAT_FLAG_BASIC_IGNOREREMAPPING, COMPAT_FLAG_TYPE_BOOL }, { "SetAsReport", COMPAT_FLAG_BASIC_SETASREPORT, COMPAT_FLAG_TYPE_BOOL }, { "Mapping", COMPAT_FLAG_BASIC_MAPPING, COMPAT_FLAG_TYPE_BYTE }, { "ColorIndexBug", COMPAT_FLAG_COLOR_IDXBUG, COMPAT_FLAG_TYPE_BOOL }, // Fibaro RGBW before version 25.25 always reported the coloridx as 3 in the Report Message. Work around it { "ForceInstances", COMPAT_FLAG_MCA_FORCEINSTANCES, COMPAT_FLAG_TYPE_BOOL }, { "MapRootToEndpoint", COMPAT_FLAG_MI_MAPROOTTOENDPOINT, COMPAT_FLAG_TYPE_BOOL }, // was mapping in old version. was 0 or false in old version. when mapping=endpoints, thats = true { "ForceUniqueEndpoints", COMPAT_FLAG_MI_FORCEUNIQUEENDPOINTS, COMPAT_FLAG_TYPE_BOOL }, { "IgnoreMCCapReports", COMPAT_FLAG_MI_IGNMCCAPREPORTS, COMPAT_FLAG_TYPE_BOOL }, // was ignoreUnsolicitedMultiChnCapReport { "EndpointHint", COMPAT_FLAG_MI_ENDPOINTHINT, COMPAT_FLAG_TYPE_BYTE }, { "Base", COMPAT_FLAG_TSSP_BASE, COMPAT_FLAG_TYPE_BYTE }, { "AltTypeInterpretation", COMPAT_FLAG_TSSP_ALTTYPEINTERPRETATION, COMPAT_FLAG_TYPE_BOOL }, { "ExposeRawUserCodes", COMPAT_FLAG_UC_EXPOSERAWVALUE, COMPAT_FLAG_TYPE_BOOL }, { "ClassGetVersionSupported", COMPAT_FLAG_VERSION_GETCLASSVERSION, COMPAT_FLAG_TYPE_BOOL }, { "DelayNoMoreInfo", COMPAT_FLAG_WAKEUP_DELAYNMI, COMPAT_FLAG_TYPE_INT }, { "RemoveCC", COMPAT_FLAG_MI_REMOVECC, COMPAT_FLAG_TYPE_BOOL_ARRAY }, { "VerifyChanged", COMPAT_FLAG_VERIFYCHANGED, COMPAT_FLAG_TYPE_BOOL_ARRAY }, { "EnableNotificationClear", COMPAT_FLAG_NOT_ENABLECLEAR, COMPAT_FLAG_TYPE_BOOL }, { "EnableV1AlarmTypes", COMPAT_FLAG_NOT_V1ALARMTYPES_ENABLED, COMPAT_FLAG_TYPE_BOOL }, { "NoRefreshAfterSet", COMPAT_FLAG_NO_REFRESH_AFTER_SET, COMPAT_FLAG_TYPE_BOOL_ARRAY } }; uint16_t availableCompatFlagsCount = sizeof(availableCompatFlags) / sizeof(availableCompatFlags[0]); CompatOptionFlagDefintions availableDiscoveryFlags[] = { { "CCVersion", STATE_FLAG_CCVERSION, COMPAT_FLAG_TYPE_BYTE }, { "StaticRequests", STATE_FLAG_STATIC_REQUESTS, COMPAT_FLAG_TYPE_BYTE }, { "AfterMark", STATE_FLAG_AFTERMARK, COMPAT_FLAG_TYPE_BOOL }, { "Encrypted", STATE_FLAG_ENCRYPTED, COMPAT_FLAG_TYPE_BOOL }, { "InNif", STATE_FLAG_INNIF, COMPAT_FLAG_TYPE_BOOL }, { "SceneCount", STATE_FLAG_CS_SCENECOUNT, COMPAT_FLAG_TYPE_BYTE }, { "ClearTimeout", STATE_FLAG_CS_CLEARTIMEOUT, COMPAT_FLAG_TYPE_INT }, { "ChangeCounter", STATE_FLAG_CCS_CHANGECOUNTER, COMPAT_FLAG_TYPE_BYTE }, { "Channels", STATE_FLAG_COLOR_CHANNELS, COMPAT_FLAG_TYPE_SHORT }, { "TimeOut", STATE_FLAG_DOORLOCK_TIMEOUT, COMPAT_FLAG_TYPE_BYTE }, { "InsideMode", STATE_FLAG_DOORLOCK_INSIDEMODE, COMPAT_FLAG_TYPE_BYTE }, { "OutsideMode", STATE_FLAG_DOORLOCK_OUTSIDEMODE, COMPAT_FLAG_TYPE_BYTE }, { "TimeOutMins", STATE_FLAG_DOORLOCK_TIMEOUTMINS, COMPAT_FLAG_TYPE_BYTE }, { "TImeOutSecs", STATE_FLAG_DOORLOCK_TIMEOUTSECS, COMPAT_FLAG_TYPE_BYTE }, { "MaxRecords", STATE_FLAG_DOORLOCKLOG_MAXRECORDS, COMPAT_FLAG_TYPE_BYTE }, { "Count", STATE_FLAG_USERCODE_COUNT, COMPAT_FLAG_TYPE_BYTE } }; uint16_t availableDiscoveryFlagsCount = sizeof(availableDiscoveryFlags) / sizeof(availableDiscoveryFlags[0]); CompatOptionManager::CompatOptionManager(CompatOptionType type, Internal::CC::CommandClass *owner) : m_owner(owner), m_comtype(type) { switch (m_comtype) { case CompatOptionType_Compatibility: m_availableFlags = availableCompatFlags; m_availableFlagsCount = availableCompatFlagsCount; break; case CompatOptionType_Discovery: m_availableFlags = availableDiscoveryFlags; m_availableFlagsCount = availableDiscoveryFlagsCount; break; } } CompatOptionManager::~CompatOptionManager() { } void CompatOptionManager::EnableFlag(CompatOptionFlags flag, uint32_t defaultval) { for (uint32_t i = 0; i < m_availableFlagsCount; i++) { if (m_availableFlags[i].flag == flag) { m_enabledCompatFlags[m_availableFlags[i].name] = flag; m_CompatVals[flag].type = m_availableFlags[i].type; m_CompatVals[flag].changed = false; switch (m_availableFlags[i].type) { case COMPAT_FLAG_TYPE_BOOL: case COMPAT_FLAG_TYPE_BOOL_ARRAY: if (defaultval > 2) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "EnableFlag: Default Value for %s is not a Bool", m_availableFlags[i].name.c_str()); defaultval = 0; } m_CompatVals[flag].valBool = (defaultval == 0 ? false : true); break; case COMPAT_FLAG_TYPE_BYTE: case COMPAT_FLAG_TYPE_BYTE_ARRAY: if (defaultval > UINT8_MAX) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "EnableFlag: Default Value for %s is larger than a byte", m_availableFlags[i].name.c_str()); defaultval = 0; } m_CompatVals[flag].valByte = defaultval; break; case COMPAT_FLAG_TYPE_SHORT: case COMPAT_FLAG_TYPE_SHORT_ARRAY: if (defaultval > UINT16_MAX) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "EnableFlag: Default Value for %s is larger than a short", m_availableFlags[i].name.c_str()); defaultval = 0; } m_CompatVals[flag].valShort = defaultval; break; case COMPAT_FLAG_TYPE_INT: case COMPAT_FLAG_TYPE_INT_ARRAY: if (defaultval > UINT32_MAX) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "EnableFlag: Default Value for %s is larger than a int", m_availableFlags[i].name.c_str()); defaultval = 0; } m_CompatVals[flag].valInt = defaultval; break; } } } } void CompatOptionManager::ReadXML(TiXmlElement const* _ccElement) { TiXmlElement const *compatElement = _ccElement->FirstChildElement(GetXMLTagName().c_str()); if (compatElement) { map::iterator it; string value; for (it = m_enabledCompatFlags.begin(); it != m_enabledCompatFlags.end(); it++) { TiXmlElement const *valElement = compatElement->FirstChildElement(it->first.c_str()); if (valElement) { value = valElement->GetText(); char* pStopChar; uint32_t val = strtol(value.c_str(), &pStopChar, 10); switch (m_CompatVals[it->second].type) { case COMPAT_FLAG_TYPE_BOOL: if (m_CompatVals[it->second].valBool != !strcmp(value.c_str(), "true")) { m_CompatVals[it->second].valBool = !strcmp(value.c_str(), "true"); m_CompatVals[it->second].changed = true; } break; case COMPAT_FLAG_TYPE_BOOL_ARRAY: { if (m_CompatVals[it->second].valBool != !strcmp(value.c_str(), "true")) { string indexVal = valElement->Attribute("index"); uint32 index = strtol(indexVal.c_str(), &pStopChar, 10); m_CompatVals[it->second].valBoolArray.insert(std::pair(index, !strcmp(value.c_str(), "true"))); m_CompatVals[it->second].changed = true; } break; } case COMPAT_FLAG_TYPE_BYTE: if (val > UINT8_MAX) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "ReadXML: (%s) - Value for %s is larger than a byte", m_owner->GetCommandClassName().c_str(), it->first.c_str()); val = 0; } if (m_CompatVals[it->second].valByte != val) { m_CompatVals[it->second].valByte = val; m_CompatVals[it->second].changed = true; } break; case COMPAT_FLAG_TYPE_BYTE_ARRAY: if (val > UINT8_MAX) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "ReadXML: (%s) - Value for %s is larger than a byte", m_owner->GetCommandClassName().c_str(), it->first.c_str()); val = 0; } if (m_CompatVals[it->second].valByte != val) { string indexVal = valElement->Attribute("index"); uint32 index = strtol(indexVal.c_str(), &pStopChar, 10); m_CompatVals[it->second].valByteArray.insert(std::pair(index, val)); m_CompatVals[it->second].changed = true; } break; case COMPAT_FLAG_TYPE_SHORT: if (val > UINT16_MAX) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "ReadXML: (%s) - Value for %s is larger than a short", m_owner->GetCommandClassName().c_str(), it->first.c_str()); val = 0; } if (m_CompatVals[it->second].valShort != val) { m_CompatVals[it->second].valShort = val; m_CompatVals[it->second].changed = true; } break; case COMPAT_FLAG_TYPE_SHORT_ARRAY: if (val > UINT16_MAX) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "ReadXML: (%s) - Value for %s is larger than a short", m_owner->GetCommandClassName().c_str(), it->first.c_str()); val = 0; } if (m_CompatVals[it->second].valShort != val) { string indexVal = valElement->Attribute("index"); uint32 index = strtol(indexVal.c_str(), &pStopChar, 10); m_CompatVals[it->second].valShortArray.insert(std::pair(index, val)); m_CompatVals[it->second].changed = true; } break; case COMPAT_FLAG_TYPE_INT: if (val > UINT32_MAX) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "ReadXML: (%s) - Value for %s is larger than a int", m_owner->GetCommandClassName().c_str(), it->first.c_str()); val = 0; } if (m_CompatVals[it->second].valInt != val) { m_CompatVals[it->second].valInt = val; m_CompatVals[it->second].changed = true; } break; case COMPAT_FLAG_TYPE_INT_ARRAY: if (val > UINT32_MAX) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "ReadXML: (%s) - Value for %s is larger than a int", m_owner->GetCommandClassName().c_str(), it->first.c_str()); val = 0; } if (m_CompatVals[it->second].valInt != val) { string indexVal = valElement->Attribute("index"); uint32 index = strtol(indexVal.c_str(), &pStopChar, 10); m_CompatVals[it->second].valIntArray.insert(std::pair(index, val)); m_CompatVals[it->second].changed = true; } break; } } } } { map::iterator it; Log::Write(LogLevel_Info, m_owner->GetNodeId(), "(%d - %s) - %s Flags:", m_owner->GetCommandClassId(), m_owner->GetCommandClassName().c_str(), GetXMLTagName().c_str()); for (it = m_enabledCompatFlags.begin(); it != m_enabledCompatFlags.end(); it++) { if (m_CompatVals[it->second].changed) { switch (m_CompatVals[it->second].type) { case COMPAT_FLAG_TYPE_BOOL: Log::Write(LogLevel_Info, m_owner->GetNodeId(), "\t %s: %s", it->first.c_str(), m_CompatVals[it->second].valBool ? "true" : "false"); break; case COMPAT_FLAG_TYPE_BOOL_ARRAY: Log::Write(LogLevel_Info, m_owner->GetNodeId(), "\t %s (Default): %s", it->first.c_str(), m_CompatVals[it->second].valBool ? "true" : "false"); for (std::map::iterator it2 = m_CompatVals[it->second].valBoolArray.begin(); it2 != m_CompatVals[it->second].valBoolArray.end(); it2++) Log::Write(LogLevel_Info, m_owner->GetNodeId(), "\t\t %s - %d: %s", it->first.c_str(), it2->first, it2->second ? "true" : "false"); break; case COMPAT_FLAG_TYPE_BYTE: Log::Write(LogLevel_Info, m_owner->GetNodeId(), "\t %s: %d", it->first.c_str(), m_CompatVals[it->second].valByte); break; case COMPAT_FLAG_TYPE_BYTE_ARRAY: Log::Write(LogLevel_Info, m_owner->GetNodeId(), "\t %s (Default): %d", it->first.c_str(), m_CompatVals[it->second].valByte); for (std::map::iterator it2 = m_CompatVals[it->second].valByteArray.begin(); it2 != m_CompatVals[it->second].valByteArray.end(); it2++) Log::Write(LogLevel_Info, m_owner->GetNodeId(), "\t\t %s - %d: %d", it->first.c_str(), it2->first, it2->second ); break; case COMPAT_FLAG_TYPE_SHORT: Log::Write(LogLevel_Info, m_owner->GetNodeId(), "\t %s: %d", it->first.c_str(), m_CompatVals[it->second].valShort); break; case COMPAT_FLAG_TYPE_SHORT_ARRAY: Log::Write(LogLevel_Info, m_owner->GetNodeId(), "\t %s (Default): %d", it->first.c_str(), m_CompatVals[it->second].valShort); for (std::map::iterator it2 = m_CompatVals[it->second].valShortArray.begin(); it2 != m_CompatVals[it->second].valShortArray.end(); it2++) Log::Write(LogLevel_Info, m_owner->GetNodeId(), "\t\t %s - %d: %d", it->first.c_str(), it2->first, it2->second ); break; case COMPAT_FLAG_TYPE_INT: Log::Write(LogLevel_Info, m_owner->GetNodeId(), "\t %s: %d", it->first.c_str(), m_CompatVals[it->second].valInt); break; case COMPAT_FLAG_TYPE_INT_ARRAY: Log::Write(LogLevel_Info, m_owner->GetNodeId(), "\t %s (Default): %d", it->first.c_str(), m_CompatVals[it->second].valShort); for (std::map::iterator it2 = m_CompatVals[it->second].valIntArray.begin(); it2 != m_CompatVals[it->second].valIntArray.end(); it2++) Log::Write(LogLevel_Info, m_owner->GetNodeId(), "\t\t %s - %d: %d", it->first.c_str(), it2->first, it2->second ); break; } } } } } void CompatOptionManager::WriteXML(TiXmlElement * _ccElement) { TiXmlElement* compatElement = new TiXmlElement(GetXMLTagName().c_str()); map::iterator it; string value; for (it = m_enabledCompatFlags.begin(); it != m_enabledCompatFlags.end(); it++) { if (m_CompatVals[it->second].changed == false) { /* skip writing out default values */ continue; } char str[32]; switch (m_CompatVals[it->second].type) { case COMPAT_FLAG_TYPE_BOOL: { TiXmlElement* valElement = new TiXmlElement(it->first.c_str()); TiXmlText *text = new TiXmlText(m_CompatVals[it->second].valBool == true ? "true" : "false"); valElement->LinkEndChild(text); compatElement->LinkEndChild(valElement); break; } case COMPAT_FLAG_TYPE_BOOL_ARRAY: { for (std::map::iterator it2 = m_CompatVals[it->second].valBoolArray.begin(); it2 != m_CompatVals[it->second].valBoolArray.end(); it2++) { if (it2->second != m_CompatVals[it->second].valBool) { TiXmlElement* valElement = new TiXmlElement(it->first.c_str()); valElement->SetAttribute("index", it2->first); TiXmlText *text = new TiXmlText(it2->second == true ? "true" : "false"); valElement->LinkEndChild(text); compatElement->LinkEndChild(valElement); } } break; } case COMPAT_FLAG_TYPE_BYTE: { snprintf(str, sizeof(str), "%d", m_CompatVals[it->second].valByte); TiXmlElement* valElement = new TiXmlElement(it->first.c_str()); TiXmlText *text = new TiXmlText(str); valElement->LinkEndChild(text); compatElement->LinkEndChild(valElement); break; } case COMPAT_FLAG_TYPE_BYTE_ARRAY: { for (std::map::iterator it2 = m_CompatVals[it->second].valByteArray.begin(); it2 != m_CompatVals[it->second].valByteArray.end(); it2++) { if (it2->second != m_CompatVals[it->second].valByte) { snprintf(str, sizeof(str), "%d", it2->second); TiXmlElement* valElement = new TiXmlElement(it->first.c_str()); valElement->SetAttribute("index", it2->first); TiXmlText *text = new TiXmlText(str); valElement->LinkEndChild(text); compatElement->LinkEndChild(valElement); } } break; } case COMPAT_FLAG_TYPE_SHORT: { snprintf(str, sizeof(str), "%d", m_CompatVals[it->second].valShort); TiXmlElement* valElement = new TiXmlElement(it->first.c_str()); TiXmlText *text = new TiXmlText(str); valElement->LinkEndChild(text); compatElement->LinkEndChild(valElement); break; } case COMPAT_FLAG_TYPE_SHORT_ARRAY: { for (std::map::iterator it2 = m_CompatVals[it->second].valShortArray.begin(); it2 != m_CompatVals[it->second].valShortArray.end(); it2++) { if (it2->second != m_CompatVals[it->second].valShort) { snprintf(str, sizeof(str), "%d", it2->second); TiXmlElement* valElement = new TiXmlElement(it->first.c_str()); valElement->SetAttribute("index", it2->first); TiXmlText *text = new TiXmlText(str); valElement->LinkEndChild(text); compatElement->LinkEndChild(valElement); } } break; } case COMPAT_FLAG_TYPE_INT: { snprintf(str, sizeof(str), "%d", m_CompatVals[it->second].valInt); TiXmlElement* valElement = new TiXmlElement(it->first.c_str()); TiXmlText *text = new TiXmlText(str); valElement->LinkEndChild(text); compatElement->LinkEndChild(valElement); break; } case COMPAT_FLAG_TYPE_INT_ARRAY: { for (std::map::iterator it2 = m_CompatVals[it->second].valIntArray.begin(); it2 != m_CompatVals[it->second].valIntArray.end(); it2++) { if (it2->second != m_CompatVals[it->second].valInt) { snprintf(str, sizeof(str), "%d", it2->second); TiXmlElement* valElement = new TiXmlElement(it->first.c_str()); valElement->SetAttribute("index", it2->first); TiXmlText *text = new TiXmlText(str); valElement->LinkEndChild(text); compatElement->LinkEndChild(valElement); } } break; } } } _ccElement->LinkEndChild(compatElement); } bool CompatOptionManager::GetFlagBool(CompatOptionFlags const flag, uint32_t index) const { if (m_CompatVals.count(flag) == 0) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "GetFlagBool: (%s) - Flag %s Not Enabled!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return false; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_BOOL) { return m_CompatVals.at(flag).valBool; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_BOOL_ARRAY) { if (index == (uint32_t)-1) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "GetFlagBool: (%s) - Flag %s had Invalid Index", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return m_CompatVals.at(flag).valBool; } if (m_CompatVals.at(flag).valBoolArray.count(index)) return m_CompatVals.at(flag).valBoolArray.at(index); /* Return our Default */ return m_CompatVals.at(flag).valBool; } Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "GetFlagBool: (%s) - Flag %s Not a Boolean Value!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return false; } uint8_t CompatOptionManager::GetFlagByte(CompatOptionFlags flag, uint32_t index) const { if (m_CompatVals.count(flag) == 0) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "GetFlagByte: (%s) - Flag %s Not Enabled!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return 0; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_BYTE) { return m_CompatVals.at(flag).valByte; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_BYTE_ARRAY) { if (index == (uint32_t)-1) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "GetFlagByte: (%s) - Flag %s had Invalid Index", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return m_CompatVals.at(flag).valByte; } if (m_CompatVals.at(flag).valByteArray.count(index)) return m_CompatVals.at(flag).valByteArray.at(index); /* Return our Default */ return m_CompatVals.at(flag).valByte; } Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "GetFlagByte: (%s) - Flag %s Not a Byte Value!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return 0; } uint16_t CompatOptionManager::GetFlagShort(CompatOptionFlags flag, uint32_t index) const { if (m_CompatVals.count(flag) == 0) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "GetFlagShort: (%s) - Flag %s Not Enabled!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return 0; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_SHORT) { return m_CompatVals.at(flag).valShort; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_SHORT_ARRAY) { if (index == (uint32_t)-1) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "GetFlagShort: (%s) - Flag %s had Invalid Index", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return m_CompatVals.at(flag).valShort; } if (m_CompatVals.at(flag).valShortArray.count(index)) return m_CompatVals.at(flag).valShortArray.at(index); /* Return our Default */ return m_CompatVals.at(flag).valShort; } Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "GetFlagShort: (%s) - Flag %s Not a Short Value!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return 0; } uint32_t CompatOptionManager::GetFlagInt(CompatOptionFlags flag, uint32_t index) const { if (m_CompatVals.count(flag) == 0) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "GetFlagInt: (%s) - Flag %s Not Enabled!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return 0; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_INT) { return m_CompatVals.at(flag).valInt; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_INT_ARRAY) { if (index == (uint32_t)-1) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "GetFlagInt: (%s) - Flag %s had Invalid Index", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return m_CompatVals.at(flag).valInt; } if (m_CompatVals.at(flag).valIntArray.count(index)) return m_CompatVals.at(flag).valIntArray.at(index); /* Return our Default */ return m_CompatVals.at(flag).valInt; } Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "GetFlagInt: (%s) - Flag %s Not a Int Value!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return 0; } bool CompatOptionManager::SetFlagBool(CompatOptionFlags flag, bool value, uint32_t index) { if (m_CompatVals.count(flag) == 0) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "SetFlagBool: (%s) - Flag %s Not Enabled!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return false; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_BOOL) { m_CompatVals.at(flag).valBool = value; m_CompatVals.at(flag).changed = true; return true; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_BOOL_ARRAY) { if (index == (uint32_t)-1) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "SetFlagBool: (%s) - Flag %s had Invalid Index", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return false; } m_CompatVals.at(flag).changed = true; if (m_CompatVals.at(flag).valBoolArray.count(index)) { m_CompatVals.at(flag).valBoolArray.at(index) = value; return true; } else { m_CompatVals.at(flag).valBoolArray.insert(std::pair(index, value)); return true; } } Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "SetFlagBool: (%s) - Flag %s Not a Bool Value!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return false; } bool CompatOptionManager::SetFlagByte(CompatOptionFlags flag, uint8_t value, uint32_t index) { if (m_CompatVals.count(flag) == 0) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "SetFlagByte: (%s) - Flag %s Not Enabled!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return false; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_BYTE) { m_CompatVals.at(flag).valByte = value; m_CompatVals.at(flag).changed = true; return true; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_BYTE_ARRAY) { if (index == (uint32_t)-1) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "SetFlagByte: (%s) - Flag %s had Invalid Index", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return false; } m_CompatVals.at(flag).changed = true; if (m_CompatVals.at(flag).valByteArray.count(index)) { m_CompatVals.at(flag).valByteArray.at(index) = value; return true; } else { m_CompatVals.at(flag).valByteArray.insert(std::pair(index, value)); return true; } } Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "SetFlagByte: (%s) - Flag %s Not a Byte Value!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return false; } bool CompatOptionManager::SetFlagShort(CompatOptionFlags flag, uint16_t value, uint32_t index) { if (m_CompatVals.count(flag) == 0) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "SetFlagShort: (%s) - Flag %s Not Enabled!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return false; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_SHORT) { m_CompatVals.at(flag).valShort = value; m_CompatVals.at(flag).changed = true; return true; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_SHORT_ARRAY) { if (index == (uint32_t)-1) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "SetFlagShort: (%s) - Flag %s had Invalid Index", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return false; } m_CompatVals.at(flag).changed = true; if (m_CompatVals.at(flag).valShortArray.count(index)) { m_CompatVals.at(flag).valShortArray.at(index) = value; return true; } else { m_CompatVals.at(flag).valShortArray.insert(std::pair(index, value)); return true; } } Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "SetFlagShort: (%s) - Flag %s Not a Short Value!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return false; } bool CompatOptionManager::SetFlagInt(CompatOptionFlags flag, uint32_t value, uint32_t index) { if (m_CompatVals.count(flag) == 0) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "SetFlagInt: (%s) - Flag %s Not Enabled!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return false; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_INT) { m_CompatVals.at(flag).valInt = value; m_CompatVals.at(flag).changed = true; return true; } if (m_CompatVals.at(flag).type == COMPAT_FLAG_TYPE_INT_ARRAY) { if (index == (uint32_t)-1) { Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "SetFlagInt: (%s) - Flag %s had Invalid Index", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return false; } m_CompatVals.at(flag).changed = true; if (m_CompatVals.at(flag).valIntArray.count(index)) { m_CompatVals.at(flag).valIntArray.at(index) = value; return true; } else { m_CompatVals.at(flag).valIntArray.insert(std::pair(index, value)); return true; } } Log::Write(LogLevel_Warning, m_owner->GetNodeId(), "SetFlagInt: (%s) - Flag %s Not a Int Value!", m_owner->GetCommandClassName().c_str(), GetFlagName(flag).c_str()); return false; } string CompatOptionManager::GetFlagName(CompatOptionFlags flag) const { for (uint32_t i = 0; i < m_availableFlagsCount; i++) { if (m_availableFlags[i].flag == flag) { return m_availableFlags[i].name; } } return "Unknown"; } string CompatOptionManager::GetXMLTagName() { switch (m_comtype) { case CompatOptionType_Compatibility: return "Compatibility"; case CompatOptionType_Discovery: return "State"; } assert(0); return "Unknown"; } } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/0000777000175200017520000000000014032143201015476 500000000000000openzwave-1.6.1914/cpp/src/command_classes/SceneActivation.h0000644000175200017520000000577514032142455020672 00000000000000//----------------------------------------------------------------------------- // // SceneActivation.h // // Implementation of the Z-Wave COMMAND_CLASS_SCENE_ACTIVATION // // Copyright (c) 2012 Greg Satz // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _SceneActivation_H #define _SceneActivation_H #include "command_classes/CommandClass.h" #include "TimerThread.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_SCENEACTIVATION (0x2B), a Z-Wave device command class. * \ingroup CommandClass */ class SceneActivation: public CommandClass, private Timer { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new SceneActivation(_homeId, _nodeId); } virtual ~SceneActivation() { } /** \brief Get command class ID (1 byte) identifying this command class. */ static uint8 const StaticGetCommandClassId() { return 0x2B; } /** \brief Get a string containing the name of this command class. */ static string const StaticGetCommandClassName() { return "COMMAND_CLASS_SCENE_ACTIVATION"; } // From CommandClass /** \brief Get command class ID (1 byte) identifying this command class. (Inherited from CommandClass) */ virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } /** \brief Get a string containing the name of this command class. (Inherited from CommandClass) */ virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } /** \brief Handle a response to a message associated with this command class. (Inherited from CommandClass) */ virtual bool HandleIncomingMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; protected: virtual void CreateVars(uint8 const _instance) override; private: void ClearScene(uint32 id); SceneActivation(uint32 const _homeId, uint8 const _nodeId); }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Security.h0000644000175200017520000000646014032142455017412 00000000000000//----------------------------------------------------------------------------- // // Security.h // // Implementation of the Z-Wave COMMAND_CLASS_Security // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Security_H #define _Security_H #include #include "aes/aescpp.h" #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { enum SecurityCmd { SecurityCmd_SupportedGet = 0x02, SecurityCmd_SupportedReport = 0x03, SecurityCmd_SchemeGet = 0x04, SecurityCmd_SchemeReport = 0x05, SecurityCmd_NetworkKeySet = 0x06, SecurityCmd_NetworkKeyVerify = 0x07, SecurityCmd_SchemeInherit = 0x08, SecurityCmd_NonceGet = 0x40, SecurityCmd_NonceReport = 0x80, SecurityCmd_MessageEncap = 0x81, SecurityCmd_MessageEncapNonceGet = 0xc1 }; enum SecurityScheme { SecurityScheme_Zero = 0x00, }; /** \brief Implements COMMAND_CLASS_SECURITY (0x98), a Z-Wave device command class. * \ingroup CommandClass */ class Security: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Security(_homeId, _nodeId); } virtual ~Security(); static uint8 const StaticGetCommandClassId() { return 0x98; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_SECURITY"; } bool Init(uint32 const _instance = 1); bool ExchangeNetworkKeys(); // From CommandClass bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; void SendMsg(Msg* _msg); protected: void CreateVars(uint8 const _instance) override; private: Security(uint32 const _homeId, uint8 const _nodeId); bool HandleSupportedReport(uint8 const* _data, uint32 const _length, uint32 const _instance = 1); bool m_schemeagreed; bool m_secured[255]; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Security.cpp0000644000175200017520000002467614032142455017756 00000000000000//----------------------------------------------------------------------------- // // Security.cpp // // Implementation of the Z-Wave COMMAND_CLASS_Security // // Copyright (c) 2011 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "command_classes/CommandClasses.h" #include "command_classes/Security.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "Utils.h" #include "value_classes/ValueBool.h" namespace OpenZWave { namespace Internal { namespace CC { Security::Security(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_schemeagreed(false) { /* We don't want the Driver to route "Security" messages back to us for Encryption, * so disable SecureSupport for the Security Command Class * (This stops this Command Class getting Marked as as IsSecured() if its listed * in the SecurityCmd_SupportedReport from the device - Which some devices do) */ ClearSecureSupport(); for (int i = 0; i < 255; i++) m_secured[i] = false; } Security::~Security() { } bool Security::Init(uint32 const _instance) { Msg* msg = new Msg("SecurityCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SecurityCmd_SupportedGet); msg->Append(GetDriver()->GetTransmitOptions()); msg->setEncrypted(); GetDriver()->SendMsg(msg, Driver::MsgQueue_Command); return true; } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Security::ExchangeNetworkKeys() { if (GetNodeUnsafe()->IsAddingNode()) { Msg * msg = new Msg("SecurityCmd_SchemeGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(SecurityCmd_SchemeGet); msg->Append(0); msg->Append(GetDriver()->GetTransmitOptions()); /* SchemeGet is unencrypted */ GetDriver()->SendMsg(msg, Driver::MsgQueue_Command); return true; } return false; } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Security::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { #if 0 if( _requestFlags & RequestFlag_Static ) { } return false; #endif return true; } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Security::RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) { Log::Write(LogLevel_Info, GetNodeId(), "Got a RequestValue Call"); return true; } bool Security::HandleSupportedReport(uint8 const* _data, uint32 const _length, uint32 const _instance) { #ifdef DEBUG PrintHex("Security Classes", _data, _length); #endif GetNodeUnsafe()->SetSecuredClasses(_data, _length, _instance); return true; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Security::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { switch ((SecurityCmd) _data[0]) { case SecurityCmd_SupportedReport: { /* this is a list of CommandClasses that should be Encrypted. * and it might contain new command classes that were not present in the NodeInfoFrame * so we have to run through, mark existing Command Classes as SetSecured (so SendMsg in the Driver * class will route the unecrypted messages to our SendMsg) and for New Command * Classes, create them, and of course, also do a SetSecured on them. * * This means we must do a SecurityCmd_SupportedGet request ASAP so we dont have * Command Classes created after the Discovery Phase is completed! */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_SupportedReport from node %d (instance %d)", GetNodeId(), _instance); m_secured[_instance] = true; if (Internal::VC::ValueBool* value = static_cast(GetValue(_instance, ValueID_Index_Security::Secured))) { value->OnValueRefreshed(m_secured[_instance]); value->Release(); } HandleSupportedReport(&_data[2], _length - 3, _instance); break; } case SecurityCmd_SchemeReport: { Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_SchemeReport from node %d: %d", GetNodeId(), _data[1]); uint8 schemes = _data[1]; if (m_schemeagreed == true) { Log::Write(LogLevel_Warning, GetNodeId(), " Already Received a SecurityCmd_SchemeReport from the node. Ignoring"); break; } if (schemes == SecurityScheme_Zero) { /* We're good to go. We now should send our NetworkKey to the device if this is the first * time we have seen it */ Log::Write(LogLevel_Info, GetNodeId(), " Security scheme agreed."); /* create the NetworkKey Packet. EncryptMessage will encrypt it for us (And request the NONCE) */ Msg * msg = new Msg("SecurityCmd_NetworkKeySet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(18); msg->Append(GetCommandClassId()); msg->Append(SecurityCmd_NetworkKeySet); for (int i = 0; i < 16; i++) msg->Append(GetDriver()->GetNetworkKey()[i]); msg->Append(GetDriver()->GetTransmitOptions()); msg->setEncrypted(); GetDriver()->SendMsg(msg, Driver::MsgQueue_Command); m_schemeagreed = true; } else { /* No common security scheme. The device should continue as an unsecured node. * but Some Command Classes might not be present... */ Log::Write(LogLevel_Warning, GetNodeId(), " No common security scheme. The device will continue as an unsecured node."); } break; } case SecurityCmd_NetworkKeySet: { /* we shouldn't get a NetworkKeySet from a node if we are the controller * as we send it out to the Devices */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_NetworkKeySet from node %d", GetNodeId()); break; } case SecurityCmd_NetworkKeyVerify: { /* if we can decrypt this packet, then we are assured that our NetworkKeySet is successfull * and thus should set the Flag referenced in SecurityCmd_SchemeReport */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_NetworkKeyVerify from node %d", GetNodeId()); /* now as for our SupportedGet */ Msg* msg = new Msg("SecurityCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SecurityCmd_SupportedGet); msg->Append(GetDriver()->GetTransmitOptions()); msg->setEncrypted(); GetDriver()->SendMsg(msg, Driver::MsgQueue_Command); break; } case SecurityCmd_SchemeInherit: { /* only used in a Controller Replication Type enviroment. * */ Log::Write(LogLevel_Info, GetNodeId(), "Received SecurityCmd_SchemeInherit from node %d", GetNodeId()); break; } /* the rest of these should be handled by the Driver Code (in Driver::ProcessMsg) */ case SecurityCmd_NonceGet: case SecurityCmd_NonceReport: case SecurityCmd_MessageEncap: case SecurityCmd_MessageEncapNonceGet: { Log::Write(LogLevel_Warning, GetNodeId(), "Received a Security Message that should have been handled in the Driver"); break; } default: { return false; } } return true; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void Security::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueBool(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_Security::Secured, "Secured", "", true, false, false, 0); if (Internal::VC::ValueBool* value = static_cast(GetValue(_instance, ValueID_Index_Security::Secured))) { value->OnValueRefreshed(m_secured[_instance]); value->Release(); } } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Basic.h0000644000175200017520000000616114032142455016622 00000000000000//----------------------------------------------------------------------------- // // Basic.h // // Implementation of the Z-Wave COMMAND_CLASS_BASIC // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Basic_H #define _Basic_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_BASIC (0x20), a Z-Wave device command class. * \ingroup CommandClass */ class Basic: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Basic(_homeId, _nodeId); } virtual ~Basic() { } static uint8 const StaticGetCommandClassId() { return 0x20; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_BASIC"; } bool SetMapping(uint8 const _commandClassId); // Map COMMAND_CLASS_BASIC messages to another command class uint8_t GetMapping() { return m_com.GetFlagByte(COMPAT_FLAG_BASIC_MAPPING); } ; // From CommandClass virtual void ReadXML(TiXmlElement const* _ccElement) override; virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool HandleIncomingMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; void Set(uint8 const _level); virtual uint8 GetMaxVersion() override { return 2; } protected: virtual void CreateVars(uint8 const _instance) override; private: Basic(uint32 const _homeId, uint8 const _nodeId); std::vector m_instances; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/ThermostatSetpoint.cpp0000644000175200017520000002752214032142455022020 00000000000000//----------------------------------------------------------------------------- // // ThermostatSetpoint.cpp // // Implementation of the Z-Wave COMMAND_CLASS_THERMOSTAT_SETPOINT // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/ThermostatSetpoint.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueDecimal.h" #include "tinyxml.h" namespace OpenZWave { namespace Internal { namespace CC { enum ThermostatSetpointCmd { ThermostatSetpointCmd_Set = 0x01, ThermostatSetpointCmd_Get = 0x02, ThermostatSetpointCmd_Report = 0x03, ThermostatSetpointCmd_SupportedGet = 0x04, ThermostatSetpointCmd_SupportedReport = 0x05, ThermostatSetpointCmd_CapabilitiesGet = 0x09, ThermostatSetpointCmd_CapabilitiesReport = 0x0A }; #define ThermostatSetpoint_Count (ValueID_Index_ThermostatSetpoint::CoolingHeating + 1) static char const* c_setpointName[] = { "Unused 0", "Heating 1", "Cooling 1", "Unused 3", "Unused 4", "Unused 5", "Unused 6", "Furnace", "Dry Air", "Moist Air", "Auto Changeover", "Heating Econ", "Cooling Econ", "Away Heating", "Away Cooling", "Full Power" }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ThermostatSetpoint::ThermostatSetpoint(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { m_com.EnableFlag(COMPAT_FLAG_TSSP_BASE, 1); m_com.EnableFlag(COMPAT_FLAG_TSSP_ALTTYPEINTERPRETATION, true); SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Get the static thermostat setpoint details from the device //----------------------------------------------------------------------------- bool ThermostatSetpoint::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool requests = false; if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { requests |= RequestValue(_requestFlags, 0xff, _instance, _queue); } if (_requestFlags & RequestFlag_Session) { for (uint8 i = 0; i < ThermostatSetpoint_Count; ++i) { requests |= RequestValue(_requestFlags, i, _instance, _queue); } } return requests; } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool ThermostatSetpoint::RequestValue(uint32 const _requestFlags, uint16 const _setPointIndex, uint8 const _instance, Driver::MsgQueue const _queue) { if (_setPointIndex == 0xff) // check for supportedget { // Request the supported setpoints Msg* msg = new Msg("ThermostatSetpointCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(ThermostatSetpointCmd_SupportedGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } if (!m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Log::Write(LogLevel_Info, GetNodeId(), "ThermostatSetpointCmd_Get Not Supported on this node"); return false; } Internal::VC::Value* value = GetValue(1, _setPointIndex); if (value != NULL) { value->Release(); // Request the setpoint value Msg* msg = new Msg("ThermostatSetpointCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(ThermostatSetpointCmd_Get); msg->Append((_setPointIndex & 0xFF)); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool ThermostatSetpoint::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (ThermostatSetpointCmd_Report == (ThermostatSetpointCmd) _data[0]) { // We have received a thermostat setpoint value from the Z-Wave device if (Internal::VC::ValueDecimal* value = static_cast(GetValue(_instance, _data[1]))) { uint8 scale; uint8 precision = 0; string temperature = ExtractValue(&_data[2], &scale, &precision); value->SetUnits(scale ? "F" : "C"); value->OnValueRefreshed(temperature); if (value->GetPrecision() != precision) { value->SetPrecision(precision); } value->Release(); Log::Write(LogLevel_Info, GetNodeId(), "Received thermostat setpoint report: Setpoint %s = %s%s", value->GetLabel().c_str(), value->GetValue().c_str(), value->GetUnits().c_str()); } return true; } else if (ThermostatSetpointCmd_SupportedReport == (ThermostatSetpointCmd) _data[0]) { if (Node* node = GetNodeUnsafe()) { // We have received the supported thermostat setpoints from the Z-Wave device Log::Write(LogLevel_Info, GetNodeId(), "Received supported thermostat setpoints"); // Parse the data for the supported setpoints for (uint32 i = 1; i < _length - 1; ++i) { for (int32 bit = 0; bit < 8; ++bit) { if ((_data[i] & (1 << bit)) != 0) { if (GetVersion() >= 3) { // Request the supported setpoints Msg* msg = new Msg("ThermostatSetpointCmd_CapabilitesGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(ThermostatSetpointCmd_CapabilitiesGet); uint8 type = ((i - 1) << 3) + bit; if (m_com.GetFlagBool(COMPAT_FLAG_TSSP_ALTTYPEINTERPRETATION) == false) { // for interpretation A the setpoint identifier makes a jump of 4 after the 2nd bit ... wtf @ zensys if (type > 2) { type += 4; } } msg->Append(type); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, OpenZWave::Driver::MsgQueue_Query); } uint8 type = ((i - 1) << 3) + bit; if (m_com.GetFlagBool(COMPAT_FLAG_TSSP_ALTTYPEINTERPRETATION) == false) { // for interpretation A the setpoint identifier makes a jump of 4 after the 2nd bit ... wtf @ zensys if (type > 2) { type += 4; } } int32 index = (int32) type + m_com.GetFlagByte(COMPAT_FLAG_TSSP_BASE); // Add supported setpoint if (index < ThermostatSetpoint_Count) { string setpointName = c_setpointName[index]; node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, index, setpointName, "C", false, false, "0.0", 0); Log::Write(LogLevel_Info, GetNodeId(), " Added setpoint: %s", setpointName.c_str()); } } } } } ClearStaticRequest(StaticRequest_Values); return true; } else if (ThermostatSetpointCmd_CapabilitiesReport == (ThermostatSetpointCmd) _data[0]) { if (Node* node = GetNodeUnsafe()) { // We have received the capabilities for supported setpoint Type uint8 scale; uint8 precision = 0; uint8 size = _data[2] & 0x07; string minValue = ExtractValue(&_data[2], &scale, &precision); string maxValue = ExtractValue(&_data[2 + size + 1], &scale, &precision); Log::Write(LogLevel_Info, GetNodeId(), "Received capabilities of thermostat setpoint type %d, min %s max %s", (int) _data[1], minValue.c_str(), maxValue.c_str()); uint8 index = _data[1]; // Add supported setpoint if (index < ThermostatSetpoint_Count) { string setpointName = c_setpointName[index]; node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ThermostatSetpoint::Unused_0_Minimum + index, setpointName + "_minimum", "C", false, false, minValue, 0); node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ThermostatSetpoint::Unused_0_Maximum + index, setpointName + "_maximum", "C", false, false, maxValue, 0); Log::Write(LogLevel_Info, GetNodeId(), " Added setpoint: %s", setpointName.c_str()); } } } return false; } //----------------------------------------------------------------------------- // // Set a thermostat setpoint temperature //----------------------------------------------------------------------------- bool ThermostatSetpoint::SetValue(Internal::VC::Value const& _value) { if (ValueID::ValueType_Decimal == _value.GetID().GetType()) { Internal::VC::ValueDecimal const* value = static_cast(&_value); uint8 scale = strcmp("C", value->GetUnits().c_str()) ? 1 : 0; Msg* msg = new Msg("ThermostatSetpointCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(4 + GetAppendValueSize(value->GetValue())); msg->Append(GetCommandClassId()); msg->Append(ThermostatSetpointCmd_Set); msg->Append((uint8_t) (value->GetID().GetIndex() & 0xFF)); AppendValue(msg, value->GetValue(), scale); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void ThermostatSetpoint::CreateVars(uint8 const _instance) { #if 0 /* I don't think this was ever orignally called when we had a index param, so lets not create this strange SetPoint */ #issue #1981 if (Node* node = GetNodeUnsafe()) { node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, _index, "Setpoint", "C", false, false, "0.0", 0); } #endif } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Clock.h0000644000175200017520000000520114032142455016626 00000000000000//----------------------------------------------------------------------------- // // Clock.h // // Implementation of the Z-Wave COMMAND_CLASS_CLOCK // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Clock_H #define _Clock_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_CLOCK (0x81), a Z-Wave device command class. * \ingroup CommandClass */ class Clock: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Clock(_homeId, _nodeId); } virtual ~Clock() { } static uint8 const StaticGetCommandClassId() { return 0x81; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_CLOCK"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: Clock(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Hail.h0000644000175200017520000000432614032142455016457 00000000000000//----------------------------------------------------------------------------- // // Hail.h // // Implementation of the Z-Wave COMMAND_CLASS_HAIL // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Hail_H #define _Hail_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_HAIL (0x82), a Z-Wave device command class. * \ingroup CommandClass */ class Hail: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Hail(_homeId, _nodeId); } virtual ~Hail() { } static uint8 const StaticGetCommandClassId() { return 0x82; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_HAIL"; } // From CommandClass virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; private: Hail(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/NodeNaming.h0000644000175200017520000000623014032142455017615 00000000000000//----------------------------------------------------------------------------- // // NodeNaming.h // // Implementation of the Z-Wave COMMAND_CLASS_NODE_NAMING // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _NodeNaming_H #define _NodeNaming_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Extract a String from a Z-Wave Encoded Packet * \ingroup CommandClass * * this function is used by the NodeNaming CC as well as the Alarm CC */ string ExtractString(uint8 const* _data, uint32 const _length); /** \brief Convert from UTF16 to UTF8 * \ingroup CommandClass * * this function is used by the NodeNaming CC as well as the Alarm CC */ uint32 ConvertUFT16ToUTF8(uint16 _utf16, char* _buffer, uint32 pos); /** \brief Implements COMMAND_CLASS_NODE_NAMING (0x77), a Z-Wave device command class. * \ingroup CommandClass */ class NodeNaming: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new NodeNaming(_homeId, _nodeId); } virtual ~NodeNaming() { } static uint8 const StaticGetCommandClassId() { return 0x77; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_NODE_NAMING"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; void SetName(string const& _name); void SetLocation(string const& _location); bool supportsMultiInstance() override { return false; } private: NodeNaming(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/ZWavePlusInfo.cpp0000644000175200017520000001410414032142455020644 00000000000000//----------------------------------------------------------------------------- // // ZWavePlusInfo.cpp // // Implementation of the Z-Wave COMMAND_CLASS_ZWAVEPLUS_INFO // // Copyright (c) 2015 // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/ZWavePlusInfo.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueShort.h" #include "value_classes/ValueList.h" namespace OpenZWave { namespace Internal { namespace CC { enum ZWavePlusInfoCmdEnum { ZWavePlusInfoCmd_Get = 0x01, ZWavePlusInfoCmd_Report }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ZWavePlusInfo::ZWavePlusInfo(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool ZWavePlusInfo::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Static) { return RequestValue(_requestFlags, 0, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool ZWavePlusInfo::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("ZWavePlusInfoCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(ZWavePlusInfoCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "ZWavePlusInfoCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool ZWavePlusInfo::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (ZWavePlusInfoCmd_Report == _data[0]) { uint8 version = _data[1]; uint8 role = _data[2]; uint8 nodeType = _data[3]; uint16 installerIcon = (_data[4] << 8) | _data[5]; uint16 deviceType = (_data[6] << 8) | _data[7]; Log::Write(LogLevel_Info, GetNodeId(), "ZW+ Info - Version %d, Role %d, NodeType %d, InstallerIcon %d, deviceType %d", version, role, nodeType, installerIcon, deviceType); /* Only set the role, NodeType and DeviceType on Instance 1 Reports. The other instances * Just have unique Icons for each endpoint */ if (_instance == 1) { if (Node* node = GetNodeUnsafe()) { node->SetPlusDeviceClasses(role, nodeType, deviceType); } // ClearStaticRequest( StaticRequest_Values ); } Internal::VC::ValueByte* value; if ((value = static_cast(GetValue(_instance, ValueID_Index_ZWavePlusInfo::Version)))) { value->OnValueRefreshed(version); value->Release(); } Internal::VC::ValueShort* svalue; if ((svalue = static_cast(GetValue(_instance, ValueID_Index_ZWavePlusInfo::InstallerIcon)))) { svalue->OnValueRefreshed(installerIcon); svalue->Release(); } if ((svalue = static_cast(GetValue(_instance, ValueID_Index_ZWavePlusInfo::UserIcon)))) { svalue->OnValueRefreshed(deviceType); svalue->Release(); } return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void ZWavePlusInfo::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueByte(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_ZWavePlusInfo::Version, "ZWave+ Version", "", true, false, 0, 0); node->CreateValueShort(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_ZWavePlusInfo::InstallerIcon, "InstallerIcon", "", true, false, 0, 0); node->CreateValueShort(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_ZWavePlusInfo::UserIcon, "UserIcon", "", true, false, 0, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/DoorLockLogging.cpp0000644000175200017520000002735714032142455021171 00000000000000//----------------------------------------------------------------------------- // // DoorLockLogging.cpp // // Implementation of the Z-Wave COMMAND_CLASS_DOOR_LOCK_LOGGING // // Copyright (c) 2014 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/DoorLockLogging.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueBool.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueInt.h" #include "value_classes/ValueString.h" #include "tinyxml.h" namespace OpenZWave { namespace Internal { namespace CC { enum DoorLockLoggingCmd { DoorLockLoggingCmd_RecordSupported_Get = 0x01, DoorLockLoggingCmd_RecordSupported_Report = 0x02, DoorLockLoggingCmd_Record_Get = 0x03, DoorLockLoggingCmd_Record_Report = 0x04 }; enum DoorLockEventType { DoorLockEventType_LockCode = 0x01, DoorLockEventType_UnLockCode = 0x02, DoorLockEventType_LockButton = 0x03, DoorLockEventType_UnLockButton = 0x04, DoorLockEventType_LockCodeOOSchedule = 0x05, DoorLockEventType_UnLockCodeOOSchedule = 0x06, DoorLockEventType_IllegalCode = 0x07, DoorLockEventType_LockManual = 0x08, DoorLockEventType_UnLockManual = 0x09, DoorLockEventType_LockAuto = 0x0A, DoorLockEventType_UnLockAuto = 0x0B, DoorLockEventType_LockRemoteCode = 0x0C, DoorLockEventType_UnLockRemoteCode = 0x0D, DoorLockEventType_LockRemote = 0x0E, DoorLockEventType_UnLockRemote = 0x0F, DoorLockEventType_LockRemoteCodeOOSchedule = 0x10, DoorLockEventType_UnLockRemoteCodeOOSchedule = 0x11, DoorLockEventType_RemoteIllegalCode = 0x12, DoorLockEventType_LockManual2 = 0x13, DoorLockEventType_UnlockManual2 = 0x14, DoorLockEventType_LockSecured = 0x15, DoorLockEventType_LockUnsecured = 0x16, DoorLockEventType_UserCodeAdded = 0x17, DoorLockEventType_UserCodeDeleted = 0x18, DoorLockEventType_AllUserCodesDeleted = 0x19, DoorLockEventType_MasterCodeChanged = 0x1A, DoorLockEventType_UserCodeChanged = 0x1B, DoorLockEventType_LockReset = 0x1C, DoorLockEventType_ConfigurationChanged = 0x1D, DoorLockEventType_LowBattery = 0x1E, DoorLockEventType_NewBattery = 0x1F, DoorLockEventType_Max = 0x20 }; static char const* c_DoorLockEventType[] = { "Locked via Access Code", "Unlocked via Access Code", "Locked via Lock Button", "Unlocked via UnLock Button", "Lock Attempt via Out of Schedule Access Code", "Unlock Attempt via Out of Schedule Access Code", "Illegal Access Code Entered", "Manually Locked", "Manually UnLocked", "Auto Locked", "Auto Unlocked", "Locked via Remote Out of Schedule Access Code", "Unlocked via Remote Out of Schedule Access Code", "Locked via Remote", "Unlocked via Remote", "Lock Attempt via Remote Out of Schedule Access Code", "Unlock Attempt via Remote Out of Schedule Access Code", "Illegal Remote Access Code", "Manually Locked (2)", "Manually Unlocked (2)", "Lock Secured", "Lock Unsecured", "User Code Added", "User Code Deleted", "All User Codes Deleted", "Master Code Changed", "User Code Changed", "Lock Reset", "Configuration Changed", "Low Battery", "New Battery Installed", "Unknown" }; /* size = 31 entries */ //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- DoorLockLogging::DoorLockLogging(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_CurRecord(0) { m_dom.EnableFlag(STATE_FLAG_DOORLOCKLOG_MAXRECORDS, 0); SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool DoorLockLogging::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool requests = false; if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { requests = RequestValue(_requestFlags, DoorLockLoggingCmd_RecordSupported_Get, _instance, _queue); } if (_requestFlags & RequestFlag_Dynamic) { requests |= RequestValue(_requestFlags, DoorLockLoggingCmd_Record_Get, _instance, _queue); } return requests; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool DoorLockLogging::RequestValue(uint32 const _requestFlags, uint16 const _what, uint8 const _instance, Driver::MsgQueue const _queue) { if (_what == DoorLockLoggingCmd_RecordSupported_Get) { Msg* msg = new Msg("DoorLockLoggingCmd_RecordSupported_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(DoorLockLoggingCmd_RecordSupported_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else if (_what == DoorLockLoggingCmd_Record_Get) { Msg* msg = new Msg("DoorLockLoggingCmd_Record_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(DoorLockLoggingCmd_Record_Get); msg->Append(m_CurRecord); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool DoorLockLogging::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (DoorLockLoggingCmd_RecordSupported_Report == (DoorLockLoggingCmd) _data[0]) { Log::Write(LogLevel_Info, GetNodeId(), "Received DoorLockLoggingCmd_RecordSupported_Report: Max Records is %d ", _data[1]); m_dom.SetFlagByte(STATE_FLAG_DOORLOCKLOG_MAXRECORDS, _data[1]); if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_DoorLockLogging::System_Config_MaxRecords))) { value->OnValueRefreshed(_data[1]); value->Release(); } ClearStaticRequest(StaticRequest_Values); return true; } else if (DoorLockLoggingCmd_Record_Report == (DoorLockLoggingCmd) _data[0]) { uint8 EventType = _data[9]; if (EventType >= DoorLockEventType_Max) EventType = DoorLockEventType_Max; Log::Write(LogLevel_Info, GetNodeId(), "Received a DoorLockLogging Record %d which is \"%s\"", _data[1], c_DoorLockEventType[EventType - 1]); if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_DoorLockLogging::GetRecordNo))) { value->OnValueRefreshed(_data[1]); value->Release(); } if (Internal::VC::ValueString* value = static_cast(GetValue(_instance, ValueID_Index_DoorLockLogging::LogRecord))) { char msg[512]; uint16 year = (_data[2] << 8) + (_data[3] & 0xFF); uint8 month = (_data[4] & 0x0F); uint8 day = (_data[5] & 0x1F); uint8 hour = (_data[6] & 0x1F); uint8 minute = (_data[7] & 0x3F); uint8 second = (_data[8] & 0x3F); bool valid = false; if (((_data[6] & 0xE0) >> 5) > 0) { valid = true; } uint8 userid = (_data[10]); uint8 usercodelength = (_data[11]); char usercode[254], tmpusercode[10]; snprintf(usercode, sizeof(usercode), "UserCode:"); if (usercodelength > 0) for (int i = 0; i < usercodelength; i++) { snprintf(tmpusercode, sizeof(tmpusercode), "%d", (int) _data[12 + i]); strncat(usercode, tmpusercode, 10); } if (valid) { snprintf(msg, sizeof(msg), "%02d/%02d/%02d %02d:%02d:%02d \tMessage: %s \tUserID: %d \t%s", (int) day, (int) month, (int) year, (int) hour, (int) minute, (int) second, c_DoorLockEventType[EventType], (int) userid, usercode); } else snprintf(msg, sizeof(msg), "Invalid Record"); value->OnValueRefreshed(msg); value->Release(); } return true; } return false; } //----------------------------------------------------------------------------- // // Set the lock's state //----------------------------------------------------------------------------- bool DoorLockLogging::SetValue(Internal::VC::Value const& _value) { if ((ValueID_Index_DoorLockLogging::GetRecordNo == _value.GetID().GetIndex()) && ValueID::ValueType_Byte == _value.GetID().GetType()) { Internal::VC::ValueByte const* value = static_cast(&_value); Log::Write(LogLevel_Info, GetNodeId(), "DoorLockLoggingCmd_Record_Get - Requesting Log Record %d", value->GetValue()); Msg* msg = new Msg("DoorLockLoggingCmd_Record_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(DoorLockLoggingCmd_Record_Get); msg->Append(value->GetValue()); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); m_CurRecord = value->GetValue(); return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void DoorLockLogging::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueByte(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_DoorLockLogging::System_Config_MaxRecords, "Max Number of Records", "", true, false, 0x0, 0); node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_DoorLockLogging::GetRecordNo, "Current Record Number", "", false, false, 0x0, 0); node->CreateValueString(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_DoorLockLogging::LogRecord, "Log Record", "", true, false, "", 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/ClimateControlSchedule.h0000644000175200017520000000537414032142455022202 00000000000000//----------------------------------------------------------------------------- // // ClimateControlSchedule.h // // Implementation of the Z-Wave COMMAND_CLASS_CLIMATE_CONTROL_SCHEDULE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ClimateControlSchedule_H #define _ClimateControlSchedule_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_CLIMATE_CONTROL_SCHEDULE (0x46), a Z-Wave device command class. * \ingroup CommandClass */ class ClimateControlSchedule: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new ClimateControlSchedule(_homeId, _nodeId); } virtual ~ClimateControlSchedule() { } static uint8 const StaticGetCommandClassId() { return 0x46; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_CLIMATE_CONTROL_SCHEDULE"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: ClimateControlSchedule(uint32 const _homeId, uint8 const _nodeId); }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/DeviceResetLocally.cpp0000644000175200017520000000504214032142455021653 00000000000000//----------------------------------------------------------------------------- // // DeviceResetLocally.cpp // // Implementation of the Z-Wave COMMAND_CLASS_DEVICE_RESET_LOCALLY // // Copyright (c) 2015 // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/DeviceResetLocally.h" #include "command_classes/NoOperation.h" #include "Defs.h" #include "Manager.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace CC { enum DeviceResetLocallyCmd { DeviceResetLocallyCmd_Notification = 1 }; //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool DeviceResetLocally::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (DeviceResetLocallyCmd_Notification == _data[0]) { // device has been reset Log::Write(LogLevel_Info, GetNodeId(), "Received Device Reset Locally from node %d", GetNodeId()); // send a NoOperation message to the node, this will fail since the node is no longer included in the network // we must do this because the Controller will only remove failed nodes if (Node* node = GetNodeUnsafe()) { if (NoOperation* noop = static_cast(node->GetCommandClass(NoOperation::StaticGetCommandClassId()))) { noop->Set(true); } } // the Controller now knows the node has failed Manager::Get()->HasNodeFailed(GetHomeId(), GetNodeId()); m_deviceReset = true; return true; } return false; } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Basic.cpp0000644000175200017520000003123714032142455017157 00000000000000//----------------------------------------------------------------------------- // // Basic.cpp // // Implementation of the Z-Wave COMMAND_CLASS_BASIC // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/Basic.h" #include "command_classes/Association.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "Notification.h" #include "platform/Log.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueInt.h" #include "command_classes/NoOperation.h" #include "tinyxml.h" namespace OpenZWave { namespace Internal { namespace CC { enum BasicCmd { BasicCmd_Set = 0x01, BasicCmd_Get = 0x02, BasicCmd_Report = 0x03 }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Basic::Basic(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { m_com.EnableFlag(COMPAT_FLAG_BASIC_IGNOREREMAPPING, false); m_com.EnableFlag(COMPAT_FLAG_BASIC_MAPPING, 0); m_com.EnableFlag(COMPAT_FLAG_BASIC_SETASREPORT, false); } //----------------------------------------------------------------------------- // // Read configuration. //----------------------------------------------------------------------------- void Basic::ReadXML(TiXmlElement const* _ccElement) { CommandClass::ReadXML(_ccElement); SetMapping(m_com.GetFlagByte(COMPAT_FLAG_BASIC_MAPPING)); if (m_com.GetFlagBool(COMPAT_FLAG_BASIC_SETASREPORT)) SetAfterMark(); } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Basic::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (IsAfterMark()) { Log::Write(LogLevel_Info, GetNodeId(), "%s is a Controlling Class", GetCommandClassName().c_str()); return false; } if (_requestFlags & RequestFlag_Dynamic) { if ((m_com.GetFlagBool(COMPAT_FLAG_BASIC_IGNOREREMAPPING) || (!m_com.GetFlagBool(COMPAT_FLAG_BASIC_IGNOREREMAPPING) && m_com.GetFlagByte(COMPAT_FLAG_BASIC_MAPPING) == 0))) return RequestValue(_requestFlags, ValueID_Index_Basic::Set, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Basic::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (IsAfterMark()) return false; if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("BasicCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(BasicCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "BasicCmd_Get Not Supported on this node"); } return false; } bool Basic::HandleIncomingMsg(uint8 const* _data, uint32 const _length, uint32 const _instance ) { /* just redirect to the HandleMsg Method */ return HandleMsg(_data, _length, _instance); } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Basic::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (BasicCmd_Report == (BasicCmd) _data[0]) { // Level Log::Write(LogLevel_Info, GetNodeId(), "Received Basic report from node %d: level=%d", GetNodeId(), _data[1]); if (!m_com.GetFlagBool(COMPAT_FLAG_BASIC_IGNOREREMAPPING) && m_com.GetFlagByte(COMPAT_FLAG_BASIC_MAPPING) != 0) { /* update our Mapped Class with the Target Values */ if (GetVersion() >= 2 && _length >= 4) UpdateMappedClass(_instance, m_com.GetFlagByte(COMPAT_FLAG_BASIC_MAPPING), _data[2]); else UpdateMappedClass(_instance, m_com.GetFlagByte(COMPAT_FLAG_BASIC_MAPPING), _data[1]); } else { if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_Basic::Set))) { /* Set the Target Value, if it is present */ if (_length >= 4) value->SetTargetValue(_data[2], _data[3]); value->OnValueRefreshed(_data[1]); value->Release(); } else { Log::Write(LogLevel_Warning, GetNodeId(), "No Valid Mapping for Basic Command Class and No ValueID Exported. Error?"); } if (_length >= 4) { if (Internal::VC::ValueByte* target = static_cast(GetValue(_instance, ValueID_Index_Basic::Target))) { target->OnValueRefreshed(_data[2]); target->Release(); } if (Internal::VC::ValueInt* duration = static_cast(GetValue(_instance, ValueID_Index_Basic::Duration))) { duration->OnValueRefreshed(decodeDuration(_data[3])); duration->Release(); } } } return true; } if (BasicCmd_Set == (BasicCmd) _data[0]) { if (m_com.GetFlagBool(COMPAT_FLAG_BASIC_SETASREPORT)) { Log::Write(LogLevel_Info, GetNodeId(), "Received Basic set from node %d: level=%d. Treating it as a Basic report.", GetNodeId(), _data[1]); if (!m_com.GetFlagBool(COMPAT_FLAG_BASIC_IGNOREREMAPPING) && m_com.GetFlagByte(COMPAT_FLAG_BASIC_MAPPING) != 0) { /* update our Mapped Class with the Target Values */ if (GetVersion() >= 2 && _length >= 4) UpdateMappedClass(_instance, m_com.GetFlagByte(COMPAT_FLAG_BASIC_MAPPING), _data[2]); else UpdateMappedClass(_instance, m_com.GetFlagByte(COMPAT_FLAG_BASIC_MAPPING), _data[1]); } else { if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_Basic::Set))) { value->OnValueRefreshed(_data[1]); value->Release(); } else { Log::Write(LogLevel_Warning, GetNodeId(), "No Valid Mapping for Basic Command Class and No ValueID Exported. Error?"); } if (_length >= 4) { if (Internal::VC::ValueByte* target = static_cast(GetValue(_instance, ValueID_Index_Basic::Target))) { target->OnValueRefreshed(_data[2]); target->Release(); } if (Internal::VC::ValueInt* duration = static_cast(GetValue(_instance, ValueID_Index_Basic::Duration))) { duration->OnValueRefreshed(decodeDuration(_data[3])); duration->Release(); } } } } else { // Commmand received from the node. Handle as a notification event Log::Write(LogLevel_Info, GetNodeId(), "Received Basic set from node %d: level=%d. Sending event notification.", GetNodeId(), _data[1]); Notification* notification = new Notification(Notification::Type_NodeEvent); notification->SetHomeNodeIdAndInstance(GetHomeId(), GetNodeId(), _instance); notification->SetEvent(_data[1]); GetDriver()->QueueNotification(notification); } return true; } return false; } //----------------------------------------------------------------------------- // // Set a value on the Z-Wave device //----------------------------------------------------------------------------- bool Basic::SetValue(Internal::VC::Value const& _value) { if (ValueID_Index_Basic::Set == _value.GetID().GetIndex()) { Internal::VC::ValueByte const* value = static_cast(&_value); Log::Write(LogLevel_Info, GetNodeId(), "Basic::Set - Setting node %d to level %d", GetNodeId(), value->GetValue()); Msg* msg = new Msg("BasicCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(BasicCmd_Set); msg->Append(value->GetValue()); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void Basic::CreateVars(uint8 const _instance) { if (m_com.GetFlagBool(COMPAT_FLAG_BASIC_IGNOREREMAPPING) || (m_com.GetFlagByte(COMPAT_FLAG_BASIC_MAPPING) == 0)) { Log::Write(LogLevel_Info, GetNodeId(), "COMMAND_CLASS_BASIC is not mapped to another CC. Exposing ValueID"); if (Node* node = GetNodeUnsafe()) { node->CreateValueByte(ValueID::ValueGenre_Basic, GetCommandClassId(), _instance, ValueID_Index_Basic::Set, "Basic", "", IsAfterMark(), false, 0, 0); if ((GetVersion() >= 2) || (IsAfterMark())) { node->CreateValueByte(ValueID::ValueGenre_Basic, GetCommandClassId(), _instance, ValueID_Index_Basic::Target, "Basic Target", "", true, false, 0, 0); node->CreateValueInt(ValueID::ValueGenre_Basic, GetCommandClassId(), _instance, ValueID_Index_Basic::Duration, "Basic Duration", "", true, false, 0, 0); } } } } //----------------------------------------------------------------------------- // // Helper method to set the level //----------------------------------------------------------------------------- void Basic::Set(uint8 const _level) { // This may look like a long winded way to do this, but // it ensures that all the proper notifications get sent. if (Internal::VC::ValueByte* value = static_cast(GetValue(1, ValueID_Index_Basic::Set))) { value->Set(_level); value->Release(); } } //----------------------------------------------------------------------------- // // Map COMMAND_CLASS_BASIC messages to another command class //----------------------------------------------------------------------------- bool Basic::SetMapping(uint8 const _commandClassId) { bool res = false; if (_commandClassId != NoOperation::StaticGetCommandClassId()) { char str[16]; snprintf(str, sizeof(str), "0x%02x", _commandClassId); string ccstr = str; if (Node const* node = GetNodeUnsafe()) { if (CommandClass* cc = node->GetCommandClass(_commandClassId)) { ccstr = cc->GetCommandClassName(); } } if (m_com.GetFlagBool(COMPAT_FLAG_BASIC_IGNOREREMAPPING)) { Log::Write(LogLevel_Info, GetNodeId(), " COMMAND_CLASS_BASIC will not be mapped to %s (ignored)", ccstr.c_str()); m_com.SetFlagByte(COMPAT_FLAG_BASIC_MAPPING, 0); } else { Log::Write(LogLevel_Info, GetNodeId(), " COMMAND_CLASS_BASIC will be mapped to %s", ccstr.c_str()); m_com.SetFlagByte(COMPAT_FLAG_BASIC_MAPPING, _commandClassId); RemoveValue(1, ValueID_Index_Basic::Set); RemoveValue(1, ValueID_Index_Basic::Target); RemoveValue(1, ValueID_Index_Basic::Duration); } res = true; } return res; } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Meter.cpp0000644000175200017520000005066714032142455017222 00000000000000//----------------------------------------------------------------------------- // // Meter.cpp // // Implementation of the Z-Wave COMMAND_CLASS_METER // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/Meter.h" #include "command_classes/MultiInstance.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "Utils.h" #include "value_classes/ValueDecimal.h" #include "value_classes/ValueList.h" #include "value_classes/ValueButton.h" #include "value_classes/ValueInt.h" #include "value_classes/ValueBool.h" namespace OpenZWave { namespace Internal { namespace CC { enum MeterCmd { MeterCmd_Get = 0x01, MeterCmd_Report = 0x02, // Version 2 MeterCmd_SupportedGet = 0x03, MeterCmd_SupportedReport = 0x04, MeterCmd_Reset = 0x05 }; enum MeterType { MeterType_Electric = 0, MeterType_Gas, MeterType_Water, MeterType_Heating, MeterType_Cooling }; struct s_MeterTypes { string Label; string Unit; }; std::map MeterTypes = { {ValueID_Index_Meter::Electric_kWh, {"Electric - kWh", "kWh"}}, {ValueID_Index_Meter::Electric_kVah, {"Electric - kVah", "kVah"}}, {ValueID_Index_Meter::Electric_W, {"Electric - W", "W"}}, {ValueID_Index_Meter::Electric_Pulse, {"Electric - Pulses", "Pulses"}}, {ValueID_Index_Meter::Electric_V, {"Electric - V", "V"}}, {ValueID_Index_Meter::Electric_A, {"Electric - A", "A"}}, {ValueID_Index_Meter::Electric_PowerFactor, {"Electric - PF", "PF"}}, {ValueID_Index_Meter::Electric_Unknown_1, {"Electric (Unknown)", ""}}, {ValueID_Index_Meter::Electric_kVar, {"Electric - kVar", "kVar"}}, {ValueID_Index_Meter::Electric_kVarh, {"Electric - kVarh", "kVarh"}}, {ValueID_Index_Meter::Electric_Unknown_2, {"Electric (Unknown)", ""}}, {ValueID_Index_Meter::Electric_Unknown_3, {"Electric (Unknown)", ""}}, {ValueID_Index_Meter::Electric_Unknown_4, {"Electric (Unknown)", ""}}, {ValueID_Index_Meter::Electric_Unknown_5, {"Electric (Unknown)", ""}}, {ValueID_Index_Meter::Electric_Unknown_6, {"Electric (Unknown)", ""}}, {ValueID_Index_Meter::Electric_Unknown_7, {"Electric (Unknown)", ""}}, {ValueID_Index_Meter::Gas_Cubic_Meters, {"Gas - m3", "m3"}}, {ValueID_Index_Meter::Gas_Cubic_Feet, {"Gas - ft3", "ft3"}}, {ValueID_Index_Meter::Gas_Unknown_1, {"Gas (Unknown)", ""}}, {ValueID_Index_Meter::Gas_Pulse, {"Gas - Pulses", "Pulses"}}, {ValueID_Index_Meter::Gas_Unknown_2, {"Gas (Unknown)", ""}}, {ValueID_Index_Meter::Gas_Unknown_3, {"Gas (Unknown)", ""}}, {ValueID_Index_Meter::Gas_Unknown_4, {"Gas (Unknown)", ""}}, {ValueID_Index_Meter::Gas_Unknown_5, {"Gas (Unknown)", ""}}, {ValueID_Index_Meter::Gas_Unknown_6, {"Gas (Unknown)", ""}}, {ValueID_Index_Meter::Gas_Unknown_7, {"Gas (Unknown)", ""}}, {ValueID_Index_Meter::Gas_Unknown_8, {"Gas (Unknown)", ""}}, {ValueID_Index_Meter::Gas_Unknown_9, {"Gas (Unknown)", ""}}, {ValueID_Index_Meter::Gas_Unknown_10, {"Gas (Unknown)", ""}}, {ValueID_Index_Meter::Gas_Unknown_11, {"Gas (Unknown)", ""}}, {ValueID_Index_Meter::Gas_Unknown_12, {"Gas (Unknown)", ""}}, {ValueID_Index_Meter::Gas_Unknown_13, {"Gas (Unknown)", ""}}, {ValueID_Index_Meter::Water_Cubic_Meters, {"Water - m3", "m3"}}, {ValueID_Index_Meter::Water_Cubic_Feet, {"Water - ft3", "ft3"}}, {ValueID_Index_Meter::Water_Cubic_US_Gallons, {"Water - gal", "gal"}}, {ValueID_Index_Meter::Water_Cubic_Pulse, {"Water - Pulses", "Pulses"}}, {ValueID_Index_Meter::Water_Unknown_1, {"Water (Unknown)", ""}}, {ValueID_Index_Meter::Water_Unknown_2, {"Water (Unknown)", ""}}, {ValueID_Index_Meter::Water_Unknown_3, {"Water (Unknown)", ""}}, {ValueID_Index_Meter::Water_Unknown_4, {"Water (Unknown)", ""}}, {ValueID_Index_Meter::Water_Unknown_5, {"Water (Unknown)", ""}}, {ValueID_Index_Meter::Water_Unknown_6, {"Water (Unknown)", ""}}, {ValueID_Index_Meter::Water_Unknown_7, {"Water (Unknown)", ""}}, {ValueID_Index_Meter::Water_Unknown_8, {"Water (Unknown)", ""}}, {ValueID_Index_Meter::Water_Unknown_9, {"Water (Unknown)", ""}}, {ValueID_Index_Meter::Water_Unknown_10, {"Water (Unknown)", ""}}, {ValueID_Index_Meter::Water_Unknown_11, {"Water (Unknown)", ""}}, {ValueID_Index_Meter::Water_Unknown_12, {"Water (Unknown)", ""}}, {ValueID_Index_Meter::Heating_kWh, {"Heating - kWh", "kWh"}}, {ValueID_Index_Meter::Heating_Unknown_1, {"Heating (Unknown)", ""}}, {ValueID_Index_Meter::Heating_Unknown_2, {"Heating (Unknown)", ""}}, {ValueID_Index_Meter::Heating_Unknown_3, {"Heating (Unknown)", ""}}, {ValueID_Index_Meter::Heating_Unknown_4, {"Heating (Unknown)", ""}}, {ValueID_Index_Meter::Heating_Unknown_5, {"Heating (Unknown)", ""}}, {ValueID_Index_Meter::Heating_Unknown_6, {"Heating (Unknown)", ""}}, {ValueID_Index_Meter::Heating_Unknown_7, {"Heating (Unknown)", ""}}, {ValueID_Index_Meter::Heating_Unknown_8, {"Heating (Unknown)", ""}}, {ValueID_Index_Meter::Heating_Unknown_9, {"Heating (Unknown)", ""}}, {ValueID_Index_Meter::Heating_Unknown_10, {"Heating (Unknown)", ""}}, {ValueID_Index_Meter::Heating_Unknown_11, {"Heating (Unknown)", ""}}, {ValueID_Index_Meter::Heating_Unknown_12, {"Heating (Unknown)", ""}}, {ValueID_Index_Meter::Heating_Unknown_13, {"Heating (Unknown)", ""}}, {ValueID_Index_Meter::Heating_Unknown_14, {"Heating (Unknown)", ""}}, {ValueID_Index_Meter::Heating_Unknown_15, {"Heating (Unknown)", ""}}, {ValueID_Index_Meter::Cooling_kWh, {"Cooling - kWh", "kWh"}}, {ValueID_Index_Meter::Cooling_Unknown_1, {"Cooling (Unknown)", ""}}, {ValueID_Index_Meter::Cooling_Unknown_2, {"Cooling (Unknown)", ""}}, {ValueID_Index_Meter::Cooling_Unknown_3, {"Cooling (Unknown)", ""}}, {ValueID_Index_Meter::Cooling_Unknown_4, {"Cooling (Unknown)", ""}}, {ValueID_Index_Meter::Cooling_Unknown_5, {"Cooling (Unknown)", ""}}, {ValueID_Index_Meter::Cooling_Unknown_6, {"Cooling (Unknown)", ""}}, {ValueID_Index_Meter::Cooling_Unknown_7, {"Cooling (Unknown)", ""}}, {ValueID_Index_Meter::Cooling_Unknown_8, {"Cooling (Unknown)", ""}}, {ValueID_Index_Meter::Cooling_Unknown_9, {"Cooling (Unknown)", ""}}, {ValueID_Index_Meter::Cooling_Unknown_10, {"Cooling (Unknown)", ""}}, {ValueID_Index_Meter::Cooling_Unknown_11, {"Cooling (Unknown)", ""}}, {ValueID_Index_Meter::Cooling_Unknown_12, {"Cooling (Unknown)", ""}}, {ValueID_Index_Meter::Cooling_Unknown_13, {"Cooling (Unknown)", ""}}, {ValueID_Index_Meter::Cooling_Unknown_14, {"Cooling (Unknown)", ""}}, {ValueID_Index_Meter::Cooling_Unknown_15, {"Cooling (Unknown)", ""}} }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Meter::Meter(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { #if 0 std::map::iterator it; for (it = MeterTypes.begin(); it != MeterTypes.end(); it++) { std::cout << "Type: " << it->first << std::endl; std::cout << "\tLabel: " << it->second.Label << std::endl; std::cout << "\tUnit: " << it->second.Unit << std::endl; } #endif SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Meter::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool res = false; if (GetVersion() > 1) { if (_requestFlags & RequestFlag_Static) { Msg* msg = new Msg("MeterCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(MeterCmd_SupportedGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); res = true; } } if (_requestFlags & RequestFlag_Dynamic) { res |= RequestValue(_requestFlags, 0, _instance, _queue); } return res; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool Meter::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { bool res = false; if (!m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Log::Write(LogLevel_Info, GetNodeId(), "MeterCmd_Get Not Supported on this node"); return false; } for (uint8 i = 0; i < MeterTypes.size(); ++i) { Internal::VC::Value* value = GetValue(_instance, i); if (value != NULL) { value->Release(); Msg* msg = new Msg("MeterCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); if (GetVersion() == 1) msg->Append(2); else if (GetVersion() <= 3) msg->Append(3); else if (GetVersion() >= 4) { uint8 scale = (i % 16); if (scale > ValueID_Index_Meter::Electric_Unknown_1) msg->Append(4); else msg->Append(3); } msg->Append(GetCommandClassId()); msg->Append(MeterCmd_Get); if (GetVersion() == 2) msg->Append((((i % 16) & 0x03) << 3)); else if (GetVersion() == 3) msg->Append((((i % 16) & 0x07) << 3)); else if (GetVersion() >= 4) { uint8 scale = (i % 16); if (scale > ValueID_Index_Meter::Electric_Unknown_1) { /* 4.55.3 - 0x38 is scale value 7 unshifted */ msg->Append(0x38); msg->Append(scale-8); } else { /* our Scale can fit in Scale 1 */ msg->Append((((i % 16) & 0x07) << 3)); } } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); res |= true; } } return res; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Meter::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { bool handled = false; if (MeterCmd_SupportedReport == (MeterCmd) _data[0]) { handled = HandleSupportedReport(_data, _length, _instance); } else if (MeterCmd_Report == (MeterCmd) _data[0]) { handled = HandleReport(_data, _length, _instance); } return handled; } //----------------------------------------------------------------------------- // // Create the values for this command class based on the reported parameters //----------------------------------------------------------------------------- bool Meter::HandleSupportedReport(uint8 const* _data, uint32 const _length, uint32 const _instance) { bool canReset = ((_data[1] & 0x80) != 0); int8 meterType = (MeterType) (_data[1] & 0x1f); if (meterType > MeterType_Cooling) /* size of c_meterTypes */ { Log::Write(LogLevel_Warning, GetNodeId(), "meterType Value was greater than range. Dropping Message"); return false; } uint32 scale = 0; uint8 scalesize = 1; /* decode the Scale */ /* Version 1 Doesn't have a Supported Report Message * The Scale is encoded in the Report Message instead */ if (GetVersion() == 2) { scale = (_data[2] & 0x0F); } if (GetVersion() == 3) { scale = (_data[2] & 0xFF); } /* Version 4 has the Scale All Over the Place */ if (GetVersion() >= 4) { /* if the MSB is set - Then the Scales Supported are specified as optional * bytes following this byte */ scale = (_data[2] & 0x7F); if (_data[2] & 0x80) { uint8_t size = _data[3]; for (int i = 1; i <= size; i++) { uint8 scale2 = _data[3+1]; scale |= (scale2 << 8*i); } size += scalesize; } } if (Node* node = GetNodeUnsafe()) { for (uint8 i = 0; i <= (scalesize*8)+1; ++i) { if (scale & (1 << i)) { uint32 type = ((meterType-1) * 16) + i; if (type > MeterTypes.size()) { /* error */ Log::Write(LogLevel_Warning, GetNodeId(), "MeterType %d and Unit %d is unknown", meterType, i); continue; } Log::Write(LogLevel_Info, GetNodeId(), "Creating MeterType %s (%d) with Unit %s (%d) at Index %d", MeterTypes.at(type).Label.c_str(), meterType, MeterTypes.at(type).Unit.c_str(), i, type); node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, type, MeterTypes.at(type).Label, MeterTypes.at(type).Unit, true, false, "0.0", 0); } } // Create the export flag node->CreateValueBool(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Meter::Exporting, "Exporting", "", true, false, false, 0); // Create the reset button if (canReset) { node->CreateValueButton(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_Meter::Reset, "Reset", 0); } return true; } return false; } //----------------------------------------------------------------------------- // // Read the reported meter value //----------------------------------------------------------------------------- bool Meter::HandleReport(uint8 const* _data, uint32 const _length, uint32 const _instance) { // Get the value and scale uint8 scale; uint8 precision = 0; string valueStr = ExtractValue(&_data[2], &scale, &precision); scale = GetScale(_data, _length); int8 meterType = (MeterType) (_data[1] & 0x1f); uint16_t index = (((meterType -1) * 16) + scale); if (MeterTypes.count(index) == 0) { Log::Write(LogLevel_Warning, GetNodeId(), "MeterTypes Index is out of range/not valid - %d", index); return false; } Log::Write(LogLevel_Info, GetNodeId(), "Received Meter Report for %s (%d) with Units %s (%d) on Index %d: %s",MeterTypes.at(index).Label.c_str(), meterType, MeterTypes.at(index).Unit.c_str(), scale, index, valueStr.c_str()); Internal::VC::ValueDecimal* value = static_cast(GetValue(_instance, index)); if (!value && (GetVersion() == 1)) { if (Node* node = GetNodeUnsafe()) { Log::Write(LogLevel_Info, GetNodeId(), "Creating Version 1 MeterType %s (%d) with Unit %s (%d) at Index %d", MeterTypes.at(index).Label.c_str(), meterType, MeterTypes.at(index).Unit.c_str(), scale, index); node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, index, MeterTypes.at(index).Label, MeterTypes.at(index).Unit, true, false, "0.0", 0); value = static_cast(GetValue(_instance, index)); } } else if (!value) { Log::Write(LogLevel_Warning, GetNodeId(), "Can't Find a ValueID Index for %s (%d) with Unit %s (%d) - Index %d", MeterTypes.at(index).Label.c_str(), meterType, MeterTypes.at(index).Unit.c_str(), scale, index); return false; } value->OnValueRefreshed(valueStr); if (value->GetPrecision() != precision) { value->SetPrecision(precision); } value->Release(); bool exporting = false; if (GetVersion() > 1) { exporting = ((_data[1] & 0x60) == 0x40); if (Internal::VC::ValueBool* value = static_cast(GetValue(_instance, ValueID_Index_Meter::Exporting))) { value->OnValueRefreshed(exporting); value->Release(); } } #if 0 /* Are Previous Values Important? */ // Read any previous value and time delta uint8 size = _data[2] & 0x07; uint16 delta = (uint16) ((_data[3 + size] << 8) | _data[4 + size]); if (delta) { // There is only a previous value if the time delta is non-zero Internal::VC::ValueDecimal* previous = static_cast(GetValue(_instance, baseIndex + 1)); if ( NULL == previous) { // We need to create a value to hold the previous if (Node* node = GetNodeUnsafe()) { node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, baseIndex + 1, "Previous Reading", value->GetUnits().c_str(), true, false, "0.0", 0); previous = static_cast(GetValue(_instance, baseIndex + 1)); } } if (previous) { precision = 0; valueStr = ExtractValue(&_data[2], &scale, &precision, 3 + size); Log::Write(LogLevel_Info, GetNodeId(), " Previous value was %s%s, received %d seconds ago.", valueStr.c_str(), previous->GetUnits().c_str(), delta); previous->OnValueRefreshed(valueStr); if (previous->GetPrecision() != precision) { previous->SetPrecision(precision); } previous->Release(); } // Time delta Internal::VC::ValueInt* interval = static_cast(GetValue(_instance, baseIndex + 2)); if ( NULL == interval) { // We need to create a value to hold the time delta if (Node* node = GetNodeUnsafe()) { node->CreateValueInt(ValueID::ValueGenre_User, GetCommandClassId(), _instance, baseIndex + 2, "Interval", "seconds", true, false, 0, 0); interval = static_cast(GetValue(_instance, baseIndex + 2)); } } if (interval) { interval->OnValueRefreshed((int32) delta); interval->Release(); } } #endif return true; } //----------------------------------------------------------------------------- // // Set the device's scale, or reset its accumulated values. //----------------------------------------------------------------------------- bool Meter::SetValue(Internal::VC::Value const& _value) { if (ValueID_Index_Meter::Reset == _value.GetID().GetIndex()) { Internal::VC::ValueButton const* button = static_cast(&_value); if (button->IsPressed()) { Msg* msg = new Msg("MeterCmd_Reset", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(MeterCmd_Reset); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } } return false; } //----------------------------------------------------------------------------- // // Decode The Scale as its all over the place in different versions //----------------------------------------------------------------------------- int32_t Meter::GetScale(uint8_t const *_data, uint32_t const _length) { uint8 scale = 0; //uint8 size = (_data[2] & 0x07); if (GetVersion() >= 1) { scale = ((_data[2] & 0x18) >> 3); } if (GetVersion() >= 3) { scale |= ((_data[1] & 0x80) >> 5); } if (GetVersion() >= 4) { /* 4.55.4 - Bit 7 indicates to use Scale 2 Field */ if (scale == 7) { scale = (_data[_length-2] + 8); } } return scale; } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Indicator.cpp0000644000175200017520000012356314032142455020056 00000000000000//----------------------------------------------------------------------------- // // Indicator.cpp // // Implementation of the Z-Wave COMMAND_CLASS_INDICATOR // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/Indicator.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueBool.h" namespace OpenZWave { namespace Internal { namespace CC { enum IndicatorCmd { IndicatorCmd_Set = 0x01, IndicatorCmd_Get = 0x02, IndicatorCmd_Report = 0x03, IndicatorCmd_Supported_Get = 0x04, IndicatorCmd_Supported_Report = 0x05, IndicatorCmd_Description_Get = 0x06, IndicatorCmd_Description_Report = 0x07 }; std::map IndicatorTypes = { {ValueID_Index_Indicator::Indicator, "Indicator"}, {ValueID_Index_Indicator::Armed, "Indicator: Armed"}, {ValueID_Index_Indicator::Not_Armed, "Indicator: Not Armed"}, {ValueID_Index_Indicator::Ready, "Indicator: Ready"}, {ValueID_Index_Indicator::Fault, "Indicator: Fault"}, {ValueID_Index_Indicator::Busy, "Indicator: Busy"}, {ValueID_Index_Indicator::Enter_ID, "Indicator: Enter ID"}, {ValueID_Index_Indicator::Enter_PIN, "Indicator: Enter PIN"}, {ValueID_Index_Indicator::Code_Accepted, "Indicator: Code Accepted"}, {ValueID_Index_Indicator::Code_Not_Accepted, "Indicator: Code Not Accepted"}, {ValueID_Index_Indicator::Armed_Stay, "Indicator: Armed Stay"}, {ValueID_Index_Indicator::Armed_Away, "Indicator: Armed Away"}, {ValueID_Index_Indicator::Alarming, "Indicator: Alarming"}, {ValueID_Index_Indicator::Alarming_Burglar, "Indicator: Alarming: Burglar"}, {ValueID_Index_Indicator::Alarming_Smoke_Fire, "Indicator: Alarming: Smoke/Fire"}, {ValueID_Index_Indicator::Alarming_Carbon_Monoxide, "Indicator: Alarming: Carbon Monoxide"}, {ValueID_Index_Indicator::Bypass_Challenge, "Indicator: Bypass Challenge"}, {ValueID_Index_Indicator::Entry_Delay, "Indicator: Entry Delay"}, {ValueID_Index_Indicator::Exit_Delay, "Indicator: Exit Delay"}, {ValueID_Index_Indicator::Alarming_Medical, "Indicator: Alarming: Medical"}, {ValueID_Index_Indicator::Alarming_Freeze_Warning, "Indicator: Alarming: Freeze Warning"}, {ValueID_Index_Indicator::Alarming_Water_Leak, "Indicator: Alarming: Water Leak"}, {ValueID_Index_Indicator::Alarming_Panic, "Indicator: Alarming: Panic"}, {ValueID_Index_Indicator::Zone_1_Armed, "Indicator: Zone 1 Armed"}, {ValueID_Index_Indicator::Zone_2_Armed, "Indicator: Zone 2 Armed"}, {ValueID_Index_Indicator::Zone_3_Armed, "Indicator: Zone 3 Armed"}, {ValueID_Index_Indicator::Zone_4_Armed, "Indicator: Zone 4 Armed"}, {ValueID_Index_Indicator::Zone_5_Armed, "Indicator: Zone 5 Armed"}, {ValueID_Index_Indicator::Zone_6_Armed, "Indicator: Zone 6 Armed"}, {ValueID_Index_Indicator::Zone_7_Armed, "Indicator: Zone 7 Armed"}, {ValueID_Index_Indicator::Zone_8_Armed, "Indicator: Zone 8 Armed"}, {ValueID_Index_Indicator::LCD_Backlight, "Indicator: LCD Backlight"}, {ValueID_Index_Indicator::Button_Backlight_Letters, "Indicator: Button: Backlight Letters"}, {ValueID_Index_Indicator::Button_Backlight_Digits, "Indicator: Button: Backlight Digits"}, {ValueID_Index_Indicator::Button_Backlight_Command, "Indicator: Button: Backlight Command"}, {ValueID_Index_Indicator::Button_1_Indication, "Indicator: Button 1"}, {ValueID_Index_Indicator::Button_2_Indication, "Indicator: Button 2"}, {ValueID_Index_Indicator::Button_3_Indication, "Indicator: Button 3"}, {ValueID_Index_Indicator::Button_4_Indication, "Indicator: Button 4"}, {ValueID_Index_Indicator::Button_5_Indication, "Indicator: Button 5"}, {ValueID_Index_Indicator::Button_6_Indication, "Indicator: Button 6"}, {ValueID_Index_Indicator::Button_7_Indication, "Indicator: Button 7"}, {ValueID_Index_Indicator::Button_8_Indication, "Indicator: Button 8"}, {ValueID_Index_Indicator::Button_9_Indication, "Indicator: Button 9"}, {ValueID_Index_Indicator::Button_10_Indication, "Indicator: Button 10"}, {ValueID_Index_Indicator::Button_11_Indication, "Indicator: Button 11"}, {ValueID_Index_Indicator::Button_12_Indication, "Indicator: Button 12"}, {ValueID_Index_Indicator::Node_Identify, "Indicator: Node Identify"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_1, "Indicator: Generic Event Sound Notification 1"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_2, "Indicator: Generic Event Sound Notification 2"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_3, "Indicator: Generic Event Sound Notification 3"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_4, "Indicator: Generic Event Sound Notification 4"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_5, "Indicator: Generic Event Sound Notification 5"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_6, "Indicator: Generic Event Sound Notification 6"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_7, "Indicator: Generic Event Sound Notification 7"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_8, "Indicator: Generic Event Sound Notification 8"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_9, "Indicator: Generic Event Sound Notification 9"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_10, "Indicator: Generic Event Sound Notification 10"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_11, "Indicator: Generic Event Sound Notification 11"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_12, "Indicator: Generic Event Sound Notification 12"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_13, "Indicator: Generic Event Sound Notification 13"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_14, "Indicator: Generic Event Sound Notification 14"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_15, "Indicator: Generic Event Sound Notification 15"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_16, "Indicator: Generic Event Sound Notification 16"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_17, "Indicator: Generic Event Sound Notification 17"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_18, "Indicator: Generic Event Sound Notification 18"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_19, "Indicator: Generic Event Sound Notification 19"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_20, "Indicator: Generic Event Sound Notification 20"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_21, "Indicator: Generic Event Sound Notification 21"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_22, "Indicator: Generic Event Sound Notification 22"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_23, "Indicator: Generic Event Sound Notification 23"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_24, "Indicator: Generic Event Sound Notification 24"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_25, "Indicator: Generic Event Sound Notification 25"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_26, "Indicator: Generic Event Sound Notification 26"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_27, "Indicator: Generic Event Sound Notification 27"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_28, "Indicator: Generic Event Sound Notification 28"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_29, "Indicator: Generic Event Sound Notification 29"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_30, "Indicator: Generic Event Sound Notification 30"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_31, "Indicator: Generic Event Sound Notification 31"}, {ValueID_Index_Indicator::Generic_Event_Sound_Notification_32, "Indicator: Generic Event Sound Notification 32"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_1, "Indicator: Manufacturer Defined Indicator 1"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_2, "Indicator: Manufacturer Defined Indicator 2"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_3, "Indicator: Manufacturer Defined Indicator 3"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_4, "Indicator: Manufacturer Defined Indicator 4"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_5, "Indicator: Manufacturer Defined Indicator 5"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_6, "Indicator: Manufacturer Defined Indicator 6"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_7, "Indicator: Manufacturer Defined Indicator 7"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_8, "Indicator: Manufacturer Defined Indicator 8"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_9, "Indicator: Manufacturer Defined Indicator 9"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_10, "Indicator: Manufacturer Defined Indicator 10"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_11, "Indicator: Manufacturer Defined Indicator 11"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_12, "Indicator: Manufacturer Defined Indicator 12"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_13, "Indicator: Manufacturer Defined Indicator 13"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_14, "Indicator: Manufacturer Defined Indicator 14"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_15, "Indicator: Manufacturer Defined Indicator 15"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_16, "Indicator: Manufacturer Defined Indicator 16"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_17, "Indicator: Manufacturer Defined Indicator 17"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_18, "Indicator: Manufacturer Defined Indicator 18"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_19, "Indicator: Manufacturer Defined Indicator 19"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_20, "Indicator: Manufacturer Defined Indicator 20"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_21, "Indicator: Manufacturer Defined Indicator 21"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_22, "Indicator: Manufacturer Defined Indicator 22"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_23, "Indicator: Manufacturer Defined Indicator 23"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_24, "Indicator: Manufacturer Defined Indicator 24"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_25, "Indicator: Manufacturer Defined Indicator 25"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_26, "Indicator: Manufacturer Defined Indicator 26"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_27, "Indicator: Manufacturer Defined Indicator 27"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_28, "Indicator: Manufacturer Defined Indicator 28"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_29, "Indicator: Manufacturer Defined Indicator 29"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_30, "Indicator: Manufacturer Defined Indicator 30"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_31, "Indicator: Manufacturer Defined Indicator 31"}, {ValueID_Index_Indicator::Manufacturer_Defined_Indicator_32, "Indicator: Manufacturer Defined Indicator 32"}, {ValueID_Index_Indicator::Buzzer, "Indicator: Buzzer"} }; enum Indicator_Property_Bit { MultiLevel_Bit = 0x02, Binary_Bit = 0x04, OnOffPeriod_Bit = 0x08, OnOffCycle_Bit = 0x10, OnTimeWithPeriod_Bit = 0x20, Timeout_Min_Bit = 0x40, Timeout_Sec_Bit = 0x80, Timeout_MS_Bit = 0x100, SoundLevel_Bit = 0x200, LowPower_Bit = 0x400 }; enum Indicator_Property_Group { MultiLevel_Grp = 0x01, Binary_Grp = 0x02, Toogle_Grp = 0x03, Timeout_Grp = 0x04, Sound_Grp = 0x05, Advertised_Grp = 0x06 }; enum Indicator_Property_offset { Multilevel_Prop = 0x01, Binary_Prop = 0x02, OnOffPeriod_Prop = 0x03, OnOffCycle_Prop = 0x04, OnTimeWithPeriod_Prop = 0x05, Timeout_Min_Prop = 0x06, Timeout_Sec_Prop = 0x07, Timeout_Ms_Prop = 0x08, Sound_Prop = 0x09, Adv_Low_Power_Prop = 0x10 }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Indicator::Indicator(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { Timer::SetDriver(GetDriver()); } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Indicator::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool ret = false; if (_requestFlags & RequestFlag_Dynamic) { if (GetVersion() == 1) return RequestValue(_requestFlags, 0, _instance, _queue); for (int i = 1; i <= ValueID_Index_Indicator::Buzzer; i++) { if (Internal::VC::Value *value = GetValue(_instance, i)) { ret |= RequestValue(_requestFlags, i, _instance, _queue); value->Release(); } } } if (GetVersion() > 1) { if (_requestFlags & RequestFlag_Static) { Msg* msg = new Msg("IndicatorCmd_Supported_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(IndicatorCmd_Supported_Get); /* get the first Supported Indicator */ msg->Append(0); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); ret = true; } } return ret; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool Indicator::RequestValue(uint32 const _requestFlags, uint16 const index, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { if (index == ValueID_Index_Indicator::Indicator) { Msg* msg = new Msg("IndicatorCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(IndicatorCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else if (index > ValueID_Index_Indicator::Indicator && index <= ValueID_Index_Indicator::Buzzer) { Msg* msg = new Msg("IndicatorCmd_Get_v2", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(IndicatorCmd_Get); msg->Append(index); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } } else { Log::Write(LogLevel_Info, GetNodeId(), "IndicatorCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Indicator::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (IndicatorCmd_Supported_Report == (IndicatorCmd) _data[0]) { uint8 id = _data[1]; uint8 nextid = _data[2]; uint8 propertiessupportedlength = (_data[3] & 0x1F); uint32 propertiessupported = 0; for (int i = 0; i < propertiessupportedlength; i++) { propertiessupported = _data[4+i] << (8*i); } Log::Write(LogLevel_Info, GetNodeId(), "Indicator Supported Report for %d - Support %d - Next Indicator %d", id, propertiessupported, nextid); std::shared_ptr idprops = std::make_shared(); idprops->id = id; idprops->instance = _instance; idprops->properties = propertiessupported; this->m_indicatorLists.insert(std::pair >(id, idprops)); if ((GetVersion() >= 4) && (id >= 0x80) && (id <= 0x9f)) { Msg* msg = new Msg("IndicatorCmd_Description_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(IndicatorCmd_Description_Get); msg->Append(id); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } else { this->createIndicatorConfigValues(id); } /* Get the Next Indicator */ if (nextid > 0) { Msg* msg = new Msg("IndicatorCmd_Supported_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(IndicatorCmd_Supported_Get); msg->Append(nextid); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Query); return true; } return true; } if (IndicatorCmd_Report == (IndicatorCmd) _data[0]) { if (GetVersion() == 1) { Log::Write(LogLevel_Info, GetNodeId(), "Received an Indicator report: Indicator=%d", _data[1]); if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_Indicator::Indicator))) { value->OnValueRefreshed(_data[1]); value->Release(); } return true; } else { uint8 size = (_data[2] & 0x1F); uint8 setid = 0; uint8 setparam = 0; for (int i = 0; i < size; i++) { uint8 id = _data[3 + (i*3)]; uint8 property = _data[4 + (i*3)]; uint8 value = _data[5 + (i*3)]; Log::Write(LogLevel_Info, GetNodeId(), "Indicator Report for %d - Property %d - Value %d", id, property, value); this->setIndicatorValue(id, _instance, property, value); /* 4.24.5 - ID Field: * All indicator objects MUST carry the same Indicator ID. */ if (setid == 0) setid = id; if (value > 0) setparam = property; } if (Internal::VC::ValueList* value = static_cast(GetValue(_instance, setid))) { bool setTimer = true; if (setparam == Indicator_Property_offset::Multilevel_Prop) { value->OnValueRefreshed(Indicator_Property_Group::MultiLevel_Grp); setTimer = false; } else if (setparam == Indicator_Property_offset::Binary_Prop) { value->OnValueRefreshed(Indicator_Property_Group::Binary_Grp); setTimer = false; } else if (setparam >= Indicator_Property_offset::OnOffPeriod_Prop && setparam <= Indicator_Property_offset::OnTimeWithPeriod_Prop) value->OnValueRefreshed(Indicator_Property_Group::Toogle_Grp); else if (setparam >= Indicator_Property_offset::Timeout_Min_Prop && setparam <= Indicator_Property_offset::Timeout_Ms_Prop) value->OnValueRefreshed(Indicator_Property_Group::Timeout_Grp); else if (setparam == Indicator_Property_offset::Sound_Prop) value->OnValueRefreshed(Indicator_Property_Group::Sound_Grp); else { value->OnValueRefreshed(0); setTimer = false; } value->Release(); if (setTimer) { int32 id = setid + (_instance << 16); TimerThread::TimerCallback callback = bind(&Indicator::refreshIndicator, this, id); TimerSetEvent(1000, callback, id); } } else { Log::Write(LogLevel_Warning, GetNodeId(), "Can't Find ValueID for Indicator %d", setid); } } return true; } if (IndicatorCmd_Description_Report == (IndicatorCmd) _data[0]) { uint8 id = _data[1]; uint8 length = _data[2]; string label("Unknown Indicator"); if (m_indicatorLists.find(id) != m_indicatorLists.end()) { if (length == 0) { /* use the default label */ if (IndicatorTypes.find(id) != IndicatorTypes.end()) { m_indicatorLists[id]->label = IndicatorTypes.at(id); } } else { string description((const char *) &_data[3], length); if (!description.empty()) m_indicatorLists[id]->label = description; } this->createIndicatorConfigValues(id); } } return false; } //----------------------------------------------------------------------------- // // Set the device's indicator value //----------------------------------------------------------------------------- bool Indicator::SetValue(Internal::VC::Value const& _value) { if (ValueID_Index_Indicator::Indicator == _value.GetID().GetIndex()) { Internal::VC::ValueByte const* value = static_cast(&_value); Log::Write(LogLevel_Info, GetNodeId(), "Indicator::SetValue - Setting indicator to %d", value->GetValue()); Msg* msg = new Msg("IndicatorCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(IndicatorCmd_Set); msg->Append(value->GetValue()); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } if (_value.GetID().GetIndex() > 1 && _value.GetID().GetIndex() <= ValueID_Index_Indicator::Buzzer) { Internal::VC::ValueList const* value = static_cast(&_value); uint32 selected = value->GetItem()->m_value; uint16 index = _value.GetID().GetIndex(); /* depending upon what is selected, we can get a Property Config ValueID's */ uint32 property = 1 << selected; uint32 propertyindex = (256 + (32 * index)); Log::Write(LogLevel_Info, GetNodeId(), "Setting Index: %d Selected %d Property %d PropertyIndex %d", index, selected, property, propertyindex); vector payload; switch (selected) { case 0: { /* turn off any indicator */ Msg* msg = new Msg("IndicatorCmd_Set_v2", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(IndicatorCmd_Set); msg->Append(0); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; break; } case Indicator_Property_Group::Binary_Grp: { if (Internal::VC::ValueBool* propertyValue = static_cast(GetValue(_value.GetID().GetInstance(), propertyindex + Indicator_Property_offset::Binary_Prop))) { payload.push_back(1); payload.push_back(index); payload.push_back(Indicator_Property_offset::Binary_Prop); payload.push_back(propertyValue->GetValue() == true ? 1 : 0); } break; } case Indicator_Property_Group::MultiLevel_Grp: { if (Internal::VC::ValueByte* propertyValue = static_cast(GetValue(_value.GetID().GetInstance(), propertyindex + Indicator_Property_offset::Multilevel_Prop))) { payload.push_back(1); payload.push_back(index); payload.push_back(Indicator_Property_offset::Multilevel_Prop); payload.push_back(propertyValue->GetValue()); } break; } case Indicator_Property_Group::Toogle_Grp: { int params = 0; if (Internal::VC::ValueByte* propertyValue = static_cast(GetValue(_value.GetID().GetInstance(), propertyindex + Indicator_Property_offset::OnOffPeriod_Prop))) { params++; payload.push_back(index); payload.push_back(Indicator_Property_offset::OnOffPeriod_Prop); payload.push_back(propertyValue->GetValue()); } if (Internal::VC::ValueByte* propertyValue = static_cast(GetValue(_value.GetID().GetInstance(), propertyindex + Indicator_Property_offset::OnOffCycle_Prop))) { params++; payload.push_back(index); payload.push_back(Indicator_Property_offset::OnOffCycle_Prop); payload.push_back(propertyValue->GetValue()); } if (Internal::VC::ValueByte* propertyValue = static_cast(GetValue(_value.GetID().GetInstance(), propertyindex + Indicator_Property_offset::OnTimeWithPeriod_Prop))) { params++; payload.push_back(index); payload.push_back(Indicator_Property_offset::OnTimeWithPeriod_Prop); payload.push_back(propertyValue->GetValue()); } payload.insert(payload.begin(), params); break; } case Indicator_Property_Group::Timeout_Grp: { int params = 0; if (Internal::VC::ValueByte* propertyValue = static_cast(GetValue(_value.GetID().GetInstance(), propertyindex + Indicator_Property_offset::Timeout_Min_Prop))) { params++; payload.push_back(index); payload.push_back(Indicator_Property_offset::Timeout_Min_Prop); payload.push_back(propertyValue->GetValue()); } if (Internal::VC::ValueByte* propertyValue = static_cast(GetValue(_value.GetID().GetInstance(), propertyindex + Indicator_Property_offset::Timeout_Sec_Prop))) { params++; payload.push_back(index); payload.push_back(Indicator_Property_offset::Timeout_Sec_Prop); payload.push_back(propertyValue->GetValue()); } if (Internal::VC::ValueByte* propertyValue = static_cast(GetValue(_value.GetID().GetInstance(), propertyindex + Indicator_Property_offset::Timeout_Ms_Prop))) { params++; payload.push_back(index); payload.push_back(Indicator_Property_offset::Timeout_Ms_Prop); payload.push_back(propertyValue->GetValue()); } payload.insert(payload.begin(), params); break; } case Indicator_Property_Group::Sound_Grp: { if (Internal::VC::ValueByte* propertyValue = static_cast(GetValue(_value.GetID().GetInstance(), propertyindex + Indicator_Property_offset::Sound_Prop))) { payload.push_back(1); payload.push_back(index); payload.push_back(Indicator_Property_offset::Sound_Prop); payload.push_back(propertyValue->GetValue()); } break; } case Indicator_Property_Group::Advertised_Grp: { /* shouldn't ever be present */ break; } } Msg* msg = new Msg("IndicatorCmd_Set_v2", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(3 + payload.size()); msg->Append(GetCommandClassId()); msg->Append(IndicatorCmd_Set); msg->Append(0); for (unsigned int i = 0; i < payload.size(); i++) { msg->Append(payload.at(i)); } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } if (_value.GetID().GetIndex() > ValueID_Index_Indicator::Buzzer) { if (_value.GetID().GetType() == ValueID::ValueType_Byte) { if (Internal::VC::ValueByte * valueByte = static_cast(GetValue(_value.GetID().GetInstance(), _value.GetID().GetIndex()))) { valueByte->OnValueRefreshed(static_cast(&_value)->GetValue()); valueByte->Release(); } } if (_value.GetID().GetType() == ValueID::ValueType_Bool) { if (Internal::VC::ValueBool * valueBool = static_cast(GetValue(_value.GetID().GetInstance(), _value.GetID().GetIndex()))) { valueBool->OnValueRefreshed(static_cast(&_value)->GetValue()); valueBool->Release(); } } return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void Indicator::CreateVars(uint8 const _instance) { if (GetVersion() == 1) { if (Node* node = GetNodeUnsafe()) { node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Indicator::Indicator, "Indicator", "", false, false, false, 0); } } } //----------------------------------------------------------------------------- // // Create the Config Values for each Indicator ID //----------------------------------------------------------------------------- void Indicator::createIndicatorConfigValues(uint8 id) { /* Value Indexes are as follows: * Assume that we can have 32 Properties per Index * 0 - 256 - Actual Indicator ValueID * 257 - 288 - Indicator 1 Properties * 289 - 320 - Indicator 2 Properties * 321 - 352 - Indicator 3 Properties * and so on. */ if (m_indicatorLists.find(id) == m_indicatorLists.end()) { Log::Write(LogLevel_Warning, GetNodeId(), "Cant find Indicator %d in List", id); return; } Log::Write(LogLevel_Info, GetNodeId(), "Indicator Support:"); if (Node* node = GetNodeUnsafe()) { string label("Unknown Indicator"); if (m_indicatorLists[id]->label.empty()) { if (IndicatorTypes.find(id) != IndicatorTypes.end()) { label = IndicatorTypes.at(id); } } else { label = m_indicatorLists[id]->label; } uint32 propertiesSet = 0; if (m_indicatorLists[id]->properties & Indicator_Property_Bit::MultiLevel_Bit) { /* MultiLevel Property */ Log::Write(LogLevel_Info, GetNodeId(), "\tMultiLevel Property - Index %d", (256 + (32 * id) + Indicator_Property_offset::Multilevel_Prop)); node->CreateValueByte(ValueID::ValueGenre_Config, GetCommandClassId(), m_indicatorLists[id]->instance, (256 + (32 * id) + Indicator_Property_offset::Multilevel_Prop), label + ": Brightness/Level", "", false, false, 0, 0); propertiesSet |= (1 << Indicator_Property_Group::MultiLevel_Grp); } if (m_indicatorLists[id]->properties & Indicator_Property_Bit::Binary_Bit) { /* Binary Property */ Log::Write(LogLevel_Info, GetNodeId(), "\tBinary Property - Index %d", (256 + (32 * id) + Indicator_Property_offset::Binary_Prop)); node->CreateValueBool(ValueID::ValueGenre_Config, GetCommandClassId(), m_indicatorLists[id]->instance, (256 + (32 * id) + Indicator_Property_offset::Binary_Prop), label + ": On/Off", "", false, false, false, 0); propertiesSet |= (1 << Indicator_Property_Group::Binary_Grp); } if (m_indicatorLists[id]->properties & Indicator_Property_Bit::OnOffPeriod_Bit) { /* On/Off Period Property */ Log::Write(LogLevel_Info, GetNodeId(), "\tOn/Off Period Property - Index %d", (256 + (32 * id) + Indicator_Property_offset::OnOffPeriod_Prop)); node->CreateValueByte(ValueID::ValueGenre_Config, GetCommandClassId(), m_indicatorLists[id]->instance, (256 + (32 * id) + Indicator_Property_offset::OnOffPeriod_Prop), label + ": On/Off Period", "Seconds", false, false, 0, 0); propertiesSet |= (1 << Indicator_Property_Group::Toogle_Grp); } if (m_indicatorLists[id]->properties & Indicator_Property_Bit::OnOffCycle_Bit) { /* On/Off Cycles */ Log::Write(LogLevel_Info, GetNodeId(), "\tOn/Off Cycles Property - Index %d", (256 + (32 * id) + Indicator_Property_offset::OnOffCycle_Prop)); node->CreateValueByte(ValueID::ValueGenre_Config, GetCommandClassId(), m_indicatorLists[id]->instance, (256 + (32 * id) + Indicator_Property_offset::OnOffCycle_Prop), label + ": On/Off Cycles", "", false, false, 0, 0); propertiesSet |= (1 << Indicator_Property_Group::Toogle_Grp); } if (m_indicatorLists[id]->properties & Indicator_Property_Bit::OnTimeWithPeriod_Bit) { /* On Time with On/Off Period combination */ Log::Write(LogLevel_Info, GetNodeId(), "\tOn Time with On/Off Period Property - Index %d", (256 + (32 * id) + Indicator_Property_offset::OnTimeWithPeriod_Prop)); node->CreateValueByte(ValueID::ValueGenre_Config, GetCommandClassId(), m_indicatorLists[id]->instance, (256 + (32 * id) + Indicator_Property_offset::OnTimeWithPeriod_Prop), label + ": On time within an On/Off period", "Seconds", false, false, 0, 0); propertiesSet |= (1 << Indicator_Property_Group::Toogle_Grp); } if (m_indicatorLists[id]->properties & Indicator_Property_Bit::Timeout_Min_Bit) { /* Timeout (Minutes) */ Log::Write(LogLevel_Info, GetNodeId(), "\tTimeout (Minutes) Property - Index %d", (256 + (32 * id) + Indicator_Property_offset::Timeout_Min_Prop)); node->CreateValueByte(ValueID::ValueGenre_Config, GetCommandClassId(), m_indicatorLists[id]->instance, (256 + (32 * id) + Indicator_Property_offset::Timeout_Min_Prop), label + ": Timeout (Minutes)", "Minutes", false, false, 0, 0); propertiesSet |= (1 << Indicator_Property_Group::Timeout_Grp); } if (m_indicatorLists[id]->properties & Indicator_Property_Bit::Timeout_Sec_Bit) { /* Timeout (Seconds) */ Log::Write(LogLevel_Info, GetNodeId(), "\tTimeout (Seconds) Property - Index %d", (256 + (32 * id) + Indicator_Property_offset::Timeout_Sec_Prop)); node->CreateValueByte(ValueID::ValueGenre_Config, GetCommandClassId(), m_indicatorLists[id]->instance, (256 + (32 * id) + Indicator_Property_offset::Timeout_Sec_Prop), label + ": Timeout (Seconds)", "Seconds", false, false, 0, 0); propertiesSet |= (1 << Indicator_Property_Group::Timeout_Grp); } if (m_indicatorLists[id]->properties & Indicator_Property_Bit::Timeout_MS_Bit) { /* Timeout (1/100 of seconds) */ Log::Write(LogLevel_Info, GetNodeId(), "\tTimeout (1/100 of seconds) Property - Index %d", (256 + (32 * id) + Indicator_Property_offset::Timeout_Ms_Prop)); node->CreateValueByte(ValueID::ValueGenre_Config, GetCommandClassId(), m_indicatorLists[id]->instance, (256 + (32 * id) + Indicator_Property_offset::Timeout_Ms_Prop), label + ": Timeout (1/100 of seconds)", "Miliseconds", false, false, 0, 0); propertiesSet |= (1 << Indicator_Property_Group::Timeout_Grp); } if (m_indicatorLists[id]->properties & Indicator_Property_Bit::SoundLevel_Bit) { /* Multilevel Sound level */ Log::Write(LogLevel_Info, GetNodeId(), "\tMultilevel Sound Property - Index %d", (256 + (32 * id) + Indicator_Property_offset::Sound_Prop)); node->CreateValueByte(ValueID::ValueGenre_Config, GetCommandClassId(), m_indicatorLists[id]->instance, (256 + (32 * id) + Indicator_Property_offset::Sound_Prop), label + ": Multilevel Sound level", "", false, false, 0, 0); propertiesSet |= Indicator_Property_Group::Sound_Grp; } if (m_indicatorLists[id]->properties & Indicator_Property_Bit::LowPower_Bit) { /* ADVERTISE: Low power */ Log::Write(LogLevel_Info, GetNodeId(), "\tADVERTISE: Low power Property - Index %d", (256 + (32 * id) + Indicator_Property_offset::Adv_Low_Power_Prop)); node->CreateValueBool(ValueID::ValueGenre_Config, GetCommandClassId(), m_indicatorLists[id]->instance, (256 + (32 * id) + Indicator_Property_offset::Adv_Low_Power_Prop), label + ": Low Power Capable", "", true, false, false, 0); propertiesSet |= Indicator_Property_Group::Advertised_Grp; } /* Create the Actual Indicator */ vector items; Internal::VC::ValueList::Item item; item.m_label = "Off"; item.m_value = 0x00; items.push_back(item); if (propertiesSet & (1 << Indicator_Property_Group::Binary_Grp)) { Internal::VC::ValueList::Item item; item.m_label = "On"; item.m_value = Indicator_Property_Group::Binary_Grp; items.push_back(item); } if (propertiesSet & (1 << Indicator_Property_Group::MultiLevel_Grp)) { Internal::VC::ValueList::Item item; item.m_label = "Level"; item.m_value = Indicator_Property_Group::MultiLevel_Grp; items.push_back(item); } if (propertiesSet & (1 << Indicator_Property_Group::Toogle_Grp)) { Internal::VC::ValueList::Item item; item.m_label = "Toogle"; item.m_value = Indicator_Property_Group::Toogle_Grp; items.push_back(item); } if (propertiesSet & (1 << Indicator_Property_Group::Timeout_Grp)) { Internal::VC::ValueList::Item item; item.m_label = "Timeout"; item.m_value = Indicator_Property_Group::Timeout_Grp; items.push_back(item); } if (propertiesSet & (1 << Indicator_Property_Group::Sound_Grp)) { Internal::VC::ValueList::Item item; item.m_label = "Sound Level"; item.m_value = Indicator_Property_Group::Sound_Grp; items.push_back(item); } node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), m_indicatorLists[id]->instance, id, label, "", false, false, 0, items, 0, 0); } } //----------------------------------------------------------------------------- // // Sets the Properties Values for each Indicator ID //----------------------------------------------------------------------------- void Indicator::setIndicatorValue(uint8 id, uint8 _instance, uint8 property, uint8 value) { uint16 index = (256 + (32 * id) + property); Internal::VC::Value* propertyValue = GetValue(_instance, index); if (!propertyValue) { Log::Write(LogLevel_Warning, GetNodeId(), "Got Indicator Property for a Unregistered Property - Id: %d Property: %d Index: %d", id, property, index); return; } switch (propertyValue->GetID().GetType()) { case ValueID::ValueType_Bool: { if (Internal::VC::ValueBool *propertyBool = static_cast(propertyValue)) { propertyBool->OnValueRefreshed(value > 0 ? true : false); } propertyValue->Release(); break; } case ValueID::ValueType_Byte: { if (Internal::VC::ValueByte *propertyByte = static_cast(propertyValue)) { propertyByte->OnValueRefreshed(value); } propertyValue->Release(); break; } default: { /* Not Handled */ Log::Write(LogLevel_Warning, GetNodeId(), "Got Indicator Property for a Unhandled Property Type %d", propertyValue->GetID().GetType()); break; } } } //----------------------------------------------------------------------------- // // Refresh The Indicator ID's Values. this is called from the timer when a indicator is active. //----------------------------------------------------------------------------- void Indicator::refreshIndicator(uint32 id) { uint16 index = (id & 0xFFFF); uint8 instance = (id & 0xF0000) >> 16; RequestValue(0, index, instance, Driver::MsgQueue_Query); } //----------------------------------------------------------------------------- // // Update class values based in BASIC mapping //----------------------------------------------------------------------------- void Indicator::SetValueBasic(uint8 const _instance, uint8 const _value) { // Send a request for new value to synchronize it with the BASIC set/report. // In case the device is sleeping, we set the value anyway so the BASIC set/report // stays in sync with it. We must be careful mapping the uint8 BASIC value // into a class specific value. // When the device wakes up, the real requested value will be retrieved. if (GetVersion() == 1) { RequestValue(0, 0, _instance, Driver::MsgQueue_Query); return; } for (int i = 1; i <= ValueID_Index_Indicator::Buzzer; i++) { if (Internal::VC::Value *value = GetValue(_instance, i)) { RequestValue(0, i, _instance, Driver::MsgQueue_Query); value->Release(); } } return; } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/SwitchToggleMultilevel.h0000644000175200017520000000616014032142455022246 00000000000000//----------------------------------------------------------------------------- // // SwitchToggleMultilevel.h // // Implementation of the Z-Wave COMMAND_CLASS_SWITCH_TOGGLE_MULTILEVEL // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _SwitchToggleMultilevel_H #define _SwitchToggleMultilevel_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_SWITCH_TOGGLE_MULTILEVEL (0x29), a Z-Wave device command class. * \ingroup CommandClass */ class SwitchToggleMultilevel: public CommandClass { public: enum SwitchToggleMultilevelDirection { SwitchToggleMultilevelDirection_Up = 0x00, SwitchToggleMultilevelDirection_Down = 0x40 }; static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new SwitchToggleMultilevel(_homeId, _nodeId); } virtual ~SwitchToggleMultilevel() { } static uint8 const StaticGetCommandClassId() { return 0x29; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_SWITCH_TOGGLE_MULTILEVEL"; } void StartLevelChange(SwitchToggleMultilevelDirection const _direction, bool const _bIgnoreStartLevel, bool const _bRollover); void StopLevelChange(); // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: SwitchToggleMultilevel(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/CRC16Encap.cpp0000644000175200017520000000604614032142455017663 00000000000000//----------------------------------------------------------------------------- // // CRC16Encap.cpp // // Implementation of the Z-Wave COMMAND_CLASS_CRC_16_ENCAP // // Copyright (c) 2012 Greg Satz // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/CRC16Encap.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace CC { // // CRC-CCITT (0x1D0F) // uint16 crc16(uint8 const * data_p, uint32 const _length) { uint8 x; uint16 crc = 0xF6AF; // 0x1D0F with first byte 0x56; uint32 length = _length; while (length--) { x = crc >> 8 ^ *data_p++; x ^= x >> 4; crc = (crc << 8) ^ ((uint16) (x << 12)) ^ ((uint16) (x << 5)) ^ ((uint16) x); } return crc; } enum CRC16EncapCmd { CRC16EncapCmd_Encap = 0x01 }; //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool CRC16Encap::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (CRC16EncapCmd_Encap == (CRC16EncapCmd) _data[0]) { Log::Write(LogLevel_Info, GetNodeId(), "Received CRC16-command from node %d", GetNodeId()); uint16 crcM = (_data[_length - 3] << 8) + _data[_length - 2]; // crc as reported in msg uint16 crcC = crc16(&_data[0], _length - 3); // crc calculated if (crcM != crcC) { Log::Write(LogLevel_Info, GetNodeId(), "CRC check failed, message contains 0x%.4x but should be 0x%.4x", crcM, crcC); return false; } if (Node const* node = GetNodeUnsafe()) { uint8 commandClassId = _data[1]; if (CommandClass* pCommandClass = node->GetCommandClass(commandClassId)) { if (!pCommandClass->IsAfterMark()) { pCommandClass->HandleMsg(&_data[2], _length - 4); } else { pCommandClass->HandleIncomingMsg(&_data[2], _length - 4); } } } return true; } return false; } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Protection.cpp0000644000175200017520000001413414032142455020261 00000000000000//----------------------------------------------------------------------------- // // Protection.cpp // // Implementation of the Z-Wave COMMAND_CLASS_PROTECTION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "command_classes/CommandClasses.h" #include "command_classes/Protection.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueList.h" namespace OpenZWave { namespace Internal { namespace CC { enum ProtectionCmd { ProtectionCmd_Set = 0x01, ProtectionCmd_Get = 0x02, ProtectionCmd_Report = 0x03 }; static char const* c_protectionStateNames[] = { "Unprotected", "Protection by Sequence", "No Operation Possible", "Unknown" }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Protection::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Session) { return RequestValue(_requestFlags, ValueID_Index_Protection::Protection, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool Protection::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("ProtectionCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(ProtectionCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "ProtectionCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Protection::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (ProtectionCmd_Report == (ProtectionCmd) _data[0]) { int8 stateValue = _data[1]; if (stateValue > 2) /* size of c_protectionStateNames minus Invalid */ { Log::Write(LogLevel_Warning, GetNodeId(), "State Value was greater than range. Setting to Invalid"); stateValue = 3; } Log::Write(LogLevel_Info, GetNodeId(), "Received a Protection report: %s", c_protectionStateNames[_data[1]]); if (Internal::VC::ValueList* value = static_cast(GetValue(_instance, ValueID_Index_Protection::Protection))) { value->OnValueRefreshed((int) _data[1]); value->Release(); } return true; } return false; } //----------------------------------------------------------------------------- // // Set the device's protection state //----------------------------------------------------------------------------- bool Protection::SetValue(Internal::VC::Value const& _value) { if (ValueID::ValueType_List == _value.GetID().GetType()) { Internal::VC::ValueList const* value = static_cast(&_value); Internal::VC::ValueList::Item const *item = value->GetItem(); if (item == NULL) return false; Log::Write(LogLevel_Info, GetNodeId(), "Protection::Set - Setting protection state to '%s'", item->m_label.c_str()); Msg* msg = new Msg("ProtectionCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(ProtectionCmd_Set); msg->Append((uint8) item->m_value); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void Protection::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { vector items; Internal::VC::ValueList::Item item; for (uint8 i = 0; i < 3; ++i) { item.m_label = c_protectionStateNames[i]; item.m_value = i; items.push_back(item); } node->CreateValueList(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_Protection::Protection, "Protection", "", false, false, 1, items, 0, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/CentralScene.cpp0000644000175200017520000003306314032142455020503 00000000000000//----------------------------------------------------------------------------- // // CentralScene.cpp // // Implementation of the Z-Wave COMMAND_CLASS_CENTRAL_SCENE // // Copyright (c) 2012 Greg Satz // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/CentralScene.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueInt.h" #include "value_classes/ValueButton.h" #include "value_classes/ValueByte.h" #include "tinyxml.h" namespace OpenZWave { namespace Internal { namespace CC { enum CentralSceneCmd { CentralSceneCmd_Capability_Get = 0x01, CentralSceneCmd_Capability_Report = 0x02, CentralSceneCmd_Set = 0x03 }; enum CentralScene_ValueID_Index { }; enum CentralScene_KeyAttributesMask { CentralSceneMask_KeyPressed1time = 0x01, CentralSceneMask_KeyReleased = 0x02, CentralSceneMask_HeldDown = 0x04, CentralSceneMask_KeyPressed2times = 0x08, CentralSceneMask_KeyPressed3times = 0x10, CentralSceneMask_KeyPressed4times = 0x20, CentralSceneMask_KeyPressed5times = 0x40, CentralSceneMask_reserved = 0x80, }; enum CentralScene_KeyAttributes { CentralScene_KeyAttributes_KeyPressed1time = 0, CentralScene_KeyAttributes_KeyReleased = 1, CentralScene_KeyAttributes_KeyHeldDown = 2, CentralScene_KeyAttributes_KeyPressed2times = 3, CentralScene_KeyAttributes_KeyPressed3times = 4, CentralScene_KeyAttributes_KeyPressed4times = 5, CentralScene_KeyAttributes_KeyPressed5times = 6, CentralScene_KeyAttributes_reserved = 7, }; static char const* c_CentralScene_KeyAttributes[] = { "Inactive", "Pressed 1 Time", "Key Released", "Key Held down", "Pressed 2 Times", "Pressed 3 Times", "Pressed 4 Times", "Pressed 5 Times" }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- CentralScene::CentralScene(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_slowrefresh(false), m_sequence(0) { m_dom.EnableFlag(STATE_FLAG_CS_SCENECOUNT, 0); m_dom.EnableFlag(STATE_FLAG_CS_CLEARTIMEOUT, 1000); Timer::SetDriver(GetDriver()); SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool CentralScene::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool requests = false; if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { requests = RequestValue(_requestFlags, CentralSceneCmd_Capability_Get, _instance, _queue); } return requests; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool CentralScene::RequestValue(uint32 const _requestFlags, uint16 const _what, uint8 const _instance, Driver::MsgQueue const _queue) { if (_what == CentralSceneCmd_Capability_Get) { Msg* msg = new Msg("CentralSceneCmd_Capability_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(CentralSceneCmd_Capability_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); } return true; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool CentralScene::SetValue(Internal::VC::Value const& _value) { if ((ValueID::ValueType_Int == _value.GetID().GetType()) && (_value.GetID().GetIndex() == ValueID_Index_CentralScene::ClearSceneTimeout)) { Internal::VC::ValueInt const *value = static_cast(&_value); m_dom.SetFlagInt(STATE_FLAG_CS_CLEARTIMEOUT, value->GetValue()); return true; } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool CentralScene::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (CentralSceneCmd_Set == (CentralSceneCmd) _data[0]) { // Central Scene Set received so send notification /* if the sequence number is the same as what we have received previously this is a retried packet */ if (m_sequence == _data[1]) { Log::Write(LogLevel_Warning, GetNodeId(), "Received Duplicated Scene Notification. Dropping..."); return true; } m_sequence = _data[1]; uint8 keyAttribute = (_data[2] & 0x07); uint8 sceneID = _data[3]; Log::Write(LogLevel_Info, GetNodeId(), "Received Central Scene set from node %d: scene id=%d with key Attribute %d. Sending event notification.", GetNodeId(), sceneID, keyAttribute); if (Internal::VC::ValueList* value = static_cast(GetValue(_instance, sceneID))) { /* plus one, as we have our own "inactive" entry at index 0 */ value->OnValueRefreshed(keyAttribute + 1); value->Release(); /* Start up a Timer to set this back to Inactive */ Log::Write(LogLevel_Info, GetNodeId(), "Automatically Clearing Scene %d in %dms", sceneID, m_dom.GetFlagInt(STATE_FLAG_CS_CLEARTIMEOUT)); if (m_TimersSet.find(sceneID) == m_TimersSet.end()) { m_TimersSet.insert(std::pair(sceneID, _instance)); } else { /* clear the Old Timer */ TimerDelEvent(sceneID); /* no need to pop it off the list, as we will add it again below */ } TimerThread::TimerCallback callback = bind(&CentralScene::ClearScene, this, sceneID); TimerSetEvent(m_dom.GetFlagInt(STATE_FLAG_CS_CLEARTIMEOUT), callback, sceneID); } else { Log::Write(LogLevel_Warning, GetNodeId(), "No ValueID created for Scene %d", sceneID); return false; } return true; } else if (CentralSceneCmd_Capability_Report == (CentralSceneCmd) _data[0]) { /* Create a Number of ValueID's based on the STATE_FLAG_CS_SCENECOUNT variable * We prefer what the Config File specifies rather than what is returned by * the Device... */ int scenecount = _data[1]; if (m_dom.GetFlagByte(STATE_FLAG_CS_SCENECOUNT) == 0) { m_dom.SetFlagByte(STATE_FLAG_CS_SCENECOUNT, scenecount); } bool identical = true; //version 1 does not know this, so set it to true. if (GetVersion() >= 2) { identical = _data[2] & 0x01; Log::Write(LogLevel_Detail, GetNodeId(), "CentralScene: all scenes identical? %i", identical); if (GetVersion() >= 3) m_slowrefresh = (_data[2] & 0x80) ? true : false; } if (Internal::VC::ValueInt* value = static_cast(GetValue(_instance, ValueID_Index_CentralScene::SceneCount))) { value->OnValueRefreshed(m_dom.GetFlagByte(STATE_FLAG_CS_SCENECOUNT)); value->Release(); } else { Log::Write(LogLevel_Warning, GetNodeId(), "Can't find ValueID for SceneCount"); } Log::Write(LogLevel_Info, GetNodeId(), "Central Scene Contains %d Scenes that are%sidentical", m_dom.GetFlagByte(STATE_FLAG_CS_SCENECOUNT), identical ? " " : " not "); for (int sceneID = 1; sceneID <= m_dom.GetFlagByte(STATE_FLAG_CS_SCENECOUNT); sceneID++) { if (GetVersion() == 1) { // version 1 does not tell us which keyAttributes are supported, but only single press, released and held down are supported, so add these 3 if (Node* node = GetNodeUnsafe()) { vector items; for (unsigned int i = 0; i < 4; i++) { Internal::VC::ValueList::Item item; item.m_label = c_CentralScene_KeyAttributes[i]; item.m_value = i; items.push_back(item); } char lbl[64]; snprintf(lbl, 64, "Scene %d", sceneID); node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), _instance, sceneID, lbl, "", true, false, 3, items, 0, 0); Log::Write(LogLevel_Info, GetNodeId(), "Created Scene %d (Version 1)", sceneID); } } if (GetVersion() >= 2) { if (identical) { int keyAttributes = _data[3]; createSupportedKeyAttributesValues(keyAttributes, sceneID, _instance); } else { int keyAttributes = _data[2 + sceneID]; createSupportedKeyAttributesValues(keyAttributes, sceneID, _instance); } Log::Write(LogLevel_Info, GetNodeId(), "Created Scene %d", sceneID); } } return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void CentralScene::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueInt(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_CentralScene::SceneCount, "Scene Count", "", true, false, 0, 0); node->CreateValueInt(ValueID::ValueGenre_Config, GetCommandClassId(), _instance, ValueID_Index_CentralScene::ClearSceneTimeout, "Scene Reset Timeout", "", false, false, m_dom.GetFlagInt(STATE_FLAG_CS_CLEARTIMEOUT), 0); } } void CentralScene::createSupportedKeyAttributesValues(uint8 keyAttributes, uint8 sceneNumber, uint8 instance) { if (Node* node = GetNodeUnsafe()) { vector items; { Internal::VC::ValueList::Item item; item.m_label = c_CentralScene_KeyAttributes[0]; item.m_value = 0; items.push_back(item); } if (keyAttributes & CentralSceneMask_KeyPressed1time) { Internal::VC::ValueList::Item item; item.m_label = c_CentralScene_KeyAttributes[1]; item.m_value = 1; items.push_back(item); } if (keyAttributes & CentralSceneMask_KeyReleased) { Internal::VC::ValueList::Item item; item.m_label = c_CentralScene_KeyAttributes[2]; item.m_value = 2; items.push_back(item); } if (keyAttributes & CentralSceneMask_HeldDown) { Internal::VC::ValueList::Item item; item.m_label = c_CentralScene_KeyAttributes[3]; item.m_value = 3; items.push_back(item); } if (keyAttributes & CentralSceneMask_KeyPressed2times) { Internal::VC::ValueList::Item item; item.m_label = c_CentralScene_KeyAttributes[4]; item.m_value = 4; items.push_back(item); } if (keyAttributes & CentralSceneMask_KeyPressed3times) { Internal::VC::ValueList::Item item; item.m_label = c_CentralScene_KeyAttributes[5]; item.m_value = 5; items.push_back(item); } if (keyAttributes & CentralSceneMask_KeyPressed4times) { Internal::VC::ValueList::Item item; item.m_label = c_CentralScene_KeyAttributes[6]; item.m_value = 6; items.push_back(item); } if (keyAttributes & CentralSceneMask_KeyPressed5times) { Internal::VC::ValueList::Item item; item.m_label = c_CentralScene_KeyAttributes[7]; item.m_value = 7; items.push_back(item); } char lbl[64]; snprintf(lbl, 64, "Scene %d", sceneNumber); node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), instance, sceneNumber, lbl, "", true, false, (uint8_t) (items.size() & 0xFF), items, 0, 0); } } void CentralScene::ClearScene(uint32 sceneID) { uint8 _instance; if (m_TimersSet.find(sceneID) != m_TimersSet.end()) { _instance = m_TimersSet.at(sceneID); } else { Log::Write(LogLevel_Warning, "Can't find Timer in TimerSet List"); return; } if (Internal::VC::ValueList* value = static_cast(GetValue(_instance, sceneID))) { /* plus one, as we have our own "inactive" entry at index 0 */ value->OnValueRefreshed(0); value->Release(); } m_TimersSet.erase(sceneID); } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/BarrierOperator.h0000644000175200017520000000551414032142455020704 00000000000000//----------------------------------------------------------------------------- // // BarrierOperator.h // // Implementation of the COMMAND_CLASS_BARRIER_OPERATOR // // Copyright (c) 2016 srirams (https://github.com/srirams) // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _BarrierOperator_H #define _BarrierOperator_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_BARRIER_OPERATOR (0x66), a Z-Wave device command class. * \ingroup CommandClass */ class BarrierOperator: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new BarrierOperator(_homeId, _nodeId); } virtual ~BarrierOperator() { } static uint8 const StaticGetCommandClassId() { return 0x66; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_BARRIER_OPERATOR"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; bool RequestSignalSupport(uint8 const _instance, Driver::MsgQueue const _queue); virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; virtual uint8 GetMaxVersion() override { return 3; } protected: virtual void CreateVars(uint8 const _instance) override; private: BarrierOperator(uint32 const _homeId, uint8 const _nodeId); }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Language.h0000644000175200017520000000531514032142455017324 00000000000000//----------------------------------------------------------------------------- // // Language.h // // Implementation of the Z-Wave COMMAND_CLASS_LANGUAGE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Language_H #define _Language_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_LANGUAGE (0x89), a Z-Wave device command class. * \ingroup CommandClass */ class Language: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Language(_homeId, _nodeId); } virtual ~Language() { } static uint8 const StaticGetCommandClassId() { return 0x89; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_LANGUAGE"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; bool supportsMultiInstance() override { return false; } protected: virtual void CreateVars(uint8 const _instance) override; private: Language(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { SetStaticRequest(StaticRequest_Values); } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/CommandClasses.cpp0000644000175200017520000004151614032142455021033 00000000000000//----------------------------------------------------------------------------- // // CommandClasses.cpp // // Singleton holding methods to create each command class object // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "command_classes/CommandClasses.h" #include "command_classes/Alarm.h" #include "command_classes/ApplicationStatus.h" #include "command_classes/Association.h" #include "command_classes/AssociationCommandConfiguration.h" #include "command_classes/SimpleAV.h" #include "command_classes/BarrierOperator.h" #include "command_classes/Basic.h" #include "command_classes/BasicWindowCovering.h" #include "command_classes/Battery.h" #include "command_classes/CentralScene.h" #include "command_classes/ClimateControlSchedule.h" #include "command_classes/Clock.h" #include "command_classes/Color.h" #include "command_classes/Configuration.h" #include "command_classes/ControllerReplication.h" #include "command_classes/CRC16Encap.h" #include "command_classes/DeviceResetLocally.h" #include "command_classes/DoorLock.h" #include "command_classes/DoorLockLogging.h" #include "command_classes/EnergyProduction.h" #include "command_classes/Hail.h" #include "command_classes/Indicator.h" #include "command_classes/Language.h" #include "command_classes/Lock.h" #include "command_classes/ManufacturerProprietary.h" #include "command_classes/ManufacturerSpecific.h" #include "command_classes/Meter.h" #include "command_classes/MeterPulse.h" #include "command_classes/MultiCmd.h" #include "command_classes/MultiInstance.h" #include "command_classes/MultiChannelAssociation.h" #include "command_classes/NodeNaming.h" #include "command_classes/NoOperation.h" #include "command_classes/Powerlevel.h" #include "command_classes/Proprietary.h" #include "command_classes/Protection.h" #include "command_classes/SceneActivation.h" #include "command_classes/Security.h" #include "command_classes/SensorAlarm.h" #include "command_classes/SensorBinary.h" #include "command_classes/SensorMultilevel.h" #include "command_classes/SoundSwitch.h" #include "command_classes/SwitchAll.h" #include "command_classes/SwitchBinary.h" #include "command_classes/SwitchMultilevel.h" #include "command_classes/SwitchToggleBinary.h" #include "command_classes/SwitchToggleMultilevel.h" #include "command_classes/TimeParameters.h" #include "command_classes/ThermostatFanMode.h" #include "command_classes/ThermostatFanState.h" #include "command_classes/ThermostatMode.h" #include "command_classes/ThermostatOperatingState.h" #include "command_classes/ThermostatSetpoint.h" #include "command_classes/UserCode.h" #include "command_classes/Version.h" #include "command_classes/WakeUp.h" #include "command_classes/ZWavePlusInfo.h" #include "value_classes/ValueBool.h" #include "value_classes/ValueButton.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueDecimal.h" #include "value_classes/ValueInt.h" #include "value_classes/ValueList.h" #include "value_classes/ValueSchedule.h" #include "value_classes/ValueShort.h" #include "value_classes/ValueString.h" #include "Manager.h" #include "Options.h" #include "Utils.h" #include "Localization.h" namespace OpenZWave { namespace Internal { namespace CC { //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- CommandClasses::CommandClasses() { memset(m_commandClassCreators, 0, sizeof(pfnCreateCommandClass_t) * 256); memset(m_supportedCommandClasses, 0, sizeof(uint32) * 8); } //----------------------------------------------------------------------------- // // Static method to determine whether a command class is supported //----------------------------------------------------------------------------- bool CommandClasses::IsSupported(uint8 const _commandClassId) { // Test the bit representing the command class return ((Get().m_supportedCommandClasses[_commandClassId >> 5] & (1u << (_commandClassId & 0x1f))) != 0); } std::string CommandClasses::GetName(uint8 const _commandClassId) { for (std::map::iterator it = Get().m_namesToIDs.begin(); it != Get().m_namesToIDs.end(); it++) { if (it->second == _commandClassId) return it->first; } return string("Unknown"); } //----------------------------------------------------------------------------- // // Static method to register a command class creator method //----------------------------------------------------------------------------- void CommandClasses::Register(uint8 const _commandClassId, string const& _commandClassName, pfnCreateCommandClass_t _creator, bool advertised) { m_commandClassCreators[_commandClassId] = _creator; // Set the bit representing the command class Get().m_supportedCommandClasses[_commandClassId >> 5] |= (1u << (_commandClassId & 0x1f)); m_namesToIDs[_commandClassName] = _commandClassId; if (advertised) { /* ZWavePlus CC must always be first */ if (_commandClassId == ZWavePlusInfo::StaticGetCommandClassId()) m_advertisedCommandClasses.push_front(_commandClassId); else m_advertisedCommandClasses.push_back(_commandClassId); } } //----------------------------------------------------------------------------- // // Create a command class object using the registered method //----------------------------------------------------------------------------- CommandClass* CommandClasses::CreateCommandClass(uint8 const _commandClassId, uint32 const _homeId, uint8 const _nodeId) { // Get a pointer to the required CommandClass's Create method pfnCreateCommandClass_t creator = Get().m_commandClassCreators[_commandClassId]; if ( NULL == creator) { return NULL; } // Create an instance of the command class CommandClass *cc = creator(_homeId, _nodeId); Localization::Get()->SetupCommandClass(cc); return cc; } //----------------------------------------------------------------------------- // // Register all our implemented command classes //----------------------------------------------------------------------------- void CommandClasses::RegisterCommandClasses() { CommandClasses& cc = Get(); cc.Register(Alarm::StaticGetCommandClassId(), Alarm::StaticGetCommandClassName(), Alarm::Create); cc.Register(ApplicationStatus::StaticGetCommandClassId(), ApplicationStatus::StaticGetCommandClassName(), ApplicationStatus::Create); cc.Register(Association::StaticGetCommandClassId(), Association::StaticGetCommandClassName(), Association::Create); cc.Register(AssociationCommandConfiguration::StaticGetCommandClassId(), AssociationCommandConfiguration::StaticGetCommandClassName(), AssociationCommandConfiguration::Create); cc.Register(SimpleAV::StaticGetCommandClassId(), SimpleAV::StaticGetCommandClassName(), SimpleAV::Create); cc.Register(BarrierOperator::StaticGetCommandClassId(), BarrierOperator::StaticGetCommandClassName(), BarrierOperator::Create); cc.Register(Basic::StaticGetCommandClassId(), Basic::StaticGetCommandClassName(), Basic::Create); cc.Register(BasicWindowCovering::StaticGetCommandClassId(), BasicWindowCovering::StaticGetCommandClassName(), BasicWindowCovering::Create); cc.Register(Battery::StaticGetCommandClassId(), Battery::StaticGetCommandClassName(), Battery::Create); cc.Register(CentralScene::StaticGetCommandClassId(), CentralScene::StaticGetCommandClassName(), CentralScene::Create); cc.Register(ClimateControlSchedule::StaticGetCommandClassId(), ClimateControlSchedule::StaticGetCommandClassName(), ClimateControlSchedule::Create); cc.Register(Clock::StaticGetCommandClassId(), Clock::StaticGetCommandClassName(), Clock::Create); cc.Register(Color::StaticGetCommandClassId(), Color::StaticGetCommandClassName(), Color::Create); cc.Register(Configuration::StaticGetCommandClassId(), Configuration::StaticGetCommandClassName(), Configuration::Create); cc.Register(ControllerReplication::StaticGetCommandClassId(), ControllerReplication::StaticGetCommandClassName(), ControllerReplication::Create); cc.Register(CRC16Encap::StaticGetCommandClassId(), CRC16Encap::StaticGetCommandClassName(), CRC16Encap::Create); cc.Register(DeviceResetLocally::StaticGetCommandClassId(), DeviceResetLocally::StaticGetCommandClassName(), DeviceResetLocally::Create); cc.Register(DoorLock::StaticGetCommandClassId(), DoorLock::StaticGetCommandClassName(), DoorLock::Create); cc.Register(DoorLockLogging::StaticGetCommandClassId(), DoorLockLogging::StaticGetCommandClassName(), DoorLockLogging::Create); cc.Register(EnergyProduction::StaticGetCommandClassId(), EnergyProduction::StaticGetCommandClassName(), EnergyProduction::Create); cc.Register(Hail::StaticGetCommandClassId(), Hail::StaticGetCommandClassName(), Hail::Create); cc.Register(Indicator::StaticGetCommandClassId(), Indicator::StaticGetCommandClassName(), Indicator::Create); cc.Register(Language::StaticGetCommandClassId(), Language::StaticGetCommandClassName(), Language::Create); cc.Register(Lock::StaticGetCommandClassId(), Lock::StaticGetCommandClassName(), Lock::Create); cc.Register(ManufacturerProprietary::StaticGetCommandClassId(), ManufacturerProprietary::StaticGetCommandClassName(), ManufacturerProprietary::Create); cc.Register(ManufacturerSpecific::StaticGetCommandClassId(), ManufacturerSpecific::StaticGetCommandClassName(), ManufacturerSpecific::Create); cc.Register(Meter::StaticGetCommandClassId(), Meter::StaticGetCommandClassName(), Meter::Create); cc.Register(MeterPulse::StaticGetCommandClassId(), MeterPulse::StaticGetCommandClassName(), MeterPulse::Create); cc.Register(MultiCmd::StaticGetCommandClassId(), MultiCmd::StaticGetCommandClassName(), MultiCmd::Create); cc.Register(MultiInstance::StaticGetCommandClassId(), MultiInstance::StaticGetCommandClassName(), MultiInstance::Create); cc.Register(MultiChannelAssociation::StaticGetCommandClassId(), MultiChannelAssociation::StaticGetCommandClassName(), MultiChannelAssociation::Create); cc.Register(NodeNaming::StaticGetCommandClassId(), NodeNaming::StaticGetCommandClassName(), NodeNaming::Create); cc.Register(NoOperation::StaticGetCommandClassId(), NoOperation::StaticGetCommandClassName(), NoOperation::Create); cc.Register(Powerlevel::StaticGetCommandClassId(), Powerlevel::StaticGetCommandClassName(), Powerlevel::Create); cc.Register(Proprietary::StaticGetCommandClassId(), Proprietary::StaticGetCommandClassName(), Proprietary::Create); cc.Register(Protection::StaticGetCommandClassId(), Protection::StaticGetCommandClassName(), Protection::Create); cc.Register(SceneActivation::StaticGetCommandClassId(), SceneActivation::StaticGetCommandClassName(), SceneActivation::Create); cc.Register(Security::StaticGetCommandClassId(), Security::StaticGetCommandClassName(), Security::Create); cc.Register(SensorAlarm::StaticGetCommandClassId(), SensorAlarm::StaticGetCommandClassName(), SensorAlarm::Create); cc.Register(SensorBinary::StaticGetCommandClassId(), SensorBinary::StaticGetCommandClassName(), SensorBinary::Create); cc.Register(SensorMultilevel::StaticGetCommandClassId(), SensorMultilevel::StaticGetCommandClassName(), SensorMultilevel::Create); cc.Register(SoundSwitch::StaticGetCommandClassId(), SoundSwitch::StaticGetCommandClassName(), SoundSwitch::Create); cc.Register(SwitchAll::StaticGetCommandClassId(), SwitchAll::StaticGetCommandClassName(), SwitchAll::Create); cc.Register(SwitchBinary::StaticGetCommandClassId(), SwitchBinary::StaticGetCommandClassName(), SwitchBinary::Create); cc.Register(SwitchMultilevel::StaticGetCommandClassId(), SwitchMultilevel::StaticGetCommandClassName(), SwitchMultilevel::Create); cc.Register(SwitchToggleBinary::StaticGetCommandClassId(), SwitchToggleBinary::StaticGetCommandClassName(), SwitchToggleBinary::Create); cc.Register(SwitchToggleMultilevel::StaticGetCommandClassId(), SwitchToggleMultilevel::StaticGetCommandClassName(), SwitchToggleMultilevel::Create); cc.Register(TimeParameters::StaticGetCommandClassId(), TimeParameters::StaticGetCommandClassName(), TimeParameters::Create); cc.Register(ThermostatFanMode::StaticGetCommandClassId(), ThermostatFanMode::StaticGetCommandClassName(), ThermostatFanMode::Create); cc.Register(ThermostatFanState::StaticGetCommandClassId(), ThermostatFanState::StaticGetCommandClassName(), ThermostatFanState::Create); cc.Register(ThermostatMode::StaticGetCommandClassId(), ThermostatMode::StaticGetCommandClassName(), ThermostatMode::Create); cc.Register(ThermostatOperatingState::StaticGetCommandClassId(), ThermostatOperatingState::StaticGetCommandClassName(), ThermostatOperatingState::Create); cc.Register(ThermostatSetpoint::StaticGetCommandClassId(), ThermostatSetpoint::StaticGetCommandClassName(), ThermostatSetpoint::Create); cc.Register(UserCode::StaticGetCommandClassId(), UserCode::StaticGetCommandClassName(), UserCode::Create); cc.Register(Version::StaticGetCommandClassId(), Version::StaticGetCommandClassName(), Version::Create); cc.Register(WakeUp::StaticGetCommandClassId(), WakeUp::StaticGetCommandClassName(), WakeUp::Create); cc.Register(ZWavePlusInfo::StaticGetCommandClassId(), ZWavePlusInfo::StaticGetCommandClassName(), ZWavePlusInfo::Create, true); // Now all the command classes have been registered, we can modify the // supported command classes array according to the program options. string str; Options::Get()->GetOptionAsString("Include", &str); if (str != "") { // The include list has entries, so we assume that it is a // complete list of what should be supported. // Any existing support is cleared first. memset(cc.m_supportedCommandClasses, 0, sizeof(uint32) * 8); cc.ParseCommandClassOption(str, true); } // Apply the excluded command class option Options::Get()->GetOptionAsString("Exclude", &str); if (str != "") { cc.ParseCommandClassOption(str, false); } } //----------------------------------------------------------------------------- // // Parse a comma delimited list of included/excluded command classes //----------------------------------------------------------------------------- void CommandClasses::ParseCommandClassOption(string const& _optionStr, bool const _include) { size_t pos = 0; size_t start = 0; bool parsing = true; while (parsing) { string ccStr; pos = _optionStr.find_first_of(",", start); if (string::npos == pos) { ccStr = _optionStr.substr(start); parsing = false; } else { ccStr = _optionStr.substr(start, pos - start); start = pos + 1; } if (ccStr != "") { uint8 ccIdx = GetCommandClassId(ccStr); if (_include) { m_supportedCommandClasses[ccIdx >> 5] |= (1u << (ccIdx & 0x1f)); } else { m_supportedCommandClasses[ccIdx >> 5] &= ~(1u << (ccIdx & 0x1f)); } } } } //----------------------------------------------------------------------------- // // Convert a command class name (e.g COMMAND_CLASS_BASIC) into its 8-bit ID //----------------------------------------------------------------------------- uint8 CommandClasses::GetCommandClassId(string const& _name) { string upperName = ToUpper(_name); map::iterator it = m_namesToIDs.find(upperName); if (it != m_namesToIDs.end()) { return it->second; } return 0xff; } //----------------------------------------------------------------------------- // // return a list of Advertised CommandClasses //----------------------------------------------------------------------------- std::list CommandClasses::GetAdvertisedCommandClasses() { CommandClasses& cc = Get(); return cc.m_advertisedCommandClasses; } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Association.cpp0000644000175200017520000003164014032142455020410 00000000000000//----------------------------------------------------------------------------- // // Association.cpp // // Implementation of the Z-Wave COMMAND_CLASS_ASSOCIATION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "tinyxml.h" #include "command_classes/CommandClasses.h" #include "command_classes/Association.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "Node.h" #include "Group.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace CC { enum AssociationCmd { AssociationCmd_Set = 0x01, AssociationCmd_Get = 0x02, AssociationCmd_Report = 0x03, AssociationCmd_Remove = 0x04, AssociationCmd_GroupingsGet = 0x05, AssociationCmd_GroupingsReport = 0x06 }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Association::Association(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_queryAll(false), m_numGroups(0) { SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Read the saved association data //----------------------------------------------------------------------------- void Association::ReadXML(TiXmlElement const* _ccElement) { CommandClass::ReadXML(_ccElement); TiXmlElement const* associationsElement = _ccElement->FirstChildElement(); while (associationsElement) { char const* str = associationsElement->Value(); if (str && !strcmp(str, "Associations")) { int intVal; if (TIXML_SUCCESS == associationsElement->QueryIntAttribute("num_groups", &intVal)) { m_numGroups = (uint8) intVal; } TiXmlElement const* groupElement = associationsElement->FirstChildElement(); while (groupElement) { if (Node* node = GetNodeUnsafe()) { Group* group = new Group(GetHomeId(), GetNodeId(), groupElement); node->AddGroup(group); } groupElement = groupElement->NextSiblingElement(); } break; } associationsElement = associationsElement->NextSiblingElement(); } } //----------------------------------------------------------------------------- // // Save the association data //----------------------------------------------------------------------------- void Association::WriteXML(TiXmlElement* _ccElement) { CommandClass::WriteXML(_ccElement); if (Node* node = GetNodeUnsafe()) { TiXmlElement* associationsElement = new TiXmlElement("Associations"); char str[8]; snprintf(str, 8, "%d", m_numGroups); associationsElement->SetAttribute("num_groups", str); _ccElement->LinkEndChild(associationsElement); node->WriteGroups(associationsElement); } } //----------------------------------------------------------------------------- // // Nothing to do for Association //----------------------------------------------------------------------------- bool Association::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { // Request the supported group info return RequestValue(_requestFlags, 0, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Nothing to do for Association //----------------------------------------------------------------------------- bool Association::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (_instance != 1) { // This command class doesn't work with multiple instances return false; } // Request the supported group info Msg* msg = new Msg("AssociationCmd_GroupingsGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(AssociationCmd_GroupingsGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } //----------------------------------------------------------------------------- // // Request the contents of each group in turn //----------------------------------------------------------------------------- void Association::RequestAllGroups(uint32 const _requestFlags) { m_queryAll = true; // Request the contents of the individual groups in turn. if (m_numGroups == 0xff) { // We start with group 255, and will then move to group 1, 2 etc and stop when we find a group with a maxAssociations of zero. Log::Write(LogLevel_Info, GetNodeId(), "Number of association groups reported for node %d is 255, which requires special case handling.", GetNodeId()); QueryGroup(0xff, _requestFlags); } else { // We start with group 1, and will then move to group 2, 3 etc and stop when the group index is greater than m_numGroups. Log::Write(LogLevel_Info, GetNodeId(), "Number of association groups reported for node %d is %d.", GetNodeId(), m_numGroups); QueryGroup(1, _requestFlags); } } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Association::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { bool handled = false; uint32 i; if (Node* node = GetNodeUnsafe()) { if (AssociationCmd_GroupingsReport == (AssociationCmd) _data[0]) { // Retrieve the number of groups this device supports. // The groups will be queried with the session data. m_numGroups = _data[1]; Log::Write(LogLevel_Info, GetNodeId(), "Received Association Groupings report from node %d. Number of groups is %d", GetNodeId(), m_numGroups); ClearStaticRequest(StaticRequest_Values); handled = true; } else if (AssociationCmd_Report == (AssociationCmd) _data[0]) { // Get the group info uint8 groupIdx = _data[1]; uint8 maxAssociations = _data[2]; // If the maxAssociations is zero, this is not a supported group. uint8 numReportsToFollow = _data[3]; // If a device supports a lot of associations, they may come in more than one message. if (groupIdx != 0) { if (maxAssociations) { if (_length >= 5) { uint8 numAssociations = _length - 5; Log::Write(LogLevel_Info, GetNodeId(), "Received Association report from node %d, group %d, containing %d associations", GetNodeId(), groupIdx, numAssociations); if (numAssociations) { Log::Write(LogLevel_Info, GetNodeId(), " The group contains:"); for (i = 0; i < numAssociations; ++i) { Log::Write(LogLevel_Info, GetNodeId(), " Node %d", _data[i + 4]); m_pendingMembers.push_back(_data[i + 4]); } } } if (numReportsToFollow) { // We're expecting more reports for this group Log::Write(LogLevel_Info, GetNodeId(), "%d more association reports expected for node %d, group %d", numReportsToFollow, GetNodeId(), groupIdx); return true; } else { // No more reports to come for this group, so we can apply the pending list Group* group = node->GetGroup(groupIdx); if ( NULL == group) { // Group has not been created yet group = new Group(GetHomeId(), GetNodeId(), groupIdx, maxAssociations); node->AddGroup(group); } // Update the group with its new contents group->OnGroupChanged(m_pendingMembers); m_pendingMembers.clear(); } } else { // maxAssociations is zero, so we've reached the end of the query process Log::Write(LogLevel_Info, GetNodeId(), "Max associations for node %d, group %d is zero. Querying associations for this node is complete.", GetNodeId(), groupIdx); node->AutoAssociate(); m_queryAll = false; } } else { Log::Write(LogLevel_Warning, GetNodeId(), "Recieved Group 0 Assocation - Invalid"); } if (m_queryAll) { // Work out which is the next group we will query. // If we are currently on group 255, the next group will be 1. uint8 nextGroup = m_currentGroupQuery + 1; if (!nextGroup) { nextGroup = 1; } if (nextGroup <= m_numGroups) { // Query the next group QueryGroup(nextGroup, 0); } else { // We're all done Log::Write(LogLevel_Info, GetNodeId(), "Querying associations for node %d is complete.", GetNodeId()); node->AutoAssociate(); m_queryAll = false; m_currentGroupQuery = 0; } } handled = true; } } return handled; } //----------------------------------------------------------------------------- // // Request details of an association group //----------------------------------------------------------------------------- void Association::QueryGroup(uint8 _groupIdx, uint32 const _requestFlags) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Log::Write(LogLevel_Info, GetNodeId(), "Get Associations for group %d of node %d", _groupIdx, GetNodeId()); Msg* msg = new Msg("AssociationCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(AssociationCmd_Get); msg->Append(_groupIdx); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); if (m_queryAll) m_currentGroupQuery = _groupIdx; return; } else { Log::Write(LogLevel_Info, GetNodeId(), "AssociationCmd_Get Not Supported on this node"); } return; } //----------------------------------------------------------------------------- // // Add an association between devices //----------------------------------------------------------------------------- void Association::Set(uint8 _groupIdx, uint8 _targetNodeId) { Log::Write(LogLevel_Info, GetNodeId(), "Association::Set - Adding node %d to group %d of node %d", _targetNodeId, _groupIdx, GetNodeId()); Msg* msg = new Msg("AssociationCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(GetNodeId()); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(AssociationCmd_Set); msg->Append(_groupIdx); msg->Append(_targetNodeId); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } //----------------------------------------------------------------------------- // // Remove an association between devices //----------------------------------------------------------------------------- void Association::Remove(uint8 _groupIdx, uint8 _targetNodeId) { Log::Write(LogLevel_Info, GetNodeId(), "Association::Remove - Removing node %d from group %d of node %d", _targetNodeId, _groupIdx, GetNodeId()); Msg* msg = new Msg("AssociationCmd_Remove", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(GetNodeId()); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(AssociationCmd_Remove); msg->Append(_groupIdx); msg->Append(_targetNodeId); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/SoundSwitch.cpp0000644000175200017520000003171314032142455020407 00000000000000//----------------------------------------------------------------------------- // // SoundSwitch.cpp // // Implementation of the Z-Wave COMMAND_CLASS_SOUND_SWITCH // // Copyright (c) 2014 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "command_classes/CommandClasses.h" #include "command_classes/SoundSwitch.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueByte.h" namespace OpenZWave { namespace Internal { namespace CC { enum SoundSwitchCmd { SoundSwitchCmd_Tones_Number_Get = 0x01, SoundSwitchCmd_Tones_Number_Report = 0x02, SoundSwitchCmd_Tones_Info_Get = 0x03, SoundSwitchCmd_Tones_Info_Report = 0x04, SoundSwitchCmd_Tones_Config_Set = 0x05, SoundSwitchCmd_Tones_Config_Get = 0x06, soundSwitchCmd_Tones_Config_Report = 0x07, SoundSwitchCmd_Tones_Play_Set = 0x08, SoundSwitchCmd_Tones_Play_Report = 0x0A }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- SoundSwitch::SoundSwitch(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_toneCount(0) { SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool SoundSwitch::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool requests = false; if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { requests |= RequestValue(_requestFlags, ValueID_Index_SoundSwitch::Tone_Count, _instance, _queue); } if (_requestFlags & RequestFlag_Dynamic) { requests |= RequestValue(_requestFlags, ValueID_Index_SoundSwitch::Volume, _instance, _queue); } return requests; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool SoundSwitch::RequestValue(uint32 const _requestFlags, uint16 const _index, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (_index == ValueID_Index_SoundSwitch::Tone_Count) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("SoundSwitchCmd_Tones_Number_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SoundSwitchCmd_Tones_Number_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "SoundSwitchCmd_Tones_Number_Get Not Supported on this node"); } } else if (_index == ValueID_Index_SoundSwitch::Volume || _index == ValueID_Index_SoundSwitch::Default_Tone) { Msg* msg = new Msg("SoundSwitchCmd_Tones_Config_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SoundSwitchCmd_Tones_Config_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool SoundSwitch::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (SoundSwitchCmd_Tones_Number_Report == (SoundSwitchCmd) _data[0]) { m_toneCount = _data[1]; Log::Write(LogLevel_Info, GetNodeId(), "Received SoundSwitch Tone Count report: %d", m_toneCount); if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_SoundSwitch::Tone_Count))) { value->OnValueRefreshed(m_toneCount); value->Release(); } for (int i = 1; i <= m_toneCount; i++) { Msg* msg = new Msg("SoundSwitchCmd_Tones_Info_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(SoundSwitchCmd_Tones_Info_Get); msg->Append(i); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } return true; } if (SoundSwitchCmd_Tones_Info_Report == (SoundSwitchCmd) _data[0]) { uint8 index = _data[1]; uint16 duration = (_data[2] << 8) + _data[3]; string name((const char *) &_data[5], _data[4]); m_toneInfo[index].duration = duration; m_toneInfo[index].name = name; Log::Write(LogLevel_Info, GetNodeId(), "Received SoundSwitch Tone Info Report: %d - %s - %d sec", index, name.c_str(), duration); if (index == m_toneCount) { vector items; { Internal::VC::ValueList::Item item; item.m_label = "Inactive"; item.m_value = 0; items.push_back(item); } for (unsigned int i = 1; i <= m_toneCount; i++) { Internal::VC::ValueList::Item item; char str[268]; // name is max 255, duration can be max 65535 so this should be enough space snprintf(str, sizeof(str), "%s (%d sec)", m_toneInfo[i].name.c_str(), m_toneInfo[i].duration); item.m_label = str; item.m_value = i; items.push_back(item); } { Internal::VC::ValueList::Item item; item.m_label = "Default Tone"; item.m_value = 0xff; items.push_back(item); } if (Node* node = GetNodeUnsafe()) { node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_SoundSwitch::Tones, "Tones", "", false, false, m_toneCount, items, 0, 0); node->CreateValueList(ValueID::ValueGenre_Config, GetCommandClassId(), _instance, ValueID_Index_SoundSwitch::Default_Tone, "Default Tone", "", false, false, m_toneCount, items, 0, 0); } /* after we got the list of Tones, Get the Configuration */ Msg* msg = new Msg("SoundSwitchCmd_Tones_Config_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SoundSwitchCmd_Tones_Config_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } return true; } if (soundSwitchCmd_Tones_Config_Report == (SoundSwitchCmd) _data[0]) { uint8 volume = _data[1]; uint8 defaulttone = _data[2]; if (volume > 100) volume = 100; Log::Write(LogLevel_Info, GetNodeId(), "Received SoundSwitch Tone Config report - Volume: %d, defaulttone: %d", volume, defaulttone); if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_SoundSwitch::Volume))) { value->OnValueRefreshed(volume); value->Release(); } if (Internal::VC::ValueList* value = static_cast(GetValue(_instance, ValueID_Index_SoundSwitch::Default_Tone))) { value->OnValueRefreshed(defaulttone); value->Release(); } ClearStaticRequest(StaticRequest_Values); return true; } if (SoundSwitchCmd_Tones_Play_Report == (SoundSwitchCmd) _data[0]) { Log::Write(LogLevel_Info, GetNodeId(), "Received SoundSwitch Tone Play report: %d", _data[1]); if (Internal::VC::ValueList* value = static_cast(GetValue(_instance, ValueID_Index_SoundSwitch::Tones))) { value->OnValueRefreshed(_data[1]); value->Release(); } return true; } return false; } //----------------------------------------------------------------------------- // // Set a value in the Z-Wave device //----------------------------------------------------------------------------- bool SoundSwitch::SetValue(Internal::VC::Value const& _value) { bool ret = false; uint8 instance = _value.GetID().GetInstance(); uint16 index = _value.GetID().GetIndex(); if (index == ValueID_Index_SoundSwitch::Tones) { if (Internal::VC::ValueList const* value = static_cast(&_value)) { Internal::VC::ValueList::Item const *item = value->GetItem(); if (item == NULL) return false; Msg* msg = new Msg("SoundSwitchCmd_Tones_Play_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(SoundSwitchCmd_Tones_Play_Set); msg->Append(item->m_value); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } ret = true; } if (index == ValueID_Index_SoundSwitch::Volume) { uint8 volume = 0xff; if (Internal::VC::ValueByte const* value = static_cast(&_value)) { volume = value->GetValue(); if (volume > 100) { volume = 0xFF; } } Msg* msg = new Msg("SoundSwitchCmd_Tones_Config_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, instance); msg->Append(GetNodeId()); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(SoundSwitchCmd_Tones_Config_Set); msg->Append(volume); msg->Append(0); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); ret = true; } if (index == ValueID_Index_SoundSwitch::Default_Tone) { uint8 defaulttone = 0x00; if (Internal::VC::ValueList const* value = static_cast(&_value)) { Internal::VC::ValueList::Item const *item = value->GetItem(); if (item == NULL) return false; defaulttone = item->m_value; /* 0 means dont update the Default Tone 0xFF is the Default tone! */ if (defaulttone == 0xFF) defaulttone = 1; } Msg* msg = new Msg("SoundSwitchCmd_Tones_Config_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, instance); msg->Append(GetNodeId()); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(SoundSwitchCmd_Tones_Config_Set); msg->Append(0xFF); msg->Append(defaulttone); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); ret = true; } return ret; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void SoundSwitch::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueByte(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_SoundSwitch::Tone_Count, "Number of Tones", "", true, false, 0, 0); node->CreateValueByte(ValueID::ValueGenre_Config, GetCommandClassId(), _instance, ValueID_Index_SoundSwitch::Volume, "Volume", "", false, false, 100, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Language.cpp0000644000175200017520000001204014032142455017650 00000000000000//----------------------------------------------------------------------------- // // Language.cpp // // Implementation of the Z-Wave COMMAND_CLASS_LANGUAGE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/Language.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueString.h" namespace OpenZWave { namespace Internal { namespace CC { enum LanguageCmd { LanguageCmd_Set = 0x01, LanguageCmd_Get = 0x02, LanguageCmd_Report = 0x03 }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Language::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { return RequestValue(_requestFlags, 0, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool Language::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (_instance != 1) { // This command class doesn't work with multiple instances return false; } if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("LanguageCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(LanguageCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "LanguageCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Language::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (LanguageCmd_Report == (LanguageCmd) _data[0]) { char language[4]; char country[3]; language[0] = _data[1]; language[1] = _data[2]; language[2] = _data[3]; language[3] = 0; country[0] = _data[4]; country[1] = _data[5]; country[2] = 0; Log::Write(LogLevel_Info, GetNodeId(), "Received Language report: Language=%s, Country=%s", language, country); ClearStaticRequest(StaticRequest_Values); if (Internal::VC::ValueString* languageValue = static_cast(GetValue(_instance, ValueID_Index_Language::Language))) { languageValue->OnValueRefreshed(language); languageValue->Release(); } if (Internal::VC::ValueString* countryValue = static_cast(GetValue(_instance, ValueID_Index_Language::Country))) { countryValue->OnValueRefreshed(country); countryValue->Release(); } return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void Language::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueString(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_Language::Language, "Language", "", false, false, "", 0); node->CreateValueString(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_Language::Country, "Country", "", false, false, "", 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/AssociationCommandConfiguration.cpp0000644000175200017520000002512714032142455024442 00000000000000//----------------------------------------------------------------------------- // // AssociationCommandConfiguration.cpp // // Implementation of the COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/AssociationCommandConfiguration.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Group.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueBool.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueShort.h" namespace OpenZWave { namespace Internal { namespace CC { enum AssociationCommandConfigurationCmd { AssociationCommandConfigurationCmd_SupportedRecordsGet = 0x01, AssociationCommandConfigurationCmd_SupportedRecordsReport = 0x02, AssociationCommandConfigurationCmd_Set = 0x03, AssociationCommandConfigurationCmd_Get = 0x04, AssociationCommandConfigurationCmd_Report = 0x05 }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool AssociationCommandConfiguration::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Session) { return RequestValue(_requestFlags, 0, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool AssociationCommandConfiguration::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (_instance != 1) { // This command class doesn't work with multiple instances return false; } Msg* msg = new Msg("AssociationCommandConfigurationCmd_SupportedRecordsGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(AssociationCommandConfigurationCmd_SupportedRecordsGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } //----------------------------------------------------------------------------- // // Request the command data //----------------------------------------------------------------------------- void AssociationCommandConfiguration::RequestCommands(uint8 const _groupIdx, uint8 const _nodeId) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("AssociationCommandConfigurationCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(AssociationCommandConfigurationCmd_Get); msg->Append(_groupIdx); msg->Append(_nodeId); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } else { Log::Write(LogLevel_Info, GetNodeId(), "AssociationCommandConfigurationCmd_Get Not Supported on this node"); } } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool AssociationCommandConfiguration::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (AssociationCommandConfigurationCmd_SupportedRecordsReport == (AssociationCommandConfigurationCmd) _data[0]) { uint8 maxCommandLength = _data[1] >> 2; bool commandsAreValues = ((_data[1] & 0x02) != 0); bool commandsAreConfigurable = ((_data[1] & 0x01) != 0); int16 numFreeCommands = (((int16) _data[2]) << 16) | (int16) _data[3]; int16 maxCommands = (((int16) _data[4]) << 16) | (int16) _data[5]; Log::Write(LogLevel_Info, GetNodeId(), "Received AssociationCommandConfiguration Supported Records Report:"); Log::Write(LogLevel_Info, GetNodeId(), " Maximum command length = %d bytes", maxCommandLength); Log::Write(LogLevel_Info, GetNodeId(), " Maximum number of commands = %d", maxCommands); Log::Write(LogLevel_Info, GetNodeId(), " Number of free commands = %d", numFreeCommands); Log::Write(LogLevel_Info, GetNodeId(), " Commands are %s and are %s", commandsAreValues ? "values" : "not values", commandsAreConfigurable ? "configurable" : "not configurable"); Internal::VC::ValueBool* valueBool; Internal::VC::ValueByte* valueByte; Internal::VC::ValueShort* valueShort; if ((valueByte = static_cast(GetValue(_instance, ValueID_Index_AssociationCommandConfiguration::MaxCommandLength)))) { valueByte->OnValueRefreshed(maxCommandLength); valueByte->Release(); } if ((valueBool = static_cast(GetValue(_instance, ValueID_Index_AssociationCommandConfiguration::CommandsAreValues)))) { valueBool->OnValueRefreshed(commandsAreValues); valueBool->Release(); } if ((valueBool = static_cast(GetValue(_instance, ValueID_Index_AssociationCommandConfiguration::CommandsAreConfigurable)))) { valueBool->OnValueRefreshed(commandsAreConfigurable); valueBool->Release(); } if ((valueShort = static_cast(GetValue(_instance, ValueID_Index_AssociationCommandConfiguration::NumFreeCommands)))) { valueShort->OnValueRefreshed(numFreeCommands); valueShort->Release(); } if ((valueShort = static_cast(GetValue(_instance, ValueID_Index_AssociationCommandConfiguration::MaxCommands)))) { valueShort->OnValueRefreshed(maxCommands); valueShort->Release(); } return true; } if (AssociationCommandConfigurationCmd_Report == (AssociationCommandConfigurationCmd) _data[0]) { uint8 groupIdx = _data[1]; uint8 nodeIdx = _data[2]; bool firstReports = ((_data[3] & 0x80) != 0); // True if this is the first message containing commands for this group and node. uint8 numReports = _data[3] & 0x0f; Log::Write(LogLevel_Info, GetNodeId(), "Received AssociationCommandConfiguration Report from:"); Log::Write(LogLevel_Info, GetNodeId(), " Commands for node %d in group %d,", nodeIdx, groupIdx); if (Node* node = GetNodeUnsafe()) { Group* group = node->GetGroup(groupIdx); if ( NULL == group) { if (firstReports) { // This is the first report message, so we should clear any existing command data group->ClearCommands(nodeIdx); } uint8 const* start = &_data[4]; for (uint8 i = 0; i < numReports; ++i) { uint8 length = start[0]; group->AddCommand(nodeIdx, length, start + 1); start += length; } } } return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void AssociationCommandConfiguration::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueByte(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_AssociationCommandConfiguration::MaxCommandLength, "Max Command Length", "", true, false, 0, 0); node->CreateValueBool(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_AssociationCommandConfiguration::CommandsAreValues, "Commands are Values", "", true, false, false, 0); node->CreateValueBool(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_AssociationCommandConfiguration::CommandsAreConfigurable, "Commands are Configurable", "", true, false, false, 0); node->CreateValueShort(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_AssociationCommandConfiguration::NumFreeCommands, "Free Commands", "", true, false, 0, 0); node->CreateValueShort(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_AssociationCommandConfiguration::MaxCommands, "Max Commands", "", true, false, 0, 0); } } //----------------------------------------------------------------------------- // // Set a command for the association //----------------------------------------------------------------------------- void AssociationCommandConfiguration::SetCommand(uint8 const _groupIdx, uint8 const _nodeId, uint8 const _length, uint8 const* _data) { Msg* msg = new Msg("AssociationCommandConfigurationCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(_length + 5); msg->Append(GetCommandClassId()); msg->Append(AssociationCommandConfigurationCmd_Set); msg->Append(_groupIdx); msg->Append(_nodeId); msg->Append(_length); for (uint8 i = 0; i < _length; ++i) { msg->Append(_data[i]); } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/NoOperation.cpp0000644000175200017520000000523114032142455020366 00000000000000//----------------------------------------------------------------------------- // // NoOperation.cpp // // Implementation of the Z-Wave COMMAND_CLASS_NO_OPERATION // // Copyright (c) 2012 Greg Satz // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/NoOperation.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace CC { //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool NoOperation::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { // We have received a no operation from the Z-Wave device. Log::Write(LogLevel_Info, GetNodeId(), "Received NoOperation command from node %d", GetNodeId()); return true; } //----------------------------------------------------------------------------- // // Send a No Operation message class. //----------------------------------------------------------------------------- void NoOperation::Set(bool const _route, Driver::MsgQueue _queue // = Driver::MsgQueue_NoOp ) { Log::Write(LogLevel_Info, GetNodeId(), "NoOperation::Set - Routing=%s", _route ? "true" : "false"); Msg* msg = new Msg("NoOperation_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(0); if (_route) msg->Append(GetDriver()->GetTransmitOptions()); else msg->Append( TRANSMIT_OPTION_ACK | TRANSMIT_OPTION_NO_ROUTE); GetDriver()->SendMsg(msg, _queue); } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/SwitchBinary.cpp0000644000175200017520000002330614032142455020542 00000000000000//----------------------------------------------------------------------------- // // SwitchBinary.cpp // // Implementation of the Z-Wave COMMAND_CLASS_SWITCH_BINARY // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // // spec: http://zwavepublic.com/sites/default/files/command_class_specs_2017A/SDS13781-3%20Z-Wave%20Application%20Command%20Class%20Specification.pdf // pp. 78ff //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/SwitchBinary.h" #include "command_classes/WakeUp.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "Node.h" #include "platform/Log.h" #include "value_classes/ValueBool.h" #include "value_classes/ValueInt.h" namespace OpenZWave { namespace Internal { namespace CC { enum SwitchBinaryCmd { SwitchBinaryCmd_Set = 0x01, SwitchBinaryCmd_Get = 0x02, SwitchBinaryCmd_Report = 0x03 }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool SwitchBinary::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Dynamic) { return RequestValue(_requestFlags, ValueID_Index_SwitchBinary::Level, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool SwitchBinary::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("SwitchBinaryCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SwitchBinaryCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "SwitchBinaryCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool SwitchBinary::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (SwitchBinaryCmd_Report == (SwitchBinaryCmd) _data[0]) { Log::Write(LogLevel_Info, GetNodeId(), "Received SwitchBinary report from node %d: level=%s", GetNodeId(), _data[1] ? "On" : "Off"); // data[1] => Switch state if (Internal::VC::ValueBool* value = static_cast(GetValue(_instance, ValueID_Index_SwitchBinary::Level))) { if (GetVersion() >= 2 && _length >= 4) value->SetTargetValue(_data[2] != 0, _data[3]); value->OnValueRefreshed(_data[1] != 0); value->Release(); } if (GetVersion() >= 2) { // data[2] => target state if (Internal::VC::ValueBool* value = static_cast(GetValue(_instance, ValueID_Index_SwitchBinary::TargetState))) { value->OnValueRefreshed(_data[2] != 0); value->Release(); } // data[3] might be duration if (_length > 3) { if (Internal::VC::ValueInt* value = static_cast(GetValue(_instance, ValueID_Index_SwitchBinary::Duration))) { value->OnValueRefreshed(decodeDuration(_data[3])); value->Release(); } } } return true; } return false; } //----------------------------------------------------------------------------- // // Set the state of the switch //----------------------------------------------------------------------------- bool SwitchBinary::SetValue(Internal::VC::Value const& _value) { bool res = false; uint8 instance = _value.GetID().GetInstance(); switch (_value.GetID().GetIndex()) { case ValueID_Index_SwitchBinary::Level: { if (Internal::VC::ValueBool* value = static_cast(GetValue(instance, ValueID_Index_SwitchBinary::Level))) { res = SetState(instance, (static_cast(&_value))->GetValue()); value->Release(); } break; } case ValueID_Index_SwitchBinary::Duration: { if (Internal::VC::ValueInt* value = static_cast(GetValue(instance, ValueID_Index_SwitchBinary::Duration))) { value->OnValueRefreshed((static_cast(&_value))->GetValue()); value->Release(); } res = true; break; } } return res; } //----------------------------------------------------------------------------- // // Update class values based in BASIC mapping //----------------------------------------------------------------------------- void SwitchBinary::SetValueBasic(uint8 const _instance, uint8 const _value) { // Send a request for new value to synchronize it with the BASIC set/report. // In case the device is sleeping, we set the value anyway so the BASIC set/report // stays in sync with it. We must be careful mapping the uint8 BASIC value // into a class specific value. // When the device wakes up, the real requested value will be retrieved. RequestValue(0, 0, _instance, Driver::MsgQueue_Send); if (Node* node = GetNodeUnsafe()) { if (Internal::CC::WakeUp* wakeUp = static_cast(node->GetCommandClass(Internal::CC::WakeUp::StaticGetCommandClassId()))) { if (!wakeUp->IsAwake()) { if (Internal::VC::ValueBool* value = static_cast(GetValue(_instance, 0))) { value->OnValueRefreshed(_value != 0); value->Release(); } } } } } //----------------------------------------------------------------------------- // // Set a new state for the switch //----------------------------------------------------------------------------- bool SwitchBinary::SetState(uint8 const _instance, bool const _state) { uint8 const nodeId = GetNodeId(); uint8 const targetValue = _state ? 0xff : 0; Log::Write(LogLevel_Info, nodeId, "SwitchBinary::Set - Setting to %s", _state ? "On" : "Off"); Msg* msg = new Msg("SwitchBinaryCmd_Set", nodeId, REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _instance); msg->Append(nodeId); if (GetVersion() >= 2) { Internal::VC::ValueInt* durationValue = static_cast(GetValue(_instance, ValueID_Index_SwitchBinary::Duration)); uint32 duration = durationValue->GetValue(); durationValue->Release(); if (duration > 7620) Log::Write(LogLevel_Info, GetNodeId(), " Duration: Device Default"); else if (duration > 0x7F) Log::Write(LogLevel_Info, GetNodeId(), " Rouding to %d Minutes (over 127 seconds)", encodeDuration(duration)-0x79); else Log::Write(LogLevel_Info, GetNodeId(), " Duration: %d seconds", duration); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(SwitchBinaryCmd_Set); msg->Append(targetValue); msg->Append(encodeDuration(duration)); } else { msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(SwitchBinaryCmd_Set); msg->Append(targetValue); } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void SwitchBinary::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { if (GetVersion() >= 2) { node->CreateValueInt(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_SwitchBinary::Duration, "Transition Duration", "Sec", false, false, -1, 0); node->CreateValueBool(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_SwitchBinary::TargetState, "Target State", "", true, false, true, 0); } node->CreateValueBool(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_SwitchBinary::Level, "Switch", "", false, false, false, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/SensorMultilevel.cpp0000644000175200017520000002726614032142455021461 00000000000000//----------------------------------------------------------------------------- // // SensorMultilevel.cpp // // Implementation of the Z-Wave COMMAND_CLASS_SENSOR_MULTILEVEL // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/SensorMultilevel.h" #include "command_classes/MultiInstance.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "SensorMultiLevelCCTypes.h" #include "platform/Log.h" #include "value_classes/ValueDecimal.h" namespace OpenZWave { namespace Internal { namespace CC { enum SensorMultilevelCmd { SensorMultilevelCmd_SupportedGet = 0x01, SensorMultilevelCmd_SupportedReport = 0x02, SensorMultiLevelCmd_SupportedGetScale = 0x03, SensorMultiLevelCmd_SupportedReportScale = 0x06, SensorMultilevelCmd_Get = 0x04, SensorMultilevelCmd_Report = 0x05 }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool SensorMultilevel::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool res = false; if (GetVersion() > 4) { if (_requestFlags & RequestFlag_Static) { /* for Versions 5 and Above * Send a Supported Get. When we get the Reply * We will send a SupportedScaleGet Message */ Msg* msg = new Msg("SensorMultilevelCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SensorMultilevelCmd_SupportedGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); res = true; } } else { if (_requestFlags & RequestFlag_Static) { /* For Versions 1-4 ** Set a Get Message - The Reply will create our ValueID */ Msg* msg = new Msg("SensorMultilevelCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SensorMultilevelCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); res = true; } } if (_requestFlags & RequestFlag_Dynamic) { res |= RequestValue(_requestFlags, 0, _instance, _queue); } return res; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool SensorMultilevel::RequestValue(uint32 const _requestFlags, uint16 const _index, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { bool res = false; if (!m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Log::Write(LogLevel_Info, GetNodeId(), "SensorMultilevelCmd_Get Not Supported on this node"); return false; } /* if Index is 0, then its a being called from RequestState * so we just get all possible Sensor Values */ if (_index == 0) { if (GetVersion() < 5) { Msg* msg = new Msg("SensorMultilevelCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SensorMultilevelCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); res = true; } else { for (uint8 i = 1; i < 255; i++) { Internal::VC::Value* value = GetValue(_instance, i); if (value != NULL) { uint8_t scale = 0; /* get the Default Scale they want */ Internal::VC::ValueList *requestedScale = static_cast(GetValue(_instance, i+255)); if (requestedScale) { const Internal::VC::ValueList::Item *item = requestedScale->GetItem(); if (item) scale = ((item->m_value & 0x03) << 3); requestedScale->Release(); } value->Release(); Msg* msg = new Msg("SensorMultilevelCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(SensorMultilevelCmd_Get); msg->Append(i); msg->Append(scale); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); res = true; } } } return res; } else if (_index < 256) { Internal::VC::Value* value = GetValue(_instance, _index); if (value != NULL) { uint8_t scale = 0; /* get the Default Scale they want */ Internal::VC::ValueList *requestedScale = static_cast(GetValue(_instance, _index+255)); if (requestedScale) { const Internal::VC::ValueList::Item *item = requestedScale->GetItem(); if (item) scale = ((item->m_value & 0x03) << 3); requestedScale->Release(); } value->Release(); Msg* msg = new Msg("SensorMultilevelCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(SensorMultilevelCmd_Get); msg->Append((uint8_t)(_index & 0xFF)); msg->Append(scale); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool SensorMultilevel::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (SensorMultilevelCmd_SupportedReport == (SensorMultilevelCmd) _data[0]) { string msg = ""; if (GetNodeUnsafe()) { for (uint8 i = 1; i <= (_length - 2); i++) { for (uint8 j = 0; j < 8; j++) { if (_data[i] & (1 << j)) { uint32_t sensorType = ((i - 1) * 8) + j + 1; Log::Write(LogLevel_Info, GetNodeId(), "Received SensorMultiLevel supported report from node %d: %s (%d)", GetNodeId(), SensorMultiLevelCCTypes::Get()->GetSensorName(sensorType).c_str(), sensorType); Msg* msg = new Msg("SensorMultiLevelCmd_SupportedGetScale", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(SensorMultiLevelCmd_SupportedGetScale); msg->Append(sensorType); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue::MsgQueue_Send); } } } } return true; } else if (SensorMultiLevelCmd_SupportedReportScale == (SensorMultilevelCmd) _data[0]) { uint32_t sensorType = _data[1]; int8_t defaultScale = -1; vector items; for (int i = 0; i <= 3; i++) { if ((_data[2] & 0x07) & (1 << i)) { uint8 sensorScale = i; if (defaultScale == -1) defaultScale = sensorScale; Log::Write(LogLevel_Info, GetNodeId(), "Received SensorMultiLevel supported Scale report from node %d for Sensor %s: %s (%d)", GetNodeId(), SensorMultiLevelCCTypes::Get()->GetSensorName(sensorType).c_str(), SensorMultiLevelCCTypes::Get()->GetSensorUnit(sensorType, sensorScale).c_str(), sensorScale); Internal::VC::ValueList::Item item; item.m_label = SensorMultiLevelCCTypes::Get()->GetSensorUnitName(sensorType, sensorScale); item.m_value = sensorScale; items.push_back(item); } } Log::Write(LogLevel_Info, GetNodeId(), "Setting SensorMultiLevel Default Scale to: %s (%d)", SensorMultiLevelCCTypes::Get()->GetSensorUnit(sensorType, defaultScale).c_str(), defaultScale); if (Node* node = GetNodeUnsafe()) { node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, sensorType, SensorMultiLevelCCTypes::Get()->GetSensorName(sensorType), SensorMultiLevelCCTypes::Get()->GetSensorUnit(sensorType, defaultScale), true, false, "0.0", 0); node->CreateValueList(ValueID::ValueGenre_System, GetCommandClassId(), _instance, sensorType+255, SensorMultiLevelCCTypes::Get()->GetSensorName(sensorType).append(" Units").c_str(), "", false, false, 1, items, 0, 0); Internal::VC::ValueList *value = static_cast(GetValue(_instance, sensorType+255)); if (value) value->SetByLabel(SensorMultiLevelCCTypes::Get()->GetSensorUnit(sensorType, defaultScale)); } return true; } else if (SensorMultilevelCmd_Report == (SensorMultilevelCmd) _data[0]) { uint8 scale; uint8 precision = 0; uint8 sensorType = _data[1]; string valueStr = ExtractValue(&_data[2], &scale, &precision); Node* node = GetNodeUnsafe(); if (node != NULL) { Internal::VC::ValueDecimal* value = static_cast(GetValue(_instance, sensorType)); if (value == NULL) { node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, sensorType, SensorMultiLevelCCTypes::Get()->GetSensorName(sensorType), "", true, false, "0.0", 0); value = static_cast(GetValue(_instance, sensorType)); } value->SetUnits(SensorMultiLevelCCTypes::Get()->GetSensorUnit(sensorType, scale)); Log::Write(LogLevel_Info, GetNodeId(), "Received SensorMultiLevel report from node %d, instance %d, %s: value=%s%s", GetNodeId(), _instance, SensorMultiLevelCCTypes::Get()->GetSensorName(sensorType).c_str(), valueStr.c_str(), value->GetUnits().c_str()); if (value->GetPrecision() != precision) { value->SetPrecision(precision); } value->OnValueRefreshed(valueStr); value->Release(); return true; } } return false; } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/NodeNaming.cpp0000644000175200017520000004361714032142455020162 00000000000000//----------------------------------------------------------------------------- // // NodeNaming.cpp // // Implementation of the Z-Wave COMMAND_CLASS_NODE_NAMING // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/NodeNaming.h" #include "command_classes/Association.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "Notification.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace CC { enum NodeNamingCmd { NodeNamingCmd_Set = 0x01, NodeNamingCmd_Get = 0x02, NodeNamingCmd_Report = 0x03, NodeNamingCmd_LocationSet = 0x04, NodeNamingCmd_LocationGet = 0x05, NodeNamingCmd_LocationReport = 0x06 }; enum StringEncoding { StringEncoding_ASCII = 0, StringEncoding_ExtendedASCII, StringEncoding_UTF16 }; // Mapping of characters 0x80 and above to Unicode. uint16 const c_extendedAsciiToUnicode[] = { 0x20ac, // 0x80 - Euro Sign 0x0081, // 0x81 - 0x201a, // 0x82 - Single Low-9 Quotation Mark 0x0192, // 0x83 - Latin Small Letter F With Hook 0x201e, // 0x84 - Double Low-9 Quotation Mark 0x2026, // 0x85 - Horizontal Ellipsis 0x2020, // 0x86 - Dagger 0x2021, // 0x87 - Double Dagger 0x02c6, // 0x88 - Modifier Letter Circumflex Accent 0x2030, // 0x89 - Per Mille Sign 0x0160, // 0x8a - Latin Capital Letter S With Caron 0x2039, // 0x8b - Single Left-Pointing Angle Quotation Mark 0x0152, // 0x8c - Latin Capital Ligature Oe 0x008d, // 0x8d - 0x017d, // 0x8e - Latin Capital Letter Z With Caron 0x008f, // 0x8f - 0x0090, // 0x90 - 0x2018, // 0x91 - Left Single Quotation Mark 0x2019, // 0x92 - Right Single Quotation Mark 0x201c, // 0x93 - Left Double Quotation Mark 0x201d, // 0x94 - Right Double Quotation Mark 0x2022, // 0x95 - Bullet 0x2013, // 0x96 - En Dash 0x2014, // 0x97 - Em Dash 0x02dc, // 0x98 - Small Tilde 0x2122, // 0x99 - Trade Mark Sign 0x0161, // 0x9a - Latin Small Letter S With Caron 0x203a, // 0x9b - Single Right-Pointing Angle Quotation Mark 0x0153, // 0x9c - Latin Small Ligature Oe 0x009d, // 0x9d - 0x017e, // 0x9e - Latin Small Letter Z With Caron 0x0178, // 0x9f - Latin Capital Letter Y With Diaeresis 0x00a0, // 0xa0 - No-Break Space 0x00a1, // 0xa1 - Inverted Exclamation Mark 0x00a2, // 0xa2 - Cent Sign 0x00a3, // 0xa3 - Pound Sign 0x00a4, // 0xa4 - Currency Sign 0x00a5, // 0xa5 - Yen Sign 0x00a6, // 0xa6 - Broken Bar 0x00a7, // 0xa7 - Section Sign 0x00a8, // 0xa8 - Diaeresis 0x00a9, // 0xa9 - Copyright Sign 0x00aa, // 0xaa - Feminine Ordinal Indicator 0x00ab, // 0xab - Left-Pointing Double Angle Quotation Mark 0x00ac, // 0xac - Not Sign 0x00ad, // 0xad - Soft Hyphen 0x00ae, // 0xae - Registered Sign 0x00af, // 0xaf - Macron 0x00b0, // 0xb0 - Degree Sign 0x00b1, // 0xb1 - Plus-Minus Sign 0x00b2, // 0xb2 - Superscript Two 0x00b3, // 0xb3 - Superscript Three 0x00b4, // 0xb4 - Acute Accent 0x00b5, // 0xb5 - Micro Sign 0x00b6, // 0xb6 - Pilcrow Sign 0x00b7, // 0xb7 - Middle Dot 0x00b8, // 0xb8 - Cedilla 0x00b9, // 0xb9 - Superscript One 0x00ba, // 0xba - Masculine Ordinal Indicator 0x00bb, // 0xbb - Right-Pointing Double Angle Quotation Mark 0x00bc, // 0xbc - Vulgar Fraction One Quarter 0x00bd, // 0xbd - Vulgar Fraction One Half 0x00be, // 0xbe - Vulgar Fraction Three Quarters 0x00bf, // 0xbf - Inverted Question Mark 0x00c0, // 0xc0 - Latin Capital Letter A With Grave 0x00c1, // 0xc1 - Latin Capital Letter A With Acute 0x00c2, // 0xc2 - Latin Capital Letter A With Circumflex 0x00c3, // 0xc3 - Latin Capital Letter A With Tilde 0x00c4, // 0xc4 - Latin Capital Letter A With Diaeresis 0x00c5, // 0xc5 - Latin Capital Letter A With Ring Above 0x00c6, // 0xc6 - Latin Capital Ligature Ae 0x00c7, // 0xc7 - Latin Capital Letter C With Cedilla 0x00c8, // 0xc8 - Latin Capital Letter E With Grave 0x00c9, // 0xc9 - Latin Capital Letter E With Acute 0x00ca, // 0xca - Latin Capital Letter E With Circumflex 0x00cb, // 0xcb - Latin Capital Letter E With Diaeresis 0x00cc, // 0xcc - Latin Capital Letter I With Grave 0x00cd, // 0xcd - Latin Capital Letter I With Acute 0x00ce, // 0xce - Latin Capital Letter I With Circumflex 0x00cf, // 0xcf - Latin Capital Letter I With Diaeresis 0x00d0, // 0xd0 - Latin Capital Letter Eth 0x00d1, // 0xd1 - Latin Capital Letter N With Tilde 0x00d2, // 0xd2 - Latin Capital Letter O With Grave 0x00d3, // 0xd3 - Latin Capital Letter O With Acute 0x00d4, // 0xd4 - Latin Capital Letter O With Circumflex 0x00d5, // 0xd5 - Latin Capital Letter O With Tilde 0x00d6, // 0xd6 - Latin Capital Letter O With Diaeresis 0x00d7, // 0xd7 - Multiplication Sign 0x00d8, // 0xd8 - Latin Capital Letter O With Stroke 0x00d9, // 0xd9 - Latin Capital Letter U With Grave 0x00da, // 0xda - Latin Capital Letter U With Acute 0x00db, // 0xdb - Latin Capital Letter U With Circumflex 0x00dc, // 0xdc - Latin Capital Letter U With Diaeresis 0x00dd, // 0xdd - Latin Capital Letter Y With Acute 0x00de, // 0xde - Latin Capital Letter Thorn 0x00df, // 0xdf - Latin Small Letter Sharp S 0x00e0, // 0xe0 - Latin Small Letter A With Grave 0x00e1, // 0xe1 - Latin Small Letter A With Acute 0x00e2, // 0xe2 - Latin Small Letter A With Circumflex 0x00e3, // 0xe3 - Latin Small Letter A With Tilde 0x00e4, // 0xe4 - Latin Small Letter A With Diaeresis 0x00e5, // 0xe5 - Latin Small Letter A With Ring Above 0x00e6, // 0xe6 - Latin Small Ligature Ae 0x00e7, // 0xe7 - Latin Small Letter C With Cedilla 0x00e8, // 0xe8 - Latin Small Letter E With Grave 0x00e9, // 0xe9 - Latin Small Letter E With Acute 0x00ea, // 0xea - Latin Small Letter E With Circumflex 0x00eb, // 0xeb - Latin Small Letter E With Diaeresis 0x00ec, // 0xec - Latin Small Letter I With Grave 0x00ed, // 0xed - Latin Small Letter I With Acute 0x00ee, // 0xee - Latin Small Letter I With Circumflex 0x00ef, // 0xef - Latin Small Letter I With Diaeresis 0x00f0, // 0xf0 - Latin Small Letter Eth 0x00f1, // 0xf1 - Latin Small Letter N With Tilde 0x00f2, // 0xf2 - Latin Small Letter O With Grave 0x00f3, // 0xf3 - Latin Small Letter O With Acute 0x00f4, // 0xf4 - Latin Small Letter O With Circumflex 0x00f5, // 0xf5 - Latin Small Letter O With Tilde 0x00f6, // 0xf6 - Latin Small Letter O With Diaeresis 0x00f7, // 0xf7 - Division Sign 0x00f8, // 0xf8 - Latin Small Letter O With Stroke 0x00f9, // 0xf9 - Latin Small Letter U With Grave 0x00fa, // 0xfa - Latin Small Letter U With Acute 0x00fb, // 0xfb - Latin Small Letter U With Circumflex 0x00fc, // 0xfc - Latin Small Letter U With Diaeresis 0x00fd, // 0xfd - Latin Small Letter Y With Acute 0x00fe, // 0xfe - Latin Small Letter Thorn 0x00ff // 0xff - Latin Small Letter Y With Diaeresis }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool NodeNaming::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool res = false; if (_requestFlags & RequestFlag_Session) { if (Node* node = GetNodeUnsafe()) { if (node->m_nodeName == "") { // If we don't already have a user-defined name, fetch it from the device res |= RequestValue(_requestFlags, NodeNamingCmd_Get, _instance, _queue); } if (node->m_location == "") { // If we don't already have a user-defined location, fetch it from the device res |= RequestValue(_requestFlags, NodeNamingCmd_LocationGet, _instance, _queue); } } } return res; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool NodeNaming::RequestValue(uint32 const _requestFlags, uint16 const _getTypeEnum, uint8 const _instance, Driver::MsgQueue const _queue) { if (_instance != 1) { // This command class doesn't work with multiple instances return false; } Msg* msg; if (_getTypeEnum == NodeNamingCmd_Get) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { msg = new Msg("NodeNamingCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(NodeNamingCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "NodeNamingCmd_Get Not Supported on this node"); } return false; } if (_getTypeEnum == NodeNamingCmd_LocationGet) { // If we don't already have a user-defined name, fetch it from the device msg = new Msg("NodeNamingCmd_LocationGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(NodeNamingCmd_LocationGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool NodeNaming::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { bool updated = false; if (Node* node = GetNodeUnsafe()) { if (NodeNamingCmd_Report == (NodeNamingCmd) _data[0]) { string name = ExtractString(_data, _length); if (node->m_nodeName == "") { // We only overwrite the name if it is empty node->m_nodeName = name; Log::Write(LogLevel_Info, GetNodeId(), "Received the name: %s.", name.c_str()); updated = true; } } else if (NodeNamingCmd_LocationReport == (NodeNamingCmd) _data[0]) { string location = ExtractString(_data, _length); if (node->m_location == "") { // We only overwrite the location if it is empty node->m_location = location; Log::Write(LogLevel_Info, GetNodeId(), "Received the location: %s.", location.c_str()); updated = true; } } } if (updated) { Notification* notification = new Notification(Notification::Type_NodeNaming); notification->SetHomeAndNodeIds(GetHomeId(), GetNodeId()); GetDriver()->QueueNotification(notification); } return true; } //----------------------------------------------------------------------------- // // Set the name in the device //----------------------------------------------------------------------------- void NodeNaming::SetName(string const& _name) { size_t length = _name.size(); if (length > 16) { length = 16; } Log::Write(LogLevel_Info, GetNodeId(), "NodeNaming::Set - Naming to '%s'", _name.c_str()); Msg* msg = new Msg("NodeNamingCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(GetNodeId()); msg->Append((uint8) (length + 3)); msg->Append(GetCommandClassId()); msg->Append(NodeNamingCmd_Set); msg->Append((uint8) StringEncoding_ASCII); for (uint32 i = 0; i < length; ++i) { msg->Append(_name[i]); } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } //----------------------------------------------------------------------------- // // Set the location in the device //----------------------------------------------------------------------------- void NodeNaming::SetLocation(string const& _location) { size_t length = _location.size(); if (length > 16) { length = 16; } Log::Write(LogLevel_Info, GetNodeId(), "NodeNaming::SetLocation - Setting location to '%s'", _location.c_str()); Msg* msg = new Msg("NodeNamingCmd_LocationSet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(GetNodeId()); msg->Append((uint8) (length + 3)); msg->Append(GetCommandClassId()); msg->Append(NodeNamingCmd_LocationSet); msg->Append((uint8) StringEncoding_ASCII); for (uint32 i = 0; i < length; ++i) { msg->Append(_location[i]); } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } //----------------------------------------------------------------------------- // // Extract a string from the report data //----------------------------------------------------------------------------- std::string ExtractString(uint8 const* _data, uint32 const _length) { uint8 i; char str[32]; uint32 pos = 0; str[0] = 0; StringEncoding encoding = (StringEncoding) (_data[1] & 0x07); if (_length >= 3) { // Get the length of the string (maximum allowed is 16 bytes) uint8 numBytes = _length - 3; if (numBytes > 16) { numBytes = 16; } switch (encoding) { case StringEncoding_ASCII: { // Copy data as-is for (i = 0; i < numBytes; ++i) { str[pos++] = _data[i + 2]; } break; } case StringEncoding_ExtendedASCII: { // Convert Extended ASCII characters to UTF-8 for (i = 0; i < numBytes; ++i) { uint8 ch = _data[i + 2]; if (ch >= 0x80) { uint16 utf16 = c_extendedAsciiToUnicode[ch - 0x80]; pos = ConvertUFT16ToUTF8(utf16, str, pos); } else { str[pos++] = (char) ch; } } break; } case StringEncoding_UTF16: { // Convert UTF-16 characters to UTF-8 for (i = 0; i < numBytes; i += 2) { uint16 utf16 = (((uint16) _data[i + 2]) << 8) | (uint16) _data[i + 3]; pos = ConvertUFT16ToUTF8(utf16, str, pos); } break; } default: { } } str[pos] = 0; } return string(str); } //----------------------------------------------------------------------------- // // Convert a UTF-16 string into UTF-8 encoding. //----------------------------------------------------------------------------- uint32 ConvertUFT16ToUTF8(uint16 _utf16, char* _buffer, uint32 pos) { static uint16 surrogate = 0; if ((surrogate != 0) && ((_utf16 & 0xdc00) == 0xdc00)) { // UTF-16 surrogate character pair converts to four UTF-8 characters. // We have the second member of the pair, so we can do the conversion now. _buffer[pos++] = (char) (((surrogate >> 7) & 0x0007) | 0x00f0); _buffer[pos++] = (char) (((surrogate >> 1) & 0x0020) | ((surrogate >> 2) & 0x000f) | 0x0090); _buffer[pos++] = (char) (((_utf16 >> 6) & 0x000f) | ((surrogate << 4) & 0x0030) | 0x0080); _buffer[pos++] = (char) ((_utf16 & 0x003f) | 0x0080); } else { surrogate = 0; if (_utf16 & 0xff80) { if (_utf16 & 0xf800) { if ((_utf16 & 0xd800) == 0xd800) { // UTF-16 surrogate character pair converts to four UTF-8 characters. // We have the first member of the pair, so we store it for next time. surrogate = _utf16; } else { // UTF-16 character can be represented by three UTF-8 characters. _buffer[pos++] = (char) ((_utf16 >> 12) | 0x00e0); _buffer[pos++] = (char) (((_utf16 >> 6) & 0x003f) | 0x0080); _buffer[pos++] = (char) ((_utf16 & 0x003f) | 0x0080); } } else { // UTF-16 character can be represented by two UTF-8 characters. _buffer[pos++] = (char) ((_utf16 >> 6) | 0x00c0); _buffer[pos++] = (char) ((_utf16 & 0x003f) | 0x0080); } } else { // UTF-16 character matches single ascii character. _buffer[pos++] = (char) _utf16; } } return pos; } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/SwitchAll.cpp0000644000175200017520000001660214032142455020027 00000000000000//----------------------------------------------------------------------------- // // SwitchAll.cpp // // Implementation of the Z-Wave COMMAND_CLASS_SWITCH_ALL // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/SwitchAll.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueList.h" namespace OpenZWave { namespace Internal { namespace CC { enum SwitchAllCmd { SwitchAllCmd_Set = 0x01, SwitchAllCmd_Get = 0x02, SwitchAllCmd_Report = 0x03, SwitchAllCmd_On = 0x04, SwitchAllCmd_Off = 0x05 }; static char const* c_switchAllStateName[] = { "Disabled", "Off Enabled", "On Enabled", "On and Off Enabled" }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool SwitchAll::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Session) { return RequestValue(_requestFlags, ValueID_Index_SwitchAll::SwitchAll, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool SwitchAll::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("SwitchAllCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SwitchAllCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "SwitchAllCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool SwitchAll::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (SwitchAllCmd_Report == (SwitchAllCmd) _data[0]) { if (Internal::VC::ValueList* value = static_cast(GetValue(_instance, ValueID_Index_SwitchAll::SwitchAll))) { value->OnValueRefreshed((int32) _data[1]); value->Release(); if (value->GetItem()) Log::Write(LogLevel_Info, GetNodeId(), "Received SwitchAll report from node %d: %s", GetNodeId(), value->GetItem()->m_label.c_str()); else Log::Write(LogLevel_Info, GetNodeId(), "Received SwitchAll report from node %d: %d", GetNodeId(), _data[1]); } return true; } return false; } //----------------------------------------------------------------------------- // // Set the device's response to SWITCH_ALL commands //----------------------------------------------------------------------------- bool SwitchAll::SetValue(Internal::VC::Value const& _value) { if (ValueID::ValueType_List == _value.GetID().GetType()) { Internal::VC::ValueList const* value = static_cast(&_value); Internal::VC::ValueList::Item const *item = value->GetItem(); if (item == NULL) return false; Log::Write(LogLevel_Info, GetNodeId(), "SwitchAll::Set - %s on node %d", item->m_label.c_str(), GetNodeId()); Msg* msg = new Msg("SwitchAllCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(SwitchAllCmd_Set); msg->Append((uint8) item->m_value); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } return false; } //----------------------------------------------------------------------------- // // Send a command to switch all devices off //----------------------------------------------------------------------------- void SwitchAll::Off(Driver* _driver, uint8 const _nodeId) { Log::Write(LogLevel_Info, _nodeId, "SwitchAll::Off (Node=%d)", _nodeId); Msg* msg = new Msg("SwitchAllCmd_Off", _nodeId, REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(_nodeId); msg->Append(2); msg->Append(StaticGetCommandClassId()); msg->Append(SwitchAllCmd_Off); msg->Append(_driver->GetTransmitOptions()); _driver->SendMsg(msg, Driver::MsgQueue_Send); } //----------------------------------------------------------------------------- // // Send a command to switch all devices on //----------------------------------------------------------------------------- void SwitchAll::On(Driver* _driver, uint8 const _nodeId) { Log::Write(LogLevel_Info, _nodeId, "SwitchAll::On (Node=%d)", _nodeId); Msg* msg = new Msg("SwitchAllCmd_On", _nodeId, REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(_nodeId); msg->Append(2); msg->Append(StaticGetCommandClassId()); msg->Append(SwitchAllCmd_On); msg->Append(_driver->GetTransmitOptions()); _driver->SendMsg(msg, Driver::MsgQueue_Send); } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void SwitchAll::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { vector items; for (int i = 0; i < 4; ++i) { Internal::VC::ValueList::Item item; item.m_label = c_switchAllStateName[i]; item.m_value = (i == 3) ? 0x000000ff : i; items.push_back(item); } node->CreateValueList(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_SwitchAll::SwitchAll, "Switch All", "", false, false, 1, items, 0, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Battery.h0000644000175200017520000000523114032142455017210 00000000000000//----------------------------------------------------------------------------- // // Battery.h // // Implementation of the Z-Wave COMMAND_CLASS_BATTERY // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Battery_H #define _Battery_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_BATTERY (0x80), a Z-Wave device command class. * \ingroup CommandClass */ class Battery: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Battery(_homeId, _nodeId); } virtual ~Battery() { } static uint8 const StaticGetCommandClassId() { return 0x80; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_BATTERY"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; bool supportsMultiInstance() override { return false; } protected: virtual void CreateVars(uint8 const _instance) override; private: Battery(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/SensorBinary.cpp0000644000175200017520000001705614032142455020557 00000000000000//----------------------------------------------------------------------------- // // SensorBinary.cpp // // Implementation of the Z-Wave COMMAND_CLASS_SENSOR_BINARY // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/SensorBinary.h" #include "command_classes/WakeUp.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueBool.h" #include "tinyxml.h" namespace OpenZWave { namespace Internal { namespace CC { enum SensorBinaryCmd { SensorBinaryCmd_Get = 0x02, SensorBinaryCmd_Report = 0x03 }; //----------------------------------------------------------------------------- // // Read node configuration data //----------------------------------------------------------------------------- void SensorBinary::ReadXML(TiXmlElement const* _ccElement) { CommandClass::ReadXML(_ccElement); TiXmlElement const* child = _ccElement->FirstChildElement(); char const* str; int index; int type; while (child) { str = child->Value(); if (str) { if (!strcmp(str, "SensorMap")) { if (TIXML_SUCCESS == child->QueryIntAttribute("index", &index) && TIXML_SUCCESS == child->QueryIntAttribute("type", &type)) { m_sensorsMap[(uint8) type] = (uint8) index; } } } child = child->NextSiblingElement(); } } //----------------------------------------------------------------------------- // // Write node configuration data //----------------------------------------------------------------------------- void SensorBinary::WriteXML(TiXmlElement* _ccElement) { CommandClass::WriteXML(_ccElement); char str[8]; for (map::iterator it = m_sensorsMap.begin(); it != m_sensorsMap.end(); it++) { TiXmlElement* sensorMapElement = new TiXmlElement("SensorMap"); _ccElement->LinkEndChild(sensorMapElement); snprintf(str, 8, "%d", it->second); sensorMapElement->SetAttribute("index", str); snprintf(str, 8, "%d", it->first); sensorMapElement->SetAttribute("type", str); } } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool SensorBinary::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Dynamic) { return RequestValue(_requestFlags, ValueID_Index_SensorBinary::Sensor_1, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool SensorBinary::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("SensorBinaryCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SensorBinaryCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "SensorBinaryCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool SensorBinary::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (SensorBinaryCmd_Report == (SensorBinaryCmd) _data[0]) { if (_length > 3) { uint8 index = m_sensorsMap[_data[2]]; Log::Write(LogLevel_Info, GetNodeId(), "Received SensorBinary report: Sensor:%d State=%s", _data[2], _data[1] ? "On" : "Off"); if (Internal::VC::ValueBool* value = static_cast(GetValue(_instance, index))) { value->OnValueRefreshed(_data[1] != 0); value->Release(); } return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "Received SensorBinary report: State=%s", _data[1] ? "On" : "Off"); if (Internal::VC::ValueBool* value = static_cast(GetValue(_instance, ValueID_Index_SensorBinary::Sensor_1))) { value->OnValueRefreshed(_data[1] != 0); value->Release(); } return true; } } return false; } //----------------------------------------------------------------------------- // // Update class values based in BASIC mapping //----------------------------------------------------------------------------- void SensorBinary::SetValueBasic(uint8 const _instance, uint8 const _value) { // Send a request for new value to synchronize it with the BASIC set/report. // In case the device is sleeping, we set the value anyway so the BASIC set/report // stays in sync with it. We must be careful mapping the uint8 BASIC value // into a class specific value. // When the device wakes up, the real requested value will be retrieved. RequestValue(0, 0, _instance, Driver::MsgQueue_Send); if (Node* node = GetNodeUnsafe()) { if (WakeUp* wakeUp = static_cast(node->GetCommandClass(WakeUp::StaticGetCommandClassId()))) { if (!wakeUp->IsAwake() || !m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { if (Internal::VC::ValueBool* value = static_cast(GetValue(_instance, 0))) { value->OnValueRefreshed(_value != 0); value->Release(); } } } } } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void SensorBinary::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueBool(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_SensorBinary::Sensor_1, "Sensor", "", true, false, false, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/UserCode.h0000644000175200017520000000716014032142455017312 00000000000000//----------------------------------------------------------------------------- // // UserCode.h // // Implementation of the Z-Wave COMMAND_CLASS_USER_CODE // // Copyright (c) 2012 Greg Satz // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _UserCode_H #define _UserCode_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_USER_CODE (0x63), a Z-Wave device command class. * \ingroup CommandClass */ class UserCode: public CommandClass { private: enum UserCodeStatus { UserCode_Available = 0x00, UserCode_Occupied = 0x01, UserCode_Reserved = 0x02, UserCode_NotAvailable = 0xfe, UserCode_Unset = 0xff }; struct UserCodeEntry { UserCodeStatus status; uint8 usercode[10]; }; public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new UserCode(_homeId, _nodeId); } virtual ~UserCode() { } static uint8 const StaticGetCommandClassId() { return 0x63; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_USER_CODE"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: UserCode(uint32 const _homeId, uint8 const _nodeId); string CodeStatus(uint8 const _byte) { switch (_byte) { case UserCode_Available: { return "Available"; } case UserCode_Occupied: { return "Occupied"; } case UserCode_Reserved: { return "Reserved"; } case UserCode_NotAvailable: { return "Not Available"; } case UserCode_Unset: { return "Unset"; } default: { return "Unknown"; } } } bool m_queryAll; // True while we are requesting all the user codes. uint16 m_currentCode; std::map m_userCode; bool m_refreshUserCodes; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Clock.cpp0000644000175200017520000001771614032142455017177 00000000000000//----------------------------------------------------------------------------- // // Clock.cpp // // Implementation of the Z-Wave COMMAND_CLASS_CLOCK // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/Clock.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueList.h" namespace OpenZWave { namespace Internal { namespace CC { enum ClockCmd { ClockCmd_Set = 0x04, ClockCmd_Get = 0x05, ClockCmd_Report = 0x06 }; static char const* c_dayNames[] = { "Invalid", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Clock::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Dynamic) { return RequestValue(_requestFlags, 0, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool Clock::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("ClockCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(ClockCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "ClockCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Clock::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (ClockCmd_Report == (ClockCmd) _data[0]) { uint8 day = _data[1] >> 5; uint8 hour = _data[1] & 0x1f; uint8 minute = _data[2]; if (day > 7) /* size of c_dayNames */ { Log::Write(LogLevel_Warning, GetNodeId(), "Day Value was greater than range. Setting to Invalid"); day = 0; } Log::Write(LogLevel_Info, GetNodeId(), "Received Clock report: %s %.2d:%.2d", c_dayNames[day], hour, minute); if (Internal::VC::ValueList* dayValue = static_cast(GetValue(_instance, ValueID_Index_Clock::Day))) { dayValue->OnValueRefreshed(day); dayValue->Release(); } if (Internal::VC::ValueByte* hourValue = static_cast(GetValue(_instance, ValueID_Index_Clock::Hour))) { hourValue->OnValueRefreshed(hour); hourValue->Release(); } if (Internal::VC::ValueByte* minuteValue = static_cast(GetValue(_instance, ValueID_Index_Clock::Minute))) { minuteValue->OnValueRefreshed(minute); minuteValue->Release(); } return true; } return false; } //----------------------------------------------------------------------------- // // Set a value in the Z-Wave device //----------------------------------------------------------------------------- bool Clock::SetValue(Internal::VC::Value const& _value) { bool ret = false; uint8 instance = _value.GetID().GetInstance(); Internal::VC::ValueList* dayValue = static_cast(GetValue(instance, ValueID_Index_Clock::Day)); Internal::VC::ValueByte* hourValue = static_cast(GetValue(instance, ValueID_Index_Clock::Hour)); Internal::VC::ValueByte* minuteValue = static_cast(GetValue(instance, ValueID_Index_Clock::Minute)); if (dayValue && hourValue && minuteValue) { if (dayValue->GetItem() == NULL) { ret = false; } else { uint8 day = dayValue->GetItem()->m_value; if (_value.GetID() == dayValue->GetID()) { Internal::VC::ValueList const * dayvaluetmp = static_cast(&_value); day = dayvaluetmp->GetItem()->m_value; dayValue->OnValueRefreshed(day); } uint8 hour = hourValue->GetValue(); if (_value.GetID() == hourValue->GetID()) { Internal::VC::ValueByte const * hourvaluetmp = static_cast(&_value); hour = hourvaluetmp->GetValue(); hourValue->OnValueRefreshed(hour); } uint8 minute = minuteValue->GetValue(); if (_value.GetID() == minuteValue->GetID()) { Internal::VC::ValueByte const * minuteValuetmp = static_cast(&_value); minute = minuteValuetmp->GetValue(); minuteValue->OnValueRefreshed(minute); } Msg* msg = new Msg("ClockCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, instance); msg->Append(GetNodeId()); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(ClockCmd_Set); msg->Append((day << 5) | hour); msg->Append(minute); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); ret = true; } } if (dayValue != NULL) { dayValue->Release(); } if (hourValue != NULL) { hourValue->Release(); } if (minuteValue != NULL) { minuteValue->Release(); } return ret; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void Clock::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { vector items; for (int i = 1; i <= 7; ++i) { Internal::VC::ValueList::Item item; item.m_label = c_dayNames[i]; item.m_value = i; items.push_back(item); } node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Clock::Day, "Day", "", false, false, 1, items, 0, 0); node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Clock::Hour, "Hour", "", false, false, 12, 0); node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Clock::Minute, "Minute", "", false, false, 0, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Association.h0000644000175200017520000000663114032142455020057 00000000000000//----------------------------------------------------------------------------- // // Association.h // // Implementation of the Z-Wave COMMAND_CLASS_ASSOCIATION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Association_H #define _Association_H #include #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_ASSOCIATION (0x85), a Z-Wave device command class. *\ingroup CommandClass */ class Association: public CommandClass { friend class OpenZWave::Group; public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Association(_homeId, _nodeId); } virtual ~Association() { } static uint8 const StaticGetCommandClassId() { return 0x85; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_ASSOCIATION"; } // From CommandClass virtual void ReadXML(TiXmlElement const* _ccElement) override; virtual void WriteXML(TiXmlElement* _ccElement) override; virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; void RequestAllGroups(uint32 const _requestFlags); void Set(uint8 const _group, uint8 const _nodeId); void Remove(uint8 const _group, uint8 const _nodeId); bool supportsMultiInstance() override { return false; } private: Association(uint32 const _homeId, uint8 const _nodeId); void QueryGroup(uint8 _groupIdx, uint32 const _requestFlags); void AutoAssociate(); bool m_queryAll; // When true, once a group has been queried, we request the next one. uint8 m_numGroups; // Number of groups supported by the device. 255 is reported by certain manufacturers and requires special handling. uint8 m_currentGroupQuery; // The Current Group we are querying for. vector m_pendingMembers; // Used to build a list of group members from multiple reports }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Version.h0000644000175200017520000000525714032142455017233 00000000000000//----------------------------------------------------------------------------- // // Version.h // // Implementation of the Z-Wave COMMAND_CLASS_VERSION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Version_H #define _Version_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_VERSION (0x86), a Z-Wave device command class. * \ingroup CommandClass */ class Version: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Version(_homeId, _nodeId); } virtual ~Version() { } static uint8 const StaticGetCommandClassId() { return 0x86; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_VERSION"; } bool RequestCommandClassVersion(CommandClass const* _commandClass); // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; bool supportsMultiInstance() override { return false; } protected: virtual void CreateVars(uint8 const _instance) override; private: Version(uint32 const _homeId, uint8 const _nodeId); }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/TimeParameters.h0000644000175200017520000000524614032142455020526 00000000000000//----------------------------------------------------------------------------- // // TimeParameters.h // // Implementation of the Z-Wave COMMAND_CLASS_TIME_PARAMETERS // // Copyright (c) 2014 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _TimeParameters_H #define _TimeParameters_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_TIME_PARAMETERS (0x8B), a Z-Wave device command class. * \ingroup CommandClass */ class TimeParameters: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new TimeParameters(_homeId, _nodeId); } virtual ~TimeParameters() { } static uint8 const StaticGetCommandClassId() { return 0x8B; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_TIME_PARAMETERS"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: TimeParameters(uint32 const _homeId, uint8 const _nodeId); }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/ManufacturerSpecific.cpp0000644000175200017520000003411414032142455022235 00000000000000//----------------------------------------------------------------------------- // // ManufacturerSpecific.cpp // // Implementation of the Z-Wave COMMAND_CLASS_MANUFACTURER_SPECIFIC // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/ManufacturerSpecific.h" #include "tinyxml.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Options.h" #include "Manager.h" #include "Driver.h" #include "ManufacturerSpecificDB.h" #include "Notification.h" #include "platform/Log.h" #include "value_classes/ValueStore.h" #include "value_classes/ValueString.h" #include "value_classes/ValueInt.h" namespace OpenZWave { namespace Internal { namespace CC { enum ManufacturerSpecificCmd { ManufacturerSpecificCmd_Get = 0x04, ManufacturerSpecificCmd_Report = 0x05, ManufacturerSpecificCmd_DeviceGet = 0x06, ManufacturerSpecificCmd_DeviceReport = 0x07 }; enum { DeviceSpecificGet_DeviceIDType_FactoryDefault = 0x00, DeviceSpecificGet_DeviceIDType_SerialNumber = 0x01, DeviceSpecificGet_DeviceIDType_PseudoRandom = 0x02, }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ManufacturerSpecific::ManufacturerSpecific(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_fileConfigRevision(0), m_loadedConfigRevision(0), m_latestConfigRevision(0) { SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool ManufacturerSpecific::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool res = false; if (_instance != 1) { /* Not applicable to get this info on multiple instances */ return res; } if (GetVersion() > 1) { if (_requestFlags & RequestFlag_Static) { { Msg* msg = new Msg("ManufacturerSpecificCmd_DeviceGet_DeviceIDType", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(ManufacturerSpecificCmd_DeviceGet); msg->Append(DeviceSpecificGet_DeviceIDType_FactoryDefault); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); } res = true; } } return res; } bool ManufacturerSpecific::Init() { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("ManufacturerSpecificCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(ManufacturerSpecificCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Query); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "ManufacturerSpecificCmd_Get Not Supported on this node"); return true; } return false; } void ManufacturerSpecific::SetProductDetails(uint16 manufacturerId, uint16 productType, uint16 productId) { string configPath = ""; std::shared_ptr product = GetDriver()->GetManufacturerSpecificDB()->getProduct(manufacturerId, productType, productId); Node *node = GetNodeUnsafe(); if (!product) { char str[64]; snprintf(str, sizeof(str), "Unknown: id=%.4x", manufacturerId); string manufacturerName = str; snprintf(str, sizeof(str), "Unknown: type=%.4x, id=%.4x", productType, productId); string productName = str; node->SetManufacturerName(manufacturerName); node->SetProductName(productName); } else { node->SetManufacturerName(product->GetManufacturerName()); node->SetProductName(product->GetProductName()); node->SetProductDetails(product); } node->SetManufacturerId(manufacturerId); node->SetProductType(productType); node->SetProductId(productId); } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool ManufacturerSpecific::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (ManufacturerSpecificCmd_Report == (ManufacturerSpecificCmd) _data[0]) { // first two bytes are manufacturer id code uint16 manufacturerId = (((uint16) _data[1]) << 8) | (uint16) _data[2]; // next four are product type and product id uint16 productType = (((uint16) _data[3]) << 8) | (uint16) _data[4]; uint16 productId = (((uint16) _data[5]) << 8) | (uint16) _data[6]; if (Node* node = GetNodeUnsafe()) { // Attempt to create the config parameters SetProductDetails(manufacturerId, productType, productId); ClearStaticRequest(StaticRequest_Values); node->m_manufacturerSpecificClassReceived = true; if (node->getConfigPath().size() > 0) { LoadConfigXML(); } Log::Write(LogLevel_Info, GetNodeId(), "Received manufacturer specific report from node %d: Manufacturer=%s, Product=%s", GetNodeId(), node->GetManufacturerName().c_str(), node->GetProductName().c_str()); Log::Write(LogLevel_Info, GetNodeId(), "Node Identity Codes: %.4x:%.4x:%.4x", manufacturerId, productType, productId); } // Notify the watchers of the name changes Notification* notification = new Notification(Notification::Type_NodeNaming); notification->SetHomeAndNodeIds(GetHomeId(), GetNodeId()); GetDriver()->QueueNotification(notification); return true; } else if (ManufacturerSpecificCmd_DeviceReport == (ManufacturerSpecificCmd) _data[0]) { uint8 deviceIDType = (_data[1] & 0x07); uint8 dataFormat = (_data[2] & 0xe0) >> 0x05; uint8 data_length = (_data[2] & 0x1f); uint8 const* deviceIDData = &_data[3]; string deviceID = ""; for (int i = 0; i < data_length; i++) { char temp_chr[32]; memset(temp_chr, 0, sizeof(temp_chr)); if (dataFormat == 0x00) { temp_chr[0] = deviceIDData[i]; } else { snprintf(temp_chr, sizeof(temp_chr), "%.2x", deviceIDData[i]); } deviceID += temp_chr; } if (deviceIDType == DeviceSpecificGet_DeviceIDType_FactoryDefault) { if (!GetValue(_instance, ValueID_Index_ManufacturerSpecific::DeviceID)) { if (Node* node = GetNodeUnsafe()) { node->CreateValueString(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_ManufacturerSpecific::DeviceID, "Device ID", "", true, false, "", 0); } } Internal::VC::ValueString *default_value = static_cast(GetValue(_instance, ValueID_Index_ManufacturerSpecific::DeviceID)); default_value->OnValueRefreshed(deviceID); default_value->Release(); Log::Write(LogLevel_Info, GetNodeId(), "Got ManufacturerSpecific FactoryDefault: %s", deviceID.c_str()); } else if (deviceIDType == DeviceSpecificGet_DeviceIDType_SerialNumber) { if (!GetValue(_instance, ValueID_Index_ManufacturerSpecific::SerialNumber)) { if (Node* node = GetNodeUnsafe()) { node->CreateValueString(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_ManufacturerSpecific::SerialNumber, "Serial Number", "", true, false, "", 0); } } Internal::VC::ValueString *serial_value = static_cast(GetValue(_instance, ValueID_Index_ManufacturerSpecific::SerialNumber)); serial_value->OnValueRefreshed(deviceID); serial_value->Release(); Log::Write(LogLevel_Info, GetNodeId(), "Got ManufacturerSpecific SerialNumber: %s", deviceID.c_str()); } return true; } return false; } //----------------------------------------------------------------------------- // // Try to find and load an XML file describing the device's config params //----------------------------------------------------------------------------- bool ManufacturerSpecific::LoadConfigXML() { if (GetNodeUnsafe()->getConfigPath().size() == 0) return false; string configPath; Options::Get()->GetOptionAsString("ConfigPath", &configPath); string filename = configPath + GetNodeUnsafe()->getConfigPath(); TiXmlDocument* doc = new TiXmlDocument(); Log::Write(LogLevel_Info, GetNodeId(), " Opening config param file %s", filename.c_str()); if (!doc->LoadFile(filename.c_str(), TIXML_ENCODING_UTF8)) { delete doc; Log::Write(LogLevel_Info, GetNodeId(), "Unable to find or load Config Param file %s", filename.c_str()); return false; } doc->SetUserData((void *) filename.c_str()); /* make sure it has the right xmlns */ TiXmlElement *product = doc->RootElement(); char const *xmlns = product->Attribute("xmlns"); if (xmlns && strcmp(xmlns, "https://github.com/OpenZWave/open-zwave")) { delete doc; Log::Write(LogLevel_Warning, GetNodeId(), "Invalid XML Namespace in %s - Ignoring", filename.c_str()); return false; } Node::QueryStage qs = GetNodeUnsafe()->GetCurrentQueryStage(); if (qs == Node::QueryStage_ManufacturerSpecific1) { GetNodeUnsafe()->ReadDeviceProtocolXML(doc->RootElement()); } else { if (!GetNodeUnsafe()->m_manufacturerSpecificClassReceived) { GetNodeUnsafe()->ReadDeviceProtocolXML(doc->RootElement()); } } GetNodeUnsafe()->ReadCommandClassesXML(doc->RootElement()); GetNodeUnsafe()->ReadMetaDataFromXML(doc->RootElement()); delete doc; return true; } //----------------------------------------------------------------------------- // // Reload previously discovered device configuration. //----------------------------------------------------------------------------- void ManufacturerSpecific::ReLoadConfigXML() { LoadConfigXML(); } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void ManufacturerSpecific::CreateVars(uint8 const _instance) { if (_instance == 1) { if (Node* node = GetNodeUnsafe()) { node->CreateValueInt(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_ManufacturerSpecific::LoadedConfig, "Loaded Config Revision", "", true, false, m_loadedConfigRevision, 0); node->CreateValueInt(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_ManufacturerSpecific::LocalConfig, "Config File Revision", "", true, false, m_fileConfigRevision, 0); node->CreateValueInt(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_ManufacturerSpecific::LatestConfig, "Latest Available Config File Revision", "", true, false, m_latestConfigRevision, 0); } } } //----------------------------------------------------------------------------- // // Set the Latest Config Revision Available for this device //----------------------------------------------------------------------------- void ManufacturerSpecific::setLatestConfigRevision(uint32 rev) { m_latestConfigRevision = rev; if (Internal::VC::ValueInt* value = static_cast(GetValue(1, ValueID_Index_ManufacturerSpecific::LatestConfig))) { value->OnValueRefreshed(rev); value->Release(); } } //----------------------------------------------------------------------------- // // Set the File Config Revision for this device //----------------------------------------------------------------------------- void ManufacturerSpecific::setFileConfigRevision(uint32 rev) { m_fileConfigRevision = rev; if (Internal::VC::ValueInt* value = static_cast(GetValue(1, ValueID_Index_ManufacturerSpecific::LocalConfig))) { value->OnValueRefreshed(rev); value->Release(); } } //----------------------------------------------------------------------------- // // Set the File Config Revision for this device //----------------------------------------------------------------------------- void ManufacturerSpecific::setLoadedConfigRevision(uint32 rev) { m_loadedConfigRevision = rev; if (Internal::VC::ValueInt* value = static_cast(GetValue(1, ValueID_Index_ManufacturerSpecific::LoadedConfig))) { value->OnValueRefreshed(rev); value->Release(); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/SwitchMultilevel.h0000644000175200017520000000645614032142455021114 00000000000000//----------------------------------------------------------------------------- // // SwitchMultilevel.h // // Implementation of the Z-Wave COMMAND_CLASS_SWITCH_MULTILEVEL // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _SwitchMultilevel_H #define _SwitchMultilevel_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_SWITCH_MULTILEVEL (0x26), a Z-Wave device command class. * \ingroup CommandClass */ class SwitchMultilevel: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new SwitchMultilevel(_homeId, _nodeId); } virtual ~SwitchMultilevel() { } static uint8 const StaticGetCommandClassId() { return 0x26; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_SWITCH_MULTILEVEL"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; virtual void SetValueBasic(uint8 const _instance, uint8 const _value) override; virtual uint8 GetMaxVersion() override { return 4; } protected: virtual void CreateVars(uint8 const _instance) override; private: enum SwitchMultilevelDirection { SwitchMultilevelDirection_Up = 0, SwitchMultilevelDirection_Down, SwitchMultilevelDirection_Inc, SwitchMultilevelDirection_Dec }; SwitchMultilevel(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } bool SetLevel(uint8 const _instance, uint8 const _level); bool StartLevelChange(uint8 const _instance, SwitchMultilevelDirection const _direction); bool StopLevelChange(uint8 const _instance); }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/ManufacturerProprietary.cpp0000644000175200017520000001650314032142455023032 00000000000000//----------------------------------------------------------------------------- // // ManufacturerProprietary.cpp // // Implementation of the Z-Wave COMMAND_CLASS_PROPRIETARY // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/ManufacturerProprietary.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueByte.h" namespace OpenZWave { namespace Internal { namespace CC { const uint8 MANUFACTURER_ID_FIBARO[2] = { 0x01, 0x0f }; //manufacturer proprietary message identifier for venetian blinds reports and get/set const uint8 FIBARO_VENETIEN_BLINDS_REPORT_ID[3] = { 0x26, 0x03, 0x03 }; const uint8 FIBARO_VENETIAN_BLINDS_GET_POSITION_TILT[5] = { 0x26, 0x02, 0x02, 0x00, 0x00 }; const uint8 FIBARO_VENETIAN_BLINDS_SET_TILT[4] = { 0x26, 0x01, 0x01, 0x00 }; const uint8 FIBARO_VENETIAN_BLINDS_SET_POSITION[3] = { 0x26, 0x01, 0x02 }; //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool ManufacturerProprietary::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { uint8 const* payload = _data + 2; if (MANUFACTURER_ID_FIBARO[0] == _data[0] && MANUFACTURER_ID_FIBARO[1] == _data[1]) { if (FIBARO_VENETIEN_BLINDS_REPORT_ID[0] == payload[0] && FIBARO_VENETIEN_BLINDS_REPORT_ID[1] == payload[1] && FIBARO_VENETIEN_BLINDS_REPORT_ID[2] == payload[2]) { Internal::VC::ValueByte* blindsValue = static_cast(GetValue(_instance, ValueID_Index_ManufacturerProprietary::FibaroVenetianBlinds_Blinds)); Internal::VC::ValueByte* tiltValue = static_cast(GetValue(_instance, ValueID_Index_ManufacturerProprietary::FibaroVenetianBlinds_Tilt)); if ( NULL != blindsValue && NULL != tiltValue) { Log::Write(LogLevel_Info, GetNodeId(), "Received Fibaro proprietary blind/slat position for node %d: Blinds: %d Slats: %d", GetNodeId(), payload[3], payload[4]); blindsValue->OnValueRefreshed(payload[3]); tiltValue->OnValueRefreshed(payload[4]); blindsValue->Release(); tiltValue->Release(); } else { Log::Write(LogLevel_Warning, GetNodeId(), "Error setting Fibaro blind/slat position. Values were not found."); } return true; } else { Log::Write(LogLevel_Warning, GetNodeId(), "Received unknown Fibaro proprietary message for node %d.", GetNodeId()); return false; } } Log::Write(LogLevel_Warning, GetNodeId(), "Received unknown manufacturer proprietary message for node %d.", GetNodeId()); return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool ManufacturerProprietary::RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("ManufacturerProprietary_RequestValue", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); if (ValueID_Index_ManufacturerProprietary::FibaroVenetianBlinds_Blinds == _index || ValueID_Index_ManufacturerProprietary::FibaroVenetianBlinds_Tilt == _index) { msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(1 + sizeof(MANUFACTURER_ID_FIBARO) + sizeof(FIBARO_VENETIAN_BLINDS_GET_POSITION_TILT)); // length of data msg->Append(GetCommandClassId()); msg->AppendArray(MANUFACTURER_ID_FIBARO, sizeof(MANUFACTURER_ID_FIBARO)); msg->AppendArray(FIBARO_VENETIAN_BLINDS_GET_POSITION_TILT, sizeof(FIBARO_VENETIAN_BLINDS_GET_POSITION_TILT)); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "ManufacturerProprietary_RequestValue Not Supported for value index %d", _index); } } else { Log::Write(LogLevel_Info, GetNodeId(), "ManufacturerProprietary_RequestValue Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Set the lock's state //----------------------------------------------------------------------------- bool ManufacturerProprietary::SetValue(Internal::VC::Value const& _value) { uint64 value_id = _value.GetID().GetIndex(); Msg* msg = new Msg("ManufacturerProprietary_SetValue", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); if (ValueID_Index_ManufacturerProprietary::FibaroVenetianBlinds_Blinds == value_id || ValueID_Index_ManufacturerProprietary::FibaroVenetianBlinds_Tilt == value_id) { Internal::VC::ValueByte const* value = static_cast(&_value); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(2 + // length of data sizeof(MANUFACTURER_ID_FIBARO) + sizeof(FIBARO_VENETIAN_BLINDS_GET_POSITION_TILT)); msg->Append(GetCommandClassId()); msg->AppendArray(MANUFACTURER_ID_FIBARO, sizeof(MANUFACTURER_ID_FIBARO)); if (ValueID_Index_ManufacturerProprietary::FibaroVenetianBlinds_Blinds == value_id) { msg->AppendArray(FIBARO_VENETIAN_BLINDS_SET_POSITION, sizeof(FIBARO_VENETIAN_BLINDS_SET_POSITION)); msg->Append(value->GetValue()); msg->Append(0x00); } else if (ValueID_Index_ManufacturerProprietary::FibaroVenetianBlinds_Tilt == value_id) { msg->AppendArray(FIBARO_VENETIAN_BLINDS_SET_TILT, sizeof(FIBARO_VENETIAN_BLINDS_SET_TILT)); msg->Append(value->GetValue()); } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "ManufacturerProprietary_SetValue %d not supported on node %d", value_id, GetNodeId()); return false; } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/EnergyProduction.cpp0000644000175200017520000001502014032142455021426 00000000000000//----------------------------------------------------------------------------- // // EnergyProduction.cpp // // Implementation of the Z-Wave COMMAND_CLASS_ENERGY_PRODUCTION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/EnergyProduction.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueDecimal.h" namespace OpenZWave { namespace Internal { namespace CC { enum EnergyProductionCmd { EnergyProductionCmd_Get = 0x02, EnergyProductionCmd_Report = 0x03 }; static char const* c_energyParameterNames[] = { "Instant energy production", "Total energy production", "Energy production today", "Total production time" }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool EnergyProduction::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool request = false; if (_requestFlags & RequestFlag_Dynamic) { // Request each of the production values request |= RequestValue(_requestFlags, ValueID_Index_EnergyProduction::Instant, _instance, _queue); request |= RequestValue(_requestFlags, ValueID_Index_EnergyProduction::Total, _instance, _queue); request |= RequestValue(_requestFlags, ValueID_Index_EnergyProduction::Today, _instance, _queue); request |= RequestValue(_requestFlags, ValueID_Index_EnergyProduction::Time, _instance, _queue); } return request; } //----------------------------------------------------------------------------- // // Request current production from the device //----------------------------------------------------------------------------- bool EnergyProduction::RequestValue(uint32 const _requestFlags, uint16 const _valueEnum, // one of EnergyProductionIndex enums uint8 const _instance, Driver::MsgQueue const _queue) { if (_valueEnum > ValueID_Index_EnergyProduction::Time) { Log::Write(LogLevel_Warning, GetNodeId(), "RequestValue _valueEnum was greater than range. Dropping"); return false; } if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Log::Write(LogLevel_Info, GetNodeId(), "Requesting the %s value", c_energyParameterNames[_valueEnum]); Msg* msg = new Msg("EnergyProductionCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(EnergyProductionCmd_Get); msg->Append((_valueEnum & 0xFF)); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "EnergyProductionCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool EnergyProduction::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (EnergyProductionCmd_Report == (EnergyProductionCmd) _data[0]) { uint8 scale; uint8 precision = 0; string value = ExtractValue(&_data[2], &scale, &precision); uint8 paramType = _data[1]; if (paramType > 4) /* size of c_energyParameterNames minus Invalid Entry*/ { Log::Write(LogLevel_Warning, GetNodeId(), "paramType Value was greater than range. Dropping Message"); return false; } Log::Write(LogLevel_Info, GetNodeId(), "Received an Energy production report: %s = %s", c_energyParameterNames[_data[1]], value.c_str()); if (Internal::VC::ValueDecimal* decimalValue = static_cast(GetValue(_instance, _data[1]))) { decimalValue->OnValueRefreshed(value); if (decimalValue->GetPrecision() != precision) { decimalValue->SetPrecision(precision); } decimalValue->Release(); } return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void EnergyProduction::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, (uint8) ValueID_Index_EnergyProduction::Instant, c_energyParameterNames[ValueID_Index_EnergyProduction::Instant], "W", true, false, "0.0", 0); node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, (uint8) ValueID_Index_EnergyProduction::Total, c_energyParameterNames[ValueID_Index_EnergyProduction::Total], "kWh", true, false, "0.0", 0); node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, (uint8) ValueID_Index_EnergyProduction::Today, c_energyParameterNames[ValueID_Index_EnergyProduction::Today], "kWh", true, false, "0.0", 0); node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, (uint8) ValueID_Index_EnergyProduction::Time, c_energyParameterNames[ValueID_Index_EnergyProduction::Time], "", true, false, "0.0", 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/CentralScene.h0000644000175200017520000000720614032142455020150 00000000000000//----------------------------------------------------------------------------- // // CentralScene.h // // Implementation of the Z-Wave COMMAND_CLASS_CENTRAL_SCENE // // Copyright (c) 2012 Greg Satz // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _CentralScene_H #define _CentralScene_H #include "command_classes/CommandClass.h" #include "TimerThread.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_CENTRAL_SCENE (0x5B), a Z-Wave device command class. * \ingroup CommandClass */ class CentralScene: public CommandClass, private Timer { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new CentralScene(_homeId, _nodeId); } virtual ~CentralScene() { } /** \brief Get command class ID (1 byte) identifying this command class. */ static uint8 const StaticGetCommandClassId() { return 0x5B; } /** \brief Get a string containing the name of this command class. */ static string const StaticGetCommandClassName() { return "COMMAND_CLASS_CENTRAL_SCENE"; } // From CommandClass /** \brief Get command class ID (1 byte) identifying this command class. (Inherited from CommandClass) */ virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } /** \brief Get a string containing the name of this command class. (Inherited from CommandClass) */ virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual uint8 GetMaxVersion() override { return 3; } /** \brief Handle a response to a message associated with this command class. (Inherited from CommandClass) */ virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; bool RequestValue(uint32 const _requestFlags, uint16 const _what, uint8 const _instance, Driver::MsgQueue const _queue) override; bool SetValue(Internal::VC::Value const& _value) override; protected: /** \brief Create Default Vars for this CC */ void CreateVars(uint8 const _instance) override; private: /** * Creates the ValueIDs for the keyAttributes * @param identical * @param keyAttributes * @param sceneNumber * @return */ void createSupportedKeyAttributesValues(uint8 keyAttributes, uint8 sceneNumber, uint8 instance); void ClearScene(uint32 sceneID); CentralScene(uint32 const _homeId, uint8 const _nodeId); bool m_slowrefresh; uint8 m_sequence; std::map m_TimersSet; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/ThermostatFanMode.h0000644000175200017520000000607214032142455021166 00000000000000//----------------------------------------------------------------------------- // // ThermostatFanMode.h // // Implementation of the Z-Wave COMMAND_CLASS_THERMOSTAT_FAN_MODE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ThermostatFanMode_H #define _ThermostatFanMode_H #include #include #include "command_classes/CommandClass.h" #include "value_classes/ValueList.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_THERMOSTAT_FAN_MODE (0x44), a Z-Wave device command class. * \ingroup CommandClass */ class ThermostatFanMode: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new ThermostatFanMode(_homeId, _nodeId); } virtual ~ThermostatFanMode() { } static uint8 const StaticGetCommandClassId() { return 0x44; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_THERMOSTAT_FAN_MODE"; } // From CommandClass virtual void ReadXML(TiXmlElement const* _ccElement) override; virtual void WriteXML(TiXmlElement* _ccElement) override; virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _getTypeEnum, uint8 const _dummy, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: ThermostatFanMode(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { SetStaticRequest(StaticRequest_Values); } vector m_supportedModes; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/MeterPulse.cpp0000644000175200017520000001054314032142455020220 00000000000000//----------------------------------------------------------------------------- // // MeterPulse.cpp // // Implementation of the Z-Wave COMMAND_CLASS_METER_PULSE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/MeterPulse.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueInt.h" namespace OpenZWave { namespace Internal { namespace CC { enum MeterPulseCmd { MeterPulseCmd_Get = 0x04, MeterPulseCmd_Report = 0x05 }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool MeterPulse::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Dynamic) { return RequestValue(_requestFlags, ValueID_Index_MeterPulse::Count, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool MeterPulse::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("MeterPulseCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(MeterPulseCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "MeterPulseCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool MeterPulse::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (MeterPulseCmd_Report == (MeterPulseCmd) _data[0]) { int32 count = 0; for (uint8 i = 0; i < 4; ++i) { count <<= 8; count |= (uint32) _data[i + 1]; } Log::Write(LogLevel_Info, GetNodeId(), "Received a meter pulse count: Count=%d", count); if (Internal::VC::ValueInt* value = static_cast(GetValue(_instance, ValueID_Index_MeterPulse::Count))) { value->OnValueRefreshed(count); value->Release(); } return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void MeterPulse::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueInt(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_MeterPulse::Count, "Count", "", true, false, 0, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/TimeParameters.cpp0000644000175200017520000002040114032142455021047 00000000000000//----------------------------------------------------------------------------- // // TimeParameters.cpp // // Implementation of the Z-Wave COMMAND_CLASS_TIME_PARAMETERS // // Copyright (c) 2014 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "command_classes/CommandClasses.h" #include "command_classes/TimeParameters.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "Utils.h" #include "value_classes/ValueButton.h" #include "value_classes/ValueString.h" namespace OpenZWave { namespace Internal { namespace CC { enum TimeParametersCmd { TimeParametersCmd_Set = 0x01, TimeParametersCmd_Get = 0x02, TimeParametersCmd_Report = 0x03 }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- TimeParameters::TimeParameters(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool TimeParameters::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { return RequestValue(_requestFlags, 0, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool TimeParameters::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("TimeParametersCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(TimeParametersCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "TimeParametersCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool TimeParameters::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (TimeParametersCmd_Report == (TimeParametersCmd) _data[0]) { uint16 year = (_data[1] << 8) + (_data[2] & 0xFF); uint8 month = (_data[3] & 0x0F); uint8 day = (_data[4] & 0x1F); uint8 hour = (_data[5] & 0x1F); uint8 minute = (_data[6] & 0x3F); uint8 second = (_data[7] & 0x3F); Log::Write(LogLevel_Info, GetNodeId(), "Received TimeParameters report: %02d/%02d/%04d %02d:%02d:%02d", (int) day, (int) month, (int) year, (int) hour, (int) minute, (int) second); if (Internal::VC::ValueString* value = static_cast(GetValue(_instance, ValueID_Index_TimeParameters::Date))) { char msg[512]; snprintf(msg, sizeof(msg), "%02d/%02d/%04d", (int) day, (int) month, (int) year); value->OnValueRefreshed(msg); value->Release(); } if (Internal::VC::ValueString* value = static_cast(GetValue(_instance, ValueID_Index_TimeParameters::Time))) { char msg[512]; snprintf(msg, sizeof(msg), "%02d:%02d:%02d", (int) hour, (int) minute, (int) second); value->OnValueRefreshed(msg); value->Release(); } ClearStaticRequest(StaticRequest_Values); return true; } return false; } //----------------------------------------------------------------------------- // // Set a value in the Z-Wave device //----------------------------------------------------------------------------- bool TimeParameters::SetValue(Internal::VC::Value const& _value) { bool ret = false; uint8 instance = _value.GetID().GetInstance(); if ((ValueID::ValueType_Button == _value.GetID().GetType()) && (_value.GetID().GetIndex() == ValueID_Index_TimeParameters::Set)) { time_t rawtime; struct tm *timeinfo; time(&rawtime); // use threadsafe verion of localtime. Reported by nihilus, 2019-04 // https://www.gnu.org/software/libc/manual/html_node/Broken_002ddown-Time.html#Broken_002ddown-Time struct tm xtm; memset(&xtm, 0, sizeof(xtm)); timeinfo = localtime_r(&rawtime, &xtm); Msg* msg = new Msg("TimeParametersCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, instance); msg->Append(GetNodeId()); msg->Append(9); msg->Append(GetCommandClassId()); msg->Append(TimeParametersCmd_Set); /* Year 1 */ msg->Append(((timeinfo->tm_year + 1900) >> 8) & 0xFF); /* Year 2 */ msg->Append(((timeinfo->tm_year + 1900) & 0xFF)); /* Month */ msg->Append((timeinfo->tm_mon & 0x0F) + 1); /* Day */ msg->Append((timeinfo->tm_mday & 0x1F)); /* Hour */ msg->Append((timeinfo->tm_hour & 0x1F)); /* Minute */ msg->Append((timeinfo->tm_min & 0x3F)); /* Second */ msg->Append((timeinfo->tm_sec & 0x3F)); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); /* Refresh after we send updated date/time */ SetStaticRequest(StaticRequest_Values); ret = RequestValue(RequestFlag_Static, 0, instance, Driver::MsgQueue_Query); } if ((ValueID::ValueType_Button == _value.GetID().GetType()) && (_value.GetID().GetIndex() == ValueID_Index_TimeParameters::Refresh)) { SetStaticRequest(StaticRequest_Values); ret = RequestValue(RequestFlag_Static, 0, instance, Driver::MsgQueue_Query); } return ret; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void TimeParameters::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueString(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_TimeParameters::Date, "Date", "", true, false, "", 0); node->CreateValueString(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_TimeParameters::Time, "Time", "", true, false, "", 0); node->CreateValueButton(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_TimeParameters::Set, "Set Date/Time", 0); node->CreateValueButton(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_TimeParameters::Refresh, "Refresh Date/Time", 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/SwitchToggleBinary.h0000644000175200017520000000541114032142455021346 00000000000000//----------------------------------------------------------------------------- // // SwitchToggleBinary.h // // Implementation of the Z-Wave COMMAND_CLASS_SWITCH_TOGGLE_BINARY // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _SwitchToggleBinary_H #define _SwitchToggleBinary_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_SWITCH_TOGGLE_BINARY (0x28), a Z-Wave device command class. * \ingroup CommandClass */ class SwitchToggleBinary: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new SwitchToggleBinary(_homeId, _nodeId); } virtual ~SwitchToggleBinary() { } static uint8 const StaticGetCommandClassId() { return 0x28; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_SWITCH_TOGGLE_BINARY"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: SwitchToggleBinary(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/MultiCmd.h0000644000175200017520000000450614032142455017320 00000000000000//----------------------------------------------------------------------------- // // MultiCmd.h // // Implementation of the Z-Wave COMMAND_CLASS_MULTI_CMD // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _MultiCmd_H #define _MultiCmd_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_MULTI_CMD (0x8f), a Z-Wave device command class. * \ingroup CommandClass */ class MultiCmd: public CommandClass { public: enum MultiCmdCmd { MultiCmdCmd_Encap = 0x01 }; static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new MultiCmd(_homeId, _nodeId); } virtual ~MultiCmd() { } static uint8 const StaticGetCommandClassId() { return 0x8f; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_MULTI_CMD"; } // From CommandClass virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; private: MultiCmd(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/SimpleAV.h0000644000175200017520000000454114032142455017261 00000000000000//----------------------------------------------------------------------------- // // SimpleAVCommandItem.h // // Implementation of the Z-Wave COMMAND_CLASS_SIMPLE_AV_CONTROL // // Copyright (c) 2018 // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** Implements COMMAND_CLASS_SIMPLE_AV_CONTROL (0x94), a Z-Wave device command class. */ class SimpleAV: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new SimpleAV(_homeId, _nodeId); } virtual ~SimpleAV() { } static uint8 const StaticGetCommandClassId() { return 0x94; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_SIMPLE_AV_CONTROL"; } // From CommandClass virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: SimpleAV(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_sequence(0) { } uint8 m_sequence; }; } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/NoOperation.h0000644000175200017520000000456114032142455020040 00000000000000//----------------------------------------------------------------------------- // // NoOperation.h // // Implementation of the Z-Wave COMMAND_CLASS_NO_OPERATION // // Copyright (c) 2012 Greg Satz // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _NoOperation_H #define _NoOperation_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_NO_OPERATION (0x00), a Z-Wave device command class. * \ingroup CommandClass */ class NoOperation: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new NoOperation(_homeId, _nodeId); } virtual ~NoOperation() { } static uint8 const StaticGetCommandClassId() { return 0x00; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_NO_OPERATION"; } void Set(bool const _route, Driver::MsgQueue const _queue = Driver::MsgQueue_NoOp); // From CommandClass virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; private: NoOperation(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Configuration.cpp0000644000175200017520000002276414032142455020752 00000000000000//----------------------------------------------------------------------------- // // Configuration.cpp // // Implementation of the Z-Wave COMMAND_CLASS_CONFIGURATION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/Configuration.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "Node.h" #include "platform/Log.h" #include "value_classes/ValueBitSet.h" #include "value_classes/ValueBool.h" #include "value_classes/ValueButton.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueInt.h" #include "value_classes/ValueList.h" #include "value_classes/ValueShort.h" namespace OpenZWave { namespace Internal { namespace CC { enum ConfigurationCmd { ConfigurationCmd_Set = 0x04, ConfigurationCmd_Get = 0x05, ConfigurationCmd_Report = 0x06 }; //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Configuration::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (ConfigurationCmd_Report == (ConfigurationCmd) _data[0]) { // Extract the parameter index and value uint8 parameter = _data[1]; uint8 size = _data[2] & 0x07; int32 paramValue = 0; for (uint8 i = 0; i < size; ++i) { paramValue <<= 8; paramValue |= (int32) _data[i + 3]; } if (Internal::VC::Value* value = GetValue(1, parameter)) { switch (value->GetID().GetType()) { case ValueID::ValueType_BitSet: { Internal::VC::ValueBitSet* vbs = static_cast(value); vbs->OnValueRefreshed(paramValue); break; } case ValueID::ValueType_Bool: { Internal::VC::ValueBool* valueBool = static_cast(value); valueBool->OnValueRefreshed(paramValue != 0); break; } case ValueID::ValueType_Byte: { Internal::VC::ValueByte* valueByte = static_cast(value); valueByte->OnValueRefreshed((uint8) paramValue); break; } case ValueID::ValueType_Short: { Internal::VC::ValueShort* valueShort = static_cast(value); valueShort->OnValueRefreshed((int16) paramValue); break; } case ValueID::ValueType_Int: { Internal::VC::ValueInt* valueInt = static_cast(value); valueInt->OnValueRefreshed(paramValue); break; } case ValueID::ValueType_List: { Internal::VC::ValueList* valueList = static_cast(value); valueList->OnValueRefreshed(paramValue); break; } default: { Log::Write(LogLevel_Info, GetNodeId(), "Invalid type (%d) for configuration parameter %d", value->GetID().GetType(), parameter); } } value->Release(); } else { char label[16]; snprintf(label, 16, "Parameter #%hhu", parameter); // Create a new value if (Node* node = GetNodeUnsafe()) { switch (size) { case 1: { node->CreateValueByte(ValueID::ValueGenre_Config, GetCommandClassId(), _instance, parameter, label, "", false, false, (uint8) paramValue, 0); break; } case 2: { node->CreateValueShort(ValueID::ValueGenre_Config, GetCommandClassId(), _instance, parameter, label, "", false, false, (int16) paramValue, 0); break; } case 4: { node->CreateValueInt(ValueID::ValueGenre_Config, GetCommandClassId(), _instance, parameter, label, "", false, false, (int32) paramValue, 0); break; } default: { Log::Write(LogLevel_Info, GetNodeId(), "Invalid size of %d bytes for configuration parameter %d", size, parameter); } } } } Log::Write(LogLevel_Info, GetNodeId(), "Received Configuration report: Parameter=%d, Value=%d", parameter, paramValue); return true; } return false; } //----------------------------------------------------------------------------- // // Set a value in the Z-Wave device //----------------------------------------------------------------------------- bool Configuration::SetValue(Internal::VC::Value const& _value) { uint16 param = _value.GetID().GetIndex(); switch (_value.GetID().GetType()) { case ValueID::ValueType_BitSet: { Internal::VC::ValueBitSet const& vbs = static_cast(_value); Set(param, (int32) vbs.GetValue(), vbs.GetSize()); return true; } case ValueID::ValueType_Bool: { Internal::VC::ValueBool const& valueBool = static_cast(_value); Set(param, (int32) valueBool.GetValue(), 1); return true; } case ValueID::ValueType_Byte: { Internal::VC::ValueByte const& valueByte = static_cast(_value); Set(param, (int32) valueByte.GetValue(), 1); return true; } case ValueID::ValueType_Short: { Internal::VC::ValueShort const& valueShort = static_cast(_value); Set(param, (int32) valueShort.GetValue(), 2); return true; } case ValueID::ValueType_Int: { Internal::VC::ValueInt const& valueInt = static_cast(_value); Set(param, valueInt.GetValue(), 4); return true; } case ValueID::ValueType_List: { Internal::VC::ValueList const& valueList = static_cast(_value); if (valueList.GetItem() != NULL) Set(param, valueList.GetItem()->m_value, valueList.GetSize()); return true; } case ValueID::ValueType_Button: { Internal::VC::ValueButton const& valueButton = static_cast(_value); Set(param, valueButton.IsPressed(), 1); return true; } default: { } } Log::Write(LogLevel_Info, GetNodeId(), "Configuration::Set failed (bad value or value type) - Parameter=%d", param); return false; } //----------------------------------------------------------------------------- // // Request current parameter value from the device //----------------------------------------------------------------------------- bool Configuration::RequestValue(uint32 const _requestFlags, uint16 const _parameter, // parameter number is encoded as the Index portion of ValueID uint8 const _instance, Driver::MsgQueue const _queue) { if (_instance != 1) { // This command class doesn't work with multiple instances return false; } if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("ConfigurationCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(ConfigurationCmd_Get); msg->Append((_parameter & 0xFF)); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "ConfigurationCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Set the device's //----------------------------------------------------------------------------- void Configuration::Set(uint16 const _parameter, int32 const _value, uint8 const _size) { Log::Write(LogLevel_Info, GetNodeId(), "Configuration::Set - Parameter=%d, Value=%d Size=%d", _parameter, _value, _size); Msg* msg = new Msg("ConfigurationCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(GetNodeId()); msg->Append(4 + _size); msg->Append(GetCommandClassId()); msg->Append(ConfigurationCmd_Set); msg->Append((_parameter & 0xFF)); msg->Append(_size); if (_size > 2) { msg->Append((uint8) ((_value >> 24) & 0xff)); msg->Append((uint8) ((_value >> 16) & 0xff)); } if (_size > 1) { msg->Append((uint8) ((_value >> 8) & 0xff)); } msg->Append((uint8) (_value & 0xff)); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/BasicWindowCovering.h0000644000175200017520000000505014032142455021503 00000000000000//----------------------------------------------------------------------------- // // BasicWindowCovering.h // // Implementation of the Z-Wave COMMAND_CLASS_BASIC_WINDOW_COVERING // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _BasicWindowCovering_H #define _BasicWindowCovering_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_BASIC_WINDOW_COVERING (0x50), a Z-Wave device command class. * \ingroup CommandClass */ class BasicWindowCovering: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new BasicWindowCovering(_homeId, _nodeId); } virtual ~BasicWindowCovering() { } static uint8 const StaticGetCommandClassId() { return 0x50; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_BASIC_WINDOW_COVERING"; } // From CommandClass virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override { return false; } virtual bool SetValue(Internal::VC::Value const& _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: BasicWindowCovering(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/SensorBinary.h0000644000175200017520000000557714032142455020231 00000000000000//----------------------------------------------------------------------------- // // SensorBinary.h // // Implementation of the Z-Wave COMMAND_CLASS_SENSOR_BINARY // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _SensorBinary_H #define _SensorBinary_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_SENSOR_BINARY (0x30), a Z-Wave device command class. * \ingroup CommandClass */ class SensorBinary: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new SensorBinary(_homeId, _nodeId); } virtual ~SensorBinary() { } static uint8 const StaticGetCommandClassId() { return 0x30; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_SENSOR_BINARY"; } // From CommandClass virtual void ReadXML(TiXmlElement const* _ccElement) override; virtual void WriteXML(TiXmlElement* _ccElement) override; virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual void SetValueBasic(uint8 const _instance, uint8 const _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: SensorBinary(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } map m_sensorsMap; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/ThermostatSetpoint.h0000644000175200017520000000550414032142455021461 00000000000000//----------------------------------------------------------------------------- // // ThermostatSetpoint.h // // Implementation of the Z-Wave COMMAND_CLASS_THERMOSTAT_SETPOINT // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ThermostatSetpoint_H #define _ThermostatSetpoint_H #include #include #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_THERMOSTAT_SETPOINT (0x43), a Z-Wave device command class. * \ingroup CommandClass */ class ThermostatSetpoint: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new ThermostatSetpoint(_homeId, _nodeId); } virtual ~ThermostatSetpoint() { } static uint8 const StaticGetCommandClassId() { return 0x43; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_THERMOSTAT_SETPOINT"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _setPointIndex, uint8 const _dummy, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; virtual uint8 GetMaxVersion() override { return 3; } protected: virtual void CreateVars(uint8 const _instance) override; private: ThermostatSetpoint(uint32 const _homeId, uint8 const _nodeId); }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Battery.cpp0000644000175200017520000001102614032142455017542 00000000000000//----------------------------------------------------------------------------- // // Battery.cpp // // Implementation of the Z-Wave COMMAND_CLASS_BATTERY // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/Battery.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueByte.h" namespace OpenZWave { namespace Internal { namespace CC { enum BatteryCmd { BatteryCmd_Get = 0x02, BatteryCmd_Report = 0x03 }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Battery::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Dynamic) { return RequestValue(_requestFlags, ValueID_Index_Battery::Level, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool Battery::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (_instance != 1) { // This command class doesn't work with multiple instances return false; } if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("BatteryCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(BatteryCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "BatteryCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Battery::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (BatteryCmd_Report == (BatteryCmd) _data[0]) { // We have received a battery level report from the Z-Wave device. // Devices send 0xff instead of zero for a low battery warning. uint8 batteryLevel = _data[1]; if (batteryLevel == 0xff) { batteryLevel = 0; } Log::Write(LogLevel_Info, GetNodeId(), "Received Battery report from node %d: level=%d", GetNodeId(), batteryLevel); if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_Battery::Level))) { value->OnValueRefreshed(batteryLevel); value->Release(); } return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void Battery::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Battery::Level, "Battery Level", "%", true, false, 100, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/BarrierOperator.cpp0000644000175200017520000003545314032142455021244 00000000000000//----------------------------------------------------------------------------- // // BarrierOperator.cpp // // Implementation of the COMMAND_CLASS_BARRIER_OPERATOR // // Copyright (c) 2016 srirams (https://github.com/srirams) // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/BarrierOperator.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueBool.h" namespace OpenZWave { namespace Internal { namespace CC { enum BarrierOperatorCmd { BarrierOperatorCmd_Set = 0x01, BarrierOperatorCmd_Get = 0x02, BarrierOperatorCmd_Report = 0x03, BarrierOperatorCmd_SignalSupportedGet = 0x04, BarrierOperatorCmd_SignalSupportedReport = 0x05, BarrierOperatorCmd_SignalSet = 0x06, BarrierOperatorCmd_SignalGet = 0x07, BarrierOperatorCmd_SignalReport = 0x08 }; enum BarrierOperatorState { BarrierOperatorState_Closed = 0x00, BarrierOperatorState_Closing = 0xFC, BarrierOperatorState_Stopped = 0xFD, BarrierOperatorState_Opening = 0xFE, BarrierOperatorState_Open = 0xFF, }; enum BarrierOperator_SignalAttributesMask { BarrierOperatorSignalMask_Audible = 0x01, BarrierOperatorSignalMask_Visual = 0x02, BarrierOperatorSignalMask_All = 0x03 }; static char const* c_BarrierOperator_States[] = { "Closed", "Closing", "Stopped", "Opening", "Opened", "Unknown" }; static char const *c_BarrierOperator_Signals[] = { "None", "Audible", "Visual", "Both" }; BarrierOperator::BarrierOperator(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool BarrierOperator::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool res = false; if (_requestFlags & RequestFlag_Dynamic) { res |= RequestValue(_requestFlags, ValueID_Index_BarrierOperator::Command, _instance, _queue); } if (_requestFlags & RequestFlag_Static) { res |= RequestValue(_requestFlags, ValueID_Index_BarrierOperator::SupportedSignals, _instance, _queue); } return res; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool BarrierOperator::RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) { if (_index == ValueID_Index_BarrierOperator::Command) { Msg* msg = new Msg("BarrierOperatorCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(BarrierOperatorCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else if (_index == ValueID_Index_BarrierOperator::Audible) { Msg* msg = new Msg("BarrierOperatorCmd_SignalGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(BarrierOperatorCmd_SignalGet); msg->Append(0x01); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else if (_index == ValueID_Index_BarrierOperator::Visual) { Msg* msg = new Msg("BarrierOperatorCmd_SignalGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(BarrierOperatorCmd_SignalGet); msg->Append(0x02); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else if (_index == ValueID_Index_BarrierOperator::SupportedSignals) { Msg* msg = new Msg("BarrierOperatorCmd_SignalSupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(BarrierOperatorCmd_SignalSupportedGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool BarrierOperator::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (BarrierOperatorCmd_Report == (BarrierOperatorCmd) _data[0]) { uint8 state_index = 5; switch (_data[1]) { case BarrierOperatorState_Closed: { state_index = 0; break; } case BarrierOperatorState_Closing: { state_index = 1; break; } case BarrierOperatorState_Stopped: { state_index = 2; break; } case BarrierOperatorState_Opening: { state_index = 3; break; } case BarrierOperatorState_Open: { state_index = 4; break; } default: { Log::Write(LogLevel_Warning, GetNodeId(), "Received Invalid BarrierOperatorState %d", _data[1]); break; } } if (Internal::VC::ValueList* value = static_cast(GetValue(_instance, ValueID_Index_BarrierOperator::Label))) { value->OnValueRefreshed(state_index); value->Release(); } else { Log::Write(LogLevel_Warning, GetNodeId(), "No ValueID created for BarrierOperator state"); return false; } return true; } if (BarrierOperatorCmd_SignalSupportedReport == (BarrierOperatorCmd) _data[0]) { Log::Write(LogLevel_Info, GetNodeId(), "Received BarrierOperator Signal Support Report"); uint8 state_index = 0; uint8 data = _data[1]; /* Aeotec GDC shifts the SupportedReport by one, so we have to shift back */ if (data > 3) { Log::Write(LogLevel_Warning, GetNodeId(), "SignalSupportedReport is out of Range. Shifting Right"); data = data >> 1; } switch (data) { case BarrierOperatorSignalMask_Audible: { state_index = 1; RequestValue(0, ValueID_Index_BarrierOperator::Audible, _instance, Driver::MsgQueue_Send); break; } case BarrierOperatorSignalMask_Visual: { state_index = 2; RequestValue(0, ValueID_Index_BarrierOperator::Visual, _instance, Driver::MsgQueue_Send); break; } case BarrierOperatorSignalMask_All: { state_index = 3; RequestValue(0, ValueID_Index_BarrierOperator::Audible, _instance, Driver::MsgQueue_Send); RequestValue(0, ValueID_Index_BarrierOperator::Visual, _instance, Driver::MsgQueue_Send); break; } default: { Log::Write(LogLevel_Warning, GetNodeId(), "Received Invalid SignalSupported Report: %d", _data[1]); break; } } if (Internal::VC::ValueList* value = static_cast(GetValue(_instance, ValueID_Index_BarrierOperator::SupportedSignals))) { value->OnValueRefreshed(state_index); value->Release(); } else { Log::Write(LogLevel_Warning, GetNodeId(), "No ValueID created for BarrierOperator SupportedSignals"); return false; } return true; } if (BarrierOperatorCmd_SignalReport == (BarrierOperatorCmd) _data[0]) { if (_data[1] & 0x01) { Log::Write(LogLevel_Info, GetNodeId(), "Received BarrierOperator Signal Report for Audible"); if (Internal::VC::ValueBool* value = static_cast(GetValue(_instance, ValueID_Index_BarrierOperator::Audible))) { value->OnValueRefreshed(_data[2] == 0xFF ? true : false); value->Release(); } } if (_data[1] & 0x02) { Log::Write(LogLevel_Info, GetNodeId(), "Received BarrierOperator Signal Report for Visual"); if (Internal::VC::ValueBool* value = static_cast(GetValue(_instance, ValueID_Index_BarrierOperator::Visual))) { value->OnValueRefreshed(_data[2] == 0xFF ? true : false); value->Release(); } } return true; } return false; } //----------------------------------------------------------------------------- // // Set a value //----------------------------------------------------------------------------- bool BarrierOperator::SetValue(Internal::VC::Value const& _value) { uint8 idx = (uint8_t) (_value.GetID().GetIndex() & 0xFF); if (ValueID::ValueType_List == _value.GetID().GetType()) { if (idx == ValueID_Index_BarrierOperator::Label) { Internal::VC::ValueList const* value = static_cast(&_value); const Internal::VC::ValueList::Item *item = value->GetItem(); uint8 position = BarrierOperatorState_Closed; if (item->m_value > 0) position = BarrierOperatorState_Open; Log::Write(LogLevel_Info, GetNodeId(), "BarrierOperator::Set - Requesting barrier to be %s", position > 0 ? "Open" : "Closed"); Msg* msg = new Msg("BarrierOperatorCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(BarrierOperatorCmd_Set); msg->Append(position); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } } if (ValueID::ValueType_Bool == _value.GetID().GetType()) { if (idx == ValueID_Index_BarrierOperator::Audible) { Internal::VC::ValueBool const* value = static_cast(&_value); Log::Write(LogLevel_Info, GetNodeId(), "BarrierOperatorSignal::Set - Requesting Audible to be %s", value->GetValue() ? "ON" : "OFF"); Msg* msg = new Msg("BarrierOperatorSignalCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(BarrierOperatorCmd_SignalSet); msg->Append(BarrierOperatorSignalMask_Audible); msg->Append(value->GetValue() ? 0xFF : 0x00); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } else if (idx == ValueID_Index_BarrierOperator::Visual) { Internal::VC::ValueBool const* value = static_cast(&_value); Log::Write(LogLevel_Info, GetNodeId(), "BarrierOperatorSignal::Set - Requesting Visual to be %s", value->GetValue() ? "ON" : "OFF"); Msg* msg = new Msg("BarrierOperatorSignalCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(BarrierOperatorCmd_SignalSet); msg->Append(BarrierOperatorSignalMask_Visual); msg->Append(value->GetValue() ? 0xFF : 0x00); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void BarrierOperator::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { { std::vector items; unsigned int size = (sizeof(c_BarrierOperator_States) / sizeof(c_BarrierOperator_States[0])); for (unsigned int i = 0; i < size; i++) { Internal::VC::ValueList::Item item; item.m_label = c_BarrierOperator_States[i]; item.m_value = i; items.push_back(item); } node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_BarrierOperator::Label, "Barrier State", "", false, false, size, items, 0, 0); } { std::vector items; unsigned int size = (sizeof(c_BarrierOperator_Signals) / sizeof(c_BarrierOperator_Signals[0])); for (unsigned int i = 0; i < size; i++) { Internal::VC::ValueList::Item item; item.m_label = c_BarrierOperator_Signals[i]; item.m_value = i; items.push_back(item); } node->CreateValueList(ValueID::ValueGenre_Config, GetCommandClassId(), _instance, ValueID_Index_BarrierOperator::SupportedSignals, "Supported Signals", "", true, false, size, items, 0, 0); } node->CreateValueBool(ValueID::ValueGenre_Config, GetCommandClassId(), _instance, ValueID_Index_BarrierOperator::Audible, "Audible Notification", "", false, false, false, 0); node->CreateValueBool(ValueID::ValueGenre_Config, GetCommandClassId(), _instance, ValueID_Index_BarrierOperator::Visual, "Visual Notification", "", false, false, false, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/ThermostatFanState.cpp0000644000175200017520000001206014032142455021707 00000000000000//----------------------------------------------------------------------------- // // ThermostatFanState.cpp // // Implementation of the Z-Wave COMMAND_CLASS_THERMOSTAT_FAN_STATE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/ThermostatFanState.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueString.h" namespace OpenZWave { namespace Internal { namespace CC { enum ThermostatFanStateCmd { ThermostatFanStateCmd_Get = 0x02, ThermostatFanStateCmd_Report = 0x03 }; static char const* c_stateName[] = { "Idle", "Running", "Running High", "State 03", // Undefined states. May be used in the future. "State 04", "State 05", "State 06", "State 07", "State 08", "State 09", "State 10", "State 11", "State 12", "State 13", "State 14", "State 15", }; //----------------------------------------------------------------------------- // // Get the static thermostat mode details from the device //----------------------------------------------------------------------------- bool ThermostatFanState::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Dynamic) { // Request the current state return RequestValue(_requestFlags, 0, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Get the thermostat fan state details from the device //----------------------------------------------------------------------------- bool ThermostatFanState::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { // Request the current state Msg* msg = new Msg("ThermostatFanStateCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(ThermostatFanStateCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "ThermostatFanStateCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool ThermostatFanState::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (ThermostatFanStateCmd_Report == (ThermostatFanStateCmd) _data[0]) { // We have received the thermostat fan state from the Z-Wave device if (Internal::VC::ValueString* valueString = static_cast(GetValue(_instance, ValueID_Index_ThermostatFanState::FanState))) { /* No need bounds checking as the state can only be a single byte - No larger than our Char array anyway */ uint8 state = (_data[1] & 0x0f); valueString->OnValueRefreshed(c_stateName[state]); valueString->Release(); Log::Write(LogLevel_Info, GetNodeId(), "Received thermostat fan state: %s", valueString->GetValue().c_str()); } return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void ThermostatFanState::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueString(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ThermostatFanState::FanState, "Fan State", "", true, false, c_stateName[0], 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Proprietary.cpp0000644000175200017520000000361514032142455020455 00000000000000//----------------------------------------------------------------------------- // // Proprietary.cpp // // Implementation of the Z-Wave COMMAND_CLASS_PROPRIETARY // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/Proprietary.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace CC { enum ProprietaryCmd { ProprietaryCmd_Set = 0x01, ProprietaryCmd_Get = 0x02, ProprietaryCmd_Report = 0x03 }; //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Proprietary::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (ProprietaryCmd_Report == (ProprietaryCmd) _data[0]) { return true; } return false; } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/CommandClasses.h0000644000175200017520000000613114032142455020472 00000000000000//----------------------------------------------------------------------------- // // CommandClasses.h // // Singleton holding methods to create each command class object // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _CommandClasses_H #define _CommandClasses_H #include #include #include #include "Defs.h" namespace OpenZWave { namespace Internal { namespace CC { class CommandClass; /** \brief Manages a map of command classes supported by a specific Z-Wave node. * \ingroup CommandClass */ class CommandClasses { public: typedef CommandClass* (*pfnCreateCommandClass_t)(uint32 const _homeId, uint8 const _nodeId); static void RegisterCommandClasses(); static CommandClass* CreateCommandClass(uint8 const _commandClassId, uint32 const _homeId, uint8 const _nodeId); static bool IsSupported(uint8 const _commandClassId); static string GetName(uint8 const _commandClassId); static list GetAdvertisedCommandClasses(); private: CommandClasses(); CommandClasses(CommandClasses const&); // prevent copy CommandClasses& operator =(CommandClasses const&); // prevent assignment static CommandClasses& Get() { static CommandClasses instance; return instance; } void Register(uint8 const _commandClassId, string const& _commandClassName, pfnCreateCommandClass_t _create, bool advertised = false); void ParseCommandClassOption(string const& _optionStr, bool const _include); uint8 GetCommandClassId(string const& _name); pfnCreateCommandClass_t m_commandClassCreators[256]; map m_namesToIDs; /* a list of CommandClasses that are advertised on the controllers NIF packet and can be controlled * via other Nodes */ list m_advertisedCommandClasses; // m_supportedCommandClasses uses single bits to mark whether OpenZWave supports a command class // Checking this is not the same as looking for non-NULL entried in m_commandClassCreators, since // this may be modified by the program options --Include and --Ingnore to filter out support // for unwanted command classes. uint32 m_supportedCommandClasses[8]; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/WakeUp.cpp0000644000175200017520000004572514032142455017341 00000000000000//----------------------------------------------------------------------------- // // WakeUp.cpp // // Implementation of the Z-Wave COMMAND_CLASS_WAKE_UP // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/WakeUp.h" #include "command_classes/MultiCmd.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "Node.h" #include "Notification.h" #include "Options.h" #include "TimerThread.h" #include "platform/Log.h" #include "platform/Mutex.h" #include "value_classes/ValueInt.h" #include "tinyxml.h" namespace OpenZWave { namespace Internal { namespace CC { enum WakeUpCmd { WakeUpCmd_IntervalSet = 0x04, WakeUpCmd_IntervalGet = 0x05, WakeUpCmd_IntervalReport = 0x06, WakeUpCmd_Notification = 0x07, WakeUpCmd_NoMoreInformation = 0x08, WakeUpCmd_IntervalCapabilitiesGet = 0x09, WakeUpCmd_IntervalCapabilitiesReport = 0x0A }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- WakeUp::WakeUp(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_mutex(new Internal::Platform::Mutex()), m_awake(true), m_pollRequired(false), m_interval(0) { Timer::SetDriver(GetDriver()); Options::Get()->GetOptionAsBool("AssumeAwake", &m_awake); m_com.EnableFlag(COMPAT_FLAG_WAKEUP_DELAYNMI, 1000); SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- WakeUp::~WakeUp() { m_mutex->Release(); while (!m_pendingQueue.empty()) { Driver::MsgQueueItem const& item = m_pendingQueue.front(); if (Driver::MsgQueueCmd_SendMsg == item.m_command) { delete item.m_msg; } else if (Driver::MsgQueueCmd_Controller == item.m_command) { delete item.m_cci; } m_pendingQueue.pop_front(); } } //----------------------------------------------------------------------------- // // Starts the process of requesting node state from a sleeping device //----------------------------------------------------------------------------- void WakeUp::Init() { // Request the wake up interval. When we receive the response, we // can send a set interval message with the same interval, but with // the target node id set to that of the controller. This will ensure // that the controller will receive the wake-up notifications from // the device. Once this is done, we can request the rest of the node // state. RequestValue(0, ValueID_Index_WakeUp::Interval, 1, Driver::MsgQueue_WakeUp); } //----------------------------------------------------------------------------- // // Nothing to do for wakeup //----------------------------------------------------------------------------- bool WakeUp::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool requests = false; if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { if (GetVersion() > 1) { requests |= RequestValue(_requestFlags, ValueID_Index_WakeUp::Min_Interval, _instance, _queue); } if (m_interval == 0) requests |= RequestValue(_requestFlags, ValueID_Index_WakeUp::Interval, _instance, _queue); ClearStaticRequest(RequestFlag_Static); } return requests; } //----------------------------------------------------------------------------- // // Nothing to do for wakeup //----------------------------------------------------------------------------- bool WakeUp::RequestValue(uint32 const _requestFlags, uint16 const _getTypeEnum, uint8 const _instance, Driver::MsgQueue const _queue) { if (_instance != 1) { // This command class doesn't work with multiple instances return false; } if (_getTypeEnum == ValueID_Index_WakeUp::Min_Interval || _getTypeEnum == ValueID_Index_WakeUp::Max_Interval || _getTypeEnum == ValueID_Index_WakeUp::Interval_Step) { Msg* msg = new Msg("WakeUpCmd_IntervalCapabilityGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(WakeUpCmd_IntervalCapabilitiesGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); } if (_getTypeEnum == ValueID_Index_WakeUp::Interval) { // We won't get a response until the device next wakes up Msg* msg = new Msg("WakeUpCmd_IntervalGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(WakeUpCmd_IntervalGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool WakeUp::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (WakeUpCmd_IntervalReport == (WakeUpCmd) _data[0]) { // some interval reports received are validly formatted (proper checksum, etc.) but only have length // of 3 (0x84 (classid), 0x06 (IntervalReport), 0x00). Not sure what this means if (_length < 6) { Log::Write(LogLevel_Warning, ""); Log::Write(LogLevel_Warning, GetNodeId(), "Unusual response: WakeUpCmd_IntervalReport with len = %d. Ignored.", _length); return false; } m_interval = ((uint32) _data[1]) << 16; m_interval |= (((uint32) _data[2]) << 8); m_interval |= (uint32) _data[3]; uint8 targetNodeId = _data[4]; Log::Write(LogLevel_Info, GetNodeId(), "Received Wakeup Interval report from node %d: Interval=%d, Target Node=%d", GetNodeId(), m_interval, targetNodeId); if (Internal::VC::ValueInt* value = static_cast(GetValue(_instance, ValueID_Index_WakeUp::Interval))) { value->OnValueRefreshed((int32) m_interval); Node *node = GetNodeUnsafe(); if ((GetDriver()->GetControllerNodeId() != targetNodeId) && node) { SetValue(*value); } value->Release(); } else { // Ensure that the target node for wake-up notifications is the controller // but only if node is not a listening device. Hybrid devices that can be // powered by other then batteries shouldn't do this. Node *node = GetNodeUnsafe(); if ((GetDriver()->GetControllerNodeId() != targetNodeId) && node) { Msg* msg = new Msg("WakeUpCmd_IntervalSet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(GetNodeId()); msg->Append(6); // length of command bytes following msg->Append(GetCommandClassId()); msg->Append(WakeUpCmd_IntervalSet); msg->Append((uint8) ((m_interval >> 16) & 0xff)); msg->Append((uint8) ((m_interval >> 8) & 0xff)); msg->Append((uint8) (m_interval & 0xff)); msg->Append(GetDriver()->GetControllerNodeId()); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_WakeUp); } } return true; } else if (WakeUpCmd_Notification == (WakeUpCmd) _data[0]) { // The device is awake. Log::Write(LogLevel_Info, GetNodeId(), "Received Wakeup Notification from node %d", GetNodeId()); SetAwake(true); return true; } else if (WakeUpCmd_IntervalCapabilitiesReport == (WakeUpCmd) _data[0]) { uint32 mininterval = (((uint32) _data[1]) << 16) | (((uint32) _data[2]) << 8) | ((uint32) _data[3]); uint32 maxinterval = (((uint32) _data[4]) << 16) | (((uint32) _data[5]) << 8) | ((uint32) _data[6]); uint32 definterval = (((uint32) _data[7]) << 16) | (((uint32) _data[8]) << 8) | ((uint32) _data[9]); uint32 stepinterval = (((uint32) _data[10]) << 16) | (((uint32) _data[11]) << 8) | ((uint32) _data[12]); Log::Write(LogLevel_Info, GetNodeId(), "Received Wakeup Interval Capability report from node %d: Min Interval=%d, Max Interval=%d, Default Interval=%d, Interval Step=%d", GetNodeId(), mininterval, maxinterval, definterval, stepinterval); if (Internal::VC::ValueInt* value = static_cast(GetValue(_instance, ValueID_Index_WakeUp::Min_Interval))) { value->OnValueRefreshed((int32) mininterval); value->Release(); } if (Internal::VC::ValueInt* value = static_cast(GetValue(_instance, ValueID_Index_WakeUp::Max_Interval))) { value->OnValueRefreshed((int32) maxinterval); value->Release(); } if (Internal::VC::ValueInt* value = static_cast(GetValue(_instance, ValueID_Index_WakeUp::Default_Interval))) { value->OnValueRefreshed((int32) definterval); value->Release(); } if (Internal::VC::ValueInt* value = static_cast(GetValue(_instance, ValueID_Index_WakeUp::Interval_Step))) { value->OnValueRefreshed((int32) stepinterval); value->Release(); } ClearStaticRequest(StaticRequest_Values); return true; } return false; } //----------------------------------------------------------------------------- // // Set the device's wakeup interval //----------------------------------------------------------------------------- bool WakeUp::SetValue(Internal::VC::Value const& _value) { if (ValueID_Index_WakeUp::Interval == _value.GetID().GetIndex()) { Internal::VC::ValueInt const* value = static_cast(&_value); Msg* msg = new Msg("WakeUpCmd_IntervalSet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(GetNodeId()); #if 0 if (GetNodeUnsafe()->GetCommandClass(MultiCmd::StaticGetCommandClassId())) { msg->Append(10); msg->Append(MultiCmd::StaticGetCommandClassId()); msg->Append(MultiCmd::MultiCmdCmd_Encap); msg->Append(1); } #endif m_interval = value->GetValue(); msg->Append(6); // length of command bytes following msg->Append(GetCommandClassId()); msg->Append(WakeUpCmd_IntervalSet); msg->Append((uint8) ((m_interval >> 16) & 0xff)); msg->Append((uint8) ((m_interval >> 8) & 0xff)); msg->Append((uint8) (m_interval & 0xff)); msg->Append(GetDriver()->GetControllerNodeId()); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_WakeUp); return true; } return false; } //----------------------------------------------------------------------------- // // Set whether the device is likely to be awake //----------------------------------------------------------------------------- void WakeUp::SetAwake(bool _state) { if (m_awake != _state) { /* we do the call on RefreshValuesOnWakeup here, so any duplicates in the wakeup Queue are handled appropriately * */ if (m_awake == false) { Node* node = GetNodeUnsafe(); if (node) node->RefreshValuesOnWakeup(); } m_awake = _state; Log::Write(LogLevel_Info, GetNodeId(), " Node %d has been marked as %s", GetNodeId(), m_awake ? "awake" : "asleep"); Notification* notification = new Notification(Notification::Type_Notification); notification->SetHomeAndNodeIds(GetHomeId(), GetNodeId()); notification->SetNotification(m_awake ? Notification::Code_Awake : Notification::Code_Sleep); GetDriver()->QueueNotification(notification); } if (m_awake) { // If the device is marked for polling, request the current state Node* node = GetNodeUnsafe(); if (m_pollRequired) { if (node != NULL) { node->SetQueryStage(Node::QueryStage_Dynamic); } m_pollRequired = false; } // Send all pending messages SendPending(); } } //----------------------------------------------------------------------------- // // Add a Z-Wave message to the queue //----------------------------------------------------------------------------- void WakeUp::QueueMsg(Driver::MsgQueueItem const& _item) { m_mutex->Lock(); // See if there is already a copy of this message in the queue. If so, // we delete it. This is to prevent duplicates building up if the // device does not wake up very often. Deleting the original and // adding the copy to the end avoids problems with the order of // commands such as on and off. list::iterator it = m_pendingQueue.begin(); while (it != m_pendingQueue.end()) { Driver::MsgQueueItem const& item = *it; if (item == _item) { // Duplicate found if (Driver::MsgQueueCmd_SendMsg == item.m_command) { delete item.m_msg; } else if (Driver::MsgQueueCmd_Controller == item.m_command) { delete item.m_cci; } it = m_pendingQueue.erase(it); } else { ++it; } } /* make sure the SendAttempts is reset to 0 */ if (_item.m_command == Driver::MsgQueueCmd_SendMsg) _item.m_msg->SetSendAttempts(0); m_pendingQueue.push_back(_item); m_mutex->Unlock(); } //----------------------------------------------------------------------------- // // The device is awake, so send all the pending messages //----------------------------------------------------------------------------- void WakeUp::SendPending() { m_awake = true; bool reloading = false; m_mutex->Lock(); list::iterator it = m_pendingQueue.begin(); while (it != m_pendingQueue.end()) { Driver::MsgQueueItem const& item = *it; if (Driver::MsgQueueCmd_SendMsg == item.m_command) { GetDriver()->SendMsg(item.m_msg, Driver::MsgQueue_WakeUp); } else if (Driver::MsgQueueCmd_QueryStageComplete == item.m_command) { GetDriver()->SendQueryStageComplete(item.m_nodeId, item.m_queryStage); } else if (Driver::MsgQueueCmd_Controller == item.m_command) { GetDriver()->BeginControllerCommand(item.m_cci->m_controllerCommand, item.m_cci->m_controllerCallback, item.m_cci->m_controllerCallbackContext, item.m_cci->m_highPower, item.m_cci->m_controllerCommandNode, item.m_cci->m_controllerCommandArg); delete item.m_cci; } else if (Driver::MsgQueueCmd_ReloadNode == item.m_command) { GetDriver()->ReloadNode(item.m_nodeId); reloading = true; } it = m_pendingQueue.erase(it); } m_mutex->Unlock(); // Send the device back to sleep, unless we have outstanding queries. bool sendToSleep = m_awake; Node* node = GetNodeUnsafe(); if (node != NULL) { if (!node->AllQueriesCompleted()) { sendToSleep = false; } } /* if we are reloading, the QueryStage_Complete will take care of sending the device back to sleep */ if (sendToSleep && !reloading) { if (m_com.GetFlagInt(COMPAT_FLAG_WAKEUP_DELAYNMI) == 0) { SendNoMoreInfo(1); } else { Log::Write(LogLevel_Info, GetNodeId(), " Node %d has delayed sleep of %dms", GetNodeId(), m_com.GetFlagInt(COMPAT_FLAG_WAKEUP_DELAYNMI)); TimerThread::TimerCallback callback = bind(&WakeUp::SendNoMoreInfo, this, 1); TimerSetEvent(m_com.GetFlagInt(COMPAT_FLAG_WAKEUP_DELAYNMI), callback, 1); } } } //----------------------------------------------------------------------------- // // Send a no more information message //----------------------------------------------------------------------------- void WakeUp::SendNoMoreInfo(uint32 id) { Msg* msg = new Msg("WakeUpCmd_NoMoreInformation", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(WakeUpCmd_NoMoreInformation); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_WakeUp); GetDriver()->WriteCache(); } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void WakeUp::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { if (!node->IsController()) // We don't add the interval value for controllers, because they don't appear to ever wake up on their own. { if (GetVersion() >= 2) { node->CreateValueInt(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_WakeUp::Min_Interval, "Minimum Wake-up Interval", "Seconds", true, false, 0, 0); node->CreateValueInt(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_WakeUp::Max_Interval, "Maximum Wake-up Interval", "Seconds", true, false, 0, 0); node->CreateValueInt(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_WakeUp::Default_Interval, "Default Wake-up Interval", "Seconds", true, false, 0, 0); node->CreateValueInt(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_WakeUp::Interval_Step, "Wake-up Interval Step", "Seconds", true, false, 0, 0); } node->CreateValueInt(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_WakeUp::Interval, "Wake-up Interval", "Seconds", false, false, 3600, 0); if (Internal::VC::ValueInt* value = static_cast(GetValue(_instance, ValueID_Index_WakeUp::Interval))) { value->OnValueRefreshed((int32) m_interval); value->Release(); } } } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/SensorAlarm.h0000644000175200017520000000537014032142455020030 00000000000000//----------------------------------------------------------------------------- // // SensorAlarm.h // // Implementation of the Z-Wave COMMAND_CLASS_SENSOR_ALARM // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _SensorAlarm_H #define _SensorAlarm_H #include #include #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_SENSOR_ALARM (0x9c), a Z-Wave device command class. * \ingroup CommandClass */ class SensorAlarm: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new SensorAlarm(_homeId, _nodeId); } virtual ~SensorAlarm() { } static uint8 const StaticGetCommandClassId() { return 0x9c; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_SENSOR_ALARM"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _alarmType, uint8 const _dummy, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; private: SensorAlarm(uint32 const _homeId, uint8 const _nodeId); enum { SensorAlarm_General = 0, SensorAlarm_Smoke, SensorAlarm_CarbonMonoxide, SensorAlarm_CarbonDioxide, SensorAlarm_Heat, SensorAlarm_Flood, SensorAlarm_Count }; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/MultiInstance.h0000644000175200017520000000777214032142455020371 00000000000000//----------------------------------------------------------------------------- // // MultiInstance.h // // Implementation of the Z-Wave COMMAND_CLASS_MULTI_INSTANCE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _MultiInstance_H #define _MultiInstance_H #include #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_MULTI_INSTANCE (0x60), a Z-Wave device command class. * \ingroup CommandClass */ class MultiInstance: public CommandClass { public: enum MultiInstanceCmd { MultiInstanceCmd_Get = 0x04, MultiInstanceCmd_Report = 0x05, MultiInstanceCmd_Encap = 0x06, // Version 2 MultiChannelCmd_EndPointGet = 0x07, MultiChannelCmd_EndPointReport = 0x08, MultiChannelCmd_CapabilityGet = 0x09, MultiChannelCmd_CapabilityReport = 0x0a, MultiChannelCmd_EndPointFind = 0x0b, MultiChannelCmd_EndPointFindReport = 0x0c, MultiChannelCmd_Encap = 0x0d }; static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new MultiInstance(_homeId, _nodeId); } virtual ~MultiInstance() { } static uint8 const StaticGetCommandClassId() { return 0x60; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_MULTI_INSTANCE/CHANNEL"; } bool RequestInstances(); // From CommandClass virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool HandleIncomingMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual uint8 GetMaxVersion() override { return 2; } void SetInstanceLabel(uint8 const _instance, char *label) override; uint8 GetGenericInstanceDeviceType(uint8); uint8 GetSpecificInstanceDeviceType(uint8); bool supportsMultiInstance() override { return false; } private: MultiInstance(uint32 const _homeId, uint8 const _nodeId); void HandleMultiInstanceReport(uint8 const* _data, uint32 const _length); void HandleMultiInstanceEncap(uint8 const* _data, uint32 const _length); void HandleMultiChannelEndPointReport(uint8 const* _data, uint32 const _length); void HandleMultiChannelCapabilityReport(uint8 const* _data, uint32 const _length); void HandleMultiChannelEndPointFindReport(uint8 const* _data, uint32 const _length); void HandleMultiChannelEncap(uint8 const* _data, uint32 const _length); bool m_numEndPointsCanChange; bool m_endPointsAreSameClass; uint8 m_numEndPoints; // Finding endpoints uint8 m_endPointFindIndex; uint8 m_numEndPointsFound; set m_endPointCommandClasses; map m_endPointGenericType; map m_endPointSpecificType; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/DoorLock.cpp0000644000175200017520000004734214032142455017656 00000000000000//----------------------------------------------------------------------------- // // DoorLock.cpp // // Implementation of the Z-Wave COMMAND_CLASS_DOOR_LOCK // // Copyright (c) 2014 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/DoorLock.h" #include "command_classes/WakeUp.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueBool.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueInt.h" #include "tinyxml.h" namespace OpenZWave { namespace Internal { namespace CC { enum DoorLockCmd { DoorLockCmd_Set = 0x01, DoorLockCmd_Get = 0x02, DoorLockCmd_Report = 0x03, DoorLockCmd_Configuration_Set = 0x04, DoorLockCmd_Configuration_Get = 0x05, DoorLockCmd_Configuration_Report = 0x06 }; enum TimeOutMode { DoorLockConfig_NoTimeout = 0x01, DoorLockConfig_Timeout = 0x02 }; static char const* c_TimeOutModeNames[] = { "No Timeout", "Secure Lock after Timeout" }; enum DoorLockControlState { DoorLockControlState_Handle1 = 0x01, DoorLockControlState_Handle2 = 0x02, DoorLockControlState_Handle3 = 0x04, DoorLockControlState_Handle4 = 0x08 }; enum DoorLockState { DoorLockState_Unsecured = 0x00, DoorLockState_Unsecured_Timeout = 0x01, DoorLockState_Inside_Unsecured = 0x10, DoorLockState_Inside_Unsecured_Timeout = 0x11, DoorLockState_Outside_Unsecured = 0x20, DoorLockState_Outside_Unsecured_Timeout = 0x21, DoorLockState_Secured = 0xFF }; static char const* c_LockStateNames[] = { "Unsecure", "Unsecured with Timeout", "Inside Handle Unsecured", "Inside Handle Unsecured with Timeout", "Outside Handle Unsecured", "Outside Handle Unsecured with Timeout", "Secured", "Invalid" }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- DoorLock::DoorLock(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { m_dom.EnableFlag(STATE_FLAG_DOORLOCK_TIMEOUT, 0); m_dom.EnableFlag(STATE_FLAG_DOORLOCK_INSIDEMODE, 0); m_dom.EnableFlag(STATE_FLAG_DOORLOCK_OUTSIDEMODE, 0); m_dom.EnableFlag(STATE_FLAG_DOORLOCK_TIMEOUTMINS, 0xFE); m_dom.EnableFlag(STATE_FLAG_DOORLOCK_TIMEOUTSECS, 0xFE); SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool DoorLock::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool requests = false; if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { requests = RequestValue(_requestFlags, ValueID_Index_DoorLock::System_Config_Mode, _instance, _queue); } if (_requestFlags & RequestFlag_Dynamic) { requests |= RequestValue(_requestFlags, ValueID_Index_DoorLock::Lock, _instance, _queue); } return requests; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool DoorLock::RequestValue(uint32 const _requestFlags, uint16 const _what, uint8 const _instance, Driver::MsgQueue const _queue) { if (_what >= ValueID_Index_DoorLock::System_Config_Mode) { Msg* msg = new Msg("DoorLockCmd_Configuration_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(DoorLockCmd_Configuration_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else if ((_what == ValueID_Index_DoorLock::Lock) || (_what == ValueID_Index_DoorLock::Lock_Mode)) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("DoorLockCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(DoorLockCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "DoorLockCmd_Get Not Supported on this node"); } } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool DoorLock::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (DoorLockCmd_Report == (DoorLockCmd) _data[0]) { uint8 lockState = (_data[1] == 0xFF) ? 6 : _data[1]; if (lockState > 6) /* size of c_LockStateNames minus Invalid Entry */ { Log::Write(LogLevel_Warning, GetNodeId(), "LockState Value was greater than range. Setting to Invalid"); lockState = 7; } Log::Write(LogLevel_Info, GetNodeId(), "Received DoorLock report: DoorLock is %s", c_LockStateNames[lockState]); if (Internal::VC::ValueBool* value = static_cast(GetValue(_instance, ValueID_Index_DoorLock::Lock))) { value->OnValueRefreshed(lockState == 0x06); value->Release(); } if (Internal::VC::ValueList* value = static_cast(GetValue(_instance, ValueID_Index_DoorLock::Lock_Mode))) { value->OnValueRefreshed(lockState); value->Release(); } return true; } else if (DoorLockCmd_Configuration_Report == (DoorLockCmd) _data[0]) { switch (_data[1]) { case DoorLockConfig_NoTimeout: m_dom.SetFlagByte(STATE_FLAG_DOORLOCK_TIMEOUT, DoorLockConfig_NoTimeout); RemoveValue(_instance, ValueID_Index_DoorLock::System_Config_Minutes); RemoveValue(_instance, ValueID_Index_DoorLock::System_Config_Seconds); m_dom.SetFlagByte(STATE_FLAG_DOORLOCK_TIMEOUTMINS, 0xFE); m_dom.SetFlagByte(STATE_FLAG_DOORLOCK_TIMEOUTSECS, 0xFE); break; case DoorLockConfig_Timeout: /* if we have a timeout, then create the Values for the timeout config */ if (Node* node = GetNodeUnsafe()) { node->CreateValueInt(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_DoorLock::System_Config_Minutes, "Timeout Minutes", "Mins", false, false, _data[3], 0); node->CreateValueInt(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_DoorLock::System_Config_Seconds, "Timeout Seconds", "Secs", false, false, _data[4], 0); } m_dom.SetFlagByte(STATE_FLAG_DOORLOCK_TIMEOUT, DoorLockConfig_Timeout); m_dom.SetFlagByte(STATE_FLAG_DOORLOCK_TIMEOUTMINS, _data[3]); m_dom.SetFlagByte(STATE_FLAG_DOORLOCK_TIMEOUTSECS, _data[4]); break; default: Log::Write(LogLevel_Warning, GetNodeId(), "Received a Unsupported Door Lock Config Report %d", _data[1]); } if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_DoorLock::System_Config_OutsideHandles))) { value->OnValueRefreshed(((_data[2] & 0xF0) >> 4)); value->Release(); m_dom.SetFlagByte(STATE_FLAG_DOORLOCK_OUTSIDEMODE, ((_data[2] & 0xF0) >> 4)); } if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_DoorLock::System_Config_InsideHandles))) { value->OnValueRefreshed((_data[2] & 0x0F)); value->Release(); m_dom.SetFlagByte(STATE_FLAG_DOORLOCK_INSIDEMODE, (_data[2] & 0x0F)); } ClearStaticRequest(StaticRequest_Values); Log::Write(LogLevel_Info, GetNodeId(), "REcieved DoorLock Config Report: OutsideMode %d, InsideMode %d, Timeout Enabled: %d : %d:%d", ((_data[2] & 0xF0) >> 4), (_data[2] & 0x0F), _data[1], _data[3], _data[4]); return true; } return false; } //----------------------------------------------------------------------------- // // Set the lock's state //----------------------------------------------------------------------------- bool DoorLock::SetValue(Internal::VC::Value const& _value) { uint8 instance = _value.GetID().GetInstance(); if ((ValueID_Index_DoorLock::Lock == _value.GetID().GetIndex()) && ValueID::ValueType_Bool == _value.GetID().GetType()) { Internal::VC::ValueBool const* value = static_cast(&_value); Log::Write(LogLevel_Info, GetNodeId(), "ValueID_Index_DoorLock::Lock::Set - Requesting lock to be %s", value->GetValue() ? "Locked" : "Unlocked"); Msg* msg = new Msg("DoorLockCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(DoorLockCmd_Set); msg->Append(value->GetValue() ? 0xFF : 0x00); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } if ((ValueID_Index_DoorLock::Lock_Mode == _value.GetID().GetIndex()) && (ValueID::ValueType_List == _value.GetID().GetType())) { Internal::VC::ValueList const* value = static_cast(&_value); Internal::VC::ValueList::Item const *item = value->GetItem(); if (item == NULL) return false; Log::Write(LogLevel_Info, GetNodeId(), "ValueID_Index_DoorLock::Lock_Mode::Set - Requesting lock to be %s", item->m_label.c_str()); Msg* msg = new Msg("DoorLockCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(DoorLockCmd_Set); msg->Append(item->m_value); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } /* if its any of our System Messages.... */ if (ValueID_Index_DoorLock::System_Config_Mode <= _value.GetID().GetIndex() && ValueID_Index_DoorLock::System_Config_InsideHandles >= _value.GetID().GetIndex()) { bool sendmsg = true; switch (_value.GetID().GetIndex()) { /* this is a List */ case ValueID_Index_DoorLock::System_Config_Mode: if (ValueID::ValueType_List != _value.GetID().GetType()) { sendmsg = false; break; } if (Internal::VC::ValueList* value = static_cast(GetValue(instance, _value.GetID().GetIndex()))) { Internal::VC::ValueList::Item const *item = (static_cast(&_value))->GetItem(); if (item != NULL) value->OnValueRefreshed(item->m_value); value->Release(); } break; /* these are a int */ case ValueID_Index_DoorLock::System_Config_Minutes: case ValueID_Index_DoorLock::System_Config_Seconds: if (ValueID::ValueType_Int != _value.GetID().GetType()) { sendmsg = false; break; } if (Internal::VC::ValueInt* value = static_cast(GetValue(instance, _value.GetID().GetIndex()))) { value->OnValueRefreshed((static_cast(&_value))->GetValue()); value->Release(); } break; /* these are a byte */ case ValueID_Index_DoorLock::System_Config_OutsideHandles: case ValueID_Index_DoorLock::System_Config_InsideHandles: if (ValueID::ValueType_Byte != _value.GetID().GetType()) { sendmsg = false; break; } if (Internal::VC::ValueByte* value = static_cast(GetValue(instance, _value.GetID().GetIndex()))) { value->OnValueRefreshed((static_cast(&_value))->GetValue()); value->Release(); } break; default: Log::Write(LogLevel_Warning, GetNodeId(), "DoorLock::SetValue - Unhandled System_Config Variable %d", _value.GetID().GetIndex()); sendmsg = false; break; } if (sendmsg) { bool ok = true; if (Internal::VC::ValueList* value = static_cast(GetValue(instance, ValueID_Index_DoorLock::System_Config_Mode))) { Internal::VC::ValueList::Item const *item = value->GetItem(); if (item != NULL) m_dom.SetFlagByte(STATE_FLAG_DOORLOCK_TIMEOUT, item->m_value); } else { ok = false; Log::Write(LogLevel_Warning, GetNodeId(), "Failed To Retrieve ValueID_Index_DoorLock::System_Config_Mode For SetValue"); } uint8 control = 0; if (Internal::VC::ValueByte* value = static_cast(GetValue(instance, ValueID_Index_DoorLock::System_Config_OutsideHandles))) { control = (value->GetValue() << 4); m_dom.SetFlagByte(STATE_FLAG_DOORLOCK_INSIDEMODE, control); } else { ok = false; Log::Write(LogLevel_Warning, GetNodeId(), "Failed To Retrieve ValueID_Index_DoorLock::System_Config_OutsideHandles For SetValue"); } if (Internal::VC::ValueByte* value = static_cast(GetValue(instance, ValueID_Index_DoorLock::System_Config_InsideHandles))) { control += (value->GetValue() & 0x0F); m_dom.SetFlagByte(STATE_FLAG_DOORLOCK_OUTSIDEMODE, (value->GetValue() & 0x0F)); } else { ok = false; Log::Write(LogLevel_Warning, GetNodeId(), "Failed To Retrieve ValueID_Index_DoorLock::System_Config_InsideHandles For SetValue"); } if (Internal::VC::ValueInt* value = static_cast(GetValue(instance, ValueID_Index_DoorLock::System_Config_Minutes))) { m_dom.SetFlagByte(STATE_FLAG_DOORLOCK_TIMEOUTMINS, value->GetValue()); } else { /* Minutes and Seconds Might Not Exist, this is fine. Set to 0xFE */ m_dom.SetFlagByte(STATE_FLAG_DOORLOCK_TIMEOUTMINS, 0xFE); } if (Internal::VC::ValueInt* value = static_cast(GetValue(instance, ValueID_Index_DoorLock::System_Config_Seconds))) { m_dom.SetFlagByte(STATE_FLAG_DOORLOCK_TIMEOUTSECS, value->GetValue()); } else { /* Minutes and Seconds Might Not Exist, this is fine. Set to 0xFE */ m_dom.SetFlagByte(STATE_FLAG_DOORLOCK_TIMEOUTSECS, 0xFE); } if (ok) { Msg* msg = new Msg("DoorLockCmd_Configuration_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(6); msg->Append(GetCommandClassId()); msg->Append(DoorLockCmd_Configuration_Set); msg->Append(m_dom.GetFlagByte(STATE_FLAG_DOORLOCK_TIMEOUT)); msg->Append(control); msg->Append(m_dom.GetFlagByte(STATE_FLAG_DOORLOCK_TIMEOUTMINS)); msg->Append(m_dom.GetFlagByte(STATE_FLAG_DOORLOCK_TIMEOUTSECS)); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } return false; } } return false; } //----------------------------------------------------------------------------- // // Update class values based in BASIC mapping //----------------------------------------------------------------------------- void DoorLock::SetValueBasic(uint8 const _instance, uint8 const _value) { // Send a request for new value to synchronize it with the BASIC set/report. // In case the device is sleeping, we set the value anyway so the BASIC set/report // stays in sync with it. We must be careful mapping the uint8 BASIC value // into a class specific value. // When the device wakes up, the real requested value will be retrieved. RequestValue(0, DoorLockCmd_Get, _instance, Driver::MsgQueue_Send); if (Node* node = GetNodeUnsafe()) { if (WakeUp* wakeUp = static_cast(node->GetCommandClass(WakeUp::StaticGetCommandClassId()))) { if (!wakeUp->IsAwake()) { if (Internal::VC::ValueBool* value = static_cast(GetValue(_instance, ValueID_Index_DoorLock::Lock))) { value->OnValueRefreshed(_value != 0); value->Release(); } } } } } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void DoorLock::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueBool(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_DoorLock::Lock, "Locked", "", false, false, false, 0); /* Complex Lock Option */ { vector items; Internal::VC::ValueList::Item item; for (uint8 i = 0; i < 8; ++i) { item.m_label = c_LockStateNames[i]; item.m_value = (i <= 6) ? i : 0xFF; items.push_back(item); } node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_DoorLock::Lock_Mode, "Locked (Advanced)", "", false, false, 1, items, 0, 0); } /* Timeout mode for Locks that support it */ { vector items; Internal::VC::ValueList::Item item; for (uint8 i = 0; i < 2; ++i) { item.m_label = c_TimeOutModeNames[i]; item.m_value = i + 1; items.push_back(item); } node->CreateValueList(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_DoorLock::System_Config_Mode, "Timeout Mode", "", false, false, 1, items, 0, 0); } node->CreateValueByte(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_DoorLock::System_Config_OutsideHandles, "Outside Handle Control", "", false, false, 0x0F, 0); node->CreateValueByte(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_DoorLock::System_Config_InsideHandles, "Inside Handle Control", "", false, false, 0x0F, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/DoorLockLogging.h0000644000175200017520000000527214032142455020626 00000000000000//----------------------------------------------------------------------------- // // DoorLockLogging.h // // Implementation of the Z-Wave COMMAND_CLASS_DOOR_LOCK_LOGGING // // Copyright (c) 2014 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _DoorLockLogging_H #define _DoorLockLogging_H #include "CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_DOOR_LOCK_LOGGING (0x4C), a Z-Wave device command class. * \ingroup CommandClass */ class DoorLockLogging: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new DoorLockLogging(_homeId, _nodeId); } virtual ~DoorLockLogging() { } static uint8 const StaticGetCommandClassId() { return 0x4c; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_DOOR_LOCK_LOGGING"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: DoorLockLogging(uint32 const _homeId, uint8 const _nodeId); uint8 m_CurRecord; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Hail.cpp0000644000175200017520000000407014032142455017006 00000000000000//----------------------------------------------------------------------------- // // Hail.cpp // // Implementation of the Z-Wave COMMAND_CLASS_HAIL // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/Hail.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace CC { enum HailCmdEnum { HailCmd_Hail = 1 }; //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Hail::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (HailCmd_Hail == _data[0]) { // We have received a hail from the Z-Wave device. // Request an update of the dynamic values. Log::Write(LogLevel_Info, GetNodeId(), "Received Hail command from node %d", GetNodeId()); if (Node* node = GetNodeUnsafe()) { node->RequestDynamicValues(); } return true; } return false; } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/MultiCmd.cpp0000644000175200017520000000676214032142455017661 00000000000000//----------------------------------------------------------------------------- // // MultiCmd.h // // Implementation of the Z-Wave COMMAND_CLASS_MULTI_CMD // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/MultiCmd.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace CC { //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool MultiCmd::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (MultiCmdCmd_Encap == (MultiCmdCmd) _data[0]) { int commands; if (_length < 3) { Log::Write(LogLevel_Error, GetNodeId(), "Multi-command frame received is invalid, _length is < 3"); return false; } else { commands = _data[1]; Log::Write(LogLevel_Info, GetNodeId(), "Multi-command frame received, encapsulates %d command(s)", commands); } if (Node const *node = GetNodeUnsafe()) { // Iterate over commands int base = 2; // Highest possible index is _length minus two because // array is zero-based and _data starts at second byte of command frame int highest_index = _length - 2; for (uint8 i = 1; i <= commands; ++i) { if (base > highest_index) { Log::Write(LogLevel_Error, GetNodeId(), "Multi-command command part %d is invalid, frame is too short: base > highest_index (%d > %d)", i, base, highest_index); return false; } uint8 length = _data[base]; int end = base + length; if (end > highest_index) { Log::Write(LogLevel_Error, GetNodeId(), "Multi-command command part %d with base %d is invalid, end > highest_index (%d > %d)", i, base, end, highest_index); return false; } uint8 commandClassId = _data[base + 1]; if (CommandClass *pCommandClass = node->GetCommandClass(commandClassId)) { if (!pCommandClass->IsAfterMark()) pCommandClass->HandleMsg(&_data[base + 2], length - 1); else pCommandClass->HandleIncomingMsg(&_data[base + 2], length - 1); } base += (length + 1); } } Log::Write(LogLevel_Info, GetNodeId(), "Multi-command, all %d command(s) processed", commands); return true; } return false; } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/ThermostatOperatingState.cpp0000644000175200017520000001212414032142455023134 00000000000000//----------------------------------------------------------------------------- // // ThermostatOperatingState.cpp // // Implementation of the Z-Wave COMMAND_CLASS_THERMOSTAT_OPERATING_STATE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/ThermostatOperatingState.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueString.h" namespace OpenZWave { namespace Internal { namespace CC { enum ThermostatOperatingStateCmd { ThermostatOperatingStateCmd_Get = 0x02, ThermostatOperatingStateCmd_Report = 0x03 }; static char const* c_stateName[] = { "Idle", "Heating", "Cooling", "Fan Only", "Pending Heat", "Pending Cool", "Vent / Economizer", "State 07", // Undefined states. May be used in the future. "State 08", "State 09", "State 10", "State 11", "State 12", "State 13", "State 14", "State 15" }; //----------------------------------------------------------------------------- // // Get the static thermostat mode details from the device //----------------------------------------------------------------------------- bool ThermostatOperatingState::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Dynamic) { return RequestValue(_requestFlags, 0, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Get a thermostat mode value from the device //----------------------------------------------------------------------------- bool ThermostatOperatingState::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("ThermostatOperatingStateCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(ThermostatOperatingStateCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "ThermostatOperatingStateCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool ThermostatOperatingState::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (ThermostatOperatingStateCmd_Report == (ThermostatOperatingStateCmd) _data[0]) { // We have received the thermostat operating state from the Z-Wave device if (Internal::VC::ValueString* valueString = static_cast(GetValue(_instance, ValueID_Index_ThermostatOperatingState::OperatingState))) { /* no need bounds checking on c_stateName here, as it can only be 1 Byte anyway */ valueString->OnValueRefreshed(c_stateName[_data[1] & 0x0f]); valueString->Release(); Log::Write(LogLevel_Info, GetNodeId(), "Received thermostat operating state: %s", valueString->GetValue().c_str()); } return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void ThermostatOperatingState::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueString(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ThermostatOperatingState::OperatingState, "Operating State", "", true, false, c_stateName[0], 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Alarm.h0000644000175200017520000000673414032142455016643 00000000000000//----------------------------------------------------------------------------- // // Alarm.h // // Implementation of the Z-Wave COMMAND_CLASS_ALARM // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Alarm_H #define _Alarm_H #include "command_classes/CommandClass.h" #include "TimerThread.h" namespace OpenZWave { class ValueByte; namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_NOTIFICATION (0x71), a Z-Wave device command class. * \ingroup CommandClass */ class Alarm: public CommandClass, private Timer { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Alarm(_homeId, _nodeId); } virtual ~Alarm() { } /** \brief Get command class ID (1 byte) identifying this command class. */ static uint8 const StaticGetCommandClassId() { return 0x71; } /** \brief Get a string containing the name of this command class. */ static string const StaticGetCommandClassName() { return "COMMAND_CLASS_NOTIFICATION"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; /** \brief Get command class ID (1 byte) identifying this command class. (Inherited from CommandClass) */ virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } /** \brief Get a string containing the name of this command class. (Inherited from CommandClass) */ virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } /** \brief Handle a response to a message associated with this command class. (Inherited from CommandClass) */ virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual uint8 GetMaxVersion() override { return 8; } virtual bool SetValue(Internal::VC::Value const& _value) override; private: Alarm(uint32 const _homeId, uint8 const _nodeId); void SetupEvents(uint32 type, uint32 index, vector *_items, uint32 const _instance); void ClearAlarm(uint32 type); void ClearEventParams(uint32 const _instance); bool m_v1Params; std::vector m_ParamsSet; uint32 m_ClearTimeout; std::map m_TimersToInstances; }; } // namespace CommandClass } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/ControllerReplication.h0000644000175200017520000000542514032142455022120 00000000000000//----------------------------------------------------------------------------- // // ControllerReplication.h // // Implementation of the Z-Wave COMMAND_CLASS_CONTROLLER_REPLICATION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ControllerReplication_H #define _ControllerReplication_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_CONTROLLER_REPLICATION (0x21), a Z-Wave device command class. * \ingroup CommandClass */ class ControllerReplication: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new ControllerReplication(_homeId, _nodeId); } virtual ~ControllerReplication() { } static uint8 const StaticGetCommandClassId() { return 0x21; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_CONTROLLER_REPLICATION"; } // From CommandClass virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; void SendNextData(); bool supportsMultiInstance() override { return false; } protected: virtual void CreateVars(uint8 const _instance) override; private: ControllerReplication(uint32 const _homeId, uint8 const _nodeId); bool StartReplication(uint8 const _instance); bool m_busy; uint8 m_targetNodeId; uint8 m_funcId; int m_nodeId; int m_groupCount; int m_groupIdx; string m_groupName; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/SwitchBinary.h0000644000175200017520000000565014032142455020211 00000000000000//----------------------------------------------------------------------------- // // SwitchBinary.h // // Implementation of the Z-Wave COMMAND_CLASS_SWITCH_BINARY // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _SwitchBinary_H #define _SwitchBinary_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_SWITCH_BINARY (0x25), a Z-Wave device command class. * \ingroup CommandClass */ class SwitchBinary: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new SwitchBinary(_homeId, _nodeId); } virtual ~SwitchBinary() { } static uint8 const StaticGetCommandClassId() { return 0x25; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_SWITCH_BINARY"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; virtual void SetValueBasic(uint8 const _instance, uint8 const _value) override; bool SetState(uint8 const _instance, bool const _state); virtual uint8 GetMaxVersion() override { return 2; } protected: virtual void CreateVars(uint8 const _instance) override; private: SwitchBinary(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/DeviceResetLocally.h0000644000175200017520000000501514032142455021320 00000000000000//----------------------------------------------------------------------------- // // DeviceResetLocally.h // // Implementation of the Z-Wave COMMAND_CLASS_DEVICE_RESET_LOCALLY // // Copyright (c) 2015 // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _DeviceResetLocally_H #define _DeviceResetLocally_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_DEVICE_RESET_LOCALLY (0x5a), a Z-Wave device command class. * \ingroup CommandClass */ class DeviceResetLocally: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new DeviceResetLocally(_homeId, _nodeId); } virtual ~DeviceResetLocally() { } static uint8 const StaticGetCommandClassId() { return 0x5a; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_DEVICE_RESET_LOCALLY"; } // From CommandClass virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool IsDeviceReset() { return m_deviceReset; } bool supportsMultiInstance() override { return false; } private: DeviceResetLocally(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_deviceReset(false) { } ; bool m_deviceReset; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/UserCode.cpp0000644000175200017520000003754414032142455017656 00000000000000//----------------------------------------------------------------------------- // // UserCode.cpp // // Implementation of the Z-Wave COMMAND_CLASS_USER_CODE // // Copyright (c) 2012 Greg Satz // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "tinyxml.h" #include "command_classes/CommandClasses.h" #include "command_classes/UserCode.h" #include "command_classes/NodeNaming.h" #include "Node.h" #include "Options.h" #include "platform/Log.h" #include "value_classes/ValueShort.h" #include "value_classes/ValueString.h" #include "value_classes/ValueRaw.h" namespace OpenZWave { namespace Internal { namespace CC { enum UserCodeCmd { UserCodeCmd_Set = 0x01, UserCodeCmd_Get = 0x02, UserCodeCmd_Report = 0x03, UserNumberCmd_Get = 0x04, UserNumberCmd_Report = 0x05 }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- UserCode::UserCode(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_queryAll(false), m_currentCode(0), m_refreshUserCodes(false) { m_com.EnableFlag(COMPAT_FLAG_UC_EXPOSERAWVALUE, false); m_dom.EnableFlag(STATE_FLAG_USERCODE_COUNT, 0); SetStaticRequest(StaticRequest_Values); Options::Get()->GetOptionAsBool("RefreshAllUserCodes", &m_refreshUserCodes); } //----------------------------------------------------------------------------- // // Nothing to do for UserCode //----------------------------------------------------------------------------- bool UserCode::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool requests = false; if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { requests |= RequestValue(_requestFlags, ValueID_Index_UserCode::Count, _instance, _queue); } if (_requestFlags & RequestFlag_Session) { if (m_dom.GetFlagByte(STATE_FLAG_USERCODE_COUNT) > 0) { m_queryAll = true; m_currentCode = 1; requests |= RequestValue(_requestFlags, m_currentCode, _instance, _queue); } } return requests; } //----------------------------------------------------------------------------- // // Nothing to do for UserCode //----------------------------------------------------------------------------- bool UserCode::RequestValue(uint32 const _requestFlags, uint16 const _userCodeIdx, uint8 const _instance, Driver::MsgQueue const _queue) { if (_instance != 1) { // This command class doesn't work with multiple instances return false; } if (!m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Log::Write(LogLevel_Info, GetNodeId(), "UserNumberCmd_Get Not Supported on this node"); return false; } if (_userCodeIdx == ValueID_Index_UserCode::Count) { // Get number of supported user codes. Msg* msg = new Msg("UserNumberCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(UserNumberCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } if (_userCodeIdx == 0) { Log::Write(LogLevel_Warning, GetNodeId(), "UserCodeCmd_Get with Index 0 not Supported"); return false; } if (_userCodeIdx > m_dom.GetFlagByte(STATE_FLAG_USERCODE_COUNT)) { Log::Write(LogLevel_Warning, GetNodeId(), "UserCodeCmd_Get with index %d is greater than max UserCodes", _userCodeIdx); return false; } Msg* msg = new Msg("UserCodeCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(UserCodeCmd_Get); msg->Append((_userCodeIdx & 0xFF)); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool UserCode::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (UserNumberCmd_Report == (UserCodeCmd) _data[0]) { m_dom.SetFlagByte(STATE_FLAG_USERCODE_COUNT, _data[1]); ClearStaticRequest(StaticRequest_Values); if (_data[1] == 0) { Log::Write(LogLevel_Info, GetNodeId(), "Received User Number report from node %d: Not supported", GetNodeId()); } else { Log::Write(LogLevel_Info, GetNodeId(), "Received User Number report from node %d: Supported Codes %d (%d)", GetNodeId(), _data[1], _data[1]); } if (Internal::VC::ValueShort* value = static_cast(GetValue(_instance, ValueID_Index_UserCode::Count))) { value->OnValueRefreshed(_data[1]); value->Release(); } if (Node* node = GetNodeUnsafe()) { string data; for (uint16 i = 0; i <= m_dom.GetFlagByte(STATE_FLAG_USERCODE_COUNT); i++) { char str[16]; if (i == 0) { snprintf(str, sizeof(str), "Enrollment Code"); node->CreateValueString(ValueID::ValueGenre_User, GetCommandClassId(), _instance, i, str, "", true, false, data, 0); } else { snprintf(str, sizeof(str), "Code %d:", i); node->CreateValueString(ValueID::ValueGenre_User, GetCommandClassId(), _instance, i, str, "", false, false, data, 0); } m_userCode[i].status = UserCode_Available; /* silly compilers */ for (int j = 0; j < 10; j++) m_userCode[i].usercode[j] = 0; } if (m_com.GetFlagBool(COMPAT_FLAG_UC_EXPOSERAWVALUE)) { node->CreateValueRaw(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_UserCode::RawValue, "Raw UserCode", "", false, false, 0, 0, 0); node->CreateValueShort(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_UserCode::RawValueIndex, "Raw UserCode Index", "", false, false, 0, 0); } } return true; } else if (UserCodeCmd_Report == (UserCodeCmd) _data[0]) { int i = _data[1]; Log::Write(LogLevel_Info, GetNodeId(), "Received User Code Report from node %d for User Code %d (%s)", GetNodeId(), i, CodeStatus(_data[2]).c_str()); int8 size = _length - 4; if (size > 10) { Log::Write(LogLevel_Warning, GetNodeId(), "User Code length %d is larger then maximum 10", size); size = 10; } m_userCode[i].status = (UserCodeStatus) _data[2]; memcpy(&m_userCode[i].usercode, &_data[3], size); if (Internal::VC::ValueString* value = static_cast(GetValue(_instance, i))) { string data; /* Max UserCode Length is 10 */ Log::Write(LogLevel_Info, GetNodeId(), "User Code Packet is %d", size); data.assign((const char*) &_data[3], size); value->OnValueRefreshed(data); value->Release(); } if (m_com.GetFlagBool(COMPAT_FLAG_UC_EXPOSERAWVALUE)) { if (Internal::VC::ValueShort* value = static_cast(GetValue(_instance, ValueID_Index_UserCode::RawValueIndex))) { value->OnValueRefreshed(i); value->Release(); } if (Internal::VC::ValueRaw* value = static_cast(GetValue(_instance, ValueID_Index_UserCode::RawValue))) { value->OnValueRefreshed(&_data[3], (_length - 4)); value->Release(); } } if (m_queryAll && i == m_currentCode) { if (m_refreshUserCodes || (_data[2] != UserCode_Available)) { if (++i <= m_dom.GetFlagByte(STATE_FLAG_USERCODE_COUNT)) { m_currentCode = i; RequestValue(0, m_currentCode, _instance, Driver::MsgQueue_Query); } else { m_queryAll = false; /* we might have reset this as part of the RefreshValues Button Value */ Options::Get()->GetOptionAsBool("RefreshAllUserCodes", &m_refreshUserCodes); } } else { Log::Write(LogLevel_Info, GetNodeId(), "Not Requesting additional UserCode Slots as RefreshAllUserCodes is false, and slot %d is available", i); m_queryAll = false; } } return true; } return false; } //----------------------------------------------------------------------------- // // Set a User Code value //----------------------------------------------------------------------------- bool UserCode::SetValue(Internal::VC::Value const& _value) { if ((ValueID::ValueType_String == _value.GetID().GetType()) && (_value.GetID().GetIndex() < ValueID_Index_UserCode::Refresh)) { Internal::VC::ValueString const* value = static_cast(&_value); string s = value->GetValue(); if (s.length() < 4) { Log::Write(LogLevel_Warning, GetNodeId(), "UserCode is smaller than 4 digits", value->GetID().GetIndex()); return false; } if (s.length() > 10) { Log::Write(LogLevel_Warning, GetNodeId(), "UserCode is larger than 10 digits", value->GetID().GetIndex()); return false; } uint8 len = (uint8_t) (s.length() & 0xFF); if (value->GetID().GetIndex() == 0 || value->GetID().GetIndex() > m_dom.GetFlagByte(STATE_FLAG_USERCODE_COUNT)) { Log::Write(LogLevel_Warning, GetNodeId(), "Index %d is out of range of UserCodeCount", value->GetID().GetIndex()); return false; } Msg* msg = new Msg("UserCodeCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(4 + len); msg->Append(GetCommandClassId()); msg->Append(UserCodeCmd_Set); msg->Append((uint8_t) (value->GetID().GetIndex() & 0xFF)); msg->Append(UserCode_Occupied); for (uint8 i = 0; i < len; i++) { msg->Append(s[i]); } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } if ((ValueID::ValueType_Button == _value.GetID().GetType()) && (_value.GetID().GetIndex() == ValueID_Index_UserCode::Refresh)) { m_refreshUserCodes = true; m_currentCode = 1; m_queryAll = true; RequestValue(0, m_currentCode, _value.GetID().GetInstance(), Driver::MsgQueue_Query); return true; } if ((ValueID::ValueType_Short == _value.GetID().GetType()) && (_value.GetID().GetIndex() == ValueID_Index_UserCode::RemoveCode)) { Internal::VC::ValueShort const* value = static_cast(&_value); uint8_t index = (uint8_t) (value->GetValue() & 0xFF); if (index == 0 || index > m_dom.GetFlagByte(STATE_FLAG_USERCODE_COUNT)) { Log::Write(LogLevel_Warning, GetNodeId(), "Index %d is out of range of UserCodeCount", index); return false; } Msg* msg = new Msg("UserCodeCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(8); msg->Append(GetCommandClassId()); msg->Append(UserCodeCmd_Set); msg->Append(index); msg->Append(UserCode_Available); for (uint8 i = 0; i < 4; i++) { msg->Append(0); } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); RequestValue(0, index, _value.GetID().GetInstance(), Driver::MsgQueue_Send); #if 0 /* Reset Our Local Copy here */ if( ValueString* oldvalue = static_cast( GetValue( _value.GetID().GetInstance(), index ) ) ) { string data; oldvalue->OnValueRefreshed( data ); oldvalue->Release(); } #endif return false; } if ((ValueID::ValueType_Short == _value.GetID().GetType()) && (_value.GetID().GetIndex() == ValueID_Index_UserCode::RawValueIndex)) { Internal::VC::ValueShort const* value = static_cast(&_value); uint16 index = value->GetValue(); if (index == 0 || index > m_dom.GetFlagByte(STATE_FLAG_USERCODE_COUNT)) { Log::Write(LogLevel_Warning, GetNodeId(), "Index %d is out of range of UserCodeCount", index); return false; } if (Internal::VC::ValueRaw* oldvalue = static_cast(GetValue(_value.GetID().GetInstance(), ValueID_Index_UserCode::RawValue))) { oldvalue->OnValueRefreshed((const uint8*) &m_userCode[index].usercode, 10); oldvalue->Release(); } return false; } if ((ValueID::ValueType_Raw == _value.GetID().GetType()) && (_value.GetID().GetIndex() == ValueID_Index_UserCode::RawValue)) { Internal::VC::ValueRaw const* value = static_cast(&_value); uint16 index = 0; if (Internal::VC::ValueShort* valueindex = static_cast(GetValue(_value.GetID().GetInstance(), ValueID_Index_UserCode::RawValueIndex))) { index = valueindex->GetValue(); } if (index == 0 || index > m_dom.GetFlagByte(STATE_FLAG_USERCODE_COUNT)) { Log::Write(LogLevel_Warning, GetNodeId(), "Index %d is out of range of UserCodeCount", index); return false; } uint8 *s = value->GetValue(); uint8 len = value->GetLength(); Msg* msg = new Msg("UserCodeCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(4 + len); msg->Append(GetCommandClassId()); msg->Append(UserCodeCmd_Set); msg->Append((uint8_t) (index & 0xFF)); msg->Append(UserCode_Occupied); for (uint8 i = 0; i < len; i++) { msg->Append(s[i]); } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); RequestValue(0, index, _value.GetID().GetInstance(), Driver::MsgQueue_Send); return false; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void UserCode::CreateVars(uint8 const _instance ) { if (Node* node = GetNodeUnsafe()) { node->CreateValueShort(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_UserCode::Count, "Code Count", "", true, false, 0, 0); node->CreateValueButton(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_UserCode::Refresh, "Refresh All UserCodes", 0); node->CreateValueShort(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_UserCode::RemoveCode, "Remove User Code", "", false, true, 0, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/SensorAlarm.cpp0000644000175200017520000001520514032142455020361 00000000000000//----------------------------------------------------------------------------- // // SensorAlarm.cpp // // Implementation of the Z-Wave COMMAND_CLASS_SENSOR_ALARM // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/SensorAlarm.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueByte.h" namespace OpenZWave { namespace Internal { namespace CC { enum SensorAlarmCmd { SensorAlarmCmd_Get = 0x01, SensorAlarmCmd_Report = 0x02, SensorAlarmCmd_SupportedGet = 0x03, SensorAlarmCmd_SupportedReport = 0x04 }; static char const* c_alarmTypeName[] = { "General", "Smoke", "Carbon Monoxide", "Carbon Dioxide", "Heat", "Flood" }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- SensorAlarm::SensorAlarm(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Get the static thermostat setpoint details from the device //----------------------------------------------------------------------------- bool SensorAlarm::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool requests = false; if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { requests = RequestValue(_requestFlags, 0xff, _instance, _queue); } if (_requestFlags & RequestFlag_Dynamic) { for (uint8 i = 0; i < SensorAlarm_Count; ++i) { Internal::VC::Value* value = GetValue(1, i); if (value != NULL) { value->Release(); // There is a value for this alarm type, so request it requests |= RequestValue(_requestFlags, i, _instance, _queue); } } } return requests; } //----------------------------------------------------------------------------- // // Get the sensor alarm details from the device //----------------------------------------------------------------------------- bool SensorAlarm::RequestValue(uint32 const _requestFlags, uint16 const _alarmType, uint8 const _instance, Driver::MsgQueue const _queue) { if (_alarmType == 0xff) { // Request the supported alarm types Msg* msg = new Msg("SensorAlarmCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SensorAlarmCmd_SupportedGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { // Request the alarm state if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("SensorAlarmCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(SensorAlarmCmd_Get); msg->Append((_alarmType & 0xFF)); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "SensorAlarmCmd_Get Not Supported on this node"); } } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool SensorAlarm::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (SensorAlarmCmd_Report == (SensorAlarmCmd) _data[0]) { // We have received an alarm state report from the Z-Wave device if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, _data[2]))) { uint8 sourceNodeId = _data[1]; uint8 state = _data[3]; // uint16 time = (((uint16)_data[4])<<8) | (uint16)_data[5]; Don't know what to do with this yet. value->OnValueRefreshed(state); value->Release(); Log::Write(LogLevel_Info, GetNodeId(), "Received alarm state report from node %d: %s = %d", sourceNodeId, value->GetLabel().c_str(), state); } return true; } if (SensorAlarmCmd_SupportedReport == (SensorAlarmCmd) _data[0]) { if (Node* node = GetNodeUnsafe()) { // We have received the supported alarm types from the Z-Wave device Log::Write(LogLevel_Info, GetNodeId(), "Received supported alarm types"); // Parse the data for the supported alarm types uint8 numBytes = _data[1]; for (uint32 i = 0; i < numBytes; ++i) { for (int32 bit = 0; bit < 8; ++bit) { if ((_data[i + 2] & (1 << bit)) != 0) { // Add supported setpoint int32 index = (int32) (i << 3) + bit; if (index < SensorAlarm_Count) { node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, index, c_alarmTypeName[index], "", true, false, 0, 0); Log::Write(LogLevel_Info, GetNodeId(), " Added alarm type: %s", c_alarmTypeName[index]); } } } } } ClearStaticRequest(StaticRequest_Values); return true; } return false; } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/ThermostatFanMode.cpp0000644000175200017520000002650214032142455021521 00000000000000//----------------------------------------------------------------------------- // // ThermostatFanMode.cpp // // Implementation of the Z-Wave COMMAND_CLASS_THERMOSTAT_FAN_MODE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "command_classes/CommandClasses.h" #include "command_classes/ThermostatFanMode.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueList.h" #include "tinyxml.h" namespace OpenZWave { namespace Internal { namespace CC { enum ThermostatFanModeCmd { ThermostatFanModeCmd_Set = 0x01, ThermostatFanModeCmd_Get = 0x02, ThermostatFanModeCmd_Report = 0x03, ThermostatFanModeCmd_SupportedGet = 0x04, ThermostatFanModeCmd_SupportedReport = 0x05 }; static std::string const c_modeName[] = { "Auto Low", "On Low", "Auto High", "On High", "Unknown 4", "Unknown 5", "Circulate", "Unknown" }; //----------------------------------------------------------------------------- // // Read the supported modes //----------------------------------------------------------------------------- void ThermostatFanMode::ReadXML(TiXmlElement const* _ccElement) { CommandClass::ReadXML(_ccElement); if (GetNodeUnsafe()) { vector supportedModes; TiXmlElement const* supportedModesElement = _ccElement->FirstChildElement("SupportedModes"); if (supportedModesElement) { TiXmlElement const* modeElement = supportedModesElement->FirstChildElement(); while (modeElement) { char const* str = modeElement->Value(); if (str && !strcmp(str, "Mode")) { int index; if (TIXML_SUCCESS == modeElement->QueryIntAttribute("index", &index)) { if (index > 6) /* size of c_modeName excluding Invalid */ { Log::Write(LogLevel_Warning, GetNodeId(), "index Value in XML was greater than range. Setting to Invalid"); index = 7; } Internal::VC::ValueList::Item item; item.m_value = index; item.m_label = c_modeName[index]; supportedModes.push_back(item); } } modeElement = modeElement->NextSiblingElement(); } } if (!supportedModes.empty()) { m_supportedModes = supportedModes; ClearStaticRequest(StaticRequest_Values); CreateVars(1); } } } //----------------------------------------------------------------------------- // // Save the supported modes //----------------------------------------------------------------------------- void ThermostatFanMode::WriteXML(TiXmlElement* _ccElement) { CommandClass::WriteXML(_ccElement); if (GetNodeUnsafe()) { TiXmlElement* supportedModesElement = new TiXmlElement("SupportedModes"); _ccElement->LinkEndChild(supportedModesElement); for (vector::iterator it = m_supportedModes.begin(); it != m_supportedModes.end(); ++it) { Internal::VC::ValueList::Item const& item = *it; TiXmlElement* modeElement = new TiXmlElement("Mode"); supportedModesElement->LinkEndChild(modeElement); char str[8]; snprintf(str, 8, "%d", item.m_value); modeElement->SetAttribute("index", str); modeElement->SetAttribute("label", item.m_label.c_str()); } } } //----------------------------------------------------------------------------- // // Get the static thermostat fan mode details from the device //----------------------------------------------------------------------------- bool ThermostatFanMode::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool requests = false; if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { // Request the supported modes requests |= RequestValue(_requestFlags, ThermostatFanModeCmd_SupportedGet, _instance, _queue); } if (_requestFlags & RequestFlag_Dynamic) { // Request the current fan mode requests |= RequestValue(_requestFlags, ThermostatFanModeCmd_Get, _instance, _queue); } return requests; } //----------------------------------------------------------------------------- // // Get the thermostat fan mode details from the device //----------------------------------------------------------------------------- bool ThermostatFanMode::RequestValue(uint32 const _requestFlags, uint16 const _getTypeEnum, uint8 const _instance, Driver::MsgQueue const _queue) { if (_getTypeEnum == ThermostatFanModeCmd_SupportedGet) { // Request the supported modes Msg* msg = new Msg("ThermostatFanModeCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(ThermostatFanModeCmd_SupportedGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } if (_getTypeEnum == ThermostatFanModeCmd_Get || _getTypeEnum == 0) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { // Request the current fan mode Msg* msg = new Msg("ThermostatFanModeCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(ThermostatFanModeCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "ThermostatFanModeCmd_Get Not Supported on this node"); } } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool ThermostatFanMode::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (ThermostatFanModeCmd_Report == (ThermostatFanModeCmd) _data[0]) { bool validMode = false; uint8 mode = (int32) _data[1]; for (vector::iterator it = m_supportedModes.begin(); it != m_supportedModes.end(); ++it) { Internal::VC::ValueList::Item const& item = *it; if (item.m_value == mode) { validMode = true; break; } } if (validMode) { // We have received the thermostat mode from the Z-Wave device if (Internal::VC::ValueList* valueList = static_cast(GetValue(_instance, ValueID_Index_ThermostatFanMode::FanMode))) { valueList->OnValueRefreshed((int32) _data[1]); if (valueList->GetItem()) Log::Write(LogLevel_Info, GetNodeId(), "Received thermostat fan mode: %s", valueList->GetItem()->m_label.c_str()); else Log::Write(LogLevel_Info, GetNodeId(), "Received thermostat fan mode: %d", _data[1]); valueList->Release(); } else { Log::Write(LogLevel_Info, GetNodeId(), "Received thermostat fan mode: index %d", mode); } } else { Log::Write(LogLevel_Info, GetNodeId(), "Received unknown thermostat fan mode: %d", mode); } return true; } if (ThermostatFanModeCmd_SupportedReport == (ThermostatFanModeCmd) _data[0]) { // We have received the supported thermostat fan modes from the Z-Wave device Log::Write(LogLevel_Info, GetNodeId(), "Received supported thermostat fan modes"); m_supportedModes.clear(); for (uint32 i = 1; i < _length - 1; ++i) { for (int32 bit = 0; bit < 8; ++bit) { if ((_data[i] & (1 << bit)) != 0) { Internal::VC::ValueList::Item item; item.m_value = (int32) ((i - 1) << 3) + bit; /* Minus 1 here as the Unknown Entry is our addition */ if ((size_t) item.m_value >= (sizeof(c_modeName) / sizeof(*c_modeName) - 1)) { Log::Write(LogLevel_Info, GetNodeId(), "Received unknown fan mode: 0x%x", item.m_value); } else { item.m_label = c_modeName[item.m_value]; m_supportedModes.push_back(item); Log::Write(LogLevel_Info, GetNodeId(), " Added fan mode: %s", c_modeName[item.m_value].c_str()); } } } } ClearStaticRequest(StaticRequest_Values); CreateVars(_instance); return true; } return false; } //----------------------------------------------------------------------------- // // Set the device's thermostat fan mode //----------------------------------------------------------------------------- bool ThermostatFanMode::SetValue(Internal::VC::Value const& _value) { if (ValueID::ValueType_List == _value.GetID().GetType()) { Internal::VC::ValueList const* value = static_cast(&_value); if (value->GetItem() == NULL) return false; uint8 state = (uint8) value->GetItem()->m_value; Msg* msg = new Msg("ThermostatFanModeCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(ThermostatFanModeCmd_Set); msg->Append(state); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void ThermostatFanMode::CreateVars(uint8 const _instance) { if (m_supportedModes.empty()) { return; } if (Node* node = GetNodeUnsafe()) { node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ThermostatFanMode::FanMode, "Fan Mode", "", false, false, 1, m_supportedModes, m_supportedModes[0].m_value, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/MultiInstance.cpp0000644000175200017520000006342114032142455020715 00000000000000//----------------------------------------------------------------------------- // // MultiInstance.cpp // // Implementation of the Z-Wave COMMAND_CLASS_MULTI_INSTANCE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "tinyxml.h" #include "command_classes/CommandClasses.h" #include "command_classes/Basic.h" #include "command_classes/MultiInstance.h" #include "command_classes/NoOperation.h" #include "command_classes/Security.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "Node.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace CC { // Reduced set of Generic Device classes sorted to reduce // the likely number of calls to MultiChannelCmd_EndPointFind. uint8 const c_genericClass[] = { 0x21, // Multilevel Sensor 0x20, // Binary Sensor 0x31, // Meter 0x08, // Thermostat 0x11, // Multilevel Switch 0x10, // Binary Switch 0x12, // Remote Switch 0xa1, // Alarm Sensor 0x16, // Ventilation 0x30, // Pulse Meter 0x40, // Entry Control 0x13, // Toggle Switch 0x03, // AV Control Point 0x04, // Display 0x00 // End of list }; char const* c_genericClassName[] = { "Multilevel Sensor", "Binary Sensor", "Meter", "Thermostat", "Multilevel Switch", "Binary Switch", "Remote Switch", "Alarm Sensor", "Ventilation", "Pulse Meter", "Entry Control", "Toggle Switch", "AV Control Point", "Display", "Unknown" }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- MultiInstance::MultiInstance(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_numEndPoints(0) { m_com.EnableFlag(COMPAT_FLAG_MI_MAPROOTTOENDPOINT, false); m_com.EnableFlag(COMPAT_FLAG_MI_FORCEUNIQUEENDPOINTS, false); m_com.EnableFlag(COMPAT_FLAG_MI_IGNMCCAPREPORTS, false); m_com.EnableFlag(COMPAT_FLAG_MI_ENDPOINTHINT, 0); m_com.EnableFlag(COMPAT_FLAG_MI_REMOVECC, false); } //----------------------------------------------------------------------------- // // Request number of instances of the specified command class from the device //----------------------------------------------------------------------------- bool MultiInstance::RequestInstances() { bool res = false; if (GetVersion() == 1) { if (Node* node = GetNodeUnsafe()) { // MULTI_INSTANCE for (map::const_iterator it = node->m_commandClassMap.begin(); it != node->m_commandClassMap.end(); ++it) { CommandClass* cc = it->second; if (cc->GetCommandClassId() == NoOperation::StaticGetCommandClassId()) { continue; } if (cc->HasStaticRequest(StaticRequest_Instances)) { Log::Write(LogLevel_Info, GetNodeId(), "MultiInstanceCmd_Get for %s", cc->GetCommandClassName().c_str()); Msg* msg = new Msg("MultiInstanceCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(MultiInstanceCmd_Get); msg->Append(cc->GetCommandClassId()); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Query); res = true; } } } } else { // MULTI_CHANNEL Log::Write(LogLevel_Info, GetNodeId(), "MultiChannelCmd_EndPointGet for node %d", GetNodeId()); Msg* msg = new Msg("MultiChannelCmd_EndPointGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(MultiChannelCmd_EndPointGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Query); res = true; } return res; } bool MultiInstance::HandleIncomingMsg(uint8 const* _data, uint32 const _length, uint32 const _instance) { return HandleMsg(_data, _length, _instance); } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool MultiInstance::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { bool handled = false; Node* node = GetNodeUnsafe(); if (node != NULL) { handled = true; switch ((MultiInstanceCmd) _data[0]) { case MultiInstanceCmd_Report: { HandleMultiInstanceReport(_data, _length); break; } case MultiInstanceCmd_Encap: { HandleMultiInstanceEncap(_data, _length); break; } case MultiChannelCmd_EndPointReport: { HandleMultiChannelEndPointReport(_data, _length); break; } case MultiChannelCmd_CapabilityReport: { HandleMultiChannelCapabilityReport(_data, _length); break; } case MultiChannelCmd_EndPointFindReport: { HandleMultiChannelEndPointFindReport(_data, _length); break; } case MultiChannelCmd_Encap: { HandleMultiChannelEncap(_data, _length); break; } default: { handled = false; break; } } } return handled; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- void MultiInstance::HandleMultiInstanceReport(uint8 const* _data, uint32 const _length) { if (Node* node = GetNodeUnsafe()) { uint8 commandClassId = _data[1]; uint8 instances = _data[2]; if (CommandClass* pCommandClass = node->GetCommandClass(commandClassId)) { Log::Write(LogLevel_Info, GetNodeId(), "Received MultiInstanceReport from node %d for %s: Number of instances = %d", GetNodeId(), pCommandClass->GetCommandClassName().c_str(), instances); pCommandClass->SetInstances(instances); pCommandClass->ClearStaticRequest(StaticRequest_Instances); } } } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- void MultiInstance::HandleMultiInstanceEncap(uint8 const* _data, uint32 const _length) { if (Node* node = GetNodeUnsafe()) { uint8 instance = _data[1]; if (GetVersion() > 1) { instance &= 0x7f; } uint8 commandClassId = _data[2]; if (CommandClass* pCommandClass = node->GetCommandClass(commandClassId)) { Log::Write(LogLevel_Info, GetNodeId(), "Received a MultiInstanceEncap from node %d, instance %d, for Command Class %s", GetNodeId(), instance, pCommandClass->GetCommandClassName().c_str()); pCommandClass->ReceivedCntIncr(); pCommandClass->HandleMsg(&_data[3], _length - 3, instance); } else { Log::Write(LogLevel_Warning, GetNodeId(), "Received invalid MultiInstanceReport from node %d. Attempting to process as MultiChannel", GetNodeId()); HandleMultiChannelEncap(_data, _length); } } } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- void MultiInstance::HandleMultiChannelEndPointReport(uint8 const* _data, uint32 const _length) { int len; if (m_numEndPoints != 0) { return; } m_numEndPointsCanChange = ((_data[1] & 0x80) != 0); // Number of endpoints can change. m_endPointsAreSameClass = ((_data[1] & 0x40) != 0); // All endpoints are the same command class. /* some devices (eg, Aeotec Smart Dimmer 6 incorrectly report all endpoints are the same */ if (m_com.GetFlagBool(COMPAT_FLAG_MI_FORCEUNIQUEENDPOINTS)) m_endPointsAreSameClass = false; m_numEndPoints = _data[2] & 0x7f; if (m_com.GetFlagByte(COMPAT_FLAG_MI_ENDPOINTHINT) != 0) { m_numEndPoints = m_com.GetFlagByte(COMPAT_FLAG_MI_ENDPOINTHINT); // don't use device's number } len = m_numEndPoints; if (m_endPointsAreSameClass) // only need to check single end point { len = 1; Log::Write(LogLevel_Info, GetNodeId(), "Received MultiChannelEndPointReport from node %d. All %d endpoints are the same.", GetNodeId(), m_numEndPoints); } else { Log::Write(LogLevel_Info, GetNodeId(), "Received MultiChannelEndPointReport from node %d. %d endpoints are not all the same.", GetNodeId(), m_numEndPoints); } // This code assumes the endpoints are all in numeric sequential order. // Since the end point finds do not appear to work this is the best estimate. for (uint8 i = 1; i <= len; i++) { // Send a single capability request to each endpoint Log::Write(LogLevel_Info, GetNodeId(), "MultiChannelCmd_CapabilityGet for endpoint %d", i); Msg* msg = new Msg("MultiChannelCmd_CapabilityGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(MultiChannelCmd_CapabilityGet); msg->Append(i); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- void MultiInstance::HandleMultiChannelCapabilityReport(uint8 const* _data, uint32 const _length) { bool dynamic = ((_data[1] & 0x80) != 0); if (Node* node = GetNodeUnsafe()) { /* if you having problems with Dynamic Devices not correctly * updating the commandclasses, see this email thread: * https://groups.google.com/d/topic/openzwave/IwepxScRAVo/discussion */ if ((m_com.GetFlagBool(COMPAT_FLAG_MI_IGNMCCAPREPORTS) && (node->GetCurrentQueryStage() != Node::QueryStage_Instances)) && !dynamic && m_endPointCommandClasses.size() > 0) { Log::Write(LogLevel_Error, GetNodeId(), "Received a Unsolicited MultiChannelEncap when we are not in QueryState_Instances"); return; } uint8 endPoint = _data[1] & 0x7f; m_endPointGenericType.insert(std::pair(endPoint, _data[2])); m_endPointSpecificType.insert(std::pair(endPoint, _data[3])); Log::Write(LogLevel_Info, GetNodeId(), "Received MultiChannelCapabilityReport from node %d for endpoint %d", GetNodeId(), endPoint); Log::Write(LogLevel_Info, GetNodeId(), " Endpoint is%sdynamic, and is a %s", dynamic ? " " : " not ", node->GetEndPointDeviceClassLabel(_data[2], _data[3]).c_str()); Log::Write(LogLevel_Info, GetNodeId(), " Command classes supported by the endpoint are:"); // Store the command classes for later use bool afterMark = false; m_endPointCommandClasses.clear(); uint8 numCommandClasses = _length - 5; for (uint8 i = 0; i < numCommandClasses; ++i) { uint8 commandClassId = _data[i + 4]; if (commandClassId == 0xef) { afterMark = true; Log::Write(LogLevel_Info, GetNodeId(), " Controlled CommandClasses:"); } if (m_com.GetFlagBool(COMPAT_FLAG_MI_REMOVECC, commandClassId) == true) { Log::Write(LogLevel_Info, GetNodeId(), " %s (%d) (Disabled By Config)", CommandClasses::GetName(commandClassId).c_str(), commandClassId); continue; } // Ensure the node supports this command class CommandClass* cc = node->GetCommandClass(commandClassId); if (!cc) { cc = node->AddCommandClass(commandClassId); } if (cc && afterMark) { cc->SetAfterMark(); Log::Write(LogLevel_Info, GetNodeId(), " %s", cc->GetCommandClassName().c_str()); } else if (cc) { Log::Write(LogLevel_Info, GetNodeId(), " %s", cc->GetCommandClassName().c_str()); } /* The AddCommandClass above will bitch about unsupported CC's so we don't need to duplicate that output */ m_endPointCommandClasses.insert(commandClassId); } // Create internal library instances for each command class in the list // Also set up mapping from intances to endpoints for encapsulation Basic* basic = static_cast(node->GetCommandClass(Basic::StaticGetCommandClassId())); if (m_endPointsAreSameClass) // Create all the same instances here { int len; if (m_com.GetFlagBool(COMPAT_FLAG_MI_MAPROOTTOENDPOINT) == false) // Include the non-endpoint instance { endPoint = 0; len = m_numEndPoints + 1; } else { endPoint = 1; len = m_numEndPoints; } // Create all the command classes for all the endpoints for (uint8 i = 1; i <= len; i++) { //std::cout << "Num Instances: " << len << std::endl; for (set::iterator it = m_endPointCommandClasses.begin(); it != m_endPointCommandClasses.end(); ++it) { uint8 commandClassId = *it; CommandClass* cc = node->GetCommandClass(commandClassId); if (cc) { if (cc->supportsMultiInstance() == false) { Log::Write(LogLevel_Info, GetNodeId(), "%s doesn't support MultiInstance - Not adding Instance", cc->GetCommandClassName().c_str()); continue; } cc->SetInstance(i); if (m_com.GetFlagBool(COMPAT_FLAG_MI_MAPROOTTOENDPOINT) != false || i != 1) { cc->SetEndPoint(i, endPoint); } // If we support the BASIC command class and it is mapped to a command class // assigned to this end point, make sure the BASIC command class is also associated // with this end point. if (basic != NULL && basic->GetMapping() == commandClassId) { basic->SetInstance(i); if (m_com.GetFlagBool(COMPAT_FLAG_MI_MAPROOTTOENDPOINT) != false || i != 1) { basic->SetEndPoint(i, endPoint); } } /* if its the Security CC, on a instance > 1, then this has come from the Security CC found in a MultiInstance Capability Report. * So we need to Query the endpoint for Secured CC's */ if ((commandClassId == Security::StaticGetCommandClassId()) && (i > 1)) { if (!node->IsSecured()) { Log::Write(LogLevel_Info, GetNodeId(), " Skipping Security_Supported_Get, as the Node is not Secured"); } else { Log::Write(LogLevel_Info, GetNodeId(), " Sending Security_Supported_Get to Instance %d", i); Security *seccc = static_cast(node->GetCommandClass(Security::StaticGetCommandClassId())); /* this will trigger a SecurityCmd_SupportedGet on the _instance of the Device. */ if (seccc && !seccc->IsAfterMark()) { seccc->Init(i); } } } } } endPoint++; } } else // Endpoints are different { for (set::iterator it = m_endPointCommandClasses.begin(); it != m_endPointCommandClasses.end(); ++it) { uint8 commandClassId = *it; CommandClass* cc = node->GetCommandClass(commandClassId); if (cc) { if (cc->supportsMultiInstance() == false) { Log::Write(LogLevel_Info, GetNodeId(), "%s doesn't support MultiInstance. Not adding Instances", cc->GetCommandClassName().c_str()); continue; } // get instance gets an instance for an endpoint // but i'm only interested if there is a related instance for an endpoint and not in the actual result // soo if the result is != 0, the endpoint is already handled bool endpointAlreadyHandled = cc->GetInstance(endPoint) != 0; if (endpointAlreadyHandled) { Log::Write(LogLevel_Warning, GetNodeId(), "Received MultiChannelCapabilityReport from node %d for endpoint %d - Endpoint already handled for CommandClass %d", GetNodeId(), endPoint, cc->GetCommandClassId()); continue; } uint8 i; // Find the next free instance of this class for (i = 1; i <= 127; i++) { if (m_com.GetFlagBool(COMPAT_FLAG_MI_MAPROOTTOENDPOINT) == false) // Include the non-endpoint instance { if (!cc->GetInstances()->IsSet(i)) { break; } } // Reuse non-endpoint instances first time we see it else if (i == 1 && cc->GetInstances()->IsSet(i) && cc->GetEndPoint(i) == 0) { break; } // Find the next free instance else if (!cc->GetInstances()->IsSet(i)) { break; } } cc->SetInstance(i); cc->SetEndPoint(i, endPoint); // If we support the BASIC command class and it is mapped to a command class // assigned to this end point, make sure the BASIC command class is also associated // with this end point. if (basic != NULL && basic->GetMapping() == commandClassId) { basic->SetInstance(i); basic->SetEndPoint(i, endPoint); } } } } } } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- void MultiInstance::HandleMultiChannelEndPointFindReport(uint8 const* _data, uint32 const _length) { Log::Write(LogLevel_Info, GetNodeId(), "Received MultiChannelEndPointFindReport from node %d", GetNodeId()); uint8 numEndPoints = _length - 5; for (uint8 i = 0; i < numEndPoints; ++i) { uint8 endPoint = _data[i + 4] & 0x7f; if (m_endPointsAreSameClass) { // Use the stored command class list to set up the endpoint. if (Node* node = GetNodeUnsafe()) { for (set::iterator it = m_endPointCommandClasses.begin(); it != m_endPointCommandClasses.end(); ++it) { uint8 commandClassId = *it; CommandClass* cc = node->GetCommandClass(commandClassId); if (cc) { Log::Write(LogLevel_Info, GetNodeId(), " Endpoint %d: Adding %s", endPoint, cc->GetCommandClassName().c_str()); cc->SetInstance(endPoint); } } } } else { // Endpoints are different, so request the capabilities Log::Write(LogLevel_Info, GetNodeId(), "MultiChannelCmd_CapabilityGet for node %d, endpoint %d", GetNodeId(), endPoint); Msg* msg = new Msg("MultiChannelCmd_CapabilityGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(MultiChannelCmd_CapabilityGet); msg->Append(endPoint); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } } m_numEndPointsFound += numEndPoints; if (!m_endPointsAreSameClass) { if (_data[1] == 0) { // No more reports to follow this one, so we can continue the search. if (m_numEndPointsFound < numEndPoints) { // We have not yet found all the endpoints, so move to the next generic class request ++m_endPointFindIndex; if (m_endPointFindIndex <= 13) /* we are finished */ { if (c_genericClass[m_endPointFindIndex] > 0) { if (m_endPointFindIndex > 13) /* size of c_genericClassName minus Unknown Entry */ { Log::Write(LogLevel_Warning, GetNodeId(), "m_endPointFindIndex Value was greater than range. Setting to Unknown"); m_endPointFindIndex = 14; } Log::Write(LogLevel_Info, GetNodeId(), "MultiChannelCmd_EndPointFind for generic device class 0x%.2x (%s)", c_genericClass[m_endPointFindIndex], c_genericClassName[m_endPointFindIndex]); Msg* msg = new Msg("MultiChannelCmd_EndPointFind", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(MultiChannelCmd_EndPointFind); msg->Append(c_genericClass[m_endPointFindIndex]); // Generic device class msg->Append(0xff); // Any specific device class msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } } else { Log::Write(LogLevel_Warning, GetNodeId(), "m_endPointFindIndex is higher than range. Not Sending MultiChannelCmd_EndPointFind message"); } } } } } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- void MultiInstance::HandleMultiChannelEncap(uint8 const* _data, uint32 const _length) { if (Node* node = GetNodeUnsafe()) { uint8 endPoint = _data[1] & 0x7f; uint8 commandClassId = _data[3]; if (CommandClass* pCommandClass = node->GetCommandClass(commandClassId)) { /* 4.85.13 - If the Root Device is originating a command to an End Point in another node, the Source End Point MUST be set to 0. * */ if (endPoint == 0) { Log::Write(LogLevel_Info, GetNodeId(), "MultiChannelEncap with endpoint set to 0 - Send to Root Device"); pCommandClass->HandleMsg(&_data[4], _length - 4); return; } uint8 instance = pCommandClass->GetInstance(endPoint); /* we can never have a 0 Instance */ if (instance == 0) instance = 1; Log::Write(LogLevel_Info, GetNodeId(), "Received a MultiChannelEncap from node %d, endpoint %d for Command Class %s", GetNodeId(), endPoint, pCommandClass->GetCommandClassName().c_str()); if (!pCommandClass->IsAfterMark()) { if (!pCommandClass->HandleMsg(&_data[4], _length - 4, instance)) { Log::Write(LogLevel_Warning, GetNodeId(), "MultiChannel Encap CommandClass %s HandleMsg returned false", pCommandClass->GetCommandClassName().c_str()); } } else { if (!pCommandClass->HandleIncomingMsg(&_data[4], _length - 4, instance)) { Log::Write(LogLevel_Warning, GetNodeId(), "MultiChannel Encap CommandClass %s HandleIncomingMsg returned false", pCommandClass->GetCommandClassName().c_str()); } } } else { Log::Write(LogLevel_Error, GetNodeId(), "Received a MultiChannelEncap for endpoint %d for Command Class %d, which we can't find", endPoint, commandClassId); } } } //----------------------------------------------------------------------------- // // Set the Generic Label for a Instance //----------------------------------------------------------------------------- void MultiInstance::SetInstanceLabel(uint8 const _instance, char *label) { CommandClass::SetInstanceLabel(_instance, label); /* Set the Default Global Instance Label for CC that don't define their own instance labels */ if (Node* node = GetNodeUnsafe()) { node->SetInstanceLabel(_instance, label); } } //----------------------------------------------------------------------------- // // Get the Generic DeviceType for a EndPoint //----------------------------------------------------------------------------- uint8 MultiInstance::GetGenericInstanceDeviceType(uint8 _instance) { if (m_endPointGenericType.find(_instance) != m_endPointGenericType.end()) return m_endPointGenericType.at(_instance); return 0; } //----------------------------------------------------------------------------- // // Get the Specific DeviceType for a Endpoint //----------------------------------------------------------------------------- uint8 MultiInstance::GetSpecificInstanceDeviceType(uint8 _instance) { if (m_endPointSpecificType.find(_instance) != m_endPointSpecificType.end()) return m_endPointSpecificType.at(_instance); return 0; } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Version.cpp0000644000175200017520000002056514032142455017565 00000000000000//----------------------------------------------------------------------------- // // Version.cpp // // Implementation of the Z-Wave COMMAND_CLASS_VERSION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/Version.h" #include "command_classes/Basic.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "Node.h" #include "platform/Log.h" #include "value_classes/ValueString.h" #include "tinyxml.h" namespace OpenZWave { namespace Internal { namespace CC { enum VersionCmd { VersionCmd_Get = 0x11, VersionCmd_Report = 0x12, VersionCmd_CommandClassGet = 0x13, VersionCmd_CommandClassReport = 0x14 }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Version::Version(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { m_com.EnableFlag(COMPAT_FLAG_VERSION_GETCLASSVERSION, true); SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Version::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { return RequestValue(_requestFlags, 0, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool Version::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 uint8 const _instance, Driver::MsgQueue const _queue) { if (_instance != 1) { // This command class doesn't work with multiple instances return false; } if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("VersionCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(VersionCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "VersionCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Version::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (Node* node = GetNodeUnsafe()) { if (VersionCmd_Report == (VersionCmd) _data[0]) { char library[8]; char protocol[16]; char application[16]; snprintf(library, sizeof(library), "%d", _data[1]); snprintf(protocol, sizeof(protocol), "%d.%.2d", _data[2], _data[3]); snprintf(application, sizeof(application), "%d.%.2d", _data[4], _data[5]); Log::Write(LogLevel_Info, GetNodeId(), "Received Version report from node %d: Library=%s, Protocol=%s, Application=%s", GetNodeId(), library, protocol, application); ClearStaticRequest(StaticRequest_Values); if (Internal::VC::ValueString* libraryValue = static_cast(GetValue(_instance, ValueID_Index_Version::Library))) { libraryValue->OnValueRefreshed(library); libraryValue->Release(); } if (Internal::VC::ValueString* protocolValue = static_cast(GetValue(_instance, ValueID_Index_Version::Protocol))) { protocolValue->OnValueRefreshed(protocol); protocolValue->Release(); } if (Internal::VC::ValueString* applicationValue = static_cast(GetValue(_instance, ValueID_Index_Version::Application))) { applicationValue->OnValueRefreshed(application); applicationValue->Release(); } return true; } if (VersionCmd_CommandClassReport == (VersionCmd) _data[0]) { if (CommandClass* pCommandClass = node->GetCommandClass(_data[1])) { Log::Write(LogLevel_Info, GetNodeId(), "Received CommandClass Version report from node %d: CommandClass=%s, Version=%d", GetNodeId(), pCommandClass->GetCommandClassName().c_str(), _data[2]); pCommandClass->ClearStaticRequest(StaticRequest_Version); /* some devices advertise CommandClasses, but return version as 0. In General this means * that the device doesn't actually support the CommandClass. So lets Remove it. */ if (_data[2] > 0) { pCommandClass->SetVersion(_data[2]); } /* More often than not our Basic CC is needed. */ else if (_data[1] == Basic::StaticGetCommandClassId()) pCommandClass->SetVersion(pCommandClass->GetMaxVersion()); else { Log::Write(LogLevel_Warning, GetNodeId(), "CommandClass Version is 0, Removing CommandClass %s", pCommandClass->GetCommandClassName().c_str()); GetNodeUnsafe()->RemoveCommandClass(_data[1]); } } return true; } } return false; } //----------------------------------------------------------------------------- // // Request the version of a command class used by the device //----------------------------------------------------------------------------- bool Version::RequestCommandClassVersion(CommandClass const* _commandClass) { if (m_com.GetFlagBool(COMPAT_FLAG_VERSION_GETCLASSVERSION)) { /* if its not a "Controlling" command Class */ if ((!_commandClass->IsAfterMark()) && (_commandClass->HasStaticRequest(StaticRequest_Version))) { Msg* msg = new Msg("VersionCmd_CommandClassGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(VersionCmd_CommandClassGet); msg->Append(_commandClass->GetCommandClassId()); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Query); return true; } } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void Version::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueString(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_Version::Library, "Library Version", "", true, false, "Unknown", 0); node->CreateValueString(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_Version::Protocol, "Protocol Version", "", true, false, "Unknown", 0); node->CreateValueString(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_Version::Application, "Application Version", "", true, false, "Unknown", 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/WakeUp.h0000644000175200017520000000715114032142455016775 00000000000000//----------------------------------------------------------------------------- // // WakeUp.h // // Implementation of the Z-Wave COMMAND_CLASS_WAKE_UP // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _WakeUp_H #define _WakeUp_H #include #include "command_classes/CommandClass.h" #include "Driver.h" #include "TimerThread.h" namespace OpenZWave { namespace Internal { namespace Platform { class Mutex; } namespace CC { /** \brief Implements COMMAND_CLASS_WAKE_UP (0x84), a Z-Wave device command class. * \ingroup CommandClass */ class WakeUp: public CommandClass, private Timer { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new WakeUp(_homeId, _nodeId); } virtual ~WakeUp(); static uint8 const StaticGetCommandClassId() { return 0x84; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_WAKE_UP"; } void Init(); // Starts the process of requesting node state from a sleeping device. void QueueMsg(Driver::MsgQueueItem const& _item); /** \brief Send all pending messages followed by a no more information message. */ void SendPending(); /** \brief Send a no more information message. */ void SendNoMoreInfo(uint32 id); bool IsAwake() const { return m_awake; } void SetAwake(bool _state); void SetPollRequired() { m_pollRequired = true; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; virtual uint8 GetMaxVersion() override { return 2; } bool supportsMultiInstance() override { return false; } protected: virtual void CreateVars(uint8 const _instance) override; private: WakeUp(uint32 const _homeId, uint8 const _nodeId); Internal::Platform::Mutex* m_mutex; // Serialize access to the pending queue list m_pendingQueue; // Messages waiting to be sent when the device wakes up bool m_awake; bool m_pollRequired; uint32 m_interval; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/CommandClass.h0000644000175200017520000002254214032142455020146 00000000000000//----------------------------------------------------------------------------- // // CommandClass.h // // Base class for all Z-Wave Command Classes // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _CommandClass_H #define _CommandClass_H #include #include #include #include "Defs.h" #include "Bitfield.h" #include "Driver.h" #include "CompatOptionManager.h" namespace OpenZWave { class Msg; class Node; class Value; namespace Internal { namespace CC { /** \defgroup CommandClass Z-Wave CommandClass Support * * This is the CommandClasses that OZW currently supports. Typically, a Application does not need * to be aware of the CommandClasses a Device exposes, as they would be transparently exposed to the * application as ValueID's */ /** \brief Base class for all Z-Wave command classes. * \ingroup CommandClass */ class OPENZWAVE_EXPORT CommandClass { friend Internal::VC::ValueStore; public: enum { RequestFlag_Static = 0x00000001, /**< Values that never change. */ RequestFlag_Session = 0x00000002, /**< Values that change infrequently, and so only need to be requested at start up, or via a manual refresh. */ RequestFlag_Dynamic = 0x00000004, /**< Values that change and will be requested if polling is enabled on the node. */ RequestFlag_AfterMark = 0x00000008 /**< Values relevent to Controlling CC, not Controlled CC. */ }; CommandClass(uint32 const _homeId, uint8 const _nodeId); virtual ~CommandClass(); virtual void ReadXML(TiXmlElement const* _ccElement); virtual void WriteXML(TiXmlElement* _ccElement); virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { return false; } virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) { return false; } virtual void refreshValuesOnWakeup(); virtual uint8 const GetCommandClassId() const = 0; virtual string const GetCommandClassName() const = 0; string const GetCommandClassLabel(); void SetCommandClassLabel(string label); virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) = 0; virtual bool HandleIncomingMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1); virtual bool SetValue(Internal::VC::Value const& _value) { return false; } virtual void SetValueBasic(uint8 const _instance, uint8 const _level) { } // Class specific handling of BASIC value mapping virtual void SetVersion(uint8 const _version); // Made out-of-line to allow checks against downgrade bool RequestStateForAllInstances(uint32 const _requestFlags, Driver::MsgQueue const _queue); bool CheckForRefreshValues(Internal::VC::Value const* _value); // The highest version number of the command class implemented by OpenZWave. We only need // to do version gets on command classes that override this with a number greater than one. virtual uint8 GetMaxVersion() { return 1; } uint8 GetVersion() const { return m_dom.GetFlagByte(STATE_FLAG_CCVERSION); } Bitfield const* GetInstances() const { return &m_instances; } uint32 GetHomeId() const { return m_homeId; } uint8 GetNodeId() const { return m_nodeId; } Driver* GetDriver() const; Node* GetNodeUnsafe() const; Internal::VC::Value* GetValue(uint8 const _instance, uint16 const _index); bool RemoveValue(uint8 const _instance, uint16 const _index); uint8 GetEndPoint(uint8 const _instance) { map::iterator it = m_endPointMap.find(_instance); return (it == m_endPointMap.end() ? 0 : it->second); } uint8 GetInstance(uint8 const _endPoint) { for (map::iterator it = m_endPointMap.begin(); it != m_endPointMap.end(); ++it) { if (_endPoint == it->second) { return it->first; } } return 0; } virtual bool supportsMultiInstance() { return true; } void SetInstances(uint8 const _instances); void SetInstance(uint8 const _endPoint); /* overridden in the MultiInstance CC to set the Global Label for each Instance */ virtual void SetInstanceLabel(uint8 const _instance, char *label); string GetInstanceLabel(uint8 const _instance); uint8 GetNumInstances() { return (uint8) m_endPointMap.size(); } ; void SetAfterMark() { m_dom.SetFlagBool(STATE_FLAG_AFTERMARK, true); } void SetEndPoint(uint8 const _instance, uint8 const _endpoint) { m_endPointMap[_instance] = _endpoint; } bool IsAfterMark() const { return m_dom.GetFlagBool(STATE_FLAG_AFTERMARK); } bool IsSecured() const { return m_dom.GetFlagBool(STATE_FLAG_ENCRYPTED); } void SetSecured() { m_dom.SetFlagBool(STATE_FLAG_ENCRYPTED, true); } bool IsSecureSupported() const { return m_SecureSupport; } void ClearSecureSupport() { m_SecureSupport = false; } void SetSecureSupport() { m_SecureSupport = true; } void SetInNIF() { m_dom.SetFlagBool(STATE_FLAG_INNIF, true); } bool IsInNIF() { return m_dom.GetFlagBool(STATE_FLAG_INNIF); } // Helper methods string ExtractValue(uint8 const* _data, uint8* _scale, uint8* _precision, uint8 _valueOffset = 1) const; uint32 decodeDuration(uint8 data) const; uint8 encodeDuration(uint32 seconds) const; /** * Append a floating-point value to a message. * \param _msg The message to which the value should be appended. * \param _value A string containing a decimal number to be appended. * \param _scale A byte indicating the scale corresponding to this value (e.g., 1=F and 0=C for temperatures). * \see Msg */ void AppendValue(Msg* _msg, string const& _value, uint8 const _scale) const; uint8 const GetAppendValueSize(string const& _value) const; int32 ValueToInteger(string const& _value, uint8* o_precision, uint8* o_size) const; void UpdateMappedClass(uint8 const _instance, uint8 const _classId, uint8 const _value); // Update mapped class's value from BASIC class typedef struct RefreshValue { uint8 cc; uint8 requestflags; uint16 index; } RefreshValue; protected: virtual void CreateVars(uint8 const _instance); void ReadValueRefreshXML(TiXmlElement const* _ccElement); CompatOptionManager m_com; CompatOptionManager m_dom; public: void CreateVars(); private: uint32 m_homeId; uint8 m_nodeId; Bitfield m_instances; map m_endPointMap; map m_instanceLabel; bool m_SecureSupport; // Does this commandclass support secure encryption (eg, the Security CC doesn't encrypt itself, so it doesn't support encryption) multimap m_RefreshClassValues; // what Command Class Values should we refresh ? string m_commandClassLabel; //----------------------------------------------------------------------------- // Record which items of static data have been read from the device //----------------------------------------------------------------------------- public: enum StaticRequest { StaticRequest_Instances = 0x01, StaticRequest_Values = 0x02, StaticRequest_Version = 0x04 }; bool HasStaticRequest(uint8_t _request) const { return ((m_dom.GetFlagByte(STATE_FLAG_STATIC_REQUESTS) & _request) != 0); } void SetStaticRequest(uint8_t _request); void ClearStaticRequest(uint8_t _request); //----------------------------------------------------------------------------- // Statistics //----------------------------------------------------------------------------- public: uint32 GetSentCnt() const { return m_sentCnt; } uint32 GetReceivedCnt() const { return m_receivedCnt; } void SentCntIncr() { m_sentCnt++; } void ReceivedCntIncr() { m_receivedCnt++; } private: uint32 m_sentCnt; // Number of messages sent from this command class. uint32 m_receivedCnt; // Number of messages received from this commandclass. }; //@} }// namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/SwitchToggleMultilevel.cpp0000644000175200017520000001643414032142455022606 00000000000000//----------------------------------------------------------------------------- // // SwitchToggleMultilevel.cpp // // Implementation of the Z-Wave COMMAND_CLASS_SWITCH_TOGGLE_MULTILEVEL // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/SwitchToggleMultilevel.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "Node.h" #include "platform/Log.h" #include "value_classes/ValueByte.h" namespace OpenZWave { namespace Internal { namespace CC { enum SwitchToggleMultilevelCmd { SwitchToggleMultilevelCmd_Set = 0x01, SwitchToggleMultilevelCmd_Get = 0x02, SwitchToggleMultilevelCmd_Report = 0x03, SwitchToggleMultilevelCmd_StartLevelChange = 0x04, SwitchToggleMultilevelCmd_StopLevelChange = 0x05 }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool SwitchToggleMultilevel::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Dynamic) { return RequestValue(_requestFlags, 0, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool SwitchToggleMultilevel::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("SwitchToggleMultilevelCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SwitchToggleMultilevelCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "SwitchToggleMultilevelCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool SwitchToggleMultilevel::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (SwitchToggleMultilevelCmd_Report == (SwitchToggleMultilevelCmd) _data[0]) { Log::Write(LogLevel_Info, GetNodeId(), "Received SwitchToggleMultiLevel report: level=%d", _data[1]); if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_SwitchToggleMultilevel::Level))) { value->OnValueRefreshed(_data[1]); value->Release(); } return true; } return false; } //----------------------------------------------------------------------------- // // Toggle the state of the switch //----------------------------------------------------------------------------- bool SwitchToggleMultilevel::SetValue(Internal::VC::Value const& _value) { Log::Write(LogLevel_Info, GetNodeId(), "SwitchToggleMultilevel::Set - Toggling the state"); Msg* msg = new Msg("SwitchToggleMultilevelCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SwitchToggleMultilevelCmd_Set); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } //----------------------------------------------------------------------------- // // Start the level changing //----------------------------------------------------------------------------- void SwitchToggleMultilevel::StartLevelChange(SwitchToggleMultilevelDirection const _direction, bool const _bIgnoreStartLevel, bool const _bRollover) { uint8 param = (uint8) _direction; param |= (_bIgnoreStartLevel ? 0x20 : 0x00); param |= (_bRollover ? 0x80 : 0x00); Log::Write(LogLevel_Info, GetNodeId(), "SwitchMultilevel::StartLevelChange - Starting a level change, Direction=%d, IgnoreStartLevel=%s and rollover=%s", (_direction == SwitchToggleMultilevelDirection_Up) ? "Up" : "Down", _bIgnoreStartLevel ? "True" : "False", _bRollover ? "True" : "False"); Msg* msg = new Msg("SwitchToggleMultilevelCmd_StartLevelChange", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(SwitchToggleMultilevelCmd_StartLevelChange); msg->Append(param); msg->Append(GetDriver()->GetTransmitOptions()); } //----------------------------------------------------------------------------- // // Stop the level changing //----------------------------------------------------------------------------- void SwitchToggleMultilevel::StopLevelChange() { Log::Write(LogLevel_Info, GetNodeId(), "SwitchToggleMultilevel::StopLevelChange - Stopping the level change"); Msg* msg = new Msg("SwitchToggleMultilevelCmd_StopLevelChange", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SwitchToggleMultilevelCmd_StopLevelChange); msg->Append(GetDriver()->GetTransmitOptions()); } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void SwitchToggleMultilevel::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_SwitchToggleMultilevel::Level, "Level", "", false, false, 0, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/ControllerReplication.cpp0000644000175200017520000002304414032142455022450 00000000000000//----------------------------------------------------------------------------- // // ControllerReplication.cpp // // Implementation of the Z-Wave COMMAND_CLASS_CONTROLLER_REPLICATION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/ControllerReplication.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "Node.h" #include "Utils.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueList.h" #include "value_classes/ValueButton.h" namespace OpenZWave { namespace Internal { namespace CC { enum ControllerReplicationCmd { ControllerReplicationCmd_TransferGroup = 0x31, ControllerReplicationCmd_TransferGroupName = 0x32, ControllerReplicationCmd_TransferScene = 0x33, ControllerReplicationCmd_TransferSceneName = 0x34 }; static char const* c_controllerReplicationFunctionNames[] = { "Groups", "Group Names", "Scenes", "Scene Names", }; //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- ControllerReplication::ControllerReplication(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_busy(false), m_targetNodeId(0), m_funcId(0), m_nodeId(-1), m_groupCount(-1), m_groupIdx(-1) { } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool ControllerReplication::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { // When creating replication messages, use FUNC_ID_ZW_SEND_REPLICATION_DATA instead of FUNC_ID_ZW_SEND_DATA // e.g. Msg* msg = new Msg( "TransferGroup", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_REPLICATION_DATA, true, false ); switch (_data[0]) { case ControllerReplicationCmd_TransferGroup: { break; } case ControllerReplicationCmd_TransferGroupName: { break; } case ControllerReplicationCmd_TransferScene: { break; } case ControllerReplicationCmd_TransferSceneName: { break; } } Msg* msg = new Msg("ControllerReplicationCmd_Complete", GetNodeId(), REQUEST, FUNC_ID_ZW_REPLICATION_COMMAND_COMPLETE, false, false); GetDriver()->SendMsg(msg, Driver::MsgQueue_Command); return true; } //----------------------------------------------------------------------------- // // Set a value on the Z-Wave device //----------------------------------------------------------------------------- bool ControllerReplication::SetValue(Internal::VC::Value const& _value) { bool res = false; uint8 instance = _value.GetID().GetInstance(); switch (_value.GetID().GetIndex()) { case ValueID_Index_ControllerReplication::NodeId: { if (Internal::VC::ValueByte* value = static_cast(GetValue(instance, (uint16) ValueID_Index_ControllerReplication::NodeId))) { value->OnValueRefreshed((static_cast(&_value))->GetValue()); value->Release(); res = true; } break; } case ValueID_Index_ControllerReplication::Function: { if (Internal::VC::ValueList* value = static_cast(GetValue(instance, ValueID_Index_ControllerReplication::Function))) { Internal::VC::ValueList::Item const *item = (static_cast(&_value))->GetItem(); value->OnValueRefreshed(item->m_value); value->Release(); res = true; } break; } case ValueID_Index_ControllerReplication::Replicate: { if (Internal::VC::ValueButton* button = static_cast(GetValue(instance, ValueID_Index_ControllerReplication::Replicate))) { if (button->IsPressed()) { res = StartReplication(instance); } button->Release(); } break; } } return res; } //----------------------------------------------------------------------------- // // Set up the group and scene data to be sent to the other controller //----------------------------------------------------------------------------- bool ControllerReplication::StartReplication(uint8 const _instance) { if (m_busy) { return false; } if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_ControllerReplication::NodeId))) { m_targetNodeId = value->GetValue(); value->Release(); } else { return false; } if (Internal::VC::ValueList* value = static_cast(GetValue(_instance, ValueID_Index_ControllerReplication::Function))) { Internal::VC::ValueList::Item const *item = value->GetItem(); if (item) m_funcId = item->m_value; value->Release(); } else { return false; } // Store the Z-Wave command we should use when replication has completed. m_nodeId = -1; m_groupCount = -1; m_groupIdx = -1; m_busy = true; // Set up the groups and scenes to be sent SendNextData(); return true; } //----------------------------------------------------------------------------- // // Send the next block of replication data //----------------------------------------------------------------------------- void ControllerReplication::SendNextData() { uint16 i = 255; if (!m_busy) { return; } while (1) { if (m_groupIdx != -1) { m_groupIdx++; if (m_groupIdx <= m_groupCount) { break; } } i = m_nodeId == -1 ? 0 : m_nodeId + 1; LockGuard LG(GetDriver()->m_nodeMutex); while (i < 256) { if (GetDriver()->m_nodes[i]) { m_groupCount = GetDriver()->m_nodes[i]->GetNumGroups(); if (m_groupCount != 0) { m_groupName = GetDriver()->m_nodes[i]->GetGroupLabel(m_groupIdx); m_groupIdx = m_groupName.length() > 0 ? 0 : 1; break; } } i++; } m_nodeId = i; break; } if (i < 255) { Msg* msg = new Msg((m_groupName.length() > 0 ? "ControllerReplicationCmd_TransferGroupName" : "ControllerReplicationCmd_TransferGroup"), m_targetNodeId, REQUEST, FUNC_ID_ZW_REPLICATION_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(m_targetNodeId); if (m_groupName.length() > 0) { msg->Append((uint8) (m_groupName.length() + 4)); msg->Append(GetCommandClassId()); msg->Append(ControllerReplicationCmd_TransferGroupName); msg->Append(0); msg->Append(m_groupIdx); for (uint8 j = 0; j < m_groupName.length(); j++) { msg->Append(m_groupName[j]); } m_groupName = ""; } else { msg->Append(5); msg->Append(GetCommandClassId()); msg->Append(ControllerReplicationCmd_TransferGroup); msg->Append(0); msg->Append(m_groupIdx); msg->Append(m_nodeId); } msg->Append( TRANSMIT_OPTION_ACK); GetDriver()->SendMsg(msg, Driver::MsgQueue_Command); } else { GetDriver()->AddNodeStop(m_funcId); m_busy = false; } } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void ControllerReplication::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueByte(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_ControllerReplication::NodeId, "Node", "", false, false, 0, 0); vector items; Internal::VC::ValueList::Item item; for (uint8 i = 0; i < 4; ++i) { item.m_label = c_controllerReplicationFunctionNames[i]; item.m_value = ControllerReplicationCmd_TransferGroup + i; items.push_back(item); } node->CreateValueList(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_ControllerReplication::Function, "Functions", "", false, false, 1, items, 0, 0); node->CreateValueButton(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_ControllerReplication::Replicate, "Replicate", 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/SoundSwitch.h0000644000175200017520000000547714032142455020064 00000000000000//----------------------------------------------------------------------------- // // SoundSwitch.h // // Implementation of the Z-Wave COMMAND_CLASS_SOUND_SWITCH // // Copyright (c) 2014 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _SoundSwitch_H #define _SoundSwitch_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_SOUND_SWITCH (0x79), a Z-Wave device command class. * \ingroup CommandClass */ class SoundSwitch: public CommandClass { private: struct SoundSwitchToneInfo { uint16 duration; string name; }; public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new SoundSwitch(_homeId, _nodeId); } virtual ~SoundSwitch() { } static uint8 const StaticGetCommandClassId() { return 0x79; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_SOUND_SWITCH"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: SoundSwitch(uint32 const _homeId, uint8 const _nodeId); uint8 m_toneCount; std::map m_toneInfo; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/SensorMultilevel.h0000644000175200017520000000532714032142455021120 00000000000000//----------------------------------------------------------------------------- // // SensorMultilevel.h // // Implementation of the Z-Wave COMMAND_CLASS_SENSOR_MULTILEVEL // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _SensorMultilevel_H #define _SensorMultilevel_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_SENSOR_MULTILEVEL (0x31), a Z-Wave device command class. * \ingroup CommandClass */ class SensorMultilevel: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new SensorMultilevel(_homeId, _nodeId); } virtual ~SensorMultilevel() { } static uint8 const StaticGetCommandClassId() { return 0x31; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_SENSOR_MULTILEVEL"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _dummy, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual uint8 GetMaxVersion() override { return 11; } private: SensorMultilevel(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } std::map SensorScaleMap; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/ThermostatMode.cpp0000644000175200017520000003172714032142455021101 00000000000000//----------------------------------------------------------------------------- // // ThermostatMode.cpp // // Implementation of the Z-Wave COMMAND_CLASS_THERMOSTAT_MODE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/ThermostatMode.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueList.h" #include "tinyxml.h" namespace OpenZWave { namespace Internal { namespace CC { enum ThermostatModeCmd { ThermostatModeCmd_Set = 0x01, ThermostatModeCmd_Get = 0x02, ThermostatModeCmd_Report = 0x03, ThermostatModeCmd_SupportedGet = 0x04, ThermostatModeCmd_SupportedReport = 0x05 }; enum { ThermostatMode_Off = 0, ThermostatMode_Heat, ThermostatMode_Cool, ThermostatMode_Auto, ThermostatMode_Auxiliary, ThermostatMode_Resume_On, ThermostatMode_Fan, ThermostatMode_Furnance, ThermostatMode_Dry, ThermostatMode_Moist, ThermostatMode_AutoChangeover, ThermostatMode_HeatingEcon, ThermostatMode_CoolingEcon, ThermostatMode_Away, ThermostatMode_Reserved0E = 0x0E, ThermostatMode_FullPower, ThermostatMode_Reserved10 = 0x10, ThermostatMode_Reserved11, ThermostatMode_Reserved12, ThermostatMode_Reserved13, ThermostatMode_Reserved14, ThermostatMode_Reserved15, ThermostatMode_Reserved16, ThermostatMode_Reserved17, ThermostatMode_Reserved18, ThermostatMode_Reserved19, ThermostatMode_Reserved1A, ThermostatMode_Reserved1B, ThermostatMode_Reserved1C, ThermostatMode_Reserved1D, ThermostatMode_Reserved1E, ThermostatMode_ManufacturerSpecific = 0x1F, ThermostatMode_Count, }; static char const* c_modeName[] = { "Off", "Heat", "Cool", "Auto", "Aux Heat", "Resume", "Fan Only", "Furnace", "Dry Air", "Moist Air", "Auto Changeover", "Heat Econ", "Cool Econ", "Away", "Unknown", "Full Power", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Manufacturer Specific" }; ThermostatMode::ThermostatMode(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_currentMode(0) { SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Read the supported modes //----------------------------------------------------------------------------- void ThermostatMode::ReadXML(TiXmlElement const* _ccElement) { CommandClass::ReadXML(_ccElement); if (GetNodeUnsafe()) { vector supportedModes; TiXmlElement const* supportedModesElement = _ccElement->FirstChildElement("SupportedModes"); if (supportedModesElement) { TiXmlElement const* modeElement = supportedModesElement->FirstChildElement(); while (modeElement) { char const* str = modeElement->Value(); if (str && !strcmp(str, "Mode")) { int index; if (TIXML_SUCCESS == modeElement->QueryIntAttribute("index", &index)) { if (index > ThermostatMode_Count) { Log::Write(LogLevel_Warning, GetNodeId(), "index Value in XML was greater than range. Setting to Invalid"); index = ThermostatMode_Count + 1; } Internal::VC::ValueList::Item item; item.m_value = index; item.m_label = c_modeName[index]; supportedModes.push_back(item); } } modeElement = modeElement->NextSiblingElement(); } } if (!supportedModes.empty()) { m_supportedModes = supportedModes; } } } //----------------------------------------------------------------------------- // // Save the supported modes //----------------------------------------------------------------------------- void ThermostatMode::WriteXML(TiXmlElement* _ccElement) { CommandClass::WriteXML(_ccElement); if (m_supportedModes.empty()) { return; } if (GetNodeUnsafe()) { TiXmlElement* supportedModesElement = new TiXmlElement("SupportedModes"); _ccElement->LinkEndChild(supportedModesElement); for (vector::iterator it = m_supportedModes.begin(); it != m_supportedModes.end(); ++it) { Internal::VC::ValueList::Item const& item = *it; TiXmlElement* modeElement = new TiXmlElement("Mode"); supportedModesElement->LinkEndChild(modeElement); char str[8]; snprintf(str, 8, "%d", item.m_value); modeElement->SetAttribute("index", str); modeElement->SetAttribute("label", item.m_label.c_str()); } } } //----------------------------------------------------------------------------- // // Get the static thermostat mode details from the device //----------------------------------------------------------------------------- bool ThermostatMode::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool requests = false; if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { // request supported mode list requests |= RequestValue(_requestFlags, 0, _instance, _queue); } if (_requestFlags & RequestFlag_Dynamic) { // Request the current mode requests |= RequestValue(_requestFlags, ValueID_Index_ThermostatMode::Mode, _instance, _queue); } return requests; } //----------------------------------------------------------------------------- // // Get the static thermostat mode details from the device //----------------------------------------------------------------------------- bool ThermostatMode::RequestValue(uint32 const _requestFlags, uint16 const _getTypeEnum, uint8 const _instance, Driver::MsgQueue const _queue) { if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { // Request the supported modes Msg* msg = new Msg("ThermostatModeCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(ThermostatModeCmd_SupportedGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else if (_getTypeEnum == ValueID_Index_ThermostatMode::Mode) // get current mode { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { // Request the current mode Msg* msg = new Msg("ThermostatModeCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(ThermostatModeCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "ThermostatModeCmd_Get Not Supported on this node"); } } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool ThermostatMode::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (ThermostatModeCmd_Report == (ThermostatModeCmd) _data[0]) { uint8 mode = _data[1] & 0x1f; bool validMode = false; for (vector::iterator it = m_supportedModes.begin(); it != m_supportedModes.end(); ++it) { Internal::VC::ValueList::Item const& item = *it; if (item.m_value == mode) { validMode = true; break; } } if (validMode) { // We have received the thermostat mode from the Z-Wave device if (Internal::VC::ValueList* valueList = static_cast(GetValue(_instance, ValueID_Index_ThermostatMode::Mode))) { valueList->OnValueRefreshed(mode); if (valueList->GetItem()) Log::Write(LogLevel_Info, GetNodeId(), "Received thermostat mode: %s", valueList->GetItem()->m_label.c_str()); else Log::Write(LogLevel_Warning, GetNodeId(), "Received thermostat mode: %d (No Item)", mode); valueList->Release(); } else { Log::Write(LogLevel_Info, GetNodeId(), "Received thermostat mode: index %d (No ValueID)", mode); } m_currentMode = mode; } else { Log::Write(LogLevel_Warning, GetNodeId(), "Received unknown thermostat mode: index %d", mode); } return true; } if (ThermostatModeCmd_SupportedReport == (ThermostatModeCmd) _data[0]) { // We have received the supported thermostat modes from the Z-Wave device // these values are used to populate m_supportedModes which, in turn, is used to "seed" the values // for each m_modes instance Log::Write(LogLevel_Info, GetNodeId(), "Received supported thermostat modes"); m_supportedModes.clear(); for (uint32 i = 1; i < _length - 1; ++i) { for (int32 bit = 0; bit < 8; ++bit) { if ((_data[i] & (1 << bit)) != 0) { Internal::VC::ValueList::Item item; item.m_value = (int32) ((i - 1) << 3) + bit; /* minus 1 in the sizeof calc here, as the Unknown entry is our addition */ if ((size_t) item.m_value >= (sizeof(c_modeName) / sizeof(*c_modeName) - 1)) { Log::Write(LogLevel_Info, GetNodeId(), "Received unknown thermostat mode: 0x%x", item.m_value); } else { item.m_label = c_modeName[item.m_value]; m_supportedModes.push_back(item); Log::Write(LogLevel_Info, GetNodeId(), " Added mode: %s", c_modeName[item.m_value]); } } } } /* at this stage, we don't know the Actual Mode of the Fan, so set it to the lowest * value... If not, set to 0, which possibly could be invalid... */ if (!m_supportedModes.empty()) { m_currentMode = m_supportedModes[0].m_value; } else { m_currentMode = 0; } if (Node* node = GetNodeUnsafe()) { node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ThermostatMode::Mode, "Mode", "", false, false, 1, m_supportedModes, m_currentMode, 0); } return true; } return false; } //----------------------------------------------------------------------------- // // Set the device's thermostat mode //----------------------------------------------------------------------------- bool ThermostatMode::SetValue(Internal::VC::Value const& _value) { if (ValueID::ValueType_List == _value.GetID().GetType()) { Internal::VC::ValueList const* value = static_cast(&_value); if (value->GetItem() == NULL) return false; uint8 state = (uint8) value->GetItem()->m_value; Msg* msg = new Msg("ThermostatModeCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(ThermostatModeCmd_Set); msg->Append(state); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void ThermostatMode::CreateVars(uint8 const _instance) { } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Proprietary.h0000644000175200017520000000443414032142455020122 00000000000000//----------------------------------------------------------------------------- // // Proprietary.h // // Implementation of the Z-Wave COMMAND_CLASS_PROPRIETARY // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Proprietary_H #define _Proprietary_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_PROPRIETARY (0x88), a Z-Wave device command class. * \ingroup CommandClass */ class Proprietary: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Proprietary(_homeId, _nodeId); } virtual ~Proprietary() { } static uint8 const StaticGetCommandClassId() { return 0x88; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_PROPRIETARY"; } // From CommandClass virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; private: Proprietary(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Color.cpp0000644000175200017520000011141714032142455017213 00000000000000//----------------------------------------------------------------------------- // // Color.cpp // // Implementation of the Z-Wave COMMAND_CLASS_COLOR // // Copyright (c) 2014 GizMoCuz // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include "command_classes/CommandClasses.h" #include "command_classes/Color.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueInt.h" #include "value_classes/ValueString.h" #include "value_classes/ValueByte.h" #include "tinyxml.h" namespace OpenZWave { namespace Internal { namespace CC { enum ColorCmd { ColorCmd_Capability_Get = 0x01, ColorCmd_Capability_Report = 0x02, ColorCmd_Get = 0x03, ColorCmd_Report = 0x04, ColorCmd_Set = 0x05, /* Version 2 */ ColorCmd_StartCapabilityLevelChange = 0x06, ColorCmd_StopStateChange = 0x07 }; //Capabilities //0=Warm White (0x00 - 0xFF: 0 100%) //1=Cold White (0x00 - 0xFF: 0 100%) //2=Red (0x00 - 0xFF: 0 100%) //3=Green (0x00 - 0xFF: 0 100%) //4=Blue (0x00 - 0xFF: 0 100%) //5=Amber (for 6ch Color mixing) (0x00 - 0xFF: 0 100%) //6=Cyan (for 6ch Color mixing) (0x00 - 0xFF: 0 100%) //7=Purple (for 6ch Color mixing) (0x00 - 0xFF: 0 100%) //8=Indexed Color (0x00 0x0FF: Color Index 0 - 255 enum ColorIDX { COLORIDX_WARMWHITE, COLORIDX_COLDWHITE, COLORIDX_RED, COLORIDX_GREEN, COLORIDX_BLUE, COLORIDX_AMBER, COLORIDX_CYAN, COLORIDX_PURPLE, COLORIDX_INDEXCOLOR }; static char const* c_ColorIndex[] = { "Off", "Cool White", "Warm White", "Red", "Lime", "Blue", "Yellow", "Cyan", "Magenta", "Silver", "Gray", "Maroon", "Olive", "Green", "Purple", "Teal", "Navy", "Custom" }; enum ValueIDSystemIndexes { }; Color::Color(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_refreshinprogress(false), m_coloridxcount(0) { m_com.EnableFlag(COMPAT_FLAG_COLOR_IDXBUG, false); m_dom.EnableFlag(STATE_FLAG_COLOR_CHANNELS, 0); for (uint8 i = 0; i < 9; i++) m_colorvalues[i] = 0; SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Color::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { bool requests = false; if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { /* if we havn't got a valid capability from our Config File, then get what the device is capable of. If the user changes the Color Channels Value we use the stored version instead */ if (m_dom.GetFlagShort(STATE_FLAG_COLOR_CHANNELS) == 0) { Msg* msg = new Msg("ColorCmd_CapabilityGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(ColorCmd_Capability_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); } return true; } if (_requestFlags & RequestFlag_Dynamic) { /* do a request for each channel. the RequestValue will filter out channels that are not supported * by the device */ if (m_refreshinprogress == true) { Log::Write(LogLevel_Info, GetNodeId(), "Color Refresh in progress"); return false; } /* if the device has the ColorIDX bug, then only request the first channel. We will get the rest later */ for (int i = 0; i <= 9; i++) { bool tmprequests = RequestColorChannelReport(i, _instance, _queue); if (tmprequests) m_coloridxcount = i; requests |= tmprequests; if (m_com.GetFlagBool(COMPAT_FLAG_COLOR_IDXBUG) && tmprequests) { m_refreshinprogress = true; break; } } } return requests; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool Color::RequestValue(uint32 const _requestFlags, uint16 const _what, uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED) && (_what == ValueID_Index_Color::Color || _what == ValueID_Index_Color::Index)) { if (m_com.GetFlagBool(COMPAT_FLAG_COLOR_IDXBUG) && m_refreshinprogress == true) { Log::Write(LogLevel_Warning, GetNodeId(), "ColorRefresh is already in progress. Ignoring Get Request"); return false; } for (int i = 0; i <= 9; i++) { if (RequestColorChannelReport(i, _instance, _queue)) { if (m_com.GetFlagBool(COMPAT_FLAG_COLOR_IDXBUG)) { m_refreshinprogress = true; m_coloridxcount = 0; return true; } } } } return false; } bool Color::RequestColorChannelReport(uint8 const coloridx, uint8 const _instance, Driver::MsgQueue const _queue) { /* make sure our coloridx is valid */ if ((m_dom.GetFlagShort(STATE_FLAG_COLOR_CHANNELS)) & (1 << (coloridx))) { Msg* msg = new Msg("ColorCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(ColorCmd_Get); msg->Append(coloridx); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } return false; } //----------------------------------------------------------------------------- // // Get a Specific Color Value from a position in a RGB String // its assumed the string is formated such as #RRGGBB[WWCWAMCYPR] // where the color values in [] are optional. // throws a exception when position is out of bounds //----------------------------------------------------------------------------- uint16 GetColor(std::string rgbstring, uint8 const position) { /* check the length of the string based on position value we passed in including the #*/ if (rgbstring.length() < (size_t) (position * 2) + 1) { OpenZWave::Log::Write(OpenZWave::LogLevel_Warning, "Request for Color Position %d exceeds String Length: %s", position, rgbstring.c_str()); throw; } std::string result = rgbstring.substr(((position - 1) * 2) + 1, 2); std::stringstream ss(result); uint16 rawresult; ss >> std::hex >> rawresult; return rawresult; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Color::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (ColorCmd_Capability_Report == (ColorCmd) _data[0]) { m_dom.SetFlagShort(STATE_FLAG_COLOR_CHANNELS, (_data[1] + (_data[2] << 8))); uint16_t f_capabilities = m_dom.GetFlagShort(STATE_FLAG_COLOR_CHANNELS); string helpstr = "#RRGGBB"; Log::Write(LogLevel_Info, GetNodeId(), "Received an Color Capability Report: Capability=%x", f_capabilities); if (f_capabilities & 0x04) Log::Write(LogLevel_Info, GetNodeId(), "Red (0x02)"); if (f_capabilities & 0x08) Log::Write(LogLevel_Info, GetNodeId(), "Green (0x03)"); if (f_capabilities & 0x10) Log::Write(LogLevel_Info, GetNodeId(), "Blue (0x04)"); if (f_capabilities & 0x01) { Log::Write(LogLevel_Info, GetNodeId(), "Warm White (0x00)"); helpstr += "WW"; } if (f_capabilities & 0x02) { Log::Write(LogLevel_Info, GetNodeId(), "Cold White (0x01)"); helpstr += "CW"; } if (f_capabilities & 0x20) { Log::Write(LogLevel_Info, GetNodeId(), "Amber (0x05)"); helpstr += "AM"; } if (f_capabilities & 0x40) { Log::Write(LogLevel_Info, GetNodeId(), "Cyan (0x06)"); helpstr += "CY"; } if (f_capabilities & 0x80) { Log::Write(LogLevel_Info, GetNodeId(), "Purple (0x07)"); helpstr += "PR"; } if (f_capabilities & 0x100) Log::Write(LogLevel_Info, GetNodeId(), "Indexed Color (0x08)"); if (Internal::VC::ValueInt* colorchannels = static_cast(GetValue(_instance, ValueID_Index_Color::Channels_Capabilities))) { colorchannels->OnValueRefreshed(f_capabilities); colorchannels->Release(); } if (Node* node = GetNodeUnsafe()) { if (Internal::VC::ValueString *color = static_cast(GetValue(_instance, ValueID_Index_Color::Color))) { color->SetUnits(helpstr); } else { node->CreateValueString(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Color::Color, "Color", helpstr, false, false, "#000000", 0); } /* always create the ColorIndex Value - If the device doesn't support Indexed Colors, we fake it up when sending */ { vector items; unsigned int size = (sizeof(c_ColorIndex) / sizeof(c_ColorIndex[0])); for (unsigned int i = 0; i < size; i++) { Internal::VC::ValueList::Item item; item.m_label = c_ColorIndex[i]; item.m_value = i; items.push_back(item); } node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Color::Index, "Color Index", "", false, false, (sizeof(c_ColorIndex) / sizeof(c_ColorIndex[0])), items, 0, 0); } if (GetVersion() > 1) node->CreateValueInt(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Color::Duration, "Duration", "Sec", false, false, -1, 0); if (GetVersion() > 2) node->CreateValueString(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Color::Target, "Target Color", helpstr, true, false, "#000000", 0); } return true; } if (ColorCmd_Report == (ColorCmd) _data[0]) { /* Fibaro is messed up. It always returns 0x03 as the Coloridx in a report message, but the values are correct for what the request was. * I read a forum post about it being a bug. If this is a case, its going to make this class messy as hell :( * * http://forum.z-wave.me/viewtopic.php?f=3422&t=20042 * * Received: 0x01, 0x0a, 0x00, 0x04, 0x00, 0x34, 0x04, 0x33, 0x04, 0x03, 0xff, 0x0a * ^^^^ * Always 0x03 * ^^^^ * But this appears to be the right value for the channel we requested * */ /* request the next color index if we are bugged */ uint8 coloridx = _data[1]; if (m_com.GetFlagBool(COMPAT_FLAG_COLOR_IDXBUG)) { coloridx = m_coloridxcount; for (uint8 idx = m_coloridxcount + 1; idx < 9; idx++) { if (RequestColorChannelReport(idx, _instance, Driver::MsgQueue_Send)) { m_coloridxcount = idx; break; } } } m_colorvalues[coloridx] = _data[2]; if (GetVersion() >= 3) m_colorTargetValues[coloridx] = _data[3]; /* test if there are any more valid coloridx */ for (uint8 idx = coloridx + 1; idx < 9; idx++) { if ((m_dom.GetFlagShort(STATE_FLAG_COLOR_CHANNELS)) & (1 << (idx))) { return true; } } if (m_com.GetFlagBool(COMPAT_FLAG_COLOR_IDXBUG)) m_refreshinprogress = false; /* if we get here, then we can update our ValueID */ string colorStr = decodeColor(m_colorvalues); if (Internal::VC::ValueString* color = static_cast(GetValue(_instance, ValueID_Index_Color::Color))) { Log::Write(LogLevel_Info, GetNodeId(), "Received a updated Color from Device: %s", colorStr.c_str()); if (GetVersion() >= 3) color->SetTargetValue(decodeColor(m_colorTargetValues), _data[4]); color->OnValueRefreshed(colorStr); color->Release(); } /* if we got a updated Color Index Value - Update our ValueID */ if (Internal::VC::ValueList* coloridx = static_cast(GetValue(_instance, ValueID_Index_Color::Index))) { if ((m_dom.GetFlagShort(STATE_FLAG_COLOR_CHANNELS)) & (1 << (COLORIDX_INDEXCOLOR))) { coloridx->OnValueRefreshed(m_colorvalues[COLORIDX_INDEXCOLOR]); } else { coloridx->OnValueRefreshed(decodeColorList(colorStr)); } coloridx->Release(); } if (GetVersion() >= 3) { string colorTargetStr = decodeColor(m_colorTargetValues); if (Internal::VC::ValueString* color = static_cast(GetValue(_instance, ValueID_Index_Color::Target))) { Log::Write(LogLevel_Info, GetNodeId(), "Received a updated Color Target from Device: %s", colorStr.c_str()); color->OnValueRefreshed(colorStr); color->Release(); } } return true; } return false; } uint8 Color::decodeColorList(string colorStr) { uint16_t f_capabilities = m_dom.GetFlagShort(STATE_FLAG_COLOR_CHANNELS); /* if we don't support the Color Index then fake it */ if (!(f_capabilities & (1 << (COLORIDX_INDEXCOLOR)))) { /* it supports the AMBER/CYAN/PURPLE Channels */ if (f_capabilities > 31) { /* Custom */ return 17; } if ((f_capabilities) & (1 << (COLORIDX_WARMWHITE))) { if (colorStr.substr(0, 9) == "#000000FF") { /* Warm White */ return 2; } } if ((f_capabilities) & (1 << (COLORIDX_COLDWHITE))) { if (colorStr.substr(0, 11) == "#00000000FF") { /* Cool White */ return 1; } } if (colorStr.substr(0, 7) == "#000000") { /* off */ return 0; } else if (colorStr.substr(0, 7) == "#FFFFFF") { /* White */ return 1; } else if (colorStr.substr(0, 7) == "#FF9329") { /* warm white */ return 2; } else if (colorStr.substr(0, 7) == "#FF0000") { /* red */ return 3; } else if (colorStr.substr(0, 7) == "#00FF00") { /* lime */ return 4; } else if (colorStr.substr(0, 7) == "#0000FF") { /* blue */ return 5; } else if (colorStr.substr(0, 7) == "#FFFF00") { /* yellow */ return 6; } else if (colorStr.substr(0, 7) == "#00FFFF") { /* Cyan */ return 7; } else if (colorStr.substr(0, 7) == "#FF00FF") { /* Magenta */ return 8; } else if (colorStr.substr(0, 7) == "#C0C0C0") { /* Silver */ return 9; } else if (colorStr.substr(0, 7) == "#808080") { /* gray */ return 10; } else if (colorStr.substr(0, 7) == "#800000") { /* maroon */ return 11; } else if (colorStr.substr(0, 7) == "#808000") { /* Olive */ return 12; } else if (colorStr.substr(0, 7) == "#008000") { /* green */ return 13; } else if (colorStr.substr(0, 7) == "#800080") { /* purple */ return 14; } else if (colorStr.substr(0, 7) == "#008080") { /* teal */ return 15; } else if (colorStr.substr(0, 7) == "#000080") { /* navy */ return 16; } else { /* custom */ return 17; } } return 17; } string Color::decodeColor(uint8 valueArray[9]) { /* create a RGB[W] String */ std::stringstream ss; std::stringstream ssbuf; bool usingbuf = false; uint16_t f_capabilities = m_dom.GetFlagShort(STATE_FLAG_COLOR_CHANNELS); ss << "#"; /* do R */ if ((f_capabilities) & (1 << (COLORIDX_RED))) ss << std::setw(2) << std::uppercase << std::hex << std::setfill('0') << (int) m_colorvalues[COLORIDX_RED]; else ss << "00"; /* do G */ if ((f_capabilities) & (1 << (COLORIDX_GREEN))) ss << std::setw(2) << std::uppercase << std::hex << std::setfill('0') << (int) m_colorvalues[COLORIDX_GREEN]; else ss << "00"; /* do B */ if ((f_capabilities) & (1 << (COLORIDX_BLUE))) ss << std::setw(2) << std::uppercase << std::hex << std::setfill('0') << (int) m_colorvalues[COLORIDX_BLUE]; else ss << "00"; /* if both whites are present.... */ if (((f_capabilities) & (1 << (COLORIDX_WARMWHITE))) && ((f_capabilities) & (1 << (COLORIDX_COLDWHITE)))) { /* append them both */ ss << std::setw(2) << std::uppercase << std::hex << std::setfill('0') << (int) m_colorvalues[COLORIDX_WARMWHITE]; ss << std::setw(2) << std::uppercase << std::hex << std::setfill('0') << (int) m_colorvalues[COLORIDX_COLDWHITE]; } else if ((f_capabilities) & (1 << (COLORIDX_WARMWHITE))) { /* else, if the warm white is present, append that */ ss << std::setw(2) << std::uppercase << std::hex << std::setfill('0') << (int) m_colorvalues[COLORIDX_WARMWHITE]; } else if ((f_capabilities) & (1 << (COLORIDX_COLDWHITE))) { /* else, if the cold white is present, append that */ ss << std::setw(2) << std::uppercase << std::hex << std::setfill('0') << (int) m_colorvalues[COLORIDX_COLDWHITE]; } else { /* we put 0000 into our buffer to represent both Warm and Cold white */ ssbuf << "0000"; usingbuf = true; } if ((f_capabilities) & (1 << (COLORIDX_AMBER))) { /* if AMBER is present, append our buffer if needed */ if (usingbuf) { ss << ssbuf.str(); ssbuf.str(""); ssbuf.clear(); usingbuf = false; } /* and then our Color */ ss << std::setw(2) << std::uppercase << std::hex << std::setfill('0') << (int) m_colorvalues[COLORIDX_AMBER]; } else { /* put 00 into our buffer */ ssbuf << "00"; usingbuf = true; } if ((f_capabilities) & (1 << (COLORIDX_CYAN))) { /* if CYAN is present, append our buffer if needed */ if (usingbuf) { ss << ssbuf.str(); ssbuf.str(""); ssbuf.clear(); usingbuf = false; } /* and then our Color */ ss << std::setw(2) << std::uppercase << std::hex << std::setfill('0') << (int) m_colorvalues[COLORIDX_CYAN]; } else { /* put 00 into our buffer */ ssbuf << "00"; usingbuf = true; } if ((f_capabilities) & (1 << (COLORIDX_PURPLE))) { /* if PURPLE is present, append our buffer if needed */ if (usingbuf) { ss << ssbuf.str(); ssbuf.str(""); ssbuf.clear(); usingbuf = false; } /* and then our Color */ ss << std::setw(2) << std::uppercase << std::hex << std::setfill('0') << (int) m_colorvalues[COLORIDX_PURPLE]; } /* No need for a else case here as COLORIDX_PURPLE is the last color. If its not supported, we * don't put anything in our Color String */ return ss.str(); } //----------------------------------------------------------------------------- // // Set the device's Color value //----------------------------------------------------------------------------- bool Color::SetValue(Internal::VC::Value const& _value) { if (ValueID_Index_Color::Color == _value.GetID().GetIndex()) { Internal::VC::ValueString const* value = static_cast(&_value); string s = value->GetValue(); /* make sure the first char is # */ if (s.at(0) != '#') { Log::Write(LogLevel_Warning, GetNodeId(), "Color::SetValue - String is Malformed. Missing #: %s", s.c_str()); return false; } /* length minus the # has to be multiple of 2's */ if ((s.length() - 1) % 2 != 0) { Log::Write(LogLevel_Warning, GetNodeId(), "Color::SetValue - Uneven Length string. Each Color should be 2 chars: %s", s.c_str()); return false; } /* the size of the string tells us how many colors are set */ uint8_t nocols = (uint8_t) ((s.length() - 1) / 2) & 0xFF; uint8_t colvals[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; bool colvalset[8] = { false, false, false, false, false, false, false, false }; try { /* we always will have at least RGB */ colvals[COLORIDX_RED] = GetColor(s, 1); colvals[COLORIDX_GREEN] = GetColor(s, 2); colvals[COLORIDX_BLUE] = GetColor(s, 3); /* if nocols = 4 then allwhite is set */ if (nocols == 4) { /* use ww as the var for all white */ colvals[COLORIDX_WARMWHITE] = GetColor(s, 4); colvalset[COLORIDX_WARMWHITE] = true; } if (nocols >= 5) { /* warm white and cold white are set */ colvals[COLORIDX_WARMWHITE] = GetColor(s, 4); colvals[COLORIDX_COLDWHITE] = GetColor(s, 5); colvalset[COLORIDX_WARMWHITE] = true; colvalset[COLORIDX_COLDWHITE] = true; } if (nocols >= 6) { /* amber is also set */ colvals[COLORIDX_AMBER] = GetColor(s, 6); colvalset[COLORIDX_AMBER] = true; } if (nocols >= 7) { /* cyan is also set */ colvals[COLORIDX_CYAN] = GetColor(s, 7); colvalset[COLORIDX_CYAN] = true; } if (nocols == 8) { /* purple is also set */ colvals[COLORIDX_PURPLE] = GetColor(s, 8); colvalset[COLORIDX_PURPLE] = true; } } catch (...) { Log::Write(LogLevel_Warning, GetNodeId(), "Color::SetValue - Color String Decoding Failed: %s", s.c_str()); return false; } Log::Write(LogLevel_Info, GetNodeId(), "Color::SetValue - Setting Color value"); Msg* msg = new Msg("ColorCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, false); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); if (GetVersion() > 1) msg->Append(3 + (nocols * 2) + 1); // each color 2 bytes - and 1 byte for duration else msg->Append(3 + (nocols * 2)); // each color 2 bytes msg->Append(GetCommandClassId()); msg->Append(ColorCmd_Set); //cmd msg->Append(nocols); msg->Append(COLORIDX_RED); msg->Append(colvals[COLORIDX_RED]); msg->Append(COLORIDX_GREEN); msg->Append(colvals[COLORIDX_GREEN]); msg->Append(COLORIDX_BLUE); msg->Append(colvals[COLORIDX_BLUE]); if (colvalset[COLORIDX_WARMWHITE] && !colvalset[COLORIDX_COLDWHITE]) { msg->Append(COLORIDX_WARMWHITE); msg->Append(colvals[COLORIDX_WARMWHITE]); } if (colvalset[COLORIDX_WARMWHITE] && colvalset[COLORIDX_COLDWHITE]) { msg->Append(COLORIDX_WARMWHITE); msg->Append(colvals[COLORIDX_WARMWHITE]); msg->Append(COLORIDX_COLDWHITE); msg->Append(colvals[COLORIDX_COLDWHITE]); } if (colvalset[COLORIDX_AMBER]) { msg->Append(COLORIDX_AMBER); msg->Append(colvals[COLORIDX_AMBER]); } if (colvalset[COLORIDX_CYAN]) { msg->Append(COLORIDX_CYAN); msg->Append(colvals[COLORIDX_CYAN]); } if (colvalset[COLORIDX_PURPLE]) { msg->Append(COLORIDX_PURPLE); msg->Append(colvals[COLORIDX_PURPLE]); } if (GetVersion() > 1) { uint32 duration = 15300; if (Internal::VC::ValueInt *valduration = static_cast(GetValue(_value.GetID().GetInstance(), ValueID_Index_Color::Duration))) { duration = valduration->GetValue(); } msg->Append(encodeDuration(duration)); } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } else if (ValueID_Index_Color::Index == _value.GetID().GetIndex()) { Internal::VC::ValueList const* value = static_cast(&_value); if (value->GetItem() == NULL) { return false; } uint8 index = value->GetItem()->m_value; if ((m_dom.GetFlagShort(STATE_FLAG_COLOR_CHANNELS)) & (1 << (COLORIDX_INDEXCOLOR))) { Log::Write(LogLevel_Info, GetNodeId(), "Color::SetValue - Setting Color Index Value (Real)"); Msg* msg = new Msg("Value_Color_Index", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, false); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); if (GetVersion() > 1) msg->Append(3 + 2 + 1); // each color 2 bytes - and 1 byte for duration else msg->Append(3 + 2); // each color 2 bytes msg->Append(GetCommandClassId()); msg->Append(ColorCmd_Set); //cmd msg->Append(1); msg->Append(COLORIDX_INDEXCOLOR); msg->Append(index); if (GetVersion() > 1) { uint32 duration = 15300; if (Internal::VC::ValueInt *valduration = static_cast(GetValue(_value.GetID().GetInstance(), ValueID_Index_Color::Duration))) { duration = valduration->GetValue(); } msg->Append(encodeDuration(duration)); } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "Color::SetValue - Setting Color Index Value (Fake)"); /* figure out the size */ uint8 nocols = 3; uint16_t f_capabilities = m_dom.GetFlagShort(STATE_FLAG_COLOR_CHANNELS); if ((f_capabilities) & (1 << (COLORIDX_WARMWHITE))) { nocols++; } if ((f_capabilities) & (1 << (COLORIDX_COLDWHITE))) { nocols++; } if ((f_capabilities) & (1 << (COLORIDX_AMBER))) { nocols++; } if ((f_capabilities) & (1 << (COLORIDX_CYAN))) { nocols++; } if ((f_capabilities) & (1 << (COLORIDX_PURPLE))) { nocols++; } Msg* msg = new Msg("ColorCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, false); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); if (GetVersion() > 1) msg->Append(3 + (nocols * 2) + 1); // each color 2 bytes - and 1 byte for duration else msg->Append(3 + (nocols * 2)); // each color 2 bytes msg->Append(GetCommandClassId()); msg->Append(ColorCmd_Set); //cmd msg->Append(nocols); bool cwset = false; bool wwset = false; /* fake it */ switch (index) { case 0: /* "Off" */ msg->Append(COLORIDX_RED); msg->Append(0x00); msg->Append(COLORIDX_GREEN); msg->Append(0x00); msg->Append(COLORIDX_BLUE); msg->Append(0x00); break; case 1: /* Cool White" */ if ((f_capabilities) & (1 << (COLORIDX_COLDWHITE))) { if ((f_capabilities) & (1 << (COLORIDX_WARMWHITE))) { msg->Append(COLORIDX_WARMWHITE); msg->Append(0x00); wwset = true; } if ((f_capabilities) & (1 << (COLORIDX_COLDWHITE))) { msg->Append(COLORIDX_COLDWHITE); msg->Append(0xFF); cwset = true; } msg->Append(COLORIDX_RED); msg->Append(0x00); msg->Append(COLORIDX_GREEN); msg->Append(0x00); msg->Append(COLORIDX_BLUE); msg->Append(0x00); } else { msg->Append(COLORIDX_RED); msg->Append(0xFF); msg->Append(COLORIDX_GREEN); msg->Append(0xFF); msg->Append(COLORIDX_BLUE); msg->Append(0xFF); } break; case 2: /* Warm White */ if ((f_capabilities) & (1 << (COLORIDX_WARMWHITE))) { if ((f_capabilities) & (1 << (COLORIDX_WARMWHITE))) { msg->Append(COLORIDX_WARMWHITE); msg->Append(0xFF); wwset = true; } if ((f_capabilities) & (1 << (COLORIDX_COLDWHITE))) { msg->Append(COLORIDX_COLDWHITE); msg->Append(0x00); cwset = true; } msg->Append(COLORIDX_RED); msg->Append(0x00); msg->Append(COLORIDX_GREEN); msg->Append(0x00); msg->Append(COLORIDX_BLUE); msg->Append(0x00); } else { msg->Append(COLORIDX_RED); msg->Append(0xFF); msg->Append(COLORIDX_GREEN); msg->Append(0x93); msg->Append(COLORIDX_BLUE); msg->Append(0x29); } break; case 3: /* "Red" */ msg->Append(COLORIDX_RED); msg->Append(0xFF); msg->Append(COLORIDX_GREEN); msg->Append(0x00); msg->Append(COLORIDX_BLUE); msg->Append(0x00); break; case 4: /* "Lime" */ msg->Append(COLORIDX_RED); msg->Append(0x00); msg->Append(COLORIDX_GREEN); msg->Append(0xFF); msg->Append(COLORIDX_BLUE); msg->Append(0x00); break; case 5: /* "Blue" */ msg->Append(COLORIDX_RED); msg->Append(0x00); msg->Append(COLORIDX_GREEN); msg->Append(0x00); msg->Append(COLORIDX_BLUE); msg->Append(0xFF); break; case 6: /* "Yellow" */ msg->Append(COLORIDX_RED); msg->Append(0xFF); msg->Append(COLORIDX_GREEN); msg->Append(0xFF); msg->Append(COLORIDX_BLUE); msg->Append(0x00); break; case 7: /* "Cyan" */ msg->Append(COLORIDX_RED); msg->Append(0x00); msg->Append(COLORIDX_GREEN); msg->Append(0xFF); msg->Append(COLORIDX_BLUE); msg->Append(0xFF); break; case 8: /* "Magenta" */ msg->Append(COLORIDX_RED); msg->Append(0xFF); msg->Append(COLORIDX_GREEN); msg->Append(0x00); msg->Append(COLORIDX_BLUE); msg->Append(0xFF); break; case 9: /* "Silver" */ msg->Append(COLORIDX_RED); msg->Append(0xC0); msg->Append(COLORIDX_GREEN); msg->Append(0xC0); msg->Append(COLORIDX_BLUE); msg->Append(0xC0); break; case 10: /* "Gray" */ msg->Append(COLORIDX_RED); msg->Append(0x80); msg->Append(COLORIDX_GREEN); msg->Append(0x80); msg->Append(COLORIDX_BLUE); msg->Append(0x80); break; case 11: /* "Maroon" */ msg->Append(COLORIDX_RED); msg->Append(0x80); msg->Append(COLORIDX_GREEN); msg->Append(0x00); msg->Append(COLORIDX_BLUE); msg->Append(0x00); break; case 12: /* "Olive" */ msg->Append(COLORIDX_RED); msg->Append(0x80); msg->Append(COLORIDX_GREEN); msg->Append(0x80); msg->Append(COLORIDX_BLUE); msg->Append(0x00); break; case 13: /* "Green" */ msg->Append(COLORIDX_RED); msg->Append(0x00); msg->Append(COLORIDX_GREEN); msg->Append(0x80); msg->Append(COLORIDX_BLUE); msg->Append(0x00); break; case 14: /* "Purple" */ msg->Append(COLORIDX_RED); msg->Append(0x80); msg->Append(COLORIDX_GREEN); msg->Append(0x00); msg->Append(COLORIDX_BLUE); msg->Append(0x80); break; case 15: /* "Teal" */ msg->Append(COLORIDX_RED); msg->Append(0x00); msg->Append(COLORIDX_GREEN); msg->Append(0x80); msg->Append(COLORIDX_BLUE); msg->Append(0x80); break; case 16: /* "Navy" */ msg->Append(COLORIDX_RED); msg->Append(0x00); msg->Append(COLORIDX_GREEN); msg->Append(0x00); msg->Append(COLORIDX_BLUE); msg->Append(0x80); break; case 17: /* "Custom" */ msg->Append(COLORIDX_RED); msg->Append(0x00); msg->Append(COLORIDX_GREEN); msg->Append(0x00); msg->Append(COLORIDX_BLUE); msg->Append(0x00); break; } if (((f_capabilities) & (1 << (COLORIDX_WARMWHITE))) && !wwset) { msg->Append(COLORIDX_WARMWHITE); msg->Append(0x00); } if (((f_capabilities) & (1 << (COLORIDX_COLDWHITE))) && !cwset) { msg->Append(COLORIDX_COLDWHITE); msg->Append(0x00); } if ((f_capabilities) & (1 << (COLORIDX_AMBER))) { msg->Append(COLORIDX_AMBER); msg->Append(0x00); } if ((f_capabilities) & (1 << (COLORIDX_CYAN))) { msg->Append(COLORIDX_CYAN); msg->Append(0x00); } if ((f_capabilities) & (1 << (COLORIDX_PURPLE))) { msg->Append(COLORIDX_PURPLE); msg->Append(0x00); } if (GetVersion() > 1) { uint32 duration = 0; if (Internal::VC::ValueInt *valduration = static_cast(GetValue(_value.GetID().GetInstance(), ValueID_Index_Color::Duration))) { duration = valduration->GetValue(); } msg->Append(encodeDuration(duration)); } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } } else if (ValueID_Index_Color::Duration == _value.GetID().GetIndex()) { Log::Write(LogLevel_Info, GetNodeId(), "Color::SetValue - Setting Color Fade Duration"); Internal::VC::ValueInt const* value = static_cast(&_value); int32 _duration = value->GetValue(); if (Internal::VC::ValueInt * m_value = static_cast(GetValue(_value.GetID().GetInstance(), ValueID_Index_Color::Duration))) { m_value->OnValueRefreshed(_duration); m_value->Release(); } return true; } else if (ValueID_Index_Color::Channels_Capabilities == _value.GetID().GetIndex()) { Log::Write(LogLevel_Info, GetNodeId(), "Color::SetValue - Setting Color Channels"); Internal::VC::ValueInt const* value = static_cast(&_value); m_dom.SetFlagShort(STATE_FLAG_COLOR_CHANNELS, value->GetValue()); /* if the Capabilities is set to 0 by the user, then refresh the defaults from the device */ if (m_dom.GetFlagShort(STATE_FLAG_COLOR_CHANNELS) == 0) { Msg* msg = new Msg("ColorCmd_CapabilityGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(ColorCmd_Capability_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } if (Internal::VC::ValueInt *m_value = static_cast(GetValue(_value.GetID().GetInstance(), ValueID_Index_Color::Channels_Capabilities))) { m_value->OnValueRefreshed(m_dom.GetFlagShort(STATE_FLAG_COLOR_CHANNELS)); m_value->Release(); } } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void Color::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { /* XXX TODO convert this to a bitset when we implement */ node->CreateValueInt(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_Color::Channels_Capabilities, "Color Channels", "", false, false, m_dom.GetFlagShort(STATE_FLAG_COLOR_CHANNELS), 0); } } //----------------------------------------------------------------------------- // // Update class values based in BASIC mapping //----------------------------------------------------------------------------- void Color::SetValueBasic(uint8 const _instance, uint8 const _value) { RequestValue(0, ValueID_Index_Color::Color, _instance, Driver::MsgQueue_Send); } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/SwitchAll.h0000644000175200017520000000544414032142455017476 00000000000000//----------------------------------------------------------------------------- // // SwitchAll.h // // Implementation of the Z-Wave COMMAND_CLASS_SWITCH_ALL // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _SwitchAll_H #define _SwitchAll_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_SWITCH_ALL (0x27), a Z-Wave device command class. * \ingroup CommandClass */ class SwitchAll: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new SwitchAll(_homeId, _nodeId); } virtual ~SwitchAll() { } static uint8 const StaticGetCommandClassId() { return 0x27; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_SWITCH_ALL"; } static void On(Driver* _driver, uint8 const _nodeId); static void Off(Driver* _driver, uint8 const _nodeId); // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: SwitchAll(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/BasicWindowCovering.cpp0000644000175200017520000001012014032142455022030 00000000000000//----------------------------------------------------------------------------- // // BasicWindowCovering.cpp // // Implementation of the Z-Wave COMMAND_CLASS_BASIC_WINDOW_COVERING // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/BasicWindowCovering.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "Node.h" #include "platform/Log.h" #include "value_classes/ValueButton.h" namespace OpenZWave { namespace Internal { namespace CC { enum BasicWindowCoveringCmd { BasicWindowCoveringCmd_StartLevelChange = 0x01, BasicWindowCoveringCmd_StopLevelChange = 0x02 }; //----------------------------------------------------------------------------- // // Set a value on the Z-Wave device //----------------------------------------------------------------------------- bool BasicWindowCovering::SetValue(Internal::VC::Value const& _value) { if (ValueID::ValueType_Button == _value.GetID().GetType()) { Internal::VC::ValueButton const* button = static_cast(&_value); uint8 action = 0x40; if (button->GetID().GetIndex() == ValueID_Index_BasicWindowCovering::Close) // Open is index zero, so non-zero is close. { // Close action = 0; } if (button && button->IsPressed()) { Log::Write(LogLevel_Info, GetNodeId(), "BasicWindowCovering - Start Level Change (%s)", action ? "Open" : "Close"); Msg* msg = new Msg("BasicWindowCoveringCmd_StartLevelChange", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(BasicWindowCoveringCmd_StartLevelChange); msg->Append(action); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "BasicWindowCovering - Stop Level Change"); Msg* msg = new Msg("BasicWindowCoveringCmd_StopLevelChange", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(BasicWindowCoveringCmd_StopLevelChange); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void BasicWindowCovering::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueButton(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_BasicWindowCovering::Open, "Open", 0); node->CreateValueButton(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_BasicWindowCovering::Close, "Close", 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/ApplicationStatus.cpp0000644000175200017520000000607514032142455021607 00000000000000//----------------------------------------------------------------------------- // // ApplicationStatus.cpp // // Implementation of the Z-Wave COMMAND_CLASS_APPLICATION_STATUS // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/ApplicationStatus.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "Notification.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace CC { enum ApplicationStatusCmd { ApplicationStatusCmd_Busy = 0x01, ApplicationStatusCmd_RejectedRequest = 0x02 }; //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool ApplicationStatus::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { Notification* notification = new Notification(Notification::Type_UserAlerts); notification->SetHomeAndNodeIds(GetHomeId(), GetNodeId()); if (ApplicationStatusCmd_Busy == (ApplicationStatusCmd) _data[0]) { switch (_data[1]) { case 0: { notification->SetUserAlertNotification(Notification::Alert_ApplicationStatus_Retry); break; } case 1: { notification->SetUserAlertNotification(Notification::Alert_ApplicationStatus_Retry); notification->SetRetry(_data[2]); break; } case 2: { notification->SetUserAlertNotification(Notification::Alert_ApplicationStatus_Queued); break; } default: { // Invalid status Log::Write(LogLevel_Warning, GetNodeId(), "Received a unknown Application Status Message %d - Assuming Rejected", _data[1]); notification->SetUserAlertNotification(Notification::Alert_ApplicationStatus_Rejected); } } } if (ApplicationStatusCmd_RejectedRequest == (ApplicationStatusCmd) _data[0]) { notification->SetUserAlertNotification(Notification::Alert_ApplicationStatus_Rejected); } GetDriver()->QueueNotification(notification); return true; } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Lock.h0000644000175200017520000000516714032142455016476 00000000000000//----------------------------------------------------------------------------- // // Lock.h // // Implementation of the Z-Wave COMMAND_CLASS_LOCK // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Lock_H #define _Lock_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_LOCK (0x76), a Z-Wave device command class. * \ingroup CommandClass */ class Lock: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Lock(_homeId, _nodeId); } virtual ~Lock() { } static uint8 const StaticGetCommandClassId() { return 0x76; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_LOCK"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: Lock(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Meter.h0000644000175200017520000000552014032142455016653 00000000000000//----------------------------------------------------------------------------- // // Meter.h // // Implementation of the Z-Wave COMMAND_CLASS_METER // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Meter_H #define _Meter_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_METER (0x32), a Z-Wave device command class. * \ingroup CommandClass */ class Meter: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Meter(_homeId, _nodeId); } virtual ~Meter() { } static uint8 const StaticGetCommandClassId() { return 0x32; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_METER"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; virtual uint8 GetMaxVersion() override { return 5; } private: Meter(uint32 const _homeId, uint8 const _nodeId); int32_t GetScale(uint8_t const *_data, uint32_t const_length); bool HandleSupportedReport(uint8 const* _data, uint32 const _length, uint32 const _instance = 1); bool HandleReport(uint8 const* _data, uint32 const _length, uint32 const _instance = 1); }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/SceneActivation.cpp0000644000175200017520000001415714032142455021217 00000000000000//----------------------------------------------------------------------------- // // SceneActivation.cpp // // Implementation of the Z-Wave COMMAND_CLASS_SCENE_ACTIVATION // // Copyright (c) 2012 Greg Satz // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/SceneActivation.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "Notification.h" #include "platform/Log.h" #include "value_classes/ValueInt.h" namespace OpenZWave { namespace Internal { namespace CC { enum SceneActivationCmd { SceneActivationCmd_Set = 0x01 }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- SceneActivation::SceneActivation(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { Timer::SetDriver(GetDriver()); } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool SceneActivation::HandleIncomingMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (SceneActivationCmd_Set == (SceneActivationCmd) _data[0]) { // Scene Activation Set received so send notification char msg[64]; uint32 duration; if (_data[2] == 0) { snprintf(msg, sizeof(msg), "now"); duration = 0; } else if (_data[2] <= 0x7F) { snprintf(msg, sizeof(msg), "%d seconds", _data[2]); duration = _data[2]; } else if (_data[2] <= 0xFE) { snprintf(msg, sizeof(msg), "%d minutes", _data[2]); duration = _data[2] * 60; } else { snprintf(msg, sizeof(msg), "via configuration"); duration = 0; } Log::Write(LogLevel_Info, GetNodeId(), "Received SceneActivation set from node %d: scene id=%d %s. Sending event notification.", GetNodeId(), _data[1], msg); /* Sending the Scene ID via a notification should be depreciated in 1.8 */ Notification* notification = new Notification(Notification::Type_SceneEvent); notification->SetHomeAndNodeIds(GetHomeId(), GetNodeId()); notification->SetSceneId(_data[1]); GetDriver()->QueueNotification(notification); Log::Write(LogLevel_Info, GetNodeId(), "Received SceneActivation report: %d (duration: %d)", _data[1], duration); if (Internal::VC::ValueInt* value = static_cast(GetValue(_instance, ValueID_Index_SceneActivation::SceneID))) { value->OnValueRefreshed(_data[1]); value->Release(); } if (Internal::VC::ValueInt* value = static_cast(GetValue(_instance, ValueID_Index_SceneActivation::Duration))) { value->OnValueRefreshed(duration); value->Release(); } if (duration < 1000) duration = 1000; else duration = duration * 1000; Log::Write(LogLevel_Info, GetNodeId(), "Automatically Clearing SceneID/Duration in %d ms", duration); TimerThread::TimerCallback callback = bind(&SceneActivation::ClearScene, this, _instance); TimerSetEvent(duration, callback, _instance); return true; } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool SceneActivation::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { Log::Write(LogLevel_Warning, GetNodeId(), "Received a SceneActivation Message for a Controlled CommandClass"); return false; } //----------------------------------------------------------------------------- // // Return the Scene ValueID's to defaults, after the duration has expired //----------------------------------------------------------------------------- void SceneActivation::ClearScene(uint32 _instance) { if (Internal::VC::ValueInt* value = static_cast(GetValue(_instance, ValueID_Index_SceneActivation::SceneID))) { value->OnValueRefreshed(0); value->Release(); } if (Internal::VC::ValueInt* value = static_cast(GetValue(_instance, ValueID_Index_SceneActivation::Duration))) { value->OnValueRefreshed(0); value->Release(); } } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void SceneActivation::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueInt(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_SceneActivation::SceneID, "Scene", "", true, false, 0, 0); node->CreateValueInt(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_SceneActivation::Duration, "Duration", "", true, false, 0, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Configuration.h0000644000175200017520000000520214032142455020403 00000000000000//----------------------------------------------------------------------------- // // Configuration.h // // Implementation of the Z-Wave COMMAND_CLASS_CONFIGURATION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Configuration_H #define _Configuration_H #include #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_CONFIGURATION (0x70), a Z-Wave device command class. * \ingroup CommandClass */ class Configuration: public CommandClass { friend class Node; public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Configuration(_homeId, _nodeId); } virtual ~Configuration() { } static uint8 const StaticGetCommandClassId() { return 0x70; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_CONFIGURATION"; } virtual bool RequestValue(uint32 const _requestFlags, uint16 const _parameter, uint8 const _index, Driver::MsgQueue const _queue) override; void Set(uint16 const _parameter, int32 const _value, uint8 const _size); // From CommandClass virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; private: Configuration(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/MultiChannelAssociation.h0000644000175200017520000000715114032142455022361 00000000000000//----------------------------------------------------------------------------- // // MultiChannelAssociation.h // // Implementation of the Z-Wave COMMAND_CLASS_MULTI_CHANNEL_ASSOCIATION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _MultiChannelAssociation_H #define _MultiChannelAssociation_H #include #include "Group.h" #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_MULTI_CHANNEL_ASSOCIATION (0x8E), a Z-Wave device command class. * \ingroup CommandClass */ class MultiChannelAssociation: public CommandClass { friend class OpenZWave::Group; public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new MultiChannelAssociation(_homeId, _nodeId); } virtual ~MultiChannelAssociation() { } static uint8 const StaticGetCommandClassId() { return 0x8e; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_MULTI_CHANNEL_ASSOCIATION"; } // From CommandClass virtual void ReadXML(TiXmlElement const* _ccElement) override; virtual void WriteXML(TiXmlElement* _ccElement) override; virtual bool RequestState(uint32 const _requestFlags, uint8 const _endPoint, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _endPoint, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _endPoint = 1) override; void RequestAllGroups(uint32 const _requestFlags); void Set(uint8 const _group, uint8 const _nodeId, uint8 const _endPoint); void Remove(uint8 const _group, uint8 const _nodeId, uint8 const _endPoint); bool supportsMultiInstance() override { return false; } private: MultiChannelAssociation(uint32 const _homeId, uint8 const _nodeId); void QueryGroup(uint8 _groupIdx, uint32 const _requestFlags); void AutoAssociate(); bool m_queryAll; // When true, once a group has been queried, we request the next one. uint8 m_numGroups; // Number of groups supported by the device. 255 is reported by certain manufacturers and requires special handling. uint8 m_currentGroupQuery; // The Current Group we are Querying for. vector m_pendingMembers; // Used to build a list of group members from multiple reports }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/ApplicationStatus.h0000644000175200017520000000453214032142455021250 00000000000000//----------------------------------------------------------------------------- // // ApplicationStatus.h // // Implementation of the Z-Wave COMMAND_CLASS_APPLICATION_STATUS // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ApplicationStatus_H #define _ApplicationStatus_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_APPLICATION_STATUS (0x22), a Z-Wave device command class. * \ingroup CommandClass */ class ApplicationStatus: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new ApplicationStatus(_homeId, _nodeId); } virtual ~ApplicationStatus() { } static uint8 const StaticGetCommandClassId() { return 0x22; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_APPLICATION_STATUS"; } // From CommandClass virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; private: ApplicationStatus(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Protection.h0000644000175200017520000000545614032142455017735 00000000000000//----------------------------------------------------------------------------- // // Protection.h // // Implementation of the Z-Wave COMMAND_CLASS_PROTECTION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Protection_H #define _Protection_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_PROTECTION (0x75), a Z-Wave device command class. * \ingroup CommandClass */ class Protection: public CommandClass { public: enum ProtectionEnum { Protection_Unprotected = 0, Protection_Sequence, Protection_NOP }; static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Protection(_homeId, _nodeId); } virtual ~Protection() { } static uint8 const StaticGetCommandClassId() { return 0x75; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_PROTECTION"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: Protection(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Lock.cpp0000644000175200017520000001222614032142455017023 00000000000000//----------------------------------------------------------------------------- // // Lock.cpp // // Implementation of the Z-Wave COMMAND_CLASS_LOCK // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/Lock.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueBool.h" namespace OpenZWave { namespace Internal { namespace CC { enum LockCmd { LockCmd_Set = 0x01, LockCmd_Get = 0x02, LockCmd_Report = 0x03 }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Lock::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Dynamic) { return RequestValue(_requestFlags, 0, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool Lock::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("LockCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(LockCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "LockCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Lock::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (LockCmd_Report == (LockCmd) _data[0]) { Log::Write(LogLevel_Info, GetNodeId(), "Received Lock report: Lock is %s", _data[1] ? "Locked" : "Unlocked"); if (Internal::VC::ValueBool* value = static_cast(GetValue(_instance, ValueID_Index_Lock::Locked))) { value->OnValueRefreshed(_data[1] != 0); value->Release(); } return true; } return false; } //----------------------------------------------------------------------------- // // Set the lock's state //----------------------------------------------------------------------------- bool Lock::SetValue(Internal::VC::Value const& _value) { if (ValueID::ValueType_Bool == _value.GetID().GetType()) { Internal::VC::ValueBool const* value = static_cast(&_value); Log::Write(LogLevel_Info, GetNodeId(), "Lock::Set - Requesting lock to be %s", value->GetValue() ? "Locked" : "Unlocked"); Msg* msg = new Msg("LockCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(LockCmd_Set); msg->Append(value->GetValue() ? 0x01 : 0x00); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } return false; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void Lock::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueBool(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Lock::Locked, "Locked", "", false, false, false, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/MultiChannelAssociation.cpp0000644000175200017520000003734114032142455022720 00000000000000//----------------------------------------------------------------------------- // // MultiChannelAssociation.cpp // // Implementation of the Z-Wave COMMAND_CLASS_MULTI_CHANNEL_ASSOCIATION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "tinyxml.h" #include "command_classes/CommandClasses.h" #include "command_classes/MultiChannelAssociation.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "Node.h" #include "Group.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { namespace CC { enum MultiChannelAssociationCmd { MultiChannelAssociationCmd_Set = 0x01, MultiChannelAssociationCmd_Get = 0x02, MultiChannelAssociationCmd_Report = 0x03, MultiChannelAssociationCmd_Remove = 0x04, MultiChannelAssociationCmd_GroupingsGet = 0x05, MultiChannelAssociationCmd_GroupingsReport = 0x06 }; // // Constructor //----------------------------------------------------------------------------- MultiChannelAssociation::MultiChannelAssociation(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_queryAll(false), m_numGroups(0) { m_com.EnableFlag(COMPAT_FLAG_MCA_FORCEINSTANCES, true); SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Read the saved association data //----------------------------------------------------------------------------- void MultiChannelAssociation::ReadXML(TiXmlElement const* _ccElement) { CommandClass::ReadXML(_ccElement); TiXmlElement const* associationsElement = _ccElement->FirstChildElement(); while (associationsElement) { char const* str = associationsElement->Value(); if (str && !strcmp(str, "Associations")) { int intVal; if (TIXML_SUCCESS == associationsElement->QueryIntAttribute("num_groups", &intVal)) { m_numGroups = (uint8) intVal; } TiXmlElement const* groupElement = associationsElement->FirstChildElement(); while (groupElement) { if (Node* node = GetNodeUnsafe()) { Group* group = new Group(GetHomeId(), GetNodeId(), groupElement); node->AddGroup(group); } groupElement = groupElement->NextSiblingElement(); } break; } associationsElement = associationsElement->NextSiblingElement(); } } //----------------------------------------------------------------------------- // // Save the association data //----------------------------------------------------------------------------- void MultiChannelAssociation::WriteXML(TiXmlElement* _ccElement) { CommandClass::WriteXML(_ccElement); if (Node* node = GetNodeUnsafe()) { TiXmlElement* associationsElement = new TiXmlElement("Associations"); char str[8]; snprintf(str, 8, "%d", m_numGroups); associationsElement->SetAttribute("num_groups", str); _ccElement->LinkEndChild(associationsElement); node->WriteGroups(associationsElement); } } //----------------------------------------------------------------------------- // // Nothing to do for Association //----------------------------------------------------------------------------- bool MultiChannelAssociation::RequestState(uint32 const _requestFlags, uint8 const _endPoint, Driver::MsgQueue const _queue) { if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { // Request the supported group info return RequestValue(_requestFlags, 0, _endPoint, _queue); } return false; } //----------------------------------------------------------------------------- // // Nothing to do for Association //----------------------------------------------------------------------------- bool MultiChannelAssociation::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _endPoint, Driver::MsgQueue const _queue) { if (_endPoint != 1) { // This command class doesn't work with multiple End Points return false; } // Request the supported group info Msg* msg = new Msg("MultiChannelAssociationCmd_GroupingsGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(MultiChannelAssociationCmd_GroupingsGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } //----------------------------------------------------------------------------- // // Request the contents of each group in turn //----------------------------------------------------------------------------- void MultiChannelAssociation::RequestAllGroups(uint32 const _requestFlags) { m_queryAll = true; // Request the contents of the individual groups in turn. if (m_numGroups == 0xff) { // We start with group 255, and will then move to group 1, 2 etc and stop when we find a group with a maxAssociations of zero. Log::Write(LogLevel_Info, GetNodeId(), "Number of association groups reported for node %d is 255, which requires special case handling.", GetNodeId()); QueryGroup(0xff, _requestFlags); } else { // We start with group 1, and will then move to group 2, 3 etc and stop when the group index is greater than m_numGroups. Log::Write(LogLevel_Info, GetNodeId(), "Number of association groups reported for node %d is %d.", GetNodeId(), m_numGroups); QueryGroup(1, _requestFlags); } } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool MultiChannelAssociation::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _endPoint // = 1 ) { bool handled = false; uint32 i; if (Node* node = GetNodeUnsafe()) { if (MultiChannelAssociationCmd_GroupingsReport == (MultiChannelAssociationCmd) _data[0]) { // Retrieve the number of groups this device supports. // The groups will be queried with the session data. m_numGroups = _data[1]; Log::Write(LogLevel_Info, GetNodeId(), "Received MULTI_CHANNEL_ASSOCIATION_GROUPINGS_REPORT from node %d. Number of groups is %d", GetNodeId(), m_numGroups); ClearStaticRequest(StaticRequest_Values); handled = true; } else if (MultiChannelAssociationCmd_Report == (MultiChannelAssociationCmd) _data[0]) { // Get the group info uint8 groupIdx = _data[1]; uint8 maxAssociations = _data[2]; // If the maxAssociations is zero, this is not a supported group. uint8 numReportsToFollow = _data[3]; // If a device supports a lot of associations, they may come in more than one message. if (groupIdx != 0) { if (maxAssociations) { if (_length >= 5) { // format: // node A // node B // 0x00 Marker // node C // End Point # // node D // End Point # Log::Write(LogLevel_Info, GetNodeId(), "Received MULTI_CHANNEL_ASSOCIATION_REPORT from node %d, group %d", GetNodeId(), groupIdx); Log::Write(LogLevel_Info, GetNodeId(), " The group contains:"); bool pastMarker = false; for (i = 0; i < _length - 5; ++i) { if (_data[i + 4] == 0x00) { pastMarker = true; } else { if (!pastMarker) { Log::Write(LogLevel_Info, GetNodeId(), " Node %d", _data[i + 4]); InstanceAssociation association; association.m_nodeId = _data[i + 4]; association.m_instance = 0x00; m_pendingMembers.push_back(association); } else { Log::Write(LogLevel_Info, GetNodeId(), " Node %d End Point %d", _data[i + 4], _data[i + 5]); InstanceAssociation association; association.m_nodeId = _data[i + 4]; association.m_instance = _data[i + 5]; m_pendingMembers.push_back(association); i++; } } } } if (numReportsToFollow) { // We're expecting more reports for this group Log::Write(LogLevel_Info, GetNodeId(), "%d more association reports expected for node %d, group %d", numReportsToFollow, GetNodeId(), groupIdx); return true; } else { // No more reports to come for this group, so we can apply the pending list Group* group = node->GetGroup(groupIdx); if ( NULL == group) { // Group has not been created yet group = new Group(GetHomeId(), GetNodeId(), groupIdx, maxAssociations); node->AddGroup(group); } group->SetMultiInstance(true); // Update the group with its new contents group->OnGroupChanged(m_pendingMembers); m_pendingMembers.clear(); } } else { // maxAssociations is zero, so we've reached the end of the query process Log::Write(LogLevel_Info, GetNodeId(), "Max associations for node %d, group %d is zero. Querying associations for this node is complete.", GetNodeId(), groupIdx); node->AutoAssociate(); m_queryAll = false; } } else { Log::Write(LogLevel_Warning, GetNodeId(), "Recieved Group 0 Assocation - Invalid"); } if (m_queryAll) { // Work out which is the next group we will query. // If we are currently on group 255, the next group will be 1. uint8 nextGroup = m_currentGroupQuery + 1; if (!nextGroup) { nextGroup = 1; } if (nextGroup <= m_numGroups) { // Query the next group QueryGroup(nextGroup, 0); } else { // We're all done Log::Write(LogLevel_Info, GetNodeId(), "Querying associations for node %d is complete.", GetNodeId()); node->AutoAssociate(); m_queryAll = false; m_currentGroupQuery = 0; } } handled = true; } } return handled; } //----------------------------------------------------------------------------- // // Request details of an association group //----------------------------------------------------------------------------- void MultiChannelAssociation::QueryGroup(uint8 _groupIdx, uint32 const _requestFlags) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Log::Write(LogLevel_Info, GetNodeId(), "Get MultiChannelAssociation for group %d of node %d", _groupIdx, GetNodeId()); Msg* msg = new Msg("MultiChannelAssociationCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(MultiChannelAssociationCmd_Get); msg->Append(_groupIdx); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); if (m_queryAll) m_currentGroupQuery = _groupIdx; return; } else { Log::Write(LogLevel_Info, GetNodeId(), "MultiChannelAssociationCmd_Get Not Supported on this node"); } return; } //----------------------------------------------------------------------------- // // Add an association between devices //----------------------------------------------------------------------------- void MultiChannelAssociation::Set(uint8 _groupIdx, uint8 _targetNodeId, uint8 _endPoint) { /* for Qubino devices, we should always set a End Point if its the ControllerNode, so MultChannelEncap works. - See Bug #857 */ if ((m_com.GetFlagBool(COMPAT_FLAG_MCA_FORCEINSTANCES) == true) && (_endPoint == 0) && (GetDriver()->GetControllerNodeId() == _targetNodeId)) { _endPoint = 0x01; } Log::Write(LogLevel_Info, GetNodeId(), "MultiChannelAssociation::Set - Adding End Point %d on node %d to group %d of node %d", _endPoint, _targetNodeId, _groupIdx, GetNodeId()); if (_endPoint == 0x00) { Msg* msg = new Msg("MultiChannelAssociationCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(GetNodeId()); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(MultiChannelAssociationCmd_Set); msg->Append(_groupIdx); msg->Append(_targetNodeId); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } else { Msg* msg = new Msg("MultiChannelAssociationCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(GetNodeId()); msg->Append(6); msg->Append(GetCommandClassId()); msg->Append(MultiChannelAssociationCmd_Set); msg->Append(_groupIdx); msg->Append(0x00); // marker msg->Append(_targetNodeId); msg->Append(_endPoint); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } } //----------------------------------------------------------------------------- // // Remove an association between devices //----------------------------------------------------------------------------- void MultiChannelAssociation::Remove(uint8 _groupIdx, uint8 _targetNodeId, uint8 _endPoint) { Log::Write(LogLevel_Info, GetNodeId(), "MultiChannelAssociation::Remove - Removing End Point %d on node %d from group %d of node %d", _endPoint, _targetNodeId, _groupIdx, GetNodeId()); if (_endPoint == 0x00) { Msg* msg = new Msg("MultiChannelAssociationCmd_Remove", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(GetNodeId()); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(MultiChannelAssociationCmd_Remove); msg->Append(_groupIdx); msg->Append(_targetNodeId); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } else { Msg* msg = new Msg("MultiChannelAssociationCmd_Remove", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->Append(GetNodeId()); msg->Append(6); msg->Append(GetCommandClassId()); msg->Append(MultiChannelAssociationCmd_Remove); msg->Append(_groupIdx); msg->Append(0x00); // marker msg->Append(_targetNodeId); msg->Append(_endPoint); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/SimpleAVCommandItem.cpp0000644000175200017520000012074414032142455021736 00000000000000//----------------------------------------------------------------------------- // // SimpleAVCommandItem.h // // Implementation of the Z-Wave COMMAND_CLASS_SIMPLE_AV_CONTROL // // Copyright (c) 2018 // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "SimpleAVCommandItem.h" #include #include #include "Defs.h" namespace OpenZWave { namespace Internal { namespace CC { static std::vector m_commands; //----------------------------------------------------------------------------- // // SimpleAVCommand constructor //----------------------------------------------------------------------------- SimpleAVCommandItem::SimpleAVCommandItem(uint16 const _code, string _name, string _description, uint16 const _version) { m_code = _code; m_name = _name; m_description = _description; m_version = _version; } //----------------------------------------------------------------------------- // // Get code of ZWave AV command //----------------------------------------------------------------------------- uint16 SimpleAVCommandItem::GetCode() { return m_code; } //----------------------------------------------------------------------------- // // Get version of AV simple command class of command //----------------------------------------------------------------------------- uint16 SimpleAVCommandItem::GetVersion() { return m_version; } //----------------------------------------------------------------------------- // // Get human-friendly name of AV command //----------------------------------------------------------------------------- std::string SimpleAVCommandItem::GetName() { return m_name; } //----------------------------------------------------------------------------- // // Get human-friendly description of AV command //----------------------------------------------------------------------------- std::string SimpleAVCommandItem::GetDescription() { return m_description; } //----------------------------------------------------------------------------- // // Get all available AV commands //----------------------------------------------------------------------------- std::vector SimpleAVCommandItem::GetCommands() { if (m_commands.size() == 0) { // Generated code m_commands.push_back(SimpleAVCommandItem(1, "Mute", "", 1)); m_commands.push_back(SimpleAVCommandItem(2, "Volume Down", "Level Down", 1)); m_commands.push_back(SimpleAVCommandItem(3, "Volume Up", "Level Up", 1)); m_commands.push_back(SimpleAVCommandItem(4, "Channel Up", "Program Up", 1)); m_commands.push_back(SimpleAVCommandItem(5, "Channel Down", "Program Down", 1)); m_commands.push_back(SimpleAVCommandItem(6, "0", "Preset 10", 1)); m_commands.push_back(SimpleAVCommandItem(7, "1", "Preset 1", 1)); m_commands.push_back(SimpleAVCommandItem(8, "2", "Preset 2", 1)); m_commands.push_back(SimpleAVCommandItem(9, "3", "Preset 3", 1)); m_commands.push_back(SimpleAVCommandItem(10, "4", "Preset 4", 1)); m_commands.push_back(SimpleAVCommandItem(11, "5", "Preset 5", 1)); m_commands.push_back(SimpleAVCommandItem(12, "6", "Preset 6", 1)); m_commands.push_back(SimpleAVCommandItem(13, "7", "Preset 7", 1)); m_commands.push_back(SimpleAVCommandItem(14, "8", "Preset 8", 1)); m_commands.push_back(SimpleAVCommandItem(15, "9", "Preset 9", 1)); m_commands.push_back(SimpleAVCommandItem(16, "Last Channel", "Recall, Previous Channel (WMC)", 1)); m_commands.push_back(SimpleAVCommandItem(17, "Display", "Info", 1)); m_commands.push_back(SimpleAVCommandItem(18, "Favorite Channel", "Favorite", 1)); m_commands.push_back(SimpleAVCommandItem(19, "Play", "", 1)); m_commands.push_back(SimpleAVCommandItem(20, "Stop", "", 1)); m_commands.push_back(SimpleAVCommandItem(21, "Pause", "Still", 1)); m_commands.push_back(SimpleAVCommandItem(22, "Fast Forward", "Search Forward", 1)); m_commands.push_back(SimpleAVCommandItem(23, "Rewind", "Search Reverse", 1)); m_commands.push_back(SimpleAVCommandItem(24, "Instant Replay", "Replay", 1)); m_commands.push_back(SimpleAVCommandItem(25, "Record", "", 1)); m_commands.push_back(SimpleAVCommandItem(26, "AC3", "Dolby Digital", 1)); m_commands.push_back(SimpleAVCommandItem(27, "PVR Menu", "Tivo", 1)); m_commands.push_back(SimpleAVCommandItem(28, "Guide", "EPG", 1)); m_commands.push_back(SimpleAVCommandItem(29, "Menu", "Settings", 1)); m_commands.push_back(SimpleAVCommandItem(30, "Menu Up", "Adjust Up", 1)); m_commands.push_back(SimpleAVCommandItem(31, "Menu Down", "Adjust Down", 1)); m_commands.push_back(SimpleAVCommandItem(32, "Menu Left", "Cursor Left", 1)); m_commands.push_back(SimpleAVCommandItem(33, "Menu Right", "Cursor Right", 1)); m_commands.push_back(SimpleAVCommandItem(34, "Page Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(35, "Page Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(36, "Select", "OK", 1)); m_commands.push_back(SimpleAVCommandItem(37, "Exit", "", 1)); m_commands.push_back(SimpleAVCommandItem(38, "Input", "Input Select", 1)); m_commands.push_back(SimpleAVCommandItem(39, "Power", "Standby", 1)); m_commands.push_back(SimpleAVCommandItem(40, "Enter Channel", "Channel Enter", 1)); m_commands.push_back(SimpleAVCommandItem(41, "10", "", 1)); m_commands.push_back(SimpleAVCommandItem(42, "11", "", 1)); m_commands.push_back(SimpleAVCommandItem(43, "12", "", 1)); m_commands.push_back(SimpleAVCommandItem(44, "13", "", 1)); m_commands.push_back(SimpleAVCommandItem(45, "14", "", 1)); m_commands.push_back(SimpleAVCommandItem(46, "15", "", 1)); m_commands.push_back(SimpleAVCommandItem(47, "16", "", 1)); m_commands.push_back(SimpleAVCommandItem(48, "10", "10+", 1)); m_commands.push_back(SimpleAVCommandItem(49, "20", "20+", 1)); m_commands.push_back(SimpleAVCommandItem(50, "100", "", 1)); m_commands.push_back(SimpleAVCommandItem(51, "-/--", "", 1)); m_commands.push_back(SimpleAVCommandItem(52, "3-CH", "", 1)); m_commands.push_back(SimpleAVCommandItem(53, "3D", "Simulated Stereo", 1)); m_commands.push_back(SimpleAVCommandItem(54, "6-CH Input", "6 Channel", 1)); m_commands.push_back(SimpleAVCommandItem(55, "A", "", 1)); m_commands.push_back(SimpleAVCommandItem(56, "Add", "Write", 1)); m_commands.push_back(SimpleAVCommandItem(57, "Alarm", "", 1)); m_commands.push_back(SimpleAVCommandItem(58, "AM", "", 1)); m_commands.push_back(SimpleAVCommandItem(59, "Analog", "", 1)); m_commands.push_back(SimpleAVCommandItem(60, "Angle", "", 1)); m_commands.push_back(SimpleAVCommandItem(61, "Antenna", "External", 1)); m_commands.push_back(SimpleAVCommandItem(62, "Antenna East", "", 1)); m_commands.push_back(SimpleAVCommandItem(63, "Antenna West", "", 1)); m_commands.push_back(SimpleAVCommandItem(64, "Aspect", "Size", 1)); m_commands.push_back(SimpleAVCommandItem(65, "Audio 1", "Audio", 1)); m_commands.push_back(SimpleAVCommandItem(66, "Audio 2", "", 1)); m_commands.push_back(SimpleAVCommandItem(67, "Audio 3", "", 1)); m_commands.push_back(SimpleAVCommandItem(68, "Audio Dubbing", "", 1)); m_commands.push_back(SimpleAVCommandItem(69, "Audio Level Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(70, "Audio Level Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(71, "Auto/Manual", "", 1)); m_commands.push_back(SimpleAVCommandItem(72, "Aux 1", "Aux", 1)); m_commands.push_back(SimpleAVCommandItem(73, "Aux 2", "", 1)); m_commands.push_back(SimpleAVCommandItem(74, "B", "", 1)); m_commands.push_back(SimpleAVCommandItem(75, "Back", "Previous Screen", 1)); m_commands.push_back(SimpleAVCommandItem(76, "Background", "Backlight", 1)); m_commands.push_back(SimpleAVCommandItem(77, "Balance", "", 1)); m_commands.push_back(SimpleAVCommandItem(78, "Balance Left", "", 1)); m_commands.push_back(SimpleAVCommandItem(79, "Balance Right", "", 1)); m_commands.push_back(SimpleAVCommandItem(80, "Band", "FM/AM", 1)); m_commands.push_back(SimpleAVCommandItem(81, "Bandwidth", "Wide/Narrow", 1)); m_commands.push_back(SimpleAVCommandItem(82, "Bass", "", 1)); m_commands.push_back(SimpleAVCommandItem(83, "Bass Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(84, "Bass Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(85, "Blank", "", 1)); m_commands.push_back(SimpleAVCommandItem(86, "Breeze Mode", "", 1)); m_commands.push_back(SimpleAVCommandItem(87, "Bright", "Brighten", 1)); m_commands.push_back(SimpleAVCommandItem(88, "Brightness", "", 1)); m_commands.push_back(SimpleAVCommandItem(89, "Brightness Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(90, "Brightness Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(91, "Buy", "", 1)); m_commands.push_back(SimpleAVCommandItem(92, "C", "", 1)); m_commands.push_back(SimpleAVCommandItem(93, "Camera", "", 1)); m_commands.push_back(SimpleAVCommandItem(94, "Category Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(95, "Category Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(96, "Center", "", 1)); m_commands.push_back(SimpleAVCommandItem(97, "Center Down", "Center Volume Down", 1)); m_commands.push_back(SimpleAVCommandItem(98, "Center Mode", "", 1)); m_commands.push_back(SimpleAVCommandItem(99, "Center Up", "Center Volume Up", 1)); m_commands.push_back(SimpleAVCommandItem(100, "Channel/Program", "C/P", 1)); m_commands.push_back(SimpleAVCommandItem(101, "Clear", "Cancel", 1)); m_commands.push_back(SimpleAVCommandItem(102, "Close", "", 1)); m_commands.push_back(SimpleAVCommandItem(103, "Closed Caption", "CC", 1)); m_commands.push_back(SimpleAVCommandItem(104, "Cold", "A/C", 1)); m_commands.push_back(SimpleAVCommandItem(105, "Color", "", 1)); m_commands.push_back(SimpleAVCommandItem(106, "Color Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(107, "Color Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(108, "Component 1", "RGB 1", 1)); m_commands.push_back(SimpleAVCommandItem(109, "Component 2", "RGB 2", 1)); m_commands.push_back(SimpleAVCommandItem(110, "Component 3", "", 1)); m_commands.push_back(SimpleAVCommandItem(111, "Concert", "", 1)); m_commands.push_back(SimpleAVCommandItem(112, "Confirm", "Check", 1)); m_commands.push_back(SimpleAVCommandItem(113, "Continue", "Continuous", 1)); m_commands.push_back(SimpleAVCommandItem(114, "Contrast", "", 1)); m_commands.push_back(SimpleAVCommandItem(115, "Contrast Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(116, "Contrast Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(117, "Counter", "", 1)); m_commands.push_back(SimpleAVCommandItem(118, "Counter Reset", "", 1)); m_commands.push_back(SimpleAVCommandItem(119, "D", "", 1)); m_commands.push_back(SimpleAVCommandItem(120, "Day Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(121, "Day Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(122, "Delay", "", 1)); m_commands.push_back(SimpleAVCommandItem(123, "Delay Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(124, "Delay Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(125, "Delete", "Erase", 1)); m_commands.push_back(SimpleAVCommandItem(126, "Delimiter", "Sub-Channel", 1)); m_commands.push_back(SimpleAVCommandItem(127, "Digest", "", 1)); m_commands.push_back(SimpleAVCommandItem(128, "Digital", "", 1)); m_commands.push_back(SimpleAVCommandItem(129, "Dim", "Dimmer", 1)); m_commands.push_back(SimpleAVCommandItem(130, "Direct", "", 1)); m_commands.push_back(SimpleAVCommandItem(131, "Disarm", "", 1)); m_commands.push_back(SimpleAVCommandItem(132, "Disc", "", 1)); m_commands.push_back(SimpleAVCommandItem(133, "Disc 1", "", 1)); m_commands.push_back(SimpleAVCommandItem(134, "Disc 2", "", 1)); m_commands.push_back(SimpleAVCommandItem(135, "Disc 3", "", 1)); m_commands.push_back(SimpleAVCommandItem(136, "Disc 4", "", 1)); m_commands.push_back(SimpleAVCommandItem(137, "Disc 5", "", 1)); m_commands.push_back(SimpleAVCommandItem(138, "Disc 6", "", 1)); m_commands.push_back(SimpleAVCommandItem(139, "Disc Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(140, "Disc Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(141, "Disco", "", 1)); m_commands.push_back(SimpleAVCommandItem(142, "Edit", "", 1)); m_commands.push_back(SimpleAVCommandItem(143, "Effect Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(144, "Effect Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(145, "Eject", "Open/Close", 1)); m_commands.push_back(SimpleAVCommandItem(146, "End", "", 1)); m_commands.push_back(SimpleAVCommandItem(147, "EQ", "Equalizer", 1)); m_commands.push_back(SimpleAVCommandItem(148, "Fader", "", 1)); m_commands.push_back(SimpleAVCommandItem(149, "Fan", "", 1)); m_commands.push_back(SimpleAVCommandItem(150, "Fan High", "", 1)); m_commands.push_back(SimpleAVCommandItem(151, "Fan Low", "", 1)); m_commands.push_back(SimpleAVCommandItem(152, "Fan Medium", "", 1)); m_commands.push_back(SimpleAVCommandItem(153, "Fan Speed", "", 1)); m_commands.push_back(SimpleAVCommandItem(154, "Fastext Blue", "", 1)); m_commands.push_back(SimpleAVCommandItem(155, "Fastext Green", "", 1)); m_commands.push_back(SimpleAVCommandItem(156, "Fastext Purple", "", 1)); m_commands.push_back(SimpleAVCommandItem(157, "Fastext Red", "", 1)); m_commands.push_back(SimpleAVCommandItem(158, "Fastext White", "", 1)); m_commands.push_back(SimpleAVCommandItem(159, "Fastext Yellow", "", 1)); m_commands.push_back(SimpleAVCommandItem(160, "Favorite Channel Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(161, "Favorite Channel Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(162, "Finalize", "", 1)); m_commands.push_back(SimpleAVCommandItem(163, "Fine Tune", "", 1)); m_commands.push_back(SimpleAVCommandItem(164, "Flat", "", 1)); m_commands.push_back(SimpleAVCommandItem(165, "FM", "", 1)); m_commands.push_back(SimpleAVCommandItem(166, "Focus Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(167, "Focus Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(168, "Freeze", "", 1)); m_commands.push_back(SimpleAVCommandItem(169, "Front", "", 1)); m_commands.push_back(SimpleAVCommandItem(170, "Game", "", 1)); m_commands.push_back(SimpleAVCommandItem(171, "GoTo", "Index Search", 1)); m_commands.push_back(SimpleAVCommandItem(172, "Hall", "", 1)); m_commands.push_back(SimpleAVCommandItem(173, "Heat", "", 1)); m_commands.push_back(SimpleAVCommandItem(174, "Help", "", 1)); m_commands.push_back(SimpleAVCommandItem(175, "Home", "", 1)); m_commands.push_back(SimpleAVCommandItem(176, "Index", "VISS", 1)); m_commands.push_back(SimpleAVCommandItem(177, "Index Forward", "", 1)); m_commands.push_back(SimpleAVCommandItem(178, "Index Reverse", "", 1)); m_commands.push_back(SimpleAVCommandItem(179, "Interactive", "Planner", 1)); m_commands.push_back(SimpleAVCommandItem(180, "Intro Scan", "", 1)); m_commands.push_back(SimpleAVCommandItem(181, "Jazz", "", 1)); m_commands.push_back(SimpleAVCommandItem(182, "Karaoke", "", 1)); m_commands.push_back(SimpleAVCommandItem(183, "Keystone", "", 1)); m_commands.push_back(SimpleAVCommandItem(184, "Keystone Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(185, "Keystone Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(186, "Language", "SAP", 1)); m_commands.push_back(SimpleAVCommandItem(187, "Left Click", "", 1)); m_commands.push_back(SimpleAVCommandItem(188, "Level", "Volume", 1)); m_commands.push_back(SimpleAVCommandItem(189, "Light", "Lamp", 1)); m_commands.push_back(SimpleAVCommandItem(190, "List", "My Shows", 1)); m_commands.push_back(SimpleAVCommandItem(191, "Live TV", "Return to Live", 1)); m_commands.push_back(SimpleAVCommandItem(192, "Local/Dx", "", 1)); m_commands.push_back(SimpleAVCommandItem(193, "Loudness", "", 1)); m_commands.push_back(SimpleAVCommandItem(194, "Mail", "Email", 1)); m_commands.push_back(SimpleAVCommandItem(195, "Mark", "Bookmark", 1)); m_commands.push_back(SimpleAVCommandItem(196, "Memory Recall", "", 1)); m_commands.push_back(SimpleAVCommandItem(197, "Monitor", "Tape Monitor", 1)); m_commands.push_back(SimpleAVCommandItem(198, "Movie", "", 1)); m_commands.push_back(SimpleAVCommandItem(199, "Multi Room", "", 1)); m_commands.push_back(SimpleAVCommandItem(200, "Music", "TV/Radio, My Music (WMC)", 1)); m_commands.push_back(SimpleAVCommandItem(201, "Music Scan", "Memory Scan", 1)); m_commands.push_back(SimpleAVCommandItem(202, "Natural", "", 1)); m_commands.push_back(SimpleAVCommandItem(203, "Night", "", 1)); m_commands.push_back(SimpleAVCommandItem(204, "Noise Reduction", "Dolby NR", 1)); m_commands.push_back(SimpleAVCommandItem(205, "Normalize", "Personal Preference", 1)); m_commands.push_back(SimpleAVCommandItem(206, "Discrete input Cable", "CATV", 1)); m_commands.push_back(SimpleAVCommandItem(207, "Discrete input CD 1", "CD", 1)); m_commands.push_back(SimpleAVCommandItem(208, "Discrete input CD 2", "CDR", 1)); m_commands.push_back(SimpleAVCommandItem(209, "Discrete input CDR", "Compact Disc Recorder", 1)); m_commands.push_back(SimpleAVCommandItem(210, "Discrete input DAT", "Digital Audio Tape", 1)); m_commands.push_back(SimpleAVCommandItem(211, "Discrete input DVD", "Digital Video Disk", 1)); m_commands.push_back(SimpleAVCommandItem(212, "Discrete input DVI", "Digital Video Interface", 1)); m_commands.push_back(SimpleAVCommandItem(213, "Discrete input HDTV", "", 1)); m_commands.push_back(SimpleAVCommandItem(214, "Discrete input LD", "Laser Disc", 1)); m_commands.push_back(SimpleAVCommandItem(215, "Discrete input MD", "Mini Disc", 1)); m_commands.push_back(SimpleAVCommandItem(216, "Discrete input PC", "Personal Computer", 1)); m_commands.push_back(SimpleAVCommandItem(217, "Discrete input PVR", "Personal Video Recorder", 1)); m_commands.push_back(SimpleAVCommandItem(218, "Discrete input TV", "", 1)); m_commands.push_back(SimpleAVCommandItem(219, "Discrete input TV/VCR", "TV/DVD", 1)); m_commands.push_back(SimpleAVCommandItem(220, "Discrete input VCR", "", 1)); m_commands.push_back(SimpleAVCommandItem(221, "One Touch Playback", "OTPB", 1)); m_commands.push_back(SimpleAVCommandItem(222, "One Touch Record", "OTR", 1)); m_commands.push_back(SimpleAVCommandItem(223, "Open", "", 1)); m_commands.push_back(SimpleAVCommandItem(224, "Optical", "", 1)); m_commands.push_back(SimpleAVCommandItem(225, "Options", "", 1)); m_commands.push_back(SimpleAVCommandItem(226, "Orchestra", "", 1)); m_commands.push_back(SimpleAVCommandItem(227, "PAL/NTSC", "System Select", 1)); m_commands.push_back(SimpleAVCommandItem(228, "Parental Lock", "Parental Control", 1)); m_commands.push_back(SimpleAVCommandItem(229, "PBC", "Playback Control", 1)); m_commands.push_back(SimpleAVCommandItem(230, "Phono", "", 1)); m_commands.push_back(SimpleAVCommandItem(231, "Photos", "Pictures, My Pictures (WMC)", 1)); m_commands.push_back(SimpleAVCommandItem(232, "Picture Menu", "Picture Adjust", 1)); m_commands.push_back(SimpleAVCommandItem(233, "Picture Mode", "Smart Picture", 1)); m_commands.push_back(SimpleAVCommandItem(234, "Picture Mute", "", 1)); m_commands.push_back(SimpleAVCommandItem(235, "PIP Channel Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(236, "PIP Channel Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(237, "PIP Freeze", "", 1)); m_commands.push_back(SimpleAVCommandItem(238, "PIP Input", "PIP Mode", 1)); m_commands.push_back(SimpleAVCommandItem(239, "PIP Move", "PIP Position", 1)); m_commands.push_back(SimpleAVCommandItem(240, "PIP Off", "", 1)); m_commands.push_back(SimpleAVCommandItem(241, "PIP On", "PIP", 1)); m_commands.push_back(SimpleAVCommandItem(242, "PIP Size", "", 1)); m_commands.push_back(SimpleAVCommandItem(243, "PIP Split", "Multi Screen", 1)); m_commands.push_back(SimpleAVCommandItem(244, "PIP Swap", "PIP Exchange", 1)); m_commands.push_back(SimpleAVCommandItem(245, "Play Mode", "", 1)); m_commands.push_back(SimpleAVCommandItem(246, "Play Reverse", "", 1)); m_commands.push_back(SimpleAVCommandItem(247, "Power Off", "", 1)); m_commands.push_back(SimpleAVCommandItem(248, "Power On", "", 1)); m_commands.push_back(SimpleAVCommandItem(249, "PPV", "Pay Per View", 1)); m_commands.push_back(SimpleAVCommandItem(250, "Preset", "", 1)); m_commands.push_back(SimpleAVCommandItem(251, "Program", "Program Memory", 1)); m_commands.push_back(SimpleAVCommandItem(252, "Progressive Scan", "Progressive", 1)); m_commands.push_back(SimpleAVCommandItem(253, "ProLogic", "Dolby Prologic", 1)); m_commands.push_back(SimpleAVCommandItem(254, "PTY", "Audio Program Type", 1)); m_commands.push_back(SimpleAVCommandItem(255, "Quick Skip", "Commercial Skip", 1)); m_commands.push_back(SimpleAVCommandItem(256, "Random", "Shuffle", 1)); m_commands.push_back(SimpleAVCommandItem(257, "RDS", "Radio Data System", 1)); m_commands.push_back(SimpleAVCommandItem(258, "Rear", "", 1)); m_commands.push_back(SimpleAVCommandItem(259, "Rear Volume Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(260, "Rear Volume Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(261, "Record Mute", "", 1)); m_commands.push_back(SimpleAVCommandItem(262, "Record Pause", "", 1)); m_commands.push_back(SimpleAVCommandItem(263, "Repeat", "", 1)); m_commands.push_back(SimpleAVCommandItem(264, "Repeat A-B", "", 1)); m_commands.push_back(SimpleAVCommandItem(265, "Resume", "", 1)); m_commands.push_back(SimpleAVCommandItem(266, "RGB", "Red Green Blue Component Video", 1)); m_commands.push_back(SimpleAVCommandItem(267, "Right Click", "", 1)); m_commands.push_back(SimpleAVCommandItem(268, "Rock", "", 1)); m_commands.push_back(SimpleAVCommandItem(269, "Rotate Left", "", 1)); m_commands.push_back(SimpleAVCommandItem(270, "Rotate Right", "", 1)); m_commands.push_back(SimpleAVCommandItem(271, "SAT", "Sky", 1)); m_commands.push_back(SimpleAVCommandItem(272, "Scan", "Channel Scan", 1)); m_commands.push_back(SimpleAVCommandItem(273, "Scart", "", 1)); m_commands.push_back(SimpleAVCommandItem(274, "Scene", "", 1)); m_commands.push_back(SimpleAVCommandItem(275, "Scroll", "", 1)); m_commands.push_back(SimpleAVCommandItem(276, "Services", "", 1)); m_commands.push_back(SimpleAVCommandItem(277, "Setup Menu", "Setup", 1)); m_commands.push_back(SimpleAVCommandItem(278, "Sharp", "", 1)); m_commands.push_back(SimpleAVCommandItem(279, "Sharpness", "", 1)); m_commands.push_back(SimpleAVCommandItem(280, "Sharpness Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(281, "Sharpness Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(282, "Side A/B", "", 1)); m_commands.push_back(SimpleAVCommandItem(283, "Skip Forward", "Next", 1)); m_commands.push_back(SimpleAVCommandItem(284, "Skip Reverse", "Previous", 1)); m_commands.push_back(SimpleAVCommandItem(285, "Sleep", "Off Timer", 1)); m_commands.push_back(SimpleAVCommandItem(286, "Slow", "", 1)); m_commands.push_back(SimpleAVCommandItem(287, "Slow Forward", "", 1)); m_commands.push_back(SimpleAVCommandItem(288, "Slow Reverse", "", 1)); m_commands.push_back(SimpleAVCommandItem(289, "Sound Menu", "Audio Menu", 1)); m_commands.push_back(SimpleAVCommandItem(290, "Sound Mode", "Smart Sound", 1)); m_commands.push_back(SimpleAVCommandItem(291, "Speed", "Record Speed", 1)); m_commands.push_back(SimpleAVCommandItem(292, "Speed Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(293, "Speed Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(294, "Sports", "Digital Surround Processing", 1)); m_commands.push_back(SimpleAVCommandItem(295, "Stadium", "", 1)); m_commands.push_back(SimpleAVCommandItem(296, "Start", "", 1)); m_commands.push_back(SimpleAVCommandItem(297, "Start ID Erase", "Erase", 1)); m_commands.push_back(SimpleAVCommandItem(298, "Start ID Renumber", "Renumber", 1)); m_commands.push_back(SimpleAVCommandItem(299, "Start ID Write", "Write", 1)); m_commands.push_back(SimpleAVCommandItem(300, "Step", "", 1)); m_commands.push_back(SimpleAVCommandItem(301, "Stereo/Mono", "L/R", 1)); m_commands.push_back(SimpleAVCommandItem(302, "Still Forward", "Frame Advance", 1)); m_commands.push_back(SimpleAVCommandItem(303, "Still Reverse", "Frame Reverse", 1)); m_commands.push_back(SimpleAVCommandItem(304, "Subtitle", "Subtitle On-Off", 1)); m_commands.push_back(SimpleAVCommandItem(305, "Subwoofer Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(306, "Subwoofer Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(307, "Super Bass", "Bass Boost", 1)); m_commands.push_back(SimpleAVCommandItem(308, "Surround", "", 1)); m_commands.push_back(SimpleAVCommandItem(309, "Surround Mode", "Sound Field", 1)); m_commands.push_back(SimpleAVCommandItem(310, "S-Video", "", 1)); m_commands.push_back(SimpleAVCommandItem(311, "Sweep", "Oscillate", 1)); m_commands.push_back(SimpleAVCommandItem(312, "Synchro Record", "CD Synchro", 1)); m_commands.push_back(SimpleAVCommandItem(313, "Tape 1", "Deck 1", 1)); m_commands.push_back(SimpleAVCommandItem(314, "Tape 1-2", "Deck 1-2", 1)); m_commands.push_back(SimpleAVCommandItem(315, "Tape 2", "Deck 2", 1)); m_commands.push_back(SimpleAVCommandItem(316, "Temperature Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(317, "Temperature Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(318, "Test Tone", "", 1)); m_commands.push_back(SimpleAVCommandItem(319, "Text", "Teletext", 1)); m_commands.push_back(SimpleAVCommandItem(320, "Text Expand", "", 1)); m_commands.push_back(SimpleAVCommandItem(321, "Text Hold", "", 1)); m_commands.push_back(SimpleAVCommandItem(322, "Text Index", "", 1)); m_commands.push_back(SimpleAVCommandItem(323, "Text Mix", "", 1)); m_commands.push_back(SimpleAVCommandItem(324, "Text Off", "", 1)); m_commands.push_back(SimpleAVCommandItem(325, "Text Reveal", "", 1)); m_commands.push_back(SimpleAVCommandItem(326, "Text Subpage", "", 1)); m_commands.push_back(SimpleAVCommandItem(327, "Text Timed Page", "", 1)); m_commands.push_back(SimpleAVCommandItem(328, "Text Update", "Text Cancel", 1)); m_commands.push_back(SimpleAVCommandItem(329, "Theater", "Cinema EQ", 1)); m_commands.push_back(SimpleAVCommandItem(330, "Theme", "Category Select", 1)); m_commands.push_back(SimpleAVCommandItem(331, "Thumbs Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(332, "Thumbs Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(333, "Tilt Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(334, "Tilt Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(335, "Time", "Clock", 1)); m_commands.push_back(SimpleAVCommandItem(336, "Timer", "", 1)); m_commands.push_back(SimpleAVCommandItem(337, "Timer Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(338, "Timer Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(339, "Tint", "", 1)); m_commands.push_back(SimpleAVCommandItem(340, "Tint Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(341, "Tint Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(342, "Title", "Top Menu", 1)); m_commands.push_back(SimpleAVCommandItem(343, "Track", "Chapter", 1)); m_commands.push_back(SimpleAVCommandItem(344, "Tracking", "", 1)); m_commands.push_back(SimpleAVCommandItem(345, "Tracking Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(346, "Tracking Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(347, "Treble", "", 1)); m_commands.push_back(SimpleAVCommandItem(348, "Treble Down", "", 1)); m_commands.push_back(SimpleAVCommandItem(349, "Treble Up", "", 1)); m_commands.push_back(SimpleAVCommandItem(350, "Tune Down", "Audio Tune Down", 1)); m_commands.push_back(SimpleAVCommandItem(351, "Tune Up", "Audio Tune Up", 1)); m_commands.push_back(SimpleAVCommandItem(352, "Tuner", "", 1)); m_commands.push_back(SimpleAVCommandItem(353, "VCR Plus+", "Showview", 1)); m_commands.push_back(SimpleAVCommandItem(354, "Video 1", "A/V 1", 1)); m_commands.push_back(SimpleAVCommandItem(355, "Video 2", "A/V 2", 1)); m_commands.push_back(SimpleAVCommandItem(356, "Video 3", "A/V 3", 1)); m_commands.push_back(SimpleAVCommandItem(357, "Video 4", "A/V 4", 1)); m_commands.push_back(SimpleAVCommandItem(358, "Video 5", "A/V 5", 1)); m_commands.push_back(SimpleAVCommandItem(359, "View", "", 1)); m_commands.push_back(SimpleAVCommandItem(360, "Voice", "Vocals", 1)); m_commands.push_back(SimpleAVCommandItem(361, "Zoom", "Magnify", 1)); m_commands.push_back(SimpleAVCommandItem(362, "Zoom In", "Zoom Up", 1)); m_commands.push_back(SimpleAVCommandItem(363, "Zoom Out", "Zoom Down", 1)); m_commands.push_back(SimpleAVCommandItem(364, "eHome", "(Windows Media Center)", 2)); m_commands.push_back(SimpleAVCommandItem(365, "Details", "(Windows Media Center)", 2)); m_commands.push_back(SimpleAVCommandItem(366, "DVD Menu", "(Windows Media Center)", 2)); m_commands.push_back(SimpleAVCommandItem(367, "My TV", "(Windows Media Center)", 2)); m_commands.push_back(SimpleAVCommandItem(368, "Recorded TV", "(Windows Media Center)", 2)); m_commands.push_back(SimpleAVCommandItem(369, "My Videos", "(Windows Media Center)", 2)); m_commands.push_back(SimpleAVCommandItem(370, "DVD Angle", "(Windows Media Center)", 2)); m_commands.push_back(SimpleAVCommandItem(371, "DVD Audio", "(Windows Media Center)", 2)); m_commands.push_back(SimpleAVCommandItem(372, "DVD Subtitle", "(Windows Media Center)", 2)); m_commands.push_back(SimpleAVCommandItem(373, "Radio", "(Windows Media Center)", 2)); m_commands.push_back(SimpleAVCommandItem(374, "#", "(Windows Media Center)", 2)); m_commands.push_back(SimpleAVCommandItem(375, "*", "(Windows Media Center)", 2)); m_commands.push_back(SimpleAVCommandItem(376, "OEM 1", "(Windows Media Center)", 2)); m_commands.push_back(SimpleAVCommandItem(377, "OEM 2", "(Windows Media Center)", 2)); m_commands.push_back(SimpleAVCommandItem(378, "Info", "Used to request information", 3)); m_commands.push_back(SimpleAVCommandItem(379, "CAPS NUM", "Switch between numeric and alpha (Shift)", 3)); m_commands.push_back(SimpleAVCommandItem(380, "TV MODE", "Cycles through video output modes/resolutions", 3)); m_commands.push_back(SimpleAVCommandItem(381, "SOURCE", "Displays the possible sources for the playback. [NFS, ext., USB, UPnP]", 3)); m_commands.push_back(SimpleAVCommandItem(382, "FILEMODE", "File manipulation. Add/remove to list, create folder, rename file", 3)); m_commands.push_back(SimpleAVCommandItem(383, "Time Seek", "This seeks to time position. Used for DVD/CD/others", 3)); m_commands.push_back(SimpleAVCommandItem(384, "Mouse enable", "Mouse pointer enable", 4)); m_commands.push_back(SimpleAVCommandItem(385, "Mouse disable", "Mouse pointer disable", 4)); m_commands.push_back(SimpleAVCommandItem(386, "VOD", "Video on demand", 4)); m_commands.push_back(SimpleAVCommandItem(387, "Thumbs Up", "Thumbs up for positive feedback in GUI", 4)); m_commands.push_back(SimpleAVCommandItem(388, "Thumbs Down", "Thumbs down for negative feedback in GUI", 4)); m_commands.push_back(SimpleAVCommandItem(389, "Apps", "Application selection/launch", 4)); m_commands.push_back(SimpleAVCommandItem(390, "Mouse toggle", "Will toggle a mouse pointer between on and off", 4)); m_commands.push_back(SimpleAVCommandItem(391, "TV Mode", "Will direct an AV device to go the TV mode (the mode is configured on the device)", 4)); m_commands.push_back(SimpleAVCommandItem(392, "DVD Mode", "Will direct an AV device to go the DVD mode (the mode is configured on the device)", 4)); m_commands.push_back(SimpleAVCommandItem(393, "STB Mode", "Will direct an AV device to go the STB mode (the mode is configured on the device)", 4)); m_commands.push_back(SimpleAVCommandItem(394, "AUX Mode", "Will direct an AV device to go the AUX mode (the mode is configured on the device)", 4)); m_commands.push_back(SimpleAVCommandItem(395, "BluRay Mode", "Will direct an AV device to go the BluRay mode (the mode is configured on the device)", 4)); m_commands.push_back(SimpleAVCommandItem(404, "Standby 1", "Used for AV devices that support multiple standby mode. Power ON should be used to turn on the device", 4)); m_commands.push_back(SimpleAVCommandItem(405, "Standby 2", "Used for AV devices that support multiple standby mode. Power ON should be used to turn on the device", 4)); m_commands.push_back(SimpleAVCommandItem(406, "Standby 3", "Used for AV devices that support multiple standby mode. Power ON should be used to turn on the device", 4)); m_commands.push_back(SimpleAVCommandItem(407, "HDMI 1", "Discrete command used to set an AV device to HDMI input 1", 4)); m_commands.push_back(SimpleAVCommandItem(408, "HDMI 2", "Discrete command used to set an AV device to HDMI input 2", 4)); m_commands.push_back(SimpleAVCommandItem(409, "HDMI 3", "Discrete command used to set an AV device to HDMI input 3", 4)); m_commands.push_back(SimpleAVCommandItem(410, "HDMI 4", "Discrete command used to set an AV device to HDMI input 4", 4)); m_commands.push_back(SimpleAVCommandItem(411, "HDMI 5", "Discrete command used to set an AV device to HDMI input 5", 4)); m_commands.push_back(SimpleAVCommandItem(412, "HDMI 6", "Discrete command used to set an AV device to HDMI input 6", 4)); m_commands.push_back(SimpleAVCommandItem(413, "HDMI 7", "Discrete command used to set an AV device to HDMI input 7", 4)); m_commands.push_back(SimpleAVCommandItem(414, "HDMI 8", "Discrete command used to set an AV device to HDMI input 8", 4)); m_commands.push_back(SimpleAVCommandItem(415, "HDMI 9", "Discrete command used to set an AV device to HDMI input 9", 4)); m_commands.push_back(SimpleAVCommandItem(416, "USB 1", "Discrete command used to set an AV device to USB input 1", 4)); m_commands.push_back(SimpleAVCommandItem(417, "USB 2", "Discrete command used to set an AV device to USB input 2", 4)); m_commands.push_back(SimpleAVCommandItem(418, "USB 3", "Discrete command used to set an AV device to USB input 3", 4)); m_commands.push_back(SimpleAVCommandItem(419, "USB 4", "Discrete command used to set an AV device to USB input 4", 4)); m_commands.push_back(SimpleAVCommandItem(420, "USB 5", "Discrete command used to set an AV device to USB input 5", 4)); m_commands.push_back(SimpleAVCommandItem(421, "ZOOM - 4:3 Normal", "Discrete commands that is used to set a TV a direct Zoom mode", 4)); m_commands.push_back(SimpleAVCommandItem(422, "ZOOM - 4:3 Zoom", "Discrete commands that is used to set a TV a direct Zoom mode", 4)); m_commands.push_back(SimpleAVCommandItem(423, "ZOOM - 16:9 Normal", "Discrete commands that is used to set a TV a direct Zoom mode", 4)); m_commands.push_back(SimpleAVCommandItem(424, "ZOOM - 16:9 Zoom", "Discrete commands that is used to set a TV a direct Zoom mode", 4)); m_commands.push_back(SimpleAVCommandItem(425, "ZOOM - 16:9 Wide 1", "Discrete commands that is used to set a TV a direct Zoom mode", 4)); m_commands.push_back(SimpleAVCommandItem(426, "ZOOM 16:9 Wide 2", "Discrete commands that is used to set a TV a direct Zoom mode", 4)); m_commands.push_back(SimpleAVCommandItem(427, "ZOOM 16:9 Wide 3", "Discrete commands that is used to set a TV a direct Zoom mode", 4)); m_commands.push_back(SimpleAVCommandItem(428, "ZOOM 16:9 Cinema", "Discrete commands that is used to set a TV a direct Zoom mode", 4)); m_commands.push_back(SimpleAVCommandItem(429, "ZOOM Default", "Discrete commands that is used to set a TV the default Zoom mode", 4)); m_commands.push_back(SimpleAVCommandItem(432, "Auto Zoom", "Will set Zoom mode automatically", 4)); m_commands.push_back(SimpleAVCommandItem(433, "ZOOM - Set as Default Zoom", "Will set the current active Zoom level to default", 4)); m_commands.push_back(SimpleAVCommandItem(434, "Mute ON", "Discrete Mute ON command", 4)); m_commands.push_back(SimpleAVCommandItem(435, "Mute OFF", "Discrete Mute OFF command", 4)); m_commands.push_back(SimpleAVCommandItem(436, "AUDIO Mode - AUDYSSEY AUDIO OFF", "Discrete Audio mode for Audussey audio processing (Off) ", 4)); m_commands.push_back(SimpleAVCommandItem(437, "AUDIO Mode - AUDYSSEY AUDIO LO", "Discrete Audio mode for Audussey audio processing (Low) ", 4)); m_commands.push_back(SimpleAVCommandItem(438, "AUDIO Mode - AUDYSSEY AUDIO MED", "Discrete Audio mode for Audussey audio processing (Medium) ", 4)); m_commands.push_back(SimpleAVCommandItem(439, "AUDIO Mode - AUDYSSEY AUDIO HI", "Discrete Audio mode for Audussey audio processing (High) ", 4)); m_commands.push_back(SimpleAVCommandItem(442, "AUDIO Mode - SRS SURROUND ON", "Discrete Audio mode for SRS audio processing", 4)); m_commands.push_back(SimpleAVCommandItem(443, "AUDIO Mode - SRS SURROUND OFF", "Discrete Audio mode for SRS audio processing", 4)); m_commands.push_back(SimpleAVCommandItem(447, "Picture Mode - Home", "Discrete picture for TVs", 4)); m_commands.push_back(SimpleAVCommandItem(448, "Picture Mode - Retail", "Discrete picture for TVs", 4)); m_commands.push_back(SimpleAVCommandItem(449, "Picture Mode - Vivid", "Discrete picture for TVs", 4)); m_commands.push_back(SimpleAVCommandItem(450, "Picture Mode - Standard", "Discrete picture for TVs", 4)); m_commands.push_back(SimpleAVCommandItem(451, "Picture Mode - Theater", "Discrete picture for TVs", 4)); m_commands.push_back(SimpleAVCommandItem(452, "Picture Mode - Sports", "Discrete picture for TVs", 4)); m_commands.push_back(SimpleAVCommandItem(453, "Picture Mode - Energy savings ", "Discrete picture for TVs", 4)); m_commands.push_back(SimpleAVCommandItem(454, "Picture Mode - Custom", "Discrete picture for TVs", 4)); m_commands.push_back(SimpleAVCommandItem(455, "Cool", "Discrete picture temperature adjustments", 4)); m_commands.push_back(SimpleAVCommandItem(456, "Medium", "Discrete picture temperature adjustments", 4)); m_commands.push_back(SimpleAVCommandItem(457, "Warm_D65", "Discrete picture temperature adjustments", 4)); m_commands.push_back(SimpleAVCommandItem(458, "CC ON", "Discrete Closed caption commands", 4)); m_commands.push_back(SimpleAVCommandItem(459, "CC OFF", "Discrete Closed caption commands", 4)); m_commands.push_back(SimpleAVCommandItem(460, "Video Mute ON", "Discrete Video mute command", 4)); m_commands.push_back(SimpleAVCommandItem(461, "Video Mute OFF", "Discrete Video mute command", 4)); m_commands.push_back(SimpleAVCommandItem(462, "Next Event", "Go to next state or event ", 4)); m_commands.push_back(SimpleAVCommandItem(463, "Previous Event", "Go to previous state or event", 4)); m_commands.push_back(SimpleAVCommandItem(464, "CEC device list", "Brings up the CES device list", 4)); m_commands.push_back(SimpleAVCommandItem(465, "MTS SAP", "Secondary Audio programming", 4)); } return m_commands; } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/ZWavePlusInfo.h0000644000175200017520000000506214032142455020314 00000000000000//----------------------------------------------------------------------------- // // ZWavePlusInfo.h // // Implementation of the Z-Wave COMMAND_CLASS_ZWAVEPLUS_INFO // // Copyright (c) 2015 // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ZWavePlusInfo_H #define _ZWavePlusInfo_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_ZWAVEPLUS_INFO (0x5E), a Z-Wave device command class. * \ingroup CommandClass */ class ZWavePlusInfo: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new ZWavePlusInfo(_homeId, _nodeId); } virtual ~ZWavePlusInfo() { } static uint8 const StaticGetCommandClassId() { return 0x5E; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_ZWAVEPLUS_INFO"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; protected: virtual void CreateVars(uint8 const _instance) override; private: ZWavePlusInfo(uint32 const _homeId, uint8 const _nodeId); }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/ManufacturerSpecific.h0000644000175200017520000000634214032142455021704 00000000000000//----------------------------------------------------------------------------- // // ManufacturerSpecific.h // // Implementation of the Z-Wave COMMAND_CLASS_MANUFACTURER_SPECIFIC // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ManufacturerSpecific_H #define _ManufacturerSpecific_H #include #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_MANUFACTURER_SPECIFIC (0x72), a Z-Wave device command class. * \ingroup CommandClass */ class ManufacturerSpecific: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new ManufacturerSpecific(_homeId, _nodeId); } virtual ~ManufacturerSpecific() { } static uint8 const StaticGetCommandClassId() { return 0x72; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_MANUFACTURER_SPECIFIC"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; //virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual uint8 GetMaxVersion() override { return 2; } void SetProductDetails(uint16 _manufacturerId, uint16 _productType, uint16 _productId); bool LoadConfigXML(); void ReLoadConfigXML(); void setLatestConfigRevision(uint32 rev); void setFileConfigRevision(uint32 rev); void setLoadedConfigRevision(uint32 rev); bool Init(); bool supportsMultiInstance() override { return false; } protected: virtual void CreateVars(uint8 const _instance) override; private: ManufacturerSpecific(uint32 const _homeId, uint8 const _nodeId); uint32 m_fileConfigRevision; uint32 m_loadedConfigRevision; uint32 m_latestConfigRevision; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/ClimateControlSchedule.cpp0000644000175200017520000003371214032142455022532 00000000000000//----------------------------------------------------------------------------- // // ClimateControlSchedule.cpp // // Implementation of the Z-Wave COMMAND_CLASS_CLIMATE_CONTROL_SCHEDULE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/ClimateControlSchedule.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "Node.h" #include "platform/Log.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueList.h" #include "value_classes/ValueSchedule.h" #include "tinyxml.h" namespace OpenZWave { namespace Internal { namespace CC { enum ClimateControlScheduleCmd { ClimateControlScheduleCmd_Set = 0x01, ClimateControlScheduleCmd_Get, ClimateControlScheduleCmd_Report, ClimateControlScheduleCmd_ChangedGet, ClimateControlScheduleCmd_ChangedReport, ClimateControlScheduleCmd_OverrideSet, ClimateControlScheduleCmd_OverrideGet, ClimateControlScheduleCmd_OverrideReport }; static char const* c_dayNames[] = { "Invalid", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" }; static char const* c_overrideStateNames[] = { "None", "Temporary", "Permanent", "Invalid" }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- ClimateControlSchedule::ClimateControlSchedule(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { m_dom.EnableFlag(STATE_FLAG_CCS_CHANGECOUNTER, 0); } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool ClimateControlSchedule::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Session) { // See if the schedule has changed since last time return RequestValue(_requestFlags, 0, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool ClimateControlSchedule::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { // See if the schedule has changed since last time Msg* msg = new Msg("ClimateControlScheduleCmd_ChangedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(ClimateControlScheduleCmd_ChangedGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool ClimateControlSchedule::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (ClimateControlScheduleCmd_Report == (ClimateControlScheduleCmd) _data[0]) { uint8 day = _data[1] & 0x07; if (day > 7) /* size of c_dayNames */ { Log::Write(LogLevel_Warning, GetNodeId(), "Day Value was greater than range. Setting to Invalid"); day = 0; } Log::Write(LogLevel_Info, GetNodeId(), "Received climate control schedule report for %s", c_dayNames[day]); if (Internal::VC::ValueSchedule* value = static_cast(GetValue(_instance, day))) { // Remove any existing data value->ClearSwitchPoints(); // Parse the switch point data for (uint8 i = 2; i < 29; i += 3) { uint8 setback = _data[i + 2]; if (setback == 0x7f) { // Switch point is unused, so we stop parsing here break; } uint8 hours = _data[i] & 0x1f; uint8 minutes = _data[i + 1] & 0x3f; if (setback == 0x79) { Log::Write(LogLevel_Info, GetNodeId(), " Switch point at %02d:%02d, Frost Protection Mode", hours, minutes, c_dayNames[day]); } else if (setback == 0x7a) { Log::Write(LogLevel_Info, GetNodeId(), " Switch point at %02d:%02d, Energy Saving Mode", hours, minutes, c_dayNames[day]); } else { Log::Write(LogLevel_Info, GetNodeId(), " Switch point at %02d:%02d, Setback %+.1fC", hours, minutes, ((float) setback) * 0.1f); } value->SetSwitchPoint(hours, minutes, setback); } if (!value->GetNumSwitchPoints()) { Log::Write(LogLevel_Info, GetNodeId(), " No Switch points have been set"); } // Notify the user value->OnValueRefreshed(); value->Release(); } return true; } if (ClimateControlScheduleCmd_ChangedReport == (ClimateControlScheduleCmd) _data[0]) { Log::Write(LogLevel_Info, GetNodeId(), "Received climate control schedule changed report:"); if (_data[1]) { if (_data[1] != m_dom.GetFlagByte(STATE_FLAG_CCS_CHANGECOUNTER)) { m_dom.SetFlagByte(STATE_FLAG_CCS_CHANGECOUNTER, _data[1]); // The schedule has changed and is not in override mode, so request reports for each day for (int i = 1; i <= 7; ++i) { Log::Write(LogLevel_Info, GetNodeId(), "Get climate control schedule for %s", c_dayNames[i]); Msg* msg = new Msg("ClimateControlScheduleCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(ClimateControlScheduleCmd_Get); msg->Append(i); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } } } else { // Device is in override mode, so we request details of that instead Msg* msg = new Msg("ClimateControlScheduleCmd_OverrideGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(ClimateControlScheduleCmd_OverrideGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } return true; } if (ClimateControlScheduleCmd_OverrideReport == (ClimateControlScheduleCmd) _data[0]) { uint8 overrideState = _data[1] & 0x03; if (overrideState > 3) /* size of c_overrideStateNames */ { Log::Write(LogLevel_Warning, GetNodeId(), "overrideState Value was greater than range. Setting to Invalid"); overrideState = 3; } Log::Write(LogLevel_Info, GetNodeId(), "Received climate control schedule override report:"); Log::Write(LogLevel_Info, GetNodeId(), " Override State: %s:", c_overrideStateNames[overrideState]); if (Internal::VC::ValueList* valueList = static_cast(GetValue(_instance, ValueID_Index_ClimateControlSchedule::OverrideState))) { valueList->OnValueRefreshed((int) overrideState); valueList->Release(); } uint8 setback = _data[2]; if (overrideState) { if (setback == 0x79) { Log::Write(LogLevel_Info, GetNodeId(), " Override Setback: Frost Protection Mode"); } else if (setback == 0x7a) { Log::Write(LogLevel_Info, GetNodeId(), " Override Setback: Energy Saving Mode"); } else { Log::Write(LogLevel_Info, GetNodeId(), " Override Setback: %+.1fC", ((float) setback) * 0.1f); } } if (Internal::VC::ValueByte* valueByte = static_cast(GetValue(_instance, ValueID_Index_ClimateControlSchedule::OverrideSetback))) { valueByte->OnValueRefreshed(setback); valueByte->Release(); } return true; } return false; } //----------------------------------------------------------------------------- // // Set a value in the device //----------------------------------------------------------------------------- bool ClimateControlSchedule::SetValue(Internal::VC::Value const& _value) { // bool res = false; uint8_t instance = _value.GetID().GetInstance(); uint8_t idx = (uint8_t) (_value.GetID().GetIndex() & 0xFF); if (idx < 8) { // Set a schedule Internal::VC::ValueSchedule const* value = static_cast(&_value); Log::Write(LogLevel_Info, GetNodeId(), "Set the climate control schedule for %s", c_dayNames[idx]); Msg* msg = new Msg("ClimateControlScheduleCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, instance); msg->Append(GetNodeId()); msg->Append(30); msg->Append(GetCommandClassId()); msg->Append(ClimateControlScheduleCmd_Set); msg->Append(idx); // Day of week for (uint8_t i = 0; i < 9; ++i) { uint8_t hours; uint8_t minutes; int8 setback; if (value->GetSwitchPoint(i, &hours, &minutes, &setback)) { msg->Append(hours); msg->Append(minutes); msg->Append(setback); } else { // Unused switch point msg->Append(0); msg->Append(0); msg->Append(0x7f); } } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } else { // Set an override if (Internal::VC::ValueList* state = static_cast(GetValue(instance, ValueID_Index_ClimateControlSchedule::OverrideState))) { if (Internal::VC::ValueList::Item const* item = state->GetItem()) { if (Internal::VC::ValueByte* setback = static_cast(GetValue(instance, ValueID_Index_ClimateControlSchedule::OverrideSetback))) { Msg* msg = new Msg("ClimateControlScheduleCmd_OverrideSet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); // nullptr check after "new" is kind of placebo, but it makes for consistent code // discussion: https://github.com/OpenZWave/open-zwave/pull/1985 if (msg != nullptr) { msg->SetInstance(this, instance); msg->Append(GetNodeId()); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(ClimateControlScheduleCmd_OverrideSet); msg->Append((uint8)item->m_value); msg->Append(setback->GetValue()); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } setback->Release(); } else { Log::Write(LogLevel_Warning, GetNodeId(), "ClimateControlSchedule::SetValue couldn't Find ValueID_Index_ClimateControlSchedule::OverrideSetback"); } } else { Log::Write(LogLevel_Warning, GetNodeId(), "ClimateControlSchedule::SetValue state->GetItem() returned nullptr"); } state->Release(); } else { Log::Write(LogLevel_Warning, GetNodeId(), "ClimateControlSchedule::SetValue couldn't Find ValueID_Index_ClimateControlSchedule::OverrideState"); } } return true; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void ClimateControlSchedule::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { // Add a ValueSchedule for each day of the week. for (uint8 i = 0; i < 7; ++i) { node->CreateValueSchedule(ValueID::ValueGenre_User, GetCommandClassId(), _instance, i + 1, c_dayNames[i + 1], "", false, false, 0); } // Add values for the override state and setback vector items; Internal::VC::ValueList::Item item; for (uint8 i = 0; i < 3; ++i) { item.m_label = c_overrideStateNames[i]; item.m_value = i; items.push_back(item); } node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ClimateControlSchedule::OverrideState, "Override State", "", false, false, 1, items, 0, 0); node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ClimateControlSchedule::OverrideSetback, "Override Setback", "", false, false, 0, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/CommandClass.cpp0000644000175200017520000007271714032142455020512 00000000000000//----------------------------------------------------------------------------- // // CommandClass.cpp // // Base class for all Z-Wave Command Classes // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include "Defs.h" #include "tinyxml.h" #include "command_classes/CommandClass.h" #include "command_classes/Basic.h" #include "command_classes/MultiInstance.h" #include "command_classes/CommandClasses.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "Localization.h" #include "Manager.h" #include "platform/Log.h" #include "value_classes/Value.h" #include "value_classes/ValueStore.h" namespace OpenZWave { namespace Internal { namespace CC { static uint8 const c_sizeMask = 0x07; static uint8 const c_scaleMask = 0x18; static uint8 const c_scaleShift = 0x03; static uint8 const c_precisionMask = 0xe0; static uint8 const c_precisionShift = 0x05; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- CommandClass::CommandClass(uint32 const _homeId, uint8 const _nodeId) : m_com(CompatOptionType_Compatibility, this), m_dom(CompatOptionType_Discovery, this), m_homeId(_homeId), m_nodeId(_nodeId), m_SecureSupport(true), m_sentCnt(0), m_receivedCnt(0) { m_com.EnableFlag(COMPAT_FLAG_GETSUPPORTED, true); m_com.EnableFlag(COMPAT_FLAG_OVERRIDEPRECISION, 0); m_com.EnableFlag(COMPAT_FLAG_FORCEVERSION, 0); m_com.EnableFlag(COMPAT_FLAG_CREATEVARS, true); m_com.EnableFlag(COMPAT_FLAG_REFRESHONWAKEUP, false); m_com.EnableFlag(COMPAT_FLAG_VERIFYCHANGED, false); m_com.EnableFlag(COMPAT_FLAG_NO_REFRESH_AFTER_SET, false); m_dom.EnableFlag(STATE_FLAG_CCVERSION, 0); m_dom.EnableFlag(STATE_FLAG_STATIC_REQUESTS, 0); m_dom.EnableFlag(STATE_FLAG_AFTERMARK, false); m_dom.EnableFlag(STATE_FLAG_ENCRYPTED, false); m_dom.EnableFlag(STATE_FLAG_INNIF, false); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- CommandClass::~CommandClass() { while (!m_endPointMap.empty()) { map::iterator it = m_endPointMap.begin(); m_endPointMap.erase(it); } while (!m_RefreshClassValues.empty()) { multimap::iterator it; for (it = m_RefreshClassValues.begin(); it != m_RefreshClassValues.end(); it++) { delete it->second; } m_RefreshClassValues.clear(); } } //----------------------------------------------------------------------------- // // Get a pointer to our driver //----------------------------------------------------------------------------- OpenZWave::Driver* CommandClass::GetDriver() const { return (Manager::Get()->GetDriver(m_homeId)); } //----------------------------------------------------------------------------- // // Get a pointer to our node without locking the mutex //----------------------------------------------------------------------------- OpenZWave::Node* CommandClass::GetNodeUnsafe() const { return (GetDriver()->GetNodeUnsafe(m_nodeId)); } //----------------------------------------------------------------------------- // // Get a pointer to a value by its instance and index //----------------------------------------------------------------------------- OpenZWave::Internal::VC::Value* CommandClass::GetValue(uint8 const _instance, uint16 const _index) { Internal::VC::Value* value = NULL; if (Node* node = GetNodeUnsafe()) { value = node->GetValue(GetCommandClassId(), _instance, _index); } return value; } //----------------------------------------------------------------------------- // // Remove a value by its instance and index //----------------------------------------------------------------------------- bool CommandClass::RemoveValue(uint8 const _instance, uint16 const _index) { if (Node* node = GetNodeUnsafe()) { return node->RemoveValue(GetCommandClassId(), _instance, _index); } return false; } //----------------------------------------------------------------------------- // // Instances as set by the MultiInstance V1 command class //----------------------------------------------------------------------------- void CommandClass::SetInstances(uint8 const _instances) { // Ensure we have a set of reported variables for each new instance if (!m_dom.GetFlagBool(STATE_FLAG_AFTERMARK)) { for (uint8 i = 0; i < _instances; ++i) { SetInstance(i + 1); } } } //----------------------------------------------------------------------------- // // Instances as set by the MultiChannel (i.e. MultiInstance V2) command class //----------------------------------------------------------------------------- void CommandClass::SetInstance(uint8 const _endPoint) { if (!m_instances.IsSet(_endPoint)) { m_instances.Set(_endPoint); } } //----------------------------------------------------------------------------- // // Set the Label for a Instance of this CommandClass //----------------------------------------------------------------------------- void CommandClass::SetInstanceLabel(uint8 const _instance, char *label) { m_instanceLabel[_instance] = std::string(label); } //----------------------------------------------------------------------------- // // Get the Label for a Instance of this CommandClass //----------------------------------------------------------------------------- std::string CommandClass::GetInstanceLabel(uint8 const _instance) { if (m_instanceLabel.count(_instance)) { return Localization::Get()->GetGlobalLabel(m_instanceLabel[_instance]); } return std::string(); } //----------------------------------------------------------------------------- // // Read the saved command class data //----------------------------------------------------------------------------- void CommandClass::ReadXML(TiXmlElement const* _ccElement) { int32 intVal; char const* str; m_com.ReadXML(_ccElement); m_dom.ReadXML(_ccElement); // Apply any differences from the saved XML to the values TiXmlElement const* child = _ccElement->FirstChildElement(); while (child) { str = child->Value(); if (str) { if (!strcmp(str, "Instance")) { uint8 instance = 0; // Add an instance to the command class if (TIXML_SUCCESS == child->QueryIntAttribute("index", &intVal)) { instance = (uint8) intVal; SetInstance(instance); } // See if its associated endpoint is present if (TIXML_SUCCESS == child->QueryIntAttribute("endpoint", &intVal)) { uint8 endpoint = (uint8) intVal; SetEndPoint(instance, endpoint); } str = child->Attribute("label"); if (str) { SetInstanceLabel(instance, (char *) str); Localization::Get()->SetGlobalLabel(str, str, ""); TiXmlElement const *labellang = child->FirstChildElement(); while (labellang) { char const* str2 = labellang->Value(); if (str2 && !strcmp(str2, "Label")) { char const *lang = labellang->Attribute("lang"); Localization::Get()->SetGlobalLabel(str, labellang->GetText(), lang); } labellang = labellang->NextSiblingElement(); } } } else if (!strcmp(str, "Value")) { // Apply any differences from the saved XML to the value GetNodeUnsafe()->ReadValueFromXML(GetCommandClassId(), child); } else if (!strcmp(str, "TriggerRefreshValue")) { ReadValueRefreshXML(child); } } child = child->NextSiblingElement(); } // Make sure previously created values are removed if create_vars=false if (!m_com.GetFlagBool(COMPAT_FLAG_CREATEVARS)) { if (Node* node = GetNodeUnsafe()) { node->GetValueStore()->RemoveCommandClassValues(GetCommandClassId()); } } } //----------------------------------------------------------------------------- // // Read the config that contains a list of Values that should be refreshed when // we recieve u updated Value from a device. (This helps Yale Door Locks, which send a // Alarm Report instead of DoorLock Report when the status of the Door Lock is changed //----------------------------------------------------------------------------- void CommandClass::ReadValueRefreshXML(TiXmlElement const* _ccElement) { char const* str; uint16 sourceIdx; bool ok = true; int temp; _ccElement->QueryIntAttribute("Index", &temp); sourceIdx = (uint16) temp; /* check if we have a entry already */ if (m_RefreshClassValues.find(sourceIdx) != m_RefreshClassValues.end()) { Log::Write(LogLevel_Warning, GetNodeId(), "TriggerRefreshValue - A Entry already exists for CC %s Index %d", GetCommandClassName().c_str(), sourceIdx); return; } Log::Write(LogLevel_Info, GetNodeId(), "Value Refresh triggered by CommandClass: %s, Index: %d for:", GetCommandClassName().c_str(), sourceIdx); TiXmlElement const* child = _ccElement->FirstChildElement(); while (child) { ok = true; str = child->Value(); if (str) { if (!strcmp(str, "RefreshClassValue")) { RefreshValue *arcc = new RefreshValue(); if (child->QueryIntAttribute("CommandClass", &temp) != TIXML_SUCCESS) { Log::Write(LogLevel_Warning, GetNodeId(), "\tInvalid XML - CommandClass Attribute is wrong type or missing"); child = child->NextSiblingElement(); continue; } arcc->cc = (uint8) temp; if (child->QueryIntAttribute("RequestFlags", &temp) != TIXML_SUCCESS) { Log::Write(LogLevel_Warning, GetNodeId(), "\tInvalid XML - RequestFlags Attribute is wrong type or missing"); child = child->NextSiblingElement(); continue; } arcc->requestflags = (uint8) temp; if (child->QueryIntAttribute("Index", &temp) != TIXML_SUCCESS) { Log::Write(LogLevel_Warning, GetNodeId(), "\tInvalid XML - Index Attribute is wrong type or missing"); child = child->NextSiblingElement(); continue; } arcc->index = (uint16) temp; /* check for Duplicates */ multimap::iterator it; for (it = m_RefreshClassValues.begin(); it != m_RefreshClassValues.end(); it++) { uint16 idx = it->first; RefreshValue *rv = it->second; if ((idx == sourceIdx) && (rv->cc == arcc->cc) && (rv->requestflags == arcc->requestflags) && (rv->index == arcc->index)) { Log::Write(LogLevel_Warning, GetNodeId(), "\tTarget Exists: CC %s Index %d", CommandClasses::GetName(arcc->cc).c_str(), arcc->index); delete arcc; ok = false; break; } } if (ok) { Log::Write(LogLevel_Info, GetNodeId(), "\tCommandClass: %s, RequestFlags: %d, Index: %d", CommandClasses::GetName(arcc->cc).c_str(), arcc->requestflags, arcc->index); m_RefreshClassValues.insert(std::make_pair(sourceIdx, arcc)); } } else { Log::Write(LogLevel_Warning, GetNodeId(), "Got Unhandled Child Entry in TriggerRefreshValue XML Config: %s", str); } } child = child->NextSiblingElement(); } } //----------------------------------------------------------------------------- // // Scan our m_RefreshClassValues vector to see if we should call any other // Command Classes to refresh their value //----------------------------------------------------------------------------- bool CommandClass::CheckForRefreshValues(Internal::VC::Value const* _value) { /* if there are no values here... */ if (m_RefreshClassValues.find(_value->GetID().GetIndex()) == m_RefreshClassValues.end()) return false; Node* node = GetNodeUnsafe(); if (node != NULL) { multimap::iterator it; for (it = m_RefreshClassValues.find(_value->GetID().GetIndex()); it != m_RefreshClassValues.end(); it++) { RefreshValue *rcc = it->second; /* just to be sure we have the right index */ if (it->first != _value->GetID().GetIndex()) return false; Log::Write(LogLevel_Debug, GetNodeId(), "Requesting Refresh of Value: CommandClass: %s Instance %d, Index %d", CommandClasses::GetName(rcc->cc).c_str(), _value->GetID().GetInstance(), rcc->index); if (CommandClass* cc = node->GetCommandClass(rcc->cc)) { cc->RequestValue(rcc->requestflags, rcc->index, _value->GetID().GetInstance(), Driver::MsgQueue_Send); } } } else /* Driver */ { Log::Write(LogLevel_Warning, GetNodeId(), "Can't get Node"); } return true; } //----------------------------------------------------------------------------- // // Save the static node configuration data //----------------------------------------------------------------------------- void CommandClass::WriteXML(TiXmlElement* _ccElement) { char str[32]; m_com.WriteXML(_ccElement); m_dom.WriteXML(_ccElement); snprintf(str, sizeof(str), "%d", GetCommandClassId()); _ccElement->SetAttribute("id", str); _ccElement->SetAttribute("name", GetCommandClassName().c_str()); // Write out the instances for (Bitfield::Iterator it = m_instances.Begin(); it != m_instances.End(); ++it) { TiXmlElement* instanceElement = new TiXmlElement("Instance"); _ccElement->LinkEndChild(instanceElement); snprintf(str, sizeof(str), "%d", *it); instanceElement->SetAttribute("index", str); map::iterator eit = m_endPointMap.find(*it); if (eit != m_endPointMap.end()) { snprintf(str, sizeof(str), "%d", eit->second); instanceElement->SetAttribute("endpoint", str); } if (m_instanceLabel.count(*it) > 0) instanceElement->SetAttribute("label", GetInstanceLabel(*it).c_str()); } // Write out the values for this command class Internal::VC::ValueStore* store = GetNodeUnsafe()->GetValueStore(); for (Internal::VC::ValueStore::Iterator it = store->Begin(); it != store->End(); ++it) { Internal::VC::Value* value = it->second; if (value->GetID().GetCommandClassId() == GetCommandClassId()) { TiXmlElement* valueElement = new TiXmlElement("Value"); _ccElement->LinkEndChild(valueElement); value->WriteXML(valueElement); } } // Write out the TriggerRefreshValue if it exists multimap::iterator it; uint16 sourceidx = 0; TiXmlElement* RefreshElement = nullptr; for (it = m_RefreshClassValues.begin(); it != m_RefreshClassValues.end(); it++) { RefreshValue *rcc = it->second; if (sourceidx != it->first) { RefreshElement = new TiXmlElement("TriggerRefreshValue"); _ccElement->LinkEndChild(RefreshElement); RefreshElement->SetAttribute("Index", it->first); sourceidx = it->first; } if (RefreshElement) { TiXmlElement *ClassElement = new TiXmlElement("RefreshClassValue"); RefreshElement->LinkEndChild(ClassElement); ClassElement->SetAttribute("CommandClass", rcc->cc); ClassElement->SetAttribute("RequestFlags", rcc->requestflags); ClassElement->SetAttribute("Index", rcc->index); } else { Log::Write(LogLevel_Warning, GetNodeId(), "CommandClass::WriteXML: - RefreshElement was empty for index %d", it->first); } } } //----------------------------------------------------------------------------- // // Read a value from a variable length sequence of bytes //----------------------------------------------------------------------------- std::string CommandClass::ExtractValue(uint8 const* _data, uint8* _scale, uint8* _precision, uint8 _valueOffset // = 1 ) const { uint8 const size = _data[0] & c_sizeMask; uint8 const precision = (_data[0] & c_precisionMask) >> c_precisionShift; if (_scale) { *_scale = (_data[0] & c_scaleMask) >> c_scaleShift; } if (_precision) { *_precision = precision; } uint32 value = 0; uint8 i; for (i = 0; i < size; ++i) { value <<= 8; value |= (uint32) _data[i + (uint32) _valueOffset]; } // Deal with sign extension. All values are signed std::string res; if (_data[_valueOffset] & 0x80) { res = "-"; // MSB is signed if (size == 1) { value |= 0xffffff00; } else if (size == 2) { value |= 0xffff0000; } } // Convert the integer to a decimal string. We avoid // using floats to prevent accuracy issues. char numBuf[12] = { 0 }; if (precision == 0) { // The precision is zero, so we can just print the number directly into the string. snprintf(numBuf, 12, "%d", (signed int) value); res = numBuf; } else { // We'll need to insert a decimal point and include any necessary leading zeros. // Fill the buffer with the value padded with leading zeros. snprintf(numBuf, 12, "%011d", (signed int) value); // Calculate the position of the decimal point in the buffer int32 decimal = 10 - precision; // Shift the characters to make space for the decimal point. // We don't worry about overwriting any minus sign since that is // already written into the res string. While we're shifting, we // also look for the real starting position of the number so we // can copy it into the res string later. int32 start = -1; for (int32 i = 0; i < decimal; ++i) { numBuf[i] = numBuf[i + 1]; if ((start < 0) && (numBuf[i] != '0')) { start = i; } } if (start < 0) { start = decimal - 1; } // Insert the decimal point struct lconv const* locale = localeconv(); numBuf[decimal] = *(locale->decimal_point); // Copy the buffer into res res += &numBuf[start]; } return res; } //----------------------------------------------------------------------------- // // Decode the Duration Field to Seconds - CC:0000.00.00.11.016 //----------------------------------------------------------------------------- uint32 CommandClass::decodeDuration(uint8 data) const { if (data <= 0x7f) return data; if ((data > 0x7f) && (data <= 0xFD)) return ((data - 0x7F)*60); /* a 0xFE means Unknown Duration * and 0xFF is Reserved - So lets return -1 (to wrap our Int) */ return -1; } uint8 CommandClass::encodeDuration(uint32 seconds) const { if (seconds <= 0x7f) return (seconds & 0xFF); /* 7620 seconds is the max that can fit into our scale, so anything above that, use it as the Default Duration * its 7620 as we only can go upto 127 minutes - See https://github.com/OpenZWave/open-zwave/issues/1321#issuecomment-656532282 */ if (seconds > 7620) return 0xFF; /* if we get here, seconds is always going to be at least 2 minutes - 0x7F(127) is > 2 minutes */ return (uint8)0x79 + ((seconds/60) & 0xFF); } //----------------------------------------------------------------------------- // // Add a value to a message as a sequence of bytes //----------------------------------------------------------------------------- void CommandClass::AppendValue(Msg* _msg, std::string const& _value, uint8 const _scale) const { uint8 precision; uint8 size; int32 val = ValueToInteger(_value, &precision, &size); _msg->Append((precision << c_precisionShift) | (_scale << c_scaleShift) | size); int32 shift = (size - 1) << 3; for (int32 i = size; i > 0; --i, shift -= 8) { _msg->Append((uint8) (val >> shift)); } } //----------------------------------------------------------------------------- // // Get the number of bytes that would be added by a call to AppendValue //----------------------------------------------------------------------------- uint8 const CommandClass::GetAppendValueSize(std::string const& _value) const { uint8 size; ValueToInteger(_value, NULL, &size); return size; } //----------------------------------------------------------------------------- // // Convert a decimal string to an integer and report the precision and // number of bytes required to store the value. //----------------------------------------------------------------------------- int32 CommandClass::ValueToInteger(std::string const& _value, uint8* o_precision, uint8* o_size) const { int32 val; uint8 precision; // Find the decimal point size_t pos = _value.find_first_of("."); if (pos == std::string::npos) pos = _value.find_first_of(","); if (pos == std::string::npos) { // No decimal point precision = 0; // Convert the string to an integer val = atol(_value.c_str()); } else { // Remove the decimal point and convert to an integer precision = (uint8) ((_value.size() - pos) - 1); std::string str = _value.substr(0, pos) + _value.substr(pos + 1); val = atol(str.c_str()); } uint8_t orp = m_com.GetFlagByte(COMPAT_FLAG_OVERRIDEPRECISION); if (orp > 0) { while (precision < orp) { precision++; val *= 10; } } if (o_precision) *o_precision = precision; if (o_size) { // Work out the size as either 1, 2 or 4 bytes *o_size = 4; if (val < 0) { if ((val & 0xffffff80) == 0xffffff80) { *o_size = 1; } else if ((val & 0xffff8000) == 0xffff8000) { *o_size = 2; } } else { if ((val & 0xffffff00) == 0) { *o_size = 1; } else if ((val & 0xffff0000) == 0) { *o_size = 2; } } } return val; } //----------------------------------------------------------------------------- // // Update the mapped class if there is one with BASIC level //----------------------------------------------------------------------------- void CommandClass::UpdateMappedClass(uint8 const _instance, uint8 const _classId, uint8 const _level) { if (_classId) { if (Node* node = GetNodeUnsafe()) { CommandClass* cc = node->GetCommandClass(_classId); if (cc != NULL) { cc->SetValueBasic(_instance, _level); } } } } //----------------------------------------------------------------------------- // // The static data for this command class has been read from the device //----------------------------------------------------------------------------- void CommandClass::ClearStaticRequest(uint8_t _request) { uint8_t f_staticRequests = m_dom.GetFlagByte(STATE_FLAG_STATIC_REQUESTS); f_staticRequests &= ~_request; m_dom.SetFlagByte(STATE_FLAG_STATIC_REQUESTS, f_staticRequests); } //----------------------------------------------------------------------------- // // The static data for this command class has been read from the device //----------------------------------------------------------------------------- void CommandClass::SetStaticRequest(uint8_t _request) { uint8_t f_staticRequests = m_dom.GetFlagByte(STATE_FLAG_STATIC_REQUESTS); f_staticRequests |= _request; m_dom.SetFlagByte(STATE_FLAG_STATIC_REQUESTS, f_staticRequests); } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool CommandClass::RequestStateForAllInstances(uint32 const _requestFlags, Driver::MsgQueue const _queue) { bool res = false; if (m_com.GetFlagBool(COMPAT_FLAG_CREATEVARS)) { if (Node* node = GetNodeUnsafe()) { MultiInstance* multiInstance = static_cast(node->GetCommandClass(MultiInstance::StaticGetCommandClassId())); if (multiInstance != NULL) { for (Bitfield::Iterator it = m_instances.Begin(); it != m_instances.End(); ++it) { res |= RequestState(_requestFlags, (uint8) *it, _queue); } } else { res = RequestState(_requestFlags, 1, _queue); } } } return res; } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- std::string const CommandClass::GetCommandClassLabel() { return m_commandClassLabel; } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- void CommandClass::SetCommandClassLabel(std::string label) { m_commandClassLabel = label; } //----------------------------------------------------------------------------- // // Made out-of-line to allow overriding //----------------------------------------------------------------------------- void CommandClass::SetVersion(uint8 const _version) { if (m_com.GetFlagByte(COMPAT_FLAG_FORCEVERSION) == 0) { if (_version >= m_dom.GetFlagByte(STATE_FLAG_CCVERSION)) { m_dom.SetFlagByte(STATE_FLAG_CCVERSION, _version); } else { Log::Write(LogLevel_Warning, GetNodeId(), "Trying to Downgrade Command Class %s version from %d to %d. Ignored", GetCommandClassName().c_str(), m_dom.GetFlagByte(STATE_FLAG_CCVERSION), _version); } } else { m_dom.SetFlagByte(STATE_FLAG_CCVERSION, m_com.GetFlagByte(COMPAT_FLAG_FORCEVERSION)); Log::Write(LogLevel_Warning, GetNodeId(), "Attempt to update Command Class %s version from %d to %d. Ignored", GetCommandClassName().c_str(), m_dom.GetFlagByte(STATE_FLAG_CCVERSION), _version); } } //----------------------------------------------------------------------------- // // Refresh Values upon Wakeup Notification //----------------------------------------------------------------------------- void CommandClass::refreshValuesOnWakeup() { if (m_com.GetFlagBool(COMPAT_FLAG_REFRESHONWAKEUP)) { Log::Write(LogLevel_Debug, GetNodeId(), "Refreshing Dynamic Values on Wakeup for CommandClass %s", GetCommandClassName().c_str()); RequestStateForAllInstances(CommandClass::RequestFlag_Dynamic, Driver::MsgQueue_Send); } } //----------------------------------------------------------------------------- // // Handles Messages for Controlling CC's (Not Controlled, which is the default) //----------------------------------------------------------------------------- bool CommandClass::HandleIncomingMsg(uint8 const* _data, uint32 const _length, uint32 const _instance) { Log::Write(LogLevel_Warning, GetNodeId(), "Routing HandleIncomingMsg to HandleMsg - Please Report: %s ", GetCommandClassName().c_str()); return HandleMsg(_data, _length, _instance); } //----------------------------------------------------------------------------- // // Calls CreateVars on the CC for each instance registered with this CC //----------------------------------------------------------------------------- void CommandClass::CreateVars() { if (m_com.GetFlagBool(COMPAT_FLAG_CREATEVARS)) { for (Bitfield::Iterator it = m_instances.Begin(); it != m_instances.End(); ++it) { Log::Write(LogLevel_Info, GetNodeId(), "Creating ValueIDs for Instance %d on %s", (uint8)*it, GetCommandClassLabel().c_str()); CreateVars((uint8) *it); } } } //----------------------------------------------------------------------------- // // Create ValueID's for Specific Instances. CC's should override this. //----------------------------------------------------------------------------- void CommandClass::CreateVars(uint8 const _instance) { } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/ManufacturerProprietary.h0000644000175200017520000000512614032142455022476 00000000000000//----------------------------------------------------------------------------- // // ManufacturerProprietary.h // // Implementation of the Z-Wave COMMAND_CLASS_PROPRIETARY // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ManufacturerProprietary_H #define _ManufacturerProprietary_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_PROPRIETARY (0x91), a Z-Wave device command class. * \ingroup CommandClass */ class ManufacturerProprietary: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new ManufacturerProprietary(_homeId, _nodeId); } virtual ~ManufacturerProprietary() { } static uint8 const StaticGetCommandClassId() { return 0x91; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_MANUFACTURER_PROPRIETARY"; } // From CommandClass virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool SetValue(Internal::VC::Value const& _value) override; private: ManufacturerProprietary(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Alarm.cpp0000644000175200017520000006755214032142455017203 00000000000000//----------------------------------------------------------------------------- // // Alarm.cpp // // Implementation of the Z-Wave COMMAND_CLASS_NOTIFICATIOn (formally COMMAND_CLASS_ALARM) // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- // This CommandClass was renamed from ALARM to NOTIFICATION in version 3 // But we cannot rename the class names as we already have a Notification Class used // for signaling events to the application. #include "command_classes/CommandClasses.h" #include "command_classes/Alarm.h" #include "command_classes/NodeNaming.h" #include "command_classes/UserCode.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "NotificationCCTypes.h" #include "platform/Log.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueBool.h" #include "value_classes/ValueList.h" #include "value_classes/ValueString.h" #include "value_classes/ValueInt.h" namespace OpenZWave { namespace Internal { namespace CC { enum AlarmCmd { AlarmCmd_Get = 0x04, AlarmCmd_Report = 0x05, AlarmCmd_Set = 0x06, // Version 2 AlarmCmd_SupportedGet = 0x07, AlarmCmd_SupportedReport = 0x08, // Version 3 AlarmCmd_Event_Supported_Get = 0x01, AlarmCmd_Event_Supported_Report = 0x02 }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Alarm::Alarm(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId), m_v1Params(false), m_ClearTimeout(5000) { Timer::SetDriver(GetDriver()); m_com.EnableFlag(COMPAT_FLAG_NOT_ENABLECLEAR, true); m_com.EnableFlag(COMPAT_FLAG_NOT_V1ALARMTYPES_ENABLED, false); SetStaticRequest(StaticRequest_Values); } //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Alarm::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) { if (GetVersion() > 1) { // Request the supported alarm types Msg* msg = new Msg("AlarmCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(AlarmCmd_SupportedGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); } if (GetVersion() == 1 || m_com.GetFlagBool(COMPAT_FLAG_NOT_V1ALARMTYPES_ENABLED)) { /* create version 1 ValueID's */ if (Node* node = GetNodeUnsafe()) { m_v1Params = true; node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Alarm::Type_v1, "Alarm Type", "", true, false, 0, 0); node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Alarm::Level_v1, "Alarm Level", "", true, false, 0, 0); } } if (GetVersion() < 4 && m_com.GetFlagBool(COMPAT_FLAG_NOT_ENABLECLEAR) == true) { if (Node* node = GetNodeUnsafe()) { node->CreateValueInt(ValueID::ValueGenre_Config, GetCommandClassId(), _instance, ValueID_Index_Alarm::AutoClearEvents, "Automatically Clear Events", "ms", false, false, m_ClearTimeout, 0); } } } if (_requestFlags & RequestFlag_Dynamic) { return RequestValue(_requestFlags, 0, _instance, _queue); } return false; } bool Alarm::SetValue(Internal::VC::Value const& _value) { if ((ValueID::ValueType_Int == _value.GetID().GetType()) && (_value.GetID().GetIndex() == ValueID_Index_Alarm::AutoClearEvents)) { Internal::VC::ValueInt const *value = static_cast(&_value); m_ClearTimeout = value->GetValue(); return true; } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool Alarm::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { if (GetVersion() <= 2) { Msg* msg = new Msg("AlarmCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(AlarmCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else if (GetVersion() >= 3) { bool res = false; Msg* msg = new Msg("AlarmCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(GetVersion() == 2 ? 4 : 5); msg->Append(GetCommandClassId()); msg->Append(AlarmCmd_Get); msg->Append(0x00); /* we don't get Version 1/2 Alarm Types */ msg->Append(0xFF); if (GetVersion() > 2) msg->Append(0x00); //get first event of type. msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); res = true; return res; } } else { Log::Write(LogLevel_Info, GetNodeId(), "AlarmCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Alarm::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (AlarmCmd_Report == (AlarmCmd) _data[0]) { Log::Write(LogLevel_Info, GetNodeId(), "Got a AlarmCmd_Report Message.... "); // We have received a report from the Z-Wave device if (GetVersion() == 1) { Log::Write(LogLevel_Info, GetNodeId(), "Received Alarm report: type=%d, level=%d", _data[1], _data[2]); if (Internal::VC::ValueByte *value = static_cast(GetValue(_instance, ValueID_Index_Alarm::Type_v1))) { value->OnValueRefreshed(_data[1]); value->Release(); } // For device on version 1 the level could have different value. This level value correspond to a list of alarm type. if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_Alarm::Level_v1))) { value->OnValueRefreshed(_data[2]); value->Release(); } } /* version 2 */ else if ((GetVersion() > 1) && (_length >= 7)) { // With Version=2, the data has more detailed information about the alarm if (m_v1Params) { Log::Write(LogLevel_Info, GetNodeId(), "Received Notification report (v1): type:%d event:%d", _data[1], _data[2]); if (Internal::VC::ValueByte *value = static_cast(GetValue(_instance, ValueID_Index_Alarm::Type_v1))) { value->OnValueRefreshed(_data[1]); value->Release(); } // For device on version 1 the level could have different value. This level value correspond to a list of alarm type. if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_Alarm::Level_v1))) { value->OnValueRefreshed(_data[2]); value->Release(); } } /* ok. Its a AlarmCC/NotificationCC Version 2 or above. */ bool NotificationStatus = false; if (_data[4] == 0xFF) NotificationStatus = true; uint8 NotificationType = _data[5]; uint8 NotificationEvent = _data[6]; bool NotificationSequencePresent = (_data[7] & 0x80); uint8 EventParamLength = (_data[7] & 0x1F); uint8 NotificationSequence = 0; if (NotificationSequencePresent) { NotificationSequence = _data[7 + EventParamLength]; } Log::Write(LogLevel_Info, GetNodeId(), "Received Notification report (>v1): Type: %s (%d) Event: %s (%d) Status: %s, Param Length: %d", NotificationCCTypes::Get()->GetAlarmType(NotificationType).c_str(), NotificationType, NotificationCCTypes::Get()->GetEventForAlarmType(NotificationType, NotificationEvent).c_str(), NotificationEvent, NotificationStatus ? "true" : "false", EventParamLength); if (NotificationSequencePresent) Log::Write(LogLevel_Info, GetNodeId(), "\t Sequence Number: %d", NotificationSequence); ClearEventParams(_instance); m_ParamsSet.clear(); /* do any Event Params that are sent over */ if (EventParamLength > 0) { const std::map > nep = NotificationCCTypes::Get()->GetAlarmNotificationEventParams(NotificationType, NotificationEvent); if (nep.size() > 0) { for (std::map >::const_iterator it = nep.begin(); it != nep.end(); it++) { switch (it->second->type) { case NotificationCCTypes::NEPT_Location: { /* _data[8] should be COMMAND_CLASS_NODE_NAMING * _data[9] should be NodeNamingCmd_Report (0x03) */ if ((_data[8] == NodeNaming::StaticGetCommandClassId()) && (_data[9] == 0x03) && EventParamLength > 2) { if (Internal::VC::ValueString *value = static_cast(GetValue(_instance, it->first))) { value->OnValueRefreshed(ExtractString(&_data[10], EventParamLength - 2)); value->Release(); m_ParamsSet.push_back(it->first); } else { Log::Write(LogLevel_Warning, GetNodeId(), "Couldn't Find ValueID_Index_Alarm::Type_ParamLocation"); } } else { Log::Write(LogLevel_Warning, GetNodeId(), "Location Param didn't have correct Header, or was too small"); } break; } case NotificationCCTypes::NEPT_List: { if (EventParamLength == 1) { if (Internal::VC::ValueList *value = static_cast(GetValue(_instance, it->first))) { value->OnValueRefreshed(_data[8]); value->Release(); m_ParamsSet.push_back(it->first); } else { Log::Write(LogLevel_Warning, GetNodeId(), "Couldn't Find ValueID_Index_Alarm::Type_ParamList"); } } else { Log::Write(LogLevel_Warning, GetNodeId(), "List Param size was not equal to 1"); } break; } case NotificationCCTypes::NEPT_UserCodeReport: { /* _data[8] should be COMMAND_CLASS_USER_CODE * _data[9] should be UserCodeCmd_Report (0x03) * _data[10] is the UserID * _data[11] is the UserID Status (Ignored) * _data[12] onwards is the UserCode Entered (minimum 4 Bytes) */ if ((EventParamLength >= 8) && (_data[8] == UserCode::StaticGetCommandClassId()) && (_data[9] == 0x03)) { if (Internal::VC::ValueByte *value = static_cast(GetValue(_instance, it->first))) { value->OnValueRefreshed(_data[11]); value->Release(); m_ParamsSet.push_back(it->first); } else { Log::Write(LogLevel_Warning, GetNodeId(), "Couldn't Find ValueID_Index_Alarm::Type_ParamUserCodeid"); } if (Internal::VC::ValueString *value = static_cast(GetValue(_instance, it->first))) { value->OnValueRefreshed(ExtractString(&_data[12], EventParamLength - 4)); value->Release(); m_ParamsSet.push_back(it->first); } else { Log::Write(LogLevel_Warning, GetNodeId(), "Couldn't Find ValueID_Index_Alarm::Type_ParamUserCodeEntered"); } } else if (EventParamLength == 1) { /* some devices (Like BeNext TagReader) don't send a Proper UserCodeCmd_Report Message, Just the Index of the Code that Triggered */ if (Internal::VC::ValueByte *value = static_cast(GetValue(_instance, it->first))) { value->OnValueRefreshed(_data[8]); value->Release(); m_ParamsSet.push_back(it->first); } else { Log::Write(LogLevel_Warning, GetNodeId(), "Couldn't Find ValueID_Index_Alarm::Type_ParamUserCodeid"); } } else { Log::Write(LogLevel_Warning, GetNodeId(), "UserCode Param didn't have correct Header, or was too small"); } break; } case NotificationCCTypes::NEPT_Byte: { if (EventParamLength == 1) { if (Internal::VC::ValueByte *value = static_cast(GetValue(_instance, it->first))) { value->OnValueRefreshed(_data[8]); value->Release(); m_ParamsSet.push_back(it->first); } else { Log::Write(LogLevel_Warning, GetNodeId(), "Couldn't Find ValueID_Index_Alarm::Type_ParamByte"); } } else { Log::Write(LogLevel_Warning, GetNodeId(), "Byte Param size was not equal to 1"); } break; } case NotificationCCTypes::NEPT_String: { if (Internal::VC::ValueString *value = static_cast(GetValue(_instance, it->first))) { value->OnValueRefreshed(ExtractString(&_data[10], EventParamLength - 2)); value->Release(); m_ParamsSet.push_back(it->first); } else { Log::Write(LogLevel_Warning, GetNodeId(), "Couldn't Find ValueID_Index_Alarm::Type_ParamString"); } break; } case NotificationCCTypes::NEPT_Time: { /* This is a Duration Entry, we will expose as seconds. Its 3 Bytes from the Event */ if (EventParamLength == 3) { uint32 duration = (_data[10] * 3600) + (_data[11] * 60) + (_data[12]); if (Internal::VC::ValueInt *value = static_cast(GetValue(_instance, it->first))) { value->OnValueRefreshed(duration); value->Release(); m_ParamsSet.push_back(it->first); } else { Log::Write(LogLevel_Warning, GetNodeId(), "Couldn't Find ValueID_Index_Alarm::Type_Duration"); } } else { Log::Write(LogLevel_Warning, GetNodeId(), "Duration Param size was not equal to 3"); } break; } } } } } /* update the actual value only after we set the Params */ if (Internal::VC::ValueList *value = static_cast(GetValue(_instance, NotificationType))) { value->OnValueRefreshed(NotificationEvent); value->Release(); } else { Log::Write(LogLevel_Warning, GetNodeId(), "Couldn't Find a ValueList for Notification Type %d (%d)", NotificationType, _instance); } /* Any Version below 4 doesn't have a Clear Event, so we trigger a timer to manually clear it */ if ((NotificationEvent != 0) && (GetVersion() < 4) && (m_ClearTimeout > 0) && (m_com.GetFlagBool(COMPAT_FLAG_NOT_ENABLECLEAR) == true)) { Log::Write(LogLevel_Info, GetNodeId(), "Automatically Clearing Alarm in %dms", m_ClearTimeout); m_TimersToInstances.insert(std::pair(NotificationType, _instance)); TimerThread::TimerCallback callback = bind(&Alarm::ClearAlarm, this, NotificationType); TimerSetEvent(m_ClearTimeout, callback, 1); } } else { Log::Write(LogLevel_Warning, GetNodeId(), "Got a AlarmCmd_Report Message - Greater than Version 2, but size was less than 7?"); } return true; } if (AlarmCmd_SupportedReport == (AlarmCmd) _data[0]) { if (Node* node = GetNodeUnsafe()) { // We have received the supported alarm types from the Z-Wave device Log::Write(LogLevel_Info, GetNodeId(), "Received supported alarm types"); /* Device Only supports Version 1 of the Alarm CC */ if ((GetVersion() > 2) && (_data[1] & 0x80)) { m_v1Params = true; Log::Write(LogLevel_Info, GetNodeId(), "Notification::SupportedReport - Device Supports Alarm Version 1 Parameters"); node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Alarm::Type_v1, "Alarm Type", "", true, false, 0, 0); node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_Alarm::Level_v1, "Alarm Level", "", true, false, 0, 0); } // Parse the data for the supported alarm types uint8 numBytes = (_data[1] & 0x1F); for (uint32 i = 0; i < numBytes; ++i) { for (int32 bit = 0; bit < 8; ++bit) { if ((_data[i + 2] & (1 << bit)) != 0) { int32 index = (int32) (i << 3) + bit; Log::Write(LogLevel_Info, GetNodeId(), "\tAlarmType: %s", NotificationCCTypes::Get()->GetAlarmType(index).c_str()); if (GetVersion() == 2) { /* EventSupported is only compatible in Version 3 and above */ vector _items; if (const std::shared_ptr nt = NotificationCCTypes::Get()->GetAlarmNotificationTypes(index)) { for (std::map >::const_iterator it = nt->Events.begin(); it != nt->Events.end(); it++) { /* Create it */ SetupEvents(index, it->first, &_items, _instance); #if 0 Log::Write ( LogLevel_Info, GetNodeId(), "\t\tAll Events - Alarm CC Version 2 - %s", it->second->name); ValueList::Item item; item.m_value = it->first; item.m_label = it->second->name; _items.push_back( item ); #endif } node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), _instance, index, NotificationCCTypes::Get()->GetAlarmType(index), "", true, false, (const uint8_t) (_items.size() & 0xFF), _items, 0, 0); } ClearStaticRequest(StaticRequest_Values); } else if (GetVersion() > 2) { /* These Devices have EVENT_SUPPORTED command */ Msg* msg = new Msg("AlarmCmd_Event_Supported_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(AlarmCmd_Event_Supported_Get); msg->Append(index); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } } } } } return true; } if (AlarmCmd_Event_Supported_Report == (AlarmCmd) _data[0]) { // if( Node* node = GetNodeUnsafe() ) { uint32 type = _data[1]; // We have received the supported alarm Event types from the Z-Wave device Log::Write(LogLevel_Info, GetNodeId(), "Received supported alarm Event types for AlarmType %s (%d)", NotificationCCTypes::Get()->GetAlarmType(type).c_str(), type); // Parse the data for the supported Alarm Event types uint8 numBytes = (_data[2] & 0x1F); vector _items; /* always Add the Clear Event Type */ SetupEvents(type, 0, &_items, _instance); for (uint32 i = 0; i < numBytes; ++i) { for (int32 bit = 0; bit < 8; ++bit) { if ((_data[i + 3] & (1 << bit)) != 0) { uint32 index = (int32) (i << 3) + bit; SetupEvents(type, index, &_items, _instance); } } } if (Node* node = GetNodeUnsafe()) { node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), _instance, type, NotificationCCTypes::Get()->GetAlarmType(type), "", true, false, (uint8_t) (_items.size() & 0xFF), _items, 0, 0); } } ClearStaticRequest(StaticRequest_Values); return true; } return false; } void Alarm::SetupEvents(uint32 type, uint32 index, vector *_items, uint32 const _instance) { if (const std::shared_ptr ne = NotificationCCTypes::Get()->GetAlarmNotificationEvents(type, index)) { Log::Write(LogLevel_Info, GetNodeId(), "\tEvent Type %d: %s ", ne->id, ne->name.c_str()); Internal::VC::ValueList::Item item; item.m_value = ne->id; item.m_label = ne->name; _items->push_back(item); /* If there are Params - Lets create the correct types now */ if (Node* node = GetNodeUnsafe()) { for (std::map >::const_iterator it = ne->EventParams.begin(); it != ne->EventParams.end(); it++) { switch (it->second->type) { case NotificationCCTypes::NEPT_Location: { node->CreateValueString(ValueID::ValueGenre_User, GetCommandClassId(), _instance, it->first, it->second->name, "", true, false, "", 0); break; } case NotificationCCTypes::NEPT_List: { vector _Paramitems; for (std::map::iterator it2 = it->second->ListItems.begin(); it2 != it->second->ListItems.end(); it2++) { Internal::VC::ValueList::Item Paramitem; Paramitem.m_value = ne->id; Paramitem.m_label = ne->name; _Paramitems.push_back(Paramitem); } node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), _instance, it->first, it->second->name, "", true, false, (uint8_t) (_Paramitems.size() & 0xFF), _Paramitems, 0, 0); break; } case NotificationCCTypes::NEPT_UserCodeReport: { node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, it->first, it->second->name, "", true, false, 0, 0); node->CreateValueString(ValueID::ValueGenre_User, GetCommandClassId(), _instance, it->first + 1, it->second->name, "", true, false, "", 0); break; } case NotificationCCTypes::NEPT_Byte: { node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, it->first, it->second->name, "", true, false, 0, 0); break; } case NotificationCCTypes::NEPT_String: { node->CreateValueString(ValueID::ValueGenre_User, GetCommandClassId(), _instance, it->first, it->second->name, "", true, false, "", 0); break; } case NotificationCCTypes::NEPT_Time: { node->CreateValueInt(ValueID::ValueGenre_User, GetCommandClassId(), _instance, it->first, it->second->name, "", true, false, 0, 0); break; } } } } } else { Log::Write(LogLevel_Info, GetNodeId(), "\tEvent Type %d: Unknown", index); Internal::VC::ValueList::Item item; item.m_value = index; item.m_label = string("Unknown"); _items->push_back(item); } } void Alarm::ClearEventParams(uint32 const _instance) { /* Reset Any of the Params that may have been previously set with another event */ for (std::vector::iterator it = m_ParamsSet.begin(); it != m_ParamsSet.end(); it++) { Internal::VC::Value *value = GetValue(_instance, (*it)); switch (value->GetID().GetType()) { case ValueID::ValueType_Byte: { if (Internal::VC::ValueByte *value = static_cast(GetValue(_instance, (*it)))) { value->OnValueRefreshed(0); value->Release(); } } break; case ValueID::ValueType_String: { if (Internal::VC::ValueString *value = static_cast(GetValue(_instance, (*it)))) { value->OnValueRefreshed(""); value->Release(); } } break; case ValueID::ValueType_List: { if (Internal::VC::ValueList *value = static_cast(GetValue(_instance, (*it)))) { /* XXX TODO: Need to specify that the default is. Not all Lists have 0 index */ value->OnValueRefreshed(0); value->Release(); } } break; case ValueID::ValueType_Int: { if (Internal::VC::ValueInt *value = static_cast(GetValue(_instance, (*it)))) { value->OnValueRefreshed(0); value->Release(); } } break; default: Log::Write(LogLevel_Warning, GetNodeId(), "TODO: Clear Events for ValueType %d", value->GetID().GetType()); } } } void Alarm::ClearAlarm(uint32 type) { uint32 _instance; if (m_TimersToInstances.find(type) != m_TimersToInstances.end()) { _instance = m_TimersToInstances.at(type); m_TimersToInstances.erase(type); } else { Log::Write(LogLevel_Warning, GetNodeId(), "Cant Find Notification Type %d in m_TimersToInstances", type); return; } ClearEventParams(_instance); /* update the actual value only after we set the Params */ if (Internal::VC::ValueList *value = static_cast(GetValue(_instance, type))) { value->OnValueRefreshed(0); value->Release(); } else { Log::Write(LogLevel_Warning, GetNodeId(), "Couldn't Find a ValueList to ClearAlarm for Notification Type %d (%d)", type, _instance); } if (m_v1Params) { if (Internal::VC::ValueByte *value = static_cast(GetValue(_instance, ValueID_Index_Alarm::Type_v1))) { value->OnValueRefreshed(0); value->Release(); } if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_Alarm::Level_v1))) { value->OnValueRefreshed(0); value->Release(); } } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/ThermostatOperatingState.h0000644000175200017520000000550614032142455022607 00000000000000//----------------------------------------------------------------------------- // // ThermostatOperatingState.h // // Implementation of the Z-Wave COMMAND_CLASS_THERMOSTAT_OPERATING_STATE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ThermostatOperatingState_H #define _ThermostatOperatingState_H #include #include #include "command_classes/CommandClass.h" #include "value_classes/ValueList.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_THERMOSTAT_OPERATING_STATE (0x42), a Z-Wave device command class. * \ingroup CommandClass */ class ThermostatOperatingState: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new ThermostatOperatingState(_homeId, _nodeId); } virtual ~ThermostatOperatingState() { } static uint8 const StaticGetCommandClassId() { return 0x42; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_THERMOSTAT_OPERATING_STATE"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; protected: virtual void CreateVars(uint8 const _instance) override; private: ThermostatOperatingState(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Powerlevel.h0000644000175200017520000000636614032142455017734 00000000000000//----------------------------------------------------------------------------- // // Powerlevel.h // // Implementation of the Z-Wave COMMAND_CLASS_POWERLEVEL // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Powerlevel_H #define _Powerlevel_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_POWERLEVEL (0x73), a Z-Wave device command class. * \ingroup CommandClass */ class Powerlevel: public CommandClass { public: enum PowerLevelEnum { PowerLevel_Normal = 0, PowerLevel_Minus1dB, PowerLevel_Minus2dB, PowerLevel_Minus3dB, PowerLevel_Minus4dB, PowerLevel_Minus5dB, PowerLevel_Minus6dB, PowerLevel_Minus7dB, PowerLevel_Minus8dB, PowerLevel_Minus9dB }; enum PowerLevelStatusEnum { PowerLevelStatus_Failed = 0, PowerLevelStatus_Success, PowerLevelStatus_InProgress }; static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Powerlevel(_homeId, _nodeId); } virtual ~Powerlevel() { } static uint8 const StaticGetCommandClassId() { return 0x73; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_POWERLEVEL"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: Powerlevel(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } bool Set(uint8 const _instance); bool Test(uint8 const _instance); bool Report(uint8 const _instance); }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Color.h0000644000175200017520000000605714032142455016663 00000000000000//----------------------------------------------------------------------------- // // Color.h // // Implementation of the Z-Wave COMMAND_CLASS_COLOR // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Color_H #define _Color_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_COLOR (0x33), a Z-Wave device command class. * \ingroup CommandClass */ class Color: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Color(_homeId, _nodeId); } virtual ~Color() { } static uint8 const StaticGetCommandClassId() { return 0x33; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_COLOR"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; bool RequestColorChannelReport(uint8 const coloridx, uint8 const _instance, Driver::MsgQueue const _queue); virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; virtual uint8 GetMaxVersion() override { return 2; } virtual void SetValueBasic(uint8 const _instance, uint8 const _value) override; protected: virtual void CreateVars(uint8 const _instance) override; string decodeColor(uint8 valueArray[9]); uint8 decodeColorList(string color); private: Color(uint32 const _homeId, uint8 const _nodeId); bool m_refreshinprogress; uint8 m_coloridxcount; uint8 m_colorvalues[9]; uint8 m_colorTargetValues[9]; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/MeterPulse.h0000644000175200017520000000515614032142455017671 00000000000000//----------------------------------------------------------------------------- // // MeterPulse.h // // Implementation of the Z-Wave COMMAND_CLASS_METER_PULSE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _MeterPulse_H #define _MeterPulse_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_METER_PULSE (0x35), a Z-Wave device command class. * \ingroup CommandClass */ class MeterPulse: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new MeterPulse(_homeId, _nodeId); } virtual ~MeterPulse() { } static uint8 const StaticGetCommandClassId() { return 0x35; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_METER_PULSE"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; protected: virtual void CreateVars(uint8 const _instance) override; private: MeterPulse(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/SwitchToggleBinary.cpp0000644000175200017520000001237714032142455021712 00000000000000//----------------------------------------------------------------------------- // // SwitchToggleBinary.cpp // // Implementation of the Z-Wave COMMAND_CLASS_SWITCH_TOGGLE_BINARY // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/SwitchToggleBinary.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "Node.h" #include "platform/Log.h" #include "value_classes/ValueBool.h" namespace OpenZWave { namespace Internal { namespace CC { enum SwitchToggleBinaryCmd { SwitchToggleBinaryCmd_Set = 0x01, SwitchToggleBinaryCmd_Get = 0x02, SwitchToggleBinaryCmd_Report = 0x03 }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool SwitchToggleBinary::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Dynamic) { return RequestValue(_requestFlags, 0, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool SwitchToggleBinary::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) uint8 const _instance, Driver::MsgQueue const _queue) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("SwitchToggleBinaryCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SwitchToggleBinaryCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "SwitchToggleBinaryCmd_Get Not Supported on this node"); } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool SwitchToggleBinary::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (SwitchToggleBinaryCmd_Report == (SwitchToggleBinaryCmd) _data[0]) { Log::Write(LogLevel_Info, GetNodeId(), "Received SwitchToggleBinary report: %s", _data[1] ? "On" : "Off"); if (Internal::VC::ValueBool* value = static_cast(GetValue(_instance, ValueID_Index_SwitchToggleBinary::ToggleSwitch))) { value->OnValueRefreshed(_data[1] != 0); value->Release(); } return true; } return false; } //----------------------------------------------------------------------------- // // Toggle the state of the switch //----------------------------------------------------------------------------- bool SwitchToggleBinary::SetValue(Internal::VC::Value const& _value) { Log::Write(LogLevel_Info, GetNodeId(), "SwitchToggleBinary::Set - Toggling the state"); Msg* msg = new Msg("SwitchToggleBinaryCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _value.GetID().GetInstance()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SwitchToggleBinaryCmd_Set); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void SwitchToggleBinary::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { node->CreateValueBool(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_SwitchToggleBinary::ToggleSwitch, "Toggle Switch", "", false, false, false, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/ThermostatMode.h0000644000175200017520000000603414032142455020537 00000000000000//----------------------------------------------------------------------------- // // ThermostatMode.h // // Implementation of the Z-Wave COMMAND_CLASS_THERMOSTAT_MODE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ThermostatMode_H #define _ThermostatMode_H #include #include #include "command_classes/CommandClass.h" #include "value_classes/ValueList.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_THERMOSTAT_MODE (0x40), a Z-Wave device command class. * \ingroup CommandClass */ class ThermostatMode: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new ThermostatMode(_homeId, _nodeId); } virtual ~ThermostatMode() { } static uint8 const StaticGetCommandClassId() { return 0x40; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_THERMOSTAT_MODE"; } // From CommandClass virtual void ReadXML(TiXmlElement const* _ccElement) override; virtual void WriteXML(TiXmlElement* _ccElement) override; virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _getTypeEnum, uint8 const _dummy, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; virtual uint8 GetMaxVersion() override { return 3; } protected: virtual void CreateVars(uint8 const _instance) override; private: ThermostatMode(uint32 const _homeId, uint8 const _nodeId); vector m_supportedModes; uint32 m_currentMode; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/Indicator.h0000644000175200017520000000624014032142455017513 00000000000000//----------------------------------------------------------------------------- // // Indicator.h // // Implementation of the Z-Wave COMMAND_CLASS_INDICATOR // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Indicator_H #define _Indicator_H #include "command_classes/CommandClass.h" #include "TimerThread.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_INDICATOR (0x87), a Z-Wave device command class. * \ingroup CommandClass */ class Indicator: public CommandClass, private Timer { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new Indicator(_homeId, _nodeId); } virtual ~Indicator() { } static uint8 const StaticGetCommandClassId() { return 0x87; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_INDICATOR"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; virtual uint8 GetMaxVersion() override { return 4; } virtual void SetValueBasic(uint8 const _instance, uint8 const _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: struct Properties { uint8 id; uint8 instance; uint8 properties; string label; }; void createIndicatorConfigValues(uint8 id); void setIndicatorValue(uint8 id, uint8 _instance, uint8 property, uint8 value); void refreshIndicator(uint32 id); Indicator(uint32 const _homeId, uint8 const _nodeId); std::map > m_indicatorLists; }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/CRC16Encap.h0000644000175200017520000000453114032142455017325 00000000000000//----------------------------------------------------------------------------- // // CRC16Encap.h // // Implementation of the Z-Wave COMMAND_CLASS_CRC_16_ENCAP // // Copyright (c) 2012 Greg Satz // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _CRC16_ENCAP_H #define _CRC16_ENCAP_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_CRC_16_ENCAP (0x56), a Z-Wave device command class. * \ingroup CommandClass */ class CRC16Encap: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new CRC16Encap(_homeId, _nodeId); } virtual ~CRC16Encap() { } static uint8 const StaticGetCommandClassId() { return 0x56; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_CRC_16_ENCAP"; } // From CommandClass virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; bool supportsMultiInstance() override { return false; } private: CRC16Encap(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/EnergyProduction.h0000644000175200017520000000525314032142455021102 00000000000000//----------------------------------------------------------------------------- // // EnergyProduction.h // // Implementation of the Z-Wave COMMAND_CLASS_ENERGY_PRODUCTION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _EnergyProduction_H #define _EnergyProduction_H #include "command_classes/CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_ENERGY_PRODUCTION (0x90), a Z-Wave device command class. * \ingroup CommandClass */ class EnergyProduction: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new EnergyProduction(_homeId, _nodeId); } virtual ~EnergyProduction() { } static uint8 const StaticGetCommandClassId() { return 0x90; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_ENERGY_PRODUCTION"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _valueEnum, uint8 const _dummy, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; protected: virtual void CreateVars(uint8 const _instance) override; private: EnergyProduction(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/ThermostatFanState.h0000644000175200017520000000541214032142455021357 00000000000000//----------------------------------------------------------------------------- // // ThermostatFanState.h // // Implementation of the Z-Wave COMMAND_CLASS_THERMOSTAT_FAN_STATE // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _ThermostatFanState_H #define _ThermostatFanState_H #include #include #include "command_classes/CommandClass.h" #include "value_classes/ValueList.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_THERMOSTAT_FAN_STATE (0x45), a Z-Wave device command class. * \ingroup CommandClass */ class ThermostatFanState: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new ThermostatFanState(_homeId, _nodeId); } virtual ~ThermostatFanState() { } static uint8 const StaticGetCommandClassId() { return 0x45; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_THERMOSTAT_FAN_STATE"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; protected: virtual void CreateVars(uint8 const _instance) override; private: ThermostatFanState(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/SimpleAV.cpp0000644000175200017520000001365014032142455017615 00000000000000//----------------------------------------------------------------------------- // // SimpleAVCommandItem.h // // Implementation of the Z-Wave COMMAND_CLASS_SIMPLE_AV_CONTROL // // Copyright (c) 2018 // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/MultiInstance.h" #include "command_classes/SimpleAV.h" #include "command_classes/SimpleAVCommandItem.h" #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Driver.h" #include "platform/Log.h" #include #include "value_classes/ValueShort.h" #include "value_classes/ValueList.h" namespace OpenZWave { namespace Internal { namespace CC { uint8 m_sequence; enum SimpleAVCmd { SimpleAVCmd_Set = 0x01 }; //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool SimpleAV::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance) { return true; } //----------------------------------------------------------------------------- // // Set a value in the Z-Wave device //----------------------------------------------------------------------------- bool SimpleAV::SetValue(Internal::VC::Value const& _value) { uint16 shortval; if (ValueID::ValueType_Short == _value.GetID().GetType()) { Internal::VC::ValueShort const* value = static_cast(&_value); shortval = value->GetValue(); } else if (ValueID::ValueType_List == _value.GetID().GetType()) { Internal::VC::ValueList const* value = static_cast(&_value); shortval = value->GetItem()->m_value; } else return false; uint8 instance = _value.GetID().GetInstance(); Msg* msg = new Msg("SimpleAVCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, instance); msg->Append(GetNodeId()); msg->Append(8); // Length msg->Append(GetCommandClassId()); msg->Append(SimpleAVCmd_Set); msg->Append(m_sequence++); // Crutch msg->Append(0); msg->Append(0); msg->Append(0); msg->Append(shortval >> 8); msg->Append(shortval & 0xff); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); if (m_sequence == 255) m_sequence = 0; return true; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void SimpleAV::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { // Create list value vector items; vector commands = SimpleAVCommandItem::GetCommands(); vector::iterator iterator; string helpList = "Possible values: \n"; string helpNumeric = "Possible values: \n"; for (iterator = commands.begin(); iterator != commands.end(); iterator++) { SimpleAVCommandItem command = *iterator; if (command.GetVersion() <= GetVersion()) { Internal::VC::ValueList::Item item; item.m_value = command.GetCode(); item.m_label = command.GetName(); items.push_back(item); #if 0 // ValueList - create command description for help string codeStr = string("ZWave command number: ").append(std::to_string(command.GetCode())); string descriptionFull = ""; if (command.GetDescription() == "") { descriptionFull = command .GetName() .append(" (") .append(codeStr) .append(")\n"); } else { descriptionFull = command .GetName() .append(" (") .append(command.GetDescription()) .append("; ") .append(codeStr) .append(")\n"); } helpList += descriptionFull; // ValueShort - create command description for help if (command.GetDescription() == "") { descriptionFull = std::to_string(command.GetCode()) .append(" (") .append(command.GetName()) .append(")\n"); } else { descriptionFull = std::to_string(command.GetCode()) .append(" (") .append(command.GetName()) .append("; ") .append(command.GetDescription()) .append(")\n"); } helpNumeric += descriptionFull; #endif } } node->CreateValueList(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_SimpleAV::Command, string("OutputAVCommand_").append(std::to_string(_instance)), "", false, true, 2, items, 0, 0); // Create a similar numeric value // node->CreateValueShort(ValueID::ValueGenre_User, GetCommandClassId(), _instance, 0, string("OutputAVCommandNumber_").append(std::to_string(_instance)), "", false, true, 0, 0, helpNumeric); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/SimpleAVCommandItem.h0000644000175200017520000000323114032142455021372 00000000000000//----------------------------------------------------------------------------- // // SimpleAVCommandItem.h // // Implementation of the Z-Wave COMMAND_CLASS_SIMPLE_AV_CONTROL // // Copyright (c) 2018 // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _SimpleAVCommandItem_H #define _SimpleAVCommandItem_H #include #include #include "Defs.h" namespace OpenZWave { namespace Internal { namespace CC { class SimpleAVCommandItem { public: SimpleAVCommandItem(uint16 const _code, string _name, string _description, uint16 const _version); uint16 GetCode(); string GetName(); string GetDescription(); uint16 GetVersion(); static vector GetCommands(); private: uint16 m_code; string m_name; string m_description; uint16 m_version; }; } // namespace CC } // namespace Internal } // namespace CC #endif openzwave-1.6.1914/cpp/src/command_classes/DoorLock.h0000644000175200017520000000525714032142455017322 00000000000000//----------------------------------------------------------------------------- // // DoorLock.h // // Implementation of the Z-Wave COMMAND_CLASS_DOOR_LOCK // // Copyright (c) 2014 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _DoorLock_H #define _DoorLock_H #include "CommandClass.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_DOOR_LOCK (0x62), a Z-Wave device command class. * \ingroup CommandClass */ class DoorLock: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new DoorLock(_homeId, _nodeId); } virtual ~DoorLock() { } static uint8 const StaticGetCommandClassId() { return 0x62; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_DOOR_LOCK"; } // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; virtual bool SetValue(Internal::VC::Value const& _value) override; virtual void SetValueBasic(uint8 const _instance, uint8 const _value) override; protected: virtual void CreateVars(uint8 const _instance) override; private: DoorLock(uint32 const _homeId, uint8 const _nodeId); }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/AssociationCommandConfiguration.h0000644000175200017520000000624614032142455024110 00000000000000//----------------------------------------------------------------------------- // // AssociationCommandConfiguration.h // // Implementation of the COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _AssociationCommandConfiguration_H #define _AssociationCommandConfiguration_H #include "command_classes/CommandClass.h" #include "value_classes/ValueBool.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueShort.h" namespace OpenZWave { namespace Internal { namespace CC { /** \brief Implements COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION (0x9b), a Z-Wave device command class. * \ingroup CommandClass */ class AssociationCommandConfiguration: public CommandClass { public: static CommandClass* Create(uint32 const _homeId, uint8 const _nodeId) { return new AssociationCommandConfiguration(_homeId, _nodeId); } virtual ~AssociationCommandConfiguration() { } static uint8 const StaticGetCommandClassId() { return 0x9b; } static string const StaticGetCommandClassName() { return "COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION"; } void RequestCommands(uint8 const _groupIdx, uint8 const _nodeId); void SetCommand(uint8 const _groupIdx, uint8 const _nodeId, uint8 const _length, uint8 const* _data); // From CommandClass virtual bool RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual bool RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) override; virtual uint8 const GetCommandClassId() const override { return StaticGetCommandClassId(); } virtual string const GetCommandClassName() const override { return StaticGetCommandClassName(); } virtual bool HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance = 1) override; bool supportsMultiInstance() override { return false; } protected: virtual void CreateVars(uint8 const _instance) override; private: AssociationCommandConfiguration(uint32 const _homeId, uint8 const _nodeId) : CommandClass(_homeId, _nodeId) { } }; } // namespace CC } // namespace Internal } // namespace OpenZWave #endif openzwave-1.6.1914/cpp/src/command_classes/SwitchMultilevel.cpp0000644000175200017520000005316014032142455021441 00000000000000//----------------------------------------------------------------------------- // // SwitchMultilevel.cpp // // Implementation of the Z-Wave COMMAND_CLASS_SWITCH_MULTILEVEL // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "command_classes/CommandClasses.h" #include "command_classes/SwitchMultilevel.h" #include "command_classes/WakeUp.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "Node.h" #include "platform/Log.h" #include "value_classes/ValueBool.h" #include "value_classes/ValueButton.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueInt.h" namespace OpenZWave { namespace Internal { namespace CC { enum SwitchMultilevelCmd { SwitchMultilevelCmd_Set = 0x01, SwitchMultilevelCmd_Get = 0x02, SwitchMultilevelCmd_Report = 0x03, SwitchMultilevelCmd_StartLevelChange = 0x04, SwitchMultilevelCmd_StopLevelChange = 0x05, SwitchMultilevelCmd_SupportedGet = 0x06, SwitchMultilevelCmd_SupportedReport = 0x07 }; static uint8 c_directionParams[] = { 0x00, 0x40, 0x00, 0x40 }; static char const* c_directionDebugLabels[] = { "Up", "Down", "Inc", "Dec" }; static char const* c_switchLabelsPos[] = { "Undefined", "On", "Up", "Open", "Clockwise", "Right", "Forward", "Push" }; static char const* c_switchLabelsNeg[] = { "Undefined", "Off", "Down", "Close", "Counter-Clockwise", "Left", "Reverse", "Pull" }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool SwitchMultilevel::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Static) { if (GetVersion() >= 3) { // Request the supported switch types Msg* msg = new Msg("SwitchMultilevelCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SwitchMultilevelCmd_SupportedGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); } return true; } if (_requestFlags & RequestFlag_Dynamic) { return RequestValue(_requestFlags, ValueID_Index_SwitchMultiLevel::Level, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool SwitchMultilevel::RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) { if (_index == ValueID_Index_SwitchMultiLevel::Level) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("SwitchMultilevelCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SwitchMultilevelCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "SwitchMultilevelCmd_Get Not Supported on this node"); } } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool SwitchMultilevel::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (SwitchMultilevelCmd_Report == (SwitchMultilevelCmd) _data[0]) { Log::Write(LogLevel_Info, GetNodeId(), "Received SwitchMultiLevel report: level=%d", _data[1]); if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_SwitchMultiLevel::Level))) { /* Target Value - 0 to 100 is valid values, 0xFF is also valid */ if ((GetVersion() >= 4) && ((_data[2] <= 100) || (_data[2] == 0xFF))) value->SetTargetValue(_data[2], _data[3]); value->OnValueRefreshed(_data[1]); value->Release(); } if (GetVersion() >= 4) { // data[2] => target value if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_SwitchMultiLevel::TargetValue))) { value->OnValueRefreshed(_data[2]); value->Release(); } // data[3] might be duration if (_length > 3) { if (Internal::VC::ValueInt* value = static_cast(GetValue(_instance, ValueID_Index_SwitchMultiLevel::Duration))) { value->OnValueRefreshed(decodeDuration(_data[3])); value->Release(); } } } return true; } if (SwitchMultilevelCmd_SupportedReport == (SwitchMultilevelCmd) _data[0]) { uint8 switchType1 = _data[1] & 0x1f; uint8 switchType2 = _data[2] & 0x1f; uint8 switchtype1label = switchType1; uint8 switchtype2label = switchType2; if (switchtype1label > 7) /* size of c_switchLabelsPos, c_switchLabelsNeg */ { Log::Write(LogLevel_Warning, GetNodeId(), "switchtype1label Value was greater than range. Setting to Invalid"); switchtype1label = 0; } if (switchtype2label > 7) /* sizeof c_switchLabelsPos, c_switchLabelsNeg */ { Log::Write(LogLevel_Warning, GetNodeId(), "switchtype2label Value was greater than range. Setting to Invalid"); switchtype2label = 0; } Log::Write(LogLevel_Info, GetNodeId(), "Received SwitchMultiLevel supported report: Switch1=%s/%s, Switch2=%s/%s", c_switchLabelsPos[switchtype1label], c_switchLabelsNeg[switchtype1label], c_switchLabelsPos[switchtype2label], c_switchLabelsNeg[switchtype2label]); ClearStaticRequest(StaticRequest_Version); // Set the labels on the values Internal::VC::ValueButton* button; if (switchType1) { if ( NULL != (button = static_cast(GetValue(_instance, ValueID_Index_SwitchMultiLevel::Bright)))) { button->SetLabel(c_switchLabelsPos[switchtype1label]); button->Release(); } if ( NULL != (button = static_cast(GetValue(_instance, ValueID_Index_SwitchMultiLevel::Dim)))) { button->SetLabel(c_switchLabelsNeg[switchtype1label]); button->Release(); } } if (switchType2) { if ( NULL != (button = static_cast(GetValue(_instance, ValueID_Index_SwitchMultiLevel::Inc)))) { button->SetLabel(c_switchLabelsPos[switchtype2label]); button->Release(); } if ( NULL != (button = static_cast(GetValue(_instance, ValueID_Index_SwitchMultiLevel::Dec)))) { button->SetLabel(c_switchLabelsNeg[switchtype2label]); button->Release(); } } return true; } Log::Write(LogLevel_Warning, GetNodeId(), "Recieved a Unhandled SwitchMultiLevel Command: %d", _data[0]); return false; } //----------------------------------------------------------------------------- // // Set the level on a device //----------------------------------------------------------------------------- bool SwitchMultilevel::SetValue(Internal::VC::Value const& _value) { bool res = false; uint8 instance = _value.GetID().GetInstance(); switch (_value.GetID().GetIndex()) { case ValueID_Index_SwitchMultiLevel::Level: { // Level if (Internal::VC::ValueByte* value = static_cast(GetValue(instance, ValueID_Index_SwitchMultiLevel::Level))) { res = SetLevel(instance, (static_cast(&_value))->GetValue()); value->Release(); } break; } case ValueID_Index_SwitchMultiLevel::Bright: { // Bright if (Internal::VC::ValueButton* button = static_cast(GetValue(instance, ValueID_Index_SwitchMultiLevel::Bright))) { if (button->IsPressed()) { res = StartLevelChange(instance, SwitchMultilevelDirection_Up); } else { res = StopLevelChange(instance); } button->Release(); } break; } case ValueID_Index_SwitchMultiLevel::Dim: { // Dim if (Internal::VC::ValueButton* button = static_cast(GetValue(instance, ValueID_Index_SwitchMultiLevel::Dim))) { if (button->IsPressed()) { res = StartLevelChange(instance, SwitchMultilevelDirection_Down); } else { res = StopLevelChange(instance); } button->Release(); } break; } case ValueID_Index_SwitchMultiLevel::IgnoreStartLevel: { if (Internal::VC::ValueBool* value = static_cast(GetValue(instance, ValueID_Index_SwitchMultiLevel::IgnoreStartLevel))) { value->OnValueRefreshed((static_cast(&_value))->GetValue()); value->Release(); } res = true; break; } case ValueID_Index_SwitchMultiLevel::StartLevel: { if (Internal::VC::ValueByte* value = static_cast(GetValue(instance, ValueID_Index_SwitchMultiLevel::StartLevel))) { value->OnValueRefreshed((static_cast(&_value))->GetValue()); value->Release(); } res = true; break; } case ValueID_Index_SwitchMultiLevel::Duration: { if (Internal::VC::ValueInt* value = static_cast(GetValue(instance, ValueID_Index_SwitchMultiLevel::Duration))) { value->OnValueRefreshed((static_cast(&_value))->GetValue()); value->Release(); } res = true; break; } case ValueID_Index_SwitchMultiLevel::Step: { if (Internal::VC::ValueByte* value = static_cast(GetValue(instance, ValueID_Index_SwitchMultiLevel::Step))) { value->OnValueRefreshed((static_cast(&_value))->GetValue()); value->Release(); } res = true; break; } case ValueID_Index_SwitchMultiLevel::Inc: { // Inc if (Internal::VC::ValueButton* button = static_cast(GetValue(instance, ValueID_Index_SwitchMultiLevel::Inc))) { if (button->IsPressed()) { res = StartLevelChange(instance, SwitchMultilevelDirection_Inc); } else { res = StopLevelChange(instance); } button->Release(); } break; } case ValueID_Index_SwitchMultiLevel::Dec: { // Dec if (Internal::VC::ValueButton* button = static_cast(GetValue(instance, ValueID_Index_SwitchMultiLevel::Dec))) { if (button->IsPressed()) { res = StartLevelChange(instance, SwitchMultilevelDirection_Dec); } else { res = StopLevelChange(instance); } button->Release(); } break; } } return res; } //----------------------------------------------------------------------------- // // Update class values based in BASIC mapping //----------------------------------------------------------------------------- void SwitchMultilevel::SetValueBasic(uint8 const _instance, uint8 const _value) { // Send a request for new value to synchronize it with the BASIC set/report. // In case the device is sleeping, we set the value anyway so the BASIC set/report // stays in sync with it. We must be careful mapping the uint8 BASIC value // into a class specific value. // When the device wakes up, the real requested value will be retrieved. RequestValue(0, 0, _instance, Driver::MsgQueue_Send); if (Node* node = GetNodeUnsafe()) { if (Internal::CC::WakeUp* wakeUp = static_cast(node->GetCommandClass(Internal::CC::WakeUp::StaticGetCommandClassId()))) { if (!wakeUp->IsAwake()) { if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_SwitchMultiLevel::Level))) { value->OnValueRefreshed(_value != 0); value->Release(); } } } } } //----------------------------------------------------------------------------- // // Set a new level for the switch //----------------------------------------------------------------------------- bool SwitchMultilevel::SetLevel(uint8 const _instance, uint8 const _level) { Log::Write(LogLevel_Info, GetNodeId(), "SwitchMultilevel::Set - Setting to level %d", _level); Msg* msg = new Msg("SwitchMultilevelCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); if (GetVersion() >= 2) { Internal::VC::ValueInt* durationValue = static_cast(GetValue(_instance, ValueID_Index_SwitchMultiLevel::Duration)); uint32 duration = durationValue->GetValue(); durationValue->Release(); if (duration > 7620) Log::Write(LogLevel_Info, GetNodeId(), " Duration: Device Default"); else if (duration > 0x7F) Log::Write(LogLevel_Info, GetNodeId(), " Rouding to %d Minutes (over 127 seconds)", encodeDuration(duration)-0x79); else Log::Write(LogLevel_Info, GetNodeId(), " Duration: %d seconds", duration); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(SwitchMultilevelCmd_Set); msg->Append(_level); msg->Append(encodeDuration(duration)); } else { msg->Append(3); msg->Append(GetCommandClassId()); msg->Append(SwitchMultilevelCmd_Set); msg->Append(_level); } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } //----------------------------------------------------------------------------- // // Start the level changing //----------------------------------------------------------------------------- bool SwitchMultilevel::StartLevelChange(uint8 const _instance, SwitchMultilevelDirection const _direction) { Log::Write(LogLevel_Info, GetNodeId(), "SwitchMultilevel::StartLevelChange - Starting a level change"); uint8 length = 4; if (_direction > 3) /* size of c_directionParams, c_directionDebugLabels */ { Log::Write(LogLevel_Warning, GetNodeId(), "_direction Value was greater than range. Dropping"); return false; } uint8 direction = c_directionParams[_direction]; Log::Write(LogLevel_Info, GetNodeId(), " Direction: %s", c_directionDebugLabels[_direction]); if (Internal::VC::ValueBool* ignoreStartLevel = static_cast(GetValue(_instance, ValueID_Index_SwitchMultiLevel::IgnoreStartLevel))) { if (ignoreStartLevel->GetValue()) { // Set the ignore start level flag direction |= 0x20; } ignoreStartLevel->Release(); } Log::Write(LogLevel_Info, GetNodeId(), " Ignore Start Level: %s", (direction & 0x20) ? "True" : "False"); uint8 startLevel = 0; if (Internal::VC::ValueByte* startLevelValue = static_cast(GetValue(_instance, ValueID_Index_SwitchMultiLevel::StartLevel))) { startLevel = startLevelValue->GetValue(); startLevelValue->Release(); } Log::Write(LogLevel_Info, GetNodeId(), " Start Level: %d", startLevel); uint32 duration = -1; if (Internal::VC::ValueInt* durationValue = static_cast(GetValue(_instance, ValueID_Index_SwitchMultiLevel::Duration))) { length = 5; duration = durationValue->GetValue(); durationValue->Release(); Log::Write(LogLevel_Info, GetNodeId(), " Duration: %d", duration); } uint8 step = 0; if ((SwitchMultilevelDirection_Inc == _direction) || (SwitchMultilevelDirection_Dec == _direction)) { if (Internal::VC::ValueByte* stepValue = static_cast(GetValue(_instance, ValueID_Index_SwitchMultiLevel::Step))) { length = 6; step = stepValue->GetValue(); stepValue->Release(); Log::Write(LogLevel_Info, GetNodeId(), " Step Size: %d", step); } } Msg* msg = new Msg("SwitchMultilevelCmd_StartLevelChange", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(length); msg->Append(GetCommandClassId()); msg->Append(SwitchMultilevelCmd_StartLevelChange); if (GetVersion() == 2) { direction &= 0x60; } else if (GetVersion() >= 3) { /* we don't support secondary switch, so we mask that out as well */ direction &= 0xE0; } msg->Append(direction); msg->Append(startLevel); if (length >= 5) { msg->Append(encodeDuration(duration)); } if (length == 6) { msg->Append(step); } msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); /* get a updated Level Value from the Device */ RequestValue(0, ValueID_Index_SwitchMultiLevel::Level, _instance, Driver::MsgQueue_Send); return true; } //----------------------------------------------------------------------------- // // Stop the level changing //----------------------------------------------------------------------------- bool SwitchMultilevel::StopLevelChange(uint8 const _instance) { Log::Write(LogLevel_Info, GetNodeId(), "SwitchMultilevel::StopLevelChange - Stopping the level change"); Msg* msg = new Msg("SwitchMultilevelCmd_StopLevelChange", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(SwitchMultilevelCmd_StopLevelChange); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); /* get a updated Level Value from the Device */ RequestValue(0, ValueID_Index_SwitchMultiLevel::Level, _instance, Driver::MsgQueue_Send); return true; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void SwitchMultilevel::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { if (GetVersion() >= 4) { node->CreateValueByte(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_SwitchMultiLevel::TargetValue, "Target Value", "", true, false, 0, 0); } if (GetVersion() >= 3) { node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_SwitchMultiLevel::Step, "Step Size", "", false, false, 0, 0); node->CreateValueButton(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_SwitchMultiLevel::Inc, "Inc", 0); node->CreateValueButton(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_SwitchMultiLevel::Dec, "Dec", 0); } if (GetVersion() >= 2) { node->CreateValueInt(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_SwitchMultiLevel::Duration, "Dimming Duration", "", false, false, -1, 0); } node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_SwitchMultiLevel::Level, "Level", "", false, false, 0, 0); node->CreateValueButton(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_SwitchMultiLevel::Bright, "Bright", 0); node->CreateValueButton(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_SwitchMultiLevel::Dim, "Dim", 0); node->CreateValueBool(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_SwitchMultiLevel::IgnoreStartLevel, "Ignore Start Level", "", false, false, true, 0); node->CreateValueByte(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_SwitchMultiLevel::StartLevel, "Start Level", "", false, false, 0, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/command_classes/Powerlevel.cpp0000644000175200017520000004131214032142455020255 00000000000000//----------------------------------------------------------------------------- // // Powerlevel.cpp // // Implementation of the Z-Wave COMMAND_CLASS_POWERLEVEL // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "command_classes/CommandClasses.h" #include "command_classes/Powerlevel.h" #include "Defs.h" #include "Msg.h" #include "Driver.h" #include "platform/Log.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueShort.h" #include "value_classes/ValueList.h" #include "value_classes/ValueButton.h" namespace OpenZWave { namespace Internal { namespace CC { enum PowerlevelCmd { PowerlevelCmd_Set = 0x01, PowerlevelCmd_Get = 0x02, PowerlevelCmd_Report = 0x03, PowerlevelCmd_TestNodeSet = 0x04, PowerlevelCmd_TestNodeGet = 0x05, PowerlevelCmd_TestNodeReport = 0x06 }; static char const* c_powerLevelNames[] = { "Normal", "-1dB", "-2dB", "-3dB", "-4dB", "-5dB", "-6dB", "-7dB", "-8dB", "-9dB", "Unknown" }; static char const* c_powerLevelStatusNames[] = { "Failed", "Success", "In Progress", "Unknown" }; //----------------------------------------------------------------------------- // // Request current state from the device //----------------------------------------------------------------------------- bool Powerlevel::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) { if (_requestFlags & RequestFlag_Session) { return RequestValue(_requestFlags, ValueID_Index_PowerLevel::Powerlevel, _instance, _queue); } return false; } //----------------------------------------------------------------------------- // // Request current value from the device //----------------------------------------------------------------------------- bool Powerlevel::RequestValue(uint32 const _requestFlags, uint16 const _index, uint8 const _instance, Driver::MsgQueue const _queue) { if (_index == 0) { if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) { Msg* msg = new Msg("PowerlevelCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(2); msg->Append(GetCommandClassId()); msg->Append(PowerlevelCmd_Get); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, _queue); return true; } else { Log::Write(LogLevel_Info, GetNodeId(), "Powerlevel_Get Not Supported on this node"); } } return false; } //----------------------------------------------------------------------------- // // Handle a message from the Z-Wave network //----------------------------------------------------------------------------- bool Powerlevel::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 ) { if (PowerlevelCmd_Report == (PowerlevelCmd) _data[0]) { PowerLevelEnum powerLevel = (PowerLevelEnum) _data[1]; if (powerLevel > 9) /* size of c_powerLevelNames minus Unknown*/ { Log::Write(LogLevel_Warning, GetNodeId(), "powerLevel Value was greater than range. Setting to Invalid"); powerLevel = (PowerLevelEnum) 10; } uint8 timeout = _data[2]; Log::Write(LogLevel_Info, GetNodeId(), "Received a PowerLevel report: PowerLevel=%s, Timeout=%d", c_powerLevelNames[powerLevel], timeout); if (Internal::VC::ValueList* value = static_cast(GetValue(_instance, ValueID_Index_PowerLevel::Powerlevel))) { value->OnValueRefreshed((int) powerLevel); value->Release(); } if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_PowerLevel::Timeout))) { value->OnValueRefreshed(timeout); value->Release(); } return true; } if (PowerlevelCmd_TestNodeReport == (PowerlevelCmd) _data[0]) { uint8 testNode = _data[1]; PowerLevelStatusEnum status = (PowerLevelStatusEnum) _data[2]; uint16 ackCount = (((uint16) _data[3]) << 8) | (uint16) _data[4]; if (status > 2) /* size of c_powerLevelStatusNames minus Unknown */ { Log::Write(LogLevel_Warning, GetNodeId(), "status Value was greater than range. Setting to Unknown"); status = (PowerLevelStatusEnum) 3; } Log::Write(LogLevel_Info, GetNodeId(), "Received a PowerLevel Test Node report: Test Node=%d, Status=%s, Test Frame ACK Count=%d", testNode, c_powerLevelStatusNames[status], ackCount); if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_PowerLevel::TestNode))) { value->OnValueRefreshed(testNode); value->Release(); } if (Internal::VC::ValueList* value = static_cast(GetValue(_instance, ValueID_Index_PowerLevel::TestStatus))) { value->OnValueRefreshed((int) status); value->Release(); } if (Internal::VC::ValueShort* value = static_cast(GetValue(_instance, ValueID_Index_PowerLevel::TestAckFrames))) { value->OnValueRefreshed((short) ackCount); value->Release(); } return true; } return false; } //----------------------------------------------------------------------------- // // Set a value on the Z-Wave device //----------------------------------------------------------------------------- bool Powerlevel::SetValue(Internal::VC::Value const& _value) { bool res = false; uint8 instance = _value.GetID().GetInstance(); switch (_value.GetID().GetIndex()) { case ValueID_Index_PowerLevel::Powerlevel: { if (Internal::VC::ValueList* value = static_cast(GetValue(instance, ValueID_Index_PowerLevel::Powerlevel))) { Internal::VC::ValueList::Item const *item = (static_cast(&_value))->GetItem(); if (item != NULL) value->OnValueRefreshed(item->m_value); value->Release(); } res = true; break; } case ValueID_Index_PowerLevel::Timeout: { if (Internal::VC::ValueByte* value = static_cast(GetValue(instance, ValueID_Index_PowerLevel::Timeout))) { value->OnValueRefreshed((static_cast(&_value))->GetValue()); value->Release(); } res = true; break; } case ValueID_Index_PowerLevel::Set: { // Set if (Internal::VC::ValueButton* button = static_cast(GetValue(instance, ValueID_Index_PowerLevel::Set))) { if (button->IsPressed()) { res = Set(instance); } button->Release(); } break; } case ValueID_Index_PowerLevel::TestNode: { if (Internal::VC::ValueByte* value = static_cast(GetValue(instance, ValueID_Index_PowerLevel::TestNode))) { value->OnValueRefreshed((static_cast(&_value))->GetValue()); value->Release(); } res = true; break; } case ValueID_Index_PowerLevel::TestPowerlevel: { if (Internal::VC::ValueList* value = static_cast(GetValue(instance, ValueID_Index_PowerLevel::TestPowerlevel))) { Internal::VC::ValueList::Item const *item = (static_cast(&_value))->GetItem(); if (item != NULL) value->OnValueRefreshed(item->m_value); value->Release(); } res = true; break; } case ValueID_Index_PowerLevel::TestFrames: { if (Internal::VC::ValueShort* value = static_cast(GetValue(instance, ValueID_Index_PowerLevel::TestFrames))) { value->OnValueRefreshed((static_cast(&_value))->GetValue()); value->Release(); } res = true; break; } case ValueID_Index_PowerLevel::Test: { // Test if (Internal::VC::ValueButton* button = static_cast(GetValue(instance, ValueID_Index_PowerLevel::Test))) { if (button->IsPressed()) { res = Test(instance); } button->Release(); } break; } case ValueID_Index_PowerLevel::Report: { // Test if (Internal::VC::ValueButton* button = static_cast(GetValue(instance, ValueID_Index_PowerLevel::Report))) { if (button->IsPressed()) { res = Report(instance); } button->Release(); } break; } } return res; } //----------------------------------------------------------------------------- // // Set the transmit power of a node for a specified time //----------------------------------------------------------------------------- bool Powerlevel::Set(uint8 const _instance) { PowerLevelEnum powerLevel = PowerLevel_Normal; uint8 timeout; if (Internal::VC::ValueList* value = static_cast(GetValue(_instance, ValueID_Index_PowerLevel::Powerlevel))) { Internal::VC::ValueList::Item const *item = value->GetItem(); if (item != NULL) powerLevel = (PowerLevelEnum) item->m_value; value->Release(); } else { return false; } if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_PowerLevel::Timeout))) { timeout = value->GetValue(); value->Release(); } else { return false; } if (powerLevel > 9) /* size of c_powerLevelNames minus Unknown */ { Log::Write(LogLevel_Warning, GetNodeId(), "powerLevel Value was greater than range. Dropping"); /* Drop it */ return false; } Log::Write(LogLevel_Info, GetNodeId(), "Setting the power level to %s for %d seconds", c_powerLevelNames[powerLevel], timeout); Msg* msg = new Msg("PowerlevelCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(4); msg->Append(GetCommandClassId()); msg->Append(PowerlevelCmd_Set); msg->Append((uint8) powerLevel); msg->Append(timeout); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } //----------------------------------------------------------------------------- // // Test node to node communications //----------------------------------------------------------------------------- bool Powerlevel::Test(uint8 const _instance) { uint8 testNodeId; PowerLevelEnum powerLevel = PowerLevel_Normal; uint16 numFrames; if (Internal::VC::ValueByte* value = static_cast(GetValue(_instance, ValueID_Index_PowerLevel::TestNode))) { testNodeId = value->GetValue(); value->Release(); } else { return false; } if (Internal::VC::ValueList* value = static_cast(GetValue(_instance, ValueID_Index_PowerLevel::TestPowerlevel))) { Internal::VC::ValueList::Item const *item = value->GetItem(); if (item != NULL) powerLevel = (PowerLevelEnum) item->m_value; value->Release(); } else { return false; } if (Internal::VC::ValueShort* value = static_cast(GetValue(_instance, ValueID_Index_PowerLevel::TestFrames))) { numFrames = value->GetValue(); value->Release(); } else { return false; } if (powerLevel > 9) /* size of c_powerLevelNames minus Unknown */ { Log::Write(LogLevel_Warning, GetNodeId(), "powerLevel Value was greater than range. Dropping"); return false; } Log::Write(LogLevel_Info, GetNodeId(), "Running a Power Level Test: Target Node = %d, Power Level = %s, Number of Frames = %d", testNodeId, c_powerLevelNames[powerLevel], numFrames); Msg* msg = new Msg("PowerlevelCmd_TestNodeSet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(6); msg->Append(GetCommandClassId()); msg->Append(PowerlevelCmd_TestNodeSet); msg->Append(testNodeId); msg->Append((uint8) powerLevel); msg->Append((uint8) (numFrames >> 8)); msg->Append((uint8) (numFrames & 0x00ff)); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } //----------------------------------------------------------------------------- // // Request test report //----------------------------------------------------------------------------- bool Powerlevel::Report(uint8 const _instance) { Log::Write(LogLevel_Info, GetNodeId(), "Power Level Report"); Msg* msg = new Msg("PowerlevelCmd_TestNodeGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); msg->SetInstance(this, _instance); msg->Append(GetNodeId()); msg->Append(6); msg->Append(GetCommandClassId()); msg->Append(PowerlevelCmd_TestNodeGet); msg->Append(GetDriver()->GetTransmitOptions()); GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); return true; } //----------------------------------------------------------------------------- // // Create the values managed by this command class //----------------------------------------------------------------------------- void Powerlevel::CreateVars(uint8 const _instance) { if (Node* node = GetNodeUnsafe()) { vector items; Internal::VC::ValueList::Item item; for (uint8 i = 0; i < 10; ++i) { item.m_label = c_powerLevelNames[i]; item.m_value = i; items.push_back(item); } node->CreateValueList(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_PowerLevel::Powerlevel, "Powerlevel", "dB", false, false, 1, items, 0, 0); node->CreateValueByte(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_PowerLevel::Timeout, "Timeout", "seconds", false, false, 0, 0); node->CreateValueButton(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_PowerLevel::Set, "Set Powerlevel", 0); node->CreateValueByte(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_PowerLevel::TestNode, "Test Node", "", false, false, 0, 0); node->CreateValueList(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_PowerLevel::TestPowerlevel, "Test Powerlevel", "dB", false, false, 1, items, 0, 0); node->CreateValueShort(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_PowerLevel::TestFrames, "Frame Count", "", false, false, 0, 0); node->CreateValueButton(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_PowerLevel::Test, "Test", 0); node->CreateValueButton(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_PowerLevel::Report, "Report", 0); items.clear(); for (uint8 i = 0; i < 3; ++i) { item.m_label = c_powerLevelStatusNames[i]; item.m_value = i; items.push_back(item); } node->CreateValueList(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_PowerLevel::TestStatus, "Test Status", "", true, false, 1, items, 0, 0); node->CreateValueShort(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_PowerLevel::TestAckFrames, "Acked Frames", "", true, false, 0, 0); } } } // namespace CC } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/NotificationCCTypes.cpp0000755000175200017520000003555114032142455016672 00000000000000//----------------------------------------------------------------------------- // // NotificationCCTypes.cpp // // NotificationCCTypes for Notification Command Class // // Copyright (c) 2018 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "NotificationCCTypes.h" #include #include "tinyxml.h" #include "Options.h" #include "Utils.h" #include "platform/Log.h" namespace OpenZWave { namespace Internal { NotificationCCTypes *NotificationCCTypes::m_instance = NULL; std::map > NotificationCCTypes::Notifications; uint32 NotificationCCTypes::m_revision(0); NotificationCCTypes::NotificationCCTypes() { } bool NotificationCCTypes::ReadXML() { // Parse the Z-Wave manufacturer and product XML file. string configPath; Options::Get()->GetOptionAsString("ConfigPath", &configPath); string path = configPath + "NotificationCCTypes.xml"; TiXmlDocument* pDoc = new TiXmlDocument(); if (!pDoc->LoadFile(path.c_str(), TIXML_ENCODING_UTF8)) { delete pDoc; Log::Write(LogLevel_Warning, "Unable to load NotificationCCTypes file %s", path.c_str()); return false; } pDoc->SetUserData((void*) path.c_str()); Log::Write(LogLevel_Info, "Loading NotificationCCTypes File %s", path.c_str()); TiXmlElement const* root = pDoc->RootElement(); char const *str = root->Value(); if (str && !strcmp(str, "NotificationTypes")) { // Read in the revision attributes str = root->Attribute("Revision"); if (!str) { Log::Write(LogLevel_Info, "Error in Product Config file at line %d - missing Revision attribute", root->Row()); delete pDoc; return false; } m_revision = atol(str); } TiXmlElement const* AlarmTypeElement = root->FirstChildElement(); while (AlarmTypeElement) { char const* str = AlarmTypeElement->Value(); char* pStopChar; if (str && !strcmp(str, "AlarmType")) { NotificationTypes *nt = new NotificationTypes; str = AlarmTypeElement->Attribute("id"); if (!str) { Log::Write(LogLevel_Warning, "NotificationCCTypes::ReadXML: Error in %s at line %d - missing AlarmType ID attribute", AlarmTypeElement->GetDocument()->GetUserData(), AlarmTypeElement->Row()); AlarmTypeElement = AlarmTypeElement->NextSiblingElement(); delete nt; continue; } nt->id = (uint32) strtol(str, &pStopChar, 10); str = AlarmTypeElement->Attribute("name"); if (!str) { Log::Write(LogLevel_Warning, "NotificationCCTypes::ReadXML: Error in %s at line %d - missing AlarmType name attribute", AlarmTypeElement->GetDocument()->GetUserData(), AlarmTypeElement->Row()); AlarmTypeElement = AlarmTypeElement->NextSiblingElement(); delete nt; continue; } nt->name = str; trim(nt->name); TiXmlElement const* AlarmEventElement = AlarmTypeElement->FirstChildElement(); while (AlarmEventElement) { str = AlarmEventElement->Value(); if (str && !strcmp(str, "AlarmEvent")) { NotificationEvents *ne = new NotificationEvents; str = AlarmEventElement->Attribute("id"); if (!str) { Log::Write(LogLevel_Warning, "NotificationCCTypes::ReadXML: Error in %s at line %d - missing AlarmEventParam id attribute", AlarmEventElement->GetDocument()->GetUserData(), AlarmEventElement->Row()); AlarmEventElement = AlarmEventElement->NextSiblingElement(); delete ne; continue; } ne->id = (uint32) strtol(str, &pStopChar, 10); str = AlarmEventElement->Attribute("name"); if (!str) { Log::Write(LogLevel_Warning, "NotificationCCTypes::ReadXML: Error in %s at line %d - missing AlarmEventParam name attribute", AlarmEventElement->GetDocument()->GetUserData(), AlarmEventElement->Row()); AlarmEventElement = AlarmEventElement->NextSiblingElement(); delete ne; continue; } ne->name = str; trim(ne->name); TiXmlElement const* nextElement = AlarmEventElement->FirstChildElement(); while (nextElement) { str = nextElement->Value(); if (str && !strcmp(str, "AlarmEventParam")) { NotificationEventParams *aep = new NotificationEventParams; str = nextElement->Attribute("id"); if (!str) { Log::Write(LogLevel_Warning, "NotificationCCTypes::ReadXML: Error in %s at line %d - missing AlarmEventParam id attribute", nextElement->GetDocument()->GetUserData(), nextElement->Row()); nextElement = nextElement->NextSiblingElement(); delete aep; continue; } aep->id = (uint32) strtol(str, &pStopChar, 10); str = nextElement->Attribute("type"); if (!str) { Log::Write(LogLevel_Warning, "NotificationCCTypes::ReadXML: Error in %s at line %d - missing AlarmEventParam id attribute", nextElement->GetDocument()->GetUserData(), nextElement->Row()); nextElement = nextElement->NextSiblingElement(); delete aep; continue; } if (!strcasecmp(str, "location")) { aep->type = NotificationCCTypes::NEPT_Location; } else if (!strcasecmp(str, "list")) { aep->type = NotificationCCTypes::NEPT_List; TiXmlElement const* listElement = nextElement->FirstChildElement(); while (listElement) { str = listElement->Value(); if (str && !strcmp(str, "Item")) { str = listElement->Attribute("id"); if (!str) { Log::Write(LogLevel_Warning, "NotificationCCTypes::ReadXML: Error in %s at line %d - missing Item id attribute", listElement->GetDocument()->GetUserData(), nextElement->Row()); listElement = listElement->NextSiblingElement(); continue; } uint32 listID = (uint32) strtol(str, &pStopChar, 10); str = listElement->Attribute("label"); if (!str) { Log::Write(LogLevel_Warning, "NotificationCCTypes::ReadXML: Error in %s at line %d - missing Item name attribute", listElement->GetDocument()->GetUserData(), nextElement->Row()); listElement = listElement->NextSiblingElement(); continue; } if (aep->ListItems.find(listID) == aep->ListItems.end()) { aep->ListItems.insert(std::pair(listID, str)); } else { Log::Write(LogLevel_Warning, "NotificationCCTypes::ReadXML: Error in %s - A AlarmEventElement with id %d already exists. Skipping ", listElement->GetDocument()->GetUserData(), ne->id); } } listElement = listElement->NextSiblingElement(); } } else if (!strcasecmp(str, "usercodereport")) { aep->type = NotificationCCTypes::NEPT_UserCodeReport; } else if (!strcasecmp(str, "byte")) { aep->type = NotificationCCTypes::NEPT_Byte; } else if (!strcasecmp(str, "string")) { aep->type = NotificationCCTypes::NEPT_String; } else if (!strcasecmp(str, "duration")) { aep->type = NotificationCCTypes::NEPT_Time; } else { Log::Write(LogLevel_Warning, "NotificationCCTypes::ReadXML: Error in %s at line %d - unknown AlarmEventParam type attribute (%s)", nextElement->GetDocument()->GetUserData(), nextElement->Row(), str); nextElement = nextElement->NextSiblingElement(); continue; } str = nextElement->Attribute("name"); if (!str) { Log::Write(LogLevel_Warning, "NotificationCCTypes::ReadXML: Error in %s at line %d - missing AlarmEventParam name attribute", nextElement->GetDocument()->GetUserData(), nextElement->Row()); nextElement = nextElement->NextSiblingElement(); continue; } aep->name = str; trim(aep->name); if (ne->EventParams.find(aep->id) == ne->EventParams.end()) ne->EventParams[aep->id] = std::shared_ptr(aep); else { Log::Write(LogLevel_Warning, "NotificationCCTypes::ReadXML: Error in %s - A AlarmEventParam with id %d already exists. Skipping ", nextElement->GetDocument()->GetUserData(), aep->id); delete aep; } } nextElement = nextElement->NextSiblingElement(); } if (nt->Events.find(ne->id) == nt->Events.end()) nt->Events[ne->id] = std::shared_ptr(ne); else { Log::Write(LogLevel_Warning, "NotificationCCTypes::ReadXML: Error in %s - A AlarmEventElement with id %d already exists. Skipping ", AlarmEventElement->GetDocument()->GetUserData(), ne->id); delete ne; } } AlarmEventElement = AlarmEventElement->NextSiblingElement(); } if (Notifications.find(nt->id) == Notifications.end()) Notifications[nt->id] = std::shared_ptr(nt); else { Log::Write(LogLevel_Warning, "NotificationCCTypes::ReadXML: Error in %s - A AlarmTypeElement with id %d already exists. Skipping ", AlarmTypeElement->GetDocument()->GetUserData(), nt->id); delete nt; } } AlarmTypeElement = AlarmTypeElement->NextSiblingElement(); } Log::Write(LogLevel_Info, "Loaded %s With Revision %d", pDoc->GetUserData(), m_revision); #if 0 std::cout << "NotificationCCTypes" << std::endl; for (std::map::iterator it = Notifications.begin(); it != Notifications.end(); it++) { std::cout << "\tAlarmType:" << it->first << " Name: " << it->second->name << std::endl; for (std::map::iterator it2 = it->second->Events.begin(); it2 != it->second->Events.end(); it2++) { std::cout << "\t\tAlarmEvents: " << it2->first << " Name: " << it2->second->name << std::endl; for (std::map::iterator it3 = it2->second->EventParams.begin(); it3 != it2->second->EventParams.end(); it3++) { std::cout << "\t\t\tEventParams: " << it3->first << " Name: " << it3->second->name << " Type: " << GetEventParamNames(it3->second->type) << std::endl; for (std::map::iterator it4 = it3->second->ListItems.begin(); it4 != it3->second->ListItems.end(); it4++) { std::cout << "\t\t\t\tEventParamsList: " << it4->first << " Name: " << it4->second << std::endl; } } } } exit(0); #endif delete pDoc; return true; } std::string NotificationCCTypes::GetEventParamNames(NotificationEventParamTypes type) { switch (type) { case NEPT_Location: return "Location"; break; case NEPT_List: return "List"; break; case NEPT_UserCodeReport: return "UserCodeReport"; break; case NEPT_Byte: return "Byte"; break; case NEPT_String: return "String"; break; case NEPT_Time: return "Duration"; break; }; return "Unknown"; } std::string NotificationCCTypes::GetAlarmType(uint32 type) { if (Notifications.find(type) != Notifications.end()) { return Notifications.at(type)->name; } Log::Write(LogLevel_Warning, "NotificationCCTypes::GetAlarmType - Unknown AlarmType %d", type); return "Unknown"; } std::string NotificationCCTypes::GetEventForAlarmType(uint32 type, uint32 event) { if (const std::shared_ptr ne = NotificationCCTypes::GetAlarmNotificationEvents(type, event)) { return ne->name; } Log::Write(LogLevel_Warning, "NotificationCCTypes::GetEventForAlarmType - Unknown AlarmType/Event %d/d", type, event); return "Unknown"; } const std::shared_ptr NotificationCCTypes::GetAlarmNotificationTypes(uint32 type) { if (Notifications.find(type) != Notifications.end()) { return Notifications.at(type); } else { Log::Write(LogLevel_Warning, "NotificationCCTypes::GetAlarmNotificationTypes - Unknown Alarm Type %d", type); } return NULL; } const std::shared_ptr NotificationCCTypes::GetAlarmNotificationEvents(uint32 type, uint32 event) { if (const std::shared_ptr nt = GetAlarmNotificationTypes(type)) { if (nt->Events.find(event) != nt->Events.end()) { return nt->Events.at(event); } Log::Write(LogLevel_Warning, "NotificationCCTypes::GetAlarmNotificationEvents - Unknown Alarm Event %d for Alarm Type %s (%d)", event, GetAlarmType(type).c_str(), type); } return NULL; } const std::map > NotificationCCTypes::GetAlarmNotificationEventParams(uint32 type, uint32 event) { if (const std::shared_ptr nt = GetAlarmNotificationTypes(type)) { if (nt->Events.find(event) != nt->Events.end()) { return nt->Events.at(event)->EventParams; } Log::Write(LogLevel_Warning, "NotificationCCTypes::GetAlarmNotificationEventParams - Unknown Alarm Event %d for Alarm Type %s (%d)", event, GetAlarmType(type).c_str(), type); } return std::map >(); } bool NotificationCCTypes::Create() { if (m_instance != NULL) { return true; } m_instance = new NotificationCCTypes(); if (!ReadXML()) { OZW_ERROR(OZWException::OZWEXCEPTION_CONFIG, "Cannot Create NotificationCCTypes Class! - Missing/Invalid Config File?"); return false; } return true; } NotificationCCTypes *NotificationCCTypes::Get() { if (m_instance != NULL) { return m_instance; } m_instance = new NotificationCCTypes(); if (!ReadXML()) { OZW_ERROR(OZWException::OZWEXCEPTION_CONFIG, "Cannot Get NotificationCCTypes Class! - Missing/Invalid Config File?"); return m_instance; } return m_instance; } } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/src/Group.cpp0000644000175200017520000004132614032142455014077 00000000000000//----------------------------------------------------------------------------- // // Group.cpp // // A set of associations in a Z-Wave device. // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "Group.h" #include "Manager.h" #include "Driver.h" #include "Node.h" #include "Notification.h" #include "Options.h" #include "command_classes/Association.h" #include "command_classes/AssociationCommandConfiguration.h" #include "command_classes/MultiChannelAssociation.h" #include "command_classes/MultiInstance.h" #include "platform/Log.h" #include "tinyxml.h" using namespace OpenZWave; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Group::Group(uint32 const _homeId, uint8 const _nodeId, uint8 const _groupIdx, uint8 const _maxAssociations) : m_homeId(_homeId), m_nodeId(_nodeId), m_groupIdx(_groupIdx), m_maxAssociations(_maxAssociations), m_auto(false), m_multiInstance(false) { char str[16]; snprintf(str, sizeof(str), "Group %d", m_groupIdx); m_label = str; CheckAuto(); } //----------------------------------------------------------------------------- // // Constructor (from XML) //----------------------------------------------------------------------------- Group::Group(uint32 const _homeId, uint8 const _nodeId, TiXmlElement const* _groupElement) : m_homeId(_homeId), m_nodeId(_nodeId), m_groupIdx(0), m_maxAssociations(0), m_auto(false), m_multiInstance(false) { int intVal; char const* str; vector pending; if (TIXML_SUCCESS == _groupElement->QueryIntAttribute("index", &intVal)) { m_groupIdx = (uint8) intVal; } /* call this so the config can override if necessary */ CheckAuto(); if (TIXML_SUCCESS == _groupElement->QueryIntAttribute("max_associations", &intVal)) { m_maxAssociations = (uint8) intVal; } str = _groupElement->Attribute("auto"); if (str) { m_auto = !strcmp(str, "true"); } str = _groupElement->Attribute("label"); if (str) { m_label = str; } str = _groupElement->Attribute("multiInstance"); if (str) { m_multiInstance = !strcmp(str, "true"); } // Read the associations for this group TiXmlElement const* associationElement = _groupElement->FirstChildElement(); while (associationElement) { char const* elementName = associationElement->Value(); if (elementName && !strcmp(elementName, "Node")) { if (associationElement->QueryIntAttribute("id", &intVal) == TIXML_SUCCESS) { /* intVal is a Int, so refuse to load anything high thatn 254 */ if (intVal >= 255) { Log::Write(LogLevel_Warning, m_nodeId, "Broadcast Address was found in cache for Association Group %d - Ignoring", m_groupIdx); /* we really should go and Delete it from the Node, but since this is a cache, lets just ignore it here */ } else { InstanceAssociation association; association.m_nodeId = (uint8) intVal; if (associationElement->QueryIntAttribute("instance", &intVal) == TIXML_SUCCESS) association.m_instance = (uint8) intVal; else association.m_instance = 0x00; pending.push_back(association); } } } associationElement = associationElement->NextSiblingElement(); } // Group must be added before OnGroupChanged is called so UpdateNodeRoutes can find it. // Since we do not want to update return routes UpdateNodeRoutes won't find the group // so nothing will go out from here. The not sending of return routes information // only works by a side effect of not finding the group. OnGroupChanged(pending); } //----------------------------------------------------------------------------- // // Check if we should AutoAssociate for this group //----------------------------------------------------------------------------- void Group::CheckAuto( ) { // Auto-association by default is with group 1 or 255, with group 1 taking precedence. // Group 255 is always created first, so if this is group 1, we need to turn off the // auto flag in group 255. All this messing about is to support the various behaviours // of certain Cooper devices. if (m_groupIdx == 255) { m_auto = true; } else if (m_groupIdx == 1) { m_auto = true; // Clear the flag from Group 255, if it exists. if (Driver* driver = Manager::Get()->GetDriver(m_homeId)) { if (Node* node = driver->GetNodeUnsafe(m_nodeId)) { if (Group* group = node->GetGroup(255)) { group->SetAuto(false); } } } } } //----------------------------------------------------------------------------- // // Write ourselves to an XML document //----------------------------------------------------------------------------- void Group::WriteXML(TiXmlElement* _groupElement) { char str[16]; snprintf(str, 16, "%d", m_groupIdx); _groupElement->SetAttribute("index", str); snprintf(str, 16, "%d", m_maxAssociations); _groupElement->SetAttribute("max_associations", str); _groupElement->SetAttribute("label", m_label.c_str()); _groupElement->SetAttribute("auto", m_auto ? "true" : "false"); if (m_multiInstance) { _groupElement->SetAttribute("multiInstance", m_multiInstance ? "true" : "false"); } for (map::iterator it = m_associations.begin(); it != m_associations.end(); ++it) { TiXmlElement* associationElement = new TiXmlElement("Node"); if (it->first.m_nodeId == 255) { Log::Write(LogLevel_Warning, m_nodeId, "Broadcast Address was found in Association Group %d when writing cache. Ignoring", m_groupIdx); } else { snprintf(str, 16, "%d", it->first.m_nodeId); associationElement->SetAttribute("id", str); if (it->first.m_instance != 0) { snprintf(str, 16, "%d", it->first.m_instance); associationElement->SetAttribute("instance", str); } _groupElement->LinkEndChild(associationElement); } } } //----------------------------------------------------------------------------- // // Whether a group contains a particular node //----------------------------------------------------------------------------- bool Group::Contains(uint8 const _nodeId, uint8 const _endPoint) { for (map::iterator it = m_associations.begin(); it != m_associations.end(); ++it) { if ((it->first.m_nodeId == _nodeId) && (it->first.m_instance == _endPoint)) { return true; } } return false; } //----------------------------------------------------------------------------- // // Associate a node with this group //----------------------------------------------------------------------------- void Group::AddAssociation(uint8 const _nodeId, uint8 const _endPoint) { if (_nodeId == 255) { Log::Write(LogLevel_Warning, m_nodeId, "Attemping to add broadcast address to Association Group %d - Ignoring", m_groupIdx); return; } if (Driver* driver = Manager::Get()->GetDriver(m_homeId)) { if (Node* node = driver->GetNodeUnsafe(m_nodeId)) { Internal::CC::MultiChannelAssociation* cc = static_cast(node->GetCommandClass(Internal::CC::MultiChannelAssociation::StaticGetCommandClassId())); Internal::CC::MultiInstance *mc = static_cast(node->GetCommandClass(Internal::CC::MultiInstance::StaticGetCommandClassId())); if (cc && IsMultiInstance()) { if (mc) { cc->Set(m_groupIdx, _nodeId, _endPoint); cc->QueryGroup(m_groupIdx, 0); return; } else { Log::Write(LogLevel_Warning, m_nodeId, "MultiChannelAssociation is Present, but MultiChannel CC is not. Trying Plain Association..."); } } if (Internal::CC::Association* cc = static_cast(node->GetCommandClass(Internal::CC::Association::StaticGetCommandClassId()))) { cc->Set(m_groupIdx, _nodeId); cc->QueryGroup(m_groupIdx, 0); } else { Log::Write(LogLevel_Info, m_nodeId, "No supported Association CC found"); } } } } //----------------------------------------------------------------------------- // // Remove a node from this group //----------------------------------------------------------------------------- void Group::RemoveAssociation(uint8 const _nodeId, uint8 const _endPoint) { if (Driver* driver = Manager::Get()->GetDriver(m_homeId)) { if (Node* node = driver->GetNodeUnsafe(m_nodeId)) { Internal::CC::MultiChannelAssociation* cc = static_cast(node->GetCommandClass(Internal::CC::MultiChannelAssociation::StaticGetCommandClassId())); if (cc && IsMultiInstance()) { cc->Remove(m_groupIdx, _nodeId, _endPoint); cc->QueryGroup(m_groupIdx, 0); } else if (Internal::CC::Association* cc = static_cast(node->GetCommandClass(Internal::CC::Association::StaticGetCommandClassId()))) { cc->Remove(m_groupIdx, _nodeId); cc->QueryGroup(m_groupIdx, 0); } else { Log::Write(LogLevel_Info, m_nodeId, "No supported Association CC found"); } } } } //----------------------------------------------------------------------------- // // Change the group contents and notify the watchers //----------------------------------------------------------------------------- void Group::OnGroupChanged(vector const& _associations) { vector instanceAssociations; uint8 i; for (i = 0; i < _associations.size(); ++i) { InstanceAssociation association; association.m_nodeId = _associations[i]; association.m_instance = 0x00; instanceAssociations.push_back(association); } OnGroupChanged(instanceAssociations); instanceAssociations.clear(); } //----------------------------------------------------------------------------- // // Change the group contents and notify the watchers //----------------------------------------------------------------------------- void Group::OnGroupChanged(vector const& _associations) { bool notify = false; // If the number of associations is different, we'll save // ourselves some work and clear the old set now. if (_associations.size() != m_associations.size()) { m_associations.clear(); notify = true; } else { // Handle initial group creation case if (_associations.size() == 0 && m_associations.size() == 0) { notify = true; } } // Add the new associations. uint8 oldSize = (uint8) m_associations.size(); uint8 i; for (i = 0; i < _associations.size(); ++i) { m_associations[_associations[i]] = AssociationCommandVec(); } if ((!notify) && (oldSize != m_associations.size())) { // The number of nodes in the original and new groups is the same, but // the number of associations has grown. There must be different nodes // in the original and new sets of nodes in the group. The easiest way // to sort this out is to clear the associations and add the new nodes again. m_associations.clear(); for (i = 0; i < _associations.size(); ++i) { m_associations[_associations[i]] = AssociationCommandVec(); } notify = true; } if (notify) { // If the node supports COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION, we need to request the command data. if (Driver* driver = Manager::Get()->GetDriver(m_homeId)) { if (Node* node = driver->GetNodeUnsafe(m_nodeId)) { if (Internal::CC::AssociationCommandConfiguration* cc = static_cast(node->GetCommandClass(Internal::CC::AssociationCommandConfiguration::StaticGetCommandClassId()))) { for (map::iterator it = m_associations.begin(); it != m_associations.end(); ++it) { cc->RequestCommands(m_groupIdx, it->first.m_nodeId); } } } } // Send notification that the group contents have changed Notification* notification = new Notification(Notification::Type_Group); notification->SetHomeAndNodeIds(m_homeId, m_nodeId); notification->SetGroupIdx(m_groupIdx); Manager::Get()->GetDriver(m_homeId)->QueueNotification(notification); // Update routes on remote node if necessary bool update = false; Options::Get()->GetOptionAsBool("PerformReturnRoutes", &update); if (update) { Driver *drv = Manager::Get()->GetDriver(m_homeId); if (drv) drv->UpdateNodeRoutes(m_nodeId); } } } //----------------------------------------------------------------------------- // // Get a list of associations for this group //----------------------------------------------------------------------------- uint32 Group::GetAssociations(uint8** o_associations) { size_t numNodes = m_associations.size(); if (!numNodes) { *o_associations = NULL; return 0; } uint8* associations = new uint8[numNodes]; // room for all associations, we only need room for the associations without instance uint32 i = 0; for (map::iterator it = m_associations.begin(); it != m_associations.end(); ++it) { if (it->first.m_instance == 0x00) { associations[i++] = it->first.m_nodeId; } } *o_associations = associations; return (uint32) i; } //----------------------------------------------------------------------------- // // Get a list of associations for this group //----------------------------------------------------------------------------- uint32 Group::GetAssociations(InstanceAssociation** o_associations) { size_t numNodes = m_associations.size(); if (!numNodes) { *o_associations = NULL; return 0; } InstanceAssociation* associations = new InstanceAssociation[numNodes]; uint32 i = 0; for (map::iterator it = m_associations.begin(); it != m_associations.end(); ++it) { associations[i++] = it->first; } *o_associations = associations; return (uint32) numNodes; } //----------------------------------------------------------------------------- // Command methods (COMMAND_CLASS_ASSOCIATION_COMMAND_CONFIGURATION) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Clear all the commands for the specified node //----------------------------------------------------------------------------- bool Group::ClearCommands(uint8 const _nodeId, uint8 const _endPoint) { for (map::iterator it = m_associations.begin(); it != m_associations.end(); ++it) { if ((it->first.m_nodeId == _nodeId) && (it->first.m_instance == _endPoint)) { it->second.clear(); return true; } } return false; } //----------------------------------------------------------------------------- // // Add a command to the list for the specified node //----------------------------------------------------------------------------- bool Group::AddCommand(uint8 const _nodeId, uint8 const _length, uint8 const* _data, uint8 const _endPoint) { for (map::iterator it = m_associations.begin(); it != m_associations.end(); ++it) { if ((it->first.m_nodeId == _nodeId) && (it->first.m_instance == _endPoint)) { it->second.push_back(AssociationCommand(_length, _data)); return true; } } return false; } //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Group::AssociationCommand::AssociationCommand(uint8 const _length, uint8 const* _data) { m_data = new uint8[_length]; memcpy(m_data, _data, _length); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- Group::AssociationCommand::~AssociationCommand() { delete[] m_data; } openzwave-1.6.1914/cpp/src/Defs.h0000644000175200017520000004306514032142455013333 00000000000000//----------------------------------------------------------------------------- // // Defs.h // // Basic types and preprocessor directives // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #ifndef _Defs_H #define _Defs_H #include #include #include #include #include // Compilation export flags #if (defined _WINDOWS || defined WIN32 || defined _MSC_VER) && (!defined MINGW && !defined __MINGW32__ && !defined __MINGW64__) // As discussd here https://github.com/OpenZWave/open-zwave/pull/1835 // Disable certain MSVC warnings here (instead of applying the pragma throughout the code as was done in the past). // Application and DLL should be built with same compiler and settings anyway. // See https://stackoverflow.com/questions/5661738/how-can-i-use-standard-library-stl-classes-in-my-dll-interface-or-abi # if defined OPENZWAVE_MAKEDLL // Create the dynamic library. # define OPENZWAVE_EXPORT __declspec(dllexport) __pragma(warning(disable: 4251)) __pragma(warning(disable: 4275)) # elif defined OPENZWAVE_USEDLL // Use the dynamic library # define OPENZWAVE_EXPORT __declspec(dllimport) __pragma(warning(disable: 4251)) __pragma(warning(disable: 4275)) # else // Create/Use the static library # define OPENZWAVE_EXPORT # endif #else # define OPENZWAVE_EXPORT #endif #ifdef __GNUC__ #define DEPRECATED __attribute__((deprecated)) #elif defined(_MSC_VER) #define DEPRECATED __declspec(deprecated) #else #pragma message("WARNING: You need to implement DEPRECATED for this compiler") #define DEPRECATED #endif #ifdef _MSC_VER #define OPENZWAVE_DEPRECATED_WARNINGS_OFF __pragma( warning(push) )\ __pragma( warning(disable: 4996) ) #else #define OPENZWAVE_DEPRECATED_WARNINGS_OFF _Pragma ( "GCC diagnostic push" )\ _Pragma ( "GCC diagnostic ignored \"-Wdeprecated-declarations\"" ) #endif #ifdef _MSC_VER #define OPENZWAVE_DEPRECATED_WARNINGS_ON __pragma( warning(pop) ) #else #define OPENZWAVE_DEPRECATED_WARNINGS_ON _Pragma ( "GCC diagnostic pop" ) #endif #ifdef NULL #undef NULL #endif #define NULL 0 // Basic types typedef signed char int8; typedef unsigned char uint8; typedef signed short int16; typedef unsigned short uint16; typedef signed int int32; typedef unsigned int uint32; #ifdef _MSC_VER typedef signed __int64 int64; typedef unsigned __int64 uint64; #endif #ifdef __GNUC__ typedef signed long long int64; typedef unsigned long long uint64; #endif typedef float float32; typedef double float64; typedef struct ozwversion { uint32_t _v; /* major << 16 | minor */ } ozwversion; /** * \brief version_major - return the major version of the given struct * \param v: the version number to obtain the major number from * \return the Major Version Number */ static inline uint16_t version_major(struct ozwversion v) { return (v._v & 0xFFFF0000) >> 16; } /** * \brief version_minor - return the minor version of the given struct * \param v: the version number to obtain the minor number from * \return the Minor Version Number */ static inline uint16_t version_minor(const struct ozwversion &v) { return v._v & 0xFFFF; } /** * \brief version - create a new version number * \param major: major version number * \param minor: minor version number * \return the Version Number Struct */ static inline struct ozwversion version(uint16_t major, uint16_t minor) { struct ozwversion v; v._v = (uint32_t) (major << 16) | (uint32_t) minor; return v; } /** * \brief version_cmp - compare two versions * \param a: the first version number * \param b: the second version number * \return a number greater, equal, or less than 0 if a is greater, equal or * less than b, respectively * * Example: * struct version a = version(1, 0); * struct version b = version(1, 3); * if (version_cmp(a, b) < 0) * printf("b is smaller than b\n"); */ static inline int version_cmp(struct ozwversion a, struct ozwversion b) { return (a._v == b._v) ? 0 : (a._v > b._v) ? 1 : -1; } #include "OZWException.h" #if defined(_MSC_VER) # define __MYFUNCTION__ __FUNCTION__ #else # define __MYFUNCTION__ __FILE__ #endif # define OZW_FATAL_ERROR(exitCode, msg) Log::Write( LogLevel_Error,"Exception: %s:%d - %d - %s", std::string(__MYFUNCTION__).substr(std::string(__MYFUNCTION__).find_last_of("/\\") + 1).c_str(), __LINE__, exitCode, msg); \ throw OZWException(__MYFUNCTION__, __LINE__, exitCode, msg) # define OZW_ERROR(exitCode, msg) Log::Write( LogLevel_Warning,"Exception: %s:%d - %d - %s", std::string(__MYFUNCTION__).substr(std::string(__MYFUNCTION__).find_last_of("/\\") + 1).c_str(), __LINE__, exitCode, msg); \ throw OZWException(__MYFUNCTION__, __LINE__, exitCode, msg) // Declare the OpenZWave namespace namespace std { } namespace OpenZWave { // Include the STL namespace using namespace std; namespace Internal { namespace CC { } } } // Modifications for Microsoft compilers #ifdef _MSC_VER // Fix for namespace-related compiler bug namespace OpenZWave { } // Rename safe versions of sprintf etc #define snprintf sprintf_s #define strcasecmp _stricmp #define sscanf sscanf_s #define strncpy(x, y, z) strncpy_s(x, sizeof(x), y, sizeof(x)-1) #define strncat strncat_s #endif // Modifications for MiNGW32 compiler #ifdef MINGW // Replace "safe" versions of sprintf #define sprintf_s snprintf // seems some MINGW versions don't have a errno_t #ifndef errno_t #define errno_t int #endif #define fopen_s fopen #endif //#define MAX_TRIES 3 // Retry sends up to 3 times #define MAX_TRIES 1 // set this to one, as I believe now that a ACK failure is indication that the device is offline, hence additional attempts will not work. #define MAX_MAX_TRIES 7 // Don't exceed this retry limit #define ACK_TIMEOUT 1000 // How long to wait for an ACK #define BYTE_TIMEOUT 150 //#define RETRY_TIMEOUT 40000 // Retry send after 40 seconds #define RETRY_TIMEOUT 10000 // Retry send after 10 seconds (we might need to keep this below 10 for Security CC to function correctly) #define SOF 0x01 #define ACK 0x06 #define NAK 0x15 #define CAN 0x18 #define NUM_NODE_BITFIELD_BYTES 29 // 29 bytes = 232 bits, one for each possible node in the network. #define REQUEST 0x00 #define RESPONSE 0x01 #define ZW_CLOCK_SET 0x30 #define TRANSMIT_OPTION_ACK 0x01 #define TRANSMIT_OPTION_LOW_POWER 0x02 #define TRANSMIT_OPTION_AUTO_ROUTE 0x04 #define TRANSMIT_OPTION_NO_ROUTE 0x10 #define TRANSMIT_OPTION_EXPLORE 0x20 #define TRANSMIT_COMPLETE_OK 0x00 #define TRANSMIT_COMPLETE_NO_ACK 0x01 #define TRANSMIT_COMPLETE_FAIL 0x02 #define TRANSMIT_COMPLETE_NOT_IDLE 0x03 #define TRANSMIT_COMPLETE_NOROUTE 0x04 #define TRANSMIT_COMPLETE_VERIFIED 0x05 #define RECEIVE_STATUS_ROUTED_BUSY 0x01 #define RECEIVE_STATUS_TYPE_BROAD 0x04 #define FUNC_ID_SERIAL_API_GET_INIT_DATA 0x02 #define FUNC_ID_SERIAL_API_APPL_NODE_INFORMATION 0x03 #define FUNC_ID_APPLICATION_COMMAND_HANDLER 0x04 #define FUNC_ID_ZW_GET_CONTROLLER_CAPABILITIES 0x05 #define FUNC_ID_SERIAL_API_SET_TIMEOUTS 0x06 #define FUNC_ID_SERIAL_API_GET_CAPABILITIES 0x07 #define FUNC_ID_SERIAL_API_SOFT_RESET 0x08 #define FUNC_ID_SERIAL_API_SETUP 0x0b #define FUNC_ID_ZW_SEND_NODE_INFORMATION 0x12 #define FUNC_ID_ZW_SEND_DATA 0x13 #define FUNC_ID_ZW_GET_VERSION 0x15 #define FUNC_ID_ZW_R_F_POWER_LEVEL_SET 0x17 #define FUNC_ID_ZW_GET_RANDOM 0x1c #define FUNC_ID_ZW_MEMORY_GET_ID 0x20 #define FUNC_ID_MEMORY_GET_BYTE 0x21 #define FUNC_ID_ZW_READ_MEMORY 0x23 #define FUNC_ID_ZW_SET_LEARN_NODE_STATE 0x40 // Not implemented #define FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO 0x41 // Get protocol info (baud rate, listening, etc.) for a given node #define FUNC_ID_ZW_SET_DEFAULT 0x42 // Reset controller and node info to default (original) values #define FUNC_ID_ZW_NEW_CONTROLLER 0x43 // Not implemented #define FUNC_ID_ZW_REPLICATION_COMMAND_COMPLETE 0x44 // Replication send data complete #define FUNC_ID_ZW_REPLICATION_SEND_DATA 0x45 // Replication send data #define FUNC_ID_ZW_ASSIGN_RETURN_ROUTE 0x46 // Assign a return route from the specified node to the controller #define FUNC_ID_ZW_DELETE_RETURN_ROUTE 0x47 // Delete all return routes from the specified node #define FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE 0x48 // Ask the specified node to update its neighbors (then read them from the controller) #define FUNC_ID_ZW_APPLICATION_UPDATE 0x49 // Get a list of supported (and controller) command classes #define FUNC_ID_ZW_ADD_NODE_TO_NETWORK 0x4a // Control the addnode (or addcontroller) process...start, stop, etc. #define FUNC_ID_ZW_REMOVE_NODE_FROM_NETWORK 0x4b // Control the removenode (or removecontroller) process...start, stop, etc. #define FUNC_ID_ZW_CREATE_NEW_PRIMARY 0x4c // Control the createnewprimary process...start, stop, etc. #define FUNC_ID_ZW_CONTROLLER_CHANGE 0x4d // Control the transferprimary process...start, stop, etc. #define FUNC_ID_ZW_SET_LEARN_MODE 0x50 // Put a controller into learn mode for replication/ receipt of configuration info #define FUNC_ID_ZW_ASSIGN_SUC_RETURN_ROUTE 0x51 // Assign a return route to the SUC #define FUNC_ID_ZW_ENABLE_SUC 0x52 // Make a controller a Static Update Controller #define FUNC_ID_ZW_REQUEST_NETWORK_UPDATE 0x53 // Network update for a SUC(?) #define FUNC_ID_ZW_SET_SUC_NODE_ID 0x54 // Identify a Static Update Controller node id #define FUNC_ID_ZW_DELETE_SUC_RETURN_ROUTE 0x55 // Remove return routes to the SUC #define FUNC_ID_ZW_GET_SUC_NODE_ID 0x56 // Try to retrieve a Static Update Controller node id (zero if no SUC present) #define FUNC_ID_ZW_REQUEST_NODE_NEIGHBOR_UPDATE_OPTIONS 0x5a // Allow options for request node neighbor update #define FUNC_ID_ZW_EXPLORE_REQUEST_INCLUSION 0x5e // supports NWI #define FUNC_ID_ZW_REQUEST_NODE_INFO 0x60 // Get info (supported command classes) for the specified node #define FUNC_ID_ZW_REMOVE_FAILED_NODE_ID 0x61 // Mark a specified node id as failed #define FUNC_ID_ZW_IS_FAILED_NODE_ID 0x62 // Check to see if a specified node has failed #define FUNC_ID_ZW_REPLACE_FAILED_NODE 0x63 // Remove a failed node from the controller's list (?) #define FUNC_ID_ZW_GET_ROUTING_INFO 0x80 // Get a specified node's neighbor information from the controller #define FUNC_ID_SERIAL_API_SLAVE_NODE_INFO 0xA0 // Set application virtual slave node information #define FUNC_ID_APPLICATION_SLAVE_COMMAND_HANDLER 0xA1 // Slave command handler #define FUNC_ID_ZW_SEND_SLAVE_NODE_INFO 0xA2 // Send a slave node information frame #define FUNC_ID_ZW_SEND_SLAVE_DATA 0xA3 // Send data from slave #define FUNC_ID_ZW_SET_SLAVE_LEARN_MODE 0xA4 // Enter slave learn mode #define FUNC_ID_ZW_GET_VIRTUAL_NODES 0xA5 // Return all virtual nodes #define FUNC_ID_ZW_IS_VIRTUAL_NODE 0xA6 // Virtual node test #define FUNC_ID_ZW_SET_PROMISCUOUS_MODE 0xD0 // Set controller into promiscuous mode to listen to all frames #define FUNC_ID_PROMISCUOUS_APPLICATION_COMMAND_HANDLER 0xD1 #define FUNC_ID_PROPRIETARY_0 0xF0 #define FUNC_ID_PROPRIETARY_1 0xF1 #define FUNC_ID_PROPRIETARY_2 0xF2 #define FUNC_ID_PROPRIETARY_3 0xF3 #define FUNC_ID_PROPRIETARY_4 0xF4 #define FUNC_ID_PROPRIETARY_5 0xF5 #define FUNC_ID_PROPRIETARY_6 0xF6 #define FUNC_ID_PROPRIETARY_7 0xF7 #define FUNC_ID_PROPRIETARY_8 0xF8 #define FUNC_ID_PROPRIETARY_9 0xF9 #define FUNC_ID_PROPRIETARY_A 0xFA #define FUNC_ID_PROPRIETARY_B 0xFB #define FUNC_ID_PROPRIETARY_C 0xFC #define FUNC_ID_PROPRIETARY_D 0xFD #define FUNC_ID_PROPRIETARY_E 0xFE #define ADD_NODE_ANY 0x01 #define ADD_NODE_CONTROLLER 0x02 #define ADD_NODE_SLAVE 0x03 #define ADD_NODE_EXISTING 0x04 #define ADD_NODE_STOP 0x05 #define ADD_NODE_STOP_FAILED 0x06 #define ADD_NODE_STATUS_LEARN_READY 0x01 #define ADD_NODE_STATUS_NODE_FOUND 0x02 #define ADD_NODE_STATUS_ADDING_SLAVE 0x03 #define ADD_NODE_STATUS_ADDING_CONTROLLER 0x04 #define ADD_NODE_STATUS_PROTOCOL_DONE 0x05 #define ADD_NODE_STATUS_DONE 0x06 #define ADD_NODE_STATUS_FAILED 0x07 #define REMOVE_NODE_ANY 0x01 #define REMOVE_NODE_CONTROLLER 0x02 #define REMOVE_NODE_SLAVE 0x03 #define REMOVE_NODE_STOP 0x05 #define REMOVE_NODE_STATUS_LEARN_READY 0x01 #define REMOVE_NODE_STATUS_NODE_FOUND 0x02 #define REMOVE_NODE_STATUS_REMOVING_SLAVE 0x03 #define REMOVE_NODE_STATUS_REMOVING_CONTROLLER 0x04 #define REMOVE_NODE_STATUS_DONE 0x06 #define REMOVE_NODE_STATUS_FAILED 0x07 #define CREATE_PRIMARY_START 0x02 #define CREATE_PRIMARY_STOP 0x05 #define CREATE_PRIMARY_STOP_FAILED 0x06 #define CONTROLLER_CHANGE_START 0x02 #define CONTROLLER_CHANGE_STOP 0x05 #define CONTROLLER_CHANGE_STOP_FAILED 0x06 #define LEARN_MODE_STARTED 0x01 #define LEARN_MODE_DONE 0x06 #define LEARN_MODE_FAILED 0x07 #define LEARN_MODE_DELETED 0x80 #define REQUEST_NEIGHBOR_UPDATE_STARTED 0x21 #define REQUEST_NEIGHBOR_UPDATE_DONE 0x22 #define REQUEST_NEIGHBOR_UPDATE_FAILED 0x23 #define FAILED_NODE_OK 0x00 #define FAILED_NODE_REMOVED 0x01 #define FAILED_NODE_NOT_REMOVED 0x02 #define FAILED_NODE_REPLACE_WAITING 0x03 #define FAILED_NODE_REPLACE_DONE 0x04 #define FAILED_NODE_REPLACE_FAILED 0x05 #define FAILED_NODE_REMOVE_STARTED 0x00 #define FAILED_NODE_NOT_PRIMARY_CONTROLLER 0x02 #define FAILED_NODE_NO_CALLBACK_FUNCTION 0x04 #define FAILED_NODE_NOT_FOUND 0x08 #define FAILED_NODE_REMOVE_PROCESS_BUSY 0x10 #define FAILED_NODE_REMOVE_FAIL 0x20 #define SUC_UPDATE_DONE 0x00 #define SUC_UPDATE_ABORT 0x01 #define SUC_UPDATE_WAIT 0x02 #define SUC_UPDATE_DISABLED 0x03 #define SUC_UPDATE_OVERFLOW 0x04 #define SUC_FUNC_BASIC_SUC 0x00 #define SUC_FUNC_NODEID_SERVER 0x01 #define UPDATE_STATE_NODE_INFO_RECEIVED 0x84 #define UPDATE_STATE_NODE_INFO_REQ_DONE 0x82 #define UPDATE_STATE_NODE_INFO_REQ_FAILED 0x81 #define UPDATE_STATE_ROUTING_PENDING 0x80 #define UPDATE_STATE_NEW_ID_ASSIGNED 0x40 #define UPDATE_STATE_DELETE_DONE 0x20 #define UPDATE_STATE_SUC_ID 0x10 #define APPLICATION_NODEINFO_LISTENING 0x01 #define APPLICATION_NODEINFO_OPTIONAL_FUNCTIONALITY 0x02 #define SLAVE_ASSIGN_COMPLETE 0x00 #define SLAVE_ASSIGN_NODEID_DONE 0x01 // Node ID has been assigned #define SLAVE_ASSIGN_RANGE_INFO_UPDATE 0x02 // Node is doing neighbor discovery #define SLAVE_LEARN_MODE_DISABLE 0x00 // disable add/remove virtual slave nodes #define SLAVE_LEARN_MODE_ENABLE 0x01 // enable ability to include/exclude virtual slave nodes #define SLAVE_LEARN_MODE_ADD 0x02 // add node directly but only if primary/inclusion controller #define SLAVE_LEARN_MODE_REMOVE 0x03 // remove node directly but only if primary/inclusion controller #define OPTION_HIGH_POWER 0x80 #define OPTION_NWI 0x40 // NWI Inclusion //Device request related #define BASIC_SET 0x01 #define BASIC_REPORT 0x03 #define COMMAND_CLASS_BASIC 0x20 #define COMMAND_CLASS_CONTROLLER_REPLICATION 0x21 #define COMMAND_CLASS_APPLICATION_STATUS 0x22 #define COMMAND_CLASS_HAIL 0x82 /* library types */ #define ZW_LIB_CONTROLLER_STATIC 0x01 #define ZW_LIB_CONTROLLER 0x02 #define ZW_LIB_SLAVE_ENHANCED 0x03 #define ZW_LIB_SLAVE 0x04 #define ZW_LIB_INSTALLER 0x05 #define ZW_LIB_SLAVE_ROUTING 0x06 #define ZW_LIB_CONTROLLER_BRIDGE 0x07 #define ZW_LIB_DUT 0x08 /* Serial API Setup Commands */ #define SERIAL_API_SETUP_CMD_TX_STATUS_REPORT 0x02 #define SERIAL_API_SETUP_CMD_TX_POWERLEVEL_SET 0x04 #define SERIAL_API_SETUP_CMD_TX_POWERLEVEL_GET 0x08 #define SERIAL_API_SETUP_CMD_TX_GET_MAX_PAYLOAD_SIZE 0x10 /* RouteScheme Definitions */ typedef enum TXSTATUS_ROUTING_SCHEME { ROUTINGSCHEME_IDLE = 0, ROUTINGSCHEME_DIRECT = 1, ROUTINGSCHEME_CACHED_ROUTE_SR = 2, ROUTINGSCHEME_CACHED_ROUTE = 3, ROUTINGSCHEME_CACHED_ROUTE_NLWR = 4, ROUTINGSCHEME_ROUTE = 5, ROUTINGSCHEME_RESORT_DIRECT = 6, ROUTINGSCHEME_RESORT_EXPLORE = 7 } TXSTATUS_ROUTING_SCHEME; /* RouteSpeed Definitions */ typedef enum TXSTATUS_ROUTE_SPEED { ROUTE_SPEED_AUTO = 0, ROUTE_SPEED_9600 = 1, ROUTE_SPEED_40K = 2, ROUTE_SPEED_100K = 3, } TXSTATUS_ROUTE_SPEED; #endif // _Defs_H openzwave-1.6.1914/cpp/src/Node.cpp0000644000175200017520000041323614032142455013673 00000000000000//----------------------------------------------------------------------------- // // Node.cpp // // A node in the Z-Wave network. // // Copyright (c) 2009 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include "Node.h" #include "Defs.h" #include "Group.h" #include "Options.h" #include "Manager.h" #include "Driver.h" #include "Localization.h" #include "ManufacturerSpecificDB.h" #include "Notification.h" #include "Msg.h" #include "ZWSecurity.h" #include "platform/Log.h" #include "platform/Mutex.h" #include "Utils.h" #include "tinyxml.h" #include "command_classes/CommandClasses.h" #include "command_classes/CommandClass.h" #include "command_classes/Association.h" #include "command_classes/Basic.h" #include "command_classes/Configuration.h" #include "command_classes/ControllerReplication.h" #include "command_classes/ManufacturerSpecific.h" #include "command_classes/MultiInstance.h" #include "command_classes/MultiChannelAssociation.h" #include "command_classes/Security.h" #include "command_classes/WakeUp.h" #include "command_classes/NodeNaming.h" #include "command_classes/NoOperation.h" #include "command_classes/Version.h" #include "command_classes/SwitchAll.h" #include "command_classes/ZWavePlusInfo.h" #include "command_classes/DeviceResetLocally.h" #include "Scene.h" #include "value_classes/ValueID.h" #include "value_classes/Value.h" #include "value_classes/ValueBitSet.h" #include "value_classes/ValueBool.h" #include "value_classes/ValueButton.h" #include "value_classes/ValueByte.h" #include "value_classes/ValueDecimal.h" #include "value_classes/ValueInt.h" #include "value_classes/ValueRaw.h" #include "value_classes/ValueList.h" #include "value_classes/ValueSchedule.h" #include "value_classes/ValueShort.h" #include "value_classes/ValueString.h" #include "value_classes/ValueStore.h" using namespace OpenZWave; //----------------------------------------------------------------------------- // Statics //----------------------------------------------------------------------------- bool Node::s_deviceClassesLoaded = false; map Node::s_basicDeviceClasses; map Node::s_genericDeviceClasses; map Node::s_roleDeviceClasses; map Node::s_deviceTypeClasses; map Node::s_nodeTypes; static char const* c_queryStageNames[] = { "None", "ProtocolInfo", "Probe", "WakeUp", "NodeInfo", "NodePlusInfo", "SecurityReport", "Versions", "ManufacturerSpecific1", "Instances", "ManufacturerSpecific2", "Static", "CacheLoad", "Associations", "Neighbors", "Session", "Dynamic", "Configuration", "Complete" }; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Node::Node(uint32 const _homeId, uint8 const _nodeId) : m_queryStage(QueryStage_None), m_queryPending(false), m_queryConfiguration(false), m_queryRetries(0), m_protocolInfoReceived(false), m_basicprotocolInfoReceived(false), m_nodeInfoReceived(false), m_nodePlusInfoReceived(false), m_manufacturerSpecificClassReceived(false), m_nodeInfoSupported(true), m_refreshonNodeInfoFrame(true), m_nodeAlive(true), // assome live node m_listening(true), // assume we start out listening m_frequentListening(false), m_beaming(false), m_routing(false), m_maxBaudRate(0), m_version(0), m_security(false), m_homeId(_homeId), m_nodeId(_nodeId), m_basic(0), m_generic(0), m_specific(0), m_type(""), m_addingNode(false), m_manufacturerName(""), m_productName(""), m_nodeName(""), m_location(""), m_manufacturerId(0), m_productType(0), m_productId(0), m_deviceType(0), m_role(0), m_nodeType(0), m_secured(false), m_nodeCache( NULL), m_Product( NULL), m_fileConfigRevision(0), m_loadedConfigRevision( 0), m_latestConfigRevision(0), m_values(new Internal::VC::ValueStore()), m_sentCnt(0), m_sentFailed(0), m_retries(0), m_receivedCnt(0), m_receivedDups(0), m_receivedUnsolicited(0), m_lastRequestRTT(0), m_lastResponseRTT(0), m_averageRequestRTT(0), m_averageResponseRTT(0), m_quality(0), m_lastReceivedMessage(), m_errors(0), m_txStatusReportSupported(false), m_txTime(0), m_hops(0), m_ackChannel(0), m_lastTxChannel(0), m_routeScheme((TXSTATUS_ROUTING_SCHEME) 0), m_routeUsed { }, m_routeSpeed((TXSTATUS_ROUTE_SPEED) 0), m_routeTries(0), m_lastFailedLinkFrom(0), m_lastFailedLinkTo(0), m_lastnonce(0) { memset(m_neighbors, 0, sizeof(m_neighbors)); memset(m_nonces, 0, sizeof(m_nonces)); memset(m_rssi_1, 0, sizeof(m_rssi_1)); memset(m_rssi_2, 0, sizeof(m_rssi_2)); memset(m_rssi_3, 0, sizeof(m_rssi_3)); memset(m_rssi_4, 0, sizeof(m_rssi_4)); memset(m_rssi_5, 0, sizeof(m_rssi_5)); AddCommandClass(Internal::CC::NoOperation::StaticGetCommandClassId()); AddCommandClass(Internal::CC::ManufacturerSpecific::StaticGetCommandClassId()); } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- Node::~Node() { // Remove any messages from queues GetDriver()->RemoveQueues(m_nodeId); // Remove the values from the poll list for (Internal::VC::ValueStore::Iterator it = m_values->Begin(); it != m_values->End(); ++it) { ValueID const& valueId = it->second->GetID(); if (GetDriver()->isPolled(valueId)) { GetDriver()->DisablePoll(valueId); } } Internal::Scene::RemoveValues(m_homeId, m_nodeId); // Delete the values delete m_values; // Delete the command classes while (!m_commandClassMap.empty()) { map::iterator it = m_commandClassMap.begin(); delete it->second; m_commandClassMap.erase(it); } // Delete the groups while (!m_groups.empty()) { map::iterator it = m_groups.begin(); delete it->second; m_groups.erase(it); } // Delete the button map while (!m_buttonMap.empty()) { map::iterator it = m_buttonMap.begin(); m_buttonMap.erase(it); } delete m_nodeCache; } //----------------------------------------------------------------------------- // // Proceed through the initialisation process //----------------------------------------------------------------------------- void Node::AdvanceQueries() { // For OpenZWave to discover everything about a node, we have to follow a certain // order of queries, because the results of one stage may affect what is requested // in the next stage. The stage is saved with the node data, so that any incomplete // queries can be restarted the next time the application runs. // The individual command classes also store some state as to whether they have // had a response to certain queries. This state is initilized by the SetStaticRequests // call in QueryStage_None. It is also saved, so we do not need to request state // from every command class if some have previously responded. // // Each stage must generate all the messages for its particular stage as // assumptions are made in later code (RemoveMsg) that this is the case. This means // each stage is only visited once. Log::Write(LogLevel_Detail, m_nodeId, "AdvanceQueries queryPending=%d queryRetries=%d queryStage=%s live=%d", m_queryPending, m_queryRetries, c_queryStageNames[m_queryStage], m_nodeAlive); bool addQSC = false; // We only want to add a query stage complete if we did some work. while (!m_queryPending && m_nodeAlive) { switch (m_queryStage) { case QueryStage_None: { // Init the node query process m_queryStage = QueryStage_ProtocolInfo; m_queryRetries = 0; break; } case QueryStage_ProtocolInfo: { // determines, among other things, whether this node is a listener, its maximum baud rate and its device classes if (!ProtocolInfoReceived()) { Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_ProtocolInfo"); Internal::Msg* msg = new Internal::Msg("Get Node Protocol Info", m_nodeId, REQUEST, FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO, false); msg->Append(m_nodeId); GetDriver()->SendMsg(msg, Driver::MsgQueue_Query); m_queryPending = true; addQSC = true; } else { // This stage has been done already, so move to the Probe stage m_queryStage = QueryStage_Probe; m_queryRetries = 0; } break; } case QueryStage_Probe: { Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_Probe"); // // Send a NoOperation message to see if the node is awake // and alive. Based on the response or lack of response // will determine next step. // Internal::CC::NoOperation* noop = static_cast(GetCommandClass(Internal::CC::NoOperation::StaticGetCommandClassId())); /* don't Probe the Controller */ if (GetDriver()->GetControllerNodeId() != m_nodeId) { noop->Set(true); m_queryPending = true; addQSC = true; } else { m_queryStage = QueryStage_WakeUp; m_queryRetries = 0; } break; } case QueryStage_WakeUp: { // For sleeping devices other than controllers, we need to defer the usual requests until // we have told the device to send it's wake-up notifications to the PC controller. Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_WakeUp"); Internal::CC::WakeUp* wakeUp = static_cast(GetCommandClass(Internal::CC::WakeUp::StaticGetCommandClassId())); // if this device is a "sleeping device" and not a controller and not a // FLiRS device. FLiRS will wake up when you send them something and they // don't seem to support Wakeup if (wakeUp && !IsController() && !IsFrequentListeningDevice()) { // start the process of requesting node state from this sleeping device wakeUp->Init(); m_queryPending = true; addQSC = true; } else { // this is not a sleeping device, so move to the ManufacturerSpecific1 stage m_queryStage = QueryStage_NodeInfo; m_queryRetries = 0; } break; } case QueryStage_NodeInfo: { Log::Write(LogLevel_Info, GetNodeId(), "NodeInfo Stage - NodeInfoRecieved %d - NotInfoSupported %d", NodeInfoReceived(), m_nodeInfoSupported); if (!NodeInfoReceived() && m_nodeInfoSupported && (GetDriver()->GetControllerNodeId() != m_nodeId)) { // obtain from the node a list of command classes that it 1) supports and 2) controls (separated by a mark in the buffer) Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_NodeInfo"); Internal::Msg* msg = new Internal::Msg("Request Node Info", m_nodeId, REQUEST, FUNC_ID_ZW_REQUEST_NODE_INFO, false, true, FUNC_ID_ZW_APPLICATION_UPDATE); msg->Append(m_nodeId); GetDriver()->SendMsg(msg, Driver::MsgQueue_Query); m_queryPending = true; addQSC = true; } else { // This stage has been done already, so move to the Manufacturer Specific stage m_queryStage = QueryStage_NodePlusInfo; m_queryRetries = 0; } break; } case QueryStage_NodePlusInfo: { Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_NodePlusInfo"); Internal::CC::ZWavePlusInfo* pluscc = static_cast(GetCommandClass(Internal::CC::ZWavePlusInfo::StaticGetCommandClassId())); if (pluscc) { m_queryPending = pluscc->RequestState(Internal::CC::CommandClass::RequestFlag_Static, 1, Driver::MsgQueue_Query); } if (m_queryPending) { addQSC = m_queryPending; } else { // this is not a Zwave+ node, so move onto the next querystage m_queryStage = QueryStage_SecurityReport; m_queryRetries = 0; } break; } case QueryStage_SecurityReport: { /* For Devices that Support the Security Class, we have to request a list of * Command Classes that Require Security. */ Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_SecurityReport"); Internal::CC::Security* seccc = static_cast(GetCommandClass(Internal::CC::Security::StaticGetCommandClassId())); if (seccc) { // start the process setting up the Security CommandClass m_queryPending = seccc->Init(); /* Dont add a QueryStageComplete flag here, as this is a multipacket exchange. * the Security Command Class will automatically advance the Query Stage * when we recieve a SecurityCmd_SupportedReport */ addQSC = true; } else { // this is not a Security Device, so move onto the next querystage m_queryStage = QueryStage_Versions; m_queryRetries = 0; } break; } case QueryStage_Versions: { // Get the version information of CommandClasses that have not had their Version Retrieved So far. (most Likely ManufacturerSpecific) Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_Versions"); if (GetDriver()->GetControllerNodeId() == m_nodeId) { m_queryStage = QueryStage_ManufacturerSpecific1; m_queryRetries = 0; break; } Internal::CC::Version* vcc = static_cast(GetCommandClass(Internal::CC::Version::StaticGetCommandClassId())); if (!vcc) { vcc = static_cast(AddCommandClass(Internal::CC::Version::StaticGetCommandClassId())); } Log::Write(LogLevel_Info, m_nodeId, "Requesting Versions"); for (map::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it) { Internal::CC::CommandClass* cc = it->second; Log::Write(LogLevel_Info, m_nodeId, "Requesting Versions for %s - Max: %d - Current %d", cc->GetCommandClassName().c_str(), cc->GetMaxVersion(), cc->GetVersion()); if (cc->GetMaxVersion() > 1 && cc->GetVersion() == 0) { // Get the version for each supported command class that // we have implemented at greater than version one. m_queryPending |= vcc->RequestCommandClassVersion(it->second); } else if (cc->GetVersion() == 0) { // set the Version to 1 cc->SetVersion(1); } } addQSC = m_queryPending; // advance to Instances stage when finished if (!m_queryPending) { m_queryStage = QueryStage_ManufacturerSpecific1; m_queryRetries = 0; } break; } case QueryStage_ManufacturerSpecific1: { // Obtain manufacturer, product type and product ID code from the node device // Manufacturer Specific data is requested before the other command class data so // that we can modify the supported command classes list through the product XML files. Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_ManufacturerSpecific1"); /* if its the Controller, then we can just load up the XML straight away */ if (GetDriver()->GetControllerNodeId() == m_nodeId) { Log::Write(LogLevel_Detail, m_nodeId, "Load Controller Manufacturer Specific Config"); Internal::CC::ManufacturerSpecific* cc = static_cast(GetCommandClass(Internal::CC::ManufacturerSpecific::StaticGetCommandClassId())); if (cc) { cc->SetInstance(1); cc->SetProductDetails(GetDriver()->GetManufacturerId(), GetDriver()->GetProductType(), GetDriver()->GetProductId()); cc->LoadConfigXML(); } m_queryStage = QueryStage_Instances; m_queryRetries = 0; } else { Log::Write(LogLevel_Detail, m_nodeId, "Checking for ManufacturerSpecific CC and Requesting values if present on this node"); Internal::CC::ManufacturerSpecific* cc = static_cast(GetCommandClass(Internal::CC::ManufacturerSpecific::StaticGetCommandClassId())); if (cc) { cc->SetInstance(1); m_queryPending = cc->Init(); addQSC = m_queryPending; } if (!m_queryPending) { m_queryStage = QueryStage_Instances; m_queryRetries = 0; } } break; } case QueryStage_Instances: { // if the device at this node supports multiple instances, obtain a list of these instances Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_Instances"); Internal::CC::MultiInstance* micc = static_cast(GetCommandClass(Internal::CC::MultiInstance::StaticGetCommandClassId())); if (micc) { if (micc->IsAfterMark()) { Log::Write(LogLevel_Detail, m_nodeId, "Skipping RequestInstances() because MultiChannel CC is \"after mark\""); } else { m_queryPending = micc->RequestInstances(); addQSC = m_queryPending; } } // when done, advance to the Static stage if (!m_queryPending) { m_queryStage = QueryStage_ManufacturerSpecific2; m_queryRetries = 0; Log::Write(LogLevel_Info, m_nodeId, "Essential node queries are complete"); Notification* notification = new Notification(Notification::Type_EssentialNodeQueriesComplete); notification->SetHomeAndNodeIds(m_homeId, m_nodeId); GetDriver()->QueueNotification(notification); } break; } case QueryStage_ManufacturerSpecific2: { if (!m_manufacturerSpecificClassReceived) { // Obtain manufacturer, product type and product ID code from the node device // Manufacturer Specific data is requested before the other command class data so // that we can modify the supported command classes list through the product XML files. Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_ManufacturerSpecific2"); Internal::CC::ManufacturerSpecific* cc = static_cast(GetCommandClass(Internal::CC::ManufacturerSpecific::StaticGetCommandClassId())); /* don't do this if its the Controller Node */ if (cc && (GetDriver()->GetControllerNodeId() != m_nodeId)) { cc->SetInstance(1); m_queryPending = cc->RequestState(Internal::CC::CommandClass::RequestFlag_Static, 1, Driver::MsgQueue_Query); addQSC = m_queryPending; } if (!m_queryPending) { m_queryStage = QueryStage_Static; m_queryRetries = 0; } } else { m_queryStage = QueryStage_Static; m_queryRetries = 0; } break; } case QueryStage_Static: { // Request any other static values associated with each command class supported by this node // examples are supported thermostat operating modes, setpoints and fan modes Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_Static"); for (map::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it) { it->second->CreateVars(); /* Dont' do this for Controller Nodes */ if (GetDriver()->GetControllerNodeId() != m_nodeId) { if (!it->second->IsAfterMark()) { m_queryPending |= it->second->RequestStateForAllInstances(Internal::CC::CommandClass::RequestFlag_Static, Driver::MsgQueue_Query); } else { /* Controlling CC's might still need to retrieve some info */ m_queryPending |= it->second->RequestStateForAllInstances(Internal::CC::CommandClass::RequestFlag_AfterMark, Driver::MsgQueue_Query); } } } addQSC = m_queryPending; if (!m_queryPending) { // when all (if any) static information has been retrieved, advance to the Associations stage // CacheLoad stage is for Nodes that are read in via the zw state file, as is skipped as we would // have already queried it at the discovery phase in Probe. m_queryStage = QueryStage_Associations; m_queryRetries = 0; } break; } /* CacheLoad is where we start if we are loading a device from our zwcfg_*.xml file rather than * a brand new device. */ case QueryStage_CacheLoad: { Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_CacheLoad"); Log::Write(LogLevel_Info, GetNodeId(), "Loading Cache for node %d: Manufacturer=%s, Product=%s", GetNodeId(), GetManufacturerName().c_str(), GetProductName().c_str()); Log::Write(LogLevel_Info, GetNodeId(), "Node Identity Codes: %.4x:%.4x:%.4x", GetManufacturerId(), GetProductType(), GetProductId()); /* Don't do this if its to the Controller */ if (GetDriver()->GetControllerNodeId() != m_nodeId) { // // Send a NoOperation message to see if the node is awake // and alive. Based on the response or lack of response // will determine next step. Called here when configuration exists. // Internal::CC::NoOperation* noop = static_cast(GetCommandClass(Internal::CC::NoOperation::StaticGetCommandClassId())); noop->Set(true); m_queryPending = true; addQSC = true; } else { m_queryStage = QueryStage_Associations; m_queryRetries = 0; } break; } case QueryStage_Associations: { // if this device supports COMMAND_CLASS_ASSOCIATION, determine to which groups this node belong Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_Associations"); Internal::CC::MultiChannelAssociation* macc = static_cast(GetCommandClass(Internal::CC::MultiChannelAssociation::StaticGetCommandClassId())); if (macc) { macc->RequestAllGroups(0); m_queryPending = true; addQSC = true; } else { Internal::CC::Association* acc = static_cast(GetCommandClass(Internal::CC::Association::StaticGetCommandClassId())); if (acc) { acc->RequestAllGroups(0); m_queryPending = true; addQSC = true; } else { // if this device doesn't support Associations, move to retrieve Session information m_queryStage = QueryStage_Neighbors; m_queryRetries = 0; } } break; } case QueryStage_Neighbors: { // retrieves this node's neighbors and stores the neighbor bitmap in the node object Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_Neighbors"); GetDriver()->RequestNodeNeighbors(m_nodeId, 0); m_queryPending = true; addQSC = true; break; } case QueryStage_Session: { // Request the session values from the command classes in turn // examples of Session information are: current thermostat setpoints, node names and climate control schedules Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_Session"); for (map::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it) { if (!it->second->IsAfterMark()) { m_queryPending |= it->second->RequestStateForAllInstances(Internal::CC::CommandClass::RequestFlag_Session, Driver::MsgQueue_Query); } } addQSC = m_queryPending; if (!m_queryPending) { m_queryStage = QueryStage_Dynamic; m_queryRetries = 0; } break; } case QueryStage_Dynamic: { // Request the dynamic values from the node, that can change at any time // Examples include on/off state, heating mode, temperature, etc. Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_Dynamic"); m_queryPending = RequestDynamicValues(); addQSC = m_queryPending; if (!m_queryPending) { m_queryStage = QueryStage_Configuration; m_queryRetries = 0; } break; } case QueryStage_Configuration: { // Request the configurable parameter values from the node. Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_Configuration"); if (m_queryConfiguration) { if (RequestAllConfigParams(0)) { m_queryPending = true; addQSC = true; } m_queryConfiguration = false; } if (!m_queryPending) { m_queryStage = QueryStage_Complete; m_queryRetries = 0; } break; } case QueryStage_Complete: { ClearAddingNode(); // Notify the watchers that the queries are complete for this node Log::Write(LogLevel_Detail, m_nodeId, "QueryStage_Complete"); Notification* notification = new Notification(Notification::Type_NodeQueriesComplete); notification->SetHomeAndNodeIds(m_homeId, m_nodeId); GetDriver()->QueueNotification(notification); /* if its a sleeping node, this will send a NoMoreInformation Packet to the device */ Internal::CC::WakeUp* cc = static_cast(GetCommandClass(Internal::CC::WakeUp::StaticGetCommandClassId())); if (cc) { cc->SendPending(); } // Check whether all nodes are now complete GetDriver()->CheckCompletedNodeQueries(); return; } default: { break; } } } if (addQSC && m_nodeAlive) { // Add a marker to the query queue so this advance method // gets called again once this stage has completed. GetDriver()->SendQueryStageComplete(m_nodeId, m_queryStage); } } //----------------------------------------------------------------------------- // // We are done with a stage in the query process //----------------------------------------------------------------------------- void Node::QueryStageComplete(QueryStage const _stage) { // Check that we are actually on the specified stage if (_stage != m_queryStage) { return; } if (m_queryStage != QueryStage_Complete) { // Move to the next stage m_queryPending = false; m_queryStage = (QueryStage) ((uint32) m_queryStage + 1); if (m_queryStage == QueryStage_CacheLoad) { m_queryStage = (QueryStage) ((uint32) m_queryStage + 1); } m_queryRetries = 0; } } //----------------------------------------------------------------------------- // // Retry a stage up to the specified maximum //----------------------------------------------------------------------------- void Node::QueryStageRetry(QueryStage const _stage, uint8 const _maxAttempts // = 0 ) { Log::Write(LogLevel_Info, m_nodeId, "QueryStageRetry stage %s requested stage %s max %d retries %d pending %d", c_queryStageNames[_stage], c_queryStageNames[m_queryStage], _maxAttempts, m_queryRetries, m_queryPending); // Check that we are actually on the specified stage if (_stage != m_queryStage) { return; } m_queryPending = false; if (_maxAttempts && (++m_queryRetries >= _maxAttempts)) { m_queryRetries = 0; // We've retried too many times. Move to the next stage but only if // we aren't in any of the probe stages. if (m_queryStage != QueryStage_Probe && m_queryStage != QueryStage_CacheLoad) { m_queryStage = (Node::QueryStage) ((uint32) (m_queryStage + 1)); } } // Repeat the current query stage GetDriver()->RetryQueryStageComplete(m_nodeId, m_queryStage); } //----------------------------------------------------------------------------- // // Set the query stage (but only to an earlier stage) //----------------------------------------------------------------------------- void Node::SetQueryStage(QueryStage const _stage, bool const _advance // = true ) { if ((int) _stage < (int) m_queryStage) { m_queryStage = _stage; m_queryPending = false; if (QueryStage_Configuration == _stage) { m_queryConfiguration = true; } } if (_advance) { AdvanceQueries(); } } //----------------------------------------------------------------------------- // // Gets the query stage name //----------------------------------------------------------------------------- string Node::GetQueryStageName(QueryStage const _stage) { return c_queryStageNames[_stage]; } //----------------------------------------------------------------------------- // // Gets the neighbors of a node //----------------------------------------------------------------------------- uint32 Node::GetNeighbors(uint8** o_neighbors) { // determine how many neighbors there are int i; uint32 numNeighbors = 0; if (m_queryStage < QueryStage_Session) { *o_neighbors = NULL; return 0; } for (i = 0; i < 29; i++) { for (unsigned char mask = 0x80; mask != 0; mask >>= 1) if ((m_neighbors[i] & mask) != 0) numNeighbors++; } // handle the possibility that no neighbors are reported if (!numNeighbors) { *o_neighbors = NULL; return 0; } // create and populate an array with neighbor node ids uint8* neighbors = new uint8[numNeighbors]; uint32 index = 0; for (int by = 0; by < 29; by++) { for (int bi = 0; bi < 8; bi++) { if ((m_neighbors[by] & (0x01 << bi))) neighbors[index++] = ((by << 3) + bi + 1); } } *o_neighbors = neighbors; return numNeighbors; } //----------------------------------------------------------------------------- // // Read the node config from the OZW Cache File... //----------------------------------------------------------------------------- void Node::ReadXML(TiXmlElement const* _node) { char const* str; int intVal; str = _node->Attribute("query_stage"); if (str) { // After restoring state from a file, we need to at least refresh the session and dynamic values. QueryStage queryStage = QueryStage_Session; for (uint32 i = 0; i < (uint32) QueryStage_Session; ++i) { if (!strcmp(str, c_queryStageNames[i])) { queryStage = (QueryStage) i; break; } } /* we cant use the SetQueryStage method here, as it only allows us to * go to a lower QueryStage, and not a higher QueryStage. As QueryStage_Complete is higher than * QueryStage_None (the default) we manually set it here. Note - in Driver::HandleSerialAPIGetInitDataResponse the * QueryStage is set to CacheLoad (which is less than QueryStage_Associations) if this is a existing node read in via the zw state file. * */ m_queryStage = queryStage; m_queryPending = false; if (QueryStage_Configuration == queryStage) { m_queryConfiguration = true; } } if (m_queryStage != QueryStage_None) { if (m_queryStage > QueryStage_ProtocolInfo) { // Notify the watchers of the protocol info. // We do the notification here so that it gets into the queue ahead of // any other notifications generated by adding command classes etc. m_protocolInfoReceived = true; Notification* notification = new Notification(Notification::Type_NodeProtocolInfo); notification->SetHomeAndNodeIds(m_homeId, m_nodeId); GetDriver()->QueueNotification(notification); } if (m_queryStage > QueryStage_NodeInfo) { m_nodeInfoReceived = true; } if (m_queryStage > QueryStage_Static) { Notification* notification = new Notification(Notification::Type_EssentialNodeQueriesComplete); notification->SetHomeAndNodeIds(m_homeId, m_nodeId); GetDriver()->QueueNotification(notification); } if (m_queryStage > QueryStage_CacheLoad) { m_nodeCache = _node->Clone(); } } str = _node->Attribute("name"); if (str) { m_nodeName = str; } str = _node->Attribute("location"); if (str) { m_location = str; } if (TIXML_SUCCESS == _node->QueryIntAttribute("basic", &intVal)) { m_basic = (uint8) intVal; } if (TIXML_SUCCESS == _node->QueryIntAttribute("generic", &intVal)) { m_generic = (uint8) intVal; } if (TIXML_SUCCESS == _node->QueryIntAttribute("specific", &intVal)) { m_specific = (uint8) intVal; } if (TIXML_SUCCESS == _node->QueryIntAttribute("roletype", &intVal)) { m_role = (uint8) intVal; m_nodePlusInfoReceived = true; } if (TIXML_SUCCESS == _node->QueryIntAttribute("devicetype", &intVal)) { m_deviceType = (uint16) intVal; m_nodePlusInfoReceived = true; } if (TIXML_SUCCESS == _node->QueryIntAttribute("nodetype", &intVal)) { m_nodeType = (uint8) intVal; m_nodePlusInfoReceived = true; } str = _node->Attribute("type"); if (str) { m_type = str; } m_listening = true; str = _node->Attribute("listening"); if (str) { m_listening = !strcmp(str, "true"); } m_frequentListening = false; str = _node->Attribute("frequentListening"); if (str) { m_frequentListening = !strcmp(str, "true"); } m_beaming = false; str = _node->Attribute("beaming"); if (str) { m_beaming = !strcmp(str, "true"); } m_routing = true; str = _node->Attribute("routing"); if (str) { m_routing = !strcmp(str, "true"); } m_maxBaudRate = 0; if (TIXML_SUCCESS == _node->QueryIntAttribute("max_baud_rate", &intVal)) { m_maxBaudRate = (uint32) intVal; } m_version = 0; if (TIXML_SUCCESS == _node->QueryIntAttribute("version", &intVal)) { m_version = (uint8) intVal; } m_security = false; str = _node->Attribute("security"); if (str) { m_security = !strcmp(str, "true"); } m_secured = false; str = _node->Attribute("secured"); if (str) { m_secured = !strcmp(str, "true"); } m_nodeInfoSupported = true; str = _node->Attribute("nodeinfosupported"); if (str) { m_nodeInfoSupported = !strcmp(str, "true"); } m_refreshonNodeInfoFrame = true; str = _node->Attribute("refreshonnodeinfoframe"); if (str) m_refreshonNodeInfoFrame = !strcmp(str, "true"); /* this is the revision of the config file that was present when we created the cache */ str = _node->Attribute("configrevision"); if (str) this->setLoadedConfigRevision(atol(str)); else this->setLoadedConfigRevision(0); // Read the manufacturer info and create the command classes TiXmlElement const* child = _node->FirstChildElement(); while (child) { str = child->Value(); if (str) { if (!strcmp(str, "Neighbors")) { TiXmlNode const *NeighborList = child->FirstChild(); char const *neighbors = NeighborList->Value(); int i = 0; char* pos = const_cast(neighbors); while (*pos && i < 29) { m_neighbors[i] = strtol(pos, &pos, 10); if ((*pos) == ',') { ++pos; ++i; } } } else if (!strcmp(str, "CommandClasses")) { ReadCommandClassesXML(child); } else if (!strcmp(str, "Manufacturer")) { uint16 manufacturerId = 0; uint16 productType = 0; uint16 productId = 0; str = child->Attribute("id"); if (str) { manufacturerId = (uint16_t) (strtol(str, NULL, 16) & 0xFFFF); } str = child->Attribute("name"); if (str) { m_manufacturerName = str; } TiXmlElement const* product = child->FirstChildElement(); if (!strcmp(product->Value(), "Product")) { str = product->Attribute("type"); if (str) { productType = (uint16_t) (strtol(str, NULL, 16) & 0xFFFF); } str = product->Attribute("id"); if (str) { productId = (uint16_t) (strtol(str, NULL, 16) & 0xFFFF); } str = product->Attribute("name"); if (str) { m_productName = str; } Internal::CC::ManufacturerSpecific* cc = static_cast(GetCommandClass(Internal::CC::ManufacturerSpecific::StaticGetCommandClassId())); if (cc) { cc->SetProductDetails(manufacturerId, productType, productId); cc->setLoadedConfigRevision(m_loadedConfigRevision); } else { Log::Write(LogLevel_Warning, GetNodeId(), "ManufacturerSpecific Class not loaded for ReadXML"); } ReadMetaDataFromXML(product); } } } // Move to the next child node child = child->NextSiblingElement(); } if (m_nodeName.length() > 0 || m_location.length() > 0 || m_manufacturerId > 0) { // Notify the watchers of the name changes Notification* notification = new Notification(Notification::Type_NodeNaming); notification->SetHomeAndNodeIds(m_homeId, m_nodeId); GetDriver()->QueueNotification(notification); } } //----------------------------------------------------------------------------- // // Read the device's protocol configuration from a device config file (Not // cache) //----------------------------------------------------------------------------- void Node::ReadDeviceProtocolXML(TiXmlElement const* _ccsElement) { char const *str = _ccsElement->Attribute("Revision"); if (str) { /* as we are loading the Node from the device config file, both the * File and Loaded Revisions will be the same */ this->setFileConfigRevision(atol(str)); this->setLoadedConfigRevision(m_fileConfigRevision); Log::Write(LogLevel_Info, GetNodeId(), " Configuration File Revision is %d", m_fileConfigRevision); } else { this->setFileConfigRevision(0); this->setLoadedConfigRevision(m_fileConfigRevision); } TiXmlElement const* ccElement = _ccsElement->FirstChildElement(); while (ccElement) { str = ccElement->Value(); if (str && !strcmp(str, "Protocol")) { str = ccElement->Attribute("nodeinfosupported"); if (str) { m_nodeInfoSupported = !strcmp(str, "true"); } str = ccElement->Attribute("refreshonnodeinfoframe"); if (str) { m_refreshonNodeInfoFrame = !strcmp(str, "true"); } // Some controllers support API calls that aren't advertised in their returned data. // So provide a way to manipulate the returned data to reflect reality. TiXmlElement const* childElement = _ccsElement->FirstChildElement(); while (childElement) { str = childElement->Value(); if (str && !strcmp(str, "APIcall")) { char const* funcStr = childElement->Attribute("function"); char *p; uint8 func = (uint8) strtol(funcStr, &p, 16); if (p != funcStr) { char const* presStr = ccElement->Attribute("present"); GetDriver()->SetAPICall(func, !strcmp(presStr, "true")); } } childElement = childElement->NextSiblingElement(); } return; } ccElement = ccElement->NextSiblingElement(); } } //----------------------------------------------------------------------------- // // Read the command classes from XML //----------------------------------------------------------------------------- void Node::ReadCommandClassesXML(TiXmlElement const* _ccsElement) { char const* str; int32 intVal; TiXmlElement const* ccElement = _ccsElement->FirstChildElement(); while (ccElement) { str = ccElement->Value(); if (str && !strcmp(str, "CommandClass")) { if (TIXML_SUCCESS == ccElement->QueryIntAttribute("id", &intVal)) { uint8 id = (uint8) intVal; // Check whether this command class is to be removed (product XMLs might // request this if a class is not implemented properly by the device) bool remove = false; char const* action = ccElement->Attribute("action"); if (action && !strcasecmp(action, "remove")) { remove = true; } Internal::CC::CommandClass* cc = GetCommandClass(id); if (remove) { // Remove support for the command class RemoveCommandClass(id); } else { if ( NULL == cc) { if (Internal::CC::Security::StaticGetCommandClassId() == id && !GetDriver()->isNetworkKeySet()) { Log::Write(LogLevel_Warning, "Security Command Class cannot be Loaded. NetworkKey is not set"); ccElement = ccElement->NextSiblingElement(); continue; } // Command class support does not exist yet, so we create it cc = AddCommandClass(id); } if ( NULL != cc) { cc->ReadXML(ccElement); } } } } ccElement = ccElement->NextSiblingElement(); } } //----------------------------------------------------------------------------- // // Save the static node configuration data //----------------------------------------------------------------------------- void Node::WriteXML(TiXmlElement* _driverElement) { if (m_queryStage <= QueryStage_CacheLoad) { /* Just return our cached copy of the "Cache" as nothing new should be here */ _driverElement->LinkEndChild(m_nodeCache->Clone()); return; } char str[32]; TiXmlElement* nodeElement = new TiXmlElement("Node"); _driverElement->LinkEndChild(nodeElement); snprintf(str, 32, "%d", m_nodeId); nodeElement->SetAttribute("id", str); nodeElement->SetAttribute("name", m_nodeName.c_str()); nodeElement->SetAttribute("location", m_location.c_str()); snprintf(str, 32, "%d", m_basic); nodeElement->SetAttribute("basic", str); snprintf(str, 32, "%d", m_generic); nodeElement->SetAttribute("generic", str); snprintf(str, 32, "%d", m_specific); nodeElement->SetAttribute("specific", str); if (m_nodePlusInfoReceived) { snprintf(str, 32, "%d", m_role); nodeElement->SetAttribute("roletype", str); snprintf(str, 32, "%d", m_deviceType); nodeElement->SetAttribute("devicetype", str); snprintf(str, 32, "%d", m_nodeType); nodeElement->SetAttribute("nodetype", str); } nodeElement->SetAttribute("type", m_type.c_str()); nodeElement->SetAttribute("listening", m_listening ? "true" : "false"); nodeElement->SetAttribute("frequentListening", m_frequentListening ? "true" : "false"); nodeElement->SetAttribute("beaming", m_beaming ? "true" : "false"); nodeElement->SetAttribute("routing", m_routing ? "true" : "false"); snprintf(str, 32, "%d", m_maxBaudRate); nodeElement->SetAttribute("max_baud_rate", str); snprintf(str, 32, "%d", m_version); nodeElement->SetAttribute("version", str); if (m_security) { nodeElement->SetAttribute("security", "true"); } if (m_secured) { nodeElement->SetAttribute("secured", "true"); } if (!m_nodeInfoSupported) { nodeElement->SetAttribute("nodeinfosupported", "false"); } if (!m_refreshonNodeInfoFrame) { nodeElement->SetAttribute("refreshonnodeinfoframe", "false"); } snprintf(str, 32, "%d", m_loadedConfigRevision); nodeElement->SetAttribute("configrevision", str); nodeElement->SetAttribute("query_stage", c_queryStageNames[m_queryStage]); TiXmlElement* neighborElement = new TiXmlElement("Neighbors"); nodeElement->LinkEndChild(neighborElement); { std::string NeighborList; for (int i = 0; i < 29; i++) { if ((i > 0) && (i != 29)) NeighborList.append(","); NeighborList.append(Internal::intToString(m_neighbors[i])); } TiXmlText* textElement = new TiXmlText(NeighborList.c_str()); neighborElement->LinkEndChild(textElement); } // Write the manufacturer and product data in the same format // as used in the ManyfacturerSpecfic.xml file. This will // allow new devices to be added via a simple cut and paste. TiXmlElement* manufacturerElement = new TiXmlElement("Manufacturer"); nodeElement->LinkEndChild(manufacturerElement); /* this should be written in hex to avoid confusion... */ { std::stringstream ss; ss << std::hex << m_manufacturerId; manufacturerElement->SetAttribute("id", ss.str().c_str()); } manufacturerElement->SetAttribute("name", m_manufacturerName.c_str()); TiXmlElement* productElement = new TiXmlElement("Product"); manufacturerElement->LinkEndChild(productElement); /* this should be written in hex to avoid confusion... */ { std::stringstream ss; ss << std::hex << m_productType; productElement->SetAttribute("type", ss.str().c_str()); } /* this should be written in hex to avoid confusion... */ { std::stringstream ss; ss << std::hex << m_productId; productElement->SetAttribute("id", ss.str().c_str()); } productElement->SetAttribute("name", m_productName.c_str()); // Write the MetaData out TiXmlElement* mdElement = new TiXmlElement("MetaData"); productElement->LinkEndChild(mdElement); WriteMetaDataXML(mdElement); // Write the command classes TiXmlElement* ccsElement = new TiXmlElement("CommandClasses"); nodeElement->LinkEndChild(ccsElement); for (map::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it) { if (it->second->GetCommandClassId() == Internal::CC::NoOperation::StaticGetCommandClassId()) // don't output NoOperation { continue; } TiXmlElement* ccElement = new TiXmlElement("CommandClass"); ccsElement->LinkEndChild(ccElement); it->second->WriteXML(ccElement); } } //----------------------------------------------------------------------------- // // Handle the FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO response //----------------------------------------------------------------------------- void Node::UpdateProtocolInfo(uint8 const* _data) { if (ProtocolInfoReceived()) { // We already have this info return; } if (_data[4] == 0) { // Node doesn't exist if Generic class is zero. Log::Write(LogLevel_Info, m_nodeId, " Protocol Info for Node %d reports node nonexistent", m_nodeId); SetNodeAlive(false); return; } // Capabilities m_listening = ((_data[0] & 0x80) != 0); m_routing = ((_data[0] & 0x40) != 0); m_maxBaudRate = 9600; if ((_data[0] & 0x38) == 0x10) { m_maxBaudRate = 40000; } // Reverse engineered by looking at Zniffer capture of crafted NIF packets // Note 2019-05-19 I have never seen a 200k device, but Zniffer decodes it, // this is not a typo... int speed_extension = _data[2] & 0x07; switch (speed_extension) { case 0: // No speed_extension break; case 1: m_maxBaudRate = 100000; break; case 2: m_maxBaudRate = 200000; break; default: Log::Write(LogLevel_Warning, m_nodeId, " Protocol Info speed_extension = %d is 'Reserved', reported Max Baud Rate might be wrong.", speed_extension); break; } m_version = (_data[0] & 0x07) + 1; m_frequentListening = ((_data[1] & (SecurityFlag_Sensor250ms | SecurityFlag_Sensor1000ms)) != 0); m_beaming = ((_data[1] & SecurityFlag_BeamCapability) != 0); // Security m_security = ((_data[1] & SecurityFlag_Security) != 0); // Optional flag is true if the device reports optional command classes. // NOTE: We stopped using this because not all devices report it properly, // and now just request the optional classes regardless. // bool optional = (( _data[1] & 0x80 ) != 0 ); /* dont do any further processing if we have already received our Protocol Info, or basicprotocolInfo */ if (ProtocolInfoReceived()) { // We already have this info return; } Log::Write(LogLevel_Info, m_nodeId, " Protocol Info for Node %d:", m_nodeId); if (m_listening) Log::Write(LogLevel_Info, m_nodeId, " Listening = true"); else { Log::Write(LogLevel_Info, m_nodeId, " Listening = false"); Log::Write(LogLevel_Info, m_nodeId, " Frequent = %s", m_frequentListening ? "true" : "false"); } Log::Write(LogLevel_Info, m_nodeId, " Beaming = %s", m_beaming ? "true" : "false"); Log::Write(LogLevel_Info, m_nodeId, " Routing = %s", m_routing ? "true" : "false"); Log::Write(LogLevel_Info, m_nodeId, " Max Baud Rate = %d", m_maxBaudRate); Log::Write(LogLevel_Info, m_nodeId, " Version = %d", m_version); Log::Write(LogLevel_Info, m_nodeId, " Security = %s", m_security ? "true" : "false"); if (m_basicprotocolInfoReceived == false) { // Notify the watchers of the protocol info. // We do the notification here so that it gets into the queue ahead of // any other notifications generated by adding command classes etc. Notification* notification = new Notification(Notification::Type_NodeProtocolInfo); notification->SetHomeAndNodeIds(m_homeId, m_nodeId); GetDriver()->QueueNotification(notification); // Set up the device class based data for the node, including mandatory command classes SetDeviceClasses(_data[3], _data[4], _data[5]); // Do this for every controller. A little extra work but it won't be a large file. if (IsController()) { GetDriver()->ReadButtons(m_nodeId); } #if 0 /* come back to this. We need to find a better way to Route Messages * from Nodes to CC's that are advertised by the ControllerNode */ /* load the Advertised CommandClasses on the Controller Node * */ if( GetDriver()->GetControllerNodeId() == m_nodeId ) { Log::Write( LogLevel_Info, m_nodeId, " Advertised CommandClasses on Controller Node:"); list advertisedCommandClasses = CommandClasses::GetAdvertisedCommandClasses(); for (list::iterator it = advertisedCommandClasses.begin(); it != advertisedCommandClasses.end(); ++it) { CommandClass *cc = AddCommandClass(*it, true); if ( cc ) { Log::Write(LogLevel_Info, m_nodeId, " %s", cc->GetCommandClassName().c_str()); } } } #endif m_basicprotocolInfoReceived = true; } /* we have to setup the Wakeup CC if needed here, because * it wouldn't have been created in the SetProtocolInfo function, as we didn't * have the Device Flags then */ if (!m_listening && !IsFrequentListeningDevice()) { // Device does not always listen, so we need the WakeUp handler. We can't // wait for the command class list because the request for the command // classes may need to go in the wakeup queue itself! if (Internal::CC::CommandClass* pCommandClass = AddCommandClass(Internal::CC::WakeUp::StaticGetCommandClassId())) { pCommandClass->SetInstance(1); } } m_protocolInfoReceived = true; } void Node::SetProtocolInfo(uint8 const* _protocolInfo, uint8 const _length) { if (ProtocolInfoReceived() || m_basicprotocolInfoReceived == true) { // We already have this info return; } if (_protocolInfo[1] == 0) { // Node doesn't exist if Generic class is zero. Log::Write(LogLevel_Info, m_nodeId, " Protocol Info for Node %d reports node nonexistent", m_nodeId); SetNodeAlive(false); return; } // Notify the watchers of the protocol info. // We do the notification here so that it gets into the queue ahead of // any other notifications generated by adding command classes etc. Notification* notification = new Notification(Notification::Type_NodeProtocolInfo); notification->SetHomeAndNodeIds(m_homeId, m_nodeId); GetDriver()->QueueNotification(notification); // Set up the device class based data for the node, including mandatory command classes SetDeviceClasses(_protocolInfo[0], _protocolInfo[1], _protocolInfo[2]); /* Remaining Bytes in _protocolInfo are the CommandClasses this device supports */ /* first iterate over them and check for the Security CC, as we want to quickly start exchanging the Network Keys * first (before other CC's start sending stuff and slowing down our exchange */ if (m_secured) { if (Internal::CC::Security *pCommandClass = static_cast(GetCommandClass(Internal::CC::Security::StaticGetCommandClassId()))) { /* Security CC has already been loaded, most likely via the SetDeviceClasses Function above */ if (!GetDriver()->isNetworkKeySet()) { Log::Write(LogLevel_Warning, m_nodeId, "Security Command Class Disabled. NetworkKey is not Set"); } else { pCommandClass->ExchangeNetworkKeys(); } } else { /* Security CC is not loaded, see if its in our NIF frame and load if necessary */ for (int i = 3; i < _length; i++) { if (_protocolInfo[i] == Internal::CC::Security::StaticGetCommandClassId()) { pCommandClass = static_cast(AddCommandClass(_protocolInfo[i])); if (!GetDriver()->isNetworkKeySet()) { Log::Write(LogLevel_Warning, m_nodeId, "Security Command Class Disabled. NetworkKey is not Set"); } else { pCommandClass->ExchangeNetworkKeys(); } } } } } UpdateNodeInfo(&_protocolInfo[3], _length - 3); m_basicprotocolInfoReceived = true; } void Node::SetSecured(bool secure) { m_secured = secure; } bool Node::IsSecured() { return m_secured; } void Node::SetInstanceLabel(uint8 const _instance, char *label) { m_globalInstanceLabel[_instance] = string(label); Driver *driver = GetDriver(); if (driver) driver->WriteCache(); } string Node::GetInstanceLabel(uint8 const _ccid, uint8 const _instance) { string label; /* find the CommandClass */ Internal::CC::CommandClass *_cc = GetCommandClass(_ccid); if (_cc) label = _cc->GetInstanceLabel(_instance); /* if the Label is Empty - Then use the Global Label */ if (label.empty()) { if (m_globalInstanceLabel.count(_instance)) label = m_globalInstanceLabel[_instance]; else { /* construct a Default Label */ std::ostringstream sstream; sstream << Internal::Localization::Get()->GetGlobalLabel("Instance") << " " << (int) _instance << ":"; label = sstream.str(); } } return label; } uint8 Node::GetNumInstances(uint8 const _ccid) { uint8 ccid = _ccid; int instances = 1; if (_ccid == 0) { ccid = Internal::CC::MultiInstance::StaticGetCommandClassId(); } if (Internal::CC::CommandClass *cc = GetCommandClass(ccid)) { return cc->GetNumInstances(); } return instances; } string Node::GetBasicString() { char str[32]; string label; uint8 _basic = GetBasic(); snprintf(str, sizeof(str), "Basic 0x%.2x", _basic); label = str; // Read in the device class data if it has not been read already. if (!s_deviceClassesLoaded) { ReadDeviceClasses(); } if (s_basicDeviceClasses.find(_basic) != s_basicDeviceClasses.end()) { return s_basicDeviceClasses.at(_basic); } return "Unknown"; } uint8 Node::GetGeneric(uint8 const _instance) const { if (_instance > 0) { if (Internal::CC::MultiInstance *cc = static_cast(GetCommandClass(Internal::CC::MultiInstance::StaticGetCommandClassId()))) { return cc->GetGenericInstanceDeviceType(_instance); } } return m_generic; } string Node::GetGenericString(uint8 const _instance) { char str[32]; string label; uint8 _generic = GetGeneric(_instance); snprintf(str, sizeof(str), "Generic 0x%.2x", _generic); label = str; // Read in the device class data if it has not been read already. if (!s_deviceClassesLoaded) { ReadDeviceClasses(); } // Get the Generic device class label if (s_genericDeviceClasses.find(_generic) != s_genericDeviceClasses.end()) { GenericDeviceClass* genericDeviceClass = s_genericDeviceClasses.at(_generic); label = genericDeviceClass->GetLabel(); } return label; } uint8 Node::GetSpecific(uint8 const _instance) const { if (_instance > 0) { if (Internal::CC::MultiInstance *cc = static_cast(GetCommandClass(Internal::CC::MultiInstance::StaticGetCommandClassId()))) { return cc->GetSpecificInstanceDeviceType(_instance); } } return m_specific; } string Node::GetSpecificString(uint8 const _instance) { char str[32]; string label; uint8 _generic = GetGeneric(_instance); uint8 _specific = GetSpecific(_instance); snprintf(str, sizeof(str), "Specific 0x%.2x", _specific); label = str; // Read in the device class data if it has not been read already. if (!s_deviceClassesLoaded) { ReadDeviceClasses(); } // Get the Generic device class label if (s_genericDeviceClasses.find(_generic) != s_genericDeviceClasses.end()) { GenericDeviceClass* genericDeviceClass = s_genericDeviceClasses.at(_generic); label = genericDeviceClass->GetLabel(); // Override with any specific device class label if (DeviceClass* specificDeviceClass = genericDeviceClass->GetSpecificDeviceClass(_specific)) { label = specificDeviceClass->GetLabel(); } } return label; } void Node::SetSecuredClasses(uint8 const* _data, uint8 const _length, uint32 const _instance) { uint32 i; m_secured = true; Log::Write(LogLevel_Info, m_nodeId, " Secured CommandClasses for node %d (instance %d):", m_nodeId, _instance); Log::Write(LogLevel_Info, m_nodeId, " Controlled CommandClasses:"); if (!GetDriver()->isNetworkKeySet()) { Log::Write(LogLevel_Warning, m_nodeId, " Secured CommandClasses cannot be enabled as Network Key is not set"); return; } bool afterMark = false; for (i = 0; i < _length; ++i) { if (_data[i] == 0xef) { // COMMAND_CLASS_MARK. // Marks the end of the list of supported command classes. The remaining classes // are those that can be controlled by the device. These classes are created // without values. Messages received cause notification events instead. afterMark = true; Log::Write(LogLevel_Info, m_nodeId, " Controlling CommandClasses:"); continue; } /* Check if this is a CC that is already registered with the node */ if (Internal::CC::CommandClass *pCommandClass = GetCommandClass(_data[i])) { /* if it was specified the he NIF frame, and came in as part of the Security SupportedReport message * then it can support both Clear Text and Secured Comms. So do a check first */ if (pCommandClass->IsInNIF()) { /* if the CC Supports Security and our SecurityStrategy says we should encrypt it, then mark it as encrypted */ if (pCommandClass->IsSecureSupported() && (Internal::ShouldSecureCommandClass(_data[i]) == Internal::SecurityStrategy_Supported)) { pCommandClass->SetSecured(); Log::Write(LogLevel_Info, m_nodeId, " %s (Secured) - %s", pCommandClass->GetCommandClassName().c_str(), pCommandClass->IsInNIF() ? "InNIF" : "NotInNIF"); } /* if it wasn't in the NIF frame, then it will only support Secured Comms. */ } else { if (pCommandClass->IsSecureSupported()) { pCommandClass->SetSecured(); Log::Write(LogLevel_Info, m_nodeId, " %s (Secured) - %s", pCommandClass->GetCommandClassName().c_str(), pCommandClass->IsInNIF() ? "InNIF" : "NotInNIF"); } } if (_instance > 1) { /* we need to get the endpoint from the Security CC, to map over to the target CC if this * is triggered by a SecurityCmd_SupportedReport from a instance */ Internal::CC::CommandClass *secc = GetCommandClass(Internal::CC::Security::StaticGetCommandClassId()); int ep = secc->GetEndPoint(_instance); pCommandClass->SetEndPoint(_instance, ep); pCommandClass->SetInstance(_instance); } } /* it might be a new CC we havn't seen as part of the NIF. In that case * its only supported via the Security CC, so no need to check our SecurityStrategy, just * encrypt it regardless */ else if (Internal::CC::CommandClasses::IsSupported(_data[i])) { if (Internal::CC::CommandClass* pCommandClass = AddCommandClass(_data[i])) { // If this class came after the COMMAND_CLASS_MARK, then we do not create values. if (afterMark) { pCommandClass->SetAfterMark(); } if (pCommandClass->IsSecureSupported()) { pCommandClass->SetSecured(); Log::Write(LogLevel_Info, m_nodeId, " %s (Secured) - %s", pCommandClass->GetCommandClassName().c_str(), pCommandClass->IsInNIF() ? "InNIF" : "NotInNIF"); } // Start with an instance count of one. If the device supports COMMMAND_CLASS_MULTI_INSTANCE // then some command class instance counts will increase once the responses to the RequestState // call at the end of this method have been processed. if (_instance > 1) pCommandClass->SetInstance(_instance); else pCommandClass->SetInstance(1); } } else { Log::Write(LogLevel_Info, m_nodeId, " Secure CommandClass 0x%.2x - NOT SUPPORTED", _data[i]); } } Log::Write(LogLevel_Info, m_nodeId, " UnSecured command classes for node %d (instance %d):", m_nodeId, _instance); for (map::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it) { if (!it->second->IsSecured()) Log::Write(LogLevel_Info, m_nodeId, " %s (Unsecured) - %s", it->second->GetCommandClassName().c_str(), it->second->IsInNIF() ? "InNIF" : "NotInNIF"); } SetStaticRequests(); } //----------------------------------------------------------------------------- // // Set up the command classes from the node info frame //----------------------------------------------------------------------------- void Node::UpdateNodeInfo(uint8 const* _data, uint8 const _length) { if (!NodeInfoReceived()) { // Add the command classes specified by the device Log::Write(LogLevel_Info, m_nodeId, " Optional CommandClasses for node %d:", m_nodeId); bool newCommandClasses = false; uint32 i; bool afterMark = false; for (i = 0; i < _length; ++i) { if (_data[i] == 0xef) { // COMMAND_CLASS_MARK. // Marks the end of the list of supported command classes. The remaining classes // are those that can be controlled by the device. These classes are created // without values. Messages received cause notification events instead. afterMark = true; if (!newCommandClasses) { Log::Write(LogLevel_Info, m_nodeId, " None"); } Log::Write(LogLevel_Info, m_nodeId, " Optional CommandClasses controlled by node %d:", m_nodeId); newCommandClasses = false; continue; } if (Internal::CC::CommandClasses::IsSupported(_data[i])) { if (Internal::CC::Security::StaticGetCommandClassId() == _data[i] && !GetDriver()->isNetworkKeySet()) { Log::Write(LogLevel_Info, m_nodeId, " %s (Disabled - Network Key Not Set)", Internal::CC::Security::StaticGetCommandClassName().c_str()); continue; } if (Internal::CC::CommandClass* pCommandClass = AddCommandClass(_data[i])) { /* this CC was in the NIF frame */ pCommandClass->SetInNIF(); // If this class came after the COMMAND_CLASS_MARK, then we do not create values. if (afterMark) { pCommandClass->SetAfterMark(); } // Start with an instance count of one. If the device supports COMMMAND_CLASS_MULTI_INSTANCE // then some command class instance counts will increase once the responses to the RequestState // call at the end of this method have been processed. pCommandClass->SetInstance(1); newCommandClasses = true; Log::Write(LogLevel_Info, m_nodeId, " %s", pCommandClass->GetCommandClassName().c_str()); } else if (Internal::CC::CommandClass *pCommandClass = GetCommandClass(_data[i])) { /* this CC was in the NIF frame */ pCommandClass->SetInNIF(); Log::Write(LogLevel_Info, m_nodeId, " %s (Existing)", pCommandClass->GetCommandClassName().c_str()); } } else { Log::Write(LogLevel_Info, m_nodeId, " CommandClass 0x%.2x - NOT REQUIRED", _data[i]); } } if (!newCommandClasses) { // No additional command classes over the mandatory ones. Log::Write(LogLevel_Info, m_nodeId, " None"); } SetStaticRequests(); m_nodeInfoReceived = true; } else { /* Only Refresh if the Device Config Specifies it - Only the dynamic stuff */ if (m_refreshonNodeInfoFrame) SetQueryStage(QueryStage_Dynamic); } // Treat the node info frame as a sign that the node is awake if (Internal::CC::WakeUp* wakeUp = static_cast(GetCommandClass(Internal::CC::WakeUp::StaticGetCommandClassId()))) { wakeUp->SetAwake(true); } } //----------------------------------------------------------------------------- // // Track alive state of a node for dead node detection. //----------------------------------------------------------------------------- void Node::SetNodeAlive(bool const _isAlive) { Notification* notification; if (_isAlive) { Log::Write(LogLevel_Error, m_nodeId, "WARNING: node revived"); m_nodeAlive = true; m_errors = 0; if (m_queryStage != Node::QueryStage_Complete) { m_queryRetries = 0; // restart at last stage AdvanceQueries(); } notification = new Notification(Notification::Type_Notification); notification->SetHomeAndNodeIds(m_homeId, m_nodeId); notification->SetNotification(Notification::Code_Alive); } else { Log::Write(LogLevel_Error, m_nodeId, "ERROR: node presumed dead"); m_nodeAlive = false; if (m_queryStage != Node::QueryStage_Complete) { // Check whether all nodes are now complete GetDriver()->CheckCompletedNodeQueries(); } notification = new Notification(Notification::Type_Notification); notification->SetHomeAndNodeIds(m_homeId, m_nodeId); notification->SetNotification(Notification::Code_Dead); } GetDriver()->QueueNotification(notification); } //----------------------------------------------------------------------------- // // The first time we hear from a node, we set flags to indicate the // need to request certain static data from the device. This is so that // we can track which data has been received, and which has not. //----------------------------------------------------------------------------- void Node::SetStaticRequests() { uint8 request = 0; if (GetCommandClass(Internal::CC::MultiInstance::StaticGetCommandClassId())) { // Request instances request |= (uint8) Internal::CC::CommandClass::StaticRequest_Instances; } if (GetCommandClass(Internal::CC::Version::StaticGetCommandClassId())) { // Request versions request |= (uint8) Internal::CC::CommandClass::StaticRequest_Version; } if (request) { for (map::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it) { it->second->SetStaticRequest(request); } SetQueryStage(QueryStage_ManufacturerSpecific2); } } //----------------------------------------------------------------------------- // // Set the name of the node //----------------------------------------------------------------------------- void Node::SetNodeName(string const& _nodeName) { m_nodeName = _nodeName; // Notify the watchers of the name changes Notification* notification = new Notification(Notification::Type_NodeNaming); notification->SetHomeAndNodeIds(m_homeId, m_nodeId); GetDriver()->QueueNotification(notification); if (Internal::CC::NodeNaming* cc = static_cast(GetCommandClass(Internal::CC::NodeNaming::StaticGetCommandClassId()))) { // The node supports naming, so we try to write the name into the device cc->SetName(_nodeName); } } //----------------------------------------------------------------------------- // // Set the location of the node //----------------------------------------------------------------------------- void Node::SetLocation(string const& _location) { m_location = _location; // Notify the watchers of the name changes Notification* notification = new Notification(Notification::Type_NodeNaming); notification->SetHomeAndNodeIds(m_homeId, m_nodeId); GetDriver()->QueueNotification(notification); if (Internal::CC::NodeNaming* cc = static_cast(GetCommandClass(Internal::CC::NodeNaming::StaticGetCommandClassId()))) { // The node supports naming, so we try to write the location into the device cc->SetLocation(_location); } } //----------------------------------------------------------------------------- // // Handle a command class message //----------------------------------------------------------------------------- void Node::ApplicationCommandHandler(uint8 const* _data, bool encrypted ) { if (Internal::CC::CommandClass* pCommandClass = GetCommandClass(_data[5])) { if (pCommandClass->IsSecured() && !encrypted) { Log::Write(LogLevel_Warning, m_nodeId, "Received a Clear Text Message for the CommandClass %s which is Secured", pCommandClass->GetCommandClassName().c_str()); bool drop = true; Options::Get()->GetOptionAsBool("EnforceSecureReception", &drop); if (drop) { Log::Write(LogLevel_Warning, m_nodeId, " Dropping Message"); return; } else { Log::Write(LogLevel_Warning, m_nodeId, " Allowing Message (EnforceSecureReception is not set)"); } } pCommandClass->ReceivedCntIncr(); if (!pCommandClass->IsAfterMark()) { if (!pCommandClass->HandleMsg(&_data[6], _data[4])) { Log::Write(LogLevel_Warning, m_nodeId, "CommandClass %s HandlerMsg Returned False", pCommandClass->GetCommandClassName().c_str()); } } else { if (!pCommandClass->HandleIncomingMsg(&_data[6], _data[4])) { Log::Write(LogLevel_Warning, m_nodeId, "CommandClass %s HandleIncomingMsg Returned False", pCommandClass->GetCommandClassName().c_str()); } } } else { if (_data[5] == Internal::CC::ControllerReplication::StaticGetCommandClassId()) { // This is a controller replication message, and we do not support it. // We have to at least acknowledge the message to avoid locking the sending device. Log::Write(LogLevel_Info, m_nodeId, "ApplicationCommandHandler - Default acknowledgment of controller replication data"); Internal::Msg* msg = new Internal::Msg("Replication Command Complete", m_nodeId, REQUEST, FUNC_ID_ZW_REPLICATION_COMMAND_COMPLETE, false); GetDriver()->SendMsg(msg, Driver::MsgQueue_Command); } else if (_data[5] == Internal::CC::MultiInstance::StaticGetCommandClassId()) { // Devices that support MultiChannelAssociation may send a MultiChannel Encapsulated message if there is a Instance set in the Association Groups // So we will dynamically load the MultiChannel CC if we receive a encapsulated message // We only do this after the QueryStage is Complete as we don't want to Add this CC to the list, and then confusing OZW that // The device supports the MultiChannel CC (eg, the Device might be asleep, we have not got the NIF and it actually does support it versus sending to a MultiChannelAssociation Endpoint if (GetCurrentQueryStage() != QueryStage_Complete) { Log::Write(LogLevel_Info, m_nodeId, "ApplicationCommandHandler - Received a MultiInstance Message, but QueryStage Isn't Complete yet"); return; } Log::Write(LogLevel_Info, m_nodeId, "ApplicationCommandHandler - Received a MultiInstance Message but MulitInstance CC isn't loaded. Loading it... "); if (Internal::CC::CommandClass* pCommandClass = AddCommandClass(Internal::CC::MultiInstance::StaticGetCommandClassId())) { pCommandClass->ReceivedCntIncr(); if (!pCommandClass->IsAfterMark()) { if (!pCommandClass->HandleMsg(&_data[6], _data[4])) { Log::Write(LogLevel_Warning, m_nodeId, "CommandClass %s HandleMsg returned false", pCommandClass->GetCommandClassName().c_str()); } } else { if (!pCommandClass->HandleIncomingMsg(&_data[6], _data[4])) { Log::Write(LogLevel_Warning, m_nodeId, "CommandClass %s HandleIncommingMsg returned false", pCommandClass->GetCommandClassName().c_str()); } } } } else { Log::Write(LogLevel_Info, m_nodeId, "ApplicationCommandHandler - Unhandled Command Class 0x%.2x", _data[5]); } } } //----------------------------------------------------------------------------- // // Get the specified command class object if supported, otherwise NULL //----------------------------------------------------------------------------- Internal::CC::CommandClass* Node::GetCommandClass(uint8 const _commandClassId) const { map::const_iterator it = m_commandClassMap.find(_commandClassId); if (it != m_commandClassMap.end()) { return it->second; } // Not found return NULL; } //----------------------------------------------------------------------------- // // Add a command class to the node //----------------------------------------------------------------------------- Internal::CC::CommandClass* Node::AddCommandClass(uint8 const _commandClassId) { if (GetCommandClass(_commandClassId)) { // Class and instance have already been added return NULL; } // Create the command class object and add it to our map if (Internal::CC::CommandClass* pCommandClass = Internal::CC::CommandClasses::CreateCommandClass(_commandClassId, m_homeId, m_nodeId)) { m_commandClassMap[_commandClassId] = pCommandClass; /* Only Request the CC Version if we are equal or after QueryStage_SecurityReport */ if (GetCurrentQueryStage() >= QueryStage_SecurityReport) { Internal::CC::Version* vcc = static_cast(GetCommandClass(Internal::CC::Version::StaticGetCommandClassId())); if (vcc) { if (pCommandClass->GetMaxVersion() > 1 && pCommandClass->GetVersion() == 0) { Log::Write(LogLevel_Info, m_nodeId, "\t\tRequesting Versions for %s", pCommandClass->GetCommandClassName().c_str()); // Get the version for each supported command class that // we have implemented at greater than version one. vcc->RequestCommandClassVersion(pCommandClass); } else { // set the Version to 1 pCommandClass->SetVersion(1); } } } return pCommandClass; } else { Log::Write(LogLevel_Info, m_nodeId, "AddCommandClass - Unsupported CommandClass 0x%.2x", _commandClassId); } return NULL; } //----------------------------------------------------------------------------- // // Remove a command class from the node //----------------------------------------------------------------------------- void Node::RemoveCommandClass(uint8 const _commandClassId) { map::iterator it = m_commandClassMap.find(_commandClassId); if (it == m_commandClassMap.end()) { // Class is not found return; } // Remove all the values associated with this class if (Internal::VC::ValueStore* store = GetValueStore()) { store->RemoveCommandClassValues(_commandClassId); } // Destroy the command class object and remove it from our map Log::Write(LogLevel_Info, m_nodeId, "RemoveCommandClass - Removed support for %s", it->second->GetCommandClassName().c_str()); delete it->second; m_commandClassMap.erase(it); } //----------------------------------------------------------------------------- // // Set a configuration parameter in a device //----------------------------------------------------------------------------- bool Node::SetConfigParam(uint8 const _param, int32 _value, uint8 const _size) { if (Internal::CC::Configuration* cc = static_cast(GetCommandClass(Internal::CC::Configuration::StaticGetCommandClassId()))) { // First try to find an existing value representing the parameter, and set that. if (Internal::VC::Value* value = cc->GetValue(1, _param)) { switch (value->GetID().GetType()) { case ValueID::ValueType_Bool: { Internal::VC::ValueBool* valueBool = static_cast(value); valueBool->Set(_value != 0); break; } case ValueID::ValueType_Byte: { Internal::VC::ValueByte* valueByte = static_cast(value); valueByte->Set((uint8) _value); break; } case ValueID::ValueType_Short: { Internal::VC::ValueShort* valueShort = static_cast(value); valueShort->Set((uint16) _value); break; } case ValueID::ValueType_Int: { Internal::VC::ValueInt* valueInt = static_cast(value); valueInt->Set(_value); break; } case ValueID::ValueType_List: { Internal::VC::ValueList* valueList = static_cast(value); valueList->SetByValue(_value); break; } default: { } } return true; } // Failed to find an existing value object representing this // configuration parameter, so we try using the default or // included size through the Configuration command class. cc->Set(_param, _value, _size); return true; } return false; } //----------------------------------------------------------------------------- // // Request the value of a configuration parameter from the device //----------------------------------------------------------------------------- void Node::RequestConfigParam(uint8 const _param) { if (Internal::CC::Configuration* cc = static_cast(GetCommandClass(Internal::CC::Configuration::StaticGetCommandClassId()))) { cc->RequestValue(0, _param, 1, Driver::MsgQueue_Send); } } //----------------------------------------------------------------------------- // // Request the values of all known configuration parameters from the device //----------------------------------------------------------------------------- bool Node::RequestAllConfigParams(uint32 const _requestFlags) { bool res = false; if (Internal::CC::Configuration* cc = static_cast(GetCommandClass(Internal::CC::Configuration::StaticGetCommandClassId()))) { // Go through all the values in the value store, and request all those which are in the Configuration command class for (Internal::VC::ValueStore::Iterator it = m_values->Begin(); it != m_values->End(); ++it) { Internal::VC::Value* value = it->second; if (value->GetID().GetCommandClassId() == Internal::CC::Configuration::StaticGetCommandClassId() && !value->IsWriteOnly()) { /* put the ConfigParams Request into the MsgQueue_Query queue. This is so MsgQueue_Send doesn't get backlogged with a * lot of ConfigParams requests, and should help speed up any user generated messages being sent out (as the MsgQueue_Send has a higher * priority than MsgQueue_Query */ res |= cc->RequestValue(_requestFlags, value->GetID().GetIndex(), 1, Driver::MsgQueue_Query); } } } return res; } //----------------------------------------------------------------------------- // // Request an update of all known dynamic values from the device //----------------------------------------------------------------------------- bool Node::RequestDynamicValues() { bool res = false; for (map::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it) { if (!it->second->IsAfterMark()) { res |= it->second->RequestStateForAllInstances(Internal::CC::CommandClass::RequestFlag_Dynamic, Driver::MsgQueue_Send); } } return res; } //----------------------------------------------------------------------------- // // Request an update of all known dynamic values from the device //----------------------------------------------------------------------------- void Node::RefreshValuesOnWakeup() { for (map::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it) { if (!it->second->IsAfterMark()) { it->second->refreshValuesOnWakeup(); } } } //----------------------------------------------------------------------------- // // Helper method to set a device's basic level //----------------------------------------------------------------------------- void Node::SetLevel(uint8 const _level) { // Level is 0-99, with 0 = off and 99 = fully on. 255 = turn on at last level. uint8 adjustedLevel = _level; if ((_level > 99) && (_level < 255)) { adjustedLevel = 99; } if (Internal::CC::Basic* cc = static_cast(GetCommandClass(Internal::CC::Basic::StaticGetCommandClassId()))) { cc->Set(adjustedLevel); } } //----------------------------------------------------------------------------- // // Helper method to set a device to be on //----------------------------------------------------------------------------- void Node::SetNodeOn() { // Level is 0-99, with 0 = off and 99 = fully on. 255 = turn on at last level. if (Internal::CC::Basic* cc = static_cast(GetCommandClass(Internal::CC::Basic::StaticGetCommandClassId()))) { cc->Set(255); } } //----------------------------------------------------------------------------- // // Helper method to set a device to be off //----------------------------------------------------------------------------- void Node::SetNodeOff() { // Level is 0-99, with 0 = off and 99 = fully on. 255 = turn on at last level. if (Internal::CC::Basic* cc = static_cast(GetCommandClass(Internal::CC::Basic::StaticGetCommandClassId()))) { cc->Set(0); } } //----------------------------------------------------------------------------- // // Helper to create a ValueID //----------------------------------------------------------------------------- ValueID Node::CreateValueID(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, ValueID::ValueType const _type) { return ValueID(m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _type); } //----------------------------------------------------------------------------- // // Helper to create a BitSet ValueID //----------------------------------------------------------------------------- bool Node::CreateValueBitSet(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, int32 const _default, uint8 const _pollIntensity) { Internal::VC::ValueBitSet* value = new Internal::VC::ValueBitSet(m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _default, _pollIntensity); Internal::VC::ValueStore* store = GetValueStore(); if (store->AddValue(value)) { value->Release(); return true; } value->Release(); return false; } //----------------------------------------------------------------------------- // // Helper to create a new bool value and add it to the value store //----------------------------------------------------------------------------- bool Node::CreateValueBool(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, bool const _default, uint8 const _pollIntensity) { Internal::VC::ValueBool* value = new Internal::VC::ValueBool(m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _default, _pollIntensity); Internal::VC::ValueStore* store = GetValueStore(); if (store->AddValue(value)) { value->Release(); return true; } value->Release(); return false; } //----------------------------------------------------------------------------- // // Helper to create a new trigger value and add it to the value store //----------------------------------------------------------------------------- bool Node::CreateValueButton(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, uint8 const _pollIntensity) { Internal::VC::ValueButton* value = new Internal::VC::ValueButton(m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _pollIntensity); Internal::VC::ValueStore* store = GetValueStore(); if (store->AddValue(value)) { value->Release(); return true; } value->Release(); return false; } //----------------------------------------------------------------------------- // // Helper to create a new byte value and add it to the value store //----------------------------------------------------------------------------- bool Node::CreateValueByte(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _default, uint8 const _pollIntensity) { Internal::VC::ValueByte* value = new Internal::VC::ValueByte(m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _default, _pollIntensity); Internal::VC::ValueStore* store = GetValueStore(); if (store->AddValue(value)) { value->Release(); return true; } value->Release(); return false; } //----------------------------------------------------------------------------- // // Helper to create a new decimal value and add it to the value store //----------------------------------------------------------------------------- bool Node::CreateValueDecimal(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, string const& _default, uint8 const _pollIntensity) { Internal::VC::ValueDecimal* value = new Internal::VC::ValueDecimal(m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _default, _pollIntensity); Internal::VC::ValueStore* store = GetValueStore(); if (store->AddValue(value)) { value->Release(); return true; } value->Release(); return false; } //----------------------------------------------------------------------------- // // Helper to create a new int value and add it to the value store //----------------------------------------------------------------------------- bool Node::CreateValueInt(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, int32 const _default, uint8 const _pollIntensity) { Internal::VC::ValueInt* value = new Internal::VC::ValueInt(m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _default, _pollIntensity); Internal::VC::ValueStore* store = GetValueStore(); if (store->AddValue(value)) { value->Release(); return true; } value->Release(); return false; } //----------------------------------------------------------------------------- // // Helper to create a new list value and add it to the value store //----------------------------------------------------------------------------- bool Node::CreateValueList(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _size, vector const& _items, int32 const _default, uint8 const _pollIntensity) { Internal::VC::ValueList* value = new Internal::VC::ValueList(m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _items, _default, _pollIntensity, _size); Internal::VC::ValueStore* store = GetValueStore(); if (store->AddValue(value)) { value->Release(); return true; } value->Release(); return false; } //----------------------------------------------------------------------------- // // Helper to create a new raw value and add it to the value store //----------------------------------------------------------------------------- bool Node::CreateValueRaw(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const* _default, uint8 const _length, uint8 const _pollIntensity) { Internal::VC::ValueRaw* value = new Internal::VC::ValueRaw(m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _default, _length, _pollIntensity); Internal::VC::ValueStore* store = GetValueStore(); if (store->AddValue(value)) { value->Release(); return true; } value->Release(); return false; } //----------------------------------------------------------------------------- // // Helper to create a new schedule value and add it to the value store //----------------------------------------------------------------------------- bool Node::CreateValueSchedule(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _pollIntensity) { Internal::VC::ValueSchedule* value = new Internal::VC::ValueSchedule(m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _pollIntensity); Internal::VC::ValueStore* store = GetValueStore(); if (store->AddValue(value)) { value->Release(); return true; } value->Release(); return false; } //----------------------------------------------------------------------------- // // Helper to create a new short value and add it to the value store //----------------------------------------------------------------------------- bool Node::CreateValueShort(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, int16 const _default, uint8 const _pollIntensity) { Internal::VC::ValueShort* value = new Internal::VC::ValueShort(m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _default, _pollIntensity); Internal::VC::ValueStore* store = GetValueStore(); if (store->AddValue(value)) { value->Release(); return true; } value->Release(); return false; } //----------------------------------------------------------------------------- // // Helper to create a new string value and add it to the value store //----------------------------------------------------------------------------- bool Node::CreateValueString(ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, string const& _default, uint8 const _pollIntensity) { Internal::VC::ValueString* value = new Internal::VC::ValueString(m_homeId, m_nodeId, _genre, _commandClassId, _instance, _valueIndex, _label, _units, _readOnly, _writeOnly, _default, _pollIntensity); Internal::VC::ValueStore* store = GetValueStore(); if (store->AddValue(value)) { value->Release(); return true; } value->Release(); return false; } //----------------------------------------------------------------------------- // // Helper to remove an existing list value from the value store //----------------------------------------------------------------------------- void Node::RemoveValueList(Internal::VC::ValueList* _value) { Internal::VC::ValueStore* store = GetValueStore(); store->RemoveValue(_value->GetID().GetValueStoreKey()); } //----------------------------------------------------------------------------- // // Get the value object with the specified ID //----------------------------------------------------------------------------- bool Node::CreateValueFromXML(uint8 const _commandClassId, TiXmlElement const* _valueElement) { Internal::VC::Value* value = NULL; // Create the value ValueID::ValueType type = Internal::VC::Value::GetTypeEnumFromName(_valueElement->Attribute("type")); switch (type) { case ValueID::ValueType_BitSet: { value = new Internal::VC::ValueBitSet(); break; } case ValueID::ValueType_Bool: { value = new Internal::VC::ValueBool(); break; } case ValueID::ValueType_Byte: { value = new Internal::VC::ValueByte(); break; } case ValueID::ValueType_Decimal: { value = new Internal::VC::ValueDecimal(); break; } case ValueID::ValueType_Int: { value = new Internal::VC::ValueInt(); break; } case ValueID::ValueType_List: { value = new Internal::VC::ValueList(); break; } case ValueID::ValueType_Schedule: { value = new Internal::VC::ValueSchedule(); break; } case ValueID::ValueType_Short: { value = new Internal::VC::ValueShort(); break; } case ValueID::ValueType_String: { value = new Internal::VC::ValueString(); break; } case ValueID::ValueType_Button: { value = new Internal::VC::ValueButton(); break; } case ValueID::ValueType_Raw: { value = new Internal::VC::ValueRaw(); break; } } if (value) { value->ReadXML(m_homeId, m_nodeId, _commandClassId, _valueElement); Internal::VC::ValueStore* store = GetValueStore(); if (store->AddValue(value)) { value->Release(); return true; } value->Release(); } else { Log::Write(LogLevel_Info, m_nodeId, "Unknown ValueType in XML: %s", _valueElement->Attribute("type")); } return false; } //----------------------------------------------------------------------------- // // Apply XML differences to a value //----------------------------------------------------------------------------- void Node::ReadValueFromXML(uint8 const _commandClassId, TiXmlElement const* _valueElement) { int32 intVal; ValueID::ValueGenre genre = Internal::VC::Value::GetGenreEnumFromName(_valueElement->Attribute("genre")); ValueID::ValueType type = Internal::VC::Value::GetTypeEnumFromName(_valueElement->Attribute("type")); uint8 instance = 0; if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("instance", &intVal)) { instance = (uint8) intVal; } uint16 index = 0; if (TIXML_SUCCESS == _valueElement->QueryIntAttribute("index", &intVal)) { index = (uint16) intVal; } ValueID id = ValueID(m_homeId, m_nodeId, genre, _commandClassId, instance, index, type); // Try to get the value from the ValueStore (everything except configuration parameters // should already have been created when the command class instance count was read in). // Create it if it doesn't already exist. if (Internal::VC::ValueStore* store = GetValueStore()) { if (Internal::VC::Value* value = store->GetValue(id.GetValueStoreKey())) { // Check if values type are the same ValueID::ValueType v_type = value->GetID().GetType(); if (v_type == type) { value->ReadXML(m_homeId, m_nodeId, _commandClassId, _valueElement); value->Release(); } else { Log::Write(LogLevel_Info, m_nodeId, "xml value type (%s) is different to stored value type (%s). Value is recreate with xml params.", value->GetTypeNameFromEnum(type), value->GetTypeNameFromEnum(v_type)); store->RemoveValue(value->GetID().GetValueStoreKey()); CreateValueFromXML(_commandClassId, _valueElement); } } else { CreateValueFromXML(_commandClassId, _valueElement); } } } //----------------------------------------------------------------------------- // // Get the value object with the specified ID //----------------------------------------------------------------------------- Internal::VC::Value* Node::GetValue(ValueID const& _id) { // This increments the value's reference count Internal::VC::Value *value = GetValueStore()->GetValue(_id.GetValueStoreKey()); if (!value) { Log::Write(LogLevel_Warning, m_nodeId, "Node::GetValue - Couldn't find ValueID in Store: %s", _id.GetAsString().c_str()); return nullptr; } if (value->GetID().GetId() != _id.GetId()) { Log::Write(LogLevel_Error, m_nodeId, "Node::GetValue called with: %s but GetValueStore returned: %s", _id.GetAsString().c_str(), value->GetID().GetAsString().c_str()); value->Release(); return nullptr; } return value; } //----------------------------------------------------------------------------- // // Get the value object with the specified settings //----------------------------------------------------------------------------- Internal::VC::Value* Node::GetValue(uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex) { Internal::VC::Value* value = NULL; Internal::VC::ValueStore* store = GetValueStore(); // This increments the value's reference count value = store->GetValue(ValueID::GetValueStoreKey(_commandClassId, _instance, _valueIndex)); return value; } //----------------------------------------------------------------------------- // // Remove the value object with the specified settings //----------------------------------------------------------------------------- bool Node::RemoveValue(uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex) { Internal::VC::ValueStore* store = GetValueStore(); return store->RemoveValue(ValueID::GetValueStoreKey(_commandClassId, _instance, _valueIndex)); } //----------------------------------------------------------------------------- // // Get a Group from the node's map //----------------------------------------------------------------------------- Group* Node::GetGroup(uint8 const _groupIdx) { map::iterator it = m_groups.find(_groupIdx); if (it == m_groups.end()) { return NULL; } return it->second; } //----------------------------------------------------------------------------- // // Add a group into the node's map //----------------------------------------------------------------------------- void Node::AddGroup(Group* _group) { map::iterator it = m_groups.find(_group->GetIdx()); if (it != m_groups.end()) { // There is already a group with this id. We will replace it. delete it->second; m_groups.erase(it); } m_groups[_group->GetIdx()] = _group; } //----------------------------------------------------------------------------- // // Save the group data //----------------------------------------------------------------------------- void Node::WriteGroups(TiXmlElement* _associationsElement) { for (map::iterator it = m_groups.begin(); it != m_groups.end(); ++it) { Group* group = it->second; TiXmlElement* groupElement = new TiXmlElement("Group"); _associationsElement->LinkEndChild(groupElement); group->WriteXML(groupElement); } } //----------------------------------------------------------------------------- // // Gets the number of association groups reported by this node //----------------------------------------------------------------------------- uint8 Node::GetNumGroups() { return (uint8) m_groups.size(); } //----------------------------------------------------------------------------- // // Gets the associations for a group //----------------------------------------------------------------------------- uint32 Node::GetAssociations(uint8 const _groupIdx, uint8** o_associations) { uint32 numAssociations = 0; if (Group* group = GetGroup(_groupIdx)) { numAssociations = group->GetAssociations(o_associations); } return numAssociations; } //----------------------------------------------------------------------------- // // Gets the associations for a group //----------------------------------------------------------------------------- uint32 Node::GetAssociations(uint8 const _groupIdx, InstanceAssociation** o_associations) { uint32 numAssociations = 0; if (Group* group = GetGroup(_groupIdx)) { numAssociations = group->GetAssociations(o_associations); } return numAssociations; } //----------------------------------------------------------------------------- // // Gets the maximum number of associations for a group //----------------------------------------------------------------------------- uint8 Node::GetMaxAssociations(uint8 const _groupIdx) { uint8 maxAssociations = 0; if (Group* group = GetGroup(_groupIdx)) { maxAssociations = group->GetMaxAssociations(); } return maxAssociations; } //----------------------------------------------------------------------------- // // Returns true if group supports multi instance //----------------------------------------------------------------------------- bool Node::IsMultiInstance(uint8 const _groupIdx) { bool multiInstance = false; if (Group* group = GetGroup(_groupIdx)) { multiInstance = group->IsMultiInstance(); } return multiInstance; } //----------------------------------------------------------------------------- // // Gets the label for a particular group //----------------------------------------------------------------------------- string Node::GetGroupLabel(uint8 const _groupIdx) { string label = ""; if (Group* group = GetGroup(_groupIdx)) { label = group->GetLabel(); } return label; } //----------------------------------------------------------------------------- // // Adds a node to an association group //----------------------------------------------------------------------------- void Node::AddAssociation(uint8 const _groupIdx, uint8 const _targetNodeId, uint8 const _instance) { if (Group* group = GetGroup(_groupIdx)) { group->AddAssociation(_targetNodeId, _instance); } } //----------------------------------------------------------------------------- // // Removes a node from an association group //----------------------------------------------------------------------------- void Node::RemoveAssociation(uint8 const _groupIdx, uint8 const _targetNodeId, uint8 const _instance) { if (Group* group = GetGroup(_groupIdx)) { group->RemoveAssociation(_targetNodeId, _instance); } } //----------------------------------------------------------------------------- // // Automatically associate the controller with certain groups //----------------------------------------------------------------------------- void Node::AutoAssociate() { bool autoAssociate = false; Options::Get()->GetOptionAsBool("Associate", &autoAssociate); if (autoAssociate) { // Try to automatically associate with any groups that have been flagged. uint8 controllerNodeId = GetDriver()->GetControllerNodeId(); for (map::iterator it = m_groups.begin(); it != m_groups.end(); ++it) { Group* group = it->second; if (group->IsAuto() && !group->Contains(controllerNodeId)) { // Associate the controller into the group Log::Write(LogLevel_Info, m_nodeId, "Adding the controller to group %d (%s) of node %d", group->GetIdx(), group->GetLabel().c_str(), GetNodeId()); group->AddAssociation(controllerNodeId); } } } } //----------------------------------------------------------------------------- // // Get a pointer to our driver //----------------------------------------------------------------------------- Driver* Node::GetDriver() const { return (Manager::Get()->GetDriver(m_homeId)); } //----------------------------------------------------------------------------- // Device Classes //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // Use the device class data to get a label for a MultiChannel EndPoint. //----------------------------------------------------------------------------- string Node::GetEndPointDeviceClassLabel(uint8 const _generic, uint8 const _specific) { char str[32]; string label; snprintf(str, sizeof(str), "Generic 0x%.2x Specific 0x%.2x", _generic, _specific); label = str; // Read in the device class data if it has not been read already. if (!s_deviceClassesLoaded) { ReadDeviceClasses(); } // Get the Generic device class label map::iterator git = s_genericDeviceClasses.find(_generic); if (git != s_genericDeviceClasses.end()) { GenericDeviceClass* genericDeviceClass = git->second; label = genericDeviceClass->GetLabel(); // Override with any specific device class label if (DeviceClass* specificDeviceClass = genericDeviceClass->GetSpecificDeviceClass(_specific)) { label = specificDeviceClass->GetLabel(); } } return label; } //----------------------------------------------------------------------------- // // Set the device class data for the node //----------------------------------------------------------------------------- bool Node::SetDeviceClasses(uint8 const _basic, uint8 const _generic, uint8 const _specific) { m_basic = _basic; m_generic = _generic; m_specific = _specific; // Read in the device class data if it has not been read already. if (!s_deviceClassesLoaded) { ReadDeviceClasses(); } // Get the basic device class label map::iterator bit = s_basicDeviceClasses.find(_basic); if (bit != s_basicDeviceClasses.end()) { m_type = bit->second; Log::Write(LogLevel_Info, m_nodeId, " Basic device class (0x%.2x) - %s", m_basic, m_type.c_str()); } else { Log::Write(LogLevel_Info, m_nodeId, " Basic device class unknown"); } // Apply any Generic device class data uint8 basicMapping = 0; map::iterator git = s_genericDeviceClasses.find(_generic); if (git != s_genericDeviceClasses.end()) { GenericDeviceClass* genericDeviceClass = git->second; m_type = genericDeviceClass->GetLabel(); Log::Write(LogLevel_Info, m_nodeId, " Generic device Class (0x%.2x) - %s", m_generic, m_type.c_str()); // Add the mandatory command classes for this generic class type AddMandatoryCommandClasses(genericDeviceClass->GetMandatoryCommandClasses()); // Get the command class that COMMAND_CLASS_BASIC maps to. basicMapping = genericDeviceClass->GetBasicMapping(); // Apply any Specific device class data if (DeviceClass* specificDeviceClass = genericDeviceClass->GetSpecificDeviceClass(_specific)) { m_type = specificDeviceClass->GetLabel(); Log::Write(LogLevel_Info, m_nodeId, " Specific device class (0x%.2x) - %s", m_specific, m_type.c_str()); // Add the mandatory command classes for this specific class type AddMandatoryCommandClasses(specificDeviceClass->GetMandatoryCommandClasses()); if (specificDeviceClass->GetBasicMapping()) { // Override the generic device class basic mapping with the specific device class one. basicMapping = specificDeviceClass->GetBasicMapping(); } } else { Log::Write(LogLevel_Info, m_nodeId, " No specific device class defined"); } } else { Log::Write(LogLevel_Info, m_nodeId, " No generic or specific device classes defined"); } // Deal with sleeping devices if (!m_listening && !IsFrequentListeningDevice()) { // Device does not always listen, so we need the WakeUp handler. We can't // wait for the command class list because the request for the command // classes may need to go in the wakeup queue itself! if (Internal::CC::CommandClass* pCommandClass = AddCommandClass(Internal::CC::WakeUp::StaticGetCommandClassId())) { pCommandClass->SetInstance(1); } } // Apply any COMMAND_CLASS_BASIC remapping if (Internal::CC::Basic* cc = static_cast(GetCommandClass(Internal::CC::Basic::StaticGetCommandClassId()))) { cc->SetMapping(basicMapping); } // Write the mandatory command classes to the log if (!m_commandClassMap.empty()) { map::const_iterator cit; Log::Write(LogLevel_Info, m_nodeId, " Mandatory Command Classes for Node %d:", m_nodeId); bool reportedClasses = false; for (cit = m_commandClassMap.begin(); cit != m_commandClassMap.end(); ++cit) { if (!cit->second->IsAfterMark() && cit->second->GetCommandClassId() != Internal::CC::NoOperation::StaticGetCommandClassId()) { Log::Write(LogLevel_Info, m_nodeId, " %s", cit->second->GetCommandClassName().c_str()); reportedClasses = true; } } if (!reportedClasses) { Log::Write(LogLevel_Info, m_nodeId, " None"); } Log::Write(LogLevel_Info, m_nodeId, " Mandatory Command Classes controlled by Node %d:", m_nodeId); reportedClasses = false; for (cit = m_commandClassMap.begin(); cit != m_commandClassMap.end(); ++cit) { if (cit->second->IsAfterMark()) { Log::Write(LogLevel_Info, m_nodeId, " %s", cit->second->GetCommandClassName().c_str()); reportedClasses = true; } } if (!reportedClasses) { Log::Write(LogLevel_Info, m_nodeId, " None"); } } return true; } //----------------------------------------------------------------------------- // // Set the device class data for the node based on the Zwave+ info report //----------------------------------------------------------------------------- bool Node::SetPlusDeviceClasses(uint8 const _role, uint8 const _nodeType, uint16 const _deviceType) { if (m_nodePlusInfoReceived) { return false; // already set } if (!s_deviceClassesLoaded) { ReadDeviceClasses(); } m_nodePlusInfoReceived = true; m_role = _role; m_deviceType = _deviceType; m_nodeType = _nodeType; Log::Write(LogLevel_Info, m_nodeId, "ZWave+ Info Received from Node %d", m_nodeId); map::iterator nit = s_nodeTypes.find(m_nodeType); if (nit != s_nodeTypes.end()) { DeviceClass* deviceClass = nit->second; Log::Write(LogLevel_Info, m_nodeId, " Zwave+ Node Type (0x%02x) - %s. Mandatory Command Classes:", m_nodeType, deviceClass->GetLabel().c_str()); uint8 const *_commandClasses = deviceClass->GetMandatoryCommandClasses(); /* no CommandClasses to add */ if (_commandClasses != NULL) { int i = 0; while (uint8 ccid = _commandClasses[i++]) { if (Internal::CC::CommandClasses::IsSupported(ccid)) { Log::Write(LogLevel_Info, m_nodeId, " %s", Internal::CC::CommandClasses::GetName(ccid).c_str()); } else { Log::Write(LogLevel_Info, m_nodeId, " 0x%02x (Not Supported)", ccid); } } // Add the mandatory command classes for this Roletype AddMandatoryCommandClasses(deviceClass->GetMandatoryCommandClasses()); } else { Log::Write(LogLevel_Info, m_nodeId, " NONE"); } } else { Log::Write(LogLevel_Warning, m_nodeId, " Zwave+ Node Type (0x%02x) - NOT FOUND. No Mandatory Command Classes Loaded:", m_nodeType); } // Apply any Zwave+ device class data map::iterator dit = s_deviceTypeClasses.find(_deviceType); if (dit != s_deviceTypeClasses.end()) { DeviceClass* deviceClass = dit->second; // m_type = deviceClass->GetLabel(); // do we what to update the type with the zwave+ info?? Log::Write(LogLevel_Info, m_nodeId, " Zwave+ Device Type (0x%04x) - %s. Mandatory Command Classes:", _deviceType, deviceClass->GetLabel().c_str()); uint8 const *_commandClasses = deviceClass->GetMandatoryCommandClasses(); /* no CommandClasses to add */ if (_commandClasses != NULL) { int i = 0; while (uint8 ccid = _commandClasses[i++]) { if (Internal::CC::CommandClasses::IsSupported(ccid)) { Log::Write(LogLevel_Info, m_nodeId, " %s", Internal::CC::CommandClasses::GetName(ccid).c_str()); } else { Log::Write(LogLevel_Info, m_nodeId, " 0x%02x (Not Supported)", ccid); } } // Add the mandatory command classes for this device class type AddMandatoryCommandClasses(deviceClass->GetMandatoryCommandClasses()); } else { Log::Write(LogLevel_Info, m_nodeId, " NONE"); } } else { Log::Write(LogLevel_Warning, m_nodeId, " Zwave+ Device Type (0x%04x) - NOT FOUND. No Mandatory Command Classes Loaded:", _deviceType); } // Apply any Role device class data map::iterator rit = s_roleDeviceClasses.find(_role); if (rit != s_roleDeviceClasses.end()) { DeviceClass* roleDeviceClass = rit->second; Log::Write(LogLevel_Info, m_nodeId, " ZWave+ Role Type (0x%02x) - %s", _role, roleDeviceClass->GetLabel().c_str()); uint8 const *_commandClasses = roleDeviceClass->GetMandatoryCommandClasses(); /* no CommandClasses to add */ if (_commandClasses != NULL) { int i = 0; while (uint8 ccid = _commandClasses[i++]) { if (Internal::CC::CommandClasses::IsSupported(ccid)) { Log::Write(LogLevel_Info, m_nodeId, " %s", Internal::CC::CommandClasses::GetName(ccid).c_str()); } else { Log::Write(LogLevel_Info, m_nodeId, " 0x%02x (Not Supported)", ccid); } } // Add the mandatory command classes for this role class type AddMandatoryCommandClasses(roleDeviceClass->GetMandatoryCommandClasses()); } else { Log::Write(LogLevel_Info, m_nodeId, " NONE"); } } else { Log::Write(LogLevel_Warning, m_nodeId, " ZWave+ Role Type (0x%02x) - NOT FOUND. No Mandatory Command Classes Loaded:", _role); } return true; } //----------------------------------------------------------------------------- // // Add mandatory command classes to the node //----------------------------------------------------------------------------- bool Node::AddMandatoryCommandClasses(uint8 const* _commandClasses) { if ( NULL == _commandClasses) { // No command classes to add return false; } int i = 0; bool afterMark = false; while (uint8 cc = _commandClasses[i++]) { if (cc == 0xef) { // COMMAND_CLASS_MARK. // Marks the end of the list of supported command classes. The remaining classes // are those that can be controlled by this device, which we can ignore. afterMark = true; continue; } if (Internal::CC::CommandClasses::IsSupported(cc)) { if (Internal::CC::Security::StaticGetCommandClassId() == cc && !GetDriver()->isNetworkKeySet()) { Log::Write(LogLevel_Warning, m_nodeId, "Security Command Class Cannot be Enabled - NetworkKey is not set"); continue; } if (Internal::CC::CommandClass* commandClass = AddCommandClass(cc)) { // If this class came after the COMMAND_CLASS_MARK, then we do not create values. if (afterMark) { commandClass->SetAfterMark(); } // Start with an instance count of one. If the device supports COMMMAND_CLASS_MULTI_INSTANCE // then some command class instance counts will increase. commandClass->SetInstance(1); } } } return true; } //----------------------------------------------------------------------------- // // Read the static device class data from the device_classes.xml file //----------------------------------------------------------------------------- bool Node::ReadDeviceClasses() { // Load the XML document that contains the device class information string configPath; Options::Get()->GetOptionAsString("ConfigPath", &configPath); string filename = configPath + string("device_classes.xml"); TiXmlDocument doc; if (!doc.LoadFile(filename.c_str(), TIXML_ENCODING_UTF8)) { Log::Write(LogLevel_Warning, "Failed to load device_classes.xml"); Log::Write(LogLevel_Warning, "Check that the config path provided when creating the Manager points to the correct location."); Log::Write(LogLevel_Warning, "tinyXML Reported %s", doc.ErrorDesc()); OZW_ERROR(OZWException::OZWEXCEPTION_CONFIG, "Cannot read device_classes.xml! - Missing/Invalid Config File?"); return false; } doc.SetUserData((void *) filename.c_str()); TiXmlElement const* deviceClassesElement = doc.RootElement(); // Read the basic and generic device classes TiXmlElement const* child = deviceClassesElement->FirstChildElement(); while (child) { char const* str = child->Value(); if (str) { char const* keyStr = child->Attribute("key"); if (keyStr) { char* pStop; /* we do a short here, as they key can be a DeviceType Key which is short */ uint16_t key = (uint16) strtol(keyStr, &pStop, 16); if (!strcmp(str, "Generic")) { if (s_genericDeviceClasses.find((uint8_t)(key & 0xFF)) == s_genericDeviceClasses.end()) { s_genericDeviceClasses[(uint8_t) (key & 0xFF)] = new GenericDeviceClass(child); } else { Log::Write(LogLevel_Warning, "Duplicate Entry for Generic Device Class %d", key); } } else if (!strcmp(str, "Basic")) { if (s_basicDeviceClasses.find((uint8_t)(key & 0xFF)) == s_basicDeviceClasses.end()) { char const* label = child->Attribute("label"); if (label) { s_basicDeviceClasses[(uint8_t) (key & 0xFF)] = label; } } else { Log::Write(LogLevel_Warning, "Duplicate Entry for Basic Device Class %d", key); } } else if (!strcmp(str, "Role")) { if (s_roleDeviceClasses.find((uint8_t)(key & 0xFF)) == s_roleDeviceClasses.end()) { s_roleDeviceClasses[(uint8_t) (key & 0xFF)] = new DeviceClass(child); } else { Log::Write(LogLevel_Warning, "Duplicate Entry for Role Device Classes %d", key); } } else if (!strcmp(str, "DeviceType")) { if (s_deviceTypeClasses.find(key) == s_deviceTypeClasses.end()) { s_deviceTypeClasses[key] = new DeviceClass(child); } else { Log::Write(LogLevel_Warning, "Duplicate Entry for Device Type Class %d", key); } } else if (!strcmp(str, "NodeType")) { if (s_nodeTypes.find((uint8_t)(key & 0xFF)) == s_nodeTypes.end()) { s_nodeTypes[(uint8_t) (key & 0xFF)] = new DeviceClass(child); } else { Log::Write(LogLevel_Warning, "Duplicate Entry for Node Type %d", key); } } } } child = child->NextSiblingElement(); } s_deviceClassesLoaded = true; return true; } //----------------------------------------------------------------------------- // // Return driver statistics //----------------------------------------------------------------------------- void Node::GetNodeStatistics(NodeData* _data) { _data->m_sentCnt = m_sentCnt; _data->m_sentFailed = m_sentFailed; _data->m_retries = m_retries; _data->m_receivedCnt = m_receivedCnt; _data->m_receivedDups = m_receivedDups; _data->m_receivedUnsolicited = m_receivedUnsolicited; _data->m_lastRequestRTT = m_lastRequestRTT; _data->m_lastResponseRTT = m_lastResponseRTT; _data->m_sentTS = m_sentTS.GetAsString(); _data->m_receivedTS = m_receivedTS.GetAsString(); _data->m_averageRequestRTT = m_averageRequestRTT; _data->m_averageResponseRTT = m_averageResponseRTT; _data->m_txStatusReportSupported = m_txStatusReportSupported; _data->m_txTime = m_txTime; _data->m_hops = m_hops; // petergebruers swap src and dst // petergebruers there are 5 rssi values because there are // 4 repeaters + 1 sending node strncpy(_data->m_rssi_1, m_rssi_1, sizeof(_data->m_rssi_1)); strncpy(_data->m_rssi_2, m_rssi_2, sizeof(_data->m_rssi_2)); strncpy(_data->m_rssi_3, m_rssi_3, sizeof(_data->m_rssi_3)); strncpy(_data->m_rssi_4, m_rssi_4, sizeof(_data->m_rssi_4)); strncpy(_data->m_rssi_5, m_rssi_5, sizeof(_data->m_rssi_5)); _data->m_ackChannel = m_ackChannel; _data->m_lastTxChannel = m_lastTxChannel; _data->m_routeScheme = m_routeScheme; _data->m_routeUsed[0] = m_routeUsed[0]; _data->m_routeUsed[1] = m_routeUsed[1]; _data->m_routeUsed[2] = m_routeUsed[2]; _data->m_routeUsed[3] = m_routeUsed[3]; //petergebruers: missed m_routeSpeed _data->m_routeSpeed = m_routeSpeed; _data->m_routeTries = m_routeTries; _data->m_lastFailedLinkFrom = m_lastFailedLinkFrom; _data->m_lastFailedLinkTo = m_lastFailedLinkTo; _data->m_quality = m_quality; memcpy(_data->m_lastReceivedMessage, m_lastReceivedMessage, sizeof(m_lastReceivedMessage)); for (map::const_iterator it = m_commandClassMap.begin(); it != m_commandClassMap.end(); ++it) { CommandClassData ccData; ccData.m_commandClassId = it->second->GetCommandClassId(); ccData.m_sentCnt = it->second->GetSentCnt(); ccData.m_receivedCnt = it->second->GetReceivedCnt(); _data->m_ccData.push_back(ccData); } } //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Node::DeviceClass::DeviceClass(TiXmlElement const* _el) : m_mandatoryCommandClasses(NULL), m_basicMapping(0) { char const* str = _el->Attribute("label"); if (str) { m_label = str; } str = _el->Attribute("command_classes"); if (str) { // Parse the comma delimted command class // list into a temporary vector. vector ccs; char* pos = const_cast(str); while (*pos) { ccs.push_back((uint8) strtol(pos, &pos, 16)); if ((*pos) == ',') { ++pos; } } // Copy the vector contents into an array. size_t numCCs = ccs.size(); m_mandatoryCommandClasses = new uint8[numCCs + 1]; m_mandatoryCommandClasses[numCCs] = 0; // Zero terminator for (uint32 i = 0; i < numCCs; ++i) { m_mandatoryCommandClasses[i] = ccs[i]; } } str = _el->Attribute("basic"); if (str) { char* pStop; m_basicMapping = (uint8) strtol(str, &pStop, 16); } } //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Node::GenericDeviceClass::GenericDeviceClass(TiXmlElement const* _el) : DeviceClass(_el) { // Add any specific device classes TiXmlElement const* child = _el->FirstChildElement(); while (child) { char const* str = child->Value(); if (str && !strcmp(str, "Specific")) { char const* keyStr = child->Attribute("key"); if (keyStr) { char* pStop; uint8 key = (uint8) strtol(keyStr, &pStop, 16); m_specificDeviceClasses[key] = new DeviceClass(child); } } child = child->NextSiblingElement(); } } //----------------------------------------------------------------------------- // // Destructor //----------------------------------------------------------------------------- Node::GenericDeviceClass::~GenericDeviceClass() { while (!m_specificDeviceClasses.empty()) { map::iterator it = m_specificDeviceClasses.begin(); delete it->second; m_specificDeviceClasses.erase(it); } } //----------------------------------------------------------------------------- // // Get a specific device class object //----------------------------------------------------------------------------- Node::DeviceClass* Node::GenericDeviceClass::GetSpecificDeviceClass(uint8 const& _specific) { map::iterator it = m_specificDeviceClasses.find(_specific); if (it != m_specificDeviceClasses.end()) { return it->second; } return NULL; } //----------------------------------------------------------------------------- // // Generate a NONCE key for this node //----------------------------------------------------------------------------- uint8 *Node::GenerateNonceKey() { uint8 idx = this->m_lastnonce; /* The first byte must be unique and non-zero. The others are random. Per Numerical Recipes in C its best to use the high-order byte. The floating point calculation here doesn't assume the size of the random integer, otherwise we could just shift the high byte over. */ uint8 match = 0; do { this->m_nonces[idx][0] = 1 + (uint8) (255.0 * rand() / (RAND_MAX + 1.0)); match = 0; for (int i = 0; i < 8; i++) { if (i == idx) { continue; } if (this->m_nonces[idx][0] == this->m_nonces[i][0]) { match = 1; } } } while (match); /* The other bytes have no restrictions. */ for (int i = 1; i < 8; i++) { this->m_nonces[idx][i] = (int) (256.0 * rand() / (RAND_MAX + 1.0)); } this->m_lastnonce++; if (this->m_lastnonce >= 8) this->m_lastnonce = 0; for (uint8 i = 0; i < 8; i++) { Internal::PrintHex("NONCES", (const uint8_t*) this->m_nonces[i], 8); } return &this->m_nonces[idx][0]; } //----------------------------------------------------------------------------- // // Get a NONCE key for this node that matches the nonceid. //----------------------------------------------------------------------------- uint8 *Node::GetNonceKey(uint32 nonceid) { for (uint8 i = 0; i < 8; i++) { /* make sure the nonceid matches the first byte of our stored Nonce */ if (nonceid == this->m_nonces[i][0]) { return &this->m_nonces[i][0]; } } Log::Write(LogLevel_Warning, m_nodeId, "A Nonce with id %x does not exist", nonceid); for (uint8 i = 0; i < 8; i++) { Internal::PrintHex("NONCES", (const uint8_t*) this->m_nonces[i], 8); } return NULL; } //----------------------------------------------------------------------------- // // Get the ZWave+ DeviceType as a String //----------------------------------------------------------------------------- string Node::GetDeviceTypeString() { if (!s_deviceClassesLoaded) { ReadDeviceClasses(); } map::iterator nit = s_deviceTypeClasses.find(m_deviceType); if (nit != s_deviceTypeClasses.end()) { DeviceClass* deviceClass = nit->second; return deviceClass->GetLabel(); } return ""; } //----------------------------------------------------------------------------- // // Get the ZWave+ RoleType as a String //----------------------------------------------------------------------------- string Node::GetRoleTypeString() { if (!s_deviceClassesLoaded) { ReadDeviceClasses(); } map::iterator nit = s_roleDeviceClasses.find(m_role); if (nit != s_roleDeviceClasses.end()) { DeviceClass* deviceClass = nit->second; return deviceClass->GetLabel(); } return ""; } //----------------------------------------------------------------------------- // // Get the ZWave+ NodeType as a String //----------------------------------------------------------------------------- string Node::GetNodeTypeString() { if (!s_deviceClassesLoaded) { ReadDeviceClasses(); } map::iterator nit = s_nodeTypes.find(m_nodeType); if (nit != s_nodeTypes.end()) { DeviceClass* deviceClass = nit->second; return deviceClass->GetLabel(); } return ""; } //----------------------------------------------------------------------------- // // Is the Node Reset? //----------------------------------------------------------------------------- bool Node::IsNodeReset() { Internal::CC::DeviceResetLocally *drl = static_cast(GetCommandClass(Internal::CC::DeviceResetLocally::StaticGetCommandClassId())); if (drl) return drl->IsDeviceReset(); else return false; } //----------------------------------------------------------------------------- // // Assign a ProductDetails class to this node //----------------------------------------------------------------------------- void Node::SetProductDetails(std::shared_ptr product) { /* add the new ProductDescriptor */ m_Product = product; } //----------------------------------------------------------------------------- // // get the Path to the configFile for this device. //----------------------------------------------------------------------------- string Node::getConfigPath() { if (m_Product) return m_Product->GetConfigPath(); else return ""; } //----------------------------------------------------------------------------- // // Set Loaded Config File Revision //----------------------------------------------------------------------------- void Node::setFileConfigRevision(uint32 rev) { m_fileConfigRevision = rev; Internal::CC::ManufacturerSpecific* cc = static_cast(GetCommandClass(Internal::CC::ManufacturerSpecific::StaticGetCommandClassId())); if (cc) { cc->setFileConfigRevision(rev); } /* check if this is the latest */ checkLatestConfigRevision(); } //----------------------------------------------------------------------------- // // Set Loaded Config File Revision //----------------------------------------------------------------------------- void Node::setLoadedConfigRevision(uint32 rev) { m_loadedConfigRevision = rev; Internal::CC::ManufacturerSpecific* cc = static_cast(GetCommandClass(Internal::CC::ManufacturerSpecific::StaticGetCommandClassId())); if (cc) { cc->setLoadedConfigRevision(rev); } } //----------------------------------------------------------------------------- // // Set Latest Config File Revision //----------------------------------------------------------------------------- void Node::setLatestConfigRevision(uint32 rev) { m_latestConfigRevision = rev; Internal::CC::ManufacturerSpecific* cc = static_cast(GetCommandClass(Internal::CC::ManufacturerSpecific::StaticGetCommandClassId())); if (cc) { cc->setLatestConfigRevision(rev); } } //----------------------------------------------------------------------------- // // Check if our Config File is the latest //----------------------------------------------------------------------------- void Node::checkLatestConfigRevision() { if (m_fileConfigRevision != 0) { GetDriver()->CheckNodeConfigRevision(this); } } //----------------------------------------------------------------------------- // // Get MetaData about a node //----------------------------------------------------------------------------- string const Node::GetMetaData(MetaDataFields field) { if (this->m_metadata.find(field) != this->m_metadata.end()) { return this->m_metadata[field]; } return string(); } //----------------------------------------------------------------------------- // // Get MetaData about a node //----------------------------------------------------------------------------- Node::ChangeLogEntry const Node::GetChangeLog(uint32_t revision) { if (this->m_changeLog.find(revision) != this->m_changeLog.end()) { return this->m_changeLog[revision]; } ChangeLogEntry cle; cle.revision = -1; return cle; } //----------------------------------------------------------------------------- // // Translate the MetaData String to a ID //----------------------------------------------------------------------------- Node::MetaDataFields Node::GetMetaDataId(string name) { if (name == "OzwInfoPage") return MetaData_OzwInfoPage_URL; if (name == "ZWProductPage") return MetaData_ZWProductPage_URL; if (name == "ProductPic") return MetaData_ProductPic; if (name == "Description") return MetaData_Description; if (name == "ProductManual") return MetaData_ProductManual_URL; if (name == "ProductPage") return MetaData_ProductPage_URL; if (name == "InclusionDescription") return MetaData_InclusionHelp; if (name == "ExclusionDescription") return MetaData_ExclusionHelp; if (name == "ResetDescription") return MetaData_ResetHelp; if (name == "WakeupDescription") return MetaData_WakeupHelp; if (name == "ProductSupport") return MetaData_ProductSupport_URL; if (name == "FrequencyName") return MetaData_Frequency; if (name == "Name") return MetaData_Name; if (name == "Identifier") return MetaData_Identifier; return MetaData_Invalid; } //----------------------------------------------------------------------------- // // Translate the MetaDataID to a String //----------------------------------------------------------------------------- string const Node::GetMetaDataString(Node::MetaDataFields id) { switch (id) { case MetaData_OzwInfoPage_URL: return "OzwInfoPage"; case MetaData_ZWProductPage_URL: return "ZWProductPage"; case MetaData_ProductPic: return "ProductPic"; case MetaData_Description: return "Description"; case MetaData_ProductManual_URL: return "ProductManual"; case MetaData_ProductPage_URL: return "ProductPage"; case MetaData_InclusionHelp: return "InclusionDescription"; case MetaData_ExclusionHelp: return "ExclusionDescription"; case MetaData_ResetHelp: return "ResetDescription"; case MetaData_WakeupHelp: return "WakeupDescription"; case MetaData_ProductSupport_URL: return "ProductSupport"; case MetaData_Frequency: return "FrequencyName"; case MetaData_Name: return "Name"; case MetaData_Identifier: return "Identifier"; case MetaData_Invalid: return ""; } return ""; } //----------------------------------------------------------------------------- // // Read the MetaData from the Config File //----------------------------------------------------------------------------- void Node::ReadMetaDataFromXML(TiXmlElement const* _valueElement) { TiXmlElement const* ccElement = _valueElement->FirstChildElement(); while (ccElement) { if (!strcmp(ccElement->Value(), "MetaData")) { TiXmlElement const* metadata = ccElement->FirstChildElement(); while (metadata) { if (!strcmp(metadata->Value(), "MetaDataItem")) { string name = metadata->Attribute("name"); if (GetMetaDataId(name) == MetaData_Invalid) { Log::Write(LogLevel_Warning, m_nodeId, "Invalid MetaData Name in Config: %s", name.c_str()); metadata = metadata->NextSiblingElement(); continue; } /* these are the MetaData that have type/id entries */ switch (GetMetaDataId(name)) { case MetaData_ZWProductPage_URL: case MetaData_Identifier: case MetaData_Frequency: { int intVal; uint16_t type = 0; uint16_t id = 0; if (TIXML_SUCCESS == metadata->QueryIntAttribute("type", &intVal)) { type = (uint16_t) intVal; } if (TIXML_SUCCESS == metadata->QueryIntAttribute("id", &intVal)) { id = (uint16_t) intVal; } if ((type != GetProductType()) || (id != GetProductId())) { metadata = metadata->NextSiblingElement(); continue; } break; } /* for the rest, just take the standard entry */ default: break; } if (metadata->GetText()) this->m_metadata[GetMetaDataId(name)] = metadata->GetText(); } else if (!strcmp(metadata->Value(), "ChangeLog")) { TiXmlElement const* entry = metadata->FirstChildElement("Entry"); while (entry) { ChangeLogEntry cle; cle.author = entry->Attribute("author"); cle.date = entry->Attribute("date"); cle.description = entry->GetText(); entry->QueryIntAttribute("revision", &cle.revision); m_changeLog.insert(std::pair(cle.revision, cle)); entry = entry->NextSiblingElement("Entry"); } } metadata = metadata->NextSiblingElement(); } } ccElement = ccElement->NextSiblingElement(); } } //----------------------------------------------------------------------------- // // Write the MetaData to the Cache File //----------------------------------------------------------------------------- void Node::WriteMetaDataXML(TiXmlElement *mdElement) { // Write out the MetaDataItems for (map::iterator it = m_metadata.begin(); it != m_metadata.end(); ++it) { /* only write if its a valid MetaData */ if (it->first < Node::MetaData_Invalid) { TiXmlElement* mdiElement = new TiXmlElement("MetaDataItem"); mdiElement->SetAttribute("name", GetMetaDataString(it->first).c_str()); switch (it->first) { case MetaData_ZWProductPage_URL: case MetaData_Identifier: case MetaData_Frequency: mdiElement->SetAttribute("type", GetProductType()); mdiElement->SetAttribute("id", GetProductId()); break; /* for the rest, just take the standard entry */ default: break; } TiXmlText* textElement = new TiXmlText(it->second.c_str()); mdiElement->LinkEndChild(textElement); mdElement->LinkEndChild(mdiElement); } } if (m_changeLog.size() > 0) { TiXmlElement* cl = new TiXmlElement("ChangeLog"); for (map::iterator it = m_changeLog.begin(); it != m_changeLog.end(); ++it) { TiXmlElement* cle = new TiXmlElement("Entry"); cle->SetAttribute("author", it->second.author.c_str()); cle->SetAttribute("date", it->second.date.c_str()); cle->SetAttribute("revision", it->second.revision); TiXmlText* textElement = new TiXmlText(it->second.description.c_str()); cle->LinkEndChild(textElement); cl->LinkEndChild(cle); } mdElement->LinkEndChild(cl); } } openzwave-1.6.1914/cpp/src/Msg.cpp0000644000175200017520000002214714032142455013531 00000000000000//----------------------------------------------------------------------------- // // Msg.cpp // // Represents a Z-Wave message // // Copyright (c) 2010 Mal Lansell // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Defs.h" #include "Msg.h" #include "Node.h" #include "Manager.h" #include "Utils.h" #include "ZWSecurity.h" #include "platform/Log.h" #include "command_classes/MultiInstance.h" #include "command_classes/Security.h" #include "aes/aescpp.h" namespace OpenZWave { namespace Internal { /* Callback for normal messages start at 10. Special Messages using a Callback prior to 10 */ uint8 Msg::s_nextCallbackId = 10; //----------------------------------------------------------------------------- // // Constructor //----------------------------------------------------------------------------- Msg::Msg(string const& _logText, uint8 _targetNodeId, uint8 const _msgType, uint8 const _function, bool const _bCallbackRequired, bool const _bReplyRequired, // = true uint8 const _expectedReply, // = 0 uint8 const _expectedCommandClassId // = 0 ) : m_logText(_logText), m_bFinal(false), m_bCallbackRequired(_bCallbackRequired), m_callbackId(0), m_expectedReply(0), m_expectedCommandClassId(_expectedCommandClassId), m_length(4), m_targetNodeId(_targetNodeId), m_sendAttempts(0), m_maxSendAttempts( MAX_TRIES), m_instance(1), m_endPoint(0), m_flags(0), m_encrypted(false), m_noncerecvd(false), m_homeId(0), m_resendDuetoCANorNAK(false) { if (_bReplyRequired) { // Wait for this message before considering the transaction complete m_expectedReply = _expectedReply ? _expectedReply : _function; } memset(m_buffer, 0x00, 256); memset(e_buffer, 0x00, 256); m_buffer[0] = SOF; m_buffer[1] = 0; // Length of the following data, filled in during Finalize. m_buffer[2] = _msgType; m_buffer[3] = _function; } //----------------------------------------------------------------------------- // // Used to enable wrapping with MultiInstance/MultiChannel during finalize. //----------------------------------------------------------------------------- void Msg::SetInstance(Internal::CC::CommandClass* _cc, uint8 const _instance) { // Determine whether we should encapsulate the message in MultiInstance or MultiCommand if (Node* node = _cc->GetNodeUnsafe()) { Internal::CC::MultiInstance* micc = static_cast(node->GetCommandClass(Internal::CC::MultiInstance::StaticGetCommandClassId())); m_instance = _instance; if (micc) { if (micc->GetVersion() > 1) { m_endPoint = _cc->GetEndPoint(_instance); if (m_endPoint != 0) { // Set the flag bit to indicate MultiChannel rather than MultiInstance m_flags |= m_MultiChannel; m_expectedCommandClassId = Internal::CC::MultiInstance::StaticGetCommandClassId(); } } else if (m_instance > 1) { // Set the flag bit to indicate MultiInstance rather than MultiChannel m_flags |= m_MultiInstance; m_expectedCommandClassId = Internal::CC::MultiInstance::StaticGetCommandClassId(); } } } } //----------------------------------------------------------------------------- // // Add a byte to the message //----------------------------------------------------------------------------- void Msg::Append(uint8 const _data) { m_buffer[m_length++] = _data; } //----------------------------------------------------------------------------- // // Add a byte array to the message //----------------------------------------------------------------------------- void Msg::AppendArray(const uint8* const _data, const uint8 _length) { for (uint8 i = 0; i < _length; i++) { this->Append(_data[i]); } } //----------------------------------------------------------------------------- // // Fill in the length and checksum values for the message //----------------------------------------------------------------------------- void Msg::Finalize() { if (m_bFinal) { // Already finalized return; } // Deal with Multi-Channel/Instance encapsulation if ((m_flags & (m_MultiChannel | m_MultiInstance)) != 0) { MultiEncap(); } // Add the callback id if (m_bCallbackRequired) { // Set the length byte m_buffer[1] = m_length; // Length of following data if (0 == s_nextCallbackId) { s_nextCallbackId = 10; } m_buffer[m_length++] = s_nextCallbackId; m_callbackId = s_nextCallbackId++; } else { // Set the length byte m_buffer[1] = m_length - 1; // Length of following data } // Calculate the checksum uint8 checksum = 0xff; for (uint32 i = 1; i < m_length; ++i) { checksum ^= m_buffer[i]; } m_buffer[m_length++] = checksum; m_bFinal = true; } //----------------------------------------------------------------------------- // // If this message has a callback ID, increment it and recalculate the checksum //----------------------------------------------------------------------------- void Msg::UpdateCallbackId() { if (m_bCallbackRequired) { if (0 == s_nextCallbackId) { s_nextCallbackId = 10; } // update the callback ID m_buffer[m_length - 2] = s_nextCallbackId; m_callbackId = s_nextCallbackId++; // Recalculate the checksum uint8 checksum = 0xff; for (int32 i = 1; i < m_length - 1; ++i) { checksum ^= m_buffer[i]; } m_buffer[m_length - 1] = checksum; } } //----------------------------------------------------------------------------- // // Create a string containing the raw data //----------------------------------------------------------------------------- std::string Msg::GetAsString() { string str = m_logText; char byteStr[16]; if (m_targetNodeId != 0xff) { snprintf(byteStr, sizeof(byteStr), " (Node=%d)", m_targetNodeId); str += byteStr; } str += ": "; for (uint32 i = 0; i < m_length; ++i) { if (i) { str += ", "; } snprintf(byteStr, sizeof(byteStr), "0x%.2x", m_buffer[i]); str += byteStr; } return str; } //----------------------------------------------------------------------------- // // Encapsulate the data inside a MultiInstance/Multicommand message //----------------------------------------------------------------------------- void Msg::MultiEncap() { char str[256]; if (m_buffer[3] != FUNC_ID_ZW_SEND_DATA) { return; } // Insert the encap header if ((m_flags & m_MultiChannel) != 0) { // MultiChannel for (uint32 i = m_length - 1; i >= 6; --i) { m_buffer[i + 4] = m_buffer[i]; } m_buffer[5] += 4; m_buffer[6] = Internal::CC::MultiInstance::StaticGetCommandClassId(); m_buffer[7] = Internal::CC::MultiInstance::MultiChannelCmd_Encap; m_buffer[8] = 1; m_buffer[9] = m_endPoint; m_length += 4; snprintf(str, sizeof(str), "MultiChannel Encapsulated (instance=%d): %s", m_instance, m_logText.c_str()); m_logText = str; } else { // MultiInstance for (uint32 i = m_length - 1; i >= 6; --i) { m_buffer[i + 3] = m_buffer[i]; } m_buffer[5] += 3; m_buffer[6] = Internal::CC::MultiInstance::StaticGetCommandClassId(); m_buffer[7] = Internal::CC::MultiInstance::MultiInstanceCmd_Encap; m_buffer[8] = m_instance; m_length += 3; snprintf(str, sizeof(str), "MultiInstance Encapsulated (instance=%d): %s", m_instance, m_logText.c_str()); m_logText = str; } } //----------------------------------------------------------------------------- // // Get a pointer to our driver //----------------------------------------------------------------------------- OpenZWave::Driver* Msg::GetDriver() const { return (Manager::Get()->GetDriver(m_homeId)); } uint8* Msg::GetBuffer() { Log::Write(LogLevel_Info, m_targetNodeId, "Encrypted Flag is %d", m_encrypted); if (m_encrypted == false) return m_buffer; else if (EncryptBuffer(m_buffer, m_length, GetDriver(), GetDriver()->GetControllerNodeId(), m_targetNodeId, m_nonce, e_buffer)) { return e_buffer; } else { Log::Write(LogLevel_Warning, m_targetNodeId, "Failed to Encrypt Packet"); return NULL; } } } // namespace Internal } // namespace OpenZWave openzwave-1.6.1914/cpp/examples/0000777000175200017520000000000014032143200013371 500000000000000openzwave-1.6.1914/cpp/examples/MinOZW/0000777000175200017520000000000014032143200014514 500000000000000openzwave-1.6.1914/cpp/examples/MinOZW/MinOZW.in0000644000175200017520000000042414032142455016116 00000000000000#!/bin/sh LD_PATH=@LDPATH@ if test $# -gt 0; then if test $1 == "gdb"; then LD_LIBRARY_PATH="$LD_PATH:$LD_LIBRARY_PATH" gdb .lib/MinOZW else LD_LIBRARY_PATH="$LD_PATH:$LD_LIBRARY_PATH" .lib/MinOZW $@ fi else LD_LIBRARY_PATH="$LD_PATH:$LD_LIBRARY_PATH" .lib/MinOZW fi openzwave-1.6.1914/cpp/examples/MinOZW/Main.cpp0000644000175200017520000003307214032142455016040 00000000000000//----------------------------------------------------------------------------- // // Main.cpp // // Minimal application to test OpenZWave. // // Creates an OpenZWave::Driver and the waits. In Debug builds // you should see verbose logging to the console, which will // indicate that communications with the Z-Wave network are working. // // Copyright (c) 2010 Mal Lansell // // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include #include #include #include "Options.h" #include "Manager.h" #include "Driver.h" #include "Node.h" #include "Group.h" #include "Notification.h" #include "value_classes/ValueStore.h" #include "value_classes/Value.h" #include "value_classes/ValueBool.h" #include "platform/Log.h" #include "Defs.h" using namespace OpenZWave; static uint32 g_homeId = 0; static bool g_initFailed = false; typedef struct { uint32 m_homeId; uint8 m_nodeId; bool m_polled; list m_values; }NodeInfo; static list g_nodes; static pthread_mutex_t g_criticalSection; static pthread_cond_t initCond = PTHREAD_COND_INITIALIZER; static pthread_mutex_t initMutex = PTHREAD_MUTEX_INITIALIZER; //----------------------------------------------------------------------------- // // Return the NodeInfo object associated with this notification //----------------------------------------------------------------------------- NodeInfo* GetNodeInfo ( Notification const* _notification ) { uint32 const homeId = _notification->GetHomeId(); uint8 const nodeId = _notification->GetNodeId(); for( list::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it ) { NodeInfo* nodeInfo = *it; if( ( nodeInfo->m_homeId == homeId ) && ( nodeInfo->m_nodeId == nodeId ) ) { return nodeInfo; } } return NULL; } //----------------------------------------------------------------------------- // // Callback that is triggered when a value, group or node changes //----------------------------------------------------------------------------- void OnNotification ( Notification const* _notification, void* _context ) { // Must do this inside a critical section to avoid conflicts with the main thread pthread_mutex_lock( &g_criticalSection ); // std::cout << "Notification: " << _notification << std::endl; switch( _notification->GetType() ) { case Notification::Type_ValueAdded: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { // Add the new value to our list nodeInfo->m_values.push_back( _notification->GetValueID() ); } break; } case Notification::Type_ValueRemoved: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { // Remove the value from out list for( list::iterator it = nodeInfo->m_values.begin(); it != nodeInfo->m_values.end(); ++it ) { if( (*it) == _notification->GetValueID() ) { nodeInfo->m_values.erase( it ); break; } } } break; } case Notification::Type_ValueChanged: { // One of the node values has changed if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { (void)nodeInfo; // placeholder for real action } break; } case Notification::Type_Group: { // One of the node's association groups has changed if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { (void)nodeInfo; // placeholder for real action } break; } case Notification::Type_NodeAdded: { // Add the new node to our list NodeInfo* nodeInfo = new NodeInfo(); nodeInfo->m_homeId = _notification->GetHomeId(); nodeInfo->m_nodeId = _notification->GetNodeId(); nodeInfo->m_polled = false; g_nodes.push_back( nodeInfo ); break; } case Notification::Type_NodeRemoved: { // Remove the node from our list uint32 const homeId = _notification->GetHomeId(); uint8 const nodeId = _notification->GetNodeId(); for( list::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it ) { NodeInfo* nodeInfo = *it; if( ( nodeInfo->m_homeId == homeId ) && ( nodeInfo->m_nodeId == nodeId ) ) { g_nodes.erase( it ); delete nodeInfo; break; } } break; } case Notification::Type_NodeEvent: { // We have received an event from the node, caused by a // basic_set or hail message. if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { (void)nodeInfo; // placeholder for real action } break; } case Notification::Type_PollingDisabled: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { nodeInfo->m_polled = false; } break; } case Notification::Type_PollingEnabled: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { nodeInfo->m_polled = true; } break; } case Notification::Type_DriverReady: { g_homeId = _notification->GetHomeId(); printf("Driver ready with HomeID: 0x%.8x\n", g_homeId); bool ext_tx = Manager::Get()->HasExtendedTxStatus(g_homeId); if (ext_tx) { printf("Controller has extended TxStatus.\n"); } else { printf("Controller does not have extended TxStatus.\n"); } break; } case Notification::Type_DriverFailed: { g_initFailed = true; pthread_cond_broadcast(&initCond); break; } case Notification::Type_AwakeNodesQueried: break; case Notification::Type_AllNodesQueried: case Notification::Type_AllNodesQueriedSomeDead: { pthread_cond_broadcast(&initCond); break; } case Notification::Type_DriverReset: case Notification::Type_Notification: case Notification::Type_NodeNaming: case Notification::Type_NodeProtocolInfo: case Notification::Type_NodeQueriesComplete: case Notification::Type_NodeNew: case Notification::Type_SceneEvent: case Notification::Type_CreateButton: case Notification::Type_DeleteButton: case Notification::Type_ButtonOn: case Notification::Type_ButtonOff: case Notification::Type_EssentialNodeQueriesComplete: case Notification::Type_DriverRemoved: case Notification::Type_ControllerCommand: case Notification::Type_NodeReset: case Notification::Type_UserAlerts: case Notification::Type_ManufacturerSpecificDBReady: case Notification::Type_ValueRefreshed: { } } pthread_mutex_unlock( &g_criticalSection ); } //----------------------------------------------------------------------------- //

// Create the driver and then wait //----------------------------------------------------------------------------- int main( int argc, char* argv[] ) { pthread_mutexattr_t mutexattr; pthread_mutexattr_init ( &mutexattr ); pthread_mutexattr_settype( &mutexattr, PTHREAD_MUTEX_RECURSIVE ); pthread_mutex_init( &g_criticalSection, &mutexattr ); pthread_mutexattr_destroy( &mutexattr ); pthread_mutex_lock( &initMutex ); // petergebruers replace getVersionAsString() with getVersionLongAsString() because // the latter prints more information, based on the status of the repository // when "make" was run. A Makefile gets this info from git describe --long --tags --dirty printf("Starting MinOZW with OpenZWave Version %s\n", Manager::getVersionLongAsString().c_str()); // Create the OpenZWave Manager. // The first argument is the path to the config files (where the manufacturer_specific.xml file is located // The second argument is the path for saved Z-Wave network state and the log file. If you leave it NULL // the log file will appear in the program's working directory. Options::Create( "../../../config/", "", "" ); Options::Get()->AddOptionInt( "SaveLogLevel", LogLevel_Detail ); Options::Get()->AddOptionInt( "QueueLogLevel", LogLevel_Debug ); Options::Get()->AddOptionInt( "DumpTrigger", LogLevel_Error ); Options::Get()->AddOptionInt( "PollInterval", 500 ); Options::Get()->AddOptionBool( "IntervalBetweenPolls", true ); Options::Get()->AddOptionBool("ValidateValueChanges", true); Options::Get()->Lock(); Manager::Create(); // Add a callback handler to the manager. The second argument is a context that // is passed to the OnNotification method. If the OnNotification is a method of // a class, the context would usually be a pointer to that class object, to // avoid the need for the notification handler to be a static. Manager::Get()->AddWatcher( OnNotification, NULL ); // Add a Z-Wave Driver // Modify this line to set the correct serial port for your PC interface. #ifdef DARWIN string port = "/dev/cu.usbserial"; #elif WIN32 string port = "\\\\.\\COM6"; #else string port = "/dev/ttyUSB0"; #endif if ( argc > 1 ) { port = argv[1]; } if( strcasecmp( port.c_str(), "usb" ) == 0 ) { Manager::Get()->AddDriver( "HID Controller", Driver::ControllerInterface_Hid ); } else { Manager::Get()->AddDriver( port ); } // Now we just wait for either the AwakeNodesQueried or AllNodesQueried notification, // then write out the config file. // In a normal app, we would be handling notifications and building a UI for the user. pthread_cond_wait( &initCond, &initMutex ); // Since the configuration file contains command class information that is only // known after the nodes on the network are queried, wait until all of the nodes // on the network have been queried (at least the "listening" ones) before // writing the configuration file. (Maybe write again after sleeping nodes have // been queried as well.) if( !g_initFailed ) { // The section below demonstrates setting up polling for a variable. In this simple // example, it has been hardwired to poll COMMAND_CLASS_BASIC on the each node that // supports this setting. pthread_mutex_lock( &g_criticalSection ); for( list::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it ) { NodeInfo* nodeInfo = *it; // skip the controller (most likely node 1) //if( nodeInfo->m_nodeId == 1) continue; printf("NodeID: %d \n ", nodeInfo->m_nodeId); printf("\t NodeName: %s \n ", Manager::Get()->GetNodeName(nodeInfo->m_homeId,nodeInfo->m_nodeId).c_str()); printf("\t ManufacturerName: %s \n ", Manager::Get()->GetNodeManufacturerName(nodeInfo->m_homeId,nodeInfo->m_nodeId).c_str()); printf("\t NodeProductName: %s \n ", Manager::Get()->GetNodeProductName(nodeInfo->m_homeId,nodeInfo->m_nodeId).c_str()); printf("Values announced by the nodes without polling: \n"); for( list::iterator it2 = nodeInfo->m_values.begin(); it2 != nodeInfo->m_values.end(); ++it2 ) { ValueID v = *it2; printf("\t ValueLabel: %s \n", Manager::Get()->GetValueLabel(v).c_str()); printf("\t\t ValueType: %s (%d) \n", v.GetTypeAsString().c_str(), v.GetType()); printf("\t\t ValueHelp: %s \n", Manager::Get()->GetValueHelp(v).c_str()); printf("\t\t ValueUnits: %s \n", Manager::Get()->GetValueUnits(v).c_str()); printf("\t\t ValueMin: %d \n", Manager::Get()->GetValueMin(v)); printf("\t\t ValueMax: %d \n", Manager::Get()->GetValueMax(v)); printf("\t\t ValueGenre: %s (%d)\n", v.GetGenreAsString().c_str(), v.GetGenre()); if( v.GetCommandClassId() == COMMAND_CLASS_BASIC ) { // Manager::Get()->EnablePoll( v, 2 ); // enables polling with "intensity" of 2, though this is irrelevant with only one value polled break; } } } pthread_mutex_unlock( &g_criticalSection ); // If we want to access our NodeInfo list, that has been built from all the // notification callbacks we received from the library, we have to do so // from inside a Critical Section. This is because the callbacks occur on other // threads, and we cannot risk the list being changed while we are using it. // We must hold the critical section for as short a time as possible, to avoid // stalling the OpenZWave drivers. // At this point, the program just waits for 3 minutes (to demonstrate polling), // then exits //for( int i = 0; i < 60*3; i++ ) //{ // pthread_mutex_lock( &g_criticalSection ); // but NodeInfo list and similar data should be inside critical section // pthread_mutex_unlock( &g_criticalSection ); // sleep(1); //} Driver::DriverData data; Manager::Get()->GetDriverStatistics( g_homeId, &data ); printf("SOF: %d ACK Waiting: %d Read Aborts: %d Bad Checksums: %d\n", data.m_SOFCnt, data.m_ACKWaiting, data.m_readAborts, data.m_badChecksum); printf("Reads: %d Writes: %d CAN: %d NAK: %d ACK: %d Out of Frame: %d\n", data.m_readCnt, data.m_writeCnt, data.m_CANCnt, data.m_NAKCnt, data.m_ACKCnt, data.m_OOFCnt); printf("Dropped: %d Retries: %d\n", data.m_dropped, data.m_retries); } // program exit (clean up) if( strcasecmp( port.c_str(), "usb" ) == 0 ) { Manager::Get()->RemoveDriver( "HID Controller" ); } else { Manager::Get()->RemoveDriver( port ); } Manager::Get()->RemoveWatcher( OnNotification, NULL ); Manager::Destroy(); Options::Destroy(); pthread_mutex_destroy( &g_criticalSection ); for( list::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it ) { NodeInfo* nodeInfo = *it; nodeInfo->m_values.clear(); delete nodeInfo; } g_nodes.clear(); return 0; } openzwave-1.6.1914/cpp/examples/MinOZW/Makefile0000644000175200017520000000527414032142455016113 00000000000000# # Makefile for OpenzWave Mac OS X applications # Greg Satz # GNU make only # requires libudev-dev .SUFFIXES: .d .cpp .o .a .PHONY: default clean DEBUG_CFLAGS := -Wall -Wno-format -ggdb -DDEBUG $(CPPFLAGS) -std=c++11 RELEASE_CFLAGS := -Wall -Wno-unknown-pragmas -Wno-format -O3 $(CPPFLAGS) -std=c++11 DEBUG_LDFLAGS := -g top_srcdir := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))../../../) #where is put the temporary library LIBDIR ?= $(top_builddir) INCLUDES := -I $(top_srcdir)/cpp/src -I $(top_srcdir)/cpp/tinyxml/ -I $(top_srcdir)/cpp/hidapi/hidapi/ LIBS = $(wildcard $(LIBDIR)/*.so $(LIBDIR)/*.dylib $(top_builddir)/cpp/build/*.so $(top_builddir)/cpp/build/*.dylib ) LIBSDIR = $(abspath $(dir $(firstword $(LIBS)))) minozwsrc := $(notdir $(wildcard $(top_srcdir)/cpp/examples/MinOZW/*.cpp)) VPATH := $(top_srcdir)/cpp/examples/MinOZW top_builddir ?= $(CURDIR) default: $(top_builddir)/MinOZW include $(top_srcdir)/cpp/build/support.mk -include $(patsubst %.cpp,$(DEPDIR)/%.d,$(minozwsrc)) #if we are on a Mac, add these flags and libs to the compile and link phases ifeq ($(UNAME),Darwin) CFLAGS += -DDARWIN ifeq ($(DARWIN_MOJAVE_UP),1) # Newer macOS releases don't support i386 so only build 64-bit TARCH += -arch x86_64 else # Support older versions of OSX that may need to build both 32-bit and 64-bit TARCH += -arch i386 -arch x86_64 endif endif # Dup from main makefile, but that is not included when building here.. ifeq ($(UNAME),FreeBSD) LDFLAGS+= -lusb ifeq ($(shell test $$(uname -U) -ge 1002000; echo $$?),1) ifeq (,$(wildcard /usr/local/include/iconv.h)) $(error FreeBSD pre 10.2: Please install libiconv from ports) else CFLAGS += -I/usr/local/include LDFLAGS+= -L/usr/local/lib -liconv endif endif else ifeq ($(UNAME),NetBSD) LDFLAGS+= -L/usr/pkg/lib -lusb-1.0 else ifeq ($(UNAME),SunOS) LDFLAGS+= -lusb-1.0 endif $(OBJDIR)/MinOZW: $(patsubst %.cpp,$(OBJDIR)/%.o,$(minozwsrc)) @echo "Linking MinOZW" @$(LD) $(LDFLAGS) $(TARCH) -o $@ $< $(LIBS) -pthread $(top_builddir)/MinOZW: $(top_srcdir)/cpp/examples/MinOZW/MinOZW.in $(OBJDIR)/MinOZW @echo "Creating Temporary Shell Launch Script" @$(SED) \ -e 's|[@]LDPATH@|$(LIBSDIR)|g' \ < "$<" > "$@" @chmod +x $(top_builddir)/MinOZW clean: @rm -rf $(DEPDIR) $(OBJDIR) $(top_builddir)/MinOZW ifeq ($(XMLLINT),) xmltest: $(XMLLINT) $(error xmllint command not found.) else xmltest: $(XMLLINT) @$(XMLLINT) --noout --schema ../../../config/zwcfg.xsd zwcfg_*.xml @$(XMLLINT) --noout --schema ../../../config/zwscene.xsd zwscene.xml endif install: $(OBJDIR)/MinOZW @echo "Installing into Prefix: $(PREFIX)" @install -d $(DESTDIR)/$(PREFIX)/bin/ @cp $(OBJDIR)/MinOZW $(DESTDIR)/$(PREFIX)/bin/MinOZW @chmod 755 $(DESTDIR)/$(PREFIX)/bin/MinOZW openzwave-1.6.1914/cpp/examples/windows/0000777000175200017520000000000014032143200015063 500000000000000openzwave-1.6.1914/cpp/examples/windows/MinOZW/0000777000175200017520000000000014032143200016206 500000000000000openzwave-1.6.1914/cpp/examples/windows/MinOZW/Main.cpp0000644000175200017520000002543614032142455017537 00000000000000//----------------------------------------------------------------------------- // // Main.cpp // // Minimal application to test OpenZWave. // // Creates an OpenZWave::Driver and the waits. In Debug builds // you should see verbose logging to the console, which will // indicate that communications with the Z-Wave network are working. // // Copyright (c) 2010 Mal Lansell // // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "Windows.h" #include "Options.h" #include "Manager.h" #include "Driver.h" #include "Node.h" #include "Group.h" #include "Notification.h" #include "value_classes/ValueStore.h" #include "value_classes/Value.h" #include "value_classes/ValueBool.h" #include "platform/Log.h" using namespace OpenZWave; static uint32 g_homeId = 0; static bool g_initFailed = false; static bool g_nodesQueried = false; typedef struct { uint32 m_homeId; uint8 m_nodeId; bool m_polled; list m_values; }NodeInfo; static list g_nodes; static CRITICAL_SECTION g_criticalSection; //----------------------------------------------------------------------------- // // Return the NodeInfo object associated with this notification //----------------------------------------------------------------------------- NodeInfo* GetNodeInfo ( Notification const* _notification ) { uint32 const homeId = _notification->GetHomeId(); uint8 const nodeId = _notification->GetNodeId(); for( list::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it ) { NodeInfo* nodeInfo = *it; if( ( nodeInfo->m_homeId == homeId ) && ( nodeInfo->m_nodeId == nodeId ) ) { return nodeInfo; } } return NULL; } //----------------------------------------------------------------------------- // // Callback that is triggered when a value, group or node changes //----------------------------------------------------------------------------- void OnNotification ( Notification const* _notification, void* _context ) { // Must do this inside a critical section to avoid conflicts with the main thread EnterCriticalSection( &g_criticalSection ); switch( _notification->GetType() ) { case Notification::Type_ValueAdded: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { // Add the new value to our list nodeInfo->m_values.push_back( _notification->GetValueID() ); } break; } case Notification::Type_ValueRemoved: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { // Remove the value from out list for( list::iterator it = nodeInfo->m_values.begin(); it != nodeInfo->m_values.end(); ++it ) { if( (*it) == _notification->GetValueID() ) { nodeInfo->m_values.erase( it ); break; } } } break; } case Notification::Type_ValueChanged: { // One of the node values has changed if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { nodeInfo = nodeInfo; // placeholder for real action } break; } case Notification::Type_Group: { // One of the node's association groups has changed if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { nodeInfo = nodeInfo; // placeholder for real action } break; } case Notification::Type_NodeAdded: { // Add the new node to our list NodeInfo* nodeInfo = new NodeInfo(); nodeInfo->m_homeId = _notification->GetHomeId(); nodeInfo->m_nodeId = _notification->GetNodeId(); nodeInfo->m_polled = false; g_nodes.push_back( nodeInfo ); break; } case Notification::Type_NodeRemoved: { // Remove the node from our list uint32 const homeId = _notification->GetHomeId(); uint8 const nodeId = _notification->GetNodeId(); for( list::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it ) { NodeInfo* nodeInfo = *it; if( ( nodeInfo->m_homeId == homeId ) && ( nodeInfo->m_nodeId == nodeId ) ) { g_nodes.erase( it ); delete nodeInfo; break; } } break; } case Notification::Type_NodeEvent: { // We have received an event from the node, caused by a // basic_set or hail message. if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { nodeInfo = nodeInfo; // placeholder for real action } break; } case Notification::Type_PollingDisabled: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { nodeInfo->m_polled = false; } break; } case Notification::Type_PollingEnabled: { if( NodeInfo* nodeInfo = GetNodeInfo( _notification ) ) { nodeInfo->m_polled = true; } break; } case Notification::Type_DriverReady: { g_homeId = _notification->GetHomeId(); break; } case Notification::Type_DriverFailed: { g_initFailed = true; break; } case Notification::Type_AwakeNodesQueried: case Notification::Type_AllNodesQueried: case Notification::Type_AllNodesQueriedSomeDead: { g_nodesQueried = true; break; } case Notification::Type_DriverReset: case Notification::Type_NodeNaming: case Notification::Type_NodeProtocolInfo: case Notification::Type_NodeQueriesComplete: default: { } } LeaveCriticalSection( &g_criticalSection ); } //----------------------------------------------------------------------------- //
// Create the driver and then wait //----------------------------------------------------------------------------- int main( int argc, char* argv[] ) { InitializeCriticalSection( &g_criticalSection ); // Create the OpenZWave Manager. // The first argument is the path to the config files (where the manufacturer_specific.xml file is located // The second argument is the path for saved Z-Wave network state and the log file. If you leave it NULL // the log file will appear in the program's working directory. Options::Create( "../../../../../config/", "", "" ); Options::Get()->AddOptionInt( "SaveLogLevel", LogLevel_Detail ); Options::Get()->AddOptionInt( "QueueLogLevel", LogLevel_Debug ); Options::Get()->AddOptionInt( "DumpTrigger", LogLevel_Error ); Options::Get()->AddOptionInt( "PollInterval", 500 ); Options::Get()->AddOptionBool( "IntervalBetweenPolls", true ); Options::Get()->AddOptionBool("ValidateValueChanges", true); Options::Get()->Lock(); Manager::Create(); // Add a callback handler to the manager. The second argument is a context that // is passed to the OnNotification method. If the OnNotification is a method of // a class, the context would usually be a pointer to that class object, to // avoid the need for the notification handler to be a static. Manager::Get()->AddWatcher( OnNotification, NULL ); // Add a Z-Wave Driver // Modify this line to set the correct serial port for your PC interface. string port = "\\\\.\\COM4"; Manager::Get()->AddDriver( ( argc > 1 ) ? argv[1] : port ); //Manager::Get()->AddDriver( "HID Controller", Driver::ControllerInterface_Hid ); // Now we just wait for either the AwakeNodesQueried or AllNodesQueried notification, // then write out the config file. // In a normal app, we would be handling notifications and building a UI for the user. // Since the configuration file contains command class information that is only // known after the nodes on the network are queried, wait until all of the nodes // on the network have been queried (at least the "listening" ones) before // writing the configuration file. (Maybe write again after sleeping nodes have // been queried as well.) while( !g_nodesQueried ) { Sleep( 1000 ); } if( !g_initFailed ) { Manager::Get()->WriteConfig( g_homeId ); // The section below demonstrates setting up polling for a variable. In this simple // example, it has been hardwired to poll COMMAND_CLASS_BASIC on the each node that // supports this setting. EnterCriticalSection( &g_criticalSection ); for( list::iterator it = g_nodes.begin(); it != g_nodes.end(); ++it ) { NodeInfo* nodeInfo = *it; // skip the controller (most likely node 1) if( nodeInfo->m_nodeId == 1) continue; for( list::iterator it2 = nodeInfo->m_values.begin(); it2 != nodeInfo->m_values.end(); ++it2 ) { ValueID v = *it2; if( v.GetCommandClassId() == 0x20 ) { Manager::Get()->EnablePoll( v, 2 ); // enables polling with "intensity" of 2, though this is irrelevant with only one value polled break; } } } LeaveCriticalSection( &g_criticalSection ); // If we want to access our NodeInfo list, that has been built from all the // notification callbacks we received from the library, we have to do so // from inside a Critical Section. This is because the callbacks occur on other // threads, and we cannot risk the list being changed while we are using it. // We must hold the critical section for as short a time as possible, to avoid // stalling the OpenZWave drivers. // At this point, the program just waits for 3 minutes (to demonstrate polling), // then exits for( int i = 0; i < 60*3*10; i++ ) { Sleep(90); // do most of your work outside critical section EnterCriticalSection( &g_criticalSection ); Sleep(10); // but NodeInfo list and similar data should be inside critical section LeaveCriticalSection( &g_criticalSection ); } Driver::DriverData data; Manager::Get()->GetDriverStatistics( g_homeId, &data ); printf("SOF: %d ACK Waiting: %d Read Aborts: %d Bad Checksums: %d\n", data.m_SOFCnt, data.m_ACKWaiting, data.m_readAborts, data.m_badChecksum); printf("Reads: %d Writes: %d CAN: %d NAK: %d ACK: %d Out of Frame: %d\n", data.m_readCnt, data.m_writeCnt, data.m_CANCnt, data.m_NAKCnt, data.m_ACKCnt, data.m_OOFCnt); printf("Dropped: %d Retries: %d\n", data.m_dropped, data.m_retries); } // program exit (clean up) Manager::Destroy(); Options::Destroy(); DeleteCriticalSection( &g_criticalSection ); return 0; } openzwave-1.6.1914/cpp/examples/windows/MinOZW/vs2010/0000777000175200017520000000000014032143200017141 500000000000000openzwave-1.6.1914/cpp/examples/windows/MinOZW/vs2010/MinOZW.vcxproj.filters0000644000175200017520000000077414032142455023307 00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx Source Files openzwave-1.6.1914/cpp/examples/windows/MinOZW/vs2010/MinOZW.sln0000644000175200017520000000435114032142455020734 00000000000000 Microsoft Visual Studio Solution File, Format Version 11.00 # Visual C++ Express 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MinOZW", "MinOZW.vcxproj", "{22847D76-B1CF-4921-8B7A-61E248412C4A}" ProjectSection(ProjectDependencies) = postProject {497F9828-DEC2-4C80-B9E0-AD066CCB587C} = {497F9828-DEC2-4C80-B9E0-AD066CCB587C} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenZWave", "..\..\..\..\build\windows\vs2010\OpenZWave.vcxproj", "{497F9828-DEC2-4C80-B9E0-AD066CCB587C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 DebugDLL|Win32 = DebugDLL|Win32 Release|Win32 = Release|Win32 ReleaseDLL|Win32 = ReleaseDLL|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {22847D76-B1CF-4921-8B7A-61E248412C4A}.Debug|Win32.ActiveCfg = Debug|Win32 {22847D76-B1CF-4921-8B7A-61E248412C4A}.Debug|Win32.Build.0 = Debug|Win32 {22847D76-B1CF-4921-8B7A-61E248412C4A}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 {22847D76-B1CF-4921-8B7A-61E248412C4A}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 {22847D76-B1CF-4921-8B7A-61E248412C4A}.Release|Win32.ActiveCfg = Release|Win32 {22847D76-B1CF-4921-8B7A-61E248412C4A}.Release|Win32.Build.0 = Release|Win32 {22847D76-B1CF-4921-8B7A-61E248412C4A}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 {22847D76-B1CF-4921-8B7A-61E248412C4A}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Debug|Win32.ActiveCfg = Debug|Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Debug|Win32.Build.0 = Debug|Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Release|Win32.ActiveCfg = Release|Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Release|Win32.Build.0 = Release|Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal openzwave-1.6.1914/cpp/examples/windows/MinOZW/vs2010/MinOZW.vcxproj0000644000175200017520000002546614032142455021645 00000000000000 DebugDLL Win32 Debug Win32 ReleaseDLL Win32 Release Win32 {22847D76-B1CF-4921-8B7A-61E248412C4A} MinOZW Win32Proj Application MultiByte true Application MultiByte Application MultiByte Application MultiByte <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)$(Configuration)\ $(SolutionDir)$(Configuration)\ $(Configuration)\ $(Configuration)\ true true $(SolutionDir)$(Configuration)\ $(SolutionDir)$(Configuration)\ $(Configuration)\ $(Configuration)\ false false AllRules.ruleset AllRules.ruleset AllRules.ruleset AllRules.ruleset Disabled ..\..\..\..\src;..\..\..\..\src\platform;..\..\..\..\src\value_classes;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue $(OutDir)\OpenZWave.lib;Ws2_32.lib;dnsapi.lib;%(AdditionalDependencies) true Console MachineX86 Disabled ..\..\..\..\src;..\..\..\..\src\platform;..\..\..\..\src\value_classes;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;OPENZWAVE_USEDLL;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue 4251 $(OutDir)\OpenZWaved.lib;%(AdditionalDependencies) true Console MachineX86 MaxSpeed true ..\..\..\..\src;..\..\..\..\src\platform;..\..\..\..\src\value_classes;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase $(OutDir)\OpenZWave.lib;Ws2_32.lib;dnsapi.lib;%(AdditionalDependencies) true Console true true MachineX86 MaxSpeed true ..\..\..\..\src;..\..\..\..\src\platform;..\..\..\..\src\value_classes;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;OPENZWAVE_USEDLL;%(PreprocessorDefinitions) MultiThreadedDLL true Level3 ProgramDatabase 4251 $(OutDir)\OpenZWave.lib;%(AdditionalDependencies) true Console true true MachineX86 openzwave-1.6.1914/cpp/test/0000777000175200017520000000000014032143201012533 500000000000000openzwave-1.6.1914/cpp/test/include/0000777000175200017520000000000014032143201014156 500000000000000openzwave-1.6.1914/cpp/test/include/gtest/0000777000175200017520000000000014032143201015304 500000000000000openzwave-1.6.1914/cpp/test/include/gtest/gtest_prod.h0000644000175200017520000000472714032142455017567 00000000000000// Copyright 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Google C++ Testing and Mocking Framework definitions useful in production code. // GOOGLETEST_CM0003 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ #define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ // When you need to test the private or protected members of a class, // use the FRIEND_TEST macro to declare your tests as friends of the // class. For example: // // class MyClass { // private: // void PrivateMethod(); // FRIEND_TEST(MyClassTest, PrivateMethodWorks); // }; // // class MyClassTest : public testing::Test { // // ... // }; // // TEST_F(MyClassTest, PrivateMethodWorks) { // // Can call MyClass::PrivateMethod() here. // } // // Note: The test class must be in the same namespace as the class being tested. // For example, putting MyClassTest in an anonymous namespace will not work. #define FRIEND_TEST(test_case_name, test_name)\ friend class test_case_name##_##test_name##_Test #endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ openzwave-1.6.1914/cpp/test/include/gtest/gtest-param-test.h0000644000175200017520000005504014032142455020610 00000000000000// Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Macros and functions for implementing parameterized tests // in Google C++ Testing and Mocking Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ // Value-parameterized tests allow you to test your code with different // parameters without writing multiple copies of the same test. // // Here is how you use value-parameterized tests: #if 0 // To write value-parameterized tests, first you should define a fixture // class. It is usually derived from testing::TestWithParam (see below for // another inheritance scheme that's sometimes useful in more complicated // class hierarchies), where the type of your parameter values. // TestWithParam is itself derived from testing::Test. T can be any // copyable type. If it's a raw pointer, you are responsible for managing the // lifespan of the pointed values. class FooTest : public ::testing::TestWithParam { // You can implement all the usual class fixture members here. }; // Then, use the TEST_P macro to define as many parameterized tests // for this fixture as you want. The _P suffix is for "parameterized" // or "pattern", whichever you prefer to think. The arguments to the // TEST_P macro are the test_suite_name and test_case (both which must be // non-empty) that will form the test name. TEST_P(FooTest, DoesBlah) { // Inside a test, access the test parameter with the GetParam() method // of the TestWithParam class: EXPECT_TRUE(foo.Blah(GetParam())); ... } TEST_P(FooTest, HasBlahBlah) { ... } // Finally, you can use INSTANTIATE_TEST_SUITE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call // (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // // Range(begin, end [, step]) - Yields values {begin, begin+step, // begin+step+step, ...}. The values do not // include end. step defaults to 1. // Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. // ValuesIn(container) - Yields values from a C-style array, an STL // ValuesIn(begin,end) container, or an iterator range [begin, end). // Bool() - Yields sequence {false, true}. // Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product // for the math savvy) of the values generated // by the N generators. // // For more details, see comments at the definitions of these functions below // in this file. // // The following statement will instantiate tests from the FooTest test suite // each with parameter values "meeny", "miny", and "moe". INSTANTIATE_TEST_SUITE_P(InstantiationName, FooTest, Values("meeny", "miny", "moe")); // To distinguish different instances of the pattern, (yes, you // can instantiate it more than once) the first argument to the // INSTANTIATE_TEST_SUITE_P macro is a prefix (which must be non-empty) that // will be added to the actual test suite name. Remember to pick unique prefixes // for different instantiations. The tests from the instantiation above will // have these names: // // * InstantiationName/FooTest.DoesBlah/0 for "meeny" // * InstantiationName/FooTest.DoesBlah/1 for "miny" // * InstantiationName/FooTest.DoesBlah/2 for "moe" // * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" // * InstantiationName/FooTest.HasBlahBlah/1 for "miny" // * InstantiationName/FooTest.HasBlahBlah/2 for "moe" // // You can use these names in --gtest_filter. // // This statement will instantiate all tests from FooTest again, each // with parameter values "cat" and "dog": const char* pets[] = {"cat", "dog"}; INSTANTIATE_TEST_SUITE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // The tests from the instantiation above will have these names: // // * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" // * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" // * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" // * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" // // Please note that INSTANTIATE_TEST_SUITE_P will instantiate all tests // in the given test suite, whether their definitions come before or // AFTER the INSTANTIATE_TEST_SUITE_P statement. // // Please also note that generator expressions (including parameters to the // generators) are evaluated in InitGoogleTest(), after main() has started. // This allows the user on one hand, to adjust generator parameters in order // to dynamically determine a set of tests to run and on the other hand, // give the user a chance to inspect the generated tests with Google Test // reflection API before RUN_ALL_TESTS() is executed. // // You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc // for more examples. // // In the future, we plan to publish the API for defining new parameter // generators. But for now this interface remains part of the internal // implementation and is subject to change. // // // A parameterized test fixture must be derived from testing::Test and from // testing::WithParamInterface, where T is the type of the parameter // values. Inheriting from TestWithParam satisfies that requirement because // TestWithParam inherits from both Test and WithParamInterface. In more // complicated hierarchies, however, it is occasionally useful to inherit // separately from Test and WithParamInterface. For example: class BaseTest : public ::testing::Test { // You can inherit all the usual members for a non-parameterized test // fixture here. }; class DerivedTest : public BaseTest, public ::testing::WithParamInterface { // The usual test fixture members go here too. }; TEST_F(BaseTest, HasFoo) { // This is an ordinary non-parameterized test. } TEST_P(DerivedTest, DoesBlah) { // GetParam works just the same here as if you inherit from TestWithParam. EXPECT_TRUE(foo.Blah(GetParam())); } #endif // 0 #include #include #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-port.h" namespace testing { // Functions producing parameter generators. // // Google Test uses these generators to produce parameters for value- // parameterized tests. When a parameterized test suite is instantiated // with a particular generator, Google Test creates and runs tests // for each element in the sequence produced by the generator. // // In the following sample, tests from test suite FooTest are instantiated // each three times with parameter values 3, 5, and 8: // // class FooTest : public TestWithParam { ... }; // // TEST_P(FooTest, TestThis) { // } // TEST_P(FooTest, TestThat) { // } // INSTANTIATE_TEST_SUITE_P(TestSequence, FooTest, Values(3, 5, 8)); // // Range() returns generators providing sequences of values in a range. // // Synopsis: // Range(start, end) // - returns a generator producing a sequence of values {start, start+1, // start+2, ..., }. // Range(start, end, step) // - returns a generator producing a sequence of values {start, start+step, // start+step+step, ..., }. // Notes: // * The generated sequences never include end. For example, Range(1, 5) // returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) // returns a generator producing {1, 3, 5, 7}. // * start and end must have the same type. That type may be any integral or // floating-point type or a user defined type satisfying these conditions: // * It must be assignable (have operator=() defined). // * It must have operator+() (operator+(int-compatible type) for // two-operand version). // * It must have operator<() defined. // Elements in the resulting sequences will also have that type. // * Condition start < end must be satisfied in order for resulting sequences // to contain any elements. // template internal::ParamGenerator Range(T start, T end, IncrementT step) { return internal::ParamGenerator( new internal::RangeGenerator(start, end, step)); } template internal::ParamGenerator Range(T start, T end) { return Range(start, end, 1); } // ValuesIn() function allows generation of tests with parameters coming from // a container. // // Synopsis: // ValuesIn(const T (&array)[N]) // - returns a generator producing sequences with elements from // a C-style array. // ValuesIn(const Container& container) // - returns a generator producing sequences with elements from // an STL-style container. // ValuesIn(Iterator begin, Iterator end) // - returns a generator producing sequences with elements from // a range [begin, end) defined by a pair of STL-style iterators. These // iterators can also be plain C pointers. // // Please note that ValuesIn copies the values from the containers // passed in and keeps them to generate tests in RUN_ALL_TESTS(). // // Examples: // // This instantiates tests from test suite StringTest // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; // INSTANTIATE_TEST_SUITE_P(StringSequence, StringTest, ValuesIn(strings)); // // This instantiates tests from test suite StlStringTest // each with STL strings with values "a" and "b": // // ::std::vector< ::std::string> GetParameterStrings() { // ::std::vector< ::std::string> v; // v.push_back("a"); // v.push_back("b"); // return v; // } // // INSTANTIATE_TEST_SUITE_P(CharSequence, // StlStringTest, // ValuesIn(GetParameterStrings())); // // // This will also instantiate tests from CharTest // each with parameter values 'a' and 'b': // // ::std::list GetParameterChars() { // ::std::list list; // list.push_back('a'); // list.push_back('b'); // return list; // } // ::std::list l = GetParameterChars(); // INSTANTIATE_TEST_SUITE_P(CharSequence2, // CharTest, // ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< typename std::iterator_traits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end) { typedef typename std::iterator_traits::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } template internal::ParamGenerator ValuesIn(const T (&array)[N]) { return ValuesIn(array, array + N); } template internal::ParamGenerator ValuesIn( const Container& container) { return ValuesIn(container.begin(), container.end()); } // Values() allows generating tests from explicitly specified list of // parameters. // // Synopsis: // Values(T v1, T v2, ..., T vN) // - returns a generator producing sequences with elements v1, v2, ..., vN. // // For example, this instantiates tests from test suite BarTest each // with values "one", "two", and "three": // // INSTANTIATE_TEST_SUITE_P(NumSequence, // BarTest, // Values("one", "two", "three")); // // This instantiates tests from test suite BazTest each with values 1, 2, 3.5. // The exact type of values will depend on the type of parameter in BazTest. // // INSTANTIATE_TEST_SUITE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); // // template internal::ValueArray Values(T... v) { return internal::ValueArray(std::move(v)...); } // Bool() allows generating tests with parameters in a set of (false, true). // // Synopsis: // Bool() // - returns a generator producing sequences with elements {false, true}. // // It is useful when testing code that depends on Boolean flags. Combinations // of multiple flags can be tested when several Bool()'s are combined using // Combine() function. // // In the following example all tests in the test suite FlagDependentTest // will be instantiated twice with parameters false and true. // // class FlagDependentTest : public testing::TestWithParam { // virtual void SetUp() { // external_flag = GetParam(); // } // } // INSTANTIATE_TEST_SUITE_P(BoolSequence, FlagDependentTest, Bool()); // inline internal::ParamGenerator Bool() { return Values(false, true); } // Combine() allows the user to combine two or more sequences to produce // values of a Cartesian product of those sequences' elements. // // Synopsis: // Combine(gen1, gen2, ..., genN) // - returns a generator producing sequences with elements coming from // the Cartesian product of elements from the sequences generated by // gen1, gen2, ..., genN. The sequence elements will have a type of // std::tuple where T1, T2, ..., TN are the types // of elements from sequences produces by gen1, gen2, ..., genN. // // Combine can have up to 10 arguments. // // Example: // // This will instantiate tests in test suite AnimalTest each one with // the parameter values tuple("cat", BLACK), tuple("cat", WHITE), // tuple("dog", BLACK), and tuple("dog", WHITE): // // enum Color { BLACK, GRAY, WHITE }; // class AnimalTest // : public testing::TestWithParam > {...}; // // TEST_P(AnimalTest, AnimalLooksNice) {...} // // INSTANTIATE_TEST_SUITE_P(AnimalVariations, AnimalTest, // Combine(Values("cat", "dog"), // Values(BLACK, WHITE))); // // This will instantiate tests in FlagDependentTest with all variations of two // Boolean flags: // // class FlagDependentTest // : public testing::TestWithParam > { // virtual void SetUp() { // // Assigns external_flag_1 and external_flag_2 values from the tuple. // std::tie(external_flag_1, external_flag_2) = GetParam(); // } // }; // // TEST_P(FlagDependentTest, TestFeature1) { // // Test your code using external_flag_1 and external_flag_2 here. // } // INSTANTIATE_TEST_SUITE_P(TwoBoolSequence, FlagDependentTest, // Combine(Bool(), Bool())); // template internal::CartesianProductHolder Combine(const Generator&... g) { return internal::CartesianProductHolder(g...); } #define TEST_P(test_suite_name, test_name) \ static_assert(sizeof(GTEST_STRINGIFY_(test_suite_name)) > 1, \ "test_suite_name must not be empty"); \ static_assert(sizeof(GTEST_STRINGIFY_(test_name)) > 1, \ "test_name must not be empty"); \ class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ : public test_suite_name { \ public: \ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ void TestBody() override; \ \ private: \ static int AddToRegistry() { \ ::testing::UnitTest::GetInstance() \ ->parameterized_test_registry() \ .GetTestSuitePatternHolder( \ GTEST_STRINGIFY_(test_suite_name), \ ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ ->AddTestPattern( \ GTEST_STRINGIFY_(test_suite_name), GTEST_STRINGIFY_(test_name), \ new ::testing::internal::TestMetaFactory()); \ return 0; \ } \ static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ test_name)); \ }; \ int GTEST_TEST_CLASS_NAME_(test_suite_name, \ test_name)::gtest_registering_dummy_ = \ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::AddToRegistry(); \ void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() // The last argument to INSTANTIATE_TEST_SUITE_P allows the user to specify // generator and an optional function or functor that generates custom test name // suffixes based on the test parameters. Such a function or functor should // accept one argument of type testing::TestParamInfo, and // return std::string. // // testing::PrintToStringParamName is a builtin test suffix generator that // returns the value of testing::PrintToString(GetParam()). // // Note: test names must be non-empty, unique, and may only contain ASCII // alphanumeric characters or underscore. Because PrintToString adds quotes // to std::string and C strings, it won't work for these types. #define GTEST_EXPAND_(arg) arg #define GTEST_GET_FIRST_(first, ...) first #define GTEST_GET_SECOND_(first, second, ...) second #define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name, ...) \ static_assert(sizeof(GTEST_STRINGIFY_(test_suite_name)) > 1, \ "test_suite_name must not be empty"); \ static_assert(sizeof(GTEST_STRINGIFY_(prefix)) > 1, \ "prefix must not be empty"); \ static ::testing::internal::ParamGenerator \ gtest_##prefix##test_suite_name##_EvalGenerator_() { \ return GTEST_EXPAND_(GTEST_GET_FIRST_(__VA_ARGS__, DUMMY_PARAM_)); \ } \ static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \ const ::testing::TestParamInfo& info) { \ if (::testing::internal::AlwaysFalse()) { \ ::testing::internal::TestNotEmpty(GTEST_EXPAND_(GTEST_GET_SECOND_( \ __VA_ARGS__, \ ::testing::internal::DefaultParamName, \ DUMMY_PARAM_))); \ auto t = std::make_tuple(__VA_ARGS__); \ static_assert(std::tuple_size::value <= 2, \ "Too Many Args!"); \ } \ return ((GTEST_EXPAND_(GTEST_GET_SECOND_( \ __VA_ARGS__, \ ::testing::internal::DefaultParamName, \ DUMMY_PARAM_))))(info); \ } \ static int gtest_##prefix##test_suite_name##_dummy_ \ GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::UnitTest::GetInstance() \ ->parameterized_test_registry() \ .GetTestSuitePatternHolder( \ GTEST_STRINGIFY_(test_suite_name), \ ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ ->AddTestSuiteInstantiation( \ GTEST_STRINGIFY_(prefix), \ >est_##prefix##test_suite_name##_EvalGenerator_, \ >est_##prefix##test_suite_name##_EvalGenerateName_, \ __FILE__, __LINE__) // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #define INSTANTIATE_TEST_CASE_P \ static_assert(::testing::internal::InstantiateTestCase_P_IsDeprecated(), \ ""); \ INSTANTIATE_TEST_SUITE_P #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ openzwave-1.6.1914/cpp/test/include/gtest/gtest_pred_impl.h0000644000175200017520000003500214032142455020564 00000000000000// Copyright 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // This file is AUTOMATICALLY GENERATED on 01/02/2019 by command // 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! // // Implements a family of generic predicate assertion macros. // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ #include "gtest/gtest.h" namespace testing { // This header implements a family of generic predicate assertion // macros: // // ASSERT_PRED_FORMAT1(pred_format, v1) // ASSERT_PRED_FORMAT2(pred_format, v1, v2) // ... // // where pred_format is a function or functor that takes n (in the // case of ASSERT_PRED_FORMATn) values and their source expression // text, and returns a testing::AssertionResult. See the definition // of ASSERT_EQ in gtest.h for an example. // // If you don't care about formatting, you can use the more // restrictive version: // // ASSERT_PRED1(pred, v1) // ASSERT_PRED2(pred, v1, v2) // ... // // where pred is an n-ary function or functor that returns bool, // and the values v1, v2, ..., must support the << operator for // streaming to std::ostream. // // We also define the EXPECT_* variations. // // For now we only support predicates whose arity is at most 5. // Please email googletestframework@googlegroups.com if you need // support for higher arities. // GTEST_ASSERT_ is the basic statement to which all of the assertions // in this file reduce. Don't use this in your code. #define GTEST_ASSERT_(expression, on_failure) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const ::testing::AssertionResult gtest_ar = (expression)) \ ; \ else \ on_failure(gtest_ar.failure_message()) // Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use // this in your code. template AssertionResult AssertPred1Helper(const char* pred_text, const char* e1, Pred pred, const T1& v1) { if (pred(v1)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << ::testing::PrintToString(v1); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. // Don't use this in your code. #define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ GTEST_ASSERT_(pred_format(#v1, v1), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use // this in your code. #define GTEST_PRED1_(pred, v1, on_failure)\ GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ #v1, \ pred, \ v1), on_failure) // Unary predicate assertion macros. #define EXPECT_PRED_FORMAT1(pred_format, v1) \ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED1(pred, v1) \ GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT1(pred_format, v1) \ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) #define ASSERT_PRED1(pred, v1) \ GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use // this in your code. template AssertionResult AssertPred2Helper(const char* pred_text, const char* e1, const char* e2, Pred pred, const T1& v1, const T2& v2) { if (pred(v1, v2)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ", " << e2 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" << e2 << " evaluates to " << ::testing::PrintToString(v2); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. // Don't use this in your code. #define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use // this in your code. #define GTEST_PRED2_(pred, v1, v2, on_failure)\ GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ #v1, \ #v2, \ pred, \ v1, \ v2), on_failure) // Binary predicate assertion macros. #define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED2(pred, v1, v2) \ GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) #define ASSERT_PRED2(pred, v1, v2) \ GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use // this in your code. template AssertionResult AssertPred3Helper(const char* pred_text, const char* e1, const char* e2, const char* e3, Pred pred, const T1& v1, const T2& v2, const T3& v3) { if (pred(v1, v2, v3)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" << e3 << " evaluates to " << ::testing::PrintToString(v3); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. // Don't use this in your code. #define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use // this in your code. #define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ #v1, \ #v2, \ #v3, \ pred, \ v1, \ v2, \ v3), on_failure) // Ternary predicate assertion macros. #define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED3(pred, v1, v2, v3) \ GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) #define ASSERT_PRED3(pred, v1, v2, v3) \ GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use // this in your code. template AssertionResult AssertPred4Helper(const char* pred_text, const char* e1, const char* e2, const char* e3, const char* e4, Pred pred, const T1& v1, const T2& v2, const T3& v3, const T4& v4) { if (pred(v1, v2, v3, v4)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" << e4 << " evaluates to " << ::testing::PrintToString(v4); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. // Don't use this in your code. #define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use // this in your code. #define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ #v1, \ #v2, \ #v3, \ #v4, \ pred, \ v1, \ v2, \ v3, \ v4), on_failure) // 4-ary predicate assertion macros. #define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED4(pred, v1, v2, v3, v4) \ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) #define ASSERT_PRED4(pred, v1, v2, v3, v4) \ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use // this in your code. template AssertionResult AssertPred5Helper(const char* pred_text, const char* e1, const char* e2, const char* e3, const char* e4, const char* e5, Pred pred, const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5) { if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 << ", " << e5 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" << e4 << " evaluates to " << ::testing::PrintToString(v4) << "\n" << e5 << " evaluates to " << ::testing::PrintToString(v5); } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. // Don't use this in your code. #define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use // this in your code. #define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ #v1, \ #v2, \ #v3, \ #v4, \ #v5, \ pred, \ v1, \ v2, \ v3, \ v4, \ v5), on_failure) // 5-ary predicate assertion macros. #define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) #define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ openzwave-1.6.1914/cpp/test/include/gtest/gtest-matchers.h0000644000175200017520000006464214032142455020351 00000000000000// Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // The Google C++ Testing and Mocking Framework (Google Test) // // This file implements just enough of the matcher interface to allow // EXPECT_DEATH and friends to accept a matcher argument. // IWYU pragma: private, include "testing/base/public/gunit.h" // IWYU pragma: friend third_party/googletest/googlemock/.* // IWYU pragma: friend third_party/googletest/googletest/.* #ifndef GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ #define GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ #include #include #include #include #include "gtest/gtest-printers.h" #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-port.h" // MSVC warning C5046 is new as of VS2017 version 15.8. #if defined(_MSC_VER) && _MSC_VER >= 1915 #define GTEST_MAYBE_5046_ 5046 #else #define GTEST_MAYBE_5046_ #endif GTEST_DISABLE_MSC_WARNINGS_PUSH_( 4251 GTEST_MAYBE_5046_ /* class A needs to have dll-interface to be used by clients of class B */ /* Symbol involving type with internal linkage not defined */) namespace testing { // To implement a matcher Foo for type T, define: // 1. a class FooMatcherImpl that implements the // MatcherInterface interface, and // 2. a factory function that creates a Matcher object from a // FooMatcherImpl*. // // The two-level delegation design makes it possible to allow a user // to write "v" instead of "Eq(v)" where a Matcher is expected, which // is impossible if we pass matchers by pointers. It also eases // ownership management as Matcher objects can now be copied like // plain values. // MatchResultListener is an abstract class. Its << operator can be // used by a matcher to explain why a value matches or doesn't match. // class MatchResultListener { public: // Creates a listener object with the given underlying ostream. The // listener does not own the ostream, and does not dereference it // in the constructor or destructor. explicit MatchResultListener(::std::ostream* os) : stream_(os) {} virtual ~MatchResultListener() = 0; // Makes this class abstract. // Streams x to the underlying ostream; does nothing if the ostream // is NULL. template MatchResultListener& operator<<(const T& x) { if (stream_ != nullptr) *stream_ << x; return *this; } // Returns the underlying ostream. ::std::ostream* stream() { return stream_; } // Returns true if and only if the listener is interested in an explanation // of the match result. A matcher's MatchAndExplain() method can use // this information to avoid generating the explanation when no one // intends to hear it. bool IsInterested() const { return stream_ != nullptr; } private: ::std::ostream* const stream_; GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener); }; inline MatchResultListener::~MatchResultListener() { } // An instance of a subclass of this knows how to describe itself as a // matcher. class MatcherDescriberInterface { public: virtual ~MatcherDescriberInterface() {} // Describes this matcher to an ostream. The function should print // a verb phrase that describes the property a value matching this // matcher should have. The subject of the verb phrase is the value // being matched. For example, the DescribeTo() method of the Gt(7) // matcher prints "is greater than 7". virtual void DescribeTo(::std::ostream* os) const = 0; // Describes the negation of this matcher to an ostream. For // example, if the description of this matcher is "is greater than // 7", the negated description could be "is not greater than 7". // You are not required to override this when implementing // MatcherInterface, but it is highly advised so that your matcher // can produce good error messages. virtual void DescribeNegationTo(::std::ostream* os) const { *os << "not ("; DescribeTo(os); *os << ")"; } }; // The implementation of a matcher. template class MatcherInterface : public MatcherDescriberInterface { public: // Returns true if and only if the matcher matches x; also explains the // match result to 'listener' if necessary (see the next paragraph), in // the form of a non-restrictive relative clause ("which ...", // "whose ...", etc) that describes x. For example, the // MatchAndExplain() method of the Pointee(...) matcher should // generate an explanation like "which points to ...". // // Implementations of MatchAndExplain() should add an explanation of // the match result *if and only if* they can provide additional // information that's not already present (or not obvious) in the // print-out of x and the matcher's description. Whether the match // succeeds is not a factor in deciding whether an explanation is // needed, as sometimes the caller needs to print a failure message // when the match succeeds (e.g. when the matcher is used inside // Not()). // // For example, a "has at least 10 elements" matcher should explain // what the actual element count is, regardless of the match result, // as it is useful information to the reader; on the other hand, an // "is empty" matcher probably only needs to explain what the actual // size is when the match fails, as it's redundant to say that the // size is 0 when the value is already known to be empty. // // You should override this method when defining a new matcher. // // It's the responsibility of the caller (Google Test) to guarantee // that 'listener' is not NULL. This helps to simplify a matcher's // implementation when it doesn't care about the performance, as it // can talk to 'listener' without checking its validity first. // However, in order to implement dummy listeners efficiently, // listener->stream() may be NULL. virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; // Inherits these methods from MatcherDescriberInterface: // virtual void DescribeTo(::std::ostream* os) const = 0; // virtual void DescribeNegationTo(::std::ostream* os) const; }; namespace internal { // Converts a MatcherInterface to a MatcherInterface. template class MatcherInterfaceAdapter : public MatcherInterface { public: explicit MatcherInterfaceAdapter(const MatcherInterface* impl) : impl_(impl) {} ~MatcherInterfaceAdapter() override { delete impl_; } void DescribeTo(::std::ostream* os) const override { impl_->DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { impl_->DescribeNegationTo(os); } bool MatchAndExplain(const T& x, MatchResultListener* listener) const override { return impl_->MatchAndExplain(x, listener); } private: const MatcherInterface* const impl_; GTEST_DISALLOW_COPY_AND_ASSIGN_(MatcherInterfaceAdapter); }; struct AnyEq { template bool operator()(const A& a, const B& b) const { return a == b; } }; struct AnyNe { template bool operator()(const A& a, const B& b) const { return a != b; } }; struct AnyLt { template bool operator()(const A& a, const B& b) const { return a < b; } }; struct AnyGt { template bool operator()(const A& a, const B& b) const { return a > b; } }; struct AnyLe { template bool operator()(const A& a, const B& b) const { return a <= b; } }; struct AnyGe { template bool operator()(const A& a, const B& b) const { return a >= b; } }; // A match result listener that ignores the explanation. class DummyMatchResultListener : public MatchResultListener { public: DummyMatchResultListener() : MatchResultListener(nullptr) {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener); }; // A match result listener that forwards the explanation to a given // ostream. The difference between this and MatchResultListener is // that the former is concrete. class StreamMatchResultListener : public MatchResultListener { public: explicit StreamMatchResultListener(::std::ostream* os) : MatchResultListener(os) {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); }; // An internal class for implementing Matcher, which will derive // from it. We put functionalities common to all Matcher // specializations here to avoid code duplication. template class MatcherBase { public: // Returns true if and only if the matcher matches x; also explains the // match result to 'listener'. bool MatchAndExplain(const T& x, MatchResultListener* listener) const { return impl_->MatchAndExplain(x, listener); } // Returns true if and only if this matcher matches x. bool Matches(const T& x) const { DummyMatchResultListener dummy; return MatchAndExplain(x, &dummy); } // Describes this matcher to an ostream. void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } // Describes the negation of this matcher to an ostream. void DescribeNegationTo(::std::ostream* os) const { impl_->DescribeNegationTo(os); } // Explains why x matches, or doesn't match, the matcher. void ExplainMatchResultTo(const T& x, ::std::ostream* os) const { StreamMatchResultListener listener(os); MatchAndExplain(x, &listener); } // Returns the describer for this matcher object; retains ownership // of the describer, which is only guaranteed to be alive when // this matcher object is alive. const MatcherDescriberInterface* GetDescriber() const { return impl_.get(); } protected: MatcherBase() {} // Constructs a matcher from its implementation. explicit MatcherBase(const MatcherInterface* impl) : impl_(impl) {} template explicit MatcherBase( const MatcherInterface* impl, typename std::enable_if::value>::type* = nullptr) : impl_(new internal::MatcherInterfaceAdapter(impl)) {} MatcherBase(const MatcherBase&) = default; MatcherBase& operator=(const MatcherBase&) = default; MatcherBase(MatcherBase&&) = default; MatcherBase& operator=(MatcherBase&&) = default; virtual ~MatcherBase() {} private: std::shared_ptr> impl_; }; } // namespace internal // A Matcher is a copyable and IMMUTABLE (except by assignment) // object that can check whether a value of type T matches. The // implementation of Matcher is just a std::shared_ptr to const // MatcherInterface. Don't inherit from Matcher! template class Matcher : public internal::MatcherBase { public: // Constructs a null matcher. Needed for storing Matcher objects in STL // containers. A default-constructed matcher is not yet initialized. You // cannot use it until a valid value has been assigned to it. explicit Matcher() {} // NOLINT // Constructs a matcher from its implementation. explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} template explicit Matcher( const MatcherInterface* impl, typename std::enable_if::value>::type* = nullptr) : internal::MatcherBase(impl) {} // Implicit constructor here allows people to write // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes Matcher(T value); // NOLINT }; // The following two specializations allow the user to write str // instead of Eq(str) and "foo" instead of Eq("foo") when a std::string // matcher is expected. template <> class GTEST_API_ Matcher : public internal::MatcherBase { public: Matcher() {} explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} // Allows the user to write str instead of Eq(str) sometimes, where // str is a std::string object. Matcher(const std::string& s); // NOLINT // Allows the user to write "foo" instead of Eq("foo") sometimes. Matcher(const char* s); // NOLINT }; template <> class GTEST_API_ Matcher : public internal::MatcherBase { public: Matcher() {} explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} // Allows the user to write str instead of Eq(str) sometimes, where // str is a string object. Matcher(const std::string& s); // NOLINT // Allows the user to write "foo" instead of Eq("foo") sometimes. Matcher(const char* s); // NOLINT }; #if GTEST_HAS_ABSL // The following two specializations allow the user to write str // instead of Eq(str) and "foo" instead of Eq("foo") when a absl::string_view // matcher is expected. template <> class GTEST_API_ Matcher : public internal::MatcherBase { public: Matcher() {} explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} // Allows the user to write str instead of Eq(str) sometimes, where // str is a std::string object. Matcher(const std::string& s); // NOLINT // Allows the user to write "foo" instead of Eq("foo") sometimes. Matcher(const char* s); // NOLINT // Allows the user to pass absl::string_views directly. Matcher(absl::string_view s); // NOLINT }; template <> class GTEST_API_ Matcher : public internal::MatcherBase { public: Matcher() {} explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} // Allows the user to write str instead of Eq(str) sometimes, where // str is a std::string object. Matcher(const std::string& s); // NOLINT // Allows the user to write "foo" instead of Eq("foo") sometimes. Matcher(const char* s); // NOLINT // Allows the user to pass absl::string_views directly. Matcher(absl::string_view s); // NOLINT }; #endif // GTEST_HAS_ABSL // Prints a matcher in a human-readable format. template std::ostream& operator<<(std::ostream& os, const Matcher& matcher) { matcher.DescribeTo(&os); return os; } // The PolymorphicMatcher class template makes it easy to implement a // polymorphic matcher (i.e. a matcher that can match values of more // than one type, e.g. Eq(n) and NotNull()). // // To define a polymorphic matcher, a user should provide an Impl // class that has a DescribeTo() method and a DescribeNegationTo() // method, and define a member function (or member function template) // // bool MatchAndExplain(const Value& value, // MatchResultListener* listener) const; // // See the definition of NotNull() for a complete example. template class PolymorphicMatcher { public: explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {} // Returns a mutable reference to the underlying matcher // implementation object. Impl& mutable_impl() { return impl_; } // Returns an immutable reference to the underlying matcher // implementation object. const Impl& impl() const { return impl_; } template operator Matcher() const { return Matcher(new MonomorphicImpl(impl_)); } private: template class MonomorphicImpl : public MatcherInterface { public: explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} void DescribeTo(::std::ostream* os) const override { impl_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { impl_.DescribeNegationTo(os); } bool MatchAndExplain(T x, MatchResultListener* listener) const override { return impl_.MatchAndExplain(x, listener); } private: const Impl impl_; }; Impl impl_; }; // Creates a matcher from its implementation. // DEPRECATED: Especially in the generic code, prefer: // Matcher(new MyMatcherImpl(...)); // // MakeMatcher may create a Matcher that accepts its argument by value, which // leads to unnecessary copies & lack of support for non-copyable types. template inline Matcher MakeMatcher(const MatcherInterface* impl) { return Matcher(impl); } // Creates a polymorphic matcher from its implementation. This is // easier to use than the PolymorphicMatcher constructor as it // doesn't require you to explicitly write the template argument, e.g. // // MakePolymorphicMatcher(foo); // vs // PolymorphicMatcher(foo); template inline PolymorphicMatcher MakePolymorphicMatcher(const Impl& impl) { return PolymorphicMatcher(impl); } namespace internal { // Implements a matcher that compares a given value with a // pre-supplied value using one of the ==, <=, <, etc, operators. The // two values being compared don't have to have the same type. // // The matcher defined here is polymorphic (for example, Eq(5) can be // used to match an int, a short, a double, etc). Therefore we use // a template type conversion operator in the implementation. // // The following template definition assumes that the Rhs parameter is // a "bare" type (i.e. neither 'const T' nor 'T&'). template class ComparisonBase { public: explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {} template operator Matcher() const { return Matcher(new Impl(rhs_)); } private: template static const T& Unwrap(const T& v) { return v; } template static const T& Unwrap(std::reference_wrapper v) { return v; } template class Impl : public MatcherInterface { public: explicit Impl(const Rhs& rhs) : rhs_(rhs) {} bool MatchAndExplain(Lhs lhs, MatchResultListener* /* listener */) const override { return Op()(lhs, Unwrap(rhs_)); } void DescribeTo(::std::ostream* os) const override { *os << D::Desc() << " "; UniversalPrint(Unwrap(rhs_), os); } void DescribeNegationTo(::std::ostream* os) const override { *os << D::NegatedDesc() << " "; UniversalPrint(Unwrap(rhs_), os); } private: Rhs rhs_; }; Rhs rhs_; }; template class EqMatcher : public ComparisonBase, Rhs, AnyEq> { public: explicit EqMatcher(const Rhs& rhs) : ComparisonBase, Rhs, AnyEq>(rhs) { } static const char* Desc() { return "is equal to"; } static const char* NegatedDesc() { return "isn't equal to"; } }; template class NeMatcher : public ComparisonBase, Rhs, AnyNe> { public: explicit NeMatcher(const Rhs& rhs) : ComparisonBase, Rhs, AnyNe>(rhs) { } static const char* Desc() { return "isn't equal to"; } static const char* NegatedDesc() { return "is equal to"; } }; template class LtMatcher : public ComparisonBase, Rhs, AnyLt> { public: explicit LtMatcher(const Rhs& rhs) : ComparisonBase, Rhs, AnyLt>(rhs) { } static const char* Desc() { return "is <"; } static const char* NegatedDesc() { return "isn't <"; } }; template class GtMatcher : public ComparisonBase, Rhs, AnyGt> { public: explicit GtMatcher(const Rhs& rhs) : ComparisonBase, Rhs, AnyGt>(rhs) { } static const char* Desc() { return "is >"; } static const char* NegatedDesc() { return "isn't >"; } }; template class LeMatcher : public ComparisonBase, Rhs, AnyLe> { public: explicit LeMatcher(const Rhs& rhs) : ComparisonBase, Rhs, AnyLe>(rhs) { } static const char* Desc() { return "is <="; } static const char* NegatedDesc() { return "isn't <="; } }; template class GeMatcher : public ComparisonBase, Rhs, AnyGe> { public: explicit GeMatcher(const Rhs& rhs) : ComparisonBase, Rhs, AnyGe>(rhs) { } static const char* Desc() { return "is >="; } static const char* NegatedDesc() { return "isn't >="; } }; // Implements polymorphic matchers MatchesRegex(regex) and // ContainsRegex(regex), which can be used as a Matcher as long as // T can be converted to a string. class MatchesRegexMatcher { public: MatchesRegexMatcher(const RE* regex, bool full_match) : regex_(regex), full_match_(full_match) {} #if GTEST_HAS_ABSL bool MatchAndExplain(const absl::string_view& s, MatchResultListener* listener) const { return MatchAndExplain(std::string(s), listener); } #endif // GTEST_HAS_ABSL // Accepts pointer types, particularly: // const char* // char* // const wchar_t* // wchar_t* template bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { return s != nullptr && MatchAndExplain(std::string(s), listener); } // Matches anything that can convert to std::string. // // This is a template, not just a plain function with const std::string&, // because absl::string_view has some interfering non-explicit constructors. template bool MatchAndExplain(const MatcheeStringType& s, MatchResultListener* /* listener */) const { const std::string& s2(s); return full_match_ ? RE::FullMatch(s2, *regex_) : RE::PartialMatch(s2, *regex_); } void DescribeTo(::std::ostream* os) const { *os << (full_match_ ? "matches" : "contains") << " regular expression "; UniversalPrinter::Print(regex_->pattern(), os); } void DescribeNegationTo(::std::ostream* os) const { *os << "doesn't " << (full_match_ ? "match" : "contain") << " regular expression "; UniversalPrinter::Print(regex_->pattern(), os); } private: const std::shared_ptr regex_; const bool full_match_; }; } // namespace internal // Matches a string that fully matches regular expression 'regex'. // The matcher takes ownership of 'regex'. inline PolymorphicMatcher MatchesRegex( const internal::RE* regex) { return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true)); } inline PolymorphicMatcher MatchesRegex( const std::string& regex) { return MatchesRegex(new internal::RE(regex)); } // Matches a string that contains regular expression 'regex'. // The matcher takes ownership of 'regex'. inline PolymorphicMatcher ContainsRegex( const internal::RE* regex) { return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false)); } inline PolymorphicMatcher ContainsRegex( const std::string& regex) { return ContainsRegex(new internal::RE(regex)); } // Creates a polymorphic matcher that matches anything equal to x. // Note: if the parameter of Eq() were declared as const T&, Eq("foo") // wouldn't compile. template inline internal::EqMatcher Eq(T x) { return internal::EqMatcher(x); } // Constructs a Matcher from a 'value' of type T. The constructed // matcher matches any value that's equal to 'value'. template Matcher::Matcher(T value) { *this = Eq(value); } // Creates a monomorphic matcher that matches anything with type Lhs // and equal to rhs. A user may need to use this instead of Eq(...) // in order to resolve an overloading ambiguity. // // TypedEq(x) is just a convenient short-hand for Matcher(Eq(x)) // or Matcher(x), but more readable than the latter. // // We could define similar monomorphic matchers for other comparison // operations (e.g. TypedLt, TypedGe, and etc), but decided not to do // it yet as those are used much less than Eq() in practice. A user // can always write Matcher(Lt(5)) to be explicit about the type, // for example. template inline Matcher TypedEq(const Rhs& rhs) { return Eq(rhs); } // Creates a polymorphic matcher that matches anything >= x. template inline internal::GeMatcher Ge(Rhs x) { return internal::GeMatcher(x); } // Creates a polymorphic matcher that matches anything > x. template inline internal::GtMatcher Gt(Rhs x) { return internal::GtMatcher(x); } // Creates a polymorphic matcher that matches anything <= x. template inline internal::LeMatcher Le(Rhs x) { return internal::LeMatcher(x); } // Creates a polymorphic matcher that matches anything < x. template inline internal::LtMatcher Lt(Rhs x) { return internal::LtMatcher(x); } // Creates a polymorphic matcher that matches anything != x. template inline internal::NeMatcher Ne(Rhs x) { return internal::NeMatcher(x); } } // namespace testing GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046 #endif // GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ openzwave-1.6.1914/cpp/test/include/gtest/gtest-printers.h0000644000175200017520000010235514032142455020403 00000000000000// Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Google Test - The Google C++ Testing and Mocking Framework // // This file implements a universal value printer that can print a // value of any type T: // // void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); // // A user can teach this function how to print a class type T by // defining either operator<<() or PrintTo() in the namespace that // defines T. More specifically, the FIRST defined function in the // following list will be used (assuming T is defined in namespace // foo): // // 1. foo::PrintTo(const T&, ostream*) // 2. operator<<(ostream&, const T&) defined in either foo or the // global namespace. // // However if T is an STL-style container then it is printed element-wise // unless foo::PrintTo(const T&, ostream*) is defined. Note that // operator<<() is ignored for container types. // // If none of the above is defined, it will print the debug string of // the value if it is a protocol buffer, or print the raw bytes in the // value otherwise. // // To aid debugging: when T is a reference type, the address of the // value is also printed; when T is a (const) char pointer, both the // pointer value and the NUL-terminated string it points to are // printed. // // We also provide some convenient wrappers: // // // Prints a value to a string. For a (const or not) char // // pointer, the NUL-terminated string (but not the pointer) is // // printed. // std::string ::testing::PrintToString(const T& value); // // // Prints a value tersely: for a reference type, the referenced // // value (but not the address) is printed; for a (const or not) char // // pointer, the NUL-terminated string (but not the pointer) is // // printed. // void ::testing::internal::UniversalTersePrint(const T& value, ostream*); // // // Prints value using the type inferred by the compiler. The difference // // from UniversalTersePrint() is that this function prints both the // // pointer and the NUL-terminated string for a (const or not) char pointer. // void ::testing::internal::UniversalPrint(const T& value, ostream*); // // // Prints the fields of a tuple tersely to a string vector, one // // element for each field. Tuple support must be enabled in // // gtest-port.h. // std::vector UniversalTersePrintTupleFieldsToStrings( // const Tuple& value); // // Known limitation: // // The print primitives print the elements of an STL-style container // using the compiler-inferred type of *iter where iter is a // const_iterator of the container. When const_iterator is an input // iterator but not a forward iterator, this inferred type may not // match value_type, and the print output may be incorrect. In // practice, this is rarely a problem as for most containers // const_iterator is a forward iterator. We'll fix this if there's an // actual need for it. Note that this fix cannot rely on value_type // being defined as many user-defined container types don't have // value_type. // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #include #include // NOLINT #include #include #include #include #include #include #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-port.h" #if GTEST_HAS_ABSL #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "absl/types/variant.h" #endif // GTEST_HAS_ABSL namespace testing { // Definitions in the 'internal' and 'internal2' name spaces are // subject to change without notice. DO NOT USE THEM IN USER CODE! namespace internal2 { // Prints the given number of bytes in the given object to the given // ostream. GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, ::std::ostream* os); // For selecting which printer to use when a given type has neither << // nor PrintTo(). enum TypeKind { kProtobuf, // a protobuf type kConvertibleToInteger, // a type implicitly convertible to BiggestInt // (e.g. a named or unnamed enum type) #if GTEST_HAS_ABSL kConvertibleToStringView, // a type implicitly convertible to // absl::string_view #endif kOtherType // anything else }; // TypeWithoutFormatter::PrintValue(value, os) is called // by the universal printer to print a value of type T when neither // operator<< nor PrintTo() is defined for T, where kTypeKind is the // "kind" of T as defined by enum TypeKind. template class TypeWithoutFormatter { public: // This default version is called when kTypeKind is kOtherType. static void PrintValue(const T& value, ::std::ostream* os) { PrintBytesInObjectTo( static_cast( reinterpret_cast(std::addressof(value))), sizeof(value), os); } }; // We print a protobuf using its ShortDebugString() when the string // doesn't exceed this many characters; otherwise we print it using // DebugString() for better readability. const size_t kProtobufOneLinerMaxLength = 50; template class TypeWithoutFormatter { public: static void PrintValue(const T& value, ::std::ostream* os) { std::string pretty_str = value.ShortDebugString(); if (pretty_str.length() > kProtobufOneLinerMaxLength) { pretty_str = "\n" + value.DebugString(); } *os << ("<" + pretty_str + ">"); } }; template class TypeWithoutFormatter { public: // Since T has no << operator or PrintTo() but can be implicitly // converted to BiggestInt, we print it as a BiggestInt. // // Most likely T is an enum type (either named or unnamed), in which // case printing it as an integer is the desired behavior. In case // T is not an enum, printing it as an integer is the best we can do // given that it has no user-defined printer. static void PrintValue(const T& value, ::std::ostream* os) { const internal::BiggestInt kBigInt = value; *os << kBigInt; } }; #if GTEST_HAS_ABSL template class TypeWithoutFormatter { public: // Since T has neither operator<< nor PrintTo() but can be implicitly // converted to absl::string_view, we print it as a absl::string_view. // // Note: the implementation is further below, as it depends on // internal::PrintTo symbol which is defined later in the file. static void PrintValue(const T& value, ::std::ostream* os); }; #endif // Prints the given value to the given ostream. If the value is a // protocol message, its debug string is printed; if it's an enum or // of a type implicitly convertible to BiggestInt, it's printed as an // integer; otherwise the bytes in the value are printed. This is // what UniversalPrinter::Print() does when it knows nothing about // type T and T has neither << operator nor PrintTo(). // // A user can override this behavior for a class type Foo by defining // a << operator in the namespace where Foo is defined. // // We put this operator in namespace 'internal2' instead of 'internal' // to simplify the implementation, as much code in 'internal' needs to // use << in STL, which would conflict with our own << were it defined // in 'internal'. // // Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If // we define it to take an std::ostream instead, we'll get an // "ambiguous overloads" compiler error when trying to print a type // Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether // operator<<(std::ostream&, const T&) or // operator<<(std::basic_stream, const Foo&) is more // specific. template ::std::basic_ostream& operator<<( ::std::basic_ostream& os, const T& x) { TypeWithoutFormatter::value ? kProtobuf : std::is_convertible< const T&, internal::BiggestInt>::value ? kConvertibleToInteger : #if GTEST_HAS_ABSL std::is_convertible< const T&, absl::string_view>::value ? kConvertibleToStringView : #endif kOtherType)>::PrintValue(x, &os); return os; } } // namespace internal2 } // namespace testing // This namespace MUST NOT BE NESTED IN ::testing, or the name look-up // magic needed for implementing UniversalPrinter won't work. namespace testing_internal { // Used to print a value that is not an STL-style container when the // user doesn't define PrintTo() for it. template void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { // With the following statement, during unqualified name lookup, // testing::internal2::operator<< appears as if it was declared in // the nearest enclosing namespace that contains both // ::testing_internal and ::testing::internal2, i.e. the global // namespace. For more details, refer to the C++ Standard section // 7.3.4-1 [namespace.udir]. This allows us to fall back onto // testing::internal2::operator<< in case T doesn't come with a << // operator. // // We cannot write 'using ::testing::internal2::operator<<;', which // gcc 3.3 fails to compile due to a compiler bug. using namespace ::testing::internal2; // NOLINT // Assuming T is defined in namespace foo, in the next statement, // the compiler will consider all of: // // 1. foo::operator<< (thanks to Koenig look-up), // 2. ::operator<< (as the current namespace is enclosed in ::), // 3. testing::internal2::operator<< (thanks to the using statement above). // // The operator<< whose type matches T best will be picked. // // We deliberately allow #2 to be a candidate, as sometimes it's // impossible to define #1 (e.g. when foo is ::std, defining // anything in it is undefined behavior unless you are a compiler // vendor.). *os << value; } } // namespace testing_internal namespace testing { namespace internal { // FormatForComparison::Format(value) formats a // value of type ToPrint that is an operand of a comparison assertion // (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in // the comparison, and is used to help determine the best way to // format the value. In particular, when the value is a C string // (char pointer) and the other operand is an STL string object, we // want to format the C string as a string, since we know it is // compared by value with the string object. If the value is a char // pointer but the other operand is not an STL string object, we don't // know whether the pointer is supposed to point to a NUL-terminated // string, and thus want to print it as a pointer to be safe. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // The default case. template class FormatForComparison { public: static ::std::string Format(const ToPrint& value) { return ::testing::PrintToString(value); } }; // Array. template class FormatForComparison { public: static ::std::string Format(const ToPrint* value) { return FormatForComparison::Format(value); } }; // By default, print C string as pointers to be safe, as we don't know // whether they actually point to a NUL-terminated string. #define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ template \ class FormatForComparison { \ public: \ static ::std::string Format(CharType* value) { \ return ::testing::PrintToString(static_cast(value)); \ } \ } GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); #undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ // If a C string is compared with an STL string object, we know it's meant // to point to a NUL-terminated string, and thus can print it as a string. #define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ template <> \ class FormatForComparison { \ public: \ static ::std::string Format(CharType* value) { \ return ::testing::PrintToString(value); \ } \ } GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); #if GTEST_HAS_STD_WSTRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); #endif #undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ // Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) // operand to be used in a failure message. The type (but not value) // of the other operand may affect the format. This allows us to // print a char* as a raw pointer when it is compared against another // char* or void*, and print it as a C string when it is compared // against an std::string object, for example. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template std::string FormatForComparisonFailureMessage( const T1& value, const T2& /* other_operand */) { return FormatForComparison::Format(value); } // UniversalPrinter::Print(value, ostream_ptr) prints the given // value to the given ostream. The caller must ensure that // 'ostream_ptr' is not NULL, or the behavior is undefined. // // We define UniversalPrinter as a class template (as opposed to a // function template), as we need to partially specialize it for // reference types, which cannot be done with function templates. template class UniversalPrinter; template void UniversalPrint(const T& value, ::std::ostream* os); enum DefaultPrinterType { kPrintContainer, kPrintPointer, kPrintFunctionPointer, kPrintOther, }; template struct WrapPrinterType {}; // Used to print an STL-style container when the user doesn't define // a PrintTo() for it. template void DefaultPrintTo(WrapPrinterType /* dummy */, const C& container, ::std::ostream* os) { const size_t kMaxCount = 32; // The maximum number of elements to print. *os << '{'; size_t count = 0; for (typename C::const_iterator it = container.begin(); it != container.end(); ++it, ++count) { if (count > 0) { *os << ','; if (count == kMaxCount) { // Enough has been printed. *os << " ..."; break; } } *os << ' '; // We cannot call PrintTo(*it, os) here as PrintTo() doesn't // handle *it being a native array. internal::UniversalPrint(*it, os); } if (count > 0) { *os << ' '; } *os << '}'; } // Used to print a pointer that is neither a char pointer nor a member // pointer, when the user doesn't define PrintTo() for it. (A member // variable pointer or member function pointer doesn't really point to // a location in the address space. Their representation is // implementation-defined. Therefore they will be printed as raw // bytes.) template void DefaultPrintTo(WrapPrinterType /* dummy */, T* p, ::std::ostream* os) { if (p == nullptr) { *os << "NULL"; } else { // T is not a function type. We just call << to print p, // relying on ADL to pick up user-defined << for their pointer // types, if any. *os << p; } } template void DefaultPrintTo(WrapPrinterType /* dummy */, T* p, ::std::ostream* os) { if (p == nullptr) { *os << "NULL"; } else { // T is a function type, so '*os << p' doesn't do what we want // (it just prints p as bool). We want to print p as a const // void*. *os << reinterpret_cast(p); } } // Used to print a non-container, non-pointer value when the user // doesn't define PrintTo() for it. template void DefaultPrintTo(WrapPrinterType /* dummy */, const T& value, ::std::ostream* os) { ::testing_internal::DefaultPrintNonContainerTo(value, os); } // Prints the given value using the << operator if it has one; // otherwise prints the bytes in it. This is what // UniversalPrinter::Print() does when PrintTo() is not specialized // or overloaded for type T. // // A user can override this behavior for a class type Foo by defining // an overload of PrintTo() in the namespace where Foo is defined. We // give the user this option as sometimes defining a << operator for // Foo is not desirable (e.g. the coding style may prevent doing it, // or there is already a << operator but it doesn't do what the user // wants). template void PrintTo(const T& value, ::std::ostream* os) { // DefaultPrintTo() is overloaded. The type of its first argument // determines which version will be picked. // // Note that we check for container types here, prior to we check // for protocol message types in our operator<<. The rationale is: // // For protocol messages, we want to give people a chance to // override Google Mock's format by defining a PrintTo() or // operator<<. For STL containers, other formats can be // incompatible with Google Mock's format for the container // elements; therefore we check for container types here to ensure // that our format is used. // // Note that MSVC and clang-cl do allow an implicit conversion from // pointer-to-function to pointer-to-object, but clang-cl warns on it. // So don't use ImplicitlyConvertible if it can be helped since it will // cause this warning, and use a separate overload of DefaultPrintTo for // function pointers so that the `*os << p` in the object pointer overload // doesn't cause that warning either. DefaultPrintTo( WrapPrinterType < (sizeof(IsContainerTest(0)) == sizeof(IsContainer)) && !IsRecursiveContainer::value ? kPrintContainer : !std::is_pointer::value ? kPrintOther : std::is_function::type>::value ? kPrintFunctionPointer : kPrintPointer > (), value, os); } // The following list of PrintTo() overloads tells // UniversalPrinter::Print() how to print standard types (built-in // types, strings, plain arrays, and pointers). // Overloads for various char types. GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os); GTEST_API_ void PrintTo(signed char c, ::std::ostream* os); inline void PrintTo(char c, ::std::ostream* os) { // When printing a plain char, we always treat it as unsigned. This // way, the output won't be affected by whether the compiler thinks // char is signed or not. PrintTo(static_cast(c), os); } // Overloads for other simple built-in types. inline void PrintTo(bool x, ::std::ostream* os) { *os << (x ? "true" : "false"); } // Overload for wchar_t type. // Prints a wchar_t as a symbol if it is printable or as its internal // code otherwise and also as its decimal code (except for L'\0'). // The L'\0' char is printed as "L'\\0'". The decimal code is printed // as signed integer when wchar_t is implemented by the compiler // as a signed type and is printed as an unsigned integer when wchar_t // is implemented as an unsigned type. GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); // Overloads for C strings. GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); inline void PrintTo(char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } // signed/unsigned char is often used for representing binary data, so // we print pointers to it as void* to be safe. inline void PrintTo(const signed char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(signed char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(const unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } // MSVC can be configured to define wchar_t as a typedef of unsigned // short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native // type. When wchar_t is a typedef, defining an overload for const // wchar_t* would cause unsigned short* be printed as a wide string, // possibly causing invalid memory accesses. #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // Overloads for wide C strings GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); inline void PrintTo(wchar_t* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } #endif // Overload for C arrays. Multi-dimensional arrays are printed // properly. // Prints the given number of elements in an array, without printing // the curly braces. template void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { UniversalPrint(a[0], os); for (size_t i = 1; i != count; i++) { *os << ", "; UniversalPrint(a[i], os); } } // Overloads for ::std::string. GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); inline void PrintTo(const ::std::string& s, ::std::ostream* os) { PrintStringTo(s, os); } // Overloads for ::std::wstring. #if GTEST_HAS_STD_WSTRING GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { PrintWideStringTo(s, os); } #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_ABSL // Overload for absl::string_view. inline void PrintTo(absl::string_view sp, ::std::ostream* os) { PrintTo(::std::string(sp), os); } #endif // GTEST_HAS_ABSL inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; } template void PrintTo(std::reference_wrapper ref, ::std::ostream* os) { UniversalPrinter::Print(ref.get(), os); } // Helper function for printing a tuple. T must be instantiated with // a tuple type. template void PrintTupleTo(const T&, std::integral_constant, ::std::ostream*) {} template void PrintTupleTo(const T& t, std::integral_constant, ::std::ostream* os) { PrintTupleTo(t, std::integral_constant(), os); GTEST_INTENTIONAL_CONST_COND_PUSH_() if (I > 1) { GTEST_INTENTIONAL_CONST_COND_POP_() *os << ", "; } UniversalPrinter::type>::Print( std::get(t), os); } template void PrintTo(const ::std::tuple& t, ::std::ostream* os) { *os << "("; PrintTupleTo(t, std::integral_constant(), os); *os << ")"; } // Overload for std::pair. template void PrintTo(const ::std::pair& value, ::std::ostream* os) { *os << '('; // We cannot use UniversalPrint(value.first, os) here, as T1 may be // a reference type. The same for printing value.second. UniversalPrinter::Print(value.first, os); *os << ", "; UniversalPrinter::Print(value.second, os); *os << ')'; } // Implements printing a non-reference type T by letting the compiler // pick the right overload of PrintTo() for T. template class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) // Note: we deliberately don't call this PrintTo(), as that name // conflicts with ::testing::internal::PrintTo in the body of the // function. static void Print(const T& value, ::std::ostream* os) { // By default, ::testing::internal::PrintTo() is used for printing // the value. // // Thanks to Koenig look-up, if T is a class and has its own // PrintTo() function defined in its namespace, that function will // be visible here. Since it is more specific than the generic ones // in ::testing::internal, it will be picked by the compiler in the // following statement - exactly what we want. PrintTo(value, os); } GTEST_DISABLE_MSC_WARNINGS_POP_() }; #if GTEST_HAS_ABSL // Printer for absl::optional template class UniversalPrinter<::absl::optional> { public: static void Print(const ::absl::optional& value, ::std::ostream* os) { *os << '('; if (!value) { *os << "nullopt"; } else { UniversalPrint(*value, os); } *os << ')'; } }; // Printer for absl::variant template class UniversalPrinter<::absl::variant> { public: static void Print(const ::absl::variant& value, ::std::ostream* os) { *os << '('; absl::visit(Visitor{os}, value); *os << ')'; } private: struct Visitor { template void operator()(const U& u) const { *os << "'" << GetTypeName() << "' with value "; UniversalPrint(u, os); } ::std::ostream* os; }; }; #endif // GTEST_HAS_ABSL // UniversalPrintArray(begin, len, os) prints an array of 'len' // elements, starting at address 'begin'. template void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { if (len == 0) { *os << "{}"; } else { *os << "{ "; const size_t kThreshold = 18; const size_t kChunkSize = 8; // If the array has more than kThreshold elements, we'll have to // omit some details by printing only the first and the last // kChunkSize elements. if (len <= kThreshold) { PrintRawArrayTo(begin, len, os); } else { PrintRawArrayTo(begin, kChunkSize, os); *os << ", ..., "; PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); } *os << " }"; } } // This overload prints a (const) char array compactly. GTEST_API_ void UniversalPrintArray( const char* begin, size_t len, ::std::ostream* os); // This overload prints a (const) wchar_t array compactly. GTEST_API_ void UniversalPrintArray( const wchar_t* begin, size_t len, ::std::ostream* os); // Implements printing an array type T[N]. template class UniversalPrinter { public: // Prints the given array, omitting some elements when there are too // many. static void Print(const T (&a)[N], ::std::ostream* os) { UniversalPrintArray(a, N, os); } }; // Implements printing a reference type T&. template class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) static void Print(const T& value, ::std::ostream* os) { // Prints the address of the value. We use reinterpret_cast here // as static_cast doesn't compile when T is a function type. *os << "@" << reinterpret_cast(&value) << " "; // Then prints the value itself. UniversalPrint(value, os); } GTEST_DISABLE_MSC_WARNINGS_POP_() }; // Prints a value tersely: for a reference type, the referenced value // (but not the address) is printed; for a (const) char pointer, the // NUL-terminated string (but not the pointer) is printed. template class UniversalTersePrinter { public: static void Print(const T& value, ::std::ostream* os) { UniversalPrint(value, os); } }; template class UniversalTersePrinter { public: static void Print(const T& value, ::std::ostream* os) { UniversalPrint(value, os); } }; template class UniversalTersePrinter { public: static void Print(const T (&value)[N], ::std::ostream* os) { UniversalPrinter::Print(value, os); } }; template <> class UniversalTersePrinter { public: static void Print(const char* str, ::std::ostream* os) { if (str == nullptr) { *os << "NULL"; } else { UniversalPrint(std::string(str), os); } } }; template <> class UniversalTersePrinter { public: static void Print(char* str, ::std::ostream* os) { UniversalTersePrinter::Print(str, os); } }; #if GTEST_HAS_STD_WSTRING template <> class UniversalTersePrinter { public: static void Print(const wchar_t* str, ::std::ostream* os) { if (str == nullptr) { *os << "NULL"; } else { UniversalPrint(::std::wstring(str), os); } } }; #endif template <> class UniversalTersePrinter { public: static void Print(wchar_t* str, ::std::ostream* os) { UniversalTersePrinter::Print(str, os); } }; template void UniversalTersePrint(const T& value, ::std::ostream* os) { UniversalTersePrinter::Print(value, os); } // Prints a value using the type inferred by the compiler. The // difference between this and UniversalTersePrint() is that for a // (const) char pointer, this prints both the pointer and the // NUL-terminated string. template void UniversalPrint(const T& value, ::std::ostream* os) { // A workarond for the bug in VC++ 7.1 that prevents us from instantiating // UniversalPrinter with T directly. typedef T T1; UniversalPrinter::Print(value, os); } typedef ::std::vector< ::std::string> Strings; // Tersely prints the first N fields of a tuple to a string vector, // one element for each field. template void TersePrintPrefixToStrings(const Tuple&, std::integral_constant, Strings*) {} template void TersePrintPrefixToStrings(const Tuple& t, std::integral_constant, Strings* strings) { TersePrintPrefixToStrings(t, std::integral_constant(), strings); ::std::stringstream ss; UniversalTersePrint(std::get(t), &ss); strings->push_back(ss.str()); } // Prints the fields of a tuple tersely to a string vector, one // element for each field. See the comment before // UniversalTersePrint() for how we define "tersely". template Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { Strings result; TersePrintPrefixToStrings( value, std::integral_constant::value>(), &result); return result; } } // namespace internal #if GTEST_HAS_ABSL namespace internal2 { template void TypeWithoutFormatter::PrintValue( const T& value, ::std::ostream* os) { internal::PrintTo(absl::string_view(value), os); } } // namespace internal2 #endif template ::std::string PrintToString(const T& value) { ::std::stringstream ss; internal::UniversalTersePrinter::Print(value, &ss); return ss.str(); } } // namespace testing // Include any custom printer added by the local installation. // We must include this header at the end to make sure it can use the // declarations from this file. #include "gtest/internal/custom/gtest-printers.h" #endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ openzwave-1.6.1914/cpp/test/include/gtest/gtest-typed-test.h0000644000175200017520000003570114032142455020637 00000000000000// Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ // This header implements typed tests and type-parameterized tests. // Typed (aka type-driven) tests repeat the same test for types in a // list. You must know which types you want to test with when writing // typed tests. Here's how you do it: #if 0 // First, define a fixture class template. It should be parameterized // by a type. Remember to derive it from testing::Test. template class FooTest : public testing::Test { public: ... typedef std::list List; static T shared_; T value_; }; // Next, associate a list of types with the test suite, which will be // repeated for each type in the list. The typedef is necessary for // the macro to parse correctly. typedef testing::Types MyTypes; TYPED_TEST_SUITE(FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: // TYPED_TEST_SUITE(FooTest, int); // Then, use TYPED_TEST() instead of TEST_F() to define as many typed // tests for this test suite as you want. TYPED_TEST(FooTest, DoesBlah) { // Inside a test, refer to the special name TypeParam to get the type // parameter. Since we are inside a derived class template, C++ requires // us to visit the members of FooTest via 'this'. TypeParam n = this->value_; // To visit static members of the fixture, add the TestFixture:: // prefix. n += TestFixture::shared_; // To refer to typedefs in the fixture, add the "typename // TestFixture::" prefix. typename TestFixture::List values; values.push_back(n); ... } TYPED_TEST(FooTest, HasPropertyA) { ... } // TYPED_TEST_SUITE takes an optional third argument which allows to specify a // class that generates custom test name suffixes based on the type. This should // be a class which has a static template function GetName(int index) returning // a string for each type. The provided integer index equals the index of the // type in the provided type list. In many cases the index can be ignored. // // For example: // class MyTypeNames { // public: // template // static std::string GetName(int) { // if (std::is_same()) return "char"; // if (std::is_same()) return "int"; // if (std::is_same()) return "unsignedInt"; // } // }; // TYPED_TEST_SUITE(FooTest, MyTypes, MyTypeNames); #endif // 0 // Type-parameterized tests are abstract test patterns parameterized // by a type. Compared with typed tests, type-parameterized tests // allow you to define the test pattern without knowing what the type // parameters are. The defined pattern can be instantiated with // different types any number of times, in any number of translation // units. // // If you are designing an interface or concept, you can define a // suite of type-parameterized tests to verify properties that any // valid implementation of the interface/concept should have. Then, // each implementation can easily instantiate the test suite to verify // that it conforms to the requirements, without having to write // similar tests repeatedly. Here's an example: #if 0 // First, define a fixture class template. It should be parameterized // by a type. Remember to derive it from testing::Test. template class FooTest : public testing::Test { ... }; // Next, declare that you will define a type-parameterized test suite // (the _P suffix is for "parameterized" or "pattern", whichever you // prefer): TYPED_TEST_SUITE_P(FooTest); // Then, use TYPED_TEST_P() to define as many type-parameterized tests // for this type-parameterized test suite as you want. TYPED_TEST_P(FooTest, DoesBlah) { // Inside a test, refer to TypeParam to get the type parameter. TypeParam n = 0; ... } TYPED_TEST_P(FooTest, HasPropertyA) { ... } // Now the tricky part: you need to register all test patterns before // you can instantiate them. The first argument of the macro is the // test suite name; the rest are the names of the tests in this test // case. REGISTER_TYPED_TEST_SUITE_P(FooTest, DoesBlah, HasPropertyA); // Finally, you are free to instantiate the pattern with the types you // want. If you put the above code in a header file, you can #include // it in multiple C++ source files and instantiate it multiple times. // // To distinguish different instances of the pattern, the first // argument to the INSTANTIATE_* macro is a prefix that will be added // to the actual test suite name. Remember to pick unique prefixes for // different instances. typedef testing::Types MyTypes; INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: // INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, int); // // Similar to the optional argument of TYPED_TEST_SUITE above, // INSTANTIATE_TEST_SUITE_P takes an optional fourth argument which allows to // generate custom names. // INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes, MyTypeNames); #endif // 0 #include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-type-util.h" // Implements typed tests. #if GTEST_HAS_TYPED_TEST // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the typedef for the type parameters of the // given test suite. #define GTEST_TYPE_PARAMS_(TestSuiteName) gtest_type_params_##TestSuiteName##_ // Expands to the name of the typedef for the NameGenerator, responsible for // creating the suffixes of the name. #define GTEST_NAME_GENERATOR_(TestSuiteName) \ gtest_type_params_##TestSuiteName##_NameGenerator #define TYPED_TEST_SUITE(CaseName, Types, ...) \ typedef ::testing::internal::GenerateTypeList::type \ GTEST_TYPE_PARAMS_(CaseName); \ typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \ GTEST_NAME_GENERATOR_(CaseName) #define TYPED_TEST(CaseName, TestName) \ template \ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ : public CaseName { \ private: \ typedef CaseName TestFixture; \ typedef gtest_TypeParam_ TypeParam; \ void TestBody() override; \ }; \ static bool gtest_##CaseName##_##TestName##_registered_ \ GTEST_ATTRIBUTE_UNUSED_ = ::testing::internal::TypeParameterizedTest< \ CaseName, \ ::testing::internal::TemplateSel, \ GTEST_TYPE_PARAMS_( \ CaseName)>::Register("", \ ::testing::internal::CodeLocation( \ __FILE__, __LINE__), \ #CaseName, #TestName, 0, \ ::testing::internal::GenerateNames< \ GTEST_NAME_GENERATOR_(CaseName), \ GTEST_TYPE_PARAMS_(CaseName)>()); \ template \ void GTEST_TEST_CLASS_NAME_(CaseName, \ TestName)::TestBody() // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #define TYPED_TEST_CASE \ static_assert(::testing::internal::TypedTestCaseIsDeprecated(), ""); \ TYPED_TEST_SUITE #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #endif // GTEST_HAS_TYPED_TEST // Implements type-parameterized tests. #if GTEST_HAS_TYPED_TEST_P // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the namespace name that the type-parameterized tests for // the given type-parameterized test suite are defined in. The exact // name of the namespace is subject to change without notice. #define GTEST_SUITE_NAMESPACE_(TestSuiteName) gtest_suite_##TestSuiteName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the variable used to remember the names of // the defined tests in the given test suite. #define GTEST_TYPED_TEST_SUITE_P_STATE_(TestSuiteName) \ gtest_typed_test_suite_p_state_##TestSuiteName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. // // Expands to the name of the variable used to remember the names of // the registered tests in the given test suite. #define GTEST_REGISTERED_TEST_NAMES_(TestSuiteName) \ gtest_registered_test_names_##TestSuiteName##_ // The variables defined in the type-parameterized test macros are // static as typically these macros are used in a .h file that can be // #included in multiple translation units linked together. #define TYPED_TEST_SUITE_P(SuiteName) \ static ::testing::internal::TypedTestSuitePState \ GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName) // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #define TYPED_TEST_CASE_P \ static_assert(::testing::internal::TypedTestCase_P_IsDeprecated(), ""); \ TYPED_TEST_SUITE_P #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #define TYPED_TEST_P(SuiteName, TestName) \ namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ template \ class TestName : public SuiteName { \ private: \ typedef SuiteName TestFixture; \ typedef gtest_TypeParam_ TypeParam; \ void TestBody() override; \ }; \ static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \ __FILE__, __LINE__, #SuiteName, #TestName); \ } \ template \ void GTEST_SUITE_NAMESPACE_( \ SuiteName)::TestName::TestBody() #define REGISTER_TYPED_TEST_SUITE_P(SuiteName, ...) \ namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ typedef ::testing::internal::Templates<__VA_ARGS__> gtest_AllTests_; \ } \ static const char* const GTEST_REGISTERED_TEST_NAMES_( \ SuiteName) GTEST_ATTRIBUTE_UNUSED_ = \ GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \ __FILE__, __LINE__, #__VA_ARGS__) // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #define REGISTER_TYPED_TEST_CASE_P \ static_assert(::testing::internal::RegisterTypedTestCase_P_IsDeprecated(), \ ""); \ REGISTER_TYPED_TEST_SUITE_P #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \ static bool gtest_##Prefix##_##SuiteName GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::internal::TypeParameterizedTestSuite< \ SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \ ::testing::internal::GenerateTypeList::type>:: \ Register(#Prefix, \ ::testing::internal::CodeLocation(__FILE__, __LINE__), \ >EST_TYPED_TEST_SUITE_P_STATE_(SuiteName), #SuiteName, \ GTEST_REGISTERED_TEST_NAMES_(SuiteName), \ ::testing::internal::GenerateNames< \ ::testing::internal::NameGeneratorSelector< \ __VA_ARGS__>::type, \ ::testing::internal::GenerateTypeList::type>()) // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #define INSTANTIATE_TYPED_TEST_CASE_P \ static_assert( \ ::testing::internal::InstantiateTypedTestCase_P_IsDeprecated(), ""); \ INSTANTIATE_TYPED_TEST_SUITE_P #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #endif // GTEST_HAS_TYPED_TEST_P #endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ openzwave-1.6.1914/cpp/test/include/gtest/gtest-spi.h0000644000175200017520000002356114032142455017331 00000000000000// Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Utilities for testing Google Test itself and code that uses Google Test // (e.g. frameworks built on top of Google Test). // GOOGLETEST_CM0004 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #include "gtest/gtest.h" GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) namespace testing { // This helper class can be used to mock out Google Test failure reporting // so that we can test Google Test or code that builds on Google Test. // // An object of this class appends a TestPartResult object to the // TestPartResultArray object given in the constructor whenever a Google Test // failure is reported. It can either intercept only failures that are // generated in the same thread that created this object or it can intercept // all generated failures. The scope of this mock object can be controlled with // the second argument to the two arguments constructor. class GTEST_API_ ScopedFakeTestPartResultReporter : public TestPartResultReporterInterface { public: // The two possible mocking modes of this object. enum InterceptMode { INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. INTERCEPT_ALL_THREADS // Intercepts all failures. }; // The c'tor sets this object as the test part result reporter used // by Google Test. The 'result' parameter specifies where to report the // results. This reporter will only catch failures generated in the current // thread. DEPRECATED explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); // Same as above, but you can choose the interception scope of this object. ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, TestPartResultArray* result); // The d'tor restores the previous test part result reporter. ~ScopedFakeTestPartResultReporter() override; // Appends the TestPartResult object to the TestPartResultArray // received in the constructor. // // This method is from the TestPartResultReporterInterface // interface. void ReportTestPartResult(const TestPartResult& result) override; private: void Init(); const InterceptMode intercept_mode_; TestPartResultReporterInterface* old_reporter_; TestPartResultArray* const result_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); }; namespace internal { // A helper class for implementing EXPECT_FATAL_FAILURE() and // EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given // TestPartResultArray contains exactly one failure that has the given // type and contains the given substring. If that's not the case, a // non-fatal failure will be generated. class GTEST_API_ SingleFailureChecker { public: // The constructor remembers the arguments. SingleFailureChecker(const TestPartResultArray* results, TestPartResult::Type type, const std::string& substr); ~SingleFailureChecker(); private: const TestPartResultArray* const results_; const TestPartResult::Type type_; const std::string substr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); }; } // namespace internal } // namespace testing GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 // A set of macros for testing Google Test assertions or code that's expected // to generate Google Test fatal failures. It verifies that the given // statement will cause exactly one fatal Google Test failure with 'substr' // being part of the failure message. // // There are two different versions of this macro. EXPECT_FATAL_FAILURE only // affects and considers failures generated in the current thread and // EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. // // The verification of the assertion is done correctly even when the statement // throws an exception or aborts the current function. // // Known restrictions: // - 'statement' cannot reference local non-static variables or // non-static members of the current object. // - 'statement' cannot return a value. // - You cannot stream a failure message to this macro. // // Note that even though the implementations of the following two // macros are much alike, we cannot refactor them to use a common // helper macro, due to some peculiarity in how the preprocessor // works. The AcceptsMacroThatExpandsToUnprotectedComma test in // gtest_unittest.cc will fail to compile if we do that. #define EXPECT_FATAL_FAILURE(statement, substr) \ do { \ class GTestExpectFatalFailureHelper {\ public:\ static void Execute() { statement; }\ };\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ GTestExpectFatalFailureHelper::Execute();\ }\ } while (::testing::internal::AlwaysFalse()) #define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ do { \ class GTestExpectFatalFailureHelper {\ public:\ static void Execute() { statement; }\ };\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ALL_THREADS, >est_failures);\ GTestExpectFatalFailureHelper::Execute();\ }\ } while (::testing::internal::AlwaysFalse()) // A macro for testing Google Test assertions or code that's expected to // generate Google Test non-fatal failures. It asserts that the given // statement will cause exactly one non-fatal Google Test failure with 'substr' // being part of the failure message. // // There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only // affects and considers failures generated in the current thread and // EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. // // 'statement' is allowed to reference local variables and members of // the current object. // // The verification of the assertion is done correctly even when the statement // throws an exception or aborts the current function. // // Known restrictions: // - You cannot stream a failure message to this macro. // // Note that even though the implementations of the following two // macros are much alike, we cannot refactor them to use a common // helper macro, due to some peculiarity in how the preprocessor // works. If we do that, the code won't compile when the user gives // EXPECT_NONFATAL_FAILURE() a statement that contains a macro that // expands to code containing an unprotected comma. The // AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc // catches that. // // For the same reason, we have to write // if (::testing::internal::AlwaysTrue()) { statement; } // instead of // GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) // to avoid an MSVC warning on unreachable code. #define EXPECT_NONFATAL_FAILURE(statement, substr) \ do {\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ if (::testing::internal::AlwaysTrue()) { statement; }\ }\ } while (::testing::internal::AlwaysFalse()) #define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ do {\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ >est_failures);\ if (::testing::internal::AlwaysTrue()) { statement; }\ }\ } while (::testing::internal::AlwaysFalse()) #endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ openzwave-1.6.1914/cpp/test/include/gtest/gtest-test-part.h0000644000175200017520000001530514032142455020456 00000000000000// Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #include #include #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) namespace testing { // A copyable object representing the result of a test part (i.e. an // assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). // // Don't inherit from TestPartResult as its destructor is not virtual. class GTEST_API_ TestPartResult { public: // The possible outcomes of a test part (i.e. an assertion or an // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). enum Type { kSuccess, // Succeeded. kNonFatalFailure, // Failed but the test can continue. kFatalFailure, // Failed and the test should be terminated. kSkip // Skipped. }; // C'tor. TestPartResult does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestPartResult object. TestPartResult(Type a_type, const char* a_file_name, int a_line_number, const char* a_message) : type_(a_type), file_name_(a_file_name == nullptr ? "" : a_file_name), line_number_(a_line_number), summary_(ExtractSummary(a_message)), message_(a_message) {} // Gets the outcome of the test part. Type type() const { return type_; } // Gets the name of the source file where the test part took place, or // NULL if it's unknown. const char* file_name() const { return file_name_.empty() ? nullptr : file_name_.c_str(); } // Gets the line in the source file where the test part took place, // or -1 if it's unknown. int line_number() const { return line_number_; } // Gets the summary of the failure message. const char* summary() const { return summary_.c_str(); } // Gets the message associated with the test part. const char* message() const { return message_.c_str(); } // Returns true if and only if the test part was skipped. bool skipped() const { return type_ == kSkip; } // Returns true if and only if the test part passed. bool passed() const { return type_ == kSuccess; } // Returns true if and only if the test part non-fatally failed. bool nonfatally_failed() const { return type_ == kNonFatalFailure; } // Returns true if and only if the test part fatally failed. bool fatally_failed() const { return type_ == kFatalFailure; } // Returns true if and only if the test part failed. bool failed() const { return fatally_failed() || nonfatally_failed(); } private: Type type_; // Gets the summary of the failure message by omitting the stack // trace in it. static std::string ExtractSummary(const char* message); // The name of the source file where the test part took place, or // "" if the source file is unknown. std::string file_name_; // The line in the source file where the test part took place, or -1 // if the line number is unknown. int line_number_; std::string summary_; // The test failure summary. std::string message_; // The test failure message. }; // Prints a TestPartResult object. std::ostream& operator<<(std::ostream& os, const TestPartResult& result); // An array of TestPartResult objects. // // Don't inherit from TestPartResultArray as its destructor is not // virtual. class GTEST_API_ TestPartResultArray { public: TestPartResultArray() {} // Appends the given TestPartResult to the array. void Append(const TestPartResult& result); // Returns the TestPartResult at the given index (0-based). const TestPartResult& GetTestPartResult(int index) const; // Returns the number of TestPartResult objects in the array. int size() const; private: std::vector array_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); }; // This interface knows how to report a test part result. class GTEST_API_ TestPartResultReporterInterface { public: virtual ~TestPartResultReporterInterface() {} virtual void ReportTestPartResult(const TestPartResult& result) = 0; }; namespace internal { // This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a // statement generates new fatal failures. To do so it registers itself as the // current test part result reporter. Besides checking if fatal failures were // reported, it only delegates the reporting to the former result reporter. // The original result reporter is restored in the destructor. // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. class GTEST_API_ HasNewFatalFailureHelper : public TestPartResultReporterInterface { public: HasNewFatalFailureHelper(); ~HasNewFatalFailureHelper() override; void ReportTestPartResult(const TestPartResult& result) override; bool has_new_fatal_failure() const { return has_new_fatal_failure_; } private: bool has_new_fatal_failure_; TestPartResultReporterInterface* original_reporter_; GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); }; } // namespace internal } // namespace testing GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 #endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ openzwave-1.6.1914/cpp/test/include/gtest/gtest.h0000644000175200017520000026730714032142455016550 00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the public API for Google Test. It should be // included by any test program that uses Google Test. // // IMPORTANT NOTE: Due to limitation of the C++ language, we have to // leave some internal implementation details in this header file. // They are clearly marked by comments like this: // // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // // Such code is NOT meant to be used by a user directly, and is subject // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! // // Acknowledgment: Google Test borrowed the idea of automatic test // registration from Barthelemy Dagenais' (barthelemy@prologique.com) // easyUnit framework. // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ #include #include #include #include #include #include #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" #include "gtest/gtest-death-test.h" #include "gtest/gtest-matchers.h" #include "gtest/gtest-message.h" #include "gtest/gtest-param-test.h" #include "gtest/gtest-printers.h" #include "gtest/gtest_prod.h" #include "gtest/gtest-test-part.h" #include "gtest/gtest-typed-test.h" GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) namespace testing { // Silence C4100 (unreferenced formal parameter) and 4805 // unsafe mix of type 'const int' and type 'const bool' #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable:4805) # pragma warning(disable:4100) #endif // Declares the flags. // This flag temporary enables the disabled tests. GTEST_DECLARE_bool_(also_run_disabled_tests); // This flag brings the debugger on an assertion failure. GTEST_DECLARE_bool_(break_on_failure); // This flag controls whether Google Test catches all test-thrown exceptions // and logs them as failures. GTEST_DECLARE_bool_(catch_exceptions); // This flag enables using colors in terminal output. Available values are // "yes" to enable colors, "no" (disable colors), or "auto" (the default) // to let Google Test decide. GTEST_DECLARE_string_(color); // This flag sets up the filter to select by name using a glob pattern // the tests to run. If the filter is not given all tests are executed. GTEST_DECLARE_string_(filter); // This flag controls whether Google Test installs a signal handler that dumps // debugging information when fatal signals are raised. GTEST_DECLARE_bool_(install_failure_signal_handler); // This flag causes the Google Test to list tests. None of the tests listed // are actually run if the flag is provided. GTEST_DECLARE_bool_(list_tests); // This flag controls whether Google Test emits a detailed XML report to a file // in addition to its normal textual output. GTEST_DECLARE_string_(output); // This flags control whether Google Test prints the elapsed time for each // test. GTEST_DECLARE_bool_(print_time); // This flags control whether Google Test prints UTF8 characters as text. GTEST_DECLARE_bool_(print_utf8); // This flag specifies the random number seed. GTEST_DECLARE_int32_(random_seed); // This flag sets how many times the tests are repeated. The default value // is 1. If the value is -1 the tests are repeating forever. GTEST_DECLARE_int32_(repeat); // This flag controls whether Google Test includes Google Test internal // stack frames in failure stack traces. GTEST_DECLARE_bool_(show_internal_stack_frames); // When this flag is specified, tests' order is randomized on every iteration. GTEST_DECLARE_bool_(shuffle); // This flag specifies the maximum number of stack frames to be // printed in a failure message. GTEST_DECLARE_int32_(stack_trace_depth); // When this flag is specified, a failed assertion will throw an // exception if exceptions are enabled, or exit the program with a // non-zero code otherwise. For use with an external test framework. GTEST_DECLARE_bool_(throw_on_failure); // When this flag is set with a "host:port" string, on supported // platforms test results are streamed to the specified port on // the specified host machine. GTEST_DECLARE_string_(stream_result_to); #if GTEST_USE_OWN_FLAGFILE_FLAG_ GTEST_DECLARE_string_(flagfile); #endif // GTEST_USE_OWN_FLAGFILE_FLAG_ // The upper limit for valid stack trace depths. const int kMaxStackTraceDepth = 100; namespace internal { class AssertHelper; class DefaultGlobalTestPartResultReporter; class ExecDeathTest; class NoExecDeathTest; class FinalSuccessChecker; class GTestFlagSaver; class StreamingListenerTest; class TestResultAccessor; class TestEventListenersAccessor; class TestEventRepeater; class UnitTestRecordPropertyTestHelper; class WindowsDeathTest; class FuchsiaDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message); } // namespace internal // The friend relationship of some of these classes is cyclic. // If we don't forward declare them the compiler might confuse the classes // in friendship clauses with same named classes on the scope. class Test; class TestSuite; // Old API is still available but deprecated #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ using TestCase = TestSuite; #endif class TestInfo; class UnitTest; // A class for indicating whether an assertion was successful. When // the assertion wasn't successful, the AssertionResult object // remembers a non-empty message that describes how it failed. // // To create an instance of this class, use one of the factory functions // (AssertionSuccess() and AssertionFailure()). // // This class is useful for two purposes: // 1. Defining predicate functions to be used with Boolean test assertions // EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts // 2. Defining predicate-format functions to be // used with predicate assertions (ASSERT_PRED_FORMAT*, etc). // // For example, if you define IsEven predicate: // // testing::AssertionResult IsEven(int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess(); // else // return testing::AssertionFailure() << n << " is odd"; // } // // Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) // will print the message // // Value of: IsEven(Fib(5)) // Actual: false (5 is odd) // Expected: true // // instead of a more opaque // // Value of: IsEven(Fib(5)) // Actual: false // Expected: true // // in case IsEven is a simple Boolean predicate. // // If you expect your predicate to be reused and want to support informative // messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up // about half as often as positive ones in our tests), supply messages for // both success and failure cases: // // testing::AssertionResult IsEven(int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess() << n << " is even"; // else // return testing::AssertionFailure() << n << " is odd"; // } // // Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print // // Value of: IsEven(Fib(6)) // Actual: true (8 is even) // Expected: false // // NB: Predicates that support negative Boolean assertions have reduced // performance in positive ones so be careful not to use them in tests // that have lots (tens of thousands) of positive Boolean assertions. // // To use this class with EXPECT_PRED_FORMAT assertions such as: // // // Verifies that Foo() returns an even number. // EXPECT_PRED_FORMAT1(IsEven, Foo()); // // you need to define: // // testing::AssertionResult IsEven(const char* expr, int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess(); // else // return testing::AssertionFailure() // << "Expected: " << expr << " is even\n Actual: it's " << n; // } // // If Foo() returns 5, you will see the following message: // // Expected: Foo() is even // Actual: it's 5 // class GTEST_API_ AssertionResult { public: // Copy constructor. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult(const AssertionResult& other); #if defined(_MSC_VER) && _MSC_VER < 1910 GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */) #endif // Used in the EXPECT_TRUE/FALSE(bool_expression). // // T must be contextually convertible to bool. // // The second parameter prevents this overload from being considered if // the argument is implicitly convertible to AssertionResult. In that case // we want AssertionResult's copy constructor to be used. template explicit AssertionResult( const T& success, typename std::enable_if< !std::is_convertible::value>::type* /*enabler*/ = nullptr) : success_(success) {} #if defined(_MSC_VER) && _MSC_VER < 1910 GTEST_DISABLE_MSC_WARNINGS_POP_() #endif // Assignment operator. AssertionResult& operator=(AssertionResult other) { swap(other); return *this; } // Returns true if and only if the assertion succeeded. operator bool() const { return success_; } // NOLINT // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult operator!() const; // Returns the text streamed into this AssertionResult. Test assertions // use it when they fail (i.e., the predicate's outcome doesn't match the // assertion's expectation). When nothing has been streamed into the // object, returns an empty string. const char* message() const { return message_.get() != nullptr ? message_->c_str() : ""; } // Deprecated; please use message() instead. const char* failure_message() const { return message(); } // Streams a custom failure message into this object. template AssertionResult& operator<<(const T& value) { AppendMessage(Message() << value); return *this; } // Allows streaming basic output manipulators such as endl or flush into // this object. AssertionResult& operator<<( ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { AppendMessage(Message() << basic_manipulator); return *this; } private: // Appends the contents of message to message_. void AppendMessage(const Message& a_message) { if (message_.get() == nullptr) message_.reset(new ::std::string); message_->append(a_message.GetString().c_str()); } // Swap the contents of this AssertionResult with other. void swap(AssertionResult& other); // Stores result of the assertion predicate. bool success_; // Stores the message describing the condition in case the expectation // construct is not satisfied with the predicate's outcome. // Referenced via a pointer to avoid taking too much stack frame space // with test assertions. std::unique_ptr< ::std::string> message_; }; // Makes a successful assertion result. GTEST_API_ AssertionResult AssertionSuccess(); // Makes a failed assertion result. GTEST_API_ AssertionResult AssertionFailure(); // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << msg. GTEST_API_ AssertionResult AssertionFailure(const Message& msg); } // namespace testing // Includes the auto-generated header that implements a family of generic // predicate assertion macros. This include comes late because it relies on // APIs declared above. #include "gtest/gtest_pred_impl.h" namespace testing { // The abstract class that all tests inherit from. // // In Google Test, a unit test program contains one or many TestSuites, and // each TestSuite contains one or many Tests. // // When you define a test using the TEST macro, you don't need to // explicitly derive from Test - the TEST macro automatically does // this for you. // // The only time you derive from Test is when defining a test fixture // to be used in a TEST_F. For example: // // class FooTest : public testing::Test { // protected: // void SetUp() override { ... } // void TearDown() override { ... } // ... // }; // // TEST_F(FooTest, Bar) { ... } // TEST_F(FooTest, Baz) { ... } // // Test is not copyable. class GTEST_API_ Test { public: friend class TestInfo; // The d'tor is virtual as we intend to inherit from Test. virtual ~Test(); // Sets up the stuff shared by all tests in this test case. // // Google Test will call Foo::SetUpTestSuite() before running the first // test in test case Foo. Hence a sub-class can define its own // SetUpTestSuite() method to shadow the one defined in the super // class. // Failures that happen during SetUpTestSuite are logged but otherwise // ignored. static void SetUpTestSuite() {} // Tears down the stuff shared by all tests in this test suite. // // Google Test will call Foo::TearDownTestSuite() after running the last // test in test case Foo. Hence a sub-class can define its own // TearDownTestSuite() method to shadow the one defined in the super // class. // Failures that happen during TearDownTestSuite are logged but otherwise // ignored. static void TearDownTestSuite() {} // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ static void TearDownTestCase() {} static void SetUpTestCase() {} #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Returns true if and only if the current test has a fatal failure. static bool HasFatalFailure(); // Returns true if and only if the current test has a non-fatal failure. static bool HasNonfatalFailure(); // Returns true if and only if the current test was skipped. static bool IsSkipped(); // Returns true if and only if the current test has a (either fatal or // non-fatal) failure. static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } // Logs a property for the current test, test suite, or for the entire // invocation of the test program when used outside of the context of a // test suite. Only the last value for a given key is remembered. These // are public static so they can be called from utility functions that are // not members of the test fixture. Calls to RecordProperty made during // lifespan of the test (from the moment its constructor starts to the // moment its destructor finishes) will be output in XML as attributes of // the element. Properties recorded from fixture's // SetUpTestSuite or TearDownTestSuite are logged as attributes of the // corresponding element. Calls to RecordProperty made in the // global context (before or after invocation of RUN_ALL_TESTS and from // SetUp/TearDown method of Environment objects registered with Google // Test) will be output as attributes of the element. static void RecordProperty(const std::string& key, const std::string& value); static void RecordProperty(const std::string& key, int value); protected: // Creates a Test object. Test(); // Sets up the test fixture. virtual void SetUp(); // Tears down the test fixture. virtual void TearDown(); private: // Returns true if and only if the current test has the same fixture class // as the first test in the current test suite. static bool HasSameFixtureClass(); // Runs the test after the test fixture has been set up. // // A sub-class must implement this to define the test logic. // // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. // Instead, use the TEST or TEST_F macro. virtual void TestBody() = 0; // Sets up, executes, and tears down the test. void Run(); // Deletes self. We deliberately pick an unusual name for this // internal method to avoid clashing with names used in user TESTs. void DeleteSelf_() { delete this; } const std::unique_ptr gtest_flag_saver_; // Often a user misspells SetUp() as Setup() and spends a long time // wondering why it is never called by Google Test. The declaration of // the following method is solely for catching such an error at // compile time: // // - The return type is deliberately chosen to be not void, so it // will be a conflict if void Setup() is declared in the user's // test fixture. // // - This method is private, so it will be another compiler error // if the method is called from the user's test fixture. // // DO NOT OVERRIDE THIS FUNCTION. // // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; } // We disallow copying Tests. GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); }; typedef internal::TimeInMillis TimeInMillis; // A copyable object representing a user specified test property which can be // output as a key/value string pair. // // Don't inherit from TestProperty as its destructor is not virtual. class TestProperty { public: // C'tor. TestProperty does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestProperty object. TestProperty(const std::string& a_key, const std::string& a_value) : key_(a_key), value_(a_value) { } // Gets the user supplied key. const char* key() const { return key_.c_str(); } // Gets the user supplied value. const char* value() const { return value_.c_str(); } // Sets a new value, overriding the one supplied in the constructor. void SetValue(const std::string& new_value) { value_ = new_value; } private: // The key supplied by the user. std::string key_; // The value supplied by the user. std::string value_; }; // The result of a single Test. This includes a list of // TestPartResults, a list of TestProperties, a count of how many // death tests there are in the Test, and how much time it took to run // the Test. // // TestResult is not copyable. class GTEST_API_ TestResult { public: // Creates an empty TestResult. TestResult(); // D'tor. Do not inherit from TestResult. ~TestResult(); // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int total_part_count() const; // Returns the number of the test properties. int test_property_count() const; // Returns true if and only if the test passed (i.e. no test part failed). bool Passed() const { return !Skipped() && !Failed(); } // Returns true if and only if the test was skipped. bool Skipped() const; // Returns true if and only if the test failed. bool Failed() const; // Returns true if and only if the test fatally failed. bool HasFatalFailure() const; // Returns true if and only if the test has a non-fatal failure. bool HasNonfatalFailure() const; // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Gets the time of the test case start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp() const { return start_timestamp_; } // Returns the i-th test part result among all the results. i can range from 0 // to total_part_count() - 1. If i is not in that range, aborts the program. const TestPartResult& GetTestPartResult(int i) const; // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& GetTestProperty(int i) const; private: friend class TestInfo; friend class TestSuite; friend class UnitTest; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::ExecDeathTest; friend class internal::TestResultAccessor; friend class internal::UnitTestImpl; friend class internal::WindowsDeathTest; friend class internal::FuchsiaDeathTest; // Gets the vector of TestPartResults. const std::vector& test_part_results() const { return test_part_results_; } // Gets the vector of TestProperties. const std::vector& test_properties() const { return test_properties_; } // Sets the start time. void set_start_timestamp(TimeInMillis start) { start_timestamp_ = start; } // Sets the elapsed time. void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } // Adds a test property to the list. The property is validated and may add // a non-fatal failure if invalid (e.g., if it conflicts with reserved // key names). If a property is already recorded for the same key, the // value will be updated, rather than storing multiple values for the same // key. xml_element specifies the element for which the property is being // recorded and is used for validation. void RecordProperty(const std::string& xml_element, const TestProperty& test_property); // Adds a failure if the key is a reserved attribute of Google Test // testsuite tags. Returns true if the property is valid. // FIXME: Validate attribute names are legal and human readable. static bool ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property); // Adds a test part result to the list. void AddTestPartResult(const TestPartResult& test_part_result); // Returns the death test count. int death_test_count() const { return death_test_count_; } // Increments the death test count, returning the new count. int increment_death_test_count() { return ++death_test_count_; } // Clears the test part results. void ClearTestPartResults(); // Clears the object. void Clear(); // Protects mutable state of the property vector and of owned // properties, whose values may be updated. internal::Mutex test_properites_mutex_; // The vector of TestPartResults std::vector test_part_results_; // The vector of TestProperties std::vector test_properties_; // Running count of death tests. int death_test_count_; // The start time, in milliseconds since UNIX Epoch. TimeInMillis start_timestamp_; // The elapsed time, in milliseconds. TimeInMillis elapsed_time_; // We disallow copying TestResult. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); }; // class TestResult // A TestInfo object stores the following information about a test: // // Test suite name // Test name // Whether the test should be run // A function pointer that creates the test object when invoked // Test result // // The constructor of TestInfo registers itself with the UnitTest // singleton such that the RUN_ALL_TESTS() macro knows which tests to // run. class GTEST_API_ TestInfo { public: // Destructs a TestInfo object. This function is not virtual, so // don't inherit from TestInfo. ~TestInfo(); // Returns the test suite name. const char* test_suite_name() const { return test_suite_name_.c_str(); } // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ const char* test_case_name() const { return test_suite_name(); } #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Returns the test name. const char* name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a typed // or a type-parameterized test. const char* type_param() const { if (type_param_.get() != nullptr) return type_param_->c_str(); return nullptr; } // Returns the text representation of the value parameter, or NULL if this // is not a value-parameterized test. const char* value_param() const { if (value_param_.get() != nullptr) return value_param_->c_str(); return nullptr; } // Returns the file name where this test is defined. const char* file() const { return location_.file.c_str(); } // Returns the line where this test is defined. int line() const { return location_.line; } // Return true if this test should not be run because it's in another shard. bool is_in_another_shard() const { return is_in_another_shard_; } // Returns true if this test should run, that is if the test is not // disabled (or it is disabled but the also_run_disabled_tests flag has // been specified) and its full name matches the user-specified filter. // // Google Test allows the user to filter the tests by their full names. // The full name of a test Bar in test suite Foo is defined as // "Foo.Bar". Only the tests that match the filter will run. // // A filter is a colon-separated list of glob (not regex) patterns, // optionally followed by a '-' and a colon-separated list of // negative patterns (tests to exclude). A test is run if it // matches one of the positive patterns and does not match any of // the negative patterns. // // For example, *A*:Foo.* is a filter that matches any string that // contains the character 'A' or starts with "Foo.". bool should_run() const { return should_run_; } // Returns true if and only if this test will appear in the XML report. bool is_reportable() const { // The XML report includes tests matching the filter, excluding those // run in other shards. return matches_filter_ && !is_in_another_shard_; } // Returns the result of the test. const TestResult* result() const { return &result_; } private: #if GTEST_HAS_DEATH_TEST friend class internal::DefaultDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST friend class Test; friend class TestSuite; friend class internal::UnitTestImpl; friend class internal::StreamingListenerTest; friend TestInfo* internal::MakeAndRegisterTestInfo( const char* test_suite_name, const char* name, const char* type_param, const char* value_param, internal::CodeLocation code_location, internal::TypeId fixture_class_id, internal::SetUpTestSuiteFunc set_up_tc, internal::TearDownTestSuiteFunc tear_down_tc, internal::TestFactoryBase* factory); // Constructs a TestInfo object. The newly constructed instance assumes // ownership of the factory object. TestInfo(const std::string& test_suite_name, const std::string& name, const char* a_type_param, // NULL if not a type-parameterized test const char* a_value_param, // NULL if not a value-parameterized test internal::CodeLocation a_code_location, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory); // Increments the number of death tests encountered in this test so // far. int increment_death_test_count() { return result_.increment_death_test_count(); } // Creates the test object, runs it, records its result, and then // deletes it. void Run(); static void ClearTestResult(TestInfo* test_info) { test_info->result_.Clear(); } // These fields are immutable properties of the test. const std::string test_suite_name_; // test suite name const std::string name_; // Test name // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. const std::unique_ptr type_param_; // Text representation of the value parameter, or NULL if this is not a // value-parameterized test. const std::unique_ptr value_param_; internal::CodeLocation location_; const internal::TypeId fixture_class_id_; // ID of the test fixture class bool should_run_; // True if and only if this test should run bool is_disabled_; // True if and only if this test is disabled bool matches_filter_; // True if this test matches the // user-specified filter. bool is_in_another_shard_; // Will be run in another shard. internal::TestFactoryBase* const factory_; // The factory that creates // the test object // This field is mutable and needs to be reset before running the // test for the second time. TestResult result_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); }; // A test suite, which consists of a vector of TestInfos. // // TestSuite is not copyable. class GTEST_API_ TestSuite { public: // Creates a TestSuite with the given name. // // TestSuite does NOT have a default constructor. Always use this // constructor to create a TestSuite object. // // Arguments: // // name: name of the test suite // a_type_param: the name of the test's type parameter, or NULL if // this is not a type-parameterized test. // set_up_tc: pointer to the function that sets up the test suite // tear_down_tc: pointer to the function that tears down the test suite TestSuite(const char* name, const char* a_type_param, internal::SetUpTestSuiteFunc set_up_tc, internal::TearDownTestSuiteFunc tear_down_tc); // Destructor of TestSuite. virtual ~TestSuite(); // Gets the name of the TestSuite. const char* name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a // type-parameterized test suite. const char* type_param() const { if (type_param_.get() != nullptr) return type_param_->c_str(); return nullptr; } // Returns true if any test in this test suite should run. bool should_run() const { return should_run_; } // Gets the number of successful tests in this test suite. int successful_test_count() const; // Gets the number of skipped tests in this test suite. int skipped_test_count() const; // Gets the number of failed tests in this test suite. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests in this test suite. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; // Get the number of tests in this test suite that should run. int test_to_run_count() const; // Gets the number of all tests in this test suite. int total_test_count() const; // Returns true if and only if the test suite passed. bool Passed() const { return !Failed(); } // Returns true if and only if the test suite failed. bool Failed() const { return failed_test_count() > 0; } // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Gets the time of the test suite start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp() const { return start_timestamp_; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* GetTestInfo(int i) const; // Returns the TestResult that holds test properties recorded during // execution of SetUpTestSuite and TearDownTestSuite. const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } private: friend class Test; friend class internal::UnitTestImpl; // Gets the (mutable) vector of TestInfos in this TestSuite. std::vector& test_info_list() { return test_info_list_; } // Gets the (immutable) vector of TestInfos in this TestSuite. const std::vector& test_info_list() const { return test_info_list_; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. TestInfo* GetMutableTestInfo(int i); // Sets the should_run member. void set_should_run(bool should) { should_run_ = should; } // Adds a TestInfo to this test suite. Will delete the TestInfo upon // destruction of the TestSuite object. void AddTestInfo(TestInfo * test_info); // Clears the results of all tests in this test suite. void ClearResult(); // Clears the results of all tests in the given test suite. static void ClearTestSuiteResult(TestSuite* test_suite) { test_suite->ClearResult(); } // Runs every test in this TestSuite. void Run(); // Runs SetUpTestSuite() for this TestSuite. This wrapper is needed // for catching exceptions thrown from SetUpTestSuite(). void RunSetUpTestSuite() { if (set_up_tc_ != nullptr) { (*set_up_tc_)(); } } // Runs TearDownTestSuite() for this TestSuite. This wrapper is // needed for catching exceptions thrown from TearDownTestSuite(). void RunTearDownTestSuite() { if (tear_down_tc_ != nullptr) { (*tear_down_tc_)(); } } // Returns true if and only if test passed. static bool TestPassed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Passed(); } // Returns true if and only if test skipped. static bool TestSkipped(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Skipped(); } // Returns true if and only if test failed. static bool TestFailed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Failed(); } // Returns true if and only if the test is disabled and will be reported in // the XML report. static bool TestReportableDisabled(const TestInfo* test_info) { return test_info->is_reportable() && test_info->is_disabled_; } // Returns true if and only if test is disabled. static bool TestDisabled(const TestInfo* test_info) { return test_info->is_disabled_; } // Returns true if and only if this test will appear in the XML report. static bool TestReportable(const TestInfo* test_info) { return test_info->is_reportable(); } // Returns true if the given test should run. static bool ShouldRunTest(const TestInfo* test_info) { return test_info->should_run(); } // Shuffles the tests in this test suite. void ShuffleTests(internal::Random* random); // Restores the test order to before the first shuffle. void UnshuffleTests(); // Name of the test suite. std::string name_; // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. const std::unique_ptr type_param_; // The vector of TestInfos in their original order. It owns the // elements in the vector. std::vector test_info_list_; // Provides a level of indirection for the test list to allow easy // shuffling and restoring the test order. The i-th element in this // vector is the index of the i-th test in the shuffled test list. std::vector test_indices_; // Pointer to the function that sets up the test suite. internal::SetUpTestSuiteFunc set_up_tc_; // Pointer to the function that tears down the test suite. internal::TearDownTestSuiteFunc tear_down_tc_; // True if and only if any test in this test suite should run. bool should_run_; // The start time, in milliseconds since UNIX Epoch. TimeInMillis start_timestamp_; // Elapsed time, in milliseconds. TimeInMillis elapsed_time_; // Holds test properties recorded during execution of SetUpTestSuite and // TearDownTestSuite. TestResult ad_hoc_test_result_; // We disallow copying TestSuites. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestSuite); }; // An Environment object is capable of setting up and tearing down an // environment. You should subclass this to define your own // environment(s). // // An Environment object does the set-up and tear-down in virtual // methods SetUp() and TearDown() instead of the constructor and the // destructor, as: // // 1. You cannot safely throw from a destructor. This is a problem // as in some cases Google Test is used where exceptions are enabled, and // we may want to implement ASSERT_* using exceptions where they are // available. // 2. You cannot use ASSERT_* directly in a constructor or // destructor. class Environment { public: // The d'tor is virtual as we need to subclass Environment. virtual ~Environment() {} // Override this to define how to set up the environment. virtual void SetUp() {} // Override this to define how to tear down the environment. virtual void TearDown() {} private: // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; } }; #if GTEST_HAS_EXCEPTIONS // Exception which can be thrown from TestEventListener::OnTestPartResult. class GTEST_API_ AssertionException : public internal::GoogleTestFailureException { public: explicit AssertionException(const TestPartResult& result) : GoogleTestFailureException(result) {} }; #endif // GTEST_HAS_EXCEPTIONS // The interface for tracing execution of tests. The methods are organized in // the order the corresponding events are fired. class TestEventListener { public: virtual ~TestEventListener() {} // Fired before any test activity starts. virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; // Fired before each iteration of tests starts. There may be more than // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration // index, starting from 0. virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration) = 0; // Fired before environment set-up for each iteration of tests starts. virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; // Fired after environment set-up for each iteration of tests ends. virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; // Fired before the test suite starts. virtual void OnTestSuiteStart(const TestSuite& /*test_suite*/) {} // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Fired before the test starts. virtual void OnTestStart(const TestInfo& test_info) = 0; // Fired after a failed assertion or a SUCCEED() invocation. // If you want to throw an exception from this function to skip to the next // TEST, it must be AssertionException defined above, or inherited from it. virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; // Fired after the test ends. virtual void OnTestEnd(const TestInfo& test_info) = 0; // Fired after the test suite ends. virtual void OnTestSuiteEnd(const TestSuite& /*test_suite*/) {} // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Fired before environment tear-down for each iteration of tests starts. virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; // Fired after environment tear-down for each iteration of tests ends. virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; // Fired after each iteration of tests finishes. virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration) = 0; // Fired after all test activities have ended. virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; }; // The convenience class for users who need to override just one or two // methods and are not concerned that a possible change to a signature of // the methods they override will not be caught during the build. For // comments about each method please see the definition of TestEventListener // above. class EmptyTestEventListener : public TestEventListener { public: void OnTestProgramStart(const UnitTest& /*unit_test*/) override {} void OnTestIterationStart(const UnitTest& /*unit_test*/, int /*iteration*/) override {} void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) override {} void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {} void OnTestSuiteStart(const TestSuite& /*test_suite*/) override {} // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void OnTestCaseStart(const TestCase& /*test_case*/) override {} #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void OnTestStart(const TestInfo& /*test_info*/) override {} void OnTestPartResult(const TestPartResult& /*test_part_result*/) override {} void OnTestEnd(const TestInfo& /*test_info*/) override {} void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {} #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void OnTestCaseEnd(const TestCase& /*test_case*/) override {} #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) override {} void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {} void OnTestIterationEnd(const UnitTest& /*unit_test*/, int /*iteration*/) override {} void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {} }; // TestEventListeners lets users add listeners to track events in Google Test. class GTEST_API_ TestEventListeners { public: TestEventListeners(); ~TestEventListeners(); // Appends an event listener to the end of the list. Google Test assumes // the ownership of the listener (i.e. it will delete the listener when // the test program finishes). void Append(TestEventListener* listener); // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. TestEventListener* Release(TestEventListener* listener); // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the caller and makes this // function return NULL the next time. TestEventListener* default_result_printer() const { return default_result_printer_; } // Returns the standard listener responsible for the default XML output // controlled by the --gtest_output=xml flag. Can be removed from the // listeners list by users who want to shut down the default XML output // controlled by this flag and substitute it with custom one. Note that // removing this object from the listener list with Release transfers its // ownership to the caller and makes this function return NULL the next // time. TestEventListener* default_xml_generator() const { return default_xml_generator_; } private: friend class TestSuite; friend class TestInfo; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::NoExecDeathTest; friend class internal::TestEventListenersAccessor; friend class internal::UnitTestImpl; // Returns repeater that broadcasts the TestEventListener events to all // subscribers. TestEventListener* repeater(); // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void SetDefaultResultPrinter(TestEventListener* listener); // Sets the default_xml_generator attribute to the provided listener. The // listener is also added to the listener list and previous // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void SetDefaultXmlGenerator(TestEventListener* listener); // Controls whether events will be forwarded by the repeater to the // listeners in the list. bool EventForwardingEnabled() const; void SuppressEventForwarding(); // The actual list of listeners. internal::TestEventRepeater* repeater_; // Listener responsible for the standard result output. TestEventListener* default_result_printer_; // Listener responsible for the creation of the XML output file. TestEventListener* default_xml_generator_; // We disallow copying TestEventListeners. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); }; // A UnitTest consists of a vector of TestSuites. // // This is a singleton class. The only instance of UnitTest is // created when UnitTest::GetInstance() is first called. This // instance is never deleted. // // UnitTest is not copyable. // // This class is thread-safe as long as the methods are called // according to their specification. class GTEST_API_ UnitTest { public: // Gets the singleton UnitTest object. The first time this method // is called, a UnitTest object is constructed and returned. // Consecutive calls will return the same object. static UnitTest* GetInstance(); // Runs all tests in this UnitTest object and prints the result. // Returns 0 if successful, or 1 otherwise. // // This method can only be called from the main thread. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. int Run() GTEST_MUST_USE_RESULT_; // Returns the working directory when the first TEST() or TEST_F() // was executed. The UnitTest object owns the string. const char* original_working_dir() const; // Returns the TestSuite object for the test that's currently running, // or NULL if no test is running. const TestSuite* current_test_suite() const GTEST_LOCK_EXCLUDED_(mutex_); // Legacy API is still available but deprecated #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ const TestCase* current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_); #endif // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. const TestInfo* current_test_info() const GTEST_LOCK_EXCLUDED_(mutex_); // Returns the random seed used at the start of the current test run. int random_seed() const; // Returns the ParameterizedTestSuiteRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. internal::ParameterizedTestSuiteRegistry& parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_); // Gets the number of successful test suites. int successful_test_suite_count() const; // Gets the number of failed test suites. int failed_test_suite_count() const; // Gets the number of all test suites. int total_test_suite_count() const; // Gets the number of all test suites that contain at least one test // that should run. int test_suite_to_run_count() const; // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ int successful_test_case_count() const; int failed_test_case_count() const; int total_test_case_count() const; int test_case_to_run_count() const; #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Gets the number of successful tests. int successful_test_count() const; // Gets the number of skipped tests. int skipped_test_count() const; // Gets the number of failed tests. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; // Gets the number of all tests. int total_test_count() const; // Gets the number of tests that should run. int test_to_run_count() const; // Gets the time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp() const; // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const; // Returns true if and only if the unit test passed (i.e. all test suites // passed). bool Passed() const; // Returns true if and only if the unit test failed (i.e. some test suite // failed or something outside of all tests failed). bool Failed() const; // Gets the i-th test suite among all the test suites. i can range from 0 to // total_test_suite_count() - 1. If i is not in that range, returns NULL. const TestSuite* GetTestSuite(int i) const; // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ const TestCase* GetTestCase(int i) const; #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Returns the TestResult containing information on test failures and // properties logged outside of individual test suites. const TestResult& ad_hoc_test_result() const; // Returns the list of event listeners that can be used to track events // inside Google Test. TestEventListeners& listeners(); private: // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in // the order they were registered. After all tests in the program // have finished, all global test environments will be torn-down in // the *reverse* order they were registered. // // The UnitTest object takes ownership of the given environment. // // This method can only be called from the main thread. Environment* AddEnvironment(Environment* env); // Adds a TestPartResult to the current TestResult object. All // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) // eventually call this to report their results. The user code // should use the assertion macros instead of calling this directly. void AddTestPartResult(TestPartResult::Type result_type, const char* file_name, int line_number, const std::string& message, const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_); // Adds a TestProperty to the current TestResult object when invoked from // inside a test, to current TestSuite's ad_hoc_test_result_ when invoked // from SetUpTestSuite or TearDownTestSuite, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void RecordProperty(const std::string& key, const std::string& value); // Gets the i-th test suite among all the test suites. i can range from 0 to // total_test_suite_count() - 1. If i is not in that range, returns NULL. TestSuite* GetMutableTestSuite(int i); // Accessors for the implementation object. internal::UnitTestImpl* impl() { return impl_; } const internal::UnitTestImpl* impl() const { return impl_; } // These classes and functions are friends as they need to access private // members of UnitTest. friend class ScopedTrace; friend class Test; friend class internal::AssertHelper; friend class internal::StreamingListenerTest; friend class internal::UnitTestRecordPropertyTestHelper; friend Environment* AddGlobalTestEnvironment(Environment* env); friend internal::UnitTestImpl* internal::GetUnitTestImpl(); friend void internal::ReportFailureInUnknownLocation( TestPartResult::Type result_type, const std::string& message); // Creates an empty UnitTest. UnitTest(); // D'tor virtual ~UnitTest(); // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. void PushGTestTrace(const internal::TraceInfo& trace) GTEST_LOCK_EXCLUDED_(mutex_); // Pops a trace from the per-thread Google Test trace stack. void PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_); // Protects mutable state in *impl_. This is mutable as some const // methods need to lock it too. mutable internal::Mutex mutex_; // Opaque implementation object. This field is never changed once // the object is constructed. We don't mark it as const here, as // doing so will cause a warning in the constructor of UnitTest. // Mutable state in *impl_ is protected by mutex_. internal::UnitTestImpl* impl_; // We disallow copying UnitTest. GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); }; // A convenient wrapper for adding an environment for the test // program. // // You should call this before RUN_ALL_TESTS() is called, probably in // main(). If you use gtest_main, you need to call this before main() // starts for it to take effect. For example, you can define a global // variable like this: // // testing::Environment* const foo_env = // testing::AddGlobalTestEnvironment(new FooEnvironment); // // However, we strongly recommend you to write your own main() and // call AddGlobalTestEnvironment() there, as relying on initialization // of global variables makes the code harder to read and may cause // problems when you register multiple environments from different // translation units and the environments have dependencies among them // (remember that the compiler doesn't guarantee the order in which // global variables from different translation units are initialized). inline Environment* AddGlobalTestEnvironment(Environment* env) { return UnitTest::GetInstance()->AddEnvironment(env); } // Initializes Google Test. This must be called before calling // RUN_ALL_TESTS(). In particular, it parses a command line for the // flags that Google Test recognizes. Whenever a Google Test flag is // seen, it is removed from argv, and *argc is decremented. // // No value is returned. Instead, the Google Test flag variables are // updated. // // Calling the function for the second time has no user-visible effect. GTEST_API_ void InitGoogleTest(int* argc, char** argv); // This overloaded version can be used in Windows programs compiled in // UNICODE mode. GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); // This overloaded version can be used on Arduino/embedded platforms where // there is no argc/argv. GTEST_API_ void InitGoogleTest(); namespace internal { // Separate the error generating code from the code path to reduce the stack // frame size of CmpHelperEQ. This helps reduce the overhead of some sanitizers // when calling EXPECT_* in a tight loop. template AssertionResult CmpHelperEQFailure(const char* lhs_expression, const char* rhs_expression, const T1& lhs, const T2& rhs) { return EqFailure(lhs_expression, rhs_expression, FormatForComparisonFailureMessage(lhs, rhs), FormatForComparisonFailureMessage(rhs, lhs), false); } // This block of code defines operator==/!= // to block lexical scope lookup. // It prevents using invalid operator==/!= defined at namespace scope. struct faketype {}; inline bool operator==(faketype, faketype) { return true; } inline bool operator!=(faketype, faketype) { return false; } // The helper function for {ASSERT|EXPECT}_EQ. template AssertionResult CmpHelperEQ(const char* lhs_expression, const char* rhs_expression, const T1& lhs, const T2& rhs) { if (lhs == rhs) { return AssertionSuccess(); } return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums // can be implicitly cast to BiggestInt. GTEST_API_ AssertionResult CmpHelperEQ(const char* lhs_expression, const char* rhs_expression, BiggestInt lhs, BiggestInt rhs); class EqHelper { public: // This templatized version is for the general case. template < typename T1, typename T2, // Disable this overload for cases where one argument is a pointer // and the other is the null pointer constant. typename std::enable_if::value || !std::is_pointer::value>::type* = nullptr> static AssertionResult Compare(const char* lhs_expression, const char* rhs_expression, const T1& lhs, const T2& rhs) { return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous // enums can be implicitly cast to BiggestInt. // // Even though its body looks the same as the above version, we // cannot merge the two, as it will make anonymous enums unhappy. static AssertionResult Compare(const char* lhs_expression, const char* rhs_expression, BiggestInt lhs, BiggestInt rhs) { return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } template static AssertionResult Compare( const char* lhs_expression, const char* rhs_expression, // Handle cases where '0' is used as a null pointer literal. std::nullptr_t /* lhs */, T* rhs) { // We already know that 'lhs' is a null pointer. return CmpHelperEQ(lhs_expression, rhs_expression, static_cast(nullptr), rhs); } }; // Separate the error generating code from the code path to reduce the stack // frame size of CmpHelperOP. This helps reduce the overhead of some sanitizers // when calling EXPECT_OP in a tight loop. template AssertionResult CmpHelperOpFailure(const char* expr1, const char* expr2, const T1& val1, const T2& val2, const char* op) { return AssertionFailure() << "Expected: (" << expr1 << ") " << op << " (" << expr2 << "), actual: " << FormatForComparisonFailureMessage(val1, val2) << " vs " << FormatForComparisonFailureMessage(val2, val1); } // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste // of similar code. // // For each templatized helper function, we also define an overloaded // version for BiggestInt in order to reduce code bloat and allow // anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled // with gcc 4. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ template \ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ const T1& val1, const T2& val2) {\ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ return CmpHelperOpFailure(expr1, expr2, val1, val2, #op);\ }\ }\ GTEST_API_ AssertionResult CmpHelper##op_name(\ const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // Implements the helper function for {ASSERT|EXPECT}_NE GTEST_IMPL_CMP_HELPER_(NE, !=); // Implements the helper function for {ASSERT|EXPECT}_LE GTEST_IMPL_CMP_HELPER_(LE, <=); // Implements the helper function for {ASSERT|EXPECT}_LT GTEST_IMPL_CMP_HELPER_(LT, <); // Implements the helper function for {ASSERT|EXPECT}_GE GTEST_IMPL_CMP_HELPER_(GE, >=); // Implements the helper function for {ASSERT|EXPECT}_GT GTEST_IMPL_CMP_HELPER_(GT, >); #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // The helper function for {ASSERT|EXPECT}_STRCASEEQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // The helper function for {ASSERT|EXPECT}_STRNE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // The helper function for {ASSERT|EXPECT}_STRCASENE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // Helper function for *_STREQ on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2); // Helper function for *_STRNE on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2); } // namespace internal // IsSubstring() and IsNotSubstring() are intended to be used as the // first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by // themselves. They check whether needle is a substring of haystack // (NULL is considered a substring of itself only), and return an // appropriate error message when they fail. // // The {needle,haystack}_expr arguments are the stringified // expressions that generated the two real arguments. GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack); GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack); GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack); #if GTEST_HAS_STD_WSTRING GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack); #endif // GTEST_HAS_STD_WSTRING namespace internal { // Helper template function for comparing floating-points. // // Template parameter: // // RawType: the raw floating-point type (either float or double) // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression, const char* rhs_expression, RawType lhs_value, RawType rhs_value) { const FloatingPoint lhs(lhs_value), rhs(rhs_value); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } ::std::stringstream lhs_ss; lhs_ss << std::setprecision(std::numeric_limits::digits10 + 2) << lhs_value; ::std::stringstream rhs_ss; rhs_ss << std::setprecision(std::numeric_limits::digits10 + 2) << rhs_value; return EqFailure(lhs_expression, rhs_expression, StringStreamToString(&lhs_ss), StringStreamToString(&rhs_ss), false); } // Helper function for implementing ASSERT_NEAR. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // A class that enables one to stream messages to assertion macros class GTEST_API_ AssertHelper { public: // Constructor. AssertHelper(TestPartResult::Type type, const char* file, int line, const char* message); ~AssertHelper(); // Message assignment is a semantic trick to enable assertion // streaming; see the GTEST_MESSAGE_ macro below. void operator=(const Message& message) const; private: // We put our data in a struct so that the size of the AssertHelper class can // be as small as possible. This is important because gcc is incapable of // re-using stack space even for temporary variables, so every EXPECT_EQ // reserves stack space for another AssertHelper. struct AssertHelperData { AssertHelperData(TestPartResult::Type t, const char* srcfile, int line_num, const char* msg) : type(t), file(srcfile), line(line_num), message(msg) { } TestPartResult::Type const type; const char* const file; int const line; std::string const message; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); }; AssertHelperData* const data_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); }; enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; GTEST_API_ GTEST_ATTRIBUTE_PRINTF_(2, 3) void ColoredPrintf(GTestColor color, const char* fmt, ...); } // namespace internal // The pure interface class that all value-parameterized tests inherit from. // A value-parameterized class must inherit from both ::testing::Test and // ::testing::WithParamInterface. In most cases that just means inheriting // from ::testing::TestWithParam, but more complicated test hierarchies // may need to inherit from Test and WithParamInterface at different levels. // // This interface has support for accessing the test parameter value via // the GetParam() method. // // Use it with one of the parameter generator defining functions, like Range(), // Values(), ValuesIn(), Bool(), and Combine(). // // class FooTest : public ::testing::TestWithParam { // protected: // FooTest() { // // Can use GetParam() here. // } // ~FooTest() override { // // Can use GetParam() here. // } // void SetUp() override { // // Can use GetParam() here. // } // void TearDown override { // // Can use GetParam() here. // } // }; // TEST_P(FooTest, DoesBar) { // // Can use GetParam() method here. // Foo foo; // ASSERT_TRUE(foo.DoesBar(GetParam())); // } // INSTANTIATE_TEST_SUITE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); template class WithParamInterface { public: typedef T ParamType; virtual ~WithParamInterface() {} // The current parameter value. Is also available in the test fixture's // constructor. static const ParamType& GetParam() { GTEST_CHECK_(parameter_ != nullptr) << "GetParam() can only be called inside a value-parameterized test " << "-- did you intend to write TEST_P instead of TEST_F?"; return *parameter_; } private: // Sets parameter value. The caller is responsible for making sure the value // remains alive and unchanged throughout the current test. static void SetParam(const ParamType* parameter) { parameter_ = parameter; } // Static value used for accessing parameter during a test lifetime. static const ParamType* parameter_; // TestClass must be a subclass of WithParamInterface and Test. template friend class internal::ParameterizedTestFactory; }; template const T* WithParamInterface::parameter_ = nullptr; // Most value-parameterized classes can ignore the existence of // WithParamInterface, and can just inherit from ::testing::TestWithParam. template class TestWithParam : public Test, public WithParamInterface { }; // Macros for indicating success/failure in test code. // Skips test in runtime. // Skipping test aborts current function. // Skipped tests are neither successful nor failed. #define GTEST_SKIP() GTEST_SKIP_("") // ADD_FAILURE unconditionally adds a failure to the current test. // SUCCEED generates a success - it doesn't automatically make the // current test successful, as a test is only successful when it has // no failure. // // EXPECT_* verifies that a certain condition is satisfied. If not, // it behaves like ADD_FAILURE. In particular: // // EXPECT_TRUE verifies that a Boolean condition is true. // EXPECT_FALSE verifies that a Boolean condition is false. // // FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except // that they will also abort the current function on failure. People // usually want the fail-fast behavior of FAIL and ASSERT_*, but those // writing data-driven tests often find themselves using ADD_FAILURE // and EXPECT_* more. // Generates a nonfatal failure with a generic message. #define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") // Generates a nonfatal failure at the given source file location with // a generic message. #define ADD_FAILURE_AT(file, line) \ GTEST_MESSAGE_AT_(file, line, "Failed", \ ::testing::TestPartResult::kNonFatalFailure) // Generates a fatal failure with a generic message. #define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") // Like GTEST_FAIL(), but at the given source file location. #define GTEST_FAIL_AT(file, line) \ GTEST_MESSAGE_AT_(file, line, "Failed", \ ::testing::TestPartResult::kFatalFailure) // Define this macro to 1 to omit the definition of FAIL(), which is a // generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_FAIL # define FAIL() GTEST_FAIL() #endif // Generates a success with a generic message. #define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") // Define this macro to 1 to omit the definition of SUCCEED(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_SUCCEED # define SUCCEED() GTEST_SUCCEED() #endif // Macros for testing exceptions. // // * {ASSERT|EXPECT}_THROW(statement, expected_exception): // Tests that the statement throws the expected exception. // * {ASSERT|EXPECT}_NO_THROW(statement): // Tests that the statement doesn't throw any exception. // * {ASSERT|EXPECT}_ANY_THROW(statement): // Tests that the statement throws an exception. #define EXPECT_THROW(statement, expected_exception) \ GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) #define EXPECT_NO_THROW(statement) \ GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) #define EXPECT_ANY_THROW(statement) \ GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) #define ASSERT_THROW(statement, expected_exception) \ GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) #define ASSERT_NO_THROW(statement) \ GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) #define ASSERT_ANY_THROW(statement) \ GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) // Boolean assertions. Condition can be either a Boolean expression or an // AssertionResult. For more information on how to use AssertionResult with // these macros see comments on that class. #define EXPECT_TRUE(condition) \ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_NONFATAL_FAILURE_) #define EXPECT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_NONFATAL_FAILURE_) #define ASSERT_TRUE(condition) \ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_FATAL_FAILURE_) #define ASSERT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_FATAL_FAILURE_) // Macros for testing equalities and inequalities. // // * {ASSERT|EXPECT}_EQ(v1, v2): Tests that v1 == v2 // * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 // * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 // * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 // * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 // * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 // // When they are not, Google Test prints both the tested expressions and // their actual values. The values must be compatible built-in types, // or you will get a compiler error. By "compatible" we mean that the // values can be compared by the respective operator. // // Note: // // 1. It is possible to make a user-defined type work with // {ASSERT|EXPECT}_??(), but that requires overloading the // comparison operators and is thus discouraged by the Google C++ // Usage Guide. Therefore, you are advised to use the // {ASSERT|EXPECT}_TRUE() macro to assert that two objects are // equal. // // 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on // pointers (in particular, C strings). Therefore, if you use it // with two C strings, you are testing how their locations in memory // are related, not how their content is related. To compare two C // strings by content, use {ASSERT|EXPECT}_STR*(). // // 3. {ASSERT|EXPECT}_EQ(v1, v2) is preferred to // {ASSERT|EXPECT}_TRUE(v1 == v2), as the former tells you // what the actual value is when it fails, and similarly for the // other comparisons. // // 4. Do not depend on the order in which {ASSERT|EXPECT}_??() // evaluate their arguments, which is undefined. // // 5. These macros evaluate their arguments exactly once. // // Examples: // // EXPECT_NE(Foo(), 5); // EXPECT_EQ(a_pointer, NULL); // ASSERT_LT(i, array_size); // ASSERT_GT(records.size(), 0) << "There is no record left."; #define EXPECT_EQ(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2) #define EXPECT_NE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define EXPECT_LE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define EXPECT_LT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) #define EXPECT_GE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) #define EXPECT_GT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) #define GTEST_ASSERT_EQ(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2) #define GTEST_ASSERT_NE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define GTEST_ASSERT_LE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define GTEST_ASSERT_LT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) #define GTEST_ASSERT_GE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) #define GTEST_ASSERT_GT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) // Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of // ASSERT_XY(), which clashes with some users' own code. #if !GTEST_DONT_DEFINE_ASSERT_EQ # define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_NE # define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_LE # define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_LT # define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_GE # define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_GT # define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) #endif // C-string Comparisons. All tests treat NULL and any non-NULL string // as different. Two NULLs are equal. // // * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 // * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 // * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case // * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case // // For wide or narrow string objects, you can use the // {ASSERT|EXPECT}_??() macros. // // Don't depend on the order in which the arguments are evaluated, // which is undefined. // // These macros evaluate their arguments exactly once. #define EXPECT_STREQ(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2) #define EXPECT_STRNE(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define EXPECT_STRCASEEQ(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) #define EXPECT_STRCASENE(s1, s2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) #define ASSERT_STREQ(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2) #define ASSERT_STRNE(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define ASSERT_STRCASEEQ(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) #define ASSERT_STRCASENE(s1, s2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) // Macros for comparing floating-point numbers. // // * {ASSERT|EXPECT}_FLOAT_EQ(val1, val2): // Tests that two float values are almost equal. // * {ASSERT|EXPECT}_DOUBLE_EQ(val1, val2): // Tests that two double values are almost equal. // * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): // Tests that v1 and v2 are within the given distance to each other. // // Google Test uses ULP-based comparison to automatically pick a default // error bound that is appropriate for the operands. See the // FloatingPoint template class in gtest-internal.h if you are // interested in the implementation details. #define EXPECT_FLOAT_EQ(val1, val2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ val1, val2) #define EXPECT_DOUBLE_EQ(val1, val2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ val1, val2) #define ASSERT_FLOAT_EQ(val1, val2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ val1, val2) #define ASSERT_DOUBLE_EQ(val1, val2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ val1, val2) #define EXPECT_NEAR(val1, val2, abs_error)\ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ val1, val2, abs_error) #define ASSERT_NEAR(val1, val2, abs_error)\ ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ val1, val2, abs_error) // These predicate format functions work on floating-point values, and // can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. // // EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, float val1, float val2); GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, double val1, double val2); #if GTEST_OS_WINDOWS // Macros that test for HRESULT failure and success, these are only useful // on Windows, and rely on Windows SDK macros and APIs to compile. // // * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) // // When expr unexpectedly fails or succeeds, Google Test prints the // expected result and the actual result with both a human-readable // string representation of the error, if available, as well as the // hex result code. # define EXPECT_HRESULT_SUCCEEDED(expr) \ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) # define ASSERT_HRESULT_SUCCEEDED(expr) \ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) # define EXPECT_HRESULT_FAILED(expr) \ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) # define ASSERT_HRESULT_FAILED(expr) \ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) #endif // GTEST_OS_WINDOWS // Macros that execute statement and check that it doesn't generate new fatal // failures in the current thread. // // * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); // // Examples: // // EXPECT_NO_FATAL_FAILURE(Process()); // ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; // #define ASSERT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) #define EXPECT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) // Causes a trace (including the given source file path and line number, // and the given message) to be included in every test failure message generated // by code in the scope of the lifetime of an instance of this class. The effect // is undone with the destruction of the instance. // // The message argument can be anything streamable to std::ostream. // // Example: // testing::ScopedTrace trace("file.cc", 123, "message"); // class GTEST_API_ ScopedTrace { public: // The c'tor pushes the given source file location and message onto // a trace stack maintained by Google Test. // Template version. Uses Message() to convert the values into strings. // Slow, but flexible. template ScopedTrace(const char* file, int line, const T& message) { PushTrace(file, line, (Message() << message).GetString()); } // Optimize for some known types. ScopedTrace(const char* file, int line, const char* message) { PushTrace(file, line, message ? message : "(null)"); } ScopedTrace(const char* file, int line, const std::string& message) { PushTrace(file, line, message); } // The d'tor pops the info pushed by the c'tor. // // Note that the d'tor is not virtual in order to be efficient. // Don't inherit from ScopedTrace! ~ScopedTrace(); private: void PushTrace(const char* file, int line, std::string message); GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); } GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its // c'tor and d'tor. Therefore it doesn't // need to be used otherwise. // Causes a trace (including the source file path, the current line // number, and the given message) to be included in every test failure // message generated by code in the current scope. The effect is // undone when the control leaves the current scope. // // The message argument can be anything streamable to std::ostream. // // In the implementation, we include the current line number as part // of the dummy variable name, thus allowing multiple SCOPED_TRACE()s // to appear in the same block - as long as they are on different // lines. // // Assuming that each thread maintains its own stack of traces. // Therefore, a SCOPED_TRACE() would (correctly) only affect the // assertions in its own thread. #define SCOPED_TRACE(message) \ ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ __FILE__, __LINE__, (message)) // Compile-time assertion for type equality. // StaticAssertTypeEq() compiles if and only if type1 and type2 // are the same type. The value it returns is not interesting. // // Instead of making StaticAssertTypeEq a class template, we make it a // function template that invokes a helper class template. This // prevents a user from misusing StaticAssertTypeEq by // defining objects of that type. // // CAVEAT: // // When used inside a method of a class template, // StaticAssertTypeEq() is effective ONLY IF the method is // instantiated. For example, given: // // template class Foo { // public: // void Bar() { testing::StaticAssertTypeEq(); } // }; // // the code: // // void Test1() { Foo foo; } // // will NOT generate a compiler error, as Foo::Bar() is never // actually instantiated. Instead, you need: // // void Test2() { Foo foo; foo.Bar(); } // // to cause a compiler error. template constexpr bool StaticAssertTypeEq() noexcept { static_assert(std::is_same::value, "T1 and T2 are not the same type"); return true; } // Defines a test. // // The first parameter is the name of the test suite, and the second // parameter is the name of the test within the test suite. // // The convention is to end the test suite name with "Test". For // example, a test suite for the Foo class can be named FooTest. // // Test code should appear between braces after an invocation of // this macro. Example: // // TEST(FooTest, InitializesCorrectly) { // Foo foo; // EXPECT_TRUE(foo.StatusIsOK()); // } // Note that we call GetTestTypeId() instead of GetTypeId< // ::testing::Test>() here to get the type ID of testing::Test. This // is to work around a suspected linker bug when using Google Test as // a framework on Mac OS X. The bug causes GetTypeId< // ::testing::Test>() to return different values depending on whether // the call is from the Google Test framework itself or from user test // code. GetTestTypeId() is guaranteed to always return the same // value, as it always calls GetTypeId<>() from the Google Test // framework. #define GTEST_TEST(test_suite_name, test_name) \ GTEST_TEST_(test_suite_name, test_name, ::testing::Test, \ ::testing::internal::GetTestTypeId()) // Define this macro to 1 to omit the definition of TEST(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_TEST #define TEST(test_suite_name, test_name) GTEST_TEST(test_suite_name, test_name) #endif // Defines a test that uses a test fixture. // // The first parameter is the name of the test fixture class, which // also doubles as the test suite name. The second parameter is the // name of the test within the test suite. // // A test fixture class must be declared earlier. The user should put // the test code between braces after using this macro. Example: // // class FooTest : public testing::Test { // protected: // void SetUp() override { b_.AddElement(3); } // // Foo a_; // Foo b_; // }; // // TEST_F(FooTest, InitializesCorrectly) { // EXPECT_TRUE(a_.StatusIsOK()); // } // // TEST_F(FooTest, ReturnsElementCountCorrectly) { // EXPECT_EQ(a_.size(), 0); // EXPECT_EQ(b_.size(), 1); // } // // GOOGLETEST_CM0011 DO NOT DELETE #define TEST_F(test_fixture, test_name)\ GTEST_TEST_(test_fixture, test_name, test_fixture, \ ::testing::internal::GetTypeId()) // Returns a path to temporary directory. // Tries to determine an appropriate directory for the platform. GTEST_API_ std::string TempDir(); #ifdef _MSC_VER # pragma warning(pop) #endif // Dynamically registers a test with the framework. // // This is an advanced API only to be used when the `TEST` macros are // insufficient. The macros should be preferred when possible, as they avoid // most of the complexity of calling this function. // // The `factory` argument is a factory callable (move-constructible) object or // function pointer that creates a new instance of the Test object. It // handles ownership to the caller. The signature of the callable is // `Fixture*()`, where `Fixture` is the test fixture class for the test. All // tests registered with the same `test_suite_name` must return the same // fixture type. This is checked at runtime. // // The framework will infer the fixture class from the factory and will call // the `SetUpTestSuite` and `TearDownTestSuite` for it. // // Must be called before `RUN_ALL_TESTS()` is invoked, otherwise behavior is // undefined. // // Use case example: // // class MyFixture : public ::testing::Test { // public: // // All of these optional, just like in regular macro usage. // static void SetUpTestSuite() { ... } // static void TearDownTestSuite() { ... } // void SetUp() override { ... } // void TearDown() override { ... } // }; // // class MyTest : public MyFixture { // public: // explicit MyTest(int data) : data_(data) {} // void TestBody() override { ... } // // private: // int data_; // }; // // void RegisterMyTests(const std::vector& values) { // for (int v : values) { // ::testing::RegisterTest( // "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr, // std::to_string(v).c_str(), // __FILE__, __LINE__, // // Important to use the fixture type as the return type here. // [=]() -> MyFixture* { return new MyTest(v); }); // } // } // ... // int main(int argc, char** argv) { // std::vector values_to_test = LoadValuesFromConfig(); // RegisterMyTests(values_to_test); // ... // return RUN_ALL_TESTS(); // } // template TestInfo* RegisterTest(const char* test_suite_name, const char* test_name, const char* type_param, const char* value_param, const char* file, int line, Factory factory) { using TestT = typename std::remove_pointer::type; class FactoryImpl : public internal::TestFactoryBase { public: explicit FactoryImpl(Factory f) : factory_(std::move(f)) {} Test* CreateTest() override { return factory_(); } private: Factory factory_; }; return internal::MakeAndRegisterTestInfo( test_suite_name, test_name, type_param, value_param, internal::CodeLocation(file, line), internal::GetTypeId(), internal::SuiteApiResolver::GetSetUpCaseOrSuite(file, line), internal::SuiteApiResolver::GetTearDownCaseOrSuite(file, line), new FactoryImpl{std::move(factory)}); } } // namespace testing // Use this function in main() to run all tests. It returns 0 if all // tests are successful, or 1 otherwise. // // RUN_ALL_TESTS() should be invoked after the command line has been // parsed by InitGoogleTest(). // // This function was formerly a macro; thus, it is in the global // namespace and has an all-caps name. int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_; inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); } GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 #endif // GTEST_INCLUDE_GTEST_GTEST_H_ openzwave-1.6.1914/cpp/test/include/gtest/gtest-message.h0000644000175200017520000001753614032142455020167 00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the Message class. // // IMPORTANT NOTE: Due to limitation of the C++ language, we have to // leave some internal implementation details in this header file. // They are clearly marked by comments like this: // // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // // Such code is NOT meant to be used by a user directly, and is subject // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #include #include #include #include "gtest/internal/gtest-port.h" GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) // Ensures that there is at least one operator<< in the global namespace. // See Message& operator<<(...) below for why. void operator<<(const testing::internal::Secret&, int); namespace testing { // The Message class works like an ostream repeater. // // Typical usage: // // 1. You stream a bunch of values to a Message object. // It will remember the text in a stringstream. // 2. Then you stream the Message object to an ostream. // This causes the text in the Message to be streamed // to the ostream. // // For example; // // testing::Message foo; // foo << 1 << " != " << 2; // std::cout << foo; // // will print "1 != 2". // // Message is not intended to be inherited from. In particular, its // destructor is not virtual. // // Note that stringstream behaves differently in gcc and in MSVC. You // can stream a NULL char pointer to it in the former, but not in the // latter (it causes an access violation if you do). The Message // class hides this difference by treating a NULL char pointer as // "(null)". class GTEST_API_ Message { private: // The type of basic IO manipulators (endl, ends, and flush) for // narrow streams. typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); public: // Constructs an empty Message. Message(); // Copy constructor. Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT *ss_ << msg.GetString(); } // Constructs a Message from a C-string. explicit Message(const char* str) : ss_(new ::std::stringstream) { *ss_ << str; } // Streams a non-pointer value to this object. template inline Message& operator <<(const T& val) { // Some libraries overload << for STL containers. These // overloads are defined in the global namespace instead of ::std. // // C++'s symbol lookup rule (i.e. Koenig lookup) says that these // overloads are visible in either the std namespace or the global // namespace, but not other namespaces, including the testing // namespace which Google Test's Message class is in. // // To allow STL containers (and other types that has a << operator // defined in the global namespace) to be used in Google Test // assertions, testing::Message must access the custom << operator // from the global namespace. With this using declaration, // overloads of << defined in the global namespace and those // visible via Koenig lookup are both exposed in this function. using ::operator <<; *ss_ << val; return *this; } // Streams a pointer value to this object. // // This function is an overload of the previous one. When you // stream a pointer to a Message, this definition will be used as it // is more specialized. (The C++ Standard, section // [temp.func.order].) If you stream a non-pointer, then the // previous definition will be used. // // The reason for this overload is that streaming a NULL pointer to // ostream is undefined behavior. Depending on the compiler, you // may get "0", "(nil)", "(null)", or an access violation. To // ensure consistent result across compilers, we always treat NULL // as "(null)". template inline Message& operator <<(T* const& pointer) { // NOLINT if (pointer == nullptr) { *ss_ << "(null)"; } else { *ss_ << pointer; } return *this; } // Since the basic IO manipulators are overloaded for both narrow // and wide streams, we have to provide this specialized definition // of operator <<, even though its body is the same as the // templatized version above. Without this definition, streaming // endl or other basic IO manipulators to Message will confuse the // compiler. Message& operator <<(BasicNarrowIoManip val) { *ss_ << val; return *this; } // Instead of 1/0, we want to see true/false for bool values. Message& operator <<(bool b) { return *this << (b ? "true" : "false"); } // These two overloads allow streaming a wide C string to a Message // using the UTF-8 encoding. Message& operator <<(const wchar_t* wide_c_str); Message& operator <<(wchar_t* wide_c_str); #if GTEST_HAS_STD_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& operator <<(const ::std::wstring& wstr); #endif // GTEST_HAS_STD_WSTRING // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. std::string GetString() const; private: // We'll hold the text streamed to this object here. const std::unique_ptr< ::std::stringstream> ss_; // We declare (but don't implement) this to prevent the compiler // from implementing the assignment operator. void operator=(const Message&); }; // Streams a Message to an ostream. inline std::ostream& operator <<(std::ostream& os, const Message& sb) { return os << sb.GetString(); } namespace internal { // Converts a streamable value to an std::string. A NULL pointer is // converted to "(null)". When the input value is a ::string, // ::std::string, ::wstring, or ::std::wstring object, each NUL // character in it is replaced with "\\0". template std::string StreamableToString(const T& streamable) { return (Message() << streamable).GetString(); } } // namespace internal } // namespace testing GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 #endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ openzwave-1.6.1914/cpp/test/include/gtest/gtest-death-test.h0000644000175200017520000003403714032142455020600 00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the public API for death tests. It is // #included by gtest.h so a user doesn't need to include this // directly. // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ #include "gtest/internal/gtest-death-test-internal.h" namespace testing { // This flag controls the style of death tests. Valid values are "threadsafe", // meaning that the death test child process will re-execute the test binary // from the start, running only a single death test, or "fast", // meaning that the child process will execute the test logic immediately // after forking. GTEST_DECLARE_string_(death_test_style); #if GTEST_HAS_DEATH_TEST namespace internal { // Returns a Boolean value indicating whether the caller is currently // executing in the context of the death test child process. Tools such as // Valgrind heap checkers may need this to modify their behavior in death // tests. IMPORTANT: This is an internal utility. Using it may break the // implementation of death tests. User code MUST NOT use it. GTEST_API_ bool InDeathTestChild(); } // namespace internal // The following macros are useful for writing death tests. // Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is // executed: // // 1. It generates a warning if there is more than one active // thread. This is because it's safe to fork() or clone() only // when there is a single thread. // // 2. The parent process clone()s a sub-process and runs the death // test in it; the sub-process exits with code 0 at the end of the // death test, if it hasn't exited already. // // 3. The parent process waits for the sub-process to terminate. // // 4. The parent process checks the exit code and error message of // the sub-process. // // Examples: // // ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); // for (int i = 0; i < 5; i++) { // EXPECT_DEATH(server.ProcessRequest(i), // "Invalid request .* in ProcessRequest()") // << "Failed to die on request " << i; // } // // ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); // // bool KilledBySIGHUP(int exit_code) { // return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; // } // // ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); // // On the regular expressions used in death tests: // // GOOGLETEST_CM0005 DO NOT DELETE // On POSIX-compliant systems (*nix), we use the library, // which uses the POSIX extended regex syntax. // // On other platforms (e.g. Windows or Mac), we only support a simple regex // syntax implemented as part of Google Test. This limited // implementation should be enough most of the time when writing // death tests; though it lacks many features you can find in PCRE // or POSIX extended regex syntax. For example, we don't support // union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and // repetition count ("x{5,7}"), among others. // // Below is the syntax that we do support. We chose it to be a // subset of both PCRE and POSIX extended regex, so it's easy to // learn wherever you come from. In the following: 'A' denotes a // literal character, period (.), or a single \\ escape sequence; // 'x' and 'y' denote regular expressions; 'm' and 'n' are for // natural numbers. // // c matches any literal character c // \\d matches any decimal digit // \\D matches any character that's not a decimal digit // \\f matches \f // \\n matches \n // \\r matches \r // \\s matches any ASCII whitespace, including \n // \\S matches any character that's not a whitespace // \\t matches \t // \\v matches \v // \\w matches any letter, _, or decimal digit // \\W matches any character that \\w doesn't match // \\c matches any literal character c, which must be a punctuation // . matches any single character except \n // A? matches 0 or 1 occurrences of A // A* matches 0 or many occurrences of A // A+ matches 1 or many occurrences of A // ^ matches the beginning of a string (not that of each line) // $ matches the end of a string (not that of each line) // xy matches x followed by y // // If you accidentally use PCRE or POSIX extended regex features // not implemented by us, you will get a run-time failure. In that // case, please try to rewrite your regular expression within the // above syntax. // // This implementation is *not* meant to be as highly tuned or robust // as a compiled regex library, but should perform well enough for a // death test, which already incurs significant overhead by launching // a child process. // // Known caveats: // // A "threadsafe" style death test obtains the path to the test // program from argv[0] and re-executes it in the sub-process. For // simplicity, the current implementation doesn't search the PATH // when launching the sub-process. This means that the user must // invoke the test program via a path that contains at least one // path separator (e.g. path/to/foo_test and // /absolute/path/to/bar_test are fine, but foo_test is not). This // is rarely a problem as people usually don't put the test binary // directory in PATH. // // Asserts that a given statement causes the program to exit, with an // integer exit status that satisfies predicate, and emitting error output // that matches regex. # define ASSERT_EXIT(statement, predicate, regex) \ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) // Like ASSERT_EXIT, but continues on to successive tests in the // test suite, if any: # define EXPECT_EXIT(statement, predicate, regex) \ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) // Asserts that a given statement causes the program to exit, either by // explicitly exiting with a nonzero exit code or being killed by a // signal, and emitting error output that matches regex. # define ASSERT_DEATH(statement, regex) \ ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) // Like ASSERT_DEATH, but continues on to successive tests in the // test suite, if any: # define EXPECT_DEATH(statement, regex) \ EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) // Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: // Tests that an exit code describes a normal exit with a given exit code. class GTEST_API_ ExitedWithCode { public: explicit ExitedWithCode(int exit_code); bool operator()(int exit_status) const; private: // No implementation - assignment is unsupported. void operator=(const ExitedWithCode& other); const int exit_code_; }; # if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Tests that an exit code describes an exit due to termination by a // given signal. // GOOGLETEST_CM0006 DO NOT DELETE class GTEST_API_ KilledBySignal { public: explicit KilledBySignal(int signum); bool operator()(int exit_status) const; private: const int signum_; }; # endif // !GTEST_OS_WINDOWS // EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. // The death testing framework causes this to have interesting semantics, // since the sideeffects of the call are only visible in opt mode, and not // in debug mode. // // In practice, this can be used to test functions that utilize the // LOG(DFATAL) macro using the following style: // // int DieInDebugOr12(int* sideeffect) { // if (sideeffect) { // *sideeffect = 12; // } // LOG(DFATAL) << "death"; // return 12; // } // // TEST(TestSuite, TestDieOr12WorksInDgbAndOpt) { // int sideeffect = 0; // // Only asserts in dbg. // EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); // // #ifdef NDEBUG // // opt-mode has sideeffect visible. // EXPECT_EQ(12, sideeffect); // #else // // dbg-mode no visible sideeffect. // EXPECT_EQ(0, sideeffect); // #endif // } // // This will assert that DieInDebugReturn12InOpt() crashes in debug // mode, usually due to a DCHECK or LOG(DFATAL), but returns the // appropriate fallback value (12 in this case) in opt mode. If you // need to test that a function has appropriate side-effects in opt // mode, include assertions against the side-effects. A general // pattern for this is: // // EXPECT_DEBUG_DEATH({ // // Side-effects here will have an effect after this statement in // // opt mode, but none in debug mode. // EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); // }, "death"); // # ifdef NDEBUG # define EXPECT_DEBUG_DEATH(statement, regex) \ GTEST_EXECUTE_STATEMENT_(statement, regex) # define ASSERT_DEBUG_DEATH(statement, regex) \ GTEST_EXECUTE_STATEMENT_(statement, regex) # else # define EXPECT_DEBUG_DEATH(statement, regex) \ EXPECT_DEATH(statement, regex) # define ASSERT_DEBUG_DEATH(statement, regex) \ ASSERT_DEATH(statement, regex) # endif // NDEBUG for EXPECT_DEBUG_DEATH #endif // GTEST_HAS_DEATH_TEST // This macro is used for implementing macros such as // EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where // death tests are not supported. Those macros must compile on such systems // if and only if EXPECT_DEATH and ASSERT_DEATH compile with the same parameters // on systems that support death tests. This allows one to write such a macro on // a system that does not support death tests and be sure that it will compile // on a death-test supporting system. It is exposed publicly so that systems // that have death-tests with stricter requirements than GTEST_HAS_DEATH_TEST // can write their own equivalent of EXPECT_DEATH_IF_SUPPORTED and // ASSERT_DEATH_IF_SUPPORTED. // // Parameters: // statement - A statement that a macro such as EXPECT_DEATH would test // for program termination. This macro has to make sure this // statement is compiled but not executed, to ensure that // EXPECT_DEATH_IF_SUPPORTED compiles with a certain // parameter if and only if EXPECT_DEATH compiles with it. // regex - A regex that a macro such as EXPECT_DEATH would use to test // the output of statement. This parameter has to be // compiled but not evaluated by this macro, to ensure that // this macro only accepts expressions that a macro such as // EXPECT_DEATH would accept. // terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED // and a return statement for ASSERT_DEATH_IF_SUPPORTED. // This ensures that ASSERT_DEATH_IF_SUPPORTED will not // compile inside functions where ASSERT_DEATH doesn't // compile. // // The branch that has an always false condition is used to ensure that // statement and regex are compiled (and thus syntactically correct) but // never executed. The unreachable code macro protects the terminator // statement from generating an 'unreachable code' warning in case // statement unconditionally returns or throws. The Message constructor at // the end allows the syntax of streaming additional messages into the // macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. # define GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, terminator) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ GTEST_LOG_(WARNING) \ << "Death tests are not supported on this platform.\n" \ << "Statement '" #statement "' cannot be verified."; \ } else if (::testing::internal::AlwaysFalse()) { \ ::testing::internal::RE::PartialMatch(".*", (regex)); \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ terminator; \ } else \ ::testing::Message() // EXPECT_DEATH_IF_SUPPORTED(statement, regex) and // ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if // death tests are supported; otherwise they just issue a warning. This is // useful when you are combining death test assertions with normal test // assertions in one test. #if GTEST_HAS_DEATH_TEST # define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ EXPECT_DEATH(statement, regex) # define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ ASSERT_DEATH(statement, regex) #else # define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, ) # define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, return) #endif } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ openzwave-1.6.1914/cpp/test/include/gtest/internal/0000777000175200017520000000000014032143201017120 500000000000000openzwave-1.6.1914/cpp/test/include/gtest/internal/gtest-type-util.h0000644000175200017520000001355714032142455022312 00000000000000// Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Type utilities needed for implementing typed and type-parameterized // tests. // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #include "gtest/internal/gtest-port.h" // #ifdef __GNUC__ is too general here. It is possible to use gcc without using // libstdc++ (which is where cxxabi.h comes from). # if GTEST_HAS_CXXABI_H_ # include # elif defined(__HP_aCC) # include # endif // GTEST_HASH_CXXABI_H_ namespace testing { namespace internal { // Canonicalizes a given name with respect to the Standard C++ Library. // This handles removing the inline namespace within `std` that is // used by various standard libraries (e.g., `std::__1`). Names outside // of namespace std are returned unmodified. inline std::string CanonicalizeForStdLibVersioning(std::string s) { static const char prefix[] = "std::__"; if (s.compare(0, strlen(prefix), prefix) == 0) { std::string::size_type end = s.find("::", strlen(prefix)); if (end != s.npos) { // Erase everything between the initial `std` and the second `::`. s.erase(strlen("std"), end - strlen("std")); } } return s; } // GetTypeName() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. template std::string GetTypeName() { # if GTEST_HAS_RTTI const char* const name = typeid(T).name(); # if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) int status = 0; // gcc's implementation of typeid(T).name() mangles the type name, // so we have to demangle it. # if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; # endif // GTEST_HAS_CXXABI_H_ char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); return CanonicalizeForStdLibVersioning(name_str); # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC # else return ""; # endif // GTEST_HAS_RTTI } #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // A unique type indicating an empty node struct None {}; # define GTEST_TEMPLATE_ template class // The template "selector" struct TemplateSel is used to // represent Tmpl, which must be a class template with one type // parameter, as a type. TemplateSel::Bind::type is defined // as the type Tmpl. This allows us to actually instantiate the // template "selected" by TemplateSel. // // This trick is necessary for simulating typedef for class templates, // which C++ doesn't support directly. template struct TemplateSel { template struct Bind { typedef Tmpl type; }; }; # define GTEST_BIND_(TmplSel, T) \ TmplSel::template Bind::type template struct Templates { using Head = TemplateSel; using Tail = Templates; }; template struct Templates { using Head = TemplateSel; using Tail = None; }; // Tuple-like type lists template struct Types { using Head = Head_; using Tail = Types; }; template struct Types { using Head = Head_; using Tail = None; }; // Helper metafunctions to tell apart a single type from types // generated by ::testing::Types template struct ProxyTypeList { using type = Types; }; template struct is_proxy_type_list : std::false_type {}; template struct is_proxy_type_list> : std::true_type {}; // Generator which conditionally creates type lists. // It recognizes if a requested type list should be created // and prevents creating a new type list nested within another one. template struct GenerateTypeList { private: using proxy = typename std::conditional::value, T, ProxyTypeList>::type; public: using type = typename proxy::type; }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P } // namespace internal template using Types = internal::ProxyTypeList; } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ openzwave-1.6.1914/cpp/test/include/gtest/internal/custom/0000777000175200017520000000000014032143201020432 500000000000000openzwave-1.6.1914/cpp/test/include/gtest/internal/custom/gtest-printers.h0000644000175200017520000000403714032142455023527 00000000000000// Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // This file provides an injection point for custom printers in a local // installation of gTest. // It will be included from gtest-printers.h and the overrides in this file // will be visible to everyone. // // Injection point for custom user configurations. See README for details // // ** Custom implementation starts here ** #ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ openzwave-1.6.1914/cpp/test/include/gtest/internal/custom/gtest.h0000644000175200017520000000346314032142455021665 00000000000000// Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Injection point for custom user configurations. See README for details // // ** Custom implementation starts here ** #ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ openzwave-1.6.1914/cpp/test/include/gtest/internal/custom/README.md0000644000175200017520000000322214032142455021636 00000000000000# Customization Points The custom directory is an injection point for custom user configurations. ## Header `gtest.h` ### The following macros can be defined: * `GTEST_OS_STACK_TRACE_GETTER_` - The name of an implementation of `OsStackTraceGetterInterface`. * `GTEST_CUSTOM_TEMPDIR_FUNCTION_` - An override for `testing::TempDir()`. See `testing::TempDir` for semantics and signature. ## Header `gtest-port.h` The following macros can be defined: ### Flag related macros: * `GTEST_FLAG(flag_name)` * `GTEST_USE_OWN_FLAGFILE_FLAG_` - Define to 0 when the system provides its own flagfile flag parsing. * `GTEST_DECLARE_bool_(name)` * `GTEST_DECLARE_int32_(name)` * `GTEST_DECLARE_string_(name)` * `GTEST_DEFINE_bool_(name, default_val, doc)` * `GTEST_DEFINE_int32_(name, default_val, doc)` * `GTEST_DEFINE_string_(name, default_val, doc)` ### Logging: * `GTEST_LOG_(severity)` * `GTEST_CHECK_(condition)` * Functions `LogToStderr()` and `FlushInfoLog()` have to be provided too. ### Threading: * `GTEST_HAS_NOTIFICATION_` - Enabled if Notification is already provided. * `GTEST_HAS_MUTEX_AND_THREAD_LOCAL_` - Enabled if `Mutex` and `ThreadLocal` are already provided. Must also provide `GTEST_DECLARE_STATIC_MUTEX_(mutex)` and `GTEST_DEFINE_STATIC_MUTEX_(mutex)` * `GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)` * `GTEST_LOCK_EXCLUDED_(locks)` ### Underlying library support features * `GTEST_HAS_CXXABI_H_` ### Exporting API symbols: * `GTEST_API_` - Specifier for exported symbols. ## Header `gtest-printers.h` * See documentation at `gtest/gtest-printers.h` for details on how to define a custom printer. openzwave-1.6.1914/cpp/test/include/gtest/internal/custom/gtest-port.h0000644000175200017520000000350214032142455022641 00000000000000// Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Injection point for custom user configurations. See README for details // // ** Custom implementation starts here ** #ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ openzwave-1.6.1914/cpp/test/include/gtest/internal/gtest-death-test-internal.h0000644000175200017520000003217414032142455024226 00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines internal utilities needed for implementing // death tests. They are subject to change without notice. // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #include "gtest/gtest-matchers.h" #include "gtest/internal/gtest-internal.h" #include #include namespace testing { namespace internal { GTEST_DECLARE_string_(internal_run_death_test); // Names of the flags (needed for parsing Google Test flags). const char kDeathTestStyleFlag[] = "death_test_style"; const char kDeathTestUseFork[] = "death_test_use_fork"; const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; #if GTEST_HAS_DEATH_TEST GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) // DeathTest is a class that hides much of the complexity of the // GTEST_DEATH_TEST_ macro. It is abstract; its static Create method // returns a concrete class that depends on the prevailing death test // style, as defined by the --gtest_death_test_style and/or // --gtest_internal_run_death_test flags. // In describing the results of death tests, these terms are used with // the corresponding definitions: // // exit status: The integer exit information in the format specified // by wait(2) // exit code: The integer code passed to exit(3), _exit(2), or // returned from main() class GTEST_API_ DeathTest { public: // Create returns false if there was an error determining the // appropriate action to take for the current death test; for example, // if the gtest_death_test_style flag is set to an invalid value. // The LastMessage method will return a more detailed message in that // case. Otherwise, the DeathTest pointer pointed to by the "test" // argument is set. If the death test should be skipped, the pointer // is set to NULL; otherwise, it is set to the address of a new concrete // DeathTest object that controls the execution of the current test. static bool Create(const char* statement, Matcher matcher, const char* file, int line, DeathTest** test); DeathTest(); virtual ~DeathTest() { } // A helper class that aborts a death test when it's deleted. class ReturnSentinel { public: explicit ReturnSentinel(DeathTest* test) : test_(test) { } ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } private: DeathTest* const test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); } GTEST_ATTRIBUTE_UNUSED_; // An enumeration of possible roles that may be taken when a death // test is encountered. EXECUTE means that the death test logic should // be executed immediately. OVERSEE means that the program should prepare // the appropriate environment for a child process to execute the death // test, then wait for it to complete. enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; // An enumeration of the three reasons that a test might be aborted. enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_THREW_EXCEPTION, TEST_DID_NOT_DIE }; // Assumes one of the above roles. virtual TestRole AssumeRole() = 0; // Waits for the death test to finish and returns its status. virtual int Wait() = 0; // Returns true if the death test passed; that is, the test process // exited during the test, its exit status matches a user-supplied // predicate, and its stderr output matches a user-supplied regular // expression. // The user-supplied predicate may be a macro expression rather // than a function pointer or functor, or else Wait and Passed could // be combined. virtual bool Passed(bool exit_status_ok) = 0; // Signals that the death test did not die as expected. virtual void Abort(AbortReason reason) = 0; // Returns a human-readable outcome message regarding the outcome of // the last death test. static const char* LastMessage(); static void set_last_death_test_message(const std::string& message); private: // A string containing a description of the outcome of the last death test. static std::string last_death_test_message_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); }; GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 // Factory interface for death tests. May be mocked out for testing. class DeathTestFactory { public: virtual ~DeathTestFactory() { } virtual bool Create(const char* statement, Matcher matcher, const char* file, int line, DeathTest** test) = 0; }; // A concrete DeathTestFactory implementation for normal use. class DefaultDeathTestFactory : public DeathTestFactory { public: bool Create(const char* statement, Matcher matcher, const char* file, int line, DeathTest** test) override; }; // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. GTEST_API_ bool ExitedUnsuccessfully(int exit_status); // A string passed to EXPECT_DEATH (etc.) is caught by one of these overloads // and interpreted as a regex (rather than an Eq matcher) for legacy // compatibility. inline Matcher MakeDeathTestMatcher( ::testing::internal::RE regex) { return ContainsRegex(regex.pattern()); } inline Matcher MakeDeathTestMatcher(const char* regex) { return ContainsRegex(regex); } inline Matcher MakeDeathTestMatcher( const ::std::string& regex) { return ContainsRegex(regex); } // If a Matcher is passed to EXPECT_DEATH (etc.), it's // used directly. inline Matcher MakeDeathTestMatcher( Matcher matcher) { return matcher; } // Traps C++ exceptions escaping statement and reports them as test // failures. Note that trapping SEH exceptions is not implemented here. # if GTEST_HAS_EXCEPTIONS # define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } catch (const ::std::exception& gtest_exception) { \ fprintf(\ stderr, \ "\n%s: Caught std::exception-derived exception escaping the " \ "death test statement. Exception message: %s\n", \ ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \ gtest_exception.what()); \ fflush(stderr); \ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ } catch (...) { \ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ } # else # define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) # endif // This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, // ASSERT_EXIT*, and EXPECT_EXIT*. #define GTEST_DEATH_TEST_(statement, predicate, regex_or_matcher, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ ::testing::internal::DeathTest* gtest_dt; \ if (!::testing::internal::DeathTest::Create( \ #statement, \ ::testing::internal::MakeDeathTestMatcher(regex_or_matcher), \ __FILE__, __LINE__, >est_dt)) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ } \ if (gtest_dt != nullptr) { \ std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr(gtest_dt); \ switch (gtest_dt->AssumeRole()) { \ case ::testing::internal::DeathTest::OVERSEE_TEST: \ if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ } \ break; \ case ::testing::internal::DeathTest::EXECUTE_TEST: { \ ::testing::internal::DeathTest::ReturnSentinel gtest_sentinel( \ gtest_dt); \ GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ break; \ } \ default: \ break; \ } \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__) \ : fail(::testing::internal::DeathTest::LastMessage()) // The symbol "fail" here expands to something into which a message // can be streamed. // This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in // NDEBUG mode. In this case we need the statements to be executed and the macro // must accept a streamed message even though the message is never printed. // The regex object is not evaluated, but it is used to prevent "unused" // warnings and to avoid an expression that doesn't compile in debug mode. #define GTEST_EXECUTE_STATEMENT_(statement, regex_or_matcher) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } else if (!::testing::internal::AlwaysTrue()) { \ ::testing::internal::MakeDeathTestMatcher(regex_or_matcher); \ } else \ ::testing::Message() // A class representing the parsed contents of the // --gtest_internal_run_death_test flag, as it existed when // RUN_ALL_TESTS was called. class InternalRunDeathTestFlag { public: InternalRunDeathTestFlag(const std::string& a_file, int a_line, int an_index, int a_write_fd) : file_(a_file), line_(a_line), index_(an_index), write_fd_(a_write_fd) {} ~InternalRunDeathTestFlag() { if (write_fd_ >= 0) posix::Close(write_fd_); } const std::string& file() const { return file_; } int line() const { return line_; } int index() const { return index_; } int write_fd() const { return write_fd_; } private: std::string file_; int line_; int index_; int write_fd_; GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); }; // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); #endif // GTEST_HAS_DEATH_TEST } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ openzwave-1.6.1914/cpp/test/include/gtest/internal/gtest-filepath.h0000644000175200017520000002304414032142455022142 00000000000000// Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Google Test filepath utilities // // This header file declares classes and functions used internally by // Google Test. They are subject to change without notice. // // This file is #included in gtest/internal/gtest-internal.h. // Do not include this header file separately! // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #include "gtest/internal/gtest-string.h" GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) namespace testing { namespace internal { // FilePath - a class for file and directory pathname manipulation which // handles platform-specific conventions (like the pathname separator). // Used for helper functions for naming files in a directory for xml output. // Except for Set methods, all methods are const or static, which provides an // "immutable value object" -- useful for peace of mind. // A FilePath with a value ending in a path separator ("like/this/") represents // a directory, otherwise it is assumed to represent a file. In either case, // it may or may not represent an actual file or directory in the file system. // Names are NOT checked for syntax correctness -- no checking for illegal // characters, malformed paths, etc. class GTEST_API_ FilePath { public: FilePath() : pathname_("") { } FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } explicit FilePath(const std::string& pathname) : pathname_(pathname) { Normalize(); } FilePath& operator=(const FilePath& rhs) { Set(rhs); return *this; } void Set(const FilePath& rhs) { pathname_ = rhs.pathname_; } const std::string& string() const { return pathname_; } const char* c_str() const { return pathname_.c_str(); } // Returns the current working directory, or "" if unsuccessful. static FilePath GetCurrentDir(); // Given directory = "dir", base_name = "test", number = 0, // extension = "xml", returns "dir/test.xml". If number is greater // than zero (e.g., 12), returns "dir/test_12.xml". // On Windows platform, uses \ as the separator rather than /. static FilePath MakeFileName(const FilePath& directory, const FilePath& base_name, int number, const char* extension); // Given directory = "dir", relative_path = "test.xml", // returns "dir/test.xml". // On Windows, uses \ as the separator rather than /. static FilePath ConcatPaths(const FilePath& directory, const FilePath& relative_path); // Returns a pathname for a file that does not currently exist. The pathname // will be directory/base_name.extension or // directory/base_name_.extension if directory/base_name.extension // already exists. The number will be incremented until a pathname is found // that does not already exist. // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. // There could be a race condition if two or more processes are calling this // function at the same time -- they could both pick the same filename. static FilePath GenerateUniqueFileName(const FilePath& directory, const FilePath& base_name, const char* extension); // Returns true if and only if the path is "". bool IsEmpty() const { return pathname_.empty(); } // If input name has a trailing separator character, removes it and returns // the name, otherwise return the name string unmodified. // On Windows platform, uses \ as the separator, other platforms use /. FilePath RemoveTrailingPathSeparator() const; // Returns a copy of the FilePath with the directory part removed. // Example: FilePath("path/to/file").RemoveDirectoryName() returns // FilePath("file"). If there is no directory part ("just_a_file"), it returns // the FilePath unmodified. If there is no file part ("just_a_dir/") it // returns an empty FilePath (""). // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath RemoveDirectoryName() const; // RemoveFileName returns the directory path with the filename removed. // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". // If the FilePath is "a_file" or "/a_file", RemoveFileName returns // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does // not have a file, like "just/a/dir/", it returns the FilePath unmodified. // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath RemoveFileName() const; // Returns a copy of the FilePath with the case-insensitive extension removed. // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns // FilePath("dir/file"). If a case-insensitive extension is not // found, returns a copy of the original FilePath. FilePath RemoveExtension(const char* extension) const; // Creates directories so that path exists. Returns true if successful or if // the directories already exist; returns false if unable to create // directories for any reason. Will also return false if the FilePath does // not represent a directory (that is, it doesn't end with a path separator). bool CreateDirectoriesRecursively() const; // Create the directory so that path exists. Returns true if successful or // if the directory already exists; returns false if unable to create the // directory for any reason, including if the parent directory does not // exist. Not named "CreateDirectory" because that's a macro on Windows. bool CreateFolder() const; // Returns true if FilePath describes something in the file-system, // either a file, directory, or whatever, and that something exists. bool FileOrDirectoryExists() const; // Returns true if pathname describes a directory in the file-system // that exists. bool DirectoryExists() const; // Returns true if FilePath ends with a path separator, which indicates that // it is intended to represent a directory. Returns false otherwise. // This does NOT check that a directory (or file) actually exists. bool IsDirectory() const; // Returns true if pathname describes a root directory. (Windows has one // root directory per disk drive.) bool IsRootDirectory() const; // Returns true if pathname describes an absolute path. bool IsAbsolutePath() const; private: // Replaces multiple consecutive separators with a single separator. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". // // A pathname with multiple consecutive separators may occur either through // user error or as a result of some scripts or APIs that generate a pathname // with a trailing separator. On other platforms the same API or script // may NOT generate a pathname with a trailing "/". Then elsewhere that // pathname may have another "/" and pathname components added to it, // without checking for the separator already being there. // The script language and operating system may allow paths like "foo//bar" // but some of the functions in FilePath will not handle that correctly. In // particular, RemoveTrailingPathSeparator() only removes one separator, and // it is called in CreateDirectoriesRecursively() assuming that it will change // a pathname from directory syntax (trailing separator) to filename syntax. // // On Windows this method also replaces the alternate path separator '/' with // the primary path separator '\\', so that for example "bar\\/\\foo" becomes // "bar\\foo". void Normalize(); // Returns a pointer to the last occurence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FindLastPathSeparator() const; std::string pathname_; }; // class FilePath } // namespace internal } // namespace testing GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ openzwave-1.6.1914/cpp/test/include/gtest/internal/gtest-param-util.h0000644000175200017520000010031414032142455022415 00000000000000// Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Type and function utilities for implementing parameterized tests. // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #include #include #include #include #include #include #include #include #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-port.h" #include "gtest/gtest-printers.h" namespace testing { // Input to a parameterized test name generator, describing a test parameter. // Consists of the parameter value and the integer parameter index. template struct TestParamInfo { TestParamInfo(const ParamType& a_param, size_t an_index) : param(a_param), index(an_index) {} ParamType param; size_t index; }; // A builtin parameterized test name generator which returns the result of // testing::PrintToString. struct PrintToStringParamName { template std::string operator()(const TestParamInfo& info) const { return PrintToString(info.param); } }; namespace internal { // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // Utility Functions // Outputs a message explaining invalid registration of different // fixture class for the same test suite. This may happen when // TEST_P macro is used to define two tests with the same name // but in different namespaces. GTEST_API_ void ReportInvalidTestSuiteType(const char* test_suite_name, CodeLocation code_location); template class ParamGeneratorInterface; template class ParamGenerator; // Interface for iterating over elements provided by an implementation // of ParamGeneratorInterface. template class ParamIteratorInterface { public: virtual ~ParamIteratorInterface() {} // A pointer to the base generator instance. // Used only for the purposes of iterator comparison // to make sure that two iterators belong to the same generator. virtual const ParamGeneratorInterface* BaseGenerator() const = 0; // Advances iterator to point to the next element // provided by the generator. The caller is responsible // for not calling Advance() on an iterator equal to // BaseGenerator()->End(). virtual void Advance() = 0; // Clones the iterator object. Used for implementing copy semantics // of ParamIterator. virtual ParamIteratorInterface* Clone() const = 0; // Dereferences the current iterator and provides (read-only) access // to the pointed value. It is the caller's responsibility not to call // Current() on an iterator equal to BaseGenerator()->End(). // Used for implementing ParamGenerator::operator*(). virtual const T* Current() const = 0; // Determines whether the given iterator and other point to the same // element in the sequence generated by the generator. // Used for implementing ParamGenerator::operator==(). virtual bool Equals(const ParamIteratorInterface& other) const = 0; }; // Class iterating over elements provided by an implementation of // ParamGeneratorInterface. It wraps ParamIteratorInterface // and implements the const forward iterator concept. template class ParamIterator { public: typedef T value_type; typedef const T& reference; typedef ptrdiff_t difference_type; // ParamIterator assumes ownership of the impl_ pointer. ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} ParamIterator& operator=(const ParamIterator& other) { if (this != &other) impl_.reset(other.impl_->Clone()); return *this; } const T& operator*() const { return *impl_->Current(); } const T* operator->() const { return impl_->Current(); } // Prefix version of operator++. ParamIterator& operator++() { impl_->Advance(); return *this; } // Postfix version of operator++. ParamIterator operator++(int /*unused*/) { ParamIteratorInterface* clone = impl_->Clone(); impl_->Advance(); return ParamIterator(clone); } bool operator==(const ParamIterator& other) const { return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); } bool operator!=(const ParamIterator& other) const { return !(*this == other); } private: friend class ParamGenerator; explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} std::unique_ptr > impl_; }; // ParamGeneratorInterface is the binary interface to access generators // defined in other translation units. template class ParamGeneratorInterface { public: typedef T ParamType; virtual ~ParamGeneratorInterface() {} // Generator interface definition virtual ParamIteratorInterface* Begin() const = 0; virtual ParamIteratorInterface* End() const = 0; }; // Wraps ParamGeneratorInterface and provides general generator syntax // compatible with the STL Container concept. // This class implements copy initialization semantics and the contained // ParamGeneratorInterface instance is shared among all copies // of the original object. This is possible because that instance is immutable. template class ParamGenerator { public: typedef ParamIterator iterator; explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} ParamGenerator& operator=(const ParamGenerator& other) { impl_ = other.impl_; return *this; } iterator begin() const { return iterator(impl_->Begin()); } iterator end() const { return iterator(impl_->End()); } private: std::shared_ptr > impl_; }; // Generates values from a range of two comparable values. Can be used to // generate sequences of user-defined types that implement operator+() and // operator<(). // This class is used in the Range() function. template class RangeGenerator : public ParamGeneratorInterface { public: RangeGenerator(T begin, T end, IncrementT step) : begin_(begin), end_(end), step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} ~RangeGenerator() override {} ParamIteratorInterface* Begin() const override { return new Iterator(this, begin_, 0, step_); } ParamIteratorInterface* End() const override { return new Iterator(this, end_, end_index_, step_); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, T value, int index, IncrementT step) : base_(base), value_(value), index_(index), step_(step) {} ~Iterator() override {} const ParamGeneratorInterface* BaseGenerator() const override { return base_; } void Advance() override { value_ = static_cast(value_ + step_); index_++; } ParamIteratorInterface* Clone() const override { return new Iterator(*this); } const T* Current() const override { return &value_; } bool Equals(const ParamIteratorInterface& other) const override { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const int other_index = CheckedDowncastToActualType(&other)->index_; return index_ == other_index; } private: Iterator(const Iterator& other) : ParamIteratorInterface(), base_(other.base_), value_(other.value_), index_(other.index_), step_(other.step_) {} // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; T value_; int index_; const IncrementT step_; }; // class RangeGenerator::Iterator static int CalculateEndIndex(const T& begin, const T& end, const IncrementT& step) { int end_index = 0; for (T i = begin; i < end; i = static_cast(i + step)) end_index++; return end_index; } // No implementation - assignment is unsupported. void operator=(const RangeGenerator& other); const T begin_; const T end_; const IncrementT step_; // The index for the end() iterator. All the elements in the generated // sequence are indexed (0-based) to aid iterator comparison. const int end_index_; }; // class RangeGenerator // Generates values from a pair of STL-style iterators. Used in the // ValuesIn() function. The elements are copied from the source range // since the source can be located on the stack, and the generator // is likely to persist beyond that stack frame. template class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { public: template ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) : container_(begin, end) {} ~ValuesInIteratorRangeGenerator() override {} ParamIteratorInterface* Begin() const override { return new Iterator(this, container_.begin()); } ParamIteratorInterface* End() const override { return new Iterator(this, container_.end()); } private: typedef typename ::std::vector ContainerType; class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, typename ContainerType::const_iterator iterator) : base_(base), iterator_(iterator) {} ~Iterator() override {} const ParamGeneratorInterface* BaseGenerator() const override { return base_; } void Advance() override { ++iterator_; value_.reset(); } ParamIteratorInterface* Clone() const override { return new Iterator(*this); } // We need to use cached value referenced by iterator_ because *iterator_ // can return a temporary object (and of type other then T), so just // having "return &*iterator_;" doesn't work. // value_ is updated here and not in Advance() because Advance() // can advance iterator_ beyond the end of the range, and we cannot // detect that fact. The client code, on the other hand, is // responsible for not calling Current() on an out-of-range iterator. const T* Current() const override { if (value_.get() == nullptr) value_.reset(new T(*iterator_)); return value_.get(); } bool Equals(const ParamIteratorInterface& other) const override { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; return iterator_ == CheckedDowncastToActualType(&other)->iterator_; } private: Iterator(const Iterator& other) // The explicit constructor call suppresses a false warning // emitted by gcc when supplied with the -Wextra option. : ParamIteratorInterface(), base_(other.base_), iterator_(other.iterator_) {} const ParamGeneratorInterface* const base_; typename ContainerType::const_iterator iterator_; // A cached value of *iterator_. We keep it here to allow access by // pointer in the wrapping iterator's operator->(). // value_ needs to be mutable to be accessed in Current(). // Use of std::unique_ptr helps manage cached value's lifetime, // which is bound by the lifespan of the iterator itself. mutable std::unique_ptr value_; }; // class ValuesInIteratorRangeGenerator::Iterator // No implementation - assignment is unsupported. void operator=(const ValuesInIteratorRangeGenerator& other); const ContainerType container_; }; // class ValuesInIteratorRangeGenerator // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Default parameterized test name generator, returns a string containing the // integer test parameter index. template std::string DefaultParamName(const TestParamInfo& info) { Message name_stream; name_stream << info.index; return name_stream.GetString(); } template void TestNotEmpty() { static_assert(sizeof(T) == 0, "Empty arguments are not allowed."); } template void TestNotEmpty(const T&) {} // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Stores a parameter value and later creates tests parameterized with that // value. template class ParameterizedTestFactory : public TestFactoryBase { public: typedef typename TestClass::ParamType ParamType; explicit ParameterizedTestFactory(ParamType parameter) : parameter_(parameter) {} Test* CreateTest() override { TestClass::SetParam(¶meter_); return new TestClass(); } private: const ParamType parameter_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // TestMetaFactoryBase is a base class for meta-factories that create // test factories for passing into MakeAndRegisterTestInfo function. template class TestMetaFactoryBase { public: virtual ~TestMetaFactoryBase() {} virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // TestMetaFactory creates test factories for passing into // MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives // ownership of test factory pointer, same factory object cannot be passed // into that method twice. But ParameterizedTestSuiteInfo is going to call // it for each Test/Parameter value combination. Thus it needs meta factory // creator class. template class TestMetaFactory : public TestMetaFactoryBase { public: using ParamType = typename TestSuite::ParamType; TestMetaFactory() {} TestFactoryBase* CreateTestFactory(ParamType parameter) override { return new ParameterizedTestFactory(parameter); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestSuiteInfoBase is a generic interface // to ParameterizedTestSuiteInfo classes. ParameterizedTestSuiteInfoBase // accumulates test information provided by TEST_P macro invocations // and generators provided by INSTANTIATE_TEST_SUITE_P macro invocations // and uses that information to register all resulting test instances // in RegisterTests method. The ParameterizeTestSuiteRegistry class holds // a collection of pointers to the ParameterizedTestSuiteInfo objects // and calls RegisterTests() on each of them when asked. class ParameterizedTestSuiteInfoBase { public: virtual ~ParameterizedTestSuiteInfoBase() {} // Base part of test suite name for display purposes. virtual const std::string& GetTestSuiteName() const = 0; // Test case id to verify identity. virtual TypeId GetTestSuiteTypeId() const = 0; // UnitTest class invokes this method to register tests in this // test suite right before running them in RUN_ALL_TESTS macro. // This method should not be called more than once on any single // instance of a ParameterizedTestSuiteInfoBase derived class. virtual void RegisterTests() = 0; protected: ParameterizedTestSuiteInfoBase() {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfoBase); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestSuiteInfo accumulates tests obtained from TEST_P // macro invocations for a particular test suite and generators // obtained from INSTANTIATE_TEST_SUITE_P macro invocations for that // test suite. It registers tests with all values generated by all // generators when asked. template class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase { public: // ParamType and GeneratorCreationFunc are private types but are required // for declarations of public methods AddTestPattern() and // AddTestSuiteInstantiation(). using ParamType = typename TestSuite::ParamType; // A function that returns an instance of appropriate generator type. typedef ParamGenerator(GeneratorCreationFunc)(); using ParamNameGeneratorFunc = std::string(const TestParamInfo&); explicit ParameterizedTestSuiteInfo(const char* name, CodeLocation code_location) : test_suite_name_(name), code_location_(code_location) {} // Test case base name for display purposes. const std::string& GetTestSuiteName() const override { return test_suite_name_; } // Test case id to verify identity. TypeId GetTestSuiteTypeId() const override { return GetTypeId(); } // TEST_P macro uses AddTestPattern() to record information // about a single test in a LocalTestInfo structure. // test_suite_name is the base name of the test suite (without invocation // prefix). test_base_name is the name of an individual test without // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is // test suite base name and DoBar is test base name. void AddTestPattern(const char* test_suite_name, const char* test_base_name, TestMetaFactoryBase* meta_factory) { tests_.push_back(std::shared_ptr( new TestInfo(test_suite_name, test_base_name, meta_factory))); } // INSTANTIATE_TEST_SUITE_P macro uses AddGenerator() to record information // about a generator. int AddTestSuiteInstantiation(const std::string& instantiation_name, GeneratorCreationFunc* func, ParamNameGeneratorFunc* name_func, const char* file, int line) { instantiations_.push_back( InstantiationInfo(instantiation_name, func, name_func, file, line)); return 0; // Return value used only to run this method in namespace scope. } // UnitTest class invokes this method to register tests in this test suite // test suites right before running tests in RUN_ALL_TESTS macro. // This method should not be called more than once on any single // instance of a ParameterizedTestSuiteInfoBase derived class. // UnitTest has a guard to prevent from calling this method more than once. void RegisterTests() override { for (typename TestInfoContainer::iterator test_it = tests_.begin(); test_it != tests_.end(); ++test_it) { std::shared_ptr test_info = *test_it; for (typename InstantiationContainer::iterator gen_it = instantiations_.begin(); gen_it != instantiations_.end(); ++gen_it) { const std::string& instantiation_name = gen_it->name; ParamGenerator generator((*gen_it->generator)()); ParamNameGeneratorFunc* name_func = gen_it->name_func; const char* file = gen_it->file; int line = gen_it->line; std::string test_suite_name; if ( !instantiation_name.empty() ) test_suite_name = instantiation_name + "/"; test_suite_name += test_info->test_suite_base_name; size_t i = 0; std::set test_param_names; for (typename ParamGenerator::iterator param_it = generator.begin(); param_it != generator.end(); ++param_it, ++i) { Message test_name_stream; std::string param_name = name_func( TestParamInfo(*param_it, i)); GTEST_CHECK_(IsValidParamName(param_name)) << "Parameterized test name '" << param_name << "' is invalid, in " << file << " line " << line << std::endl; GTEST_CHECK_(test_param_names.count(param_name) == 0) << "Duplicate parameterized test name '" << param_name << "', in " << file << " line " << line << std::endl; test_param_names.insert(param_name); test_name_stream << test_info->test_base_name << "/" << param_name; MakeAndRegisterTestInfo( test_suite_name.c_str(), test_name_stream.GetString().c_str(), nullptr, // No type parameter. PrintToString(*param_it).c_str(), code_location_, GetTestSuiteTypeId(), SuiteApiResolver::GetSetUpCaseOrSuite(file, line), SuiteApiResolver::GetTearDownCaseOrSuite(file, line), test_info->test_meta_factory->CreateTestFactory(*param_it)); } // for param_it } // for gen_it } // for test_it } // RegisterTests private: // LocalTestInfo structure keeps information about a single test registered // with TEST_P macro. struct TestInfo { TestInfo(const char* a_test_suite_base_name, const char* a_test_base_name, TestMetaFactoryBase* a_test_meta_factory) : test_suite_base_name(a_test_suite_base_name), test_base_name(a_test_base_name), test_meta_factory(a_test_meta_factory) {} const std::string test_suite_base_name; const std::string test_base_name; const std::unique_ptr > test_meta_factory; }; using TestInfoContainer = ::std::vector >; // Records data received from INSTANTIATE_TEST_SUITE_P macros: // struct InstantiationInfo { InstantiationInfo(const std::string &name_in, GeneratorCreationFunc* generator_in, ParamNameGeneratorFunc* name_func_in, const char* file_in, int line_in) : name(name_in), generator(generator_in), name_func(name_func_in), file(file_in), line(line_in) {} std::string name; GeneratorCreationFunc* generator; ParamNameGeneratorFunc* name_func; const char* file; int line; }; typedef ::std::vector InstantiationContainer; static bool IsValidParamName(const std::string& name) { // Check for empty string if (name.empty()) return false; // Check for invalid characters for (std::string::size_type index = 0; index < name.size(); ++index) { if (!isalnum(name[index]) && name[index] != '_') return false; } return true; } const std::string test_suite_name_; CodeLocation code_location_; TestInfoContainer tests_; InstantiationContainer instantiations_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfo); }; // class ParameterizedTestSuiteInfo // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ template using ParameterizedTestCaseInfo = ParameterizedTestSuiteInfo; #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestSuiteRegistry contains a map of // ParameterizedTestSuiteInfoBase classes accessed by test suite names. TEST_P // and INSTANTIATE_TEST_SUITE_P macros use it to locate their corresponding // ParameterizedTestSuiteInfo descriptors. class ParameterizedTestSuiteRegistry { public: ParameterizedTestSuiteRegistry() {} ~ParameterizedTestSuiteRegistry() { for (auto& test_suite_info : test_suite_infos_) { delete test_suite_info; } } // Looks up or creates and returns a structure containing information about // tests and instantiations of a particular test suite. template ParameterizedTestSuiteInfo* GetTestSuitePatternHolder( const char* test_suite_name, CodeLocation code_location) { ParameterizedTestSuiteInfo* typed_test_info = nullptr; for (auto& test_suite_info : test_suite_infos_) { if (test_suite_info->GetTestSuiteName() == test_suite_name) { if (test_suite_info->GetTestSuiteTypeId() != GetTypeId()) { // Complain about incorrect usage of Google Test facilities // and terminate the program since we cannot guaranty correct // test suite setup and tear-down in this case. ReportInvalidTestSuiteType(test_suite_name, code_location); posix::Abort(); } else { // At this point we are sure that the object we found is of the same // type we are looking for, so we downcast it to that type // without further checks. typed_test_info = CheckedDowncastToActualType< ParameterizedTestSuiteInfo >(test_suite_info); } break; } } if (typed_test_info == nullptr) { typed_test_info = new ParameterizedTestSuiteInfo( test_suite_name, code_location); test_suite_infos_.push_back(typed_test_info); } return typed_test_info; } void RegisterTests() { for (auto& test_suite_info : test_suite_infos_) { test_suite_info->RegisterTests(); } } // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ template ParameterizedTestCaseInfo* GetTestCasePatternHolder( const char* test_case_name, CodeLocation code_location) { return GetTestSuitePatternHolder(test_case_name, code_location); } #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ private: using TestSuiteInfoContainer = ::std::vector; TestSuiteInfoContainer test_suite_infos_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteRegistry); }; } // namespace internal // Forward declarations of ValuesIn(), which is implemented in // include/gtest/gtest-param-test.h. template internal::ParamGenerator ValuesIn( const Container& container); namespace internal { // Used in the Values() function to provide polymorphic capabilities. template class ValueArray { public: ValueArray(Ts... v) : v_{std::move(v)...} {} template operator ParamGenerator() const { // NOLINT return ValuesIn(MakeVector(MakeIndexSequence())); } private: template std::vector MakeVector(IndexSequence) const { return std::vector{static_cast(v_.template Get())...}; } FlatTuple v_; }; template class CartesianProductGenerator : public ParamGeneratorInterface<::std::tuple> { public: typedef ::std::tuple ParamType; CartesianProductGenerator(const std::tuple...>& g) : generators_(g) {} ~CartesianProductGenerator() override {} ParamIteratorInterface* Begin() const override { return new Iterator(this, generators_, false); } ParamIteratorInterface* End() const override { return new Iterator(this, generators_, true); } private: template class IteratorImpl; template class IteratorImpl> : public ParamIteratorInterface { public: IteratorImpl(const ParamGeneratorInterface* base, const std::tuple...>& generators, bool is_end) : base_(base), begin_(std::get(generators).begin()...), end_(std::get(generators).end()...), current_(is_end ? end_ : begin_) { ComputeCurrentValue(); } ~IteratorImpl() override {} const ParamGeneratorInterface* BaseGenerator() const override { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. void Advance() override { assert(!AtEnd()); // Advance the last iterator. ++std::get(current_); // if that reaches end, propagate that up. AdvanceIfEnd(); ComputeCurrentValue(); } ParamIteratorInterface* Clone() const override { return new IteratorImpl(*this); } const ParamType* Current() const override { return current_value_.get(); } bool Equals(const ParamIteratorInterface& other) const override { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const IteratorImpl* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). if (AtEnd() && typed_other->AtEnd()) return true; bool same = true; bool dummy[] = { (same = same && std::get(current_) == std::get(typed_other->current_))...}; (void)dummy; return same; } private: template void AdvanceIfEnd() { if (std::get(current_) != std::get(end_)) return; bool last = ThisI == 0; if (last) { // We are done. Nothing else to propagate. return; } constexpr size_t NextI = ThisI - (ThisI != 0); std::get(current_) = std::get(begin_); ++std::get(current_); AdvanceIfEnd(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = std::make_shared(*std::get(current_)...); } bool AtEnd() const { bool at_end = false; bool dummy[] = { (at_end = at_end || std::get(current_) == std::get(end_))...}; (void)dummy; return at_end; } const ParamGeneratorInterface* const base_; std::tuple::iterator...> begin_; std::tuple::iterator...> end_; std::tuple::iterator...> current_; std::shared_ptr current_value_; }; using Iterator = IteratorImpl::type>; std::tuple...> generators_; }; template class CartesianProductHolder { public: CartesianProductHolder(const Gen&... g) : generators_(g...) {} template operator ParamGenerator<::std::tuple>() const { return ParamGenerator<::std::tuple>( new CartesianProductGenerator(generators_)); } private: std::tuple generators_; }; } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ openzwave-1.6.1914/cpp/test/include/gtest/internal/gtest-internal.h0000644000175200017520000015313414032142455022166 00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // The Google C++ Testing and Mocking Framework (Google Test) // // This header file declares functions and macros used internally by // Google Test. They are subject to change without notice. // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ #include "gtest/internal/gtest-port.h" #if GTEST_OS_LINUX # include # include # include # include #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS # include #endif #include #include #include #include #include #include #include #include #include #include #include "gtest/gtest-message.h" #include "gtest/internal/gtest-filepath.h" #include "gtest/internal/gtest-string.h" #include "gtest/internal/gtest-type-util.h" // Due to C++ preprocessor weirdness, we need double indirection to // concatenate two tokens when one of them is __LINE__. Writing // // foo ## __LINE__ // // will result in the token foo__LINE__, instead of foo followed by // the current line number. For more details, see // http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 #define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) #define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar // Stringifies its argument. #define GTEST_STRINGIFY_(name) #name namespace proto2 { class Message; } namespace testing { // Forward declarations. class AssertionResult; // Result of an assertion. class Message; // Represents a failure message. class Test; // Represents a test. class TestInfo; // Information about a test. class TestPartResult; // Result of a test part. class UnitTest; // A collection of test suites. template ::std::string PrintToString(const T& value); namespace internal { struct TraceInfo; // Information about a trace point. class TestInfoImpl; // Opaque implementation of TestInfo class UnitTestImpl; // Opaque implementation of UnitTest // The text used in failure messages to indicate the start of the // stack trace. GTEST_API_ extern const char kStackTraceMarker[]; // An IgnoredValue object can be implicitly constructed from ANY value. class IgnoredValue { struct Sink {}; public: // This constructor template allows any value to be implicitly // converted to IgnoredValue. The object has no data member and // doesn't try to remember anything about the argument. We // deliberately omit the 'explicit' keyword in order to allow the // conversion to be implicit. // Disable the conversion if T already has a magical conversion operator. // Otherwise we get ambiguity. template ::value, int>::type = 0> IgnoredValue(const T& /* ignored */) {} // NOLINT(runtime/explicit) }; // Appends the user-supplied message to the Google-Test-generated message. GTEST_API_ std::string AppendUserMessage( const std::string& gtest_msg, const Message& user_msg); #if GTEST_HAS_EXCEPTIONS GTEST_DISABLE_MSC_WARNINGS_PUSH_(4275 \ /* an exported class was derived from a class that was not exported */) // This exception is thrown by (and only by) a failed Google Test // assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions // are enabled). We derive it from std::runtime_error, which is for // errors presumably detectable only at run time. Since // std::runtime_error inherits from std::exception, many testing // frameworks know how to extract and print the message inside it. class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { public: explicit GoogleTestFailureException(const TestPartResult& failure); }; GTEST_DISABLE_MSC_WARNINGS_POP_() // 4275 #endif // GTEST_HAS_EXCEPTIONS namespace edit_distance { // Returns the optimal edits to go from 'left' to 'right'. // All edits cost the same, with replace having lower priority than // add/remove. // Simple implementation of the Wagner-Fischer algorithm. // See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm enum EditType { kMatch, kAdd, kRemove, kReplace }; GTEST_API_ std::vector CalculateOptimalEdits( const std::vector& left, const std::vector& right); // Same as above, but the input is represented as strings. GTEST_API_ std::vector CalculateOptimalEdits( const std::vector& left, const std::vector& right); // Create a diff of the input strings in Unified diff format. GTEST_API_ std::string CreateUnifiedDiff(const std::vector& left, const std::vector& right, size_t context = 2); } // namespace edit_distance // Calculate the diff between 'left' and 'right' and return it in unified diff // format. // If not null, stores in 'total_line_count' the total number of lines found // in left + right. GTEST_API_ std::string DiffStrings(const std::string& left, const std::string& right, size_t* total_line_count); // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // // The first four parameters are the expressions used in the assertion // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // // expected_expression: "foo" // actual_expression: "bar" // expected_value: "5" // actual_value: "6" // // The ignoring_case parameter is true if and only if the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. GTEST_API_ AssertionResult EqFailure(const char* expected_expression, const char* actual_expression, const std::string& expected_value, const std::string& actual_value, bool ignoring_case); // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. GTEST_API_ std::string GetBoolAssertionFailureMessage( const AssertionResult& assertion_result, const char* expression_text, const char* actual_predicate_value, const char* expected_predicate_value); // This template class represents an IEEE floating-point number // (either single-precision or double-precision, depending on the // template parameters). // // The purpose of this class is to do more sophisticated number // comparison. (Due to round-off error, etc, it's very unlikely that // two floating-points will be equal exactly. Hence a naive // comparison by the == operation often doesn't work.) // // Format of IEEE floating-point: // // The most-significant bit being the leftmost, an IEEE // floating-point looks like // // sign_bit exponent_bits fraction_bits // // Here, sign_bit is a single bit that designates the sign of the // number. // // For float, there are 8 exponent bits and 23 fraction bits. // // For double, there are 11 exponent bits and 52 fraction bits. // // More details can be found at // http://en.wikipedia.org/wiki/IEEE_floating-point_standard. // // Template parameter: // // RawType: the raw floating-point type (either float or double) template class FloatingPoint { public: // Defines the unsigned integer type that has the same size as the // floating point number. typedef typename TypeWithSize::UInt Bits; // Constants. // # of bits in a number. static const size_t kBitCount = 8*sizeof(RawType); // # of fraction bits in a number. static const size_t kFractionBitCount = std::numeric_limits::digits - 1; // # of exponent bits in a number. static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; // The mask for the sign bit. static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); // The mask for the fraction bits. static const Bits kFractionBitMask = ~static_cast(0) >> (kExponentBitCount + 1); // The mask for the exponent bits. static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); // How many ULP's (Units in the Last Place) we want to tolerate when // comparing two numbers. The larger the value, the more error we // allow. A 0 value means that two numbers must be exactly the same // to be considered equal. // // The maximum error of a single floating-point operation is 0.5 // units in the last place. On Intel CPU's, all floating-point // calculations are done with 80-bit precision, while double has 64 // bits. Therefore, 4 should be enough for ordinary use. // // See the following article for more details on ULP: // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ static const size_t kMaxUlps = 4; // Constructs a FloatingPoint from a raw floating-point number. // // On an Intel CPU, passing a non-normalized NAN (Not a Number) // around may change its bits, although the new value is guaranteed // to be also a NAN. Therefore, don't expect this constructor to // preserve the bits in x when x is a NAN. explicit FloatingPoint(const RawType& x) { u_.value_ = x; } // Static methods // Reinterprets a bit pattern as a floating-point number. // // This function is needed to test the AlmostEquals() method. static RawType ReinterpretBits(const Bits bits) { FloatingPoint fp(0); fp.u_.bits_ = bits; return fp.u_.value_; } // Returns the floating-point number that represent positive infinity. static RawType Infinity() { return ReinterpretBits(kExponentBitMask); } // Returns the maximum representable finite floating-point number. static RawType Max(); // Non-static methods // Returns the bits that represents this number. const Bits &bits() const { return u_.bits_; } // Returns the exponent bits of this number. Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } // Returns the fraction bits of this number. Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } // Returns the sign bit of this number. Bits sign_bit() const { return kSignBitMask & u_.bits_; } // Returns true if and only if this is NAN (not a number). bool is_nan() const { // It's a NAN if the exponent bits are all ones and the fraction // bits are not entirely zeros. return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); } // Returns true if and only if this number is at most kMaxUlps ULP's away // from rhs. In particular, this function: // // - returns false if either number is (or both are) NAN. // - treats really large numbers as almost equal to infinity. // - thinks +0.0 and -0.0 are 0 DLP's apart. bool AlmostEquals(const FloatingPoint& rhs) const { // The IEEE standard says that any comparison operation involving // a NAN must return false. if (is_nan() || rhs.is_nan()) return false; return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) <= kMaxUlps; } private: // The data type used to store the actual floating-point number. union FloatingPointUnion { RawType value_; // The raw floating-point number. Bits bits_; // The bits that represent the number. }; // Converts an integer from the sign-and-magnitude representation to // the biased representation. More precisely, let N be 2 to the // power of (kBitCount - 1), an integer x is represented by the // unsigned number x + N. // // For instance, // // -N + 1 (the most negative number representable using // sign-and-magnitude) is represented by 1; // 0 is represented by N; and // N - 1 (the biggest number representable using // sign-and-magnitude) is represented by 2N - 1. // // Read http://en.wikipedia.org/wiki/Signed_number_representations // for more details on signed number representations. static Bits SignAndMagnitudeToBiased(const Bits &sam) { if (kSignBitMask & sam) { // sam represents a negative number. return ~sam + 1; } else { // sam represents a positive number. return kSignBitMask | sam; } } // Given two numbers in the sign-and-magnitude representation, // returns the distance between them as an unsigned number. static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, const Bits &sam2) { const Bits biased1 = SignAndMagnitudeToBiased(sam1); const Bits biased2 = SignAndMagnitudeToBiased(sam2); return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); } FloatingPointUnion u_; }; // We cannot use std::numeric_limits::max() as it clashes with the max() // macro defined by . template <> inline float FloatingPoint::Max() { return FLT_MAX; } template <> inline double FloatingPoint::Max() { return DBL_MAX; } // Typedefs the instances of the FloatingPoint template class that we // care to use. typedef FloatingPoint Float; typedef FloatingPoint Double; // In order to catch the mistake of putting tests that use different // test fixture classes in the same test suite, we need to assign // unique IDs to fixture classes and compare them. The TypeId type is // used to hold such IDs. The user should treat TypeId as an opaque // type: the only operation allowed on TypeId values is to compare // them for equality using the == operator. typedef const void* TypeId; template class TypeIdHelper { public: // dummy_ must not have a const type. Otherwise an overly eager // compiler (e.g. MSVC 7.1 & 8.0) may try to merge // TypeIdHelper::dummy_ for different Ts as an "optimization". static bool dummy_; }; template bool TypeIdHelper::dummy_ = false; // GetTypeId() returns the ID of type T. Different values will be // returned for different types. Calling the function twice with the // same type argument is guaranteed to return the same ID. template TypeId GetTypeId() { // The compiler is required to allocate a different // TypeIdHelper::dummy_ variable for each T used to instantiate // the template. Therefore, the address of dummy_ is guaranteed to // be unique. return &(TypeIdHelper::dummy_); } // Returns the type ID of ::testing::Test. Always call this instead // of GetTypeId< ::testing::Test>() to get the type ID of // ::testing::Test, as the latter may give the wrong result due to a // suspected linker bug when compiling Google Test as a Mac OS X // framework. GTEST_API_ TypeId GetTestTypeId(); // Defines the abstract factory interface that creates instances // of a Test object. class TestFactoryBase { public: virtual ~TestFactoryBase() {} // Creates a test instance to run. The instance is both created and destroyed // within TestInfoImpl::Run() virtual Test* CreateTest() = 0; protected: TestFactoryBase() {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); }; // This class provides implementation of TeastFactoryBase interface. // It is used in TEST and TEST_F macros. template class TestFactoryImpl : public TestFactoryBase { public: Test* CreateTest() override { return new TestClass; } }; #if GTEST_OS_WINDOWS // Predicate-formatters for implementing the HRESULT checking macros // {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} // We pass a long instead of HRESULT to avoid causing an // include dependency for the HRESULT type. GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, long hr); // NOLINT GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, long hr); // NOLINT #endif // GTEST_OS_WINDOWS // Types of SetUpTestSuite() and TearDownTestSuite() functions. using SetUpTestSuiteFunc = void (*)(); using TearDownTestSuiteFunc = void (*)(); struct CodeLocation { CodeLocation(const std::string& a_file, int a_line) : file(a_file), line(a_line) {} std::string file; int line; }; // Helper to identify which setup function for TestCase / TestSuite to call. // Only one function is allowed, either TestCase or TestSute but not both. // Utility functions to help SuiteApiResolver using SetUpTearDownSuiteFuncType = void (*)(); inline SetUpTearDownSuiteFuncType GetNotDefaultOrNull( SetUpTearDownSuiteFuncType a, SetUpTearDownSuiteFuncType def) { return a == def ? nullptr : a; } template // Note that SuiteApiResolver inherits from T because // SetUpTestSuite()/TearDownTestSuite() could be protected. Ths way // SuiteApiResolver can access them. struct SuiteApiResolver : T { // testing::Test is only forward declared at this point. So we make it a // dependend class for the compiler to be OK with it. using Test = typename std::conditional::type; static SetUpTearDownSuiteFuncType GetSetUpCaseOrSuite(const char* filename, int line_num) { SetUpTearDownSuiteFuncType test_case_fp = GetNotDefaultOrNull(&T::SetUpTestCase, &Test::SetUpTestCase); SetUpTearDownSuiteFuncType test_suite_fp = GetNotDefaultOrNull(&T::SetUpTestSuite, &Test::SetUpTestSuite); GTEST_CHECK_(!test_case_fp || !test_suite_fp) << "Test can not provide both SetUpTestSuite and SetUpTestCase, please " "make sure there is only one present at " << filename << ":" << line_num; return test_case_fp != nullptr ? test_case_fp : test_suite_fp; } static SetUpTearDownSuiteFuncType GetTearDownCaseOrSuite(const char* filename, int line_num) { SetUpTearDownSuiteFuncType test_case_fp = GetNotDefaultOrNull(&T::TearDownTestCase, &Test::TearDownTestCase); SetUpTearDownSuiteFuncType test_suite_fp = GetNotDefaultOrNull(&T::TearDownTestSuite, &Test::TearDownTestSuite); GTEST_CHECK_(!test_case_fp || !test_suite_fp) << "Test can not provide both TearDownTestSuite and TearDownTestCase," " please make sure there is only one present at" << filename << ":" << line_num; return test_case_fp != nullptr ? test_case_fp : test_suite_fp; } }; // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // // test_suite_name: name of the test suite // name: name of the test // type_param the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param text representation of the test's value parameter, // or NULL if this is not a type-parameterized test. // code_location: code location where the test is defined // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test suite // tear_down_tc: pointer to the function that tears down the test suite // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. GTEST_API_ TestInfo* MakeAndRegisterTestInfo( const char* test_suite_name, const char* name, const char* type_param, const char* value_param, CodeLocation code_location, TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory); // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) // State of the definition of a type-parameterized test suite. class GTEST_API_ TypedTestSuitePState { public: TypedTestSuitePState() : registered_(false) {} // Adds the given test name to defined_test_names_ and return true // if the test suite hasn't been registered; otherwise aborts the // program. bool AddTestName(const char* file, int line, const char* case_name, const char* test_name) { if (registered_) { fprintf(stderr, "%s Test %s must be defined before " "REGISTER_TYPED_TEST_SUITE_P(%s, ...).\n", FormatFileLocation(file, line).c_str(), test_name, case_name); fflush(stderr); posix::Abort(); } registered_tests_.insert( ::std::make_pair(test_name, CodeLocation(file, line))); return true; } bool TestExists(const std::string& test_name) const { return registered_tests_.count(test_name) > 0; } const CodeLocation& GetCodeLocation(const std::string& test_name) const { RegisteredTestsMap::const_iterator it = registered_tests_.find(test_name); GTEST_CHECK_(it != registered_tests_.end()); return it->second; } // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. const char* VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests); private: typedef ::std::map RegisteredTestsMap; bool registered_; RegisteredTestsMap registered_tests_; }; // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ using TypedTestCasePState = TypedTestSuitePState; #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 // Skips to the first non-space char after the first comma in 'str'; // returns NULL if no comma is found in 'str'. inline const char* SkipComma(const char* str) { const char* comma = strchr(str, ','); if (comma == nullptr) { return nullptr; } while (IsSpace(*(++comma))) {} return comma; } // Returns the prefix of 'str' before the first comma in it; returns // the entire string if it contains no comma. inline std::string GetPrefixUntilComma(const char* str) { const char* comma = strchr(str, ','); return comma == nullptr ? str : std::string(str, comma); } // Splits a given string on a given delimiter, populating a given // vector with the fields. void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest); // The default argument to the template below for the case when the user does // not provide a name generator. struct DefaultNameGenerator { template static std::string GetName(int i) { return StreamableToString(i); } }; template struct NameGeneratorSelector { typedef Provided type; }; template void GenerateNamesRecursively(internal::None, std::vector*, int) {} template void GenerateNamesRecursively(Types, std::vector* result, int i) { result->push_back(NameGenerator::template GetName(i)); GenerateNamesRecursively(typename Types::Tail(), result, i + 1); } template std::vector GenerateNames() { std::vector result; GenerateNamesRecursively(Types(), &result, 0); return result; } // TypeParameterizedTest::Register() // registers a list of type-parameterized tests with Google Test. The // return value is insignificant - we just need to return something // such that we can call this function in a namespace scope. // // Implementation note: The GTEST_TEMPLATE_ macro declares a template // template parameter. It's defined in gtest-type-util.h. template class TypeParameterizedTest { public: // 'index' is the index of the test in the type list 'Types' // specified in INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, TestSuite, // Types). Valid values for 'index' are [0, N - 1] where N is the // length of Types. static bool Register(const char* prefix, const CodeLocation& code_location, const char* case_name, const char* test_names, int index, const std::vector& type_names = GenerateNames()) { typedef typename Types::Head Type; typedef Fixture FixtureClass; typedef typename GTEST_BIND_(TestSel, Type) TestClass; // First, registers the first type-parameterized test in the type // list. MakeAndRegisterTestInfo( (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/" + type_names[static_cast(index)]) .c_str(), StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(), GetTypeName().c_str(), nullptr, // No value parameter. code_location, GetTypeId(), SuiteApiResolver::GetSetUpCaseOrSuite( code_location.file.c_str(), code_location.line), SuiteApiResolver::GetTearDownCaseOrSuite( code_location.file.c_str(), code_location.line), new TestFactoryImpl); // Next, recurses (at compile time) with the tail of the type list. return TypeParameterizedTest::Register(prefix, code_location, case_name, test_names, index + 1, type_names); } }; // The base case for the compile time recursion. template class TypeParameterizedTest { public: static bool Register(const char* /*prefix*/, const CodeLocation&, const char* /*case_name*/, const char* /*test_names*/, int /*index*/, const std::vector& = std::vector() /*type_names*/) { return true; } }; // TypeParameterizedTestSuite::Register() // registers *all combinations* of 'Tests' and 'Types' with Google // Test. The return value is insignificant - we just need to return // something such that we can call this function in a namespace scope. template class TypeParameterizedTestSuite { public: static bool Register(const char* prefix, CodeLocation code_location, const TypedTestSuitePState* state, const char* case_name, const char* test_names, const std::vector& type_names = GenerateNames()) { std::string test_name = StripTrailingSpaces( GetPrefixUntilComma(test_names)); if (!state->TestExists(test_name)) { fprintf(stderr, "Failed to get code location for test %s.%s at %s.", case_name, test_name.c_str(), FormatFileLocation(code_location.file.c_str(), code_location.line).c_str()); fflush(stderr); posix::Abort(); } const CodeLocation& test_location = state->GetCodeLocation(test_name); typedef typename Tests::Head Head; // First, register the first test in 'Test' for each type in 'Types'. TypeParameterizedTest::Register( prefix, test_location, case_name, test_names, 0, type_names); // Next, recurses (at compile time) with the tail of the test list. return TypeParameterizedTestSuite::Register(prefix, code_location, state, case_name, SkipComma(test_names), type_names); } }; // The base case for the compile time recursion. template class TypeParameterizedTestSuite { public: static bool Register(const char* /*prefix*/, const CodeLocation&, const TypedTestSuitePState* /*state*/, const char* /*case_name*/, const char* /*test_names*/, const std::vector& = std::vector() /*type_names*/) { return true; } }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. GTEST_API_ std::string GetCurrentOsStackTraceExceptTop( UnitTest* unit_test, int skip_count); // Helpers for suppressing warnings on unreachable code or constant // condition. // Always returns true. GTEST_API_ bool AlwaysTrue(); // Always returns false. inline bool AlwaysFalse() { return !AlwaysTrue(); } // Helper for suppressing false warning from Clang on a const char* // variable declared in a conditional expression always being NULL in // the else branch. struct GTEST_API_ ConstCharPtr { ConstCharPtr(const char* str) : value(str) {} operator bool() const { return true; } const char* value; }; // Helper for declaring std::string within 'if' statement // in pre C++17 build environment. struct GTEST_API_ TrueWithString { TrueWithString() = default; explicit TrueWithString(const char* str) : value(str) {} explicit TrueWithString(const std::string& str) : value(str) {} explicit operator bool() const { return true; } std::string value; }; // A simple Linear Congruential Generator for generating random // numbers with a uniform distribution. Unlike rand() and srand(), it // doesn't use global state (and therefore can't interfere with user // code). Unlike rand_r(), it's portable. An LCG isn't very random, // but it's good enough for our purposes. class GTEST_API_ Random { public: static const UInt32 kMaxRange = 1u << 31; explicit Random(UInt32 seed) : state_(seed) {} void Reseed(UInt32 seed) { state_ = seed; } // Generates a random number from [0, range). Crashes if 'range' is // 0 or greater than kMaxRange. UInt32 Generate(UInt32 range); private: UInt32 state_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); }; // Turns const U&, U&, const U, and U all into U. #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ typename std::remove_const::type>::type // IsAProtocolMessage::value is a compile-time bool constant that's // true if and only if T is type proto2::Message or a subclass of it. template struct IsAProtocolMessage : public std::is_convertible {}; // When the compiler sees expression IsContainerTest(0), if C is an // STL-style container class, the first overload of IsContainerTest // will be viable (since both C::iterator* and C::const_iterator* are // valid types and NULL can be implicitly converted to them). It will // be picked over the second overload as 'int' is a perfect match for // the type of argument 0. If C::iterator or C::const_iterator is not // a valid type, the first overload is not viable, and the second // overload will be picked. Therefore, we can determine whether C is // a container class by checking the type of IsContainerTest(0). // The value of the expression is insignificant. // // In C++11 mode we check the existence of a const_iterator and that an // iterator is properly implemented for the container. // // For pre-C++11 that we look for both C::iterator and C::const_iterator. // The reason is that C++ injects the name of a class as a member of the // class itself (e.g. you can refer to class iterator as either // 'iterator' or 'iterator::iterator'). If we look for C::iterator // only, for example, we would mistakenly think that a class named // iterator is an STL container. // // Also note that the simpler approach of overloading // IsContainerTest(typename C::const_iterator*) and // IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. typedef int IsContainer; template ().begin()), class = decltype(::std::declval().end()), class = decltype(++::std::declval()), class = decltype(*::std::declval()), class = typename C::const_iterator> IsContainer IsContainerTest(int /* dummy */) { return 0; } typedef char IsNotContainer; template IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } // Trait to detect whether a type T is a hash table. // The heuristic used is that the type contains an inner type `hasher` and does // not contain an inner type `reverse_iterator`. // If the container is iterable in reverse, then order might actually matter. template struct IsHashTable { private: template static char test(typename U::hasher*, typename U::reverse_iterator*); template static int test(typename U::hasher*, ...); template static char test(...); public: static const bool value = sizeof(test(nullptr, nullptr)) == sizeof(int); }; template const bool IsHashTable::value; template (0)) == sizeof(IsContainer)> struct IsRecursiveContainerImpl; template struct IsRecursiveContainerImpl : public std::false_type {}; // Since the IsRecursiveContainerImpl depends on the IsContainerTest we need to // obey the same inconsistencies as the IsContainerTest, namely check if // something is a container is relying on only const_iterator in C++11 and // is relying on both const_iterator and iterator otherwise template struct IsRecursiveContainerImpl { using value_type = decltype(*std::declval()); using type = std::is_same::type>::type, C>; }; // IsRecursiveContainer is a unary compile-time predicate that // evaluates whether C is a recursive container type. A recursive container // type is a container type whose value_type is equal to the container type // itself. An example for a recursive container type is // boost::filesystem::path, whose iterator has a value_type that is equal to // boost::filesystem::path. template struct IsRecursiveContainer : public IsRecursiveContainerImpl::type {}; // Utilities for native arrays. // ArrayEq() compares two k-dimensional native arrays using the // elements' operator==, where k can be any integer >= 0. When k is // 0, ArrayEq() degenerates into comparing a single pair of values. template bool ArrayEq(const T* lhs, size_t size, const U* rhs); // This generic version is used when k is 0. template inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } // This overload is used when k >= 1. template inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { return internal::ArrayEq(lhs, N, rhs); } // This helper reduces code bloat. If we instead put its logic inside // the previous ArrayEq() function, arrays with different sizes would // lead to different copies of the template code. template bool ArrayEq(const T* lhs, size_t size, const U* rhs) { for (size_t i = 0; i != size; i++) { if (!internal::ArrayEq(lhs[i], rhs[i])) return false; } return true; } // Finds the first element in the iterator range [begin, end) that // equals elem. Element may be a native array type itself. template Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { for (Iter it = begin; it != end; ++it) { if (internal::ArrayEq(*it, elem)) return it; } return end; } // CopyArray() copies a k-dimensional native array using the elements' // operator=, where k can be any integer >= 0. When k is 0, // CopyArray() degenerates into copying a single value. template void CopyArray(const T* from, size_t size, U* to); // This generic version is used when k is 0. template inline void CopyArray(const T& from, U* to) { *to = from; } // This overload is used when k >= 1. template inline void CopyArray(const T(&from)[N], U(*to)[N]) { internal::CopyArray(from, N, *to); } // This helper reduces code bloat. If we instead put its logic inside // the previous CopyArray() function, arrays with different sizes // would lead to different copies of the template code. template void CopyArray(const T* from, size_t size, U* to) { for (size_t i = 0; i != size; i++) { internal::CopyArray(from[i], to + i); } } // The relation between an NativeArray object (see below) and the // native array it represents. // We use 2 different structs to allow non-copyable types to be used, as long // as RelationToSourceReference() is passed. struct RelationToSourceReference {}; struct RelationToSourceCopy {}; // Adapts a native array to a read-only STL-style container. Instead // of the complete STL container concept, this adaptor only implements // members useful for Google Mock's container matchers. New members // should be added as needed. To simplify the implementation, we only // support Element being a raw type (i.e. having no top-level const or // reference modifier). It's the client's responsibility to satisfy // this requirement. Element can be an array type itself (hence // multi-dimensional arrays are supported). template class NativeArray { public: // STL-style container typedefs. typedef Element value_type; typedef Element* iterator; typedef const Element* const_iterator; // Constructs from a native array. References the source. NativeArray(const Element* array, size_t count, RelationToSourceReference) { InitRef(array, count); } // Constructs from a native array. Copies the source. NativeArray(const Element* array, size_t count, RelationToSourceCopy) { InitCopy(array, count); } // Copy constructor. NativeArray(const NativeArray& rhs) { (this->*rhs.clone_)(rhs.array_, rhs.size_); } ~NativeArray() { if (clone_ != &NativeArray::InitRef) delete[] array_; } // STL-style container methods. size_t size() const { return size_; } const_iterator begin() const { return array_; } const_iterator end() const { return array_ + size_; } bool operator==(const NativeArray& rhs) const { return size() == rhs.size() && ArrayEq(begin(), size(), rhs.begin()); } private: static_assert(!std::is_const::value, "Type must not be const"); static_assert(!std::is_reference::value, "Type must not be a reference"); // Initializes this object with a copy of the input. void InitCopy(const Element* array, size_t a_size) { Element* const copy = new Element[a_size]; CopyArray(array, a_size, copy); array_ = copy; size_ = a_size; clone_ = &NativeArray::InitCopy; } // Initializes this object with a reference of the input. void InitRef(const Element* array, size_t a_size) { array_ = array; size_ = a_size; clone_ = &NativeArray::InitRef; } const Element* array_; size_t size_; void (NativeArray::*clone_)(const Element*, size_t); GTEST_DISALLOW_ASSIGN_(NativeArray); }; // Backport of std::index_sequence. template struct IndexSequence { using type = IndexSequence; }; // Double the IndexSequence, and one if plus_one is true. template struct DoubleSequence; template struct DoubleSequence, sizeofT> { using type = IndexSequence; }; template struct DoubleSequence, sizeofT> { using type = IndexSequence; }; // Backport of std::make_index_sequence. // It uses O(ln(N)) instantiation depth. template struct MakeIndexSequence : DoubleSequence::type, N / 2>::type {}; template <> struct MakeIndexSequence<0> : IndexSequence<> {}; template struct Ignore { Ignore(...); // NOLINT }; template struct ElemFromListImpl; template struct ElemFromListImpl> { // We make Ignore a template to solve a problem with MSVC. // A non-template Ignore would work fine with `decltype(Ignore(I))...`, but // MSVC doesn't understand how to deal with that pack expansion. // Use `0 * I` to have a single instantiation of Ignore. template static R Apply(Ignore<0 * I>..., R (*)(), ...); }; template struct ElemFromList { using type = decltype(ElemFromListImpl::type>::Apply( static_cast(nullptr)...)); }; template class FlatTuple; template struct FlatTupleElemBase; template struct FlatTupleElemBase, I> { using value_type = typename ElemFromList::type; FlatTupleElemBase() = default; explicit FlatTupleElemBase(value_type t) : value(std::move(t)) {} value_type value; }; template struct FlatTupleBase; template struct FlatTupleBase, IndexSequence> : FlatTupleElemBase, Idx>... { using Indices = IndexSequence; FlatTupleBase() = default; explicit FlatTupleBase(T... t) : FlatTupleElemBase, Idx>(std::move(t))... {} }; // Analog to std::tuple but with different tradeoffs. // This class minimizes the template instantiation depth, thus allowing more // elements that std::tuple would. std::tuple has been seen to require an // instantiation depth of more than 10x the number of elements in some // implementations. // FlatTuple and ElemFromList are not recursive and have a fixed depth // regardless of T... // MakeIndexSequence, on the other hand, it is recursive but with an // instantiation depth of O(ln(N)). template class FlatTuple : private FlatTupleBase, typename MakeIndexSequence::type> { using Indices = typename FlatTuple::FlatTupleBase::Indices; public: FlatTuple() = default; explicit FlatTuple(T... t) : FlatTuple::FlatTupleBase(std::move(t)...) {} template const typename ElemFromList::type& Get() const { return static_cast*>(this)->value; } template typename ElemFromList::type& Get() { return static_cast*>(this)->value; } }; // Utility functions to be called with static_assert to induce deprecation // warnings. GTEST_INTERNAL_DEPRECATED( "INSTANTIATE_TEST_CASE_P is deprecated, please use " "INSTANTIATE_TEST_SUITE_P") constexpr bool InstantiateTestCase_P_IsDeprecated() { return true; } GTEST_INTERNAL_DEPRECATED( "TYPED_TEST_CASE_P is deprecated, please use " "TYPED_TEST_SUITE_P") constexpr bool TypedTestCase_P_IsDeprecated() { return true; } GTEST_INTERNAL_DEPRECATED( "TYPED_TEST_CASE is deprecated, please use " "TYPED_TEST_SUITE") constexpr bool TypedTestCaseIsDeprecated() { return true; } GTEST_INTERNAL_DEPRECATED( "REGISTER_TYPED_TEST_CASE_P is deprecated, please use " "REGISTER_TYPED_TEST_SUITE_P") constexpr bool RegisterTypedTestCase_P_IsDeprecated() { return true; } GTEST_INTERNAL_DEPRECATED( "INSTANTIATE_TYPED_TEST_CASE_P is deprecated, please use " "INSTANTIATE_TYPED_TEST_SUITE_P") constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } } // namespace internal } // namespace testing #define GTEST_MESSAGE_AT_(file, line, message, result_type) \ ::testing::internal::AssertHelper(result_type, file, line, message) \ = ::testing::Message() #define GTEST_MESSAGE_(message, result_type) \ GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) #define GTEST_FATAL_FAILURE_(message) \ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) #define GTEST_NONFATAL_FAILURE_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) #define GTEST_SUCCESS_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) #define GTEST_SKIP_(message) \ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kSkip) // Suppress MSVC warning 4072 (unreachable code) for the code following // statement if it returns or throws (or doesn't return or throw in some // situations). #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ if (::testing::internal::AlwaysTrue()) { statement; } #define GTEST_TEST_THROW_(statement, expected_exception, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::ConstCharPtr gtest_msg = "") { \ bool gtest_caught_expected = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (expected_exception const&) { \ gtest_caught_expected = true; \ } \ catch (...) { \ gtest_msg.value = \ "Expected: " #statement " throws an exception of type " \ #expected_exception ".\n Actual: it throws a different type."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ } \ if (!gtest_caught_expected) { \ gtest_msg.value = \ "Expected: " #statement " throws an exception of type " \ #expected_exception ".\n Actual: it throws nothing."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ fail(gtest_msg.value) #if GTEST_HAS_EXCEPTIONS #define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \ catch (std::exception const& e) { \ gtest_msg.value = ( \ "it throws std::exception-derived exception with description: \"" \ ); \ gtest_msg.value += e.what(); \ gtest_msg.value += "\"."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ } #else // GTEST_HAS_EXCEPTIONS #define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() #endif // GTEST_HAS_EXCEPTIONS #define GTEST_TEST_NO_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::TrueWithString gtest_msg{}) { \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \ catch (...) { \ gtest_msg.value = "it throws."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ fail(("Expected: " #statement " doesn't throw an exception.\n" \ " Actual: " + gtest_msg.value).c_str()) #define GTEST_TEST_ANY_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ bool gtest_caught_any = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (...) { \ gtest_caught_any = true; \ } \ if (!gtest_caught_any) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ fail("Expected: " #statement " throws an exception.\n" \ " Actual: it doesn't.") // Implements Boolean test assertions such as EXPECT_TRUE. expression can be // either a boolean expression or an AssertionResult. text is a textual // represenation of expression as it was passed into the EXPECT_TRUE. #define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const ::testing::AssertionResult gtest_ar_ = \ ::testing::AssertionResult(expression)) \ ; \ else \ fail(::testing::internal::GetBoolAssertionFailureMessage(\ gtest_ar_, text, #actual, #expected).c_str()) #define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ fail("Expected: " #statement " doesn't generate new fatal " \ "failures in the current thread.\n" \ " Actual: it does.") // Expands to the name of the class that implements the given test. #define GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ test_suite_name##_##test_name##_Test // Helper macro for defining tests. #define GTEST_TEST_(test_suite_name, test_name, parent_class, parent_id) \ static_assert(sizeof(GTEST_STRINGIFY_(test_suite_name)) > 1, \ "test_suite_name must not be empty"); \ static_assert(sizeof(GTEST_STRINGIFY_(test_name)) > 1, \ "test_name must not be empty"); \ class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ : public parent_class { \ public: \ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ \ private: \ void TestBody() override; \ static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ test_name)); \ }; \ \ ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suite_name, \ test_name)::test_info_ = \ ::testing::internal::MakeAndRegisterTestInfo( \ #test_suite_name, #test_name, nullptr, nullptr, \ ::testing::internal::CodeLocation(__FILE__, __LINE__), (parent_id), \ ::testing::internal::SuiteApiResolver< \ parent_class>::GetSetUpCaseOrSuite(__FILE__, __LINE__), \ ::testing::internal::SuiteApiResolver< \ parent_class>::GetTearDownCaseOrSuite(__FILE__, __LINE__), \ new ::testing::internal::TestFactoryImpl); \ void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ openzwave-1.6.1914/cpp/test/include/gtest/internal/gtest-string.h0000644000175200017520000001563614032142455021664 00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // The Google C++ Testing and Mocking Framework (Google Test) // // This header file declares the String class and functions used internally by // Google Test. They are subject to change without notice. They should not used // by code external to Google Test. // // This header file is #included by gtest-internal.h. // It should not be #included by other files. // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #ifdef __BORLANDC__ // string.h is not guaranteed to provide strcpy on C++ Builder. # include #endif #include #include #include "gtest/internal/gtest-port.h" namespace testing { namespace internal { // String - an abstract class holding static string utilities. class GTEST_API_ String { public: // Static utility methods // Clones a 0-terminated C string, allocating memory using new. The // caller is responsible for deleting the return value using // delete[]. Returns the cloned string, or NULL if the input is // NULL. // // This is different from strdup() in string.h, which allocates // memory using malloc(). static const char* CloneCString(const char* c_str); #if GTEST_OS_WINDOWS_MOBILE // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be // able to pass strings to Win32 APIs on CE we need to convert them // to 'Unicode', UTF-16. // Creates a UTF-16 wide string from the given ANSI string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the wide string, or NULL if the // input is NULL. // // The wide string is created using the ANSI codepage (CP_ACP) to // match the behaviour of the ANSI versions of Win32 calls and the // C runtime. static LPCWSTR AnsiToUtf16(const char* c_str); // Creates an ANSI string from the given wide string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. // // The returned string is created using the ANSI codepage (CP_ACP) to // match the behaviour of the ANSI versions of Win32 calls and the // C runtime. static const char* Utf16ToAnsi(LPCWSTR utf16_str); #endif // Compares two C strings. Returns true if and only if they have the same // content. // // Unlike strcmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. static bool CStringEquals(const char* lhs, const char* rhs); // Converts a wide C string to a String using the UTF-8 encoding. // NULL will be converted to "(null)". If an error occurred during // the conversion, "(failed to convert from wide string)" is // returned. static std::string ShowWideCString(const wchar_t* wide_c_str); // Compares two wide C strings. Returns true if and only if they have the // same content. // // Unlike wcscmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); // Compares two C strings, ignoring case. Returns true if and only if // they have the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL C string, // including the empty string. static bool CaseInsensitiveCStringEquals(const char* lhs, const char* rhs); // Compares two wide C strings, ignoring case. Returns true if and only if // they have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, // including the empty string. // NB: The implementations on different platforms slightly differ. // On windows, this method uses _wcsicmp which compares according to LC_CTYPE // environment variable. On GNU platform this method uses wcscasecmp // which compares according to LC_CTYPE category of the current locale. // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the // current locale. static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); // Returns true if and only if the given string ends with the given suffix, // ignoring case. Any string is considered to end with an empty suffix. static bool EndsWithCaseInsensitive( const std::string& str, const std::string& suffix); // Formats an int value as "%02d". static std::string FormatIntWidth2(int value); // "%02d" for width == 2 // Formats an int value as "%X". static std::string FormatHexInt(int value); // Formats an int value as "%X". static std::string FormatHexUInt32(UInt32 value); // Formats a byte as "%02X". static std::string FormatByte(unsigned char value); private: String(); // Not meant to be instantiated. }; // class String // Gets the content of the stringstream's buffer as an std::string. Each '\0' // character in the buffer is replaced with "\\0". GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ openzwave-1.6.1914/cpp/test/include/gtest/internal/gtest-port-arch.h0000644000175200017520000000773114032142455022252 00000000000000// Copyright 2015, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the GTEST_OS_* macro. // It is separate from gtest-port.h so that custom/gtest-port.h can include it. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ // Determines the platform on which Google Test is compiled. #ifdef __CYGWIN__ # define GTEST_OS_CYGWIN 1 # elif defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__) # define GTEST_OS_WINDOWS_MINGW 1 # define GTEST_OS_WINDOWS 1 #elif defined _WIN32 # define GTEST_OS_WINDOWS 1 # ifdef _WIN32_WCE # define GTEST_OS_WINDOWS_MOBILE 1 # elif defined(WINAPI_FAMILY) # include # if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) # define GTEST_OS_WINDOWS_DESKTOP 1 # elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) # define GTEST_OS_WINDOWS_PHONE 1 # elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) # define GTEST_OS_WINDOWS_RT 1 # elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE) # define GTEST_OS_WINDOWS_PHONE 1 # define GTEST_OS_WINDOWS_TV_TITLE 1 # else // WINAPI_FAMILY defined but no known partition matched. // Default to desktop. # define GTEST_OS_WINDOWS_DESKTOP 1 # endif # else # define GTEST_OS_WINDOWS_DESKTOP 1 # endif // _WIN32_WCE #elif defined __OS2__ # define GTEST_OS_OS2 1 #elif defined __APPLE__ # define GTEST_OS_MAC 1 # if TARGET_OS_IPHONE # define GTEST_OS_IOS 1 # endif #elif defined __DragonFly__ # define GTEST_OS_DRAGONFLY 1 #elif defined __FreeBSD__ # define GTEST_OS_FREEBSD 1 #elif defined __Fuchsia__ # define GTEST_OS_FUCHSIA 1 #elif defined(__GLIBC__) && defined(__FreeBSD_kernel__) # define GTEST_OS_GNU_KFREEBSD 1 #elif defined __linux__ # define GTEST_OS_LINUX 1 # if defined __ANDROID__ # define GTEST_OS_LINUX_ANDROID 1 # endif #elif defined __MVS__ # define GTEST_OS_ZOS 1 #elif defined(__sun) && defined(__SVR4) # define GTEST_OS_SOLARIS 1 #elif defined(_AIX) # define GTEST_OS_AIX 1 #elif defined(__hpux) # define GTEST_OS_HPUX 1 #elif defined __native_client__ # define GTEST_OS_NACL 1 #elif defined __NetBSD__ # define GTEST_OS_NETBSD 1 #elif defined __OpenBSD__ # define GTEST_OS_OPENBSD 1 #elif defined __QNX__ # define GTEST_OS_QNX 1 #elif defined(__HAIKU__) #define GTEST_OS_HAIKU 1 #elif defined ESP8266 #define GTEST_OS_ESP8266 1 #elif defined ESP32 #define GTEST_OS_ESP32 1 #endif // __CYGWIN__ #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ openzwave-1.6.1914/cpp/test/include/gtest/internal/gtest-port.h0000644000175200017520000023310614032142455021334 00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Low-level types and utilities for porting Google Test to various // platforms. All macros ending with _ and symbols defined in an // internal namespace are subject to change without notice. Code // outside Google Test MUST NOT USE THEM DIRECTLY. Macros that don't // end with _ are part of Google Test's public API and can be used by // code outside Google Test. // // This file is fundamental to Google Test. All other Google Test source // files are expected to #include this. Therefore, it cannot #include // any other Google Test header. // GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ // Environment-describing macros // ----------------------------- // // Google Test can be used in many different environments. Macros in // this section tell Google Test what kind of environment it is being // used in, such that Google Test can provide environment-specific // features and implementations. // // Google Test tries to automatically detect the properties of its // environment, so users usually don't need to worry about these // macros. However, the automatic detection is not perfect. // Sometimes it's necessary for a user to define some of the following // macros in the build script to override Google Test's decisions. // // If the user doesn't define a macro in the list, Google Test will // provide a default definition. After this header is #included, all // macros in this list will be defined to either 1 or 0. // // Notes to maintainers: // - Each macro here is a user-tweakable knob; do not grow the list // lightly. // - Use #if to key off these macros. Don't use #ifdef or "#if // defined(...)", which will not work as these macros are ALWAYS // defined. // // GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) // is/isn't available. // GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions // are enabled. // GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular // expressions are/aren't available. // GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that // is/isn't available. // GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't // enabled. // GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that // std::wstring does/doesn't work (Google Test can // be used where std::wstring is unavailable). // GTEST_HAS_SEH - Define it to 1/0 to indicate whether the // compiler supports Microsoft's "Structured // Exception Handling". // GTEST_HAS_STREAM_REDIRECTION // - Define it to 1/0 to indicate whether the // platform supports I/O stream redirection using // dup() and dup2(). // GTEST_LINKED_AS_SHARED_LIBRARY // - Define to 1 when compiling tests that use // Google Test as a shared library (known as // DLL on Windows). // GTEST_CREATE_SHARED_LIBRARY // - Define to 1 when compiling Google Test itself // as a shared library. // GTEST_DEFAULT_DEATH_TEST_STYLE // - The default value of --gtest_death_test_style. // The legacy default has been "fast" in the open // source version since 2008. The recommended value // is "threadsafe", and can be set in // custom/gtest-port.h. // Platform-indicating macros // -------------------------- // // Macros indicating the platform on which Google Test is being used // (a macro is defined to 1 if compiled on the given platform; // otherwise UNDEFINED -- it's never defined to 0.). Google Test // defines these macros automatically. Code outside Google Test MUST // NOT define them. // // GTEST_OS_AIX - IBM AIX // GTEST_OS_CYGWIN - Cygwin // GTEST_OS_DRAGONFLY - DragonFlyBSD // GTEST_OS_FREEBSD - FreeBSD // GTEST_OS_FUCHSIA - Fuchsia // GTEST_OS_GNU_KFREEBSD - GNU/kFreeBSD // GTEST_OS_HAIKU - Haiku // GTEST_OS_HPUX - HP-UX // GTEST_OS_LINUX - Linux // GTEST_OS_LINUX_ANDROID - Google Android // GTEST_OS_MAC - Mac OS X // GTEST_OS_IOS - iOS // GTEST_OS_NACL - Google Native Client (NaCl) // GTEST_OS_NETBSD - NetBSD // GTEST_OS_OPENBSD - OpenBSD // GTEST_OS_OS2 - OS/2 // GTEST_OS_QNX - QNX // GTEST_OS_SOLARIS - Sun Solaris // GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) // GTEST_OS_WINDOWS_DESKTOP - Windows Desktop // GTEST_OS_WINDOWS_MINGW - MinGW // GTEST_OS_WINDOWS_MOBILE - Windows Mobile // GTEST_OS_WINDOWS_PHONE - Windows Phone // GTEST_OS_WINDOWS_RT - Windows Store App/WinRT // GTEST_OS_ZOS - z/OS // // Among the platforms, Cygwin, Linux, Mac OS X, and Windows have the // most stable support. Since core members of the Google Test project // don't have access to other platforms, support for them may be less // stable. If you notice any problems on your platform, please notify // googletestframework@googlegroups.com (patches for fixing them are // even more welcome!). // // It is possible that none of the GTEST_OS_* macros are defined. // Feature-indicating macros // ------------------------- // // Macros indicating which Google Test features are available (a macro // is defined to 1 if the corresponding feature is supported; // otherwise UNDEFINED -- it's never defined to 0.). Google Test // defines these macros automatically. Code outside Google Test MUST // NOT define them. // // These macros are public so that portable tests can be written. // Such tests typically surround code using a feature with an #if // which controls that code. For example: // // #if GTEST_HAS_DEATH_TEST // EXPECT_DEATH(DoSomethingDeadly()); // #endif // // GTEST_HAS_DEATH_TEST - death tests // GTEST_HAS_TYPED_TEST - typed tests // GTEST_HAS_TYPED_TEST_P - type-parameterized tests // GTEST_IS_THREADSAFE - Google Test is thread-safe. // GOOGLETEST_CM0007 DO NOT DELETE // GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with // GTEST_HAS_POSIX_RE (see above) which users can // define themselves. // GTEST_USES_SIMPLE_RE - our own simple regex is used; // the above RE\b(s) are mutually exclusive. // Misc public macros // ------------------ // // GTEST_FLAG(flag_name) - references the variable corresponding to // the given Google Test flag. // Internal utilities // ------------------ // // The following macros and utilities are for Google Test's INTERNAL // use only. Code outside Google Test MUST NOT USE THEM DIRECTLY. // // Macros for basic C++ coding: // GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. // GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a // variable don't have to be used. // GTEST_DISALLOW_ASSIGN_ - disables operator=. // GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. // GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. // GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is // suppressed (constant conditional). // GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 // is suppressed. // // Synchronization: // Mutex, MutexLock, ThreadLocal, GetThreadCount() // - synchronization primitives. // // Regular expressions: // RE - a simple regular expression class using the POSIX // Extended Regular Expression syntax on UNIX-like platforms // GOOGLETEST_CM0008 DO NOT DELETE // or a reduced regular exception syntax on other // platforms, including Windows. // Logging: // GTEST_LOG_() - logs messages at the specified severity level. // LogToStderr() - directs all log messages to stderr. // FlushInfoLog() - flushes informational log messages. // // Stdout and stderr capturing: // CaptureStdout() - starts capturing stdout. // GetCapturedStdout() - stops capturing stdout and returns the captured // string. // CaptureStderr() - starts capturing stderr. // GetCapturedStderr() - stops capturing stderr and returns the captured // string. // // Integer types: // TypeWithSize - maps an integer to a int type. // Int32, UInt32, Int64, UInt64, TimeInMillis // - integers of known sizes. // BiggestInt - the biggest signed integer type. // // Command-line utilities: // GTEST_DECLARE_*() - declares a flag. // GTEST_DEFINE_*() - defines a flag. // GetInjectableArgvs() - returns the command line as a vector of strings. // // Environment variable utilities: // GetEnv() - gets the value of an environment variable. // BoolFromGTestEnv() - parses a bool environment variable. // Int32FromGTestEnv() - parses an Int32 environment variable. // StringFromGTestEnv() - parses a string environment variable. // // Deprecation warnings: // GTEST_INTERNAL_DEPRECATED(message) - attribute marking a function as // deprecated; calling a marked function // should generate a compiler warning #include // for isspace, etc #include // for ptrdiff_t #include #include #include #include #ifndef _WIN32_WCE # include # include #endif // !_WIN32_WCE #if defined __APPLE__ # include # include #endif #include // NOLINT #include #include // NOLINT #include #include // NOLINT #include "gtest/internal/custom/gtest-port.h" #include "gtest/internal/gtest-port-arch.h" #if !defined(GTEST_DEV_EMAIL_) # define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" # define GTEST_FLAG_PREFIX_ "gtest_" # define GTEST_FLAG_PREFIX_DASH_ "gtest-" # define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" # define GTEST_NAME_ "Google Test" # define GTEST_PROJECT_URL_ "https://github.com/google/googletest/" #endif // !defined(GTEST_DEV_EMAIL_) #if !defined(GTEST_INIT_GOOGLE_TEST_NAME_) # define GTEST_INIT_GOOGLE_TEST_NAME_ "testing::InitGoogleTest" #endif // !defined(GTEST_INIT_GOOGLE_TEST_NAME_) // Determines the version of gcc that is used to compile this. #ifdef __GNUC__ // 40302 means version 4.3.2. # define GTEST_GCC_VER_ \ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) #endif // __GNUC__ // Macros for disabling Microsoft Visual C++ warnings. // // GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385) // /* code that triggers warnings C4800 and C4385 */ // GTEST_DISABLE_MSC_WARNINGS_POP_() #if defined(_MSC_VER) # define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \ __pragma(warning(push)) \ __pragma(warning(disable: warnings)) # define GTEST_DISABLE_MSC_WARNINGS_POP_() \ __pragma(warning(pop)) #else // Not all compilers are MSVC # define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) # define GTEST_DISABLE_MSC_WARNINGS_POP_() #endif // Clang on Windows does not understand MSVC's pragma warning. // We need clang-specific way to disable function deprecation warning. #ifdef __clang__ # define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \ _Pragma("clang diagnostic ignored \"-Wdeprecated-implementations\"") #define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ _Pragma("clang diagnostic pop") #else # define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) # define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ GTEST_DISABLE_MSC_WARNINGS_POP_() #endif // Brings in definitions for functions used in the testing::internal::posix // namespace (read, write, close, chdir, isatty, stat). We do not currently // use them on Windows Mobile. #if GTEST_OS_WINDOWS # if !GTEST_OS_WINDOWS_MOBILE # include # include # endif // In order to avoid having to include , use forward declaration #if GTEST_OS_WINDOWS_MINGW && !defined(__MINGW64_VERSION_MAJOR) // MinGW defined _CRITICAL_SECTION and _RTL_CRITICAL_SECTION as two // separate (equivalent) structs, instead of using typedef typedef struct _CRITICAL_SECTION GTEST_CRITICAL_SECTION; #else // Assume CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION. // This assumption is verified by // WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION. typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; #endif #else // This assumes that non-Windows OSes provide unistd.h. For OSes where this // is not the case, we need to include headers that provide the functions // mentioned above. # include # include #endif // GTEST_OS_WINDOWS #if GTEST_OS_LINUX_ANDROID // Used to define __ANDROID_API__ matching the target NDK API level. # include // NOLINT #endif // Defines this to true if and only if Google Test can use POSIX regular // expressions. #ifndef GTEST_HAS_POSIX_RE # if GTEST_OS_LINUX_ANDROID // On Android, is only available starting with Gingerbread. # define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9) # else # define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) # endif #endif #if GTEST_USES_PCRE // The appropriate headers have already been included. #elif GTEST_HAS_POSIX_RE // On some platforms, needs someone to define size_t, and // won't compile otherwise. We can #include it here as we already // included , which is guaranteed to define size_t through // . # include // NOLINT # define GTEST_USES_POSIX_RE 1 #elif GTEST_OS_WINDOWS // is not available on Windows. Use our own simple regex // implementation instead. # define GTEST_USES_SIMPLE_RE 1 #else // may not be available on this platform. Use our own // simple regex implementation instead. # define GTEST_USES_SIMPLE_RE 1 #endif // GTEST_USES_PCRE #ifndef GTEST_HAS_EXCEPTIONS // The user didn't tell us whether exceptions are enabled, so we need // to figure it out. # if defined(_MSC_VER) && defined(_CPPUNWIND) // MSVC defines _CPPUNWIND to 1 if and only if exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__BORLANDC__) // C++Builder's implementation of the STL uses the _HAS_EXCEPTIONS // macro to enable exceptions, so we'll do the same. // Assumes that exceptions are enabled by default. # ifndef _HAS_EXCEPTIONS # define _HAS_EXCEPTIONS 1 # endif // _HAS_EXCEPTIONS # define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS # elif defined(__clang__) // clang defines __EXCEPTIONS if and only if exceptions are enabled before clang // 220714, but if and only if cleanups are enabled after that. In Obj-C++ files, // there can be cleanups for ObjC exceptions which also need cleanups, even if // C++ exceptions are disabled. clang has __has_feature(cxx_exceptions) which // checks for C++ exceptions starting at clang r206352, but which checked for // cleanups prior to that. To reliably check for C++ exception availability with // clang, check for // __EXCEPTIONS && __has_feature(cxx_exceptions). # define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions)) # elif defined(__GNUC__) && __EXCEPTIONS // gcc defines __EXCEPTIONS to 1 if and only if exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__SUNPRO_CC) // Sun Pro CC supports exceptions. However, there is no compile-time way of // detecting whether they are enabled or not. Therefore, we assume that // they are enabled unless the user tells us otherwise. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__IBMCPP__) && __EXCEPTIONS // xlC defines __EXCEPTIONS to 1 if and only if exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__HP_aCC) // Exception handling is in effect by default in HP aCC compiler. It has to // be turned of by +noeh compiler option if desired. # define GTEST_HAS_EXCEPTIONS 1 # else // For other compilers, we assume exceptions are disabled to be // conservative. # define GTEST_HAS_EXCEPTIONS 0 # endif // defined(_MSC_VER) || defined(__BORLANDC__) #endif // GTEST_HAS_EXCEPTIONS #ifndef GTEST_HAS_STD_WSTRING // The user didn't tell us whether ::std::wstring is available, so we need // to figure it out. // Cygwin 1.7 and below doesn't support ::std::wstring. // Solaris' libc++ doesn't support it either. Android has // no support for it at least as recent as Froyo (2.2). #define GTEST_HAS_STD_WSTRING \ (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ GTEST_OS_HAIKU || GTEST_OS_ESP32 || GTEST_OS_ESP8266)) #endif // GTEST_HAS_STD_WSTRING // Determines whether RTTI is available. #ifndef GTEST_HAS_RTTI // The user didn't tell us whether RTTI is enabled, so we need to // figure it out. # ifdef _MSC_VER #ifdef _CPPRTTI // MSVC defines this macro if and only if RTTI is enabled. # define GTEST_HAS_RTTI 1 # else # define GTEST_HAS_RTTI 0 # endif // Starting with version 4.3.2, gcc defines __GXX_RTTI if and only if RTTI is // enabled. # elif defined(__GNUC__) # ifdef __GXX_RTTI // When building against STLport with the Android NDK and with // -frtti -fno-exceptions, the build fails at link time with undefined // references to __cxa_bad_typeid. Note sure if STL or toolchain bug, // so disable RTTI when detected. # if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \ !defined(__EXCEPTIONS) # define GTEST_HAS_RTTI 0 # else # define GTEST_HAS_RTTI 1 # endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS # else # define GTEST_HAS_RTTI 0 # endif // __GXX_RTTI // Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends // using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the // first version with C++ support. # elif defined(__clang__) # define GTEST_HAS_RTTI __has_feature(cxx_rtti) // Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if // both the typeid and dynamic_cast features are present. # elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) # ifdef __RTTI_ALL__ # define GTEST_HAS_RTTI 1 # else # define GTEST_HAS_RTTI 0 # endif # else // For all other compilers, we assume RTTI is enabled. # define GTEST_HAS_RTTI 1 # endif // _MSC_VER #endif // GTEST_HAS_RTTI // It's this header's responsibility to #include when RTTI // is enabled. #if GTEST_HAS_RTTI # include #endif // Determines whether Google Test can use the pthreads library. #ifndef GTEST_HAS_PTHREAD // The user didn't tell us explicitly, so we make reasonable assumptions about // which platforms have pthreads support. // // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // to your compiler flags. #define GTEST_HAS_PTHREAD \ (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX || \ GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \ GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_OPENBSD || \ GTEST_OS_HAIKU) #endif // GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD // gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is // true. # include // NOLINT // For timespec and nanosleep, used below. # include // NOLINT #endif // Determines whether clone(2) is supported. // Usually it will only be available on Linux, excluding // Linux on the Itanium architecture. // Also see http://linux.die.net/man/2/clone. #ifndef GTEST_HAS_CLONE // The user didn't tell us, so we need to figure it out. # if GTEST_OS_LINUX && !defined(__ia64__) # if GTEST_OS_LINUX_ANDROID // On Android, clone() became available at different API levels for each 32-bit // architecture. # if defined(__LP64__) || \ (defined(__arm__) && __ANDROID_API__ >= 9) || \ (defined(__mips__) && __ANDROID_API__ >= 12) || \ (defined(__i386__) && __ANDROID_API__ >= 17) # define GTEST_HAS_CLONE 1 # else # define GTEST_HAS_CLONE 0 # endif # else # define GTEST_HAS_CLONE 1 # endif # else # define GTEST_HAS_CLONE 0 # endif // GTEST_OS_LINUX && !defined(__ia64__) #endif // GTEST_HAS_CLONE // Determines whether to support stream redirection. This is used to test // output correctness and to implement death tests. #ifndef GTEST_HAS_STREAM_REDIRECTION // By default, we assume that stream redirection is supported on all // platforms except known mobile ones. #if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \ GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 # define GTEST_HAS_STREAM_REDIRECTION 0 # else # define GTEST_HAS_STREAM_REDIRECTION 1 # endif // !GTEST_OS_WINDOWS_MOBILE #endif // GTEST_HAS_STREAM_REDIRECTION // Determines whether to support death tests. // pops up a dialog window that cannot be suppressed programmatically. #if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ (GTEST_OS_MAC && !GTEST_OS_IOS) || \ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER) || GTEST_OS_WINDOWS_MINGW || \ GTEST_OS_AIX || GTEST_OS_HPUX || GTEST_OS_OPENBSD || GTEST_OS_QNX || \ GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \ GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_HAIKU) # define GTEST_HAS_DEATH_TEST 1 #endif // Determines whether to support type-driven tests. // Typed tests need and variadic macros, which GCC, VC++ 8.0, // Sun Pro CC, IBM Visual Age, and HP aCC support. #if defined(__GNUC__) || defined(_MSC_VER) || defined(__SUNPRO_CC) || \ defined(__IBMCPP__) || defined(__HP_aCC) # define GTEST_HAS_TYPED_TEST 1 # define GTEST_HAS_TYPED_TEST_P 1 #endif // Determines whether the system compiler uses UTF-16 for encoding wide strings. #define GTEST_WIDE_STRING_USES_UTF16_ \ (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_AIX || GTEST_OS_OS2) // Determines whether test results can be streamed to a socket. #if GTEST_OS_LINUX || GTEST_OS_GNU_KFREEBSD || GTEST_OS_DRAGONFLY || \ GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_OPENBSD # define GTEST_CAN_STREAM_RESULTS_ 1 #endif // Defines some utility macros. // The GNU compiler emits a warning if nested "if" statements are followed by // an "else" statement and braces are not used to explicitly disambiguate the // "else" binding. This leads to problems with code like: // // if (gate) // ASSERT_*(condition) << "Some message"; // // The "switch (0) case 0:" idiom is used to suppress this. #ifdef __INTEL_COMPILER # define GTEST_AMBIGUOUS_ELSE_BLOCKER_ #else # define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT #endif // Use this annotation at the end of a struct/class definition to // prevent the compiler from optimizing away instances that are never // used. This is useful when all interesting logic happens inside the // c'tor and / or d'tor. Example: // // struct Foo { // Foo() { ... } // } GTEST_ATTRIBUTE_UNUSED_; // // Also use it after a variable or parameter declaration to tell the // compiler the variable/parameter does not have to be used. #if defined(__GNUC__) && !defined(COMPILER_ICC) # define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) #elif defined(__clang__) # if __has_attribute(unused) # define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) # endif #endif #ifndef GTEST_ATTRIBUTE_UNUSED_ # define GTEST_ATTRIBUTE_UNUSED_ #endif // Use this annotation before a function that takes a printf format string. #if (defined(__GNUC__) || defined(__clang__)) && !defined(COMPILER_ICC) # if defined(__MINGW_PRINTF_FORMAT) // MinGW has two different printf implementations. Ensure the format macro // matches the selected implementation. See // https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/. # define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ __attribute__((__format__(__MINGW_PRINTF_FORMAT, string_index, \ first_to_check))) # else # define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ __attribute__((__format__(__printf__, string_index, first_to_check))) # endif #else # define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) #endif // A macro to disallow operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_ASSIGN_(type) \ void operator=(type const &) = delete // A macro to disallow copy constructor and operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_COPY_AND_ASSIGN_(type) \ type(type const &) = delete; \ GTEST_DISALLOW_ASSIGN_(type) // Tell the compiler to warn about unused return values for functions declared // with this macro. The macro should be used on function declarations // following the argument list: // // Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; #if defined(__GNUC__) && !defined(COMPILER_ICC) # define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) #else # define GTEST_MUST_USE_RESULT_ #endif // __GNUC__ && !COMPILER_ICC // MS C++ compiler emits warning when a conditional expression is compile time // constant. In some contexts this warning is false positive and needs to be // suppressed. Use the following two macros in such cases: // // GTEST_INTENTIONAL_CONST_COND_PUSH_() // while (true) { // GTEST_INTENTIONAL_CONST_COND_POP_() // } # define GTEST_INTENTIONAL_CONST_COND_PUSH_() \ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127) # define GTEST_INTENTIONAL_CONST_COND_POP_() \ GTEST_DISABLE_MSC_WARNINGS_POP_() // Determine whether the compiler supports Microsoft's Structured Exception // Handling. This is supported by several Windows compilers but generally // does not exist on any other system. #ifndef GTEST_HAS_SEH // The user didn't tell us, so we need to figure it out. # if defined(_MSC_VER) || defined(__BORLANDC__) // These two compilers are known to support SEH. # define GTEST_HAS_SEH 1 # else // Assume no SEH. # define GTEST_HAS_SEH 0 # endif #endif // GTEST_HAS_SEH #ifndef GTEST_IS_THREADSAFE #define GTEST_IS_THREADSAFE \ (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ || \ (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) || \ GTEST_HAS_PTHREAD) #endif // GTEST_IS_THREADSAFE // GTEST_API_ qualifies all symbols that must be exported. The definitions below // are guarded by #ifndef to give embedders a chance to define GTEST_API_ in // gtest/internal/custom/gtest-port.h #ifndef GTEST_API_ #ifdef _MSC_VER # if GTEST_LINKED_AS_SHARED_LIBRARY # define GTEST_API_ __declspec(dllimport) # elif GTEST_CREATE_SHARED_LIBRARY # define GTEST_API_ __declspec(dllexport) # endif #elif __GNUC__ >= 4 || defined(__clang__) # define GTEST_API_ __attribute__((visibility ("default"))) #endif // _MSC_VER #endif // GTEST_API_ #ifndef GTEST_API_ # define GTEST_API_ #endif // GTEST_API_ #ifndef GTEST_DEFAULT_DEATH_TEST_STYLE # define GTEST_DEFAULT_DEATH_TEST_STYLE "fast" #endif // GTEST_DEFAULT_DEATH_TEST_STYLE #ifdef __GNUC__ // Ask the compiler to never inline a given function. # define GTEST_NO_INLINE_ __attribute__((noinline)) #else # define GTEST_NO_INLINE_ #endif // _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. #if !defined(GTEST_HAS_CXXABI_H_) # if defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && !defined(_MSC_VER)) # define GTEST_HAS_CXXABI_H_ 1 # else # define GTEST_HAS_CXXABI_H_ 0 # endif #endif // A function level attribute to disable checking for use of uninitialized // memory when built with MemorySanitizer. #if defined(__clang__) # if __has_feature(memory_sanitizer) # define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ \ __attribute__((no_sanitize_memory)) # else # define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ # endif // __has_feature(memory_sanitizer) #else # define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ #endif // __clang__ // A function level attribute to disable AddressSanitizer instrumentation. #if defined(__clang__) # if __has_feature(address_sanitizer) # define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ \ __attribute__((no_sanitize_address)) # else # define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ # endif // __has_feature(address_sanitizer) #else # define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ #endif // __clang__ // A function level attribute to disable HWAddressSanitizer instrumentation. #if defined(__clang__) # if __has_feature(hwaddress_sanitizer) # define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ \ __attribute__((no_sanitize("hwaddress"))) # else # define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ # endif // __has_feature(hwaddress_sanitizer) #else # define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ #endif // __clang__ // A function level attribute to disable ThreadSanitizer instrumentation. #if defined(__clang__) # if __has_feature(thread_sanitizer) # define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ \ __attribute__((no_sanitize_thread)) # else # define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ # endif // __has_feature(thread_sanitizer) #else # define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ #endif // __clang__ namespace testing { class Message; // Legacy imports for backwards compatibility. // New code should use std:: names directly. using std::get; using std::make_tuple; using std::tuple; using std::tuple_element; using std::tuple_size; namespace internal { // A secret type that Google Test users don't know about. It has no // definition on purpose. Therefore it's impossible to create a // Secret object, which is what we want. class Secret; // The GTEST_COMPILE_ASSERT_ is a legacy macro used to verify that a compile // time expression is true (in new code, use static_assert instead). For // example, you could use it to verify the size of a static array: // // GTEST_COMPILE_ASSERT_(GTEST_ARRAY_SIZE_(names) == NUM_NAMES, // names_incorrect_size); // // The second argument to the macro must be a valid C++ identifier. If the // expression is false, compiler will issue an error containing this identifier. #define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg) // A helper for suppressing warnings on constant condition. It just // returns 'condition'. GTEST_API_ bool IsTrue(bool condition); // Defines RE. #if GTEST_USES_PCRE // if used, PCRE is injected by custom/gtest-port.h #elif GTEST_USES_POSIX_RE || GTEST_USES_SIMPLE_RE // A simple C++ wrapper for . It uses the POSIX Extended // Regular Expression syntax. class GTEST_API_ RE { public: // A copy constructor is required by the Standard to initialize object // references from r-values. RE(const RE& other) { Init(other.pattern()); } // Constructs an RE from a string. RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT RE(const char* regex) { Init(regex); } // NOLINT ~RE(); // Returns the string representation of the regex. const char* pattern() const { return pattern_; } // FullMatch(str, re) returns true if and only if regular expression re // matches the entire str. // PartialMatch(str, re) returns true if and only if regular expression re // matches a substring of str (including str itself). static bool FullMatch(const ::std::string& str, const RE& re) { return FullMatch(str.c_str(), re); } static bool PartialMatch(const ::std::string& str, const RE& re) { return PartialMatch(str.c_str(), re); } static bool FullMatch(const char* str, const RE& re); static bool PartialMatch(const char* str, const RE& re); private: void Init(const char* regex); const char* pattern_; bool is_valid_; # if GTEST_USES_POSIX_RE regex_t full_regex_; // For FullMatch(). regex_t partial_regex_; // For PartialMatch(). # else // GTEST_USES_SIMPLE_RE const char* full_pattern_; // For FullMatch(); # endif GTEST_DISALLOW_ASSIGN_(RE); }; #endif // GTEST_USES_PCRE // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); // Formats a file location for compiler-independent XML output. // Although this function is not platform dependent, we put it next to // FormatFileLocation in order to contrast the two functions. GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, int line); // Defines logging utilities: // GTEST_LOG_(severity) - logs messages at the specified severity level. The // message itself is streamed into the macro. // LogToStderr() - directs all log messages to stderr. // FlushInfoLog() - flushes informational log messages. enum GTestLogSeverity { GTEST_INFO, GTEST_WARNING, GTEST_ERROR, GTEST_FATAL }; // Formats log entry severity, provides a stream object for streaming the // log message, and terminates the message with a newline when going out of // scope. class GTEST_API_ GTestLog { public: GTestLog(GTestLogSeverity severity, const char* file, int line); // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. ~GTestLog(); ::std::ostream& GetStream() { return ::std::cerr; } private: const GTestLogSeverity severity_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); }; #if !defined(GTEST_LOG_) # define GTEST_LOG_(severity) \ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ __FILE__, __LINE__).GetStream() inline void LogToStderr() {} inline void FlushInfoLog() { fflush(nullptr); } #endif // !defined(GTEST_LOG_) #if !defined(GTEST_CHECK_) // INTERNAL IMPLEMENTATION - DO NOT USE. // // GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition // is not satisfied. // Synopsys: // GTEST_CHECK_(boolean_condition); // or // GTEST_CHECK_(boolean_condition) << "Additional message"; // // This checks the condition and if the condition is not satisfied // it prints message about the condition violation, including the // condition itself, plus additional message streamed into it, if any, // and then it aborts the program. It aborts the program irrespective of // whether it is built in the debug mode or not. # define GTEST_CHECK_(condition) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::IsTrue(condition)) \ ; \ else \ GTEST_LOG_(FATAL) << "Condition " #condition " failed. " #endif // !defined(GTEST_CHECK_) // An all-mode assert to verify that the given POSIX-style function // call returns 0 (indicating success). Known limitation: this // doesn't expand to a balanced 'if' statement, so enclose the macro // in {} if you need to use it as the only statement in an 'if' // branch. #define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ if (const int gtest_error = (posix_call)) \ GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ << gtest_error // Transforms "T" into "const T&" according to standard reference collapsing // rules (this is only needed as a backport for C++98 compilers that do not // support reference collapsing). Specifically, it transforms: // // char ==> const char& // const char ==> const char& // char& ==> char& // const char& ==> const char& // // Note that the non-const reference will not have "const" added. This is // standard, and necessary so that "T" can always bind to "const T&". template struct ConstRef { typedef const T& type; }; template struct ConstRef { typedef T& type; }; // The argument T must depend on some template parameters. #define GTEST_REFERENCE_TO_CONST_(T) \ typename ::testing::internal::ConstRef::type // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Use ImplicitCast_ as a safe version of static_cast for upcasting in // the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a // const Foo*). When you use ImplicitCast_, the compiler checks that // the cast is safe. Such explicit ImplicitCast_s are necessary in // surprisingly many situations where C++ demands an exact type match // instead of an argument type convertable to a target type. // // The syntax for using ImplicitCast_ is the same as for static_cast: // // ImplicitCast_(expr) // // ImplicitCast_ would have been part of the C++ standard library, // but the proposal was submitted too late. It will probably make // its way into the language in the future. // // This relatively ugly name is intentional. It prevents clashes with // similar functions users may have (e.g., implicit_cast). The internal // namespace alone is not enough because the function can be found by ADL. template inline To ImplicitCast_(To x) { return x; } // When you upcast (that is, cast a pointer from type Foo to type // SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts // always succeed. When you downcast (that is, cast a pointer from // type Foo to type SubclassOfFoo), static_cast<> isn't safe, because // how do you know the pointer is really of type SubclassOfFoo? It // could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, // when you downcast, you should use this macro. In debug mode, we // use dynamic_cast<> to double-check the downcast is legal (we die // if it's not). In normal mode, we do the efficient static_cast<> // instead. Thus, it's important to test in debug mode to make sure // the cast is legal! // This is the only place in the code we should use dynamic_cast<>. // In particular, you SHOULDN'T be using dynamic_cast<> in order to // do RTTI (eg code like this: // if (dynamic_cast(foo)) HandleASubclass1Object(foo); // if (dynamic_cast(foo)) HandleASubclass2Object(foo); // You should design the code some other way not to need this. // // This relatively ugly name is intentional. It prevents clashes with // similar functions users may have (e.g., down_cast). The internal // namespace alone is not enough because the function can be found by ADL. template // use like this: DownCast_(foo); inline To DownCast_(From* f) { // so we only accept pointers // Ensures that To is a sub-type of From *. This test is here only // for compile-time type checking, and has no overhead in an // optimized build at run-time, as it will be optimized away // completely. GTEST_INTENTIONAL_CONST_COND_PUSH_() if (false) { GTEST_INTENTIONAL_CONST_COND_POP_() const To to = nullptr; ::testing::internal::ImplicitCast_(to); } #if GTEST_HAS_RTTI // RTTI: debug mode only! GTEST_CHECK_(f == nullptr || dynamic_cast(f) != nullptr); #endif return static_cast(f); } // Downcasts the pointer of type Base to Derived. // Derived must be a subclass of Base. The parameter MUST // point to a class of type Derived, not any subclass of it. // When RTTI is available, the function performs a runtime // check to enforce this. template Derived* CheckedDowncastToActualType(Base* base) { #if GTEST_HAS_RTTI GTEST_CHECK_(typeid(*base) == typeid(Derived)); #endif #if GTEST_HAS_DOWNCAST_ return ::down_cast(base); #elif GTEST_HAS_RTTI return dynamic_cast(base); // NOLINT #else return static_cast(base); // Poor man's downcast. #endif } #if GTEST_HAS_STREAM_REDIRECTION // Defines the stderr capturer: // CaptureStdout - starts capturing stdout. // GetCapturedStdout - stops capturing stdout and returns the captured string. // CaptureStderr - starts capturing stderr. // GetCapturedStderr - stops capturing stderr and returns the captured string. // GTEST_API_ void CaptureStdout(); GTEST_API_ std::string GetCapturedStdout(); GTEST_API_ void CaptureStderr(); GTEST_API_ std::string GetCapturedStderr(); #endif // GTEST_HAS_STREAM_REDIRECTION // Returns the size (in bytes) of a file. GTEST_API_ size_t GetFileSize(FILE* file); // Reads the entire content of a file as a string. GTEST_API_ std::string ReadEntireFile(FILE* file); // All command line arguments. GTEST_API_ std::vector GetArgvs(); #if GTEST_HAS_DEATH_TEST std::vector GetInjectableArgvs(); // Deprecated: pass the args vector by value instead. void SetInjectableArgvs(const std::vector* new_argvs); void SetInjectableArgvs(const std::vector& new_argvs); void ClearInjectableArgvs(); #endif // GTEST_HAS_DEATH_TEST // Defines synchronization primitives. #if GTEST_IS_THREADSAFE # if GTEST_HAS_PTHREAD // Sleeps for (roughly) n milliseconds. This function is only for testing // Google Test's own constructs. Don't use it in user tests, either // directly or indirectly. inline void SleepMilliseconds(int n) { const timespec time = { 0, // 0 seconds. n * 1000L * 1000L, // And n ms. }; nanosleep(&time, nullptr); } # endif // GTEST_HAS_PTHREAD # if GTEST_HAS_NOTIFICATION_ // Notification has already been imported into the namespace. // Nothing to do here. # elif GTEST_HAS_PTHREAD // Allows a controller thread to pause execution of newly created // threads until notified. Instances of this class must be created // and destroyed in the controller thread. // // This class is only for testing Google Test's own constructs. Do not // use it in user tests, either directly or indirectly. class Notification { public: Notification() : notified_(false) { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); } ~Notification() { pthread_mutex_destroy(&mutex_); } // Notifies all threads created with this notification to start. Must // be called from the controller thread. void Notify() { pthread_mutex_lock(&mutex_); notified_ = true; pthread_mutex_unlock(&mutex_); } // Blocks until the controller thread notifies. Must be called from a test // thread. void WaitForNotification() { for (;;) { pthread_mutex_lock(&mutex_); const bool notified = notified_; pthread_mutex_unlock(&mutex_); if (notified) break; SleepMilliseconds(10); } } private: pthread_mutex_t mutex_; bool notified_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; # elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT GTEST_API_ void SleepMilliseconds(int n); // Provides leak-safe Windows kernel handle ownership. // Used in death tests and in threading support. class GTEST_API_ AutoHandle { public: // Assume that Win32 HANDLE type is equivalent to void*. Doing so allows us to // avoid including in this header file. Including is // undesirable because it defines a lot of symbols and macros that tend to // conflict with client code. This assumption is verified by // WindowsTypesTest.HANDLEIsVoidStar. typedef void* Handle; AutoHandle(); explicit AutoHandle(Handle handle); ~AutoHandle(); Handle Get() const; void Reset(); void Reset(Handle handle); private: // Returns true if and only if the handle is a valid handle object that can be // closed. bool IsCloseable() const; Handle handle_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); }; // Allows a controller thread to pause execution of newly created // threads until notified. Instances of this class must be created // and destroyed in the controller thread. // // This class is only for testing Google Test's own constructs. Do not // use it in user tests, either directly or indirectly. class GTEST_API_ Notification { public: Notification(); void Notify(); void WaitForNotification(); private: AutoHandle event_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; # endif // GTEST_HAS_NOTIFICATION_ // On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD // defined, but we don't want to use MinGW's pthreads implementation, which // has conformance problems with some versions of the POSIX standard. # if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW // As a C-function, ThreadFuncWithCLinkage cannot be templated itself. // Consequently, it cannot select a correct instantiation of ThreadWithParam // in order to call its Run(). Introducing ThreadWithParamBase as a // non-templated base class for ThreadWithParam allows us to bypass this // problem. class ThreadWithParamBase { public: virtual ~ThreadWithParamBase() {} virtual void Run() = 0; }; // pthread_create() accepts a pointer to a function type with the C linkage. // According to the Standard (7.5/1), function types with different linkages // are different even if they are otherwise identical. Some compilers (for // example, SunStudio) treat them as different types. Since class methods // cannot be defined with C-linkage we need to define a free C-function to // pass into pthread_create(). extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { static_cast(thread)->Run(); return nullptr; } // Helper class for testing Google Test's multi-threading constructs. // To use it, write: // // void ThreadFunc(int param) { /* Do things with param */ } // Notification thread_can_start; // ... // // The thread_can_start parameter is optional; you can supply NULL. // ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); // thread_can_start.Notify(); // // These classes are only for testing Google Test's own constructs. Do // not use them in user tests, either directly or indirectly. template class ThreadWithParam : public ThreadWithParamBase { public: typedef void UserThreadFunc(T); ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) : func_(func), param_(param), thread_can_start_(thread_can_start), finished_(false) { ThreadWithParamBase* const base = this; // The thread can be created only after all fields except thread_ // have been initialized. GTEST_CHECK_POSIX_SUCCESS_( pthread_create(&thread_, nullptr, &ThreadFuncWithCLinkage, base)); } ~ThreadWithParam() override { Join(); } void Join() { if (!finished_) { GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, nullptr)); finished_ = true; } } void Run() override { if (thread_can_start_ != nullptr) thread_can_start_->WaitForNotification(); func_(param_); } private: UserThreadFunc* const func_; // User-supplied thread function. const T param_; // User-supplied parameter to the thread function. // When non-NULL, used to block execution until the controller thread // notifies. Notification* const thread_can_start_; bool finished_; // true if and only if we know that the thread function has // finished. pthread_t thread_; // The native thread object. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); }; # endif // !GTEST_OS_WINDOWS && GTEST_HAS_PTHREAD || // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ # if GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ // Mutex and ThreadLocal have already been imported into the namespace. // Nothing to do here. # elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // Mutex implements mutex on Windows platforms. It is used in conjunction // with class MutexLock: // // Mutex mutex; // ... // MutexLock lock(&mutex); // Acquires the mutex and releases it at the // // end of the current scope. // // A static Mutex *must* be defined or declared using one of the following // macros: // GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); // GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); // // (A non-static Mutex is defined/declared in the usual way). class GTEST_API_ Mutex { public: enum MutexType { kStatic = 0, kDynamic = 1 }; // We rely on kStaticMutex being 0 as it is to what the linker initializes // type_ in static mutexes. critical_section_ will be initialized lazily // in ThreadSafeLazyInit(). enum StaticConstructorSelector { kStaticMutex = 0 }; // This constructor intentionally does nothing. It relies on type_ being // statically initialized to 0 (effectively setting it to kStatic) and on // ThreadSafeLazyInit() to lazily initialize the rest of the members. explicit Mutex(StaticConstructorSelector /*dummy*/) {} Mutex(); ~Mutex(); void Lock(); void Unlock(); // Does nothing if the current thread holds the mutex. Otherwise, crashes // with high probability. void AssertHeld(); private: // Initializes owner_thread_id_ and critical_section_ in static mutexes. void ThreadSafeLazyInit(); // Per https://blogs.msdn.microsoft.com/oldnewthing/20040223-00/?p=40503, // we assume that 0 is an invalid value for thread IDs. unsigned int owner_thread_id_; // For static mutexes, we rely on these members being initialized to zeros // by the linker. MutexType type_; long critical_section_init_phase_; // NOLINT GTEST_CRITICAL_SECTION* critical_section_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; # define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::Mutex mutex # define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ ::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex) // We cannot name this class MutexLock because the ctor declaration would // conflict with a macro named MutexLock, which is defined on some // platforms. That macro is used as a defensive measure to prevent against // inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than // "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(Mutex* mutex) : mutex_(mutex) { mutex_->Lock(); } ~GTestMutexLock() { mutex_->Unlock(); } private: Mutex* const mutex_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); }; typedef GTestMutexLock MutexLock; // Base class for ValueHolder. Allows a caller to hold and delete a value // without knowing its type. class ThreadLocalValueHolderBase { public: virtual ~ThreadLocalValueHolderBase() {} }; // Provides a way for a thread to send notifications to a ThreadLocal // regardless of its parameter type. class ThreadLocalBase { public: // Creates a new ValueHolder object holding a default value passed to // this ThreadLocal's constructor and returns it. It is the caller's // responsibility not to call this when the ThreadLocal instance already // has a value on the current thread. virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const = 0; protected: ThreadLocalBase() {} virtual ~ThreadLocalBase() {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocalBase); }; // Maps a thread to a set of ThreadLocals that have values instantiated on that // thread and notifies them when the thread exits. A ThreadLocal instance is // expected to persist until all threads it has values on have terminated. class GTEST_API_ ThreadLocalRegistry { public: // Registers thread_local_instance as having value on the current thread. // Returns a value that can be used to identify the thread from other threads. static ThreadLocalValueHolderBase* GetValueOnCurrentThread( const ThreadLocalBase* thread_local_instance); // Invoked when a ThreadLocal instance is destroyed. static void OnThreadLocalDestroyed( const ThreadLocalBase* thread_local_instance); }; class GTEST_API_ ThreadWithParamBase { public: void Join(); protected: class Runnable { public: virtual ~Runnable() {} virtual void Run() = 0; }; ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start); virtual ~ThreadWithParamBase(); private: AutoHandle thread_; }; // Helper class for testing Google Test's multi-threading constructs. template class ThreadWithParam : public ThreadWithParamBase { public: typedef void UserThreadFunc(T); ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) : ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) { } virtual ~ThreadWithParam() {} private: class RunnableImpl : public Runnable { public: RunnableImpl(UserThreadFunc* func, T param) : func_(func), param_(param) { } virtual ~RunnableImpl() {} virtual void Run() { func_(param_); } private: UserThreadFunc* const func_; const T param_; GTEST_DISALLOW_COPY_AND_ASSIGN_(RunnableImpl); }; GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); }; // Implements thread-local storage on Windows systems. // // // Thread 1 // ThreadLocal tl(100); // 100 is the default value for each thread. // // // Thread 2 // tl.set(150); // Changes the value for thread 2 only. // EXPECT_EQ(150, tl.get()); // // // Thread 1 // EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. // tl.set(200); // EXPECT_EQ(200, tl.get()); // // The template type argument T must have a public copy constructor. // In addition, the default ThreadLocal constructor requires T to have // a public default constructor. // // The users of a TheadLocal instance have to make sure that all but one // threads (including the main one) using that instance have exited before // destroying it. Otherwise, the per-thread objects managed for them by the // ThreadLocal instance are not guaranteed to be destroyed on all platforms. // // Google Test only uses global ThreadLocal objects. That means they // will die after main() has returned. Therefore, no per-thread // object managed by Google Test will be leaked as long as all threads // using Google Test have exited when main() returns. template class ThreadLocal : public ThreadLocalBase { public: ThreadLocal() : default_factory_(new DefaultValueHolderFactory()) {} explicit ThreadLocal(const T& value) : default_factory_(new InstanceValueHolderFactory(value)) {} ~ThreadLocal() { ThreadLocalRegistry::OnThreadLocalDestroyed(this); } T* pointer() { return GetOrCreateValue(); } const T* pointer() const { return GetOrCreateValue(); } const T& get() const { return *pointer(); } void set(const T& value) { *pointer() = value; } private: // Holds a value of T. Can be deleted via its base class without the caller // knowing the type of T. class ValueHolder : public ThreadLocalValueHolderBase { public: ValueHolder() : value_() {} explicit ValueHolder(const T& value) : value_(value) {} T* pointer() { return &value_; } private: T value_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); }; T* GetOrCreateValue() const { return static_cast( ThreadLocalRegistry::GetValueOnCurrentThread(this))->pointer(); } virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const { return default_factory_->MakeNewHolder(); } class ValueHolderFactory { public: ValueHolderFactory() {} virtual ~ValueHolderFactory() {} virtual ValueHolder* MakeNewHolder() const = 0; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); }; class DefaultValueHolderFactory : public ValueHolderFactory { public: DefaultValueHolderFactory() {} ValueHolder* MakeNewHolder() const override { return new ValueHolder(); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); }; class InstanceValueHolderFactory : public ValueHolderFactory { public: explicit InstanceValueHolderFactory(const T& value) : value_(value) {} ValueHolder* MakeNewHolder() const override { return new ValueHolder(value_); } private: const T value_; // The value for each thread. GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); }; std::unique_ptr default_factory_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; # elif GTEST_HAS_PTHREAD // MutexBase and Mutex implement mutex on pthreads-based platforms. class MutexBase { public: // Acquires this mutex. void Lock() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); owner_ = pthread_self(); has_owner_ = true; } // Releases this mutex. void Unlock() { // Since the lock is being released the owner_ field should no longer be // considered valid. We don't protect writing to has_owner_ here, as it's // the caller's responsibility to ensure that the current thread holds the // mutex when this is called. has_owner_ = false; GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); } // Does nothing if the current thread holds the mutex. Otherwise, crashes // with high probability. void AssertHeld() const { GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self())) << "The current thread is not holding the mutex @" << this; } // A static mutex may be used before main() is entered. It may even // be used before the dynamic initialization stage. Therefore we // must be able to initialize a static mutex object at link time. // This means MutexBase has to be a POD and its member variables // have to be public. public: pthread_mutex_t mutex_; // The underlying pthread mutex. // has_owner_ indicates whether the owner_ field below contains a valid thread // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All // accesses to the owner_ field should be protected by a check of this field. // An alternative might be to memset() owner_ to all zeros, but there's no // guarantee that a zero'd pthread_t is necessarily invalid or even different // from pthread_self(). bool has_owner_; pthread_t owner_; // The thread holding the mutex. }; // Forward-declares a static mutex. # define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::MutexBase mutex // Defines and statically (i.e. at link time) initializes a static mutex. // The initialization list here does not explicitly initialize each field, // instead relying on default initialization for the unspecified fields. In // particular, the owner_ field (a pthread_t) is not explicitly initialized. // This allows initialization to work whether pthread_t is a scalar or struct. // The flag -Wmissing-field-initializers must not be specified for this to work. #define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ ::testing::internal::MutexBase mutex = {PTHREAD_MUTEX_INITIALIZER, false, 0} // The Mutex class can only be used for mutexes created at runtime. It // shares its API with MutexBase otherwise. class Mutex : public MutexBase { public: Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); has_owner_ = false; } ~Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; // We cannot name this class MutexLock because the ctor declaration would // conflict with a macro named MutexLock, which is defined on some // platforms. That macro is used as a defensive measure to prevent against // inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than // "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(MutexBase* mutex) : mutex_(mutex) { mutex_->Lock(); } ~GTestMutexLock() { mutex_->Unlock(); } private: MutexBase* const mutex_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); }; typedef GTestMutexLock MutexLock; // Helpers for ThreadLocal. // pthread_key_create() requires DeleteThreadLocalValue() to have // C-linkage. Therefore it cannot be templatized to access // ThreadLocal. Hence the need for class // ThreadLocalValueHolderBase. class ThreadLocalValueHolderBase { public: virtual ~ThreadLocalValueHolderBase() {} }; // Called by pthread to delete thread-local data stored by // pthread_setspecific(). extern "C" inline void DeleteThreadLocalValue(void* value_holder) { delete static_cast(value_holder); } // Implements thread-local storage on pthreads-based systems. template class GTEST_API_ ThreadLocal { public: ThreadLocal() : key_(CreateKey()), default_factory_(new DefaultValueHolderFactory()) {} explicit ThreadLocal(const T& value) : key_(CreateKey()), default_factory_(new InstanceValueHolderFactory(value)) {} ~ThreadLocal() { // Destroys the managed object for the current thread, if any. DeleteThreadLocalValue(pthread_getspecific(key_)); // Releases resources associated with the key. This will *not* // delete managed objects for other threads. GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); } T* pointer() { return GetOrCreateValue(); } const T* pointer() const { return GetOrCreateValue(); } const T& get() const { return *pointer(); } void set(const T& value) { *pointer() = value; } private: // Holds a value of type T. class ValueHolder : public ThreadLocalValueHolderBase { public: ValueHolder() : value_() {} explicit ValueHolder(const T& value) : value_(value) {} T* pointer() { return &value_; } private: T value_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); }; static pthread_key_t CreateKey() { pthread_key_t key; // When a thread exits, DeleteThreadLocalValue() will be called on // the object managed for that thread. GTEST_CHECK_POSIX_SUCCESS_( pthread_key_create(&key, &DeleteThreadLocalValue)); return key; } T* GetOrCreateValue() const { ThreadLocalValueHolderBase* const holder = static_cast(pthread_getspecific(key_)); if (holder != nullptr) { return CheckedDowncastToActualType(holder)->pointer(); } ValueHolder* const new_holder = default_factory_->MakeNewHolder(); ThreadLocalValueHolderBase* const holder_base = new_holder; GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); return new_holder->pointer(); } class ValueHolderFactory { public: ValueHolderFactory() {} virtual ~ValueHolderFactory() {} virtual ValueHolder* MakeNewHolder() const = 0; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); }; class DefaultValueHolderFactory : public ValueHolderFactory { public: DefaultValueHolderFactory() {} ValueHolder* MakeNewHolder() const override { return new ValueHolder(); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); }; class InstanceValueHolderFactory : public ValueHolderFactory { public: explicit InstanceValueHolderFactory(const T& value) : value_(value) {} ValueHolder* MakeNewHolder() const override { return new ValueHolder(value_); } private: const T value_; // The value for each thread. GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); }; // A key pthreads uses for looking up per-thread values. const pthread_key_t key_; std::unique_ptr default_factory_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; # endif // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ #else // GTEST_IS_THREADSAFE // A dummy implementation of synchronization primitives (mutex, lock, // and thread-local variable). Necessary for compiling Google Test where // mutex is not supported - using Google Test in multiple threads is not // supported on such platforms. class Mutex { public: Mutex() {} void Lock() {} void Unlock() {} void AssertHeld() const {} }; # define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::Mutex mutex # define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex // We cannot name this class MutexLock because the ctor declaration would // conflict with a macro named MutexLock, which is defined on some // platforms. That macro is used as a defensive measure to prevent against // inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than // "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(Mutex*) {} // NOLINT }; typedef GTestMutexLock MutexLock; template class GTEST_API_ ThreadLocal { public: ThreadLocal() : value_() {} explicit ThreadLocal(const T& value) : value_(value) {} T* pointer() { return &value_; } const T* pointer() const { return &value_; } const T& get() const { return value_; } void set(const T& value) { value_ = value; } private: T value_; }; #endif // GTEST_IS_THREADSAFE // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. GTEST_API_ size_t GetThreadCount(); #if GTEST_OS_WINDOWS # define GTEST_PATH_SEP_ "\\" # define GTEST_HAS_ALT_PATH_SEP_ 1 // The biggest signed integer type the compiler supports. typedef __int64 BiggestInt; #else # define GTEST_PATH_SEP_ "/" # define GTEST_HAS_ALT_PATH_SEP_ 0 typedef long long BiggestInt; // NOLINT #endif // GTEST_OS_WINDOWS // Utilities for char. // isspace(int ch) and friends accept an unsigned char or EOF. char // may be signed, depending on the compiler (or compiler flags). // Therefore we need to cast a char to unsigned char before calling // isspace(), etc. inline bool IsAlpha(char ch) { return isalpha(static_cast(ch)) != 0; } inline bool IsAlNum(char ch) { return isalnum(static_cast(ch)) != 0; } inline bool IsDigit(char ch) { return isdigit(static_cast(ch)) != 0; } inline bool IsLower(char ch) { return islower(static_cast(ch)) != 0; } inline bool IsSpace(char ch) { return isspace(static_cast(ch)) != 0; } inline bool IsUpper(char ch) { return isupper(static_cast(ch)) != 0; } inline bool IsXDigit(char ch) { return isxdigit(static_cast(ch)) != 0; } inline bool IsXDigit(wchar_t ch) { const unsigned char low_byte = static_cast(ch); return ch == low_byte && isxdigit(low_byte) != 0; } inline char ToLower(char ch) { return static_cast(tolower(static_cast(ch))); } inline char ToUpper(char ch) { return static_cast(toupper(static_cast(ch))); } inline std::string StripTrailingSpaces(std::string str) { std::string::iterator it = str.end(); while (it != str.begin() && IsSpace(*--it)) it = str.erase(it); return str; } // The testing::internal::posix namespace holds wrappers for common // POSIX functions. These wrappers hide the differences between // Windows/MSVC and POSIX systems. Since some compilers define these // standard functions as macros, the wrapper cannot have the same name // as the wrapped function. namespace posix { // Functions with a different name on Windows. #if GTEST_OS_WINDOWS typedef struct _stat StatStruct; # ifdef __BORLANDC__ inline int IsATTY(int fd) { return isatty(fd); } inline int StrCaseCmp(const char* s1, const char* s2) { return stricmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } # else // !__BORLANDC__ # if GTEST_OS_WINDOWS_MOBILE inline int IsATTY(int /* fd */) { return 0; } # else inline int IsATTY(int fd) { return _isatty(fd); } # endif // GTEST_OS_WINDOWS_MOBILE inline int StrCaseCmp(const char* s1, const char* s2) { return _stricmp(s1, s2); } inline char* StrDup(const char* src) { return _strdup(src); } # endif // __BORLANDC__ # if GTEST_OS_WINDOWS_MOBILE inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } // Stat(), RmDir(), and IsDir() are not needed on Windows CE at this // time and thus not defined there. # else inline int FileNo(FILE* file) { return _fileno(file); } inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } inline int RmDir(const char* dir) { return _rmdir(dir); } inline bool IsDir(const StatStruct& st) { return (_S_IFDIR & st.st_mode) != 0; } # endif // GTEST_OS_WINDOWS_MOBILE #elif GTEST_OS_ESP8266 typedef struct stat StatStruct; inline int FileNo(FILE* file) { return fileno(file); } inline int IsATTY(int fd) { return isatty(fd); } inline int Stat(const char* path, StatStruct* buf) { // stat function not implemented on ESP8266 return 0; } inline int StrCaseCmp(const char* s1, const char* s2) { return strcasecmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } inline int RmDir(const char* dir) { return rmdir(dir); } inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } #else typedef struct stat StatStruct; inline int FileNo(FILE* file) { return fileno(file); } inline int IsATTY(int fd) { return isatty(fd); } inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } inline int StrCaseCmp(const char* s1, const char* s2) { return strcasecmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } inline int RmDir(const char* dir) { return rmdir(dir); } inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } #endif // GTEST_OS_WINDOWS // Functions deprecated by MSVC 8.0. GTEST_DISABLE_MSC_DEPRECATED_PUSH_() // ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and // StrError() aren't needed on Windows CE at this time and thus not // defined there. #if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT inline int ChDir(const char* dir) { return chdir(dir); } #endif inline FILE* FOpen(const char* path, const char* mode) { return fopen(path, mode); } #if !GTEST_OS_WINDOWS_MOBILE inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { return freopen(path, mode, stream); } inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } #endif inline int FClose(FILE* fp) { return fclose(fp); } #if !GTEST_OS_WINDOWS_MOBILE inline int Read(int fd, void* buf, unsigned int count) { return static_cast(read(fd, buf, count)); } inline int Write(int fd, const void* buf, unsigned int count) { return static_cast(write(fd, buf, count)); } inline int Close(int fd) { return close(fd); } inline const char* StrError(int errnum) { return strerror(errnum); } #endif inline const char* GetEnv(const char* name) { #if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \ GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 // We are on an embedded platform, which has no environment variables. static_cast(name); // To prevent 'unused argument' warning. return nullptr; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) // Environment variables which we programmatically clear will be set to the // empty string rather than unset (NULL). Handle that case. const char* const env = getenv(name); return (env != nullptr && env[0] != '\0') ? env : nullptr; #else return getenv(name); #endif } GTEST_DISABLE_MSC_DEPRECATED_POP_() #if GTEST_OS_WINDOWS_MOBILE // Windows CE has no C library. The abort() function is used in // several places in Google Test. This implementation provides a reasonable // imitation of standard behaviour. [[noreturn]] void Abort(); #else [[noreturn]] inline void Abort() { abort(); } #endif // GTEST_OS_WINDOWS_MOBILE } // namespace posix // MSVC "deprecates" snprintf and issues warnings wherever it is used. In // order to avoid these warnings, we need to use _snprintf or _snprintf_s on // MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate // function in order to achieve that. We use macro definition here because // snprintf is a variadic function. #if _MSC_VER && !GTEST_OS_WINDOWS_MOBILE // MSVC 2005 and above support variadic macros. # define GTEST_SNPRINTF_(buffer, size, format, ...) \ _snprintf_s(buffer, size, size, format, __VA_ARGS__) #elif defined(_MSC_VER) // Windows CE does not define _snprintf_s # define GTEST_SNPRINTF_ _snprintf #else # define GTEST_SNPRINTF_ snprintf #endif // The maximum number a BiggestInt can represent. This definition // works no matter BiggestInt is represented in one's complement or // two's complement. // // We cannot rely on numeric_limits in STL, as __int64 and long long // are not part of standard C++ and numeric_limits doesn't need to be // defined for them. const BiggestInt kMaxBiggestInt = ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); // This template class serves as a compile-time function from size to // type. It maps a size in bytes to a primitive type with that // size. e.g. // // TypeWithSize<4>::UInt // // is typedef-ed to be unsigned int (unsigned integer made up of 4 // bytes). // // Such functionality should belong to STL, but I cannot find it // there. // // Google Test uses this class in the implementation of floating-point // comparison. // // For now it only handles UInt (unsigned int) as that's all Google Test // needs. Other types can be easily added in the future if need // arises. template class TypeWithSize { public: // This prevents the user from using TypeWithSize with incorrect // values of N. typedef void UInt; }; // The specialization for size 4. template <> class TypeWithSize<4> { public: // unsigned int has size 4 in both gcc and MSVC. // // As base/basictypes.h doesn't compile on Windows, we cannot use // uint32, uint64, and etc here. typedef int Int; typedef unsigned int UInt; }; // The specialization for size 8. template <> class TypeWithSize<8> { public: #if GTEST_OS_WINDOWS typedef __int64 Int; typedef unsigned __int64 UInt; #else typedef long long Int; // NOLINT typedef unsigned long long UInt; // NOLINT #endif // GTEST_OS_WINDOWS }; // Integer types of known sizes. typedef TypeWithSize<4>::Int Int32; typedef TypeWithSize<4>::UInt UInt32; typedef TypeWithSize<8>::Int Int64; typedef TypeWithSize<8>::UInt UInt64; typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Utilities for command line flags and environment variables. // Macro for referencing flags. #if !defined(GTEST_FLAG) # define GTEST_FLAG(name) FLAGS_gtest_##name #endif // !defined(GTEST_FLAG) #if !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) # define GTEST_USE_OWN_FLAGFILE_FLAG_ 1 #endif // !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) #if !defined(GTEST_DECLARE_bool_) # define GTEST_FLAG_SAVER_ ::testing::internal::GTestFlagSaver // Macros for declaring flags. # define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) # define GTEST_DECLARE_int32_(name) \ GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) # define GTEST_DECLARE_string_(name) \ GTEST_API_ extern ::std::string GTEST_FLAG(name) // Macros for defining flags. # define GTEST_DEFINE_bool_(name, default_val, doc) \ GTEST_API_ bool GTEST_FLAG(name) = (default_val) # define GTEST_DEFINE_int32_(name, default_val, doc) \ GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) # define GTEST_DEFINE_string_(name, default_val, doc) \ GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) #endif // !defined(GTEST_DECLARE_bool_) // Thread annotations #if !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) # define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) # define GTEST_LOCK_EXCLUDED_(locks) #endif // !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) // Parses 'str' for a 32-bit signed integer. If successful, writes the result // to *value and returns true; otherwise leaves *value unchanged and returns // false. bool ParseInt32(const Message& src_text, const char* str, Int32* value); // Parses a bool/Int32/string from the environment variable // corresponding to the given Google Test flag. bool BoolFromGTestEnv(const char* flag, bool default_val); GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); std::string OutputFlagAlsoCheckEnvVar(); const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing #if !defined(GTEST_INTERNAL_DEPRECATED) // Internal Macro to mark an API deprecated, for googletest usage only // Usage: class GTEST_INTERNAL_DEPRECATED(message) MyClass or // GTEST_INTERNAL_DEPRECATED(message) myFunction(); Every usage of // a deprecated entity will trigger a warning when compiled with // `-Wdeprecated-declarations` option (clang, gcc, any __GNUC__ compiler). // For msvc /W3 option will need to be used // Note that for 'other' compilers this macro evaluates to nothing to prevent // compilations errors. #if defined(_MSC_VER) #define GTEST_INTERNAL_DEPRECATED(message) __declspec(deprecated(message)) #elif defined(__GNUC__) #define GTEST_INTERNAL_DEPRECATED(message) __attribute__((deprecated(message))) #else #define GTEST_INTERNAL_DEPRECATED(message) #endif #endif // !defined(GTEST_INTERNAL_DEPRECATED) #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ openzwave-1.6.1914/cpp/test/src/0000777000175200017520000000000014032143201013322 500000000000000openzwave-1.6.1914/cpp/test/src/gtest-internal-inl.h0000644000175200017520000013367614032142455017161 00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Utility functions and classes used by the Google C++ testing framework.// // This file contains purely Google Test's internal implementation. Please // DO NOT #INCLUDE IT IN A USER PROGRAM. #ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ #define GTEST_SRC_GTEST_INTERNAL_INL_H_ #ifndef _WIN32_WCE # include #endif // !_WIN32_WCE #include #include // For strtoll/_strtoul64/malloc/free. #include // For memmove. #include #include #include #include #include "gtest/internal/gtest-port.h" #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT #endif #if GTEST_OS_WINDOWS # include // NOLINT #endif // GTEST_OS_WINDOWS #include "gtest/gtest.h" #include "gtest/gtest-spi.h" GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ /* class A needs to have dll-interface to be used by clients of class B */) namespace testing { // Declares the flags. // // We don't want the users to modify this flag in the code, but want // Google Test's own unit tests to be able to access it. Therefore we // declare it here as opposed to in gtest.h. GTEST_DECLARE_bool_(death_test_use_fork); namespace internal { // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; // Names of the flags (needed for parsing Google Test flags). const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; const char kBreakOnFailureFlag[] = "break_on_failure"; const char kCatchExceptionsFlag[] = "catch_exceptions"; const char kColorFlag[] = "color"; const char kFilterFlag[] = "filter"; const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; const char kPrintTimeFlag[] = "print_time"; const char kPrintUTF8Flag[] = "print_utf8"; const char kRandomSeedFlag[] = "random_seed"; const char kRepeatFlag[] = "repeat"; const char kShuffleFlag[] = "shuffle"; const char kStackTraceDepthFlag[] = "stack_trace_depth"; const char kStreamResultToFlag[] = "stream_result_to"; const char kThrowOnFailureFlag[] = "throw_on_failure"; const char kFlagfileFlag[] = "flagfile"; // A valid random seed must be in [1, kMaxRandomSeed]. const int kMaxRandomSeed = 99999; // g_help_flag is true if and only if the --help flag or an equivalent form // is specified on the command line. GTEST_API_ extern bool g_help_flag; // Returns the current time in milliseconds. GTEST_API_ TimeInMillis GetTimeInMillis(); // Returns true if and only if Google Test should use colors in the output. GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); // Formats the given time in milliseconds as seconds. GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); // Converts the given time in milliseconds to a date string in the ISO 8601 // format, without the timezone information. N.B.: due to the use the // non-reentrant localtime() function, this function is not thread safe. Do // not use it in any code that can be called from multiple threads. GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms); // Parses a string for an Int32 flag, in the form of "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. GTEST_API_ bool ParseInt32Flag( const char* str, const char* flag, Int32* value); // Returns a random seed in range [1, kMaxRandomSeed] based on the // given --gtest_random_seed flag value. inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { const unsigned int raw_seed = (random_seed_flag == 0) ? static_cast(GetTimeInMillis()) : static_cast(random_seed_flag); // Normalizes the actual seed to range [1, kMaxRandomSeed] such that // it's easy to type. const int normalized_seed = static_cast((raw_seed - 1U) % static_cast(kMaxRandomSeed)) + 1; return normalized_seed; } // Returns the first valid random seed after 'seed'. The behavior is // undefined if 'seed' is invalid. The seed after kMaxRandomSeed is // considered to be 1. inline int GetNextRandomSeed(int seed) { GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) << "Invalid random seed " << seed << " - must be in [1, " << kMaxRandomSeed << "]."; const int next_seed = seed + 1; return (next_seed > kMaxRandomSeed) ? 1 : next_seed; } // This class saves the values of all Google Test flags in its c'tor, and // restores them in its d'tor. class GTestFlagSaver { public: // The c'tor. GTestFlagSaver() { also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); break_on_failure_ = GTEST_FLAG(break_on_failure); catch_exceptions_ = GTEST_FLAG(catch_exceptions); color_ = GTEST_FLAG(color); death_test_style_ = GTEST_FLAG(death_test_style); death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); filter_ = GTEST_FLAG(filter); internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); list_tests_ = GTEST_FLAG(list_tests); output_ = GTEST_FLAG(output); print_time_ = GTEST_FLAG(print_time); print_utf8_ = GTEST_FLAG(print_utf8); random_seed_ = GTEST_FLAG(random_seed); repeat_ = GTEST_FLAG(repeat); shuffle_ = GTEST_FLAG(shuffle); stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); stream_result_to_ = GTEST_FLAG(stream_result_to); throw_on_failure_ = GTEST_FLAG(throw_on_failure); } // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. ~GTestFlagSaver() { GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; GTEST_FLAG(break_on_failure) = break_on_failure_; GTEST_FLAG(catch_exceptions) = catch_exceptions_; GTEST_FLAG(color) = color_; GTEST_FLAG(death_test_style) = death_test_style_; GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; GTEST_FLAG(filter) = filter_; GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; GTEST_FLAG(list_tests) = list_tests_; GTEST_FLAG(output) = output_; GTEST_FLAG(print_time) = print_time_; GTEST_FLAG(print_utf8) = print_utf8_; GTEST_FLAG(random_seed) = random_seed_; GTEST_FLAG(repeat) = repeat_; GTEST_FLAG(shuffle) = shuffle_; GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; GTEST_FLAG(stream_result_to) = stream_result_to_; GTEST_FLAG(throw_on_failure) = throw_on_failure_; } private: // Fields for saving the original values of flags. bool also_run_disabled_tests_; bool break_on_failure_; bool catch_exceptions_; std::string color_; std::string death_test_style_; bool death_test_use_fork_; std::string filter_; std::string internal_run_death_test_; bool list_tests_; std::string output_; bool print_time_; bool print_utf8_; internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; internal::Int32 stack_trace_depth_; std::string stream_result_to_; bool throw_on_failure_; } GTEST_ATTRIBUTE_UNUSED_; // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted // to "(Invalid Unicode 0xXXXXXXXX)". GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: // UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number // of wchar_t characters processed. -1 is used when the entire string // should be processed. // If the string contains code points that are not valid Unicode code points // (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars); // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded(); // Checks whether sharding is enabled by examining the relevant // environment variable values. If the variables are present, // but inconsistent (e.g., shard_index >= total_shards), prints // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. GTEST_API_ bool ShouldShard(const char* total_shards_str, const char* shard_index_str, bool in_subprocess_for_death_test); // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error and // and aborts. GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); // Given the total number of shards, the shard index, and the test id, // returns true if and only if the test should be run on this shard. The test id // is some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. GTEST_API_ bool ShouldRunTestOnShard( int total_shards, int shard_index, int test_id); // STL container utilities. // Returns the number of elements in the given container that satisfy // the given predicate. template inline int CountIf(const Container& c, Predicate predicate) { // Implemented as an explicit loop since std::count_if() in libCstd on // Solaris has a non-standard signature. int count = 0; for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { if (predicate(*it)) ++count; } return count; } // Applies a function/functor to each element in the container. template void ForEach(const Container& c, Functor functor) { std::for_each(c.begin(), c.end(), functor); } // Returns the i-th element of the vector, or default_value if i is not // in range [0, v.size()). template inline E GetElementOr(const std::vector& v, int i, E default_value) { return (i < 0 || i >= static_cast(v.size())) ? default_value : v[static_cast(i)]; } // Performs an in-place shuffle of a range of the vector's elements. // 'begin' and 'end' are element indices as an STL-style range; // i.e. [begin, end) are shuffled, where 'end' == size() means to // shuffle to the end of the vector. template void ShuffleRange(internal::Random* random, int begin, int end, std::vector* v) { const int size = static_cast(v->size()); GTEST_CHECK_(0 <= begin && begin <= size) << "Invalid shuffle range start " << begin << ": must be in range [0, " << size << "]."; GTEST_CHECK_(begin <= end && end <= size) << "Invalid shuffle range finish " << end << ": must be in range [" << begin << ", " << size << "]."; // Fisher-Yates shuffle, from // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle for (int range_width = end - begin; range_width >= 2; range_width--) { const int last_in_range = begin + range_width - 1; const int selected = begin + static_cast(random->Generate(static_cast(range_width))); std::swap((*v)[static_cast(selected)], (*v)[static_cast(last_in_range)]); } } // Performs an in-place shuffle of the vector's elements. template inline void Shuffle(internal::Random* random, std::vector* v) { ShuffleRange(random, 0, static_cast(v->size()), v); } // A function for deleting an object. Handy for being used as a // functor. template static void Delete(T* x) { delete x; } // A predicate that checks the key of a TestProperty against a known key. // // TestPropertyKeyIs is copyable. class TestPropertyKeyIs { public: // Constructor. // // TestPropertyKeyIs has NO default constructor. explicit TestPropertyKeyIs(const std::string& key) : key_(key) {} // Returns true if and only if the test name of test property matches on key_. bool operator()(const TestProperty& test_property) const { return test_property.key() == key_; } private: std::string key_; }; // Class UnitTestOptions. // // This class contains functions for processing options the user // specifies when running the tests. It has only static members. // // In most cases, the user can specify an option using either an // environment variable or a command line flag. E.g. you can set the // test filter using either GTEST_FILTER or --gtest_filter. If both // the variable and the flag are present, the latter overrides the // former. class GTEST_API_ UnitTestOptions { public: // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. static std::string GetOutputFormat(); // Returns the absolute path of the requested output file, or the // default (test_detail.xml in the original working directory) if // none was explicitly specified. static std::string GetAbsolutePathToOutputFile(); // Functions for processing the gtest_filter flag. // Returns true if and only if the wildcard pattern matches the string. // The first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. static bool PatternMatchesString(const char *pattern, const char *str); // Returns true if and only if the user-specified filter matches the test // suite name and the test name. static bool FilterMatchesTest(const std::string& test_suite_name, const std::string& test_name); #if GTEST_OS_WINDOWS // Function for supporting the gtest_catch_exception flag. // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. static int GTestShouldProcessSEH(DWORD exception_code); #endif // GTEST_OS_WINDOWS // Returns true if "name" matches the ':' separated list of glob-style // filters in "filter". static bool MatchesFilter(const std::string& name, const char* filter); }; // Returns the current application's name, removing directory path if that // is present. Used by UnitTestOptions::GetOutputFile. GTEST_API_ FilePath GetCurrentExecutableName(); // The role interface for getting the OS stack trace as a string. class OsStackTraceGetterInterface { public: OsStackTraceGetterInterface() {} virtual ~OsStackTraceGetterInterface() {} // Returns the current OS stack trace as an std::string. Parameters: // // max_depth - the maximum number of stack frames to be included // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. virtual std::string CurrentStackTrace(int max_depth, int skip_count) = 0; // UponLeavingGTest() should be called immediately before Google Test calls // user code. It saves some information about the current stack that // CurrentStackTrace() will use to find and hide Google Test stack frames. virtual void UponLeavingGTest() = 0; // This string is inserted in place of stack frames that are part of // Google Test's implementation. static const char* const kElidedFramesMarker; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); }; // A working implementation of the OsStackTraceGetterInterface interface. class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() {} std::string CurrentStackTrace(int max_depth, int skip_count) override; void UponLeavingGTest() override; private: #if GTEST_HAS_ABSL Mutex mutex_; // Protects all internal state. // We save the stack frame below the frame that calls user code. // We do this because the address of the frame immediately below // the user code changes between the call to UponLeavingGTest() // and any calls to the stack trace code from within the user code. void* caller_frame_ = nullptr; #endif // GTEST_HAS_ABSL GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); }; // Information about a Google Test trace point. struct TraceInfo { const char* file; int line; std::string message; }; // This is the default global test part result reporter used in UnitTestImpl. // This class should only be used by UnitTestImpl. class DefaultGlobalTestPartResultReporter : public TestPartResultReporterInterface { public: explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. Reports the test part // result in the current test. void ReportTestPartResult(const TestPartResult& result) override; private: UnitTestImpl* const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); }; // This is the default per thread test part result reporter used in // UnitTestImpl. This class should only be used by UnitTestImpl. class DefaultPerThreadTestPartResultReporter : public TestPartResultReporterInterface { public: explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. The implementation just // delegates to the current global test part result reporter of *unit_test_. void ReportTestPartResult(const TestPartResult& result) override; private: UnitTestImpl* const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); }; // The private implementation of the UnitTest class. We don't protect // the methods under a mutex, as this class is not accessible by a // user and the UnitTest class that delegates work to this class does // proper locking. class GTEST_API_ UnitTestImpl { public: explicit UnitTestImpl(UnitTest* parent); virtual ~UnitTestImpl(); // There are two different ways to register your own TestPartResultReporter. // You can register your own repoter to listen either only for test results // from the current thread or for results from all threads. // By default, each per-thread test result repoter just passes a new // TestPartResult to the global test result reporter, which registers the // test part result for the currently running test. // Returns the global test part result reporter. TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); // Sets the global test part result reporter. void SetGlobalTestPartResultReporter( TestPartResultReporterInterface* reporter); // Returns the test part result reporter for the current thread. TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); // Sets the test part result reporter for the current thread. void SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter); // Gets the number of successful test suites. int successful_test_suite_count() const; // Gets the number of failed test suites. int failed_test_suite_count() const; // Gets the number of all test suites. int total_test_suite_count() const; // Gets the number of all test suites that contain at least one test // that should run. int test_suite_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; // Gets the number of skipped tests. int skipped_test_count() const; // Gets the number of failed tests. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; // Gets the number of all tests. int total_test_count() const; // Gets the number of tests that should run. int test_to_run_count() const; // Gets the time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp() const { return start_timestamp_; } // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns true if and only if the unit test passed (i.e. all test suites // passed). bool Passed() const { return !Failed(); } // Returns true if and only if the unit test failed (i.e. some test suite // failed or something outside of all tests failed). bool Failed() const { return failed_test_suite_count() > 0 || ad_hoc_test_result()->Failed(); } // Gets the i-th test suite among all the test suites. i can range from 0 to // total_test_suite_count() - 1. If i is not in that range, returns NULL. const TestSuite* GetTestSuite(int i) const { const int index = GetElementOr(test_suite_indices_, i, -1); return index < 0 ? nullptr : test_suites_[static_cast(i)]; } // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ const TestCase* GetTestCase(int i) const { return GetTestSuite(i); } #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Gets the i-th test suite among all the test suites. i can range from 0 to // total_test_suite_count() - 1. If i is not in that range, returns NULL. TestSuite* GetMutableSuiteCase(int i) { const int index = GetElementOr(test_suite_indices_, i, -1); return index < 0 ? nullptr : test_suites_[static_cast(index)]; } // Provides access to the event listener list. TestEventListeners* listeners() { return &listeners_; } // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. TestResult* current_test_result(); // Returns the TestResult for the ad hoc test. const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter // are the same; otherwise, deletes the old getter and makes the // input the current getter. void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* os_stack_trace_getter(); // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; // Finds and returns a TestSuite with the given name. If one doesn't // exist, creates one and returns it. // // Arguments: // // test_suite_name: name of the test suite // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // set_up_tc: pointer to the function that sets up the test suite // tear_down_tc: pointer to the function that tears down the test suite TestSuite* GetTestSuite(const char* test_suite_name, const char* type_param, internal::SetUpTestSuiteFunc set_up_tc, internal::TearDownTestSuiteFunc tear_down_tc); // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ TestCase* GetTestCase(const char* test_case_name, const char* type_param, internal::SetUpTestSuiteFunc set_up_tc, internal::TearDownTestSuiteFunc tear_down_tc) { return GetTestSuite(test_case_name, type_param, set_up_tc, tear_down_tc); } #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Adds a TestInfo to the unit test. // // Arguments: // // set_up_tc: pointer to the function that sets up the test suite // tear_down_tc: pointer to the function that tears down the test suite // test_info: the TestInfo object void AddTestInfo(internal::SetUpTestSuiteFunc set_up_tc, internal::TearDownTestSuiteFunc tear_down_tc, TestInfo* test_info) { // In order to support thread-safe death tests, we need to // remember the original working directory when the test program // was first invoked. We cannot do this in RUN_ALL_TESTS(), as // the user may have changed the current directory before calling // RUN_ALL_TESTS(). Therefore we capture the current directory in // AddTestInfo(), which is called to register a TEST or TEST_F // before main() is reached. if (original_working_dir_.IsEmpty()) { original_working_dir_.Set(FilePath::GetCurrentDir()); GTEST_CHECK_(!original_working_dir_.IsEmpty()) << "Failed to get the current working directory."; } GetTestSuite(test_info->test_suite_name(), test_info->type_param(), set_up_tc, tear_down_tc) ->AddTestInfo(test_info); } // Returns ParameterizedTestSuiteRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestSuiteRegistry& parameterized_test_registry() { return parameterized_test_registry_; } // Sets the TestSuite object for the test that's currently running. void set_current_test_suite(TestSuite* a_current_test_suite) { current_test_suite_ = a_current_test_suite; } // Sets the TestInfo object for the test that's currently running. If // current_test_info is NULL, the assertion results will be stored in // ad_hoc_test_result_. void set_current_test_info(TestInfo* a_current_test_info) { current_test_info_ = a_current_test_info; } // Registers all parameterized tests defined using TEST_P and // INSTANTIATE_TEST_SUITE_P, creating regular tests for each test/parameter // combination. This method can be called more then once; it has guards // protecting from registering the tests more then once. If // value-parameterized tests are disabled, RegisterParameterizedTests is // present but does nothing. void RegisterParameterizedTests(); // Runs all tests in this UnitTest object, prints the result, and // returns true if all tests are successful. If any exception is // thrown during a test, this test is considered to be failed, but // the rest of the tests will still be run. bool RunAllTests(); // Clears the results of all tests, except the ad hoc tests. void ClearNonAdHocTestResult() { ForEach(test_suites_, TestSuite::ClearTestSuiteResult); } // Clears the results of ad-hoc test assertions. void ClearAdHocTestResult() { ad_hoc_test_result_.Clear(); } // Adds a TestProperty to the current TestResult object when invoked in a // context of a test or a test suite, or to the global property set. If the // result already contains a property with the same key, the value will be // updated. void RecordProperty(const TestProperty& test_property); enum ReactionToSharding { HONOR_SHARDING_PROTOCOL, IGNORE_SHARDING_PROTOCOL }; // Matches the full name of each test against the user-specified // filter to decide whether the test should run, then records the // result in each TestSuite and TestInfo object. // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests // based on sharding variables in the environment. // Returns the number of tests that should run. int FilterTests(ReactionToSharding shard_tests); // Prints the names of the tests matching the user-specified filter flag. void ListTestsMatchingFilter(); const TestSuite* current_test_suite() const { return current_test_suite_; } TestInfo* current_test_info() { return current_test_info_; } const TestInfo* current_test_info() const { return current_test_info_; } // Returns the vector of environments that need to be set-up/torn-down // before/after the tests are run. std::vector& environments() { return environments_; } // Getters for the per-thread Google Test trace stack. std::vector& gtest_trace_stack() { return *(gtest_trace_stack_.pointer()); } const std::vector& gtest_trace_stack() const { return gtest_trace_stack_.get(); } #if GTEST_HAS_DEATH_TEST void InitDeathTestSubprocessControlInfo() { internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); } // Returns a pointer to the parsed --gtest_internal_run_death_test // flag, or NULL if that flag was not specified. // This information is useful only in a death test child process. // Must not be called before a call to InitGoogleTest. const InternalRunDeathTestFlag* internal_run_death_test_flag() const { return internal_run_death_test_flag_.get(); } // Returns a pointer to the current death test factory. internal::DeathTestFactory* death_test_factory() { return death_test_factory_.get(); } void SuppressTestEventsIfInSubprocess(); friend class ReplaceDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST // Initializes the event listener performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void ConfigureXmlOutput(); #if GTEST_CAN_STREAM_RESULTS_ // Initializes the event listener for streaming test results to a socket. // Must not be called before InitGoogleTest. void ConfigureStreamingOutput(); #endif // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest // this function is also called from RunAllTests. Since this function can be // called more than once, it has to be idempotent. void PostFlagParsingInit(); // Gets the random seed used at the start of the current test iteration. int random_seed() const { return random_seed_; } // Gets the random number generator. internal::Random* random() { return &random_; } // Shuffles all test suites, and the tests within each test suite, // making sure that death tests are still run first. void ShuffleTests(); // Restores the test suites and tests to their order before the first shuffle. void UnshuffleTests(); // Returns the value of GTEST_FLAG(catch_exceptions) at the moment // UnitTest::Run() starts. bool catch_exceptions() const { return catch_exceptions_; } private: friend class ::testing::UnitTest; // Used by UnitTest::Run() to capture the state of // GTEST_FLAG(catch_exceptions) at the moment it starts. void set_catch_exceptions(bool value) { catch_exceptions_ = value; } // The UnitTest object that owns this implementation object. UnitTest* const parent_; // The working directory when the first TEST() or TEST_F() was // executed. internal::FilePath original_working_dir_; // The default test part result reporters. DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; DefaultPerThreadTestPartResultReporter default_per_thread_test_part_result_reporter_; // Points to (but doesn't own) the global test part result reporter. TestPartResultReporterInterface* global_test_part_result_repoter_; // Protects read and write access to global_test_part_result_reporter_. internal::Mutex global_test_part_result_reporter_mutex_; // Points to (but doesn't own) the per-thread test part result reporter. internal::ThreadLocal per_thread_test_part_result_reporter_; // The vector of environments that need to be set-up/torn-down // before/after the tests are run. std::vector environments_; // The vector of TestSuites in their original order. It owns the // elements in the vector. std::vector test_suites_; // Provides a level of indirection for the test suite list to allow // easy shuffling and restoring the test suite order. The i-th // element of this vector is the index of the i-th test suite in the // shuffled order. std::vector test_suite_indices_; // ParameterizedTestRegistry object used to register value-parameterized // tests. internal::ParameterizedTestSuiteRegistry parameterized_test_registry_; // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; // Index of the last death test suite registered. Initially -1. int last_death_test_suite_; // This points to the TestSuite for the currently running test. It // changes as Google Test goes through one test suite after another. // When no test is running, this is set to NULL and Google Test // stores assertion results in ad_hoc_test_result_. Initially NULL. TestSuite* current_test_suite_; // This points to the TestInfo for the currently running test. It // changes as Google Test goes through one test after another. When // no test is running, this is set to NULL and Google Test stores // assertion results in ad_hoc_test_result_. Initially NULL. TestInfo* current_test_info_; // Normally, a user only writes assertions inside a TEST or TEST_F, // or inside a function called by a TEST or TEST_F. Since Google // Test keeps track of which test is current running, it can // associate such an assertion with the test it belongs to. // // If an assertion is encountered when no TEST or TEST_F is running, // Google Test attributes the assertion result to an imaginary "ad hoc" // test, and records the result in ad_hoc_test_result_. TestResult ad_hoc_test_result_; // The list of event listeners that can be used to track events inside // Google Test. TestEventListeners listeners_; // The OS stack trace getter. Will be deleted when the UnitTest // object is destructed. By default, an OsStackTraceGetter is used, // but the user can set this field to use a custom getter if that is // desired. OsStackTraceGetterInterface* os_stack_trace_getter_; // True if and only if PostFlagParsingInit() has been called. bool post_flag_parse_init_performed_; // The random number seed used at the beginning of the test run. int random_seed_; // Our random number generator. internal::Random random_; // The time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp_; // How long the test took to run, in milliseconds. TimeInMillis elapsed_time_; #if GTEST_HAS_DEATH_TEST // The decomposed components of the gtest_internal_run_death_test flag, // parsed when RUN_ALL_TESTS is called. std::unique_ptr internal_run_death_test_flag_; std::unique_ptr death_test_factory_; #endif // GTEST_HAS_DEATH_TEST // A per-thread stack of traces created by the SCOPED_TRACE() macro. internal::ThreadLocal > gtest_trace_stack_; // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() // starts. bool catch_exceptions_; GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); }; // class UnitTestImpl // Convenience function for accessing the global UnitTest // implementation object. inline UnitTestImpl* GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } #if GTEST_USES_SIMPLE_RE // Internal helper functions for implementing the simple regular // expression matcher. GTEST_API_ bool IsInSet(char ch, const char* str); GTEST_API_ bool IsAsciiDigit(char ch); GTEST_API_ bool IsAsciiPunct(char ch); GTEST_API_ bool IsRepeat(char ch); GTEST_API_ bool IsAsciiWhiteSpace(char ch); GTEST_API_ bool IsAsciiWordChar(char ch); GTEST_API_ bool IsValidEscape(char ch); GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); GTEST_API_ bool ValidateRegex(const char* regex); GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); GTEST_API_ bool MatchRepetitionAndRegexAtHead( bool escaped, char ch, char repeat, const char* regex, const char* str); GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); #endif // GTEST_USES_SIMPLE_RE // Parses the command line for Google Test flags, without initializing // other parts of Google Test. GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); #if GTEST_HAS_DEATH_TEST // Returns the message describing the last system error, regardless of the // platform. GTEST_API_ std::string GetLastErrnoDescription(); // Attempts to parse a string into a positive integer pointed to by the // number parameter. Returns true if that is possible. // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use // it here. template bool ParseNaturalNumber(const ::std::string& str, Integer* number) { // Fail fast if the given string does not begin with a digit; // this bypasses strtoXXX's "optional leading whitespace and plus // or minus sign" semantics, which are undesirable here. if (str.empty() || !IsDigit(str[0])) { return false; } errno = 0; char* end; // BiggestConvertible is the largest integer type that system-provided // string-to-number conversion routines can return. # if GTEST_OS_WINDOWS && !defined(__GNUC__) // MSVC and C++ Builder define __int64 instead of the standard long long. typedef unsigned __int64 BiggestConvertible; const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); # else typedef unsigned long long BiggestConvertible; // NOLINT const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); # endif // GTEST_OS_WINDOWS && !defined(__GNUC__) const bool parse_success = *end == '\0' && errno == 0; GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); const Integer result = static_cast(parsed); if (parse_success && static_cast(result) == parsed) { *number = result; return true; } return false; } #endif // GTEST_HAS_DEATH_TEST // TestResult contains some private methods that should be hidden from // Google Test user but are required for testing. This class allow our tests // to access them. // // This class is supplied only for the purpose of testing Google Test's own // constructs. Do not use it in user tests, either directly or indirectly. class TestResultAccessor { public: static void RecordProperty(TestResult* test_result, const std::string& xml_element, const TestProperty& property) { test_result->RecordProperty(xml_element, property); } static void ClearTestPartResults(TestResult* test_result) { test_result->ClearTestPartResults(); } static const std::vector& test_part_results( const TestResult& test_result) { return test_result.test_part_results(); } }; #if GTEST_CAN_STREAM_RESULTS_ // Streams test results to the given port on the given host machine. class StreamingListener : public EmptyTestEventListener { public: // Abstract base class for writing strings to a socket. class AbstractSocketWriter { public: virtual ~AbstractSocketWriter() {} // Sends a string to the socket. virtual void Send(const std::string& message) = 0; // Closes the socket. virtual void CloseConnection() {} // Sends a string and a newline to the socket. void SendLn(const std::string& message) { Send(message + "\n"); } }; // Concrete class for actually writing strings to a socket. class SocketWriter : public AbstractSocketWriter { public: SocketWriter(const std::string& host, const std::string& port) : sockfd_(-1), host_name_(host), port_num_(port) { MakeConnection(); } ~SocketWriter() override { if (sockfd_ != -1) CloseConnection(); } // Sends a string to the socket. void Send(const std::string& message) override { GTEST_CHECK_(sockfd_ != -1) << "Send() can be called only when there is a connection."; const auto len = static_cast(message.length()); if (write(sockfd_, message.c_str(), len) != static_cast(len)) { GTEST_LOG_(WARNING) << "stream_result_to: failed to stream to " << host_name_ << ":" << port_num_; } } private: // Creates a client socket and connects to the server. void MakeConnection(); // Closes the socket. void CloseConnection() override { GTEST_CHECK_(sockfd_ != -1) << "CloseConnection() can be called only when there is a connection."; close(sockfd_); sockfd_ = -1; } int sockfd_; // socket file descriptor const std::string host_name_; const std::string port_num_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); }; // class SocketWriter // Escapes '=', '&', '%', and '\n' characters in str as "%xx". static std::string UrlEncode(const char* str); StreamingListener(const std::string& host, const std::string& port) : socket_writer_(new SocketWriter(host, port)) { Start(); } explicit StreamingListener(AbstractSocketWriter* socket_writer) : socket_writer_(socket_writer) { Start(); } void OnTestProgramStart(const UnitTest& /* unit_test */) override { SendLn("event=TestProgramStart"); } void OnTestProgramEnd(const UnitTest& unit_test) override { // Note that Google Test current only report elapsed time for each // test iteration, not for the entire test program. SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); // Notify the streaming server to stop. socket_writer_->CloseConnection(); } void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) override { SendLn("event=TestIterationStart&iteration=" + StreamableToString(iteration)); } void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) override { SendLn("event=TestIterationEnd&passed=" + FormatBool(unit_test.Passed()) + "&elapsed_time=" + StreamableToString(unit_test.elapsed_time()) + "ms"); } // Note that "event=TestCaseStart" is a wire format and has to remain // "case" for compatibilty void OnTestCaseStart(const TestCase& test_case) override { SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); } // Note that "event=TestCaseEnd" is a wire format and has to remain // "case" for compatibilty void OnTestCaseEnd(const TestCase& test_case) override { SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) + "ms"); } void OnTestStart(const TestInfo& test_info) override { SendLn(std::string("event=TestStart&name=") + test_info.name()); } void OnTestEnd(const TestInfo& test_info) override { SendLn("event=TestEnd&passed=" + FormatBool((test_info.result())->Passed()) + "&elapsed_time=" + StreamableToString((test_info.result())->elapsed_time()) + "ms"); } void OnTestPartResult(const TestPartResult& test_part_result) override { const char* file_name = test_part_result.file_name(); if (file_name == nullptr) file_name = ""; SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + "&line=" + StreamableToString(test_part_result.line_number()) + "&message=" + UrlEncode(test_part_result.message())); } private: // Sends the given message and a newline to the socket. void SendLn(const std::string& message) { socket_writer_->SendLn(message); } // Called at the start of streaming to notify the receiver what // protocol we are using. void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } std::string FormatBool(bool value) { return value ? "1" : "0"; } const std::unique_ptr socket_writer_; GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); }; // class StreamingListener #endif // GTEST_CAN_STREAM_RESULTS_ } // namespace internal } // namespace testing GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 #endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ openzwave-1.6.1914/cpp/test/src/gtest-filepath.cc0000644000175200017520000003373314032142455016510 00000000000000// Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "gtest/internal/gtest-filepath.h" #include #include "gtest/internal/gtest-port.h" #include "gtest/gtest-message.h" #if GTEST_OS_WINDOWS_MOBILE # include #elif GTEST_OS_WINDOWS # include # include #else # include # include // Some Linux distributions define PATH_MAX here. #endif // GTEST_OS_WINDOWS_MOBILE #include "gtest/internal/gtest-string.h" #if GTEST_OS_WINDOWS # define GTEST_PATH_MAX_ _MAX_PATH #elif defined(PATH_MAX) # define GTEST_PATH_MAX_ PATH_MAX #elif defined(_XOPEN_PATH_MAX) # define GTEST_PATH_MAX_ _XOPEN_PATH_MAX #else # define GTEST_PATH_MAX_ _POSIX_PATH_MAX #endif // GTEST_OS_WINDOWS namespace testing { namespace internal { #if GTEST_OS_WINDOWS // On Windows, '\\' is the standard path separator, but many tools and the // Windows API also accept '/' as an alternate path separator. Unless otherwise // noted, a file path can contain either kind of path separators, or a mixture // of them. const char kPathSeparator = '\\'; const char kAlternatePathSeparator = '/'; const char kAlternatePathSeparatorString[] = "/"; # if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory. You should not use // the current directory in tests on Windows CE, but this at least // provides a reasonable fallback. const char kCurrentDirectoryString[] = "\\"; // Windows CE doesn't define INVALID_FILE_ATTRIBUTES const DWORD kInvalidFileAttributes = 0xffffffff; # else const char kCurrentDirectoryString[] = ".\\"; # endif // GTEST_OS_WINDOWS_MOBILE #else const char kPathSeparator = '/'; const char kCurrentDirectoryString[] = "./"; #endif // GTEST_OS_WINDOWS // Returns whether the given character is a valid path separator. static bool IsPathSeparator(char c) { #if GTEST_HAS_ALT_PATH_SEP_ return (c == kPathSeparator) || (c == kAlternatePathSeparator); #else return c == kPathSeparator; #endif } // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { #if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \ GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_ESP32 // These platforms do not have a current directory, so we just return // something reasonable. return FilePath(kCurrentDirectoryString); #elif GTEST_OS_WINDOWS char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; return FilePath(_getcwd(cwd, sizeof(cwd)) == nullptr ? "" : cwd); #else char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; char* result = getcwd(cwd, sizeof(cwd)); # if GTEST_OS_NACL // getcwd will likely fail in NaCl due to the sandbox, so return something // reasonable. The user may have provided a shim implementation for getcwd, // however, so fallback only when failure is detected. return FilePath(result == nullptr ? kCurrentDirectoryString : cwd); # endif // GTEST_OS_NACL return FilePath(result == nullptr ? "" : cwd); #endif // GTEST_OS_WINDOWS_MOBILE } // Returns a copy of the FilePath with the case-insensitive extension removed. // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns // FilePath("dir/file"). If a case-insensitive extension is not // found, returns a copy of the original FilePath. FilePath FilePath::RemoveExtension(const char* extension) const { const std::string dot_extension = std::string(".") + extension; if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) { return FilePath(pathname_.substr( 0, pathname_.length() - dot_extension.length())); } return *this; } // Returns a pointer to the last occurrence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FilePath::FindLastPathSeparator() const { const char* const last_sep = strrchr(c_str(), kPathSeparator); #if GTEST_HAS_ALT_PATH_SEP_ const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); // Comparing two pointers of which only one is NULL is undefined. if (last_alt_sep != nullptr && (last_sep == nullptr || last_alt_sep > last_sep)) { return last_alt_sep; } #endif return last_sep; } // Returns a copy of the FilePath with the directory part removed. // Example: FilePath("path/to/file").RemoveDirectoryName() returns // FilePath("file"). If there is no directory part ("just_a_file"), it returns // the FilePath unmodified. If there is no file part ("just_a_dir/") it // returns an empty FilePath (""). // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveDirectoryName() const { const char* const last_sep = FindLastPathSeparator(); return last_sep ? FilePath(last_sep + 1) : *this; } // RemoveFileName returns the directory path with the filename removed. // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". // If the FilePath is "a_file" or "/a_file", RemoveFileName returns // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does // not have a file, like "just/a/dir/", it returns the FilePath unmodified. // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveFileName() const { const char* const last_sep = FindLastPathSeparator(); std::string dir; if (last_sep) { dir = std::string(c_str(), static_cast(last_sep + 1 - c_str())); } else { dir = kCurrentDirectoryString; } return FilePath(dir); } // Helper functions for naming files in a directory for xml output. // Given directory = "dir", base_name = "test", number = 0, // extension = "xml", returns "dir/test.xml". If number is greater // than zero (e.g., 12), returns "dir/test_12.xml". // On Windows platform, uses \ as the separator rather than /. FilePath FilePath::MakeFileName(const FilePath& directory, const FilePath& base_name, int number, const char* extension) { std::string file; if (number == 0) { file = base_name.string() + "." + extension; } else { file = base_name.string() + "_" + StreamableToString(number) + "." + extension; } return ConcatPaths(directory, FilePath(file)); } // Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". // On Windows, uses \ as the separator rather than /. FilePath FilePath::ConcatPaths(const FilePath& directory, const FilePath& relative_path) { if (directory.IsEmpty()) return relative_path; const FilePath dir(directory.RemoveTrailingPathSeparator()); return FilePath(dir.string() + kPathSeparator + relative_path.string()); } // Returns true if pathname describes something findable in the file-system, // either a file, directory, or whatever. bool FilePath::FileOrDirectoryExists() const { #if GTEST_OS_WINDOWS_MOBILE LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); const DWORD attributes = GetFileAttributes(unicode); delete [] unicode; return attributes != kInvalidFileAttributes; #else posix::StatStruct file_stat; return posix::Stat(pathname_.c_str(), &file_stat) == 0; #endif // GTEST_OS_WINDOWS_MOBILE } // Returns true if pathname describes a directory in the file-system // that exists. bool FilePath::DirectoryExists() const { bool result = false; #if GTEST_OS_WINDOWS // Don't strip off trailing separator if path is a root directory on // Windows (like "C:\\"). const FilePath& path(IsRootDirectory() ? *this : RemoveTrailingPathSeparator()); #else const FilePath& path(*this); #endif #if GTEST_OS_WINDOWS_MOBILE LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); const DWORD attributes = GetFileAttributes(unicode); delete [] unicode; if ((attributes != kInvalidFileAttributes) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) { result = true; } #else posix::StatStruct file_stat; result = posix::Stat(path.c_str(), &file_stat) == 0 && posix::IsDir(file_stat); #endif // GTEST_OS_WINDOWS_MOBILE return result; } // Returns true if pathname describes a root directory. (Windows has one // root directory per disk drive.) bool FilePath::IsRootDirectory() const { #if GTEST_OS_WINDOWS return pathname_.length() == 3 && IsAbsolutePath(); #else return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); #endif } // Returns true if pathname describes an absolute path. bool FilePath::IsAbsolutePath() const { const char* const name = pathname_.c_str(); #if GTEST_OS_WINDOWS return pathname_.length() >= 3 && ((name[0] >= 'a' && name[0] <= 'z') || (name[0] >= 'A' && name[0] <= 'Z')) && name[1] == ':' && IsPathSeparator(name[2]); #else return IsPathSeparator(name[0]); #endif } // Returns a pathname for a file that does not currently exist. The pathname // will be directory/base_name.extension or // directory/base_name_.extension if directory/base_name.extension // already exists. The number will be incremented until a pathname is found // that does not already exist. // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. // There could be a race condition if two or more processes are calling this // function at the same time -- they could both pick the same filename. FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, const FilePath& base_name, const char* extension) { FilePath full_pathname; int number = 0; do { full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); } while (full_pathname.FileOrDirectoryExists()); return full_pathname; } // Returns true if FilePath ends with a path separator, which indicates that // it is intended to represent a directory. Returns false otherwise. // This does NOT check that a directory (or file) actually exists. bool FilePath::IsDirectory() const { return !pathname_.empty() && IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); } // Create directories so that path exists. Returns true if successful or if // the directories already exist; returns false if unable to create directories // for any reason. bool FilePath::CreateDirectoriesRecursively() const { if (!this->IsDirectory()) { return false; } if (pathname_.length() == 0 || this->DirectoryExists()) { return true; } const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); return parent.CreateDirectoriesRecursively() && this->CreateFolder(); } // Create the directory so that path exists. Returns true if successful or // if the directory already exists; returns false if unable to create the // directory for any reason, including if the parent directory does not // exist. Not named "CreateDirectory" because that's a macro on Windows. bool FilePath::CreateFolder() const { #if GTEST_OS_WINDOWS_MOBILE FilePath removed_sep(this->RemoveTrailingPathSeparator()); LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); int result = CreateDirectory(unicode, nullptr) ? 0 : -1; delete [] unicode; #elif GTEST_OS_WINDOWS int result = _mkdir(pathname_.c_str()); #elif GTEST_OS_ESP8266 // do nothing int result = 0; #else int result = mkdir(pathname_.c_str(), 0777); #endif // GTEST_OS_WINDOWS_MOBILE if (result == -1) { return this->DirectoryExists(); // An error is OK if the directory exists. } return true; // No error. } // If input name has a trailing separator character, remove it and return the // name, otherwise return the name string unmodified. // On Windows platform, uses \ as the separator, other platforms use /. FilePath FilePath::RemoveTrailingPathSeparator() const { return IsDirectory() ? FilePath(pathname_.substr(0, pathname_.length() - 1)) : *this; } // Removes any redundant separators that might be in the pathname. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". void FilePath::Normalize() { if (pathname_.c_str() == nullptr) { pathname_ = ""; return; } const char* src = pathname_.c_str(); char* const dest = new char[pathname_.length() + 1]; char* dest_ptr = dest; memset(dest_ptr, 0, pathname_.length() + 1); while (*src != '\0') { *dest_ptr = *src; if (!IsPathSeparator(*src)) { src++; } else { #if GTEST_HAS_ALT_PATH_SEP_ if (*dest_ptr == kAlternatePathSeparator) { *dest_ptr = kPathSeparator; } #endif while (IsPathSeparator(*src)) src++; } dest_ptr++; } *dest_ptr = '\0'; pathname_ = dest; delete[] dest; } } // namespace internal } // namespace testing openzwave-1.6.1914/cpp/test/src/gtest-typed-test.cc0000644000175200017520000000752314032142455017014 00000000000000// Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "gtest/gtest-typed-test.h" #include "gtest/gtest.h" namespace testing { namespace internal { #if GTEST_HAS_TYPED_TEST_P // Skips to the first non-space char in str. Returns an empty string if str // contains only whitespace characters. static const char* SkipSpaces(const char* str) { while (IsSpace(*str)) str++; return str; } static std::vector SplitIntoTestNames(const char* src) { std::vector name_vec; src = SkipSpaces(src); for (; src != nullptr; src = SkipComma(src)) { name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src))); } return name_vec; } // Verifies that registered_tests match the test names in // registered_tests_; returns registered_tests if successful, or // aborts the program otherwise. const char* TypedTestSuitePState::VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests) { typedef RegisteredTestsMap::const_iterator RegisteredTestIter; registered_ = true; std::vector name_vec = SplitIntoTestNames(registered_tests); Message errors; std::set tests; for (std::vector::const_iterator name_it = name_vec.begin(); name_it != name_vec.end(); ++name_it) { const std::string& name = *name_it; if (tests.count(name) != 0) { errors << "Test " << name << " is listed more than once.\n"; continue; } bool found = false; for (RegisteredTestIter it = registered_tests_.begin(); it != registered_tests_.end(); ++it) { if (name == it->first) { found = true; break; } } if (found) { tests.insert(name); } else { errors << "No test named " << name << " can be found in this test suite.\n"; } } for (RegisteredTestIter it = registered_tests_.begin(); it != registered_tests_.end(); ++it) { if (tests.count(it->first) == 0) { errors << "You forgot to list test " << it->first << ".\n"; } } const std::string& errors_str = errors.GetString(); if (errors_str != "") { fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), errors_str.c_str()); fflush(stderr); posix::Abort(); } return registered_tests; } #endif // GTEST_HAS_TYPED_TEST_P } // namespace internal } // namespace testing openzwave-1.6.1914/cpp/test/src/gtest-test-part.cc0000644000175200017520000001003614032142455016626 00000000000000// Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // The Google C++ Testing and Mocking Framework (Google Test) #include "gtest/gtest-test-part.h" #include "gtest/internal/gtest-port.h" #include "src/gtest-internal-inl.h" namespace testing { using internal::GetUnitTestImpl; // Gets the summary of the failure message by omitting the stack trace // in it. std::string TestPartResult::ExtractSummary(const char* message) { const char* const stack_trace = strstr(message, internal::kStackTraceMarker); return stack_trace == nullptr ? message : std::string(message, stack_trace); } // Prints a TestPartResult object. std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { return os << internal::FormatFileLocation(result.file_name(), result.line_number()) << " " << (result.type() == TestPartResult::kSuccess ? "Success" : result.type() == TestPartResult::kSkip ? "Skipped" : result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : "Non-fatal failure") << ":\n" << result.message() << std::endl; } // Appends a TestPartResult to the array. void TestPartResultArray::Append(const TestPartResult& result) { array_.push_back(result); } // Returns the TestPartResult at the given index (0-based). const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { if (index < 0 || index >= size()) { printf("\nInvalid index (%d) into TestPartResultArray.\n", index); internal::posix::Abort(); } return array_[static_cast(index)]; } // Returns the number of TestPartResult objects in the array. int TestPartResultArray::size() const { return static_cast(array_.size()); } namespace internal { HasNewFatalFailureHelper::HasNewFatalFailureHelper() : has_new_fatal_failure_(false), original_reporter_(GetUnitTestImpl()-> GetTestPartResultReporterForCurrentThread()) { GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); } HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( original_reporter_); } void HasNewFatalFailureHelper::ReportTestPartResult( const TestPartResult& result) { if (result.fatally_failed()) has_new_fatal_failure_ = true; original_reporter_->ReportTestPartResult(result); } } // namespace internal } // namespace testing openzwave-1.6.1914/cpp/test/src/gtest.cc0000644000175200017520000067230714032142455014724 00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // The Google C++ Testing and Mocking Framework (Google Test) #include "gtest/gtest.h" #include "gtest/internal/custom/gtest.h" #include "gtest/gtest-spi.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include // NOLINT #include #include #if GTEST_OS_LINUX # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # include // NOLINT # include // NOLINT // Declares vsnprintf(). This header is not available on Windows. # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # include #elif GTEST_OS_ZOS # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT // On z/OS we additionally need strings.h for strcasecmp. # include // NOLINT #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. # include // NOLINT # undef min #elif GTEST_OS_WINDOWS // We are on Windows proper. # include // NOLINT # undef min # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # endif // GTEST_OS_WINDOWS_MINGW #else // Assume other platforms have gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT # include // NOLINT #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS # include #endif #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT #endif #include "src/gtest-internal-inl.h" #if GTEST_OS_WINDOWS # define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS #if GTEST_OS_MAC #ifndef GTEST_OS_IOS #include #endif #endif #if GTEST_HAS_ABSL #include "absl/debugging/failure_signal_handler.h" #include "absl/debugging/stacktrace.h" #include "absl/debugging/symbolize.h" #include "absl/strings/str_cat.h" #endif // GTEST_HAS_ABSL namespace testing { using internal::CountIf; using internal::ForEach; using internal::GetElementOr; using internal::Shuffle; // Constants. // A test whose test suite name or test name matches this filter is // disabled and not run. static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; // A test suite whose name matches this filter is considered a death // test suite and will be run before test suites whose name doesn't // match this filter. static const char kDeathTestSuiteFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; // The default output format. static const char kDefaultOutputFormat[] = "xml"; // The default output file. static const char kDefaultOutputFile[] = "test_detail"; // The environment variable name for the test shard index. static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; // The environment variable name for the total number of test shards. static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; // The environment variable name for the test shard status file. static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; namespace internal { // The text used in failure messages to indicate the start of the // stack trace. const char kStackTraceMarker[] = "\nStack trace:\n"; // g_help_flag is true if and only if the --help flag or an equivalent form // is specified on the command line. bool g_help_flag = false; // Utilty function to Open File for Writing static FILE* OpenFileForWriting(const std::string& output_file) { FILE* fileout = nullptr; FilePath output_file_path(output_file); FilePath output_dir(output_file_path.RemoveFileName()); if (output_dir.CreateDirectoriesRecursively()) { fileout = posix::FOpen(output_file.c_str(), "w"); } if (fileout == nullptr) { GTEST_LOG_(FATAL) << "Unable to open file \"" << output_file << "\""; } return fileout; } } // namespace internal // Bazel passes in the argument to '--test_filter' via the TESTBRIDGE_TEST_ONLY // environment variable. static const char* GetDefaultFilter() { const char* const testbridge_test_only = internal::posix::GetEnv("TESTBRIDGE_TEST_ONLY"); if (testbridge_test_only != nullptr) { return testbridge_test_only; } return kUniversalFilter; } GTEST_DEFINE_bool_( also_run_disabled_tests, internal::BoolFromGTestEnv("also_run_disabled_tests", false), "Run disabled tests too, in addition to the tests normally being run."); GTEST_DEFINE_bool_( break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), "True if and only if a failed assertion should be a debugger " "break-point."); GTEST_DEFINE_bool_(catch_exceptions, internal::BoolFromGTestEnv("catch_exceptions", true), "True if and only if " GTEST_NAME_ " should catch exceptions and treat them as test failures."); GTEST_DEFINE_string_( color, internal::StringFromGTestEnv("color", "auto"), "Whether to use colors in the output. Valid values: yes, no, " "and auto. 'auto' means to use colors if the output is " "being sent to a terminal and the TERM environment variable " "is set to a terminal type that supports colors."); GTEST_DEFINE_string_( filter, internal::StringFromGTestEnv("filter", GetDefaultFilter()), "A colon-separated list of glob (not regex) patterns " "for filtering the tests to run, optionally followed by a " "'-' and a : separated list of negative patterns (tests to " "exclude). A test is run if it matches one of the positive " "patterns and does not match any of the negative patterns."); GTEST_DEFINE_bool_( install_failure_signal_handler, internal::BoolFromGTestEnv("install_failure_signal_handler", false), "If true and supported on the current platform, " GTEST_NAME_ " should " "install a signal handler that dumps debugging information when fatal " "signals are raised."); GTEST_DEFINE_bool_(list_tests, false, "List all tests without running them."); // The net priority order after flag processing is thus: // --gtest_output command line flag // GTEST_OUTPUT environment variable // XML_OUTPUT_FILE environment variable // '' GTEST_DEFINE_string_( output, internal::StringFromGTestEnv("output", internal::OutputFlagAlsoCheckEnvVar().c_str()), "A format (defaults to \"xml\" but can be specified to be \"json\"), " "optionally followed by a colon and an output file name or directory. " "A directory is indicated by a trailing pathname separator. " "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " "If a directory is specified, output files will be created " "within that directory, with file-names based on the test " "executable's name and, if necessary, made unique by adding " "digits."); GTEST_DEFINE_bool_(print_time, internal::BoolFromGTestEnv("print_time", true), "True if and only if " GTEST_NAME_ " should display elapsed time in text output."); GTEST_DEFINE_bool_(print_utf8, internal::BoolFromGTestEnv("print_utf8", true), "True if and only if " GTEST_NAME_ " prints UTF8 characters as text."); GTEST_DEFINE_int32_( random_seed, internal::Int32FromGTestEnv("random_seed", 0), "Random number seed to use when shuffling test orders. Must be in range " "[1, 99999], or 0 to use a seed based on the current time."); GTEST_DEFINE_int32_( repeat, internal::Int32FromGTestEnv("repeat", 1), "How many times to repeat each test. Specify a negative number " "for repeating forever. Useful for shaking out flaky tests."); GTEST_DEFINE_bool_(show_internal_stack_frames, false, "True if and only if " GTEST_NAME_ " should include internal stack frames when " "printing test failure stack traces."); GTEST_DEFINE_bool_(shuffle, internal::BoolFromGTestEnv("shuffle", false), "True if and only if " GTEST_NAME_ " should randomize tests' order on every run."); GTEST_DEFINE_int32_( stack_trace_depth, internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), "The maximum number of stack frames to print when an " "assertion fails. The valid range is 0 through 100, inclusive."); GTEST_DEFINE_string_( stream_result_to, internal::StringFromGTestEnv("stream_result_to", ""), "This flag specifies the host name and the port number on which to stream " "test results. Example: \"localhost:555\". The flag is effective only on " "Linux."); GTEST_DEFINE_bool_( throw_on_failure, internal::BoolFromGTestEnv("throw_on_failure", false), "When this flag is specified, a failed assertion will throw an exception " "if exceptions are enabled or exit the program with a non-zero code " "otherwise. For use with an external test framework."); #if GTEST_USE_OWN_FLAGFILE_FLAG_ GTEST_DEFINE_string_( flagfile, internal::StringFromGTestEnv("flagfile", ""), "This flag specifies the flagfile to read command-line flags from."); #endif // GTEST_USE_OWN_FLAGFILE_FLAG_ namespace internal { // Generates a random number from [0, range), using a Linear // Congruential Generator (LCG). Crashes if 'range' is 0 or greater // than kMaxRange. UInt32 Random::Generate(UInt32 range) { // These constants are the same as are used in glibc's rand(3). // Use wider types than necessary to prevent unsigned overflow diagnostics. state_ = static_cast(1103515245ULL*state_ + 12345U) % kMaxRange; GTEST_CHECK_(range > 0) << "Cannot generate a number in the range [0, 0)."; GTEST_CHECK_(range <= kMaxRange) << "Generation of a number in [0, " << range << ") was requested, " << "but this can only generate numbers in [0, " << kMaxRange << ")."; // Converting via modulus introduces a bit of downward bias, but // it's simple, and a linear congruential generator isn't too good // to begin with. return state_ % range; } // GTestIsInitialized() returns true if and only if the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). static bool GTestIsInitialized() { return GetArgvs().size() > 0; } // Iterates over a vector of TestSuites, keeping a running sum of the // results of calling a given int-returning method on each. // Returns the sum. static int SumOverTestSuiteList(const std::vector& case_list, int (TestSuite::*method)() const) { int sum = 0; for (size_t i = 0; i < case_list.size(); i++) { sum += (case_list[i]->*method)(); } return sum; } // Returns true if and only if the test suite passed. static bool TestSuitePassed(const TestSuite* test_suite) { return test_suite->should_run() && test_suite->Passed(); } // Returns true if and only if the test suite failed. static bool TestSuiteFailed(const TestSuite* test_suite) { return test_suite->should_run() && test_suite->Failed(); } // Returns true if and only if test_suite contains at least one test that // should run. static bool ShouldRunTestSuite(const TestSuite* test_suite) { return test_suite->should_run(); } // AssertHelper constructor. AssertHelper::AssertHelper(TestPartResult::Type type, const char* file, int line, const char* message) : data_(new AssertHelperData(type, file, line, message)) { } AssertHelper::~AssertHelper() { delete data_; } // Message assignment, for assertion streaming support. void AssertHelper::operator=(const Message& message) const { UnitTest::GetInstance()-> AddTestPartResult(data_->type, data_->file, data_->line, AppendUserMessage(data_->message, message), UnitTest::GetInstance()->impl() ->CurrentOsStackTraceExceptTop(1) // Skips the stack frame for this function itself. ); // NOLINT } // A copy of all command line arguments. Set by InitGoogleTest(). static ::std::vector g_argvs; ::std::vector GetArgvs() { #if defined(GTEST_CUSTOM_GET_ARGVS_) // GTEST_CUSTOM_GET_ARGVS_() may return a container of std::string or // ::string. This code converts it to the appropriate type. const auto& custom = GTEST_CUSTOM_GET_ARGVS_(); return ::std::vector(custom.begin(), custom.end()); #else // defined(GTEST_CUSTOM_GET_ARGVS_) return g_argvs; #endif // defined(GTEST_CUSTOM_GET_ARGVS_) } // Returns the current application's name, removing directory path if that // is present. FilePath GetCurrentExecutableName() { FilePath result; #if GTEST_OS_WINDOWS || GTEST_OS_OS2 result.Set(FilePath(GetArgvs()[0]).RemoveExtension("exe")); #else result.Set(FilePath(GetArgvs()[0])); #endif // GTEST_OS_WINDOWS return result.RemoveDirectoryName(); } // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. std::string UnitTestOptions::GetOutputFormat() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); const char* const colon = strchr(gtest_output_flag, ':'); return (colon == nullptr) ? std::string(gtest_output_flag) : std::string(gtest_output_flag, static_cast(colon - gtest_output_flag)); } // Returns the name of the requested output file, or the default if none // was explicitly specified. std::string UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); std::string format = GetOutputFormat(); if (format.empty()) format = std::string(kDefaultOutputFormat); const char* const colon = strchr(gtest_output_flag, ':'); if (colon == nullptr) return internal::FilePath::MakeFileName( internal::FilePath( UnitTest::GetInstance()->original_working_dir()), internal::FilePath(kDefaultOutputFile), 0, format.c_str()).string(); internal::FilePath output_name(colon + 1); if (!output_name.IsAbsolutePath()) output_name = internal::FilePath::ConcatPaths( internal::FilePath(UnitTest::GetInstance()->original_working_dir()), internal::FilePath(colon + 1)); if (!output_name.IsDirectory()) return output_name.string(); internal::FilePath result(internal::FilePath::GenerateUniqueFileName( output_name, internal::GetCurrentExecutableName(), GetOutputFormat().c_str())); return result.string(); } // Returns true if and only if the wildcard pattern matches the string. // The first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. bool UnitTestOptions::PatternMatchesString(const char *pattern, const char *str) { switch (*pattern) { case '\0': case ':': // Either ':' or '\0' marks the end of the pattern. return *str == '\0'; case '?': // Matches any single character. return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); case '*': // Matches any string (possibly empty) of characters. return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || PatternMatchesString(pattern + 1, str); default: // Non-special character. Matches itself. return *pattern == *str && PatternMatchesString(pattern + 1, str + 1); } } bool UnitTestOptions::MatchesFilter( const std::string& name, const char* filter) { const char *cur_pattern = filter; for (;;) { if (PatternMatchesString(cur_pattern, name.c_str())) { return true; } // Finds the next pattern in the filter. cur_pattern = strchr(cur_pattern, ':'); // Returns if no more pattern can be found. if (cur_pattern == nullptr) { return false; } // Skips the pattern separater (the ':' character). cur_pattern++; } } // Returns true if and only if the user-specified filter matches the test // suite name and the test name. bool UnitTestOptions::FilterMatchesTest(const std::string& test_suite_name, const std::string& test_name) { const std::string& full_name = test_suite_name + "." + test_name.c_str(); // Split --gtest_filter at '-', if there is one, to separate into // positive filter and negative filter portions const char* const p = GTEST_FLAG(filter).c_str(); const char* const dash = strchr(p, '-'); std::string positive; std::string negative; if (dash == nullptr) { positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter negative = ""; } else { positive = std::string(p, dash); // Everything up to the dash negative = std::string(dash + 1); // Everything after the dash if (positive.empty()) { // Treat '-test1' as the same as '*-test1' positive = kUniversalFilter; } } // A filter is a colon-separated list of patterns. It matches a // test if any pattern in it matches the test. return (MatchesFilter(full_name, positive.c_str()) && !MatchesFilter(full_name, negative.c_str())); } #if GTEST_HAS_SEH // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { // Google Test should handle a SEH exception if: // 1. the user wants it to, AND // 2. this is not a breakpoint exception, AND // 3. this is not a C++ exception (VC++ implements them via SEH, // apparently). // // SEH exception code for C++ exceptions. // (see http://support.microsoft.com/kb/185294 for more information). const DWORD kCxxExceptionCode = 0xe06d7363; bool should_handle = true; if (!GTEST_FLAG(catch_exceptions)) should_handle = false; else if (exception_code == EXCEPTION_BREAKPOINT) should_handle = false; else if (exception_code == kCxxExceptionCode) should_handle = false; return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; } #endif // GTEST_HAS_SEH } // namespace internal // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. Intercepts only failures from the current thread. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( TestPartResultArray* result) : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), result_(result) { Init(); } // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( InterceptMode intercept_mode, TestPartResultArray* result) : intercept_mode_(intercept_mode), result_(result) { Init(); } void ScopedFakeTestPartResultReporter::Init() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { old_reporter_ = impl->GetGlobalTestPartResultReporter(); impl->SetGlobalTestPartResultReporter(this); } else { old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); impl->SetTestPartResultReporterForCurrentThread(this); } } // The d'tor restores the test part result reporter used by Google Test // before. ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { impl->SetGlobalTestPartResultReporter(old_reporter_); } else { impl->SetTestPartResultReporterForCurrentThread(old_reporter_); } } // Increments the test part result count and remembers the result. // This method is from the TestPartResultReporterInterface interface. void ScopedFakeTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { result_->Append(result); } namespace internal { // Returns the type ID of ::testing::Test. We should always call this // instead of GetTypeId< ::testing::Test>() to get the type ID of // testing::Test. This is to work around a suspected linker bug when // using Google Test as a framework on Mac OS X. The bug causes // GetTypeId< ::testing::Test>() to return different values depending // on whether the call is from the Google Test framework itself or // from user test code. GetTestTypeId() is guaranteed to always // return the same value, as it always calls GetTypeId<>() from the // gtest.cc, which is within the Google Test framework. TypeId GetTestTypeId() { return GetTypeId(); } // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); // This predicate-formatter checks that 'results' contains a test part // failure of the given type and that the failure message contains the // given substring. static AssertionResult HasOneFailure(const char* /* results_expr */, const char* /* type_expr */, const char* /* substr_expr */, const TestPartResultArray& results, TestPartResult::Type type, const std::string& substr) { const std::string expected(type == TestPartResult::kFatalFailure ? "1 fatal failure" : "1 non-fatal failure"); Message msg; if (results.size() != 1) { msg << "Expected: " << expected << "\n" << " Actual: " << results.size() << " failures"; for (int i = 0; i < results.size(); i++) { msg << "\n" << results.GetTestPartResult(i); } return AssertionFailure() << msg; } const TestPartResult& r = results.GetTestPartResult(0); if (r.type() != type) { return AssertionFailure() << "Expected: " << expected << "\n" << " Actual:\n" << r; } if (strstr(r.message(), substr.c_str()) == nullptr) { return AssertionFailure() << "Expected: " << expected << " containing \"" << substr << "\"\n" << " Actual:\n" << r; } return AssertionSuccess(); } // The constructor of SingleFailureChecker remembers where to look up // test part results, what type of failure we expect, and what // substring the failure message should contain. SingleFailureChecker::SingleFailureChecker(const TestPartResultArray* results, TestPartResult::Type type, const std::string& substr) : results_(results), type_(type), substr_(substr) {} // The destructor of SingleFailureChecker verifies that the given // TestPartResultArray contains exactly one failure that has the given // type and contains the given substring. If that's not the case, a // non-fatal failure will be generated. SingleFailureChecker::~SingleFailureChecker() { EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); } DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( UnitTestImpl* unit_test) : unit_test_(unit_test) {} void DefaultGlobalTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->current_test_result()->AddTestPartResult(result); unit_test_->listeners()->repeater()->OnTestPartResult(result); } DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( UnitTestImpl* unit_test) : unit_test_(unit_test) {} void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); } // Returns the global test part result reporter. TestPartResultReporterInterface* UnitTestImpl::GetGlobalTestPartResultReporter() { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); return global_test_part_result_repoter_; } // Sets the global test part result reporter. void UnitTestImpl::SetGlobalTestPartResultReporter( TestPartResultReporterInterface* reporter) { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); global_test_part_result_repoter_ = reporter; } // Returns the test part result reporter for the current thread. TestPartResultReporterInterface* UnitTestImpl::GetTestPartResultReporterForCurrentThread() { return per_thread_test_part_result_reporter_.get(); } // Sets the test part result reporter for the current thread. void UnitTestImpl::SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter) { per_thread_test_part_result_reporter_.set(reporter); } // Gets the number of successful test suites. int UnitTestImpl::successful_test_suite_count() const { return CountIf(test_suites_, TestSuitePassed); } // Gets the number of failed test suites. int UnitTestImpl::failed_test_suite_count() const { return CountIf(test_suites_, TestSuiteFailed); } // Gets the number of all test suites. int UnitTestImpl::total_test_suite_count() const { return static_cast(test_suites_.size()); } // Gets the number of all test suites that contain at least one test // that should run. int UnitTestImpl::test_suite_to_run_count() const { return CountIf(test_suites_, ShouldRunTestSuite); } // Gets the number of successful tests. int UnitTestImpl::successful_test_count() const { return SumOverTestSuiteList(test_suites_, &TestSuite::successful_test_count); } // Gets the number of skipped tests. int UnitTestImpl::skipped_test_count() const { return SumOverTestSuiteList(test_suites_, &TestSuite::skipped_test_count); } // Gets the number of failed tests. int UnitTestImpl::failed_test_count() const { return SumOverTestSuiteList(test_suites_, &TestSuite::failed_test_count); } // Gets the number of disabled tests that will be reported in the XML report. int UnitTestImpl::reportable_disabled_test_count() const { return SumOverTestSuiteList(test_suites_, &TestSuite::reportable_disabled_test_count); } // Gets the number of disabled tests. int UnitTestImpl::disabled_test_count() const { return SumOverTestSuiteList(test_suites_, &TestSuite::disabled_test_count); } // Gets the number of tests to be printed in the XML report. int UnitTestImpl::reportable_test_count() const { return SumOverTestSuiteList(test_suites_, &TestSuite::reportable_test_count); } // Gets the number of all tests. int UnitTestImpl::total_test_count() const { return SumOverTestSuiteList(test_suites_, &TestSuite::total_test_count); } // Gets the number of tests that should run. int UnitTestImpl::test_to_run_count() const { return SumOverTestSuiteList(test_suites_, &TestSuite::test_to_run_count); } // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { return os_stack_trace_getter()->CurrentStackTrace( static_cast(GTEST_FLAG(stack_trace_depth)), skip_count + 1 // Skips the user-specified number of frames plus this function // itself. ); // NOLINT } // Returns the current time in milliseconds. TimeInMillis GetTimeInMillis() { #if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) // Difference between 1970-01-01 and 1601-01-01 in milliseconds. // http://analogous.blogspot.com/2005/04/epoch.html const TimeInMillis kJavaEpochToWinFileTimeDelta = static_cast(116444736UL) * 100000UL; const DWORD kTenthMicrosInMilliSecond = 10000; SYSTEMTIME now_systime; FILETIME now_filetime; ULARGE_INTEGER now_int64; GetSystemTime(&now_systime); if (SystemTimeToFileTime(&now_systime, &now_filetime)) { now_int64.LowPart = now_filetime.dwLowDateTime; now_int64.HighPart = now_filetime.dwHighDateTime; now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - kJavaEpochToWinFileTimeDelta; return now_int64.QuadPart; } return 0; #elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ __timeb64 now; // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. GTEST_DISABLE_MSC_DEPRECATED_PUSH_() _ftime64(&now); GTEST_DISABLE_MSC_DEPRECATED_POP_() return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; gettimeofday(&now, nullptr); return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; #else # error "Don't know how to get the current time on your system." #endif } // Utilities // class String. #if GTEST_OS_WINDOWS_MOBILE // Creates a UTF-16 wide string from the given ANSI string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the wide string, or NULL if the // input is NULL. LPCWSTR String::AnsiToUtf16(const char* ansi) { if (!ansi) return nullptr; const int length = strlen(ansi); const int unicode_length = MultiByteToWideChar(CP_ACP, 0, ansi, length, nullptr, 0); WCHAR* unicode = new WCHAR[unicode_length + 1]; MultiByteToWideChar(CP_ACP, 0, ansi, length, unicode, unicode_length); unicode[unicode_length] = 0; return unicode; } // Creates an ANSI string from the given wide string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { if (!utf16_str) return nullptr; const int ansi_length = WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, nullptr, 0, nullptr, nullptr); char* ansi = new char[ansi_length + 1]; WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, ansi, ansi_length, nullptr, nullptr); ansi[ansi_length] = 0; return ansi; } #endif // GTEST_OS_WINDOWS_MOBILE // Compares two C strings. Returns true if and only if they have the same // content. // // Unlike strcmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::CStringEquals(const char * lhs, const char * rhs) { if (lhs == nullptr) return rhs == nullptr; if (rhs == nullptr) return false; return strcmp(lhs, rhs) == 0; } #if GTEST_HAS_STD_WSTRING // Converts an array of wide chars to a narrow string using the UTF-8 // encoding, and streams the result to the given Message object. static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, Message* msg) { for (size_t i = 0; i != length; ) { // NOLINT if (wstr[i] != L'\0') { *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); while (i != length && wstr[i] != L'\0') i++; } else { *msg << '\0'; i++; } } } #endif // GTEST_HAS_STD_WSTRING void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest) { ::std::vector< ::std::string> parsed; ::std::string::size_type pos = 0; while (::testing::internal::AlwaysTrue()) { const ::std::string::size_type colon = str.find(delimiter, pos); if (colon == ::std::string::npos) { parsed.push_back(str.substr(pos)); break; } else { parsed.push_back(str.substr(pos, colon - pos)); pos = colon + 1; } } dest->swap(parsed); } } // namespace internal // Constructs an empty Message. // We allocate the stringstream separately because otherwise each use of // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's // stack frame leading to huge stack frames in some cases; gcc does not reuse // the stack space. Message::Message() : ss_(new ::std::stringstream) { // By default, we want there to be enough precision when printing // a double to a Message. *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); } // These two overloads allow streaming a wide C string to a Message // using the UTF-8 encoding. Message& Message::operator <<(const wchar_t* wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } Message& Message::operator <<(wchar_t* wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } #if GTEST_HAS_STD_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& Message::operator <<(const ::std::wstring& wstr) { internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); return *this; } #endif // GTEST_HAS_STD_WSTRING // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". std::string Message::GetString() const { return internal::StringStreamToString(ss_.get()); } // AssertionResult constructors. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult::AssertionResult(const AssertionResult& other) : success_(other.success_), message_(other.message_.get() != nullptr ? new ::std::string(*other.message_) : static_cast< ::std::string*>(nullptr)) {} // Swaps two AssertionResults. void AssertionResult::swap(AssertionResult& other) { using std::swap; swap(success_, other.success_); swap(message_, other.message_); } // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult AssertionResult::operator!() const { AssertionResult negation(!success_); if (message_.get() != nullptr) negation << *message_; return negation; } // Makes a successful assertion result. AssertionResult AssertionSuccess() { return AssertionResult(true); } // Makes a failed assertion result. AssertionResult AssertionFailure() { return AssertionResult(false); } // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << message. AssertionResult AssertionFailure(const Message& message) { return AssertionFailure() << message; } namespace internal { namespace edit_distance { std::vector CalculateOptimalEdits(const std::vector& left, const std::vector& right) { std::vector > costs( left.size() + 1, std::vector(right.size() + 1)); std::vector > best_move( left.size() + 1, std::vector(right.size() + 1)); // Populate for empty right. for (size_t l_i = 0; l_i < costs.size(); ++l_i) { costs[l_i][0] = static_cast(l_i); best_move[l_i][0] = kRemove; } // Populate for empty left. for (size_t r_i = 1; r_i < costs[0].size(); ++r_i) { costs[0][r_i] = static_cast(r_i); best_move[0][r_i] = kAdd; } for (size_t l_i = 0; l_i < left.size(); ++l_i) { for (size_t r_i = 0; r_i < right.size(); ++r_i) { if (left[l_i] == right[r_i]) { // Found a match. Consume it. costs[l_i + 1][r_i + 1] = costs[l_i][r_i]; best_move[l_i + 1][r_i + 1] = kMatch; continue; } const double add = costs[l_i + 1][r_i]; const double remove = costs[l_i][r_i + 1]; const double replace = costs[l_i][r_i]; if (add < remove && add < replace) { costs[l_i + 1][r_i + 1] = add + 1; best_move[l_i + 1][r_i + 1] = kAdd; } else if (remove < add && remove < replace) { costs[l_i + 1][r_i + 1] = remove + 1; best_move[l_i + 1][r_i + 1] = kRemove; } else { // We make replace a little more expensive than add/remove to lower // their priority. costs[l_i + 1][r_i + 1] = replace + 1.00001; best_move[l_i + 1][r_i + 1] = kReplace; } } } // Reconstruct the best path. We do it in reverse order. std::vector best_path; for (size_t l_i = left.size(), r_i = right.size(); l_i > 0 || r_i > 0;) { EditType move = best_move[l_i][r_i]; best_path.push_back(move); l_i -= move != kAdd; r_i -= move != kRemove; } std::reverse(best_path.begin(), best_path.end()); return best_path; } namespace { // Helper class to convert string into ids with deduplication. class InternalStrings { public: size_t GetId(const std::string& str) { IdMap::iterator it = ids_.find(str); if (it != ids_.end()) return it->second; size_t id = ids_.size(); return ids_[str] = id; } private: typedef std::map IdMap; IdMap ids_; }; } // namespace std::vector CalculateOptimalEdits( const std::vector& left, const std::vector& right) { std::vector left_ids, right_ids; { InternalStrings intern_table; for (size_t i = 0; i < left.size(); ++i) { left_ids.push_back(intern_table.GetId(left[i])); } for (size_t i = 0; i < right.size(); ++i) { right_ids.push_back(intern_table.GetId(right[i])); } } return CalculateOptimalEdits(left_ids, right_ids); } namespace { // Helper class that holds the state for one hunk and prints it out to the // stream. // It reorders adds/removes when possible to group all removes before all // adds. It also adds the hunk header before printint into the stream. class Hunk { public: Hunk(size_t left_start, size_t right_start) : left_start_(left_start), right_start_(right_start), adds_(), removes_(), common_() {} void PushLine(char edit, const char* line) { switch (edit) { case ' ': ++common_; FlushEdits(); hunk_.push_back(std::make_pair(' ', line)); break; case '-': ++removes_; hunk_removes_.push_back(std::make_pair('-', line)); break; case '+': ++adds_; hunk_adds_.push_back(std::make_pair('+', line)); break; } } void PrintTo(std::ostream* os) { PrintHeader(os); FlushEdits(); for (std::list >::const_iterator it = hunk_.begin(); it != hunk_.end(); ++it) { *os << it->first << it->second << "\n"; } } bool has_edits() const { return adds_ || removes_; } private: void FlushEdits() { hunk_.splice(hunk_.end(), hunk_removes_); hunk_.splice(hunk_.end(), hunk_adds_); } // Print a unified diff header for one hunk. // The format is // "@@ -, +, @@" // where the left/right parts are omitted if unnecessary. void PrintHeader(std::ostream* ss) const { *ss << "@@ "; if (removes_) { *ss << "-" << left_start_ << "," << (removes_ + common_); } if (removes_ && adds_) { *ss << " "; } if (adds_) { *ss << "+" << right_start_ << "," << (adds_ + common_); } *ss << " @@\n"; } size_t left_start_, right_start_; size_t adds_, removes_, common_; std::list > hunk_, hunk_adds_, hunk_removes_; }; } // namespace // Create a list of diff hunks in Unified diff format. // Each hunk has a header generated by PrintHeader above plus a body with // lines prefixed with ' ' for no change, '-' for deletion and '+' for // addition. // 'context' represents the desired unchanged prefix/suffix around the diff. // If two hunks are close enough that their contexts overlap, then they are // joined into one hunk. std::string CreateUnifiedDiff(const std::vector& left, const std::vector& right, size_t context) { const std::vector edits = CalculateOptimalEdits(left, right); size_t l_i = 0, r_i = 0, edit_i = 0; std::stringstream ss; while (edit_i < edits.size()) { // Find first edit. while (edit_i < edits.size() && edits[edit_i] == kMatch) { ++l_i; ++r_i; ++edit_i; } // Find the first line to include in the hunk. const size_t prefix_context = std::min(l_i, context); Hunk hunk(l_i - prefix_context + 1, r_i - prefix_context + 1); for (size_t i = prefix_context; i > 0; --i) { hunk.PushLine(' ', left[l_i - i].c_str()); } // Iterate the edits until we found enough suffix for the hunk or the input // is over. size_t n_suffix = 0; for (; edit_i < edits.size(); ++edit_i) { if (n_suffix >= context) { // Continue only if the next hunk is very close. auto it = edits.begin() + static_cast(edit_i); while (it != edits.end() && *it == kMatch) ++it; if (it == edits.end() || static_cast(it - edits.begin()) - edit_i >= context) { // There is no next edit or it is too far away. break; } } EditType edit = edits[edit_i]; // Reset count when a non match is found. n_suffix = edit == kMatch ? n_suffix + 1 : 0; if (edit == kMatch || edit == kRemove || edit == kReplace) { hunk.PushLine(edit == kMatch ? ' ' : '-', left[l_i].c_str()); } if (edit == kAdd || edit == kReplace) { hunk.PushLine('+', right[r_i].c_str()); } // Advance indices, depending on edit type. l_i += edit != kAdd; r_i += edit != kRemove; } if (!hunk.has_edits()) { // We are done. We don't want this hunk. break; } hunk.PrintTo(&ss); } return ss.str(); } } // namespace edit_distance namespace { // The string representation of the values received in EqFailure() are already // escaped. Split them on escaped '\n' boundaries. Leave all other escaped // characters the same. std::vector SplitEscapedString(const std::string& str) { std::vector lines; size_t start = 0, end = str.size(); if (end > 2 && str[0] == '"' && str[end - 1] == '"') { ++start; --end; } bool escaped = false; for (size_t i = start; i + 1 < end; ++i) { if (escaped) { escaped = false; if (str[i] == 'n') { lines.push_back(str.substr(start, i - start - 1)); start = i + 1; } } else { escaped = str[i] == '\\'; } } lines.push_back(str.substr(start, end - start)); return lines; } } // namespace // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // // The first four parameters are the expressions used in the assertion // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // // lhs_expression: "foo" // rhs_expression: "bar" // lhs_value: "5" // rhs_value: "6" // // The ignoring_case parameter is true if and only if the assertion is a // *_STRCASEEQ*. When it's true, the string "Ignoring case" will // be inserted into the message. AssertionResult EqFailure(const char* lhs_expression, const char* rhs_expression, const std::string& lhs_value, const std::string& rhs_value, bool ignoring_case) { Message msg; msg << "Expected equality of these values:"; msg << "\n " << lhs_expression; if (lhs_value != lhs_expression) { msg << "\n Which is: " << lhs_value; } msg << "\n " << rhs_expression; if (rhs_value != rhs_expression) { msg << "\n Which is: " << rhs_value; } if (ignoring_case) { msg << "\nIgnoring case"; } if (!lhs_value.empty() && !rhs_value.empty()) { const std::vector lhs_lines = SplitEscapedString(lhs_value); const std::vector rhs_lines = SplitEscapedString(rhs_value); if (lhs_lines.size() > 1 || rhs_lines.size() > 1) { msg << "\nWith diff:\n" << edit_distance::CreateUnifiedDiff(lhs_lines, rhs_lines); } } return AssertionFailure() << msg; } // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. std::string GetBoolAssertionFailureMessage( const AssertionResult& assertion_result, const char* expression_text, const char* actual_predicate_value, const char* expected_predicate_value) { const char* actual_message = assertion_result.message(); Message msg; msg << "Value of: " << expression_text << "\n Actual: " << actual_predicate_value; if (actual_message[0] != '\0') msg << " (" << actual_message << ")"; msg << "\nExpected: " << expected_predicate_value; return msg.GetString(); } // Helper function for implementing ASSERT_NEAR. AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error) { const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); return AssertionFailure() << "The difference between " << expr1 << " and " << expr2 << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" << expr1 << " evaluates to " << val1 << ",\n" << expr2 << " evaluates to " << val2 << ", and\n" << abs_error_expr << " evaluates to " << abs_error << "."; } // Helper template for implementing FloatLE() and DoubleLE(). template AssertionResult FloatingPointLE(const char* expr1, const char* expr2, RawType val1, RawType val2) { // Returns success if val1 is less than val2, if (val1 < val2) { return AssertionSuccess(); } // or if val1 is almost equal to val2. const FloatingPoint lhs(val1), rhs(val2); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } // Note that the above two checks will both fail if either val1 or // val2 is NaN, as the IEEE floating-point standard requires that // any predicate involving a NaN must return false. ::std::stringstream val1_ss; val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val1; ::std::stringstream val2_ss; val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val2; return AssertionFailure() << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" << " Actual: " << StringStreamToString(&val1_ss) << " vs " << StringStreamToString(&val2_ss); } } // namespace internal // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. AssertionResult FloatLE(const char* expr1, const char* expr2, float val1, float val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. AssertionResult DoubleLE(const char* expr1, const char* expr2, double val1, double val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } namespace internal { // The helper function for {ASSERT|EXPECT}_EQ with int or enum // arguments. AssertionResult CmpHelperEQ(const char* lhs_expression, const char* rhs_expression, BiggestInt lhs, BiggestInt rhs) { if (lhs == rhs) { return AssertionSuccess(); } return EqFailure(lhs_expression, rhs_expression, FormatForComparisonFailureMessage(lhs, rhs), FormatForComparisonFailureMessage(rhs, lhs), false); } // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here // just to avoid copy-and-paste of similar code. #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ BiggestInt val1, BiggestInt val2) {\ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ return AssertionFailure() \ << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1);\ }\ } // Implements the helper function for {ASSERT|EXPECT}_NE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(NE, !=) // Implements the helper function for {ASSERT|EXPECT}_LE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(LE, <=) // Implements the helper function for {ASSERT|EXPECT}_LT with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(LT, < ) // Implements the helper function for {ASSERT|EXPECT}_GE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(GE, >=) // Implements the helper function for {ASSERT|EXPECT}_GT with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(GT, > ) #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. AssertionResult CmpHelperSTREQ(const char* lhs_expression, const char* rhs_expression, const char* lhs, const char* rhs) { if (String::CStringEquals(lhs, rhs)) { return AssertionSuccess(); } return EqFailure(lhs_expression, rhs_expression, PrintToString(lhs), PrintToString(rhs), false); } // The helper function for {ASSERT|EXPECT}_STRCASEEQ. AssertionResult CmpHelperSTRCASEEQ(const char* lhs_expression, const char* rhs_expression, const char* lhs, const char* rhs) { if (String::CaseInsensitiveCStringEquals(lhs, rhs)) { return AssertionSuccess(); } return EqFailure(lhs_expression, rhs_expression, PrintToString(lhs), PrintToString(rhs), true); } // The helper function for {ASSERT|EXPECT}_STRNE. AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2) { if (!String::CStringEquals(s1, s2)) { return AssertionSuccess(); } else { return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: \"" << s1 << "\" vs \"" << s2 << "\""; } } // The helper function for {ASSERT|EXPECT}_STRCASENE. AssertionResult CmpHelperSTRCASENE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2) { if (!String::CaseInsensitiveCStringEquals(s1, s2)) { return AssertionSuccess(); } else { return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << ") (ignoring case), actual: \"" << s1 << "\" vs \"" << s2 << "\""; } } } // namespace internal namespace { // Helper functions for implementing IsSubString() and IsNotSubstring(). // This group of overloaded functions return true if and only if needle // is a substring of haystack. NULL is considered a substring of // itself only. bool IsSubstringPred(const char* needle, const char* haystack) { if (needle == nullptr || haystack == nullptr) return needle == haystack; return strstr(haystack, needle) != nullptr; } bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { if (needle == nullptr || haystack == nullptr) return needle == haystack; return wcsstr(haystack, needle) != nullptr; } // StringType here can be either ::std::string or ::std::wstring. template bool IsSubstringPred(const StringType& needle, const StringType& haystack) { return haystack.find(needle) != StringType::npos; } // This function implements either IsSubstring() or IsNotSubstring(), // depending on the value of the expected_to_be_substring parameter. // StringType here can be const char*, const wchar_t*, ::std::string, // or ::std::wstring. template AssertionResult IsSubstringImpl( bool expected_to_be_substring, const char* needle_expr, const char* haystack_expr, const StringType& needle, const StringType& haystack) { if (IsSubstringPred(needle, haystack) == expected_to_be_substring) return AssertionSuccess(); const bool is_wide_string = sizeof(needle[0]) > 1; const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; return AssertionFailure() << "Value of: " << needle_expr << "\n" << " Actual: " << begin_string_quote << needle << "\"\n" << "Expected: " << (expected_to_be_substring ? "" : "not ") << "a substring of " << haystack_expr << "\n" << "Which is: " << begin_string_quote << haystack << "\""; } } // namespace // IsSubstring() and IsNotSubstring() check whether needle is a // substring of haystack (NULL is considered a substring of itself // only), and return an appropriate error message when they fail. AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #if GTEST_HAS_STD_WSTRING AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #endif // GTEST_HAS_STD_WSTRING namespace internal { #if GTEST_OS_WINDOWS namespace { // Helper function for IsHRESULT{SuccessFailure} predicates AssertionResult HRESULTFailureHelper(const char* expr, const char* expected, long hr) { // NOLINT # if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_TV_TITLE // Windows CE doesn't support FormatMessage. const char error_text[] = ""; # else // Looks up the human-readable system message for the HRESULT code // and since we're not passing any params to FormatMessage, we don't // want inserts expanded. const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; const DWORD kBufSize = 4096; // Gets the system's human readable message string for this HRESULT. char error_text[kBufSize] = { '\0' }; DWORD message_length = ::FormatMessageA(kFlags, 0, // no source, we're asking system static_cast(hr), // the error 0, // no line width restrictions error_text, // output buffer kBufSize, // buf size nullptr); // no arguments for inserts // Trims tailing white space (FormatMessage leaves a trailing CR-LF) for (; message_length && IsSpace(error_text[message_length - 1]); --message_length) { error_text[message_length - 1] = '\0'; } # endif // GTEST_OS_WINDOWS_MOBILE const std::string error_hex("0x" + String::FormatHexInt(hr)); return ::testing::AssertionFailure() << "Expected: " << expr << " " << expected << ".\n" << " Actual: " << error_hex << " " << error_text << "\n"; } } // namespace AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT if (SUCCEEDED(hr)) { return AssertionSuccess(); } return HRESULTFailureHelper(expr, "succeeds", hr); } AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT if (FAILED(hr)) { return AssertionSuccess(); } return HRESULTFailureHelper(expr, "fails", hr); } #endif // GTEST_OS_WINDOWS // Utility functions for encoding Unicode text (wide strings) in // UTF-8. // A Unicode code-point can have up to 21 bits, and is encoded in UTF-8 // like this: // // Code-point length Encoding // 0 - 7 bits 0xxxxxxx // 8 - 11 bits 110xxxxx 10xxxxxx // 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx // 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // The maximum code-point a one-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; // The maximum code-point a two-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; // The maximum code-point a three-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; // The maximum code-point a four-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; // Chops off the n lowest bits from a bit pattern. Returns the n // lowest bits. As a side effect, the original bit pattern will be // shifted to the right by n bits. inline UInt32 ChopLowBits(UInt32* bits, int n) { const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); *bits >>= n; return low_bits; } // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted // to "(Invalid Unicode 0xXXXXXXXX)". std::string CodePointToUtf8(UInt32 code_point) { if (code_point > kMaxCodePoint4) { return "(Invalid Unicode 0x" + String::FormatHexUInt32(code_point) + ")"; } char str[5]; // Big enough for the largest valid code point. if (code_point <= kMaxCodePoint1) { str[1] = '\0'; str[0] = static_cast(code_point); // 0xxxxxxx } else if (code_point <= kMaxCodePoint2) { str[2] = '\0'; str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xC0 | code_point); // 110xxxxx } else if (code_point <= kMaxCodePoint3) { str[3] = '\0'; str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xE0 | code_point); // 1110xxxx } else { // code_point <= kMaxCodePoint4 str[4] = '\0'; str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xF0 | code_point); // 11110xxx } return str; } // The following two functions only make sense if the system // uses UTF-16 for wide string encoding. All supported systems // with 16 bit wchar_t (Windows, Cygwin) do use UTF-16. // Determines if the arguments constitute UTF-16 surrogate pair // and thus should be combined into a single Unicode code point // using CreateCodePointFromUtf16SurrogatePair. inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { return sizeof(wchar_t) == 2 && (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; } // Creates a Unicode code point from UTF16 surrogate pair. inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, wchar_t second) { const auto first_u = static_cast(first); const auto second_u = static_cast(second); const UInt32 mask = (1 << 10) - 1; return (sizeof(wchar_t) == 2) ? (((first_u & mask) << 10) | (second_u & mask)) + 0x10000 : // This function should not be called when the condition is // false, but we provide a sensible default in case it is. first_u; } // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: // UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number // of wchar_t characters processed. -1 is used when the entire string // should be processed. // If the string contains code points that are not valid Unicode code points // (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. std::string WideStringToUtf8(const wchar_t* str, int num_chars) { if (num_chars == -1) num_chars = static_cast(wcslen(str)); ::std::stringstream stream; for (int i = 0; i < num_chars; ++i) { UInt32 unicode_code_point; if (str[i] == L'\0') { break; } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], str[i + 1]); i++; } else { unicode_code_point = static_cast(str[i]); } stream << CodePointToUtf8(unicode_code_point); } return StringStreamToString(&stream); } // Converts a wide C string to an std::string using the UTF-8 encoding. // NULL will be converted to "(null)". std::string String::ShowWideCString(const wchar_t * wide_c_str) { if (wide_c_str == nullptr) return "(null)"; return internal::WideStringToUtf8(wide_c_str, -1); } // Compares two wide C strings. Returns true if and only if they have the // same content. // // Unlike wcscmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { if (lhs == nullptr) return rhs == nullptr; if (rhs == nullptr) return false; return wcscmp(lhs, rhs) == 0; } // Helper function for *_STREQ on wide strings. AssertionResult CmpHelperSTREQ(const char* lhs_expression, const char* rhs_expression, const wchar_t* lhs, const wchar_t* rhs) { if (String::WideCStringEquals(lhs, rhs)) { return AssertionSuccess(); } return EqFailure(lhs_expression, rhs_expression, PrintToString(lhs), PrintToString(rhs), false); } // Helper function for *_STRNE on wide strings. AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2) { if (!String::WideCStringEquals(s1, s2)) { return AssertionSuccess(); } return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: " << PrintToString(s1) << " vs " << PrintToString(s2); } // Compares two C strings, ignoring case. Returns true if and only if they have // the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { if (lhs == nullptr) return rhs == nullptr; if (rhs == nullptr) return false; return posix::StrCaseCmp(lhs, rhs) == 0; } // Compares two wide C strings, ignoring case. Returns true if and only if they // have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, // including the empty string. // NB: The implementations on different platforms slightly differ. // On windows, this method uses _wcsicmp which compares according to LC_CTYPE // environment variable. On GNU platform this method uses wcscasecmp // which compares according to LC_CTYPE category of the current locale. // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the // current locale. bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs) { if (lhs == nullptr) return rhs == nullptr; if (rhs == nullptr) return false; #if GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; #elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID return wcscasecmp(lhs, rhs) == 0; #else // Android, Mac OS X and Cygwin don't define wcscasecmp. // Other unknown OSes may not define it either. wint_t left, right; do { left = towlower(static_cast(*lhs++)); right = towlower(static_cast(*rhs++)); } while (left && left == right); return left == right; #endif // OS selector } // Returns true if and only if str ends with the given suffix, ignoring case. // Any string is considered to end with an empty suffix. bool String::EndsWithCaseInsensitive( const std::string& str, const std::string& suffix) { const size_t str_len = str.length(); const size_t suffix_len = suffix.length(); return (str_len >= suffix_len) && CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len, suffix.c_str()); } // Formats an int value as "%02d". std::string String::FormatIntWidth2(int value) { std::stringstream ss; ss << std::setfill('0') << std::setw(2) << value; return ss.str(); } // Formats an int value as "%X". std::string String::FormatHexUInt32(UInt32 value) { std::stringstream ss; ss << std::hex << std::uppercase << value; return ss.str(); } // Formats an int value as "%X". std::string String::FormatHexInt(int value) { return FormatHexUInt32(static_cast(value)); } // Formats a byte as "%02X". std::string String::FormatByte(unsigned char value) { std::stringstream ss; ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << static_cast(value); return ss.str(); } // Converts the buffer in a stringstream to an std::string, converting NUL // bytes to "\\0" along the way. std::string StringStreamToString(::std::stringstream* ss) { const ::std::string& str = ss->str(); const char* const start = str.c_str(); const char* const end = start + str.length(); std::string result; result.reserve(static_cast(2 * (end - start))); for (const char* ch = start; ch != end; ++ch) { if (*ch == '\0') { result += "\\0"; // Replaces NUL with "\\0"; } else { result += *ch; } } return result; } // Appends the user-supplied message to the Google-Test-generated message. std::string AppendUserMessage(const std::string& gtest_msg, const Message& user_msg) { // Appends the user message if it's non-empty. const std::string user_msg_string = user_msg.GetString(); if (user_msg_string.empty()) { return gtest_msg; } return gtest_msg + "\n" + user_msg_string; } } // namespace internal // class TestResult // Creates an empty TestResult. TestResult::TestResult() : death_test_count_(0), start_timestamp_(0), elapsed_time_(0) {} // D'tor. TestResult::~TestResult() { } // Returns the i-th test part result among all the results. i can // range from 0 to total_part_count() - 1. If i is not in that range, // aborts the program. const TestPartResult& TestResult::GetTestPartResult(int i) const { if (i < 0 || i >= total_part_count()) internal::posix::Abort(); return test_part_results_.at(static_cast(i)); } // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& TestResult::GetTestProperty(int i) const { if (i < 0 || i >= test_property_count()) internal::posix::Abort(); return test_properties_.at(static_cast(i)); } // Clears the test part results. void TestResult::ClearTestPartResults() { test_part_results_.clear(); } // Adds a test part result to the list. void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { test_part_results_.push_back(test_part_result); } // Adds a test property to the list. If a property with the same key as the // supplied property is already represented, the value of this test_property // replaces the old value for that key. void TestResult::RecordProperty(const std::string& xml_element, const TestProperty& test_property) { if (!ValidateTestProperty(xml_element, test_property)) { return; } internal::MutexLock lock(&test_properites_mutex_); const std::vector::iterator property_with_matching_key = std::find_if(test_properties_.begin(), test_properties_.end(), internal::TestPropertyKeyIs(test_property.key())); if (property_with_matching_key == test_properties_.end()) { test_properties_.push_back(test_property); return; } property_with_matching_key->SetValue(test_property.value()); } // The list of reserved attributes used in the element of XML // output. static const char* const kReservedTestSuitesAttributes[] = { "disabled", "errors", "failures", "name", "random_seed", "tests", "time", "timestamp" }; // The list of reserved attributes used in the element of XML // output. static const char* const kReservedTestSuiteAttributes[] = { "disabled", "errors", "failures", "name", "tests", "time", "timestamp"}; // The list of reserved attributes used in the element of XML output. static const char* const kReservedTestCaseAttributes[] = { "classname", "name", "status", "time", "type_param", "value_param", "file", "line"}; // Use a slightly different set for allowed output to ensure existing tests can // still RecordProperty("result") or "RecordProperty(timestamp") static const char* const kReservedOutputTestCaseAttributes[] = { "classname", "name", "status", "time", "type_param", "value_param", "file", "line", "result", "timestamp"}; template std::vector ArrayAsVector(const char* const (&array)[kSize]) { return std::vector(array, array + kSize); } static std::vector GetReservedAttributesForElement( const std::string& xml_element) { if (xml_element == "testsuites") { return ArrayAsVector(kReservedTestSuitesAttributes); } else if (xml_element == "testsuite") { return ArrayAsVector(kReservedTestSuiteAttributes); } else if (xml_element == "testcase") { return ArrayAsVector(kReservedTestCaseAttributes); } else { GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; } // This code is unreachable but some compilers may not realizes that. return std::vector(); } // TODO(jdesprez): Merge the two getReserved attributes once skip is improved static std::vector GetReservedOutputAttributesForElement( const std::string& xml_element) { if (xml_element == "testsuites") { return ArrayAsVector(kReservedTestSuitesAttributes); } else if (xml_element == "testsuite") { return ArrayAsVector(kReservedTestSuiteAttributes); } else if (xml_element == "testcase") { return ArrayAsVector(kReservedOutputTestCaseAttributes); } else { GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; } // This code is unreachable but some compilers may not realizes that. return std::vector(); } static std::string FormatWordList(const std::vector& words) { Message word_list; for (size_t i = 0; i < words.size(); ++i) { if (i > 0 && words.size() > 2) { word_list << ", "; } if (i == words.size() - 1) { word_list << "and "; } word_list << "'" << words[i] << "'"; } return word_list.GetString(); } static bool ValidateTestPropertyName( const std::string& property_name, const std::vector& reserved_names) { if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != reserved_names.end()) { ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name << " (" << FormatWordList(reserved_names) << " are reserved by " << GTEST_NAME_ << ")"; return false; } return true; } // Adds a failure if the key is a reserved attribute of the element named // xml_element. Returns true if the property is valid. bool TestResult::ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property) { return ValidateTestPropertyName(test_property.key(), GetReservedAttributesForElement(xml_element)); } // Clears the object. void TestResult::Clear() { test_part_results_.clear(); test_properties_.clear(); death_test_count_ = 0; elapsed_time_ = 0; } // Returns true off the test part was skipped. static bool TestPartSkipped(const TestPartResult& result) { return result.skipped(); } // Returns true if and only if the test was skipped. bool TestResult::Skipped() const { return !Failed() && CountIf(test_part_results_, TestPartSkipped) > 0; } // Returns true if and only if the test failed. bool TestResult::Failed() const { for (int i = 0; i < total_part_count(); ++i) { if (GetTestPartResult(i).failed()) return true; } return false; } // Returns true if and only if the test part fatally failed. static bool TestPartFatallyFailed(const TestPartResult& result) { return result.fatally_failed(); } // Returns true if and only if the test fatally failed. bool TestResult::HasFatalFailure() const { return CountIf(test_part_results_, TestPartFatallyFailed) > 0; } // Returns true if and only if the test part non-fatally failed. static bool TestPartNonfatallyFailed(const TestPartResult& result) { return result.nonfatally_failed(); } // Returns true if and only if the test has a non-fatal failure. bool TestResult::HasNonfatalFailure() const { return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; } // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int TestResult::total_part_count() const { return static_cast(test_part_results_.size()); } // Returns the number of the test properties. int TestResult::test_property_count() const { return static_cast(test_properties_.size()); } // class Test // Creates a Test object. // The c'tor saves the states of all flags. Test::Test() : gtest_flag_saver_(new GTEST_FLAG_SAVER_) { } // The d'tor restores the states of all flags. The actual work is // done by the d'tor of the gtest_flag_saver_ field, and thus not // visible here. Test::~Test() { } // Sets up the test fixture. // // A sub-class may override this. void Test::SetUp() { } // Tears down the test fixture. // // A sub-class may override this. void Test::TearDown() { } // Allows user supplied key value pairs to be recorded for later output. void Test::RecordProperty(const std::string& key, const std::string& value) { UnitTest::GetInstance()->RecordProperty(key, value); } // Allows user supplied key value pairs to be recorded for later output. void Test::RecordProperty(const std::string& key, int value) { Message value_message; value_message << value; RecordProperty(key, value_message.GetString().c_str()); } namespace internal { void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message) { // This function is a friend of UnitTest and as such has access to // AddTestPartResult. UnitTest::GetInstance()->AddTestPartResult( result_type, nullptr, // No info about the source file where the exception occurred. -1, // We have no info on which line caused the exception. message, ""); // No stack trace, either. } } // namespace internal // Google Test requires all tests in the same test suite to use the same test // fixture class. This function checks if the current test has the // same fixture class as the first test in the current test suite. If // yes, it returns true; otherwise it generates a Google Test failure and // returns false. bool Test::HasSameFixtureClass() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); const TestSuite* const test_suite = impl->current_test_suite(); // Info about the first test in the current test suite. const TestInfo* const first_test_info = test_suite->test_info_list()[0]; const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; const char* const first_test_name = first_test_info->name(); // Info about the current test. const TestInfo* const this_test_info = impl->current_test_info(); const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; const char* const this_test_name = this_test_info->name(); if (this_fixture_id != first_fixture_id) { // Is the first test defined using TEST? const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); // Is this test defined using TEST? const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); if (first_is_TEST || this_is_TEST) { // Both TEST and TEST_F appear in same test suite, which is incorrect. // Tell the user how to fix this. // Gets the name of the TEST and the name of the TEST_F. Note // that first_is_TEST and this_is_TEST cannot both be true, as // the fixture IDs are different for the two tests. const char* const TEST_name = first_is_TEST ? first_test_name : this_test_name; const char* const TEST_F_name = first_is_TEST ? this_test_name : first_test_name; ADD_FAILURE() << "All tests in the same test suite must use the same test fixture\n" << "class, so mixing TEST_F and TEST in the same test suite is\n" << "illegal. In test suite " << this_test_info->test_suite_name() << ",\n" << "test " << TEST_F_name << " is defined using TEST_F but\n" << "test " << TEST_name << " is defined using TEST. You probably\n" << "want to change the TEST to TEST_F or move it to another test\n" << "case."; } else { // Two fixture classes with the same name appear in two different // namespaces, which is not allowed. Tell the user how to fix this. ADD_FAILURE() << "All tests in the same test suite must use the same test fixture\n" << "class. However, in test suite " << this_test_info->test_suite_name() << ",\n" << "you defined test " << first_test_name << " and test " << this_test_name << "\n" << "using two different test fixture classes. This can happen if\n" << "the two classes are from different namespaces or translation\n" << "units and have the same name. You should probably rename one\n" << "of the classes to put the tests into different test suites."; } return false; } return true; } #if GTEST_HAS_SEH // Adds an "exception thrown" fatal failure to the current test. This // function returns its result via an output parameter pointer because VC++ // prohibits creation of objects with destructors on stack in functions // using __try (see error C2712). static std::string* FormatSehExceptionMessage(DWORD exception_code, const char* location) { Message message; message << "SEH exception with code 0x" << std::setbase(16) << exception_code << std::setbase(10) << " thrown in " << location << "."; return new std::string(message.GetString()); } #endif // GTEST_HAS_SEH namespace internal { #if GTEST_HAS_EXCEPTIONS // Adds an "exception thrown" fatal failure to the current test. static std::string FormatCxxExceptionMessage(const char* description, const char* location) { Message message; if (description != nullptr) { message << "C++ exception with description \"" << description << "\""; } else { message << "Unknown C++ exception"; } message << " thrown in " << location << "."; return message.GetString(); } static std::string PrintTestPartResultToString( const TestPartResult& test_part_result); GoogleTestFailureException::GoogleTestFailureException( const TestPartResult& failure) : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} #endif // GTEST_HAS_EXCEPTIONS // We put these helper functions in the internal namespace as IBM's xlC // compiler rejects the code if they were declared static. // Runs the given method and handles SEH exceptions it throws, when // SEH is supported; returns the 0-value for type Result in case of an // SEH exception. (Microsoft compilers cannot handle SEH and C++ // exceptions in the same function. Therefore, we provide a separate // wrapper function for handling SEH exceptions.) template Result HandleSehExceptionsInMethodIfSupported( T* object, Result (T::*method)(), const char* location) { #if GTEST_HAS_SEH __try { return (object->*method)(); } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT GetExceptionCode())) { // We create the exception message on the heap because VC++ prohibits // creation of objects with destructors on stack in functions using __try // (see error C2712). std::string* exception_message = FormatSehExceptionMessage( GetExceptionCode(), location); internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, *exception_message); delete exception_message; return static_cast(0); } #else (void)location; return (object->*method)(); #endif // GTEST_HAS_SEH } // Runs the given method and catches and reports C++ and/or SEH-style // exceptions, if they are supported; returns the 0-value for type // Result in case of an SEH exception. template Result HandleExceptionsInMethodIfSupported( T* object, Result (T::*method)(), const char* location) { // NOTE: The user code can affect the way in which Google Test handles // exceptions by setting GTEST_FLAG(catch_exceptions), but only before // RUN_ALL_TESTS() starts. It is technically possible to check the flag // after the exception is caught and either report or re-throw the // exception based on the flag's value: // // try { // // Perform the test method. // } catch (...) { // if (GTEST_FLAG(catch_exceptions)) // // Report the exception as failure. // else // throw; // Re-throws the original exception. // } // // However, the purpose of this flag is to allow the program to drop into // the debugger when the exception is thrown. On most platforms, once the // control enters the catch block, the exception origin information is // lost and the debugger will stop the program at the point of the // re-throw in this function -- instead of at the point of the original // throw statement in the code under test. For this reason, we perform // the check early, sacrificing the ability to affect Google Test's // exception handling in the method where the exception is thrown. if (internal::GetUnitTestImpl()->catch_exceptions()) { #if GTEST_HAS_EXCEPTIONS try { return HandleSehExceptionsInMethodIfSupported(object, method, location); } catch (const AssertionException&) { // NOLINT // This failure was reported already. } catch (const internal::GoogleTestFailureException&) { // NOLINT // This exception type can only be thrown by a failed Google // Test assertion with the intention of letting another testing // framework catch it. Therefore we just re-throw it. throw; } catch (const std::exception& e) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, FormatCxxExceptionMessage(e.what(), location)); } catch (...) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, FormatCxxExceptionMessage(nullptr, location)); } return static_cast(0); #else return HandleSehExceptionsInMethodIfSupported(object, method, location); #endif // GTEST_HAS_EXCEPTIONS } else { return (object->*method)(); } } } // namespace internal // Runs the test and updates the test result. void Test::Run() { if (!HasSameFixtureClass()) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); // We will run the test only if SetUp() was successful and didn't call // GTEST_SKIP(). if (!HasFatalFailure() && !IsSkipped()) { impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &Test::TestBody, "the test body"); } // However, we want to clean up as much as possible. Hence we will // always call TearDown(), even if SetUp() or the test body has // failed. impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &Test::TearDown, "TearDown()"); } // Returns true if and only if the current test has a fatal failure. bool Test::HasFatalFailure() { return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); } // Returns true if and only if the current test has a non-fatal failure. bool Test::HasNonfatalFailure() { return internal::GetUnitTestImpl()->current_test_result()-> HasNonfatalFailure(); } // Returns true if and only if the current test was skipped. bool Test::IsSkipped() { return internal::GetUnitTestImpl()->current_test_result()->Skipped(); } // class TestInfo // Constructs a TestInfo object. It assumes ownership of the test factory // object. TestInfo::TestInfo(const std::string& a_test_suite_name, const std::string& a_name, const char* a_type_param, const char* a_value_param, internal::CodeLocation a_code_location, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) : test_suite_name_(a_test_suite_name), name_(a_name), type_param_(a_type_param ? new std::string(a_type_param) : nullptr), value_param_(a_value_param ? new std::string(a_value_param) : nullptr), location_(a_code_location), fixture_class_id_(fixture_class_id), should_run_(false), is_disabled_(false), matches_filter_(false), factory_(factory), result_() {} // Destructs a TestInfo object. TestInfo::~TestInfo() { delete factory_; } namespace internal { // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // // test_suite_name: name of the test suite // name: name of the test // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param: text representation of the test's value parameter, // or NULL if this is not a value-parameterized test. // code_location: code location where the test is defined // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test suite // tear_down_tc: pointer to the function that tears down the test suite // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. TestInfo* MakeAndRegisterTestInfo( const char* test_suite_name, const char* name, const char* type_param, const char* value_param, CodeLocation code_location, TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory) { TestInfo* const test_info = new TestInfo(test_suite_name, name, type_param, value_param, code_location, fixture_class_id, factory); GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } void ReportInvalidTestSuiteType(const char* test_suite_name, CodeLocation code_location) { Message errors; errors << "Attempted redefinition of test suite " << test_suite_name << ".\n" << "All tests in the same test suite must use the same test fixture\n" << "class. However, in test suite " << test_suite_name << ", you tried\n" << "to define a test using a fixture class different from the one\n" << "used earlier. This can happen if the two fixture classes are\n" << "from different namespaces and have the same name. You should\n" << "probably rename one of the classes to put the tests into different\n" << "test suites."; GTEST_LOG_(ERROR) << FormatFileLocation(code_location.file.c_str(), code_location.line) << " " << errors.GetString(); } } // namespace internal namespace { // A predicate that checks the test name of a TestInfo against a known // value. // // This is used for implementation of the TestSuite class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // // TestNameIs is copyable. class TestNameIs { public: // Constructor. // // TestNameIs has NO default constructor. explicit TestNameIs(const char* name) : name_(name) {} // Returns true if and only if the test name of test_info matches name_. bool operator()(const TestInfo * test_info) const { return test_info && test_info->name() == name_; } private: std::string name_; }; } // namespace namespace internal { // This method expands all parameterized tests registered with macros TEST_P // and INSTANTIATE_TEST_SUITE_P into regular tests and registers those. // This will be done just once during the program runtime. void UnitTestImpl::RegisterParameterizedTests() { if (!parameterized_tests_registered_) { parameterized_test_registry_.RegisterTests(); parameterized_tests_registered_ = true; } } } // namespace internal // Creates the test object, runs it, records its result, and then // deletes it. void TestInfo::Run() { if (!should_run_) return; // Tells UnitTest where to store test result. internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_info(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); // Notifies the unit test event listeners that a test is about to start. repeater->OnTestStart(*this); const TimeInMillis start = internal::GetTimeInMillis(); impl->os_stack_trace_getter()->UponLeavingGTest(); // Creates the test object. Test* const test = internal::HandleExceptionsInMethodIfSupported( factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); // Runs the test if the constructor didn't generate a fatal failure or invoke // GTEST_SKIP(). // Note that the object will not be null if (!Test::HasFatalFailure() && !Test::IsSkipped()) { // This doesn't throw as all user code that can throw are wrapped into // exception handling code. test->Run(); } if (test != nullptr) { // Deletes the test object. impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( test, &Test::DeleteSelf_, "the test fixture's destructor"); } result_.set_start_timestamp(start); result_.set_elapsed_time(internal::GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. repeater->OnTestEnd(*this); // Tells UnitTest to stop associating assertion results to this // test. impl->set_current_test_info(nullptr); } // class TestSuite // Gets the number of successful tests in this test suite. int TestSuite::successful_test_count() const { return CountIf(test_info_list_, TestPassed); } // Gets the number of successful tests in this test suite. int TestSuite::skipped_test_count() const { return CountIf(test_info_list_, TestSkipped); } // Gets the number of failed tests in this test suite. int TestSuite::failed_test_count() const { return CountIf(test_info_list_, TestFailed); } // Gets the number of disabled tests that will be reported in the XML report. int TestSuite::reportable_disabled_test_count() const { return CountIf(test_info_list_, TestReportableDisabled); } // Gets the number of disabled tests in this test suite. int TestSuite::disabled_test_count() const { return CountIf(test_info_list_, TestDisabled); } // Gets the number of tests to be printed in the XML report. int TestSuite::reportable_test_count() const { return CountIf(test_info_list_, TestReportable); } // Get the number of tests in this test suite that should run. int TestSuite::test_to_run_count() const { return CountIf(test_info_list_, ShouldRunTest); } // Gets the number of all tests. int TestSuite::total_test_count() const { return static_cast(test_info_list_.size()); } // Creates a TestSuite with the given name. // // Arguments: // // name: name of the test suite // a_type_param: the name of the test suite's type parameter, or NULL if // this is not a typed or a type-parameterized test suite. // set_up_tc: pointer to the function that sets up the test suite // tear_down_tc: pointer to the function that tears down the test suite TestSuite::TestSuite(const char* a_name, const char* a_type_param, internal::SetUpTestSuiteFunc set_up_tc, internal::TearDownTestSuiteFunc tear_down_tc) : name_(a_name), type_param_(a_type_param ? new std::string(a_type_param) : nullptr), set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), start_timestamp_(0), elapsed_time_(0) {} // Destructor of TestSuite. TestSuite::~TestSuite() { // Deletes every Test in the collection. ForEach(test_info_list_, internal::Delete); } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* TestSuite::GetTestInfo(int i) const { const int index = GetElementOr(test_indices_, i, -1); return index < 0 ? nullptr : test_info_list_[static_cast(index)]; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. TestInfo* TestSuite::GetMutableTestInfo(int i) { const int index = GetElementOr(test_indices_, i, -1); return index < 0 ? nullptr : test_info_list_[static_cast(index)]; } // Adds a test to this test suite. Will delete the test upon // destruction of the TestSuite object. void TestSuite::AddTestInfo(TestInfo* test_info) { test_info_list_.push_back(test_info); test_indices_.push_back(static_cast(test_indices_.size())); } // Runs every test in this TestSuite. void TestSuite::Run() { if (!should_run_) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_suite(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); // Call both legacy and the new API repeater->OnTestSuiteStart(*this); // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI repeater->OnTestCaseStart(*this); #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &TestSuite::RunSetUpTestSuite, "SetUpTestSuite()"); start_timestamp_ = internal::GetTimeInMillis(); for (int i = 0; i < total_test_count(); i++) { GetMutableTestInfo(i)->Run(); } elapsed_time_ = internal::GetTimeInMillis() - start_timestamp_; impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &TestSuite::RunTearDownTestSuite, "TearDownTestSuite()"); // Call both legacy and the new API repeater->OnTestSuiteEnd(*this); // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI repeater->OnTestCaseEnd(*this); #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI impl->set_current_test_suite(nullptr); } // Clears the results of all tests in this test suite. void TestSuite::ClearResult() { ad_hoc_test_result_.Clear(); ForEach(test_info_list_, TestInfo::ClearTestResult); } // Shuffles the tests in this test suite. void TestSuite::ShuffleTests(internal::Random* random) { Shuffle(random, &test_indices_); } // Restores the test order to before the first shuffle. void TestSuite::UnshuffleTests() { for (size_t i = 0; i < test_indices_.size(); i++) { test_indices_[i] = static_cast(i); } } // Formats a countable noun. Depending on its quantity, either the // singular form or the plural form is used. e.g. // // FormatCountableNoun(1, "formula", "formuli") returns "1 formula". // FormatCountableNoun(5, "book", "books") returns "5 books". static std::string FormatCountableNoun(int count, const char * singular_form, const char * plural_form) { return internal::StreamableToString(count) + " " + (count == 1 ? singular_form : plural_form); } // Formats the count of tests. static std::string FormatTestCount(int test_count) { return FormatCountableNoun(test_count, "test", "tests"); } // Formats the count of test suites. static std::string FormatTestSuiteCount(int test_suite_count) { return FormatCountableNoun(test_suite_count, "test suite", "test suites"); } // Converts a TestPartResult::Type enum to human-friendly string // representation. Both kNonFatalFailure and kFatalFailure are translated // to "Failure", as the user usually doesn't care about the difference // between the two when viewing the test result. static const char * TestPartResultTypeToString(TestPartResult::Type type) { switch (type) { case TestPartResult::kSkip: return "Skipped"; case TestPartResult::kSuccess: return "Success"; case TestPartResult::kNonFatalFailure: case TestPartResult::kFatalFailure: #ifdef _MSC_VER return "error: "; #else return "Failure\n"; #endif default: return "Unknown result type"; } } namespace internal { // Prints a TestPartResult to an std::string. static std::string PrintTestPartResultToString( const TestPartResult& test_part_result) { return (Message() << internal::FormatFileLocation(test_part_result.file_name(), test_part_result.line_number()) << " " << TestPartResultTypeToString(test_part_result.type()) << test_part_result.message()).GetString(); } // Prints a TestPartResult. static void PrintTestPartResult(const TestPartResult& test_part_result) { const std::string& result = PrintTestPartResultToString(test_part_result); printf("%s\n", result.c_str()); fflush(stdout); // If the test program runs in Visual Studio or a debugger, the // following statements add the test part result message to the Output // window such that the user can double-click on it to jump to the // corresponding source code location; otherwise they do nothing. #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // We don't call OutputDebugString*() on Windows Mobile, as printing // to stdout is done by OutputDebugString() there already - we don't // want the same message printed twice. ::OutputDebugStringA(result.c_str()); ::OutputDebugStringA("\n"); #endif } // class PrettyUnitTestResultPrinter #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW // Returns the character attribute for the given color. static WORD GetColorAttribute(GTestColor color) { switch (color) { case COLOR_RED: return FOREGROUND_RED; case COLOR_GREEN: return FOREGROUND_GREEN; case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; default: return 0; } } static int GetBitOffset(WORD color_mask) { if (color_mask == 0) return 0; int bitOffset = 0; while ((color_mask & 1) == 0) { color_mask >>= 1; ++bitOffset; } return bitOffset; } static WORD GetNewColor(GTestColor color, WORD old_color_attrs) { // Let's reuse the BG static const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY; static const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; const WORD existing_bg = old_color_attrs & background_mask; WORD new_color = GetColorAttribute(color) | existing_bg | FOREGROUND_INTENSITY; static const int bg_bitOffset = GetBitOffset(background_mask); static const int fg_bitOffset = GetBitOffset(foreground_mask); if (((new_color & background_mask) >> bg_bitOffset) == ((new_color & foreground_mask) >> fg_bitOffset)) { new_color ^= FOREGROUND_INTENSITY; // invert intensity } return new_color; } #else // Returns the ANSI color code for the given color. COLOR_DEFAULT is // an invalid input. static const char* GetAnsiColorCode(GTestColor color) { switch (color) { case COLOR_RED: return "1"; case COLOR_GREEN: return "2"; case COLOR_YELLOW: return "3"; default: return nullptr; } } #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // Returns true if and only if Google Test should use colors in the output. bool ShouldUseColor(bool stdout_is_tty) { const char* const gtest_color = GTEST_FLAG(color).c_str(); if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW // On Windows the TERM variable is usually not set, but the // console there does support colors. return stdout_is_tty; #else // On non-Windows platforms, we rely on the TERM variable. const char* const term = posix::GetEnv("TERM"); const bool term_supports_color = String::CStringEquals(term, "xterm") || String::CStringEquals(term, "xterm-color") || String::CStringEquals(term, "xterm-256color") || String::CStringEquals(term, "screen") || String::CStringEquals(term, "screen-256color") || String::CStringEquals(term, "tmux") || String::CStringEquals(term, "tmux-256color") || String::CStringEquals(term, "rxvt-unicode") || String::CStringEquals(term, "rxvt-unicode-256color") || String::CStringEquals(term, "linux") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; #endif // GTEST_OS_WINDOWS } return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || String::CaseInsensitiveCStringEquals(gtest_color, "true") || String::CaseInsensitiveCStringEquals(gtest_color, "t") || String::CStringEquals(gtest_color, "1"); // We take "yes", "true", "t", and "1" as meaning "yes". If the // value is neither one of these nor "auto", we treat it as "no" to // be conservative. } // Helpers for printing colored strings to stdout. Note that on Windows, we // cannot simply emit special characters and have the terminal change colors. // This routine must actually emit the characters rather than return a string // that would be colored when printed, as can be done on Linux. void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); #if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS || GTEST_OS_IOS || \ GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT || defined(ESP_PLATFORM) const bool use_color = AlwaysFalse(); #else static const bool in_color_mode = ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); const bool use_color = in_color_mode && (color != COLOR_DEFAULT); #endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS if (!use_color) { vprintf(fmt, args); va_end(args); return; } #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. CONSOLE_SCREEN_BUFFER_INFO buffer_info; GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); const WORD old_color_attrs = buffer_info.wAttributes; const WORD new_color = GetNewColor(color, old_color_attrs); // We need to flush the stream buffers into the console before each // SetConsoleTextAttribute call lest it affect the text that is already // printed but has not yet reached the console. fflush(stdout); SetConsoleTextAttribute(stdout_handle, new_color); vprintf(fmt, args); fflush(stdout); // Restores the text color. SetConsoleTextAttribute(stdout_handle, old_color_attrs); #else printf("\033[0;3%sm", GetAnsiColorCode(color)); vprintf(fmt, args); printf("\033[m"); // Resets the terminal to default. #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE va_end(args); } // Text printed in Google Test's text output and --gtest_list_tests // output to label the type parameter and value parameter for a test. static const char kTypeParamLabel[] = "TypeParam"; static const char kValueParamLabel[] = "GetParam()"; static void PrintFullTestCommentIfPresent(const TestInfo& test_info) { const char* const type_param = test_info.type_param(); const char* const value_param = test_info.value_param(); if (type_param != nullptr || value_param != nullptr) { printf(", where "); if (type_param != nullptr) { printf("%s = %s", kTypeParamLabel, type_param); if (value_param != nullptr) printf(" and "); } if (value_param != nullptr) { printf("%s = %s", kValueParamLabel, value_param); } } } // This class implements the TestEventListener interface. // // Class PrettyUnitTestResultPrinter is copyable. class PrettyUnitTestResultPrinter : public TestEventListener { public: PrettyUnitTestResultPrinter() {} static void PrintTestName(const char* test_suite, const char* test) { printf("%s.%s", test_suite, test); } // The following methods override what's in the TestEventListener class. void OnTestProgramStart(const UnitTest& /*unit_test*/) override {} void OnTestIterationStart(const UnitTest& unit_test, int iteration) override; void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override; void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {} #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void OnTestCaseStart(const TestCase& test_case) override; #else void OnTestSuiteStart(const TestSuite& test_suite) override; #endif // OnTestCaseStart void OnTestStart(const TestInfo& test_info) override; void OnTestPartResult(const TestPartResult& result) override; void OnTestEnd(const TestInfo& test_info) override; #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void OnTestCaseEnd(const TestCase& test_case) override; #else void OnTestSuiteEnd(const TestSuite& test_suite) override; #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override; void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {} void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {} private: static void PrintFailedTests(const UnitTest& unit_test); static void PrintSkippedTests(const UnitTest& unit_test); }; // Fired before each iteration of tests starts. void PrettyUnitTestResultPrinter::OnTestIterationStart( const UnitTest& unit_test, int iteration) { if (GTEST_FLAG(repeat) != 1) printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); const char* const filter = GTEST_FLAG(filter).c_str(); // Prints the filter if it's not *. This reminds the user that some // tests may be skipped. if (!String::CStringEquals(filter, kUniversalFilter)) { ColoredPrintf(COLOR_YELLOW, "Note: %s filter = %s\n", GTEST_NAME_, filter); } if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); ColoredPrintf(COLOR_YELLOW, "Note: This is test shard %d of %s.\n", static_cast(shard_index) + 1, internal::posix::GetEnv(kTestTotalShards)); } if (GTEST_FLAG(shuffle)) { ColoredPrintf(COLOR_YELLOW, "Note: Randomizing tests' orders with a seed of %d .\n", unit_test.random_seed()); } ColoredPrintf(COLOR_GREEN, "[==========] "); printf("Running %s from %s.\n", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str()); fflush(stdout); } void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment set-up.\n"); fflush(stdout); } #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s", counts.c_str(), test_case.name()); if (test_case.type_param() == nullptr) { printf("\n"); } else { printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); } fflush(stdout); } #else void PrettyUnitTestResultPrinter::OnTestSuiteStart( const TestSuite& test_suite) { const std::string counts = FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s", counts.c_str(), test_suite.name()); if (test_suite.type_param() == nullptr) { printf("\n"); } else { printf(", where %s = %s\n", kTypeParamLabel, test_suite.type_param()); } fflush(stdout); } #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); PrintTestName(test_info.test_suite_name(), test_info.name()); printf("\n"); fflush(stdout); } // Called after an assertion failure. void PrettyUnitTestResultPrinter::OnTestPartResult( const TestPartResult& result) { switch (result.type()) { // If the test part succeeded, we don't need to do anything. case TestPartResult::kSuccess: return; default: // Print failure message from the assertion // (e.g. expected this and got that). PrintTestPartResult(result); fflush(stdout); } } void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { if (test_info.result()->Passed()) { ColoredPrintf(COLOR_GREEN, "[ OK ] "); } else if (test_info.result()->Skipped()) { ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); } else { ColoredPrintf(COLOR_RED, "[ FAILED ] "); } PrintTestName(test_info.test_suite_name(), test_info.name()); if (test_info.result()->Failed()) PrintFullTestCommentIfPresent(test_info); if (GTEST_FLAG(print_time)) { printf(" (%s ms)\n", internal::StreamableToString( test_info.result()->elapsed_time()).c_str()); } else { printf("\n"); } fflush(stdout); } #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { if (!GTEST_FLAG(print_time)) return; const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case.name(), internal::StreamableToString(test_case.elapsed_time()).c_str()); fflush(stdout); } #else void PrettyUnitTestResultPrinter::OnTestSuiteEnd(const TestSuite& test_suite) { if (!GTEST_FLAG(print_time)) return; const std::string counts = FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_suite.name(), internal::StreamableToString(test_suite.elapsed_time()).c_str()); fflush(stdout); } #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment tear-down\n"); fflush(stdout); } // Internal helper for printing the list of failed tests. void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { const int failed_test_count = unit_test.failed_test_count(); if (failed_test_count == 0) { return; } for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { const TestSuite& test_suite = *unit_test.GetTestSuite(i); if (!test_suite.should_run() || (test_suite.failed_test_count() == 0)) { continue; } for (int j = 0; j < test_suite.total_test_count(); ++j) { const TestInfo& test_info = *test_suite.GetTestInfo(j); if (!test_info.should_run() || !test_info.result()->Failed()) { continue; } ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s.%s", test_suite.name(), test_info.name()); PrintFullTestCommentIfPresent(test_info); printf("\n"); } } } // Internal helper for printing the list of skipped tests. void PrettyUnitTestResultPrinter::PrintSkippedTests(const UnitTest& unit_test) { const int skipped_test_count = unit_test.skipped_test_count(); if (skipped_test_count == 0) { return; } for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { const TestSuite& test_suite = *unit_test.GetTestSuite(i); if (!test_suite.should_run() || (test_suite.skipped_test_count() == 0)) { continue; } for (int j = 0; j < test_suite.total_test_count(); ++j) { const TestInfo& test_info = *test_suite.GetTestInfo(j); if (!test_info.should_run() || !test_info.result()->Skipped()) { continue; } ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); printf("%s.%s", test_suite.name(), test_info.name()); printf("\n"); } } } void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { ColoredPrintf(COLOR_GREEN, "[==========] "); printf("%s from %s ran.", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str()); if (GTEST_FLAG(print_time)) { printf(" (%s ms total)", internal::StreamableToString(unit_test.elapsed_time()).c_str()); } printf("\n"); ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); const int skipped_test_count = unit_test.skipped_test_count(); if (skipped_test_count > 0) { ColoredPrintf(COLOR_GREEN, "[ SKIPPED ] "); printf("%s, listed below:\n", FormatTestCount(skipped_test_count).c_str()); PrintSkippedTests(unit_test); } int num_failures = unit_test.failed_test_count(); if (!unit_test.Passed()) { const int failed_test_count = unit_test.failed_test_count(); ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); PrintFailedTests(unit_test); printf("\n%2d FAILED %s\n", num_failures, num_failures == 1 ? "TEST" : "TESTS"); } int num_disabled = unit_test.reportable_disabled_test_count(); if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { if (!num_failures) { printf("\n"); // Add a spacer if no FAILURE banner is displayed. } ColoredPrintf(COLOR_YELLOW, " YOU HAVE %d DISABLED %s\n\n", num_disabled, num_disabled == 1 ? "TEST" : "TESTS"); } // Ensure that Google Test output is printed before, e.g., heapchecker output. fflush(stdout); } // End PrettyUnitTestResultPrinter // class TestEventRepeater // // This class forwards events to other event listeners. class TestEventRepeater : public TestEventListener { public: TestEventRepeater() : forwarding_enabled_(true) {} ~TestEventRepeater() override; void Append(TestEventListener *listener); TestEventListener* Release(TestEventListener* listener); // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled() const { return forwarding_enabled_; } void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } void OnTestProgramStart(const UnitTest& unit_test) override; void OnTestIterationStart(const UnitTest& unit_test, int iteration) override; void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override; void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) override; // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void OnTestCaseStart(const TestSuite& parameter) override; #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void OnTestSuiteStart(const TestSuite& parameter) override; void OnTestStart(const TestInfo& test_info) override; void OnTestPartResult(const TestPartResult& result) override; void OnTestEnd(const TestInfo& test_info) override; // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void OnTestCaseEnd(const TestCase& parameter) override; #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ void OnTestSuiteEnd(const TestSuite& parameter) override; void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override; void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) override; void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; void OnTestProgramEnd(const UnitTest& unit_test) override; private: // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled_; // The list of listeners that receive events. std::vector listeners_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); }; TestEventRepeater::~TestEventRepeater() { ForEach(listeners_, Delete); } void TestEventRepeater::Append(TestEventListener *listener) { listeners_.push_back(listener); } TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { for (size_t i = 0; i < listeners_.size(); ++i) { if (listeners_[i] == listener) { listeners_.erase(listeners_.begin() + static_cast(i)); return listener; } } return nullptr; } // Since most methods are very similar, use macros to reduce boilerplate. // This defines a member that forwards the call to all listeners. #define GTEST_REPEATER_METHOD_(Name, Type) \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (size_t i = 0; i < listeners_.size(); i++) { \ listeners_[i]->Name(parameter); \ } \ } \ } // This defines a member that forwards the call to all listeners in reverse // order. #define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (size_t i = listeners_.size(); i != 0; i--) { \ listeners_[i - 1]->Name(parameter); \ } \ } \ } GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ GTEST_REPEATER_METHOD_(OnTestCaseStart, TestSuite) #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ GTEST_REPEATER_METHOD_(OnTestSuiteStart, TestSuite) GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestSuite) #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ GTEST_REVERSE_REPEATER_METHOD_(OnTestSuiteEnd, TestSuite) GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) #undef GTEST_REPEATER_METHOD_ #undef GTEST_REVERSE_REPEATER_METHOD_ void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { for (size_t i = 0; i < listeners_.size(); i++) { listeners_[i]->OnTestIterationStart(unit_test, iteration); } } } void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { for (size_t i = listeners_.size(); i > 0; i--) { listeners_[i - 1]->OnTestIterationEnd(unit_test, iteration); } } } // End TestEventRepeater // This class generates an XML output file. class XmlUnitTestResultPrinter : public EmptyTestEventListener { public: explicit XmlUnitTestResultPrinter(const char* output_file); void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; void ListTestsMatchingFilter(const std::vector& test_suites); // Prints an XML summary of all unit tests. static void PrintXmlTestsList(std::ostream* stream, const std::vector& test_suites); private: // Is c a whitespace character that is normalized to a space character // when it appears in an XML attribute value? static bool IsNormalizableWhitespace(char c) { return c == 0x9 || c == 0xA || c == 0xD; } // May c appear in a well-formed XML document? static bool IsValidXmlCharacter(char c) { return IsNormalizableWhitespace(c) || c >= 0x20; } // Returns an XML-escaped copy of the input string str. If // is_attribute is true, the text is meant to appear as an attribute // value, and normalizable whitespace is preserved by replacing it // with character references. static std::string EscapeXml(const std::string& str, bool is_attribute); // Returns the given string with all characters invalid in XML removed. static std::string RemoveInvalidXmlCharacters(const std::string& str); // Convenience wrapper around EscapeXml when str is an attribute value. static std::string EscapeXmlAttribute(const std::string& str) { return EscapeXml(str, true); } // Convenience wrapper around EscapeXml when str is not an attribute value. static std::string EscapeXmlText(const char* str) { return EscapeXml(str, false); } // Verifies that the given attribute belongs to the given element and // streams the attribute as XML. static void OutputXmlAttribute(std::ostream* stream, const std::string& element_name, const std::string& name, const std::string& value); // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. static void OutputXmlCDataSection(::std::ostream* stream, const char* data); // Streams an XML representation of a TestInfo object. static void OutputXmlTestInfo(::std::ostream* stream, const char* test_suite_name, const TestInfo& test_info); // Prints an XML representation of a TestSuite object static void PrintXmlTestSuite(::std::ostream* stream, const TestSuite& test_suite); // Prints an XML summary of unit_test to output stream out. static void PrintXmlUnitTest(::std::ostream* stream, const UnitTest& unit_test); // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. // When the std::string is not empty, it includes a space at the beginning, // to delimit this attribute from prior attributes. static std::string TestPropertiesAsXmlAttributes(const TestResult& result); // Streams an XML representation of the test properties of a TestResult // object. static void OutputXmlTestProperties(std::ostream* stream, const TestResult& result); // The output file. const std::string output_file_; GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); }; // Creates a new XmlUnitTestResultPrinter. XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) : output_file_(output_file) { if (output_file_.empty()) { GTEST_LOG_(FATAL) << "XML output file may not be null"; } } // Called after the unit test ends. void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { FILE* xmlout = OpenFileForWriting(output_file_); std::stringstream stream; PrintXmlUnitTest(&stream, unit_test); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); fclose(xmlout); } void XmlUnitTestResultPrinter::ListTestsMatchingFilter( const std::vector& test_suites) { FILE* xmlout = OpenFileForWriting(output_file_); std::stringstream stream; PrintXmlTestsList(&stream, test_suites); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); fclose(xmlout); } // Returns an XML-escaped copy of the input string str. If is_attribute // is true, the text is meant to appear as an attribute value, and // normalizable whitespace is preserved by replacing it with character // references. // // Invalid XML characters in str, if any, are stripped from the output. // It is expected that most, if not all, of the text processed by this // module will consist of ordinary English text. // If this module is ever modified to produce version 1.1 XML output, // most invalid characters can be retained using character references. std::string XmlUnitTestResultPrinter::EscapeXml( const std::string& str, bool is_attribute) { Message m; for (size_t i = 0; i < str.size(); ++i) { const char ch = str[i]; switch (ch) { case '<': m << "<"; break; case '>': m << ">"; break; case '&': m << "&"; break; case '\'': if (is_attribute) m << "'"; else m << '\''; break; case '"': if (is_attribute) m << """; else m << '"'; break; default: if (IsValidXmlCharacter(ch)) { if (is_attribute && IsNormalizableWhitespace(ch)) m << "&#x" << String::FormatByte(static_cast(ch)) << ";"; else m << ch; } break; } } return m.GetString(); } // Returns the given string with all characters invalid in XML removed. // Currently invalid characters are dropped from the string. An // alternative is to replace them with certain characters such as . or ?. std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( const std::string& str) { std::string output; output.reserve(str.size()); for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) if (IsValidXmlCharacter(*it)) output.push_back(*it); return output; } // The following routines generate an XML representation of a UnitTest // object. // GOOGLETEST_CM0009 DO NOT DELETE // // This is how Google Test concepts map to the DTD: // // <-- corresponds to a UnitTest object // <-- corresponds to a TestSuite object // <-- corresponds to a TestInfo object // ... // ... // ... // <-- individual assertion failures // // // // Formats the given time in milliseconds as seconds. std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { ::std::stringstream ss; ss << (static_cast(ms) * 1e-3); return ss.str(); } static bool PortableLocaltime(time_t seconds, struct tm* out) { #if defined(_MSC_VER) return localtime_s(out, &seconds) == 0; #elif defined(__MINGW32__) || defined(__MINGW64__) // MINGW provides neither localtime_r nor localtime_s, but uses // Windows' localtime(), which has a thread-local tm buffer. struct tm* tm_ptr = localtime(&seconds); // NOLINT if (tm_ptr == nullptr) return false; *out = *tm_ptr; return true; #else return localtime_r(&seconds, out) != nullptr; #endif } // Converts the given epoch time in milliseconds to a date string in the ISO // 8601 format, without the timezone information. std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { struct tm time_struct; if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) return ""; // YYYY-MM-DDThh:mm:ss return StreamableToString(time_struct.tm_year + 1900) + "-" + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + String::FormatIntWidth2(time_struct.tm_mday) + "T" + String::FormatIntWidth2(time_struct.tm_hour) + ":" + String::FormatIntWidth2(time_struct.tm_min) + ":" + String::FormatIntWidth2(time_struct.tm_sec); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, const char* data) { const char* segment = data; *stream << ""); if (next_segment != nullptr) { stream->write( segment, static_cast(next_segment - segment)); *stream << "]]>]]>"); } else { *stream << segment; break; } } *stream << "]]>"; } void XmlUnitTestResultPrinter::OutputXmlAttribute( std::ostream* stream, const std::string& element_name, const std::string& name, const std::string& value) { const std::vector& allowed_names = GetReservedOutputAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != allowed_names.end()) << "Attribute " << name << " is not allowed for element <" << element_name << ">."; *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\""; } // Prints an XML representation of a TestInfo object. void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, const char* test_suite_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); const std::string kTestsuite = "testcase"; if (test_info.is_in_another_shard()) { return; } *stream << " \n"; return; } OutputXmlAttribute(stream, kTestsuite, "status", test_info.should_run() ? "run" : "notrun"); OutputXmlAttribute(stream, kTestsuite, "result", test_info.should_run() ? (result.Skipped() ? "skipped" : "completed") : "suppressed"); OutputXmlAttribute(stream, kTestsuite, "time", FormatTimeInMillisAsSeconds(result.elapsed_time())); OutputXmlAttribute( stream, kTestsuite, "timestamp", FormatEpochTimeInMillisAsIso8601(result.start_timestamp())); OutputXmlAttribute(stream, kTestsuite, "classname", test_suite_name); int failures = 0; for (int i = 0; i < result.total_part_count(); ++i) { const TestPartResult& part = result.GetTestPartResult(i); if (part.failed()) { if (++failures == 1) { *stream << ">\n"; } const std::string location = internal::FormatCompilerIndependentFileLocation(part.file_name(), part.line_number()); const std::string summary = location + "\n" + part.summary(); *stream << " "; const std::string detail = location + "\n" + part.message(); OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); *stream << "\n"; } } if (failures == 0 && result.test_property_count() == 0) { *stream << " />\n"; } else { if (failures == 0) { *stream << ">\n"; } OutputXmlTestProperties(stream, result); *stream << " \n"; } } // Prints an XML representation of a TestSuite object void XmlUnitTestResultPrinter::PrintXmlTestSuite(std::ostream* stream, const TestSuite& test_suite) { const std::string kTestsuite = "testsuite"; *stream << " <" << kTestsuite; OutputXmlAttribute(stream, kTestsuite, "name", test_suite.name()); OutputXmlAttribute(stream, kTestsuite, "tests", StreamableToString(test_suite.reportable_test_count())); if (!GTEST_FLAG(list_tests)) { OutputXmlAttribute(stream, kTestsuite, "failures", StreamableToString(test_suite.failed_test_count())); OutputXmlAttribute( stream, kTestsuite, "disabled", StreamableToString(test_suite.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuite, "errors", "0"); OutputXmlAttribute(stream, kTestsuite, "time", FormatTimeInMillisAsSeconds(test_suite.elapsed_time())); OutputXmlAttribute( stream, kTestsuite, "timestamp", FormatEpochTimeInMillisAsIso8601(test_suite.start_timestamp())); *stream << TestPropertiesAsXmlAttributes(test_suite.ad_hoc_test_result()); } *stream << ">\n"; for (int i = 0; i < test_suite.total_test_count(); ++i) { if (test_suite.GetTestInfo(i)->is_reportable()) OutputXmlTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); } *stream << " \n"; } // Prints an XML summary of unit_test to output stream out. void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, const UnitTest& unit_test) { const std::string kTestsuites = "testsuites"; *stream << "\n"; *stream << "<" << kTestsuites; OutputXmlAttribute(stream, kTestsuites, "tests", StreamableToString(unit_test.reportable_test_count())); OutputXmlAttribute(stream, kTestsuites, "failures", StreamableToString(unit_test.failed_test_count())); OutputXmlAttribute( stream, kTestsuites, "disabled", StreamableToString(unit_test.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuites, "errors", "0"); OutputXmlAttribute(stream, kTestsuites, "time", FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); OutputXmlAttribute( stream, kTestsuites, "timestamp", FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); if (GTEST_FLAG(shuffle)) { OutputXmlAttribute(stream, kTestsuites, "random_seed", StreamableToString(unit_test.random_seed())); } *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) PrintXmlTestSuite(stream, *unit_test.GetTestSuite(i)); } *stream << "\n"; } void XmlUnitTestResultPrinter::PrintXmlTestsList( std::ostream* stream, const std::vector& test_suites) { const std::string kTestsuites = "testsuites"; *stream << "\n"; *stream << "<" << kTestsuites; int total_tests = 0; for (auto test_suite : test_suites) { total_tests += test_suite->total_test_count(); } OutputXmlAttribute(stream, kTestsuites, "tests", StreamableToString(total_tests)); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; for (auto test_suite : test_suites) { PrintXmlTestSuite(stream, *test_suite); } *stream << "\n"; } // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( const TestResult& result) { Message attributes; for (int i = 0; i < result.test_property_count(); ++i) { const TestProperty& property = result.GetTestProperty(i); attributes << " " << property.key() << "=" << "\"" << EscapeXmlAttribute(property.value()) << "\""; } return attributes.GetString(); } void XmlUnitTestResultPrinter::OutputXmlTestProperties( std::ostream* stream, const TestResult& result) { const std::string kProperties = "properties"; const std::string kProperty = "property"; if (result.test_property_count() <= 0) { return; } *stream << "<" << kProperties << ">\n"; for (int i = 0; i < result.test_property_count(); ++i) { const TestProperty& property = result.GetTestProperty(i); *stream << "<" << kProperty; *stream << " name=\"" << EscapeXmlAttribute(property.key()) << "\""; *stream << " value=\"" << EscapeXmlAttribute(property.value()) << "\""; *stream << "/>\n"; } *stream << "\n"; } // End XmlUnitTestResultPrinter // This class generates an JSON output file. class JsonUnitTestResultPrinter : public EmptyTestEventListener { public: explicit JsonUnitTestResultPrinter(const char* output_file); void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override; // Prints an JSON summary of all unit tests. static void PrintJsonTestList(::std::ostream* stream, const std::vector& test_suites); private: // Returns an JSON-escaped copy of the input string str. static std::string EscapeJson(const std::string& str); //// Verifies that the given attribute belongs to the given element and //// streams the attribute as JSON. static void OutputJsonKey(std::ostream* stream, const std::string& element_name, const std::string& name, const std::string& value, const std::string& indent, bool comma = true); static void OutputJsonKey(std::ostream* stream, const std::string& element_name, const std::string& name, int value, const std::string& indent, bool comma = true); // Streams a JSON representation of a TestInfo object. static void OutputJsonTestInfo(::std::ostream* stream, const char* test_suite_name, const TestInfo& test_info); // Prints a JSON representation of a TestSuite object static void PrintJsonTestSuite(::std::ostream* stream, const TestSuite& test_suite); // Prints a JSON summary of unit_test to output stream out. static void PrintJsonUnitTest(::std::ostream* stream, const UnitTest& unit_test); // Produces a string representing the test properties in a result as // a JSON dictionary. static std::string TestPropertiesAsJson(const TestResult& result, const std::string& indent); // The output file. const std::string output_file_; GTEST_DISALLOW_COPY_AND_ASSIGN_(JsonUnitTestResultPrinter); }; // Creates a new JsonUnitTestResultPrinter. JsonUnitTestResultPrinter::JsonUnitTestResultPrinter(const char* output_file) : output_file_(output_file) { if (output_file_.empty()) { GTEST_LOG_(FATAL) << "JSON output file may not be null"; } } void JsonUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { FILE* jsonout = OpenFileForWriting(output_file_); std::stringstream stream; PrintJsonUnitTest(&stream, unit_test); fprintf(jsonout, "%s", StringStreamToString(&stream).c_str()); fclose(jsonout); } // Returns an JSON-escaped copy of the input string str. std::string JsonUnitTestResultPrinter::EscapeJson(const std::string& str) { Message m; for (size_t i = 0; i < str.size(); ++i) { const char ch = str[i]; switch (ch) { case '\\': case '"': case '/': m << '\\' << ch; break; case '\b': m << "\\b"; break; case '\t': m << "\\t"; break; case '\n': m << "\\n"; break; case '\f': m << "\\f"; break; case '\r': m << "\\r"; break; default: if (ch < ' ') { m << "\\u00" << String::FormatByte(static_cast(ch)); } else { m << ch; } break; } } return m.GetString(); } // The following routines generate an JSON representation of a UnitTest // object. // Formats the given time in milliseconds as seconds. static std::string FormatTimeInMillisAsDuration(TimeInMillis ms) { ::std::stringstream ss; ss << (static_cast(ms) * 1e-3) << "s"; return ss.str(); } // Converts the given epoch time in milliseconds to a date string in the // RFC3339 format, without the timezone information. static std::string FormatEpochTimeInMillisAsRFC3339(TimeInMillis ms) { struct tm time_struct; if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) return ""; // YYYY-MM-DDThh:mm:ss return StreamableToString(time_struct.tm_year + 1900) + "-" + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + String::FormatIntWidth2(time_struct.tm_mday) + "T" + String::FormatIntWidth2(time_struct.tm_hour) + ":" + String::FormatIntWidth2(time_struct.tm_min) + ":" + String::FormatIntWidth2(time_struct.tm_sec) + "Z"; } static inline std::string Indent(size_t width) { return std::string(width, ' '); } void JsonUnitTestResultPrinter::OutputJsonKey( std::ostream* stream, const std::string& element_name, const std::string& name, const std::string& value, const std::string& indent, bool comma) { const std::vector& allowed_names = GetReservedOutputAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != allowed_names.end()) << "Key \"" << name << "\" is not allowed for value \"" << element_name << "\"."; *stream << indent << "\"" << name << "\": \"" << EscapeJson(value) << "\""; if (comma) *stream << ",\n"; } void JsonUnitTestResultPrinter::OutputJsonKey( std::ostream* stream, const std::string& element_name, const std::string& name, int value, const std::string& indent, bool comma) { const std::vector& allowed_names = GetReservedOutputAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != allowed_names.end()) << "Key \"" << name << "\" is not allowed for value \"" << element_name << "\"."; *stream << indent << "\"" << name << "\": " << StreamableToString(value); if (comma) *stream << ",\n"; } // Prints a JSON representation of a TestInfo object. void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream, const char* test_suite_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); const std::string kTestsuite = "testcase"; const std::string kIndent = Indent(10); *stream << Indent(8) << "{\n"; OutputJsonKey(stream, kTestsuite, "name", test_info.name(), kIndent); if (test_info.value_param() != nullptr) { OutputJsonKey(stream, kTestsuite, "value_param", test_info.value_param(), kIndent); } if (test_info.type_param() != nullptr) { OutputJsonKey(stream, kTestsuite, "type_param", test_info.type_param(), kIndent); } if (GTEST_FLAG(list_tests)) { OutputJsonKey(stream, kTestsuite, "file", test_info.file(), kIndent); OutputJsonKey(stream, kTestsuite, "line", test_info.line(), kIndent, false); *stream << "\n" << Indent(8) << "}"; return; } OutputJsonKey(stream, kTestsuite, "status", test_info.should_run() ? "RUN" : "NOTRUN", kIndent); OutputJsonKey(stream, kTestsuite, "result", test_info.should_run() ? (result.Skipped() ? "SKIPPED" : "COMPLETED") : "SUPPRESSED", kIndent); OutputJsonKey(stream, kTestsuite, "timestamp", FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()), kIndent); OutputJsonKey(stream, kTestsuite, "time", FormatTimeInMillisAsDuration(result.elapsed_time()), kIndent); OutputJsonKey(stream, kTestsuite, "classname", test_suite_name, kIndent, false); *stream << TestPropertiesAsJson(result, kIndent); int failures = 0; for (int i = 0; i < result.total_part_count(); ++i) { const TestPartResult& part = result.GetTestPartResult(i); if (part.failed()) { *stream << ",\n"; if (++failures == 1) { *stream << kIndent << "\"" << "failures" << "\": [\n"; } const std::string location = internal::FormatCompilerIndependentFileLocation(part.file_name(), part.line_number()); const std::string message = EscapeJson(location + "\n" + part.message()); *stream << kIndent << " {\n" << kIndent << " \"failure\": \"" << message << "\",\n" << kIndent << " \"type\": \"\"\n" << kIndent << " }"; } } if (failures > 0) *stream << "\n" << kIndent << "]"; *stream << "\n" << Indent(8) << "}"; } // Prints an JSON representation of a TestSuite object void JsonUnitTestResultPrinter::PrintJsonTestSuite( std::ostream* stream, const TestSuite& test_suite) { const std::string kTestsuite = "testsuite"; const std::string kIndent = Indent(6); *stream << Indent(4) << "{\n"; OutputJsonKey(stream, kTestsuite, "name", test_suite.name(), kIndent); OutputJsonKey(stream, kTestsuite, "tests", test_suite.reportable_test_count(), kIndent); if (!GTEST_FLAG(list_tests)) { OutputJsonKey(stream, kTestsuite, "failures", test_suite.failed_test_count(), kIndent); OutputJsonKey(stream, kTestsuite, "disabled", test_suite.reportable_disabled_test_count(), kIndent); OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent); OutputJsonKey( stream, kTestsuite, "timestamp", FormatEpochTimeInMillisAsRFC3339(test_suite.start_timestamp()), kIndent); OutputJsonKey(stream, kTestsuite, "time", FormatTimeInMillisAsDuration(test_suite.elapsed_time()), kIndent, false); *stream << TestPropertiesAsJson(test_suite.ad_hoc_test_result(), kIndent) << ",\n"; } *stream << kIndent << "\"" << kTestsuite << "\": [\n"; bool comma = false; for (int i = 0; i < test_suite.total_test_count(); ++i) { if (test_suite.GetTestInfo(i)->is_reportable()) { if (comma) { *stream << ",\n"; } else { comma = true; } OutputJsonTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); } } *stream << "\n" << kIndent << "]\n" << Indent(4) << "}"; } // Prints a JSON summary of unit_test to output stream out. void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream, const UnitTest& unit_test) { const std::string kTestsuites = "testsuites"; const std::string kIndent = Indent(2); *stream << "{\n"; OutputJsonKey(stream, kTestsuites, "tests", unit_test.reportable_test_count(), kIndent); OutputJsonKey(stream, kTestsuites, "failures", unit_test.failed_test_count(), kIndent); OutputJsonKey(stream, kTestsuites, "disabled", unit_test.reportable_disabled_test_count(), kIndent); OutputJsonKey(stream, kTestsuites, "errors", 0, kIndent); if (GTEST_FLAG(shuffle)) { OutputJsonKey(stream, kTestsuites, "random_seed", unit_test.random_seed(), kIndent); } OutputJsonKey(stream, kTestsuites, "timestamp", FormatEpochTimeInMillisAsRFC3339(unit_test.start_timestamp()), kIndent); OutputJsonKey(stream, kTestsuites, "time", FormatTimeInMillisAsDuration(unit_test.elapsed_time()), kIndent, false); *stream << TestPropertiesAsJson(unit_test.ad_hoc_test_result(), kIndent) << ",\n"; OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); *stream << kIndent << "\"" << kTestsuites << "\": [\n"; bool comma = false; for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) { if (comma) { *stream << ",\n"; } else { comma = true; } PrintJsonTestSuite(stream, *unit_test.GetTestSuite(i)); } } *stream << "\n" << kIndent << "]\n" << "}\n"; } void JsonUnitTestResultPrinter::PrintJsonTestList( std::ostream* stream, const std::vector& test_suites) { const std::string kTestsuites = "testsuites"; const std::string kIndent = Indent(2); *stream << "{\n"; int total_tests = 0; for (auto test_suite : test_suites) { total_tests += test_suite->total_test_count(); } OutputJsonKey(stream, kTestsuites, "tests", total_tests, kIndent); OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); *stream << kIndent << "\"" << kTestsuites << "\": [\n"; for (size_t i = 0; i < test_suites.size(); ++i) { if (i != 0) { *stream << ",\n"; } PrintJsonTestSuite(stream, *test_suites[i]); } *stream << "\n" << kIndent << "]\n" << "}\n"; } // Produces a string representing the test properties in a result as // a JSON dictionary. std::string JsonUnitTestResultPrinter::TestPropertiesAsJson( const TestResult& result, const std::string& indent) { Message attributes; for (int i = 0; i < result.test_property_count(); ++i) { const TestProperty& property = result.GetTestProperty(i); attributes << ",\n" << indent << "\"" << property.key() << "\": " << "\"" << EscapeJson(property.value()) << "\""; } return attributes.GetString(); } // End JsonUnitTestResultPrinter #if GTEST_CAN_STREAM_RESULTS_ // Checks if str contains '=', '&', '%' or '\n' characters. If yes, // replaces them by "%xx" where xx is their hexadecimal value. For // example, replaces "=" with "%3D". This algorithm is O(strlen(str)) // in both time and space -- important as the input str may contain an // arbitrarily long test failure message and stack trace. std::string StreamingListener::UrlEncode(const char* str) { std::string result; result.reserve(strlen(str) + 1); for (char ch = *str; ch != '\0'; ch = *++str) { switch (ch) { case '%': case '=': case '&': case '\n': result.append("%" + String::FormatByte(static_cast(ch))); break; default: result.push_back(ch); break; } } return result; } void StreamingListener::SocketWriter::MakeConnection() { GTEST_CHECK_(sockfd_ == -1) << "MakeConnection() can't be called when there is already a connection."; addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. hints.ai_socktype = SOCK_STREAM; addrinfo* servinfo = nullptr; // Use the getaddrinfo() to get a linked list of IP addresses for // the given host name. const int error_num = getaddrinfo( host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); if (error_num != 0) { GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " << gai_strerror(error_num); } // Loop through all the results and connect to the first we can. for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != nullptr; cur_addr = cur_addr->ai_next) { sockfd_ = socket( cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); if (sockfd_ != -1) { // Connect the client socket to the server socket. if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { close(sockfd_); sockfd_ = -1; } } } freeaddrinfo(servinfo); // all done with this structure if (sockfd_ == -1) { GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " << host_name_ << ":" << port_num_; } } // End of class Streaming Listener #endif // GTEST_CAN_STREAM_RESULTS__ // class OsStackTraceGetter const char* const OsStackTraceGetterInterface::kElidedFramesMarker = "... " GTEST_NAME_ " internal frames ..."; std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count) GTEST_LOCK_EXCLUDED_(mutex_) { #if GTEST_HAS_ABSL std::string result; if (max_depth <= 0) { return result; } max_depth = std::min(max_depth, kMaxStackTraceDepth); std::vector raw_stack(max_depth); // Skips the frames requested by the caller, plus this function. const int raw_stack_size = absl::GetStackTrace(&raw_stack[0], max_depth, skip_count + 1); void* caller_frame = nullptr; { MutexLock lock(&mutex_); caller_frame = caller_frame_; } for (int i = 0; i < raw_stack_size; ++i) { if (raw_stack[i] == caller_frame && !GTEST_FLAG(show_internal_stack_frames)) { // Add a marker to the trace and stop adding frames. absl::StrAppend(&result, kElidedFramesMarker, "\n"); break; } char tmp[1024]; const char* symbol = "(unknown)"; if (absl::Symbolize(raw_stack[i], tmp, sizeof(tmp))) { symbol = tmp; } char line[1024]; snprintf(line, sizeof(line), " %p: %s\n", raw_stack[i], symbol); result += line; } return result; #else // !GTEST_HAS_ABSL static_cast(max_depth); static_cast(skip_count); return ""; #endif // GTEST_HAS_ABSL } void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) { #if GTEST_HAS_ABSL void* caller_frame = nullptr; if (absl::GetStackTrace(&caller_frame, 1, 3) <= 0) { caller_frame = nullptr; } MutexLock lock(&mutex_); caller_frame_ = caller_frame; #endif // GTEST_HAS_ABSL } // A helper class that creates the premature-exit file in its // constructor and deletes the file in its destructor. class ScopedPrematureExitFile { public: explicit ScopedPrematureExitFile(const char* premature_exit_filepath) : premature_exit_filepath_(premature_exit_filepath ? premature_exit_filepath : "") { // If a path to the premature-exit file is specified... if (!premature_exit_filepath_.empty()) { // create the file with a single "0" character in it. I/O // errors are ignored as there's nothing better we can do and we // don't want to fail the test because of this. FILE* pfile = posix::FOpen(premature_exit_filepath, "w"); fwrite("0", 1, 1, pfile); fclose(pfile); } } ~ScopedPrematureExitFile() { #if !defined GTEST_OS_ESP8266 if (!premature_exit_filepath_.empty()) { int retval = remove(premature_exit_filepath_.c_str()); if (retval) { GTEST_LOG_(ERROR) << "Failed to remove premature exit filepath \"" << premature_exit_filepath_ << "\" with error " << retval; } } #endif } private: const std::string premature_exit_filepath_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); }; } // namespace internal // class TestEventListeners TestEventListeners::TestEventListeners() : repeater_(new internal::TestEventRepeater()), default_result_printer_(nullptr), default_xml_generator_(nullptr) {} TestEventListeners::~TestEventListeners() { delete repeater_; } // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the user. void TestEventListeners::Append(TestEventListener* listener) { repeater_->Append(listener); } // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. TestEventListener* TestEventListeners::Release(TestEventListener* listener) { if (listener == default_result_printer_) default_result_printer_ = nullptr; else if (listener == default_xml_generator_) default_xml_generator_ = nullptr; return repeater_->Release(listener); } // Returns repeater that broadcasts the TestEventListener events to all // subscribers. TestEventListener* TestEventListeners::repeater() { return repeater_; } // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { if (default_result_printer_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_result_printer_); default_result_printer_ = listener; if (listener != nullptr) Append(listener); } } // Sets the default_xml_generator attribute to the provided listener. The // listener is also added to the listener list and previous // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { if (default_xml_generator_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_xml_generator_); default_xml_generator_ = listener; if (listener != nullptr) Append(listener); } } // Controls whether events will be forwarded by the repeater to the // listeners in the list. bool TestEventListeners::EventForwardingEnabled() const { return repeater_->forwarding_enabled(); } void TestEventListeners::SuppressEventForwarding() { repeater_->set_forwarding_enabled(false); } // class UnitTest // Gets the singleton UnitTest object. The first time this method is // called, a UnitTest object is constructed and returned. Consecutive // calls will return the same object. // // We don't protect this under mutex_ as a user is not supposed to // call this before main() starts, from which point on the return // value will never change. UnitTest* UnitTest::GetInstance() { // CodeGear C++Builder insists on a public destructor for the // default implementation. Use this implementation to keep good OO // design with private destructor. #if defined(__BORLANDC__) static UnitTest* const instance = new UnitTest; return instance; #else static UnitTest instance; return &instance; #endif // defined(__BORLANDC__) } // Gets the number of successful test suites. int UnitTest::successful_test_suite_count() const { return impl()->successful_test_suite_count(); } // Gets the number of failed test suites. int UnitTest::failed_test_suite_count() const { return impl()->failed_test_suite_count(); } // Gets the number of all test suites. int UnitTest::total_test_suite_count() const { return impl()->total_test_suite_count(); } // Gets the number of all test suites that contain at least one test // that should run. int UnitTest::test_suite_to_run_count() const { return impl()->test_suite_to_run_count(); } // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ int UnitTest::successful_test_case_count() const { return impl()->successful_test_suite_count(); } int UnitTest::failed_test_case_count() const { return impl()->failed_test_suite_count(); } int UnitTest::total_test_case_count() const { return impl()->total_test_suite_count(); } int UnitTest::test_case_to_run_count() const { return impl()->test_suite_to_run_count(); } #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Gets the number of successful tests. int UnitTest::successful_test_count() const { return impl()->successful_test_count(); } // Gets the number of skipped tests. int UnitTest::skipped_test_count() const { return impl()->skipped_test_count(); } // Gets the number of failed tests. int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } // Gets the number of disabled tests that will be reported in the XML report. int UnitTest::reportable_disabled_test_count() const { return impl()->reportable_disabled_test_count(); } // Gets the number of disabled tests. int UnitTest::disabled_test_count() const { return impl()->disabled_test_count(); } // Gets the number of tests to be printed in the XML report. int UnitTest::reportable_test_count() const { return impl()->reportable_test_count(); } // Gets the number of all tests. int UnitTest::total_test_count() const { return impl()->total_test_count(); } // Gets the number of tests that should run. int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } // Gets the time of the test program start, in ms from the start of the // UNIX epoch. internal::TimeInMillis UnitTest::start_timestamp() const { return impl()->start_timestamp(); } // Gets the elapsed time, in milliseconds. internal::TimeInMillis UnitTest::elapsed_time() const { return impl()->elapsed_time(); } // Returns true if and only if the unit test passed (i.e. all test suites // passed). bool UnitTest::Passed() const { return impl()->Passed(); } // Returns true if and only if the unit test failed (i.e. some test suite // failed or something outside of all tests failed). bool UnitTest::Failed() const { return impl()->Failed(); } // Gets the i-th test suite among all the test suites. i can range from 0 to // total_test_suite_count() - 1. If i is not in that range, returns NULL. const TestSuite* UnitTest::GetTestSuite(int i) const { return impl()->GetTestSuite(i); } // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ const TestCase* UnitTest::GetTestCase(int i) const { return impl()->GetTestCase(i); } #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ // Returns the TestResult containing information on test failures and // properties logged outside of individual test suites. const TestResult& UnitTest::ad_hoc_test_result() const { return *impl()->ad_hoc_test_result(); } // Gets the i-th test suite among all the test suites. i can range from 0 to // total_test_suite_count() - 1. If i is not in that range, returns NULL. TestSuite* UnitTest::GetMutableTestSuite(int i) { return impl()->GetMutableSuiteCase(i); } // Returns the list of event listeners that can be used to track events // inside Google Test. TestEventListeners& UnitTest::listeners() { return *impl()->listeners(); } // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in the // order they were registered. After all tests in the program have // finished, all global test environments will be torn-down in the // *reverse* order they were registered. // // The UnitTest object takes ownership of the given environment. // // We don't protect this under mutex_, as we only support calling it // from the main thread. Environment* UnitTest::AddEnvironment(Environment* env) { if (env == nullptr) { return nullptr; } impl_->environments().push_back(env); return env; } // Adds a TestPartResult to the current TestResult object. All Google Test // assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call // this to report their results. The user code should use the // assertion macros instead of calling this directly. void UnitTest::AddTestPartResult( TestPartResult::Type result_type, const char* file_name, int line_number, const std::string& message, const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) { Message msg; msg << message; internal::MutexLock lock(&mutex_); if (impl_->gtest_trace_stack().size() > 0) { msg << "\n" << GTEST_NAME_ << " trace:"; for (size_t i = impl_->gtest_trace_stack().size(); i > 0; --i) { const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) << " " << trace.message; } } if (os_stack_trace.c_str() != nullptr && !os_stack_trace.empty()) { msg << internal::kStackTraceMarker << os_stack_trace; } const TestPartResult result = TestPartResult( result_type, file_name, line_number, msg.GetString().c_str()); impl_->GetTestPartResultReporterForCurrentThread()-> ReportTestPartResult(result); if (result_type != TestPartResult::kSuccess && result_type != TestPartResult::kSkip) { // gtest_break_on_failure takes precedence over // gtest_throw_on_failure. This allows a user to set the latter // in the code (perhaps in order to use Google Test assertions // with another testing framework) and specify the former on the // command line for debugging. if (GTEST_FLAG(break_on_failure)) { #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // Using DebugBreak on Windows allows gtest to still break into a debugger // when a failure happens and both the --gtest_break_on_failure and // the --gtest_catch_exceptions flags are specified. DebugBreak(); #elif (!defined(__native_client__)) && \ ((defined(__clang__) || defined(__GNUC__)) && \ (defined(__x86_64__) || defined(__i386__))) // with clang/gcc we can achieve the same effect on x86 by invoking int3 asm("int3"); #else // Dereference nullptr through a volatile pointer to prevent the compiler // from removing. We use this rather than abort() or __builtin_trap() for // portability: some debuggers don't correctly trap abort(). *static_cast(nullptr) = 1; #endif // GTEST_OS_WINDOWS } else if (GTEST_FLAG(throw_on_failure)) { #if GTEST_HAS_EXCEPTIONS throw internal::GoogleTestFailureException(result); #else // We cannot call abort() as it generates a pop-up in debug mode // that cannot be suppressed in VC 7.1 or below. exit(1); #endif } } } // Adds a TestProperty to the current TestResult object when invoked from // inside a test, to current TestSuite's ad_hoc_test_result_ when invoked // from SetUpTestSuite or TearDownTestSuite, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void UnitTest::RecordProperty(const std::string& key, const std::string& value) { impl_->RecordProperty(TestProperty(key, value)); } // Runs all tests in this UnitTest object and prints the result. // Returns 0 if successful, or 1 otherwise. // // We don't protect this under mutex_, as we only support calling it // from the main thread. int UnitTest::Run() { const bool in_death_test_child_process = internal::GTEST_FLAG(internal_run_death_test).length() > 0; // Google Test implements this protocol for catching that a test // program exits before returning control to Google Test: // // 1. Upon start, Google Test creates a file whose absolute path // is specified by the environment variable // TEST_PREMATURE_EXIT_FILE. // 2. When Google Test has finished its work, it deletes the file. // // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before // running a Google-Test-based test program and check the existence // of the file at the end of the test execution to see if it has // exited prematurely. // If we are in the child process of a death test, don't // create/delete the premature exit file, as doing so is unnecessary // and will confuse the parent process. Otherwise, create/delete // the file upon entering/leaving this function. If the program // somehow exits before this function has a chance to return, the // premature-exit file will be left undeleted, causing a test runner // that understands the premature-exit-file protocol to report the // test as having failed. const internal::ScopedPrematureExitFile premature_exit_file( in_death_test_child_process ? nullptr : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); // Captures the value of GTEST_FLAG(catch_exceptions). This value will be // used for the duration of the program. impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); #if GTEST_OS_WINDOWS // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected. if (impl()->catch_exceptions() || in_death_test_child_process) { # if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); # endif // !GTEST_OS_WINDOWS_MOBILE # if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE // Death test children can be terminated with _abort(). On Windows, // _abort() can show a dialog with a warning message. This forces the // abort message to go to stderr instead. _set_error_mode(_OUT_TO_STDERR); # endif # if defined(_MSC_VER) && !GTEST_OS_WINDOWS_MOBILE // In the debug version, Visual Studio pops up a separate dialog // offering a choice to debug the aborted program. We need to suppress // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement // executed. Google Test will notify the user of any unexpected // failure via stderr. if (!GTEST_FLAG(break_on_failure)) _set_abort_behavior( 0x0, // Clear the following flags: _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. # endif // In debug mode, the Windows CRT can crash with an assertion over invalid // input (e.g. passing an invalid file descriptor). The default handling // for these assertions is to pop up a dialog and wait for user input. // Instead ask the CRT to dump such assertions to stderr non-interactively. if (!IsDebuggerPresent()) { (void)_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); } } #endif // GTEST_OS_WINDOWS return internal::HandleExceptionsInMethodIfSupported( impl(), &internal::UnitTestImpl::RunAllTests, "auxiliary test code (environments or event listeners)") ? 0 : 1; } // Returns the working directory when the first TEST() or TEST_F() was // executed. const char* UnitTest::original_working_dir() const { return impl_->original_working_dir_.c_str(); } // Returns the TestSuite object for the test that's currently running, // or NULL if no test is running. const TestSuite* UnitTest::current_test_suite() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); return impl_->current_test_suite(); } // Legacy API is still available but deprecated #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ const TestCase* UnitTest::current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); return impl_->current_test_suite(); } #endif // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. const TestInfo* UnitTest::current_test_info() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); return impl_->current_test_info(); } // Returns the random seed used at the start of the current test run. int UnitTest::random_seed() const { return impl_->random_seed(); } // Returns ParameterizedTestSuiteRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestSuiteRegistry& UnitTest::parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_) { return impl_->parameterized_test_registry(); } // Creates an empty UnitTest. UnitTest::UnitTest() { impl_ = new internal::UnitTestImpl(this); } // Destructor of UnitTest. UnitTest::~UnitTest() { delete impl_; } // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().push_back(trace); } // Pops a trace from the per-thread Google Test trace stack. void UnitTest::PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().pop_back(); } namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */) default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), GTEST_DISABLE_MSC_WARNINGS_POP_() global_test_part_result_repoter_( &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), parameterized_test_registry_(), parameterized_tests_registered_(false), last_death_test_suite_(-1), current_test_suite_(nullptr), current_test_info_(nullptr), ad_hoc_test_result_(), os_stack_trace_getter_(nullptr), post_flag_parse_init_performed_(false), random_seed_(0), // Will be overridden by the flag before first use. random_(0), // Will be reseeded before first use. start_timestamp_(0), elapsed_time_(0), #if GTEST_HAS_DEATH_TEST death_test_factory_(new DefaultDeathTestFactory), #endif // Will be overridden by the flag before first use. catch_exceptions_(false) { listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); } UnitTestImpl::~UnitTestImpl() { // Deletes every TestSuite. ForEach(test_suites_, internal::Delete); // Deletes every Environment. ForEach(environments_, internal::Delete); delete os_stack_trace_getter_; } // Adds a TestProperty to the current TestResult object when invoked in a // context of a test, to current test suite's ad_hoc_test_result when invoke // from SetUpTestSuite/TearDownTestSuite, or to the global property set // otherwise. If the result already contains a property with the same key, // the value will be updated. void UnitTestImpl::RecordProperty(const TestProperty& test_property) { std::string xml_element; TestResult* test_result; // TestResult appropriate for property recording. if (current_test_info_ != nullptr) { xml_element = "testcase"; test_result = &(current_test_info_->result_); } else if (current_test_suite_ != nullptr) { xml_element = "testsuite"; test_result = &(current_test_suite_->ad_hoc_test_result_); } else { xml_element = "testsuites"; test_result = &ad_hoc_test_result_; } test_result->RecordProperty(xml_element, test_property); } #if GTEST_HAS_DEATH_TEST // Disables event forwarding if the control is currently in a death test // subprocess. Must not be called before InitGoogleTest. void UnitTestImpl::SuppressTestEventsIfInSubprocess() { if (internal_run_death_test_flag_.get() != nullptr) listeners()->SuppressEventForwarding(); } #endif // GTEST_HAS_DEATH_TEST // Initializes event listeners performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureXmlOutput() { const std::string& output_format = UnitTestOptions::GetOutputFormat(); if (output_format == "xml") { listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); } else if (output_format == "json") { listeners()->SetDefaultXmlGenerator(new JsonUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); } else if (output_format != "") { GTEST_LOG_(WARNING) << "WARNING: unrecognized output format \"" << output_format << "\" ignored."; } } #if GTEST_CAN_STREAM_RESULTS_ // Initializes event listeners for streaming test results in string form. // Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureStreamingOutput() { const std::string& target = GTEST_FLAG(stream_result_to); if (!target.empty()) { const size_t pos = target.find(':'); if (pos != std::string::npos) { listeners()->Append(new StreamingListener(target.substr(0, pos), target.substr(pos+1))); } else { GTEST_LOG_(WARNING) << "unrecognized streaming target \"" << target << "\" ignored."; } } } #endif // GTEST_CAN_STREAM_RESULTS_ // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest // this function is also called from RunAllTests. Since this function can be // called more than once, it has to be idempotent. void UnitTestImpl::PostFlagParsingInit() { // Ensures that this function does not execute more than once. if (!post_flag_parse_init_performed_) { post_flag_parse_init_performed_ = true; #if defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_) // Register to send notifications about key process state changes. listeners()->Append(new GTEST_CUSTOM_TEST_EVENT_LISTENER_()); #endif // defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_) #if GTEST_HAS_DEATH_TEST InitDeathTestSubprocessControlInfo(); SuppressTestEventsIfInSubprocess(); #endif // GTEST_HAS_DEATH_TEST // Registers parameterized tests. This makes parameterized tests // available to the UnitTest reflection API without running // RUN_ALL_TESTS. RegisterParameterizedTests(); // Configures listeners for XML output. This makes it possible for users // to shut down the default XML output before invoking RUN_ALL_TESTS. ConfigureXmlOutput(); #if GTEST_CAN_STREAM_RESULTS_ // Configures listeners for streaming test results to the specified server. ConfigureStreamingOutput(); #endif // GTEST_CAN_STREAM_RESULTS_ #if GTEST_HAS_ABSL if (GTEST_FLAG(install_failure_signal_handler)) { absl::FailureSignalHandlerOptions options; absl::InstallFailureSignalHandler(options); } #endif // GTEST_HAS_ABSL } } // A predicate that checks the name of a TestSuite against a known // value. // // This is used for implementation of the UnitTest class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // // TestSuiteNameIs is copyable. class TestSuiteNameIs { public: // Constructor. explicit TestSuiteNameIs(const std::string& name) : name_(name) {} // Returns true if and only if the name of test_suite matches name_. bool operator()(const TestSuite* test_suite) const { return test_suite != nullptr && strcmp(test_suite->name(), name_.c_str()) == 0; } private: std::string name_; }; // Finds and returns a TestSuite with the given name. If one doesn't // exist, creates one and returns it. It's the CALLER'S // RESPONSIBILITY to ensure that this function is only called WHEN THE // TESTS ARE NOT SHUFFLED. // // Arguments: // // test_suite_name: name of the test suite // type_param: the name of the test suite's type parameter, or NULL if // this is not a typed or a type-parameterized test suite. // set_up_tc: pointer to the function that sets up the test suite // tear_down_tc: pointer to the function that tears down the test suite TestSuite* UnitTestImpl::GetTestSuite( const char* test_suite_name, const char* type_param, internal::SetUpTestSuiteFunc set_up_tc, internal::TearDownTestSuiteFunc tear_down_tc) { // Can we find a TestSuite with the given name? const auto test_suite = std::find_if(test_suites_.rbegin(), test_suites_.rend(), TestSuiteNameIs(test_suite_name)); if (test_suite != test_suites_.rend()) return *test_suite; // No. Let's create one. auto* const new_test_suite = new TestSuite(test_suite_name, type_param, set_up_tc, tear_down_tc); // Is this a death test suite? if (internal::UnitTestOptions::MatchesFilter(test_suite_name, kDeathTestSuiteFilter)) { // Yes. Inserts the test suite after the last death test suite // defined so far. This only works when the test suites haven't // been shuffled. Otherwise we may end up running a death test // after a non-death test. ++last_death_test_suite_; test_suites_.insert(test_suites_.begin() + last_death_test_suite_, new_test_suite); } else { // No. Appends to the end of the list. test_suites_.push_back(new_test_suite); } test_suite_indices_.push_back(static_cast(test_suite_indices_.size())); return new_test_suite; } // Helpers for setting up / tearing down the given environment. They // are for use in the ForEach() function. static void SetUpEnvironment(Environment* env) { env->SetUp(); } static void TearDownEnvironment(Environment* env) { env->TearDown(); } // Runs all tests in this UnitTest object, prints the result, and // returns true if all tests are successful. If any exception is // thrown during a test, the test is considered to be failed, but the // rest of the tests will still be run. // // When parameterized tests are enabled, it expands and registers // parameterized tests first in RegisterParameterizedTests(). // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. bool UnitTestImpl::RunAllTests() { // True if and only if Google Test is initialized before RUN_ALL_TESTS() is // called. const bool gtest_is_initialized_before_run_all_tests = GTestIsInitialized(); // Do not run any test if the --help flag was specified. if (g_help_flag) return true; // Repeats the call to the post-flag parsing initialization in case the // user didn't call InitGoogleTest. PostFlagParsingInit(); // Even if sharding is not on, test runners may want to use the // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding // protocol. internal::WriteToShardStatusFileIfNeeded(); // True if and only if we are in a subprocess for running a thread-safe-style // death test. bool in_subprocess_for_death_test = false; #if GTEST_HAS_DEATH_TEST in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != nullptr); # if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) if (in_subprocess_for_death_test) { GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_(); } # endif // defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) #endif // GTEST_HAS_DEATH_TEST const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, in_subprocess_for_death_test); // Compares the full test names with the filter to decide which // tests to run. const bool has_tests_to_run = FilterTests(should_shard ? HONOR_SHARDING_PROTOCOL : IGNORE_SHARDING_PROTOCOL) > 0; // Lists the tests and exits if the --gtest_list_tests flag was specified. if (GTEST_FLAG(list_tests)) { // This must be called *after* FilterTests() has been called. ListTestsMatchingFilter(); return true; } random_seed_ = GTEST_FLAG(shuffle) ? GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; // True if and only if at least one test has failed. bool failed = false; TestEventListener* repeater = listeners()->repeater(); start_timestamp_ = GetTimeInMillis(); repeater->OnTestProgramStart(*parent_); // How many times to repeat the tests? We don't want to repeat them // when we are inside the subprocess of a death test. const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); // Repeats forever if the repeat count is negative. const bool gtest_repeat_forever = repeat < 0; for (int i = 0; gtest_repeat_forever || i != repeat; i++) { // We want to preserve failures generated by ad-hoc test // assertions executed before RUN_ALL_TESTS(). ClearNonAdHocTestResult(); const TimeInMillis start = GetTimeInMillis(); // Shuffles test suites and tests if requested. if (has_tests_to_run && GTEST_FLAG(shuffle)) { random()->Reseed(static_cast(random_seed_)); // This should be done before calling OnTestIterationStart(), // such that a test event listener can see the actual test order // in the event. ShuffleTests(); } // Tells the unit test event listeners that the tests are about to start. repeater->OnTestIterationStart(*parent_, i); // Runs each test suite if there is at least one test to run. if (has_tests_to_run) { // Sets up all environments beforehand. repeater->OnEnvironmentsSetUpStart(*parent_); ForEach(environments_, SetUpEnvironment); repeater->OnEnvironmentsSetUpEnd(*parent_); // Runs the tests only if there was no fatal failure or skip triggered // during global set-up. if (Test::IsSkipped()) { // Emit diagnostics when global set-up calls skip, as it will not be // emitted by default. TestResult& test_result = *internal::GetUnitTestImpl()->current_test_result(); for (int j = 0; j < test_result.total_part_count(); ++j) { const TestPartResult& test_part_result = test_result.GetTestPartResult(j); if (test_part_result.type() == TestPartResult::kSkip) { const std::string& result = test_part_result.message(); printf("%s\n", result.c_str()); } } fflush(stdout); } else if (!Test::HasFatalFailure()) { for (int test_index = 0; test_index < total_test_suite_count(); test_index++) { GetMutableSuiteCase(test_index)->Run(); } } // Tears down all environments in reverse order afterwards. repeater->OnEnvironmentsTearDownStart(*parent_); std::for_each(environments_.rbegin(), environments_.rend(), TearDownEnvironment); repeater->OnEnvironmentsTearDownEnd(*parent_); } elapsed_time_ = GetTimeInMillis() - start; // Tells the unit test event listener that the tests have just finished. repeater->OnTestIterationEnd(*parent_, i); // Gets the result and clears it. if (!Passed()) { failed = true; } // Restores the original test order after the iteration. This // allows the user to quickly repro a failure that happens in the // N-th iteration without repeating the first (N - 1) iterations. // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in // case the user somehow changes the value of the flag somewhere // (it's always safe to unshuffle the tests). UnshuffleTests(); if (GTEST_FLAG(shuffle)) { // Picks a new random seed for each iteration. random_seed_ = GetNextRandomSeed(random_seed_); } } repeater->OnTestProgramEnd(*parent_); if (!gtest_is_initialized_before_run_all_tests) { ColoredPrintf( COLOR_RED, "\nIMPORTANT NOTICE - DO NOT IGNORE:\n" "This test program did NOT call " GTEST_INIT_GOOGLE_TEST_NAME_ "() before calling RUN_ALL_TESTS(). This is INVALID. Soon " GTEST_NAME_ " will start to enforce the valid usage. " "Please fix it ASAP, or IT WILL START TO FAIL.\n"); // NOLINT #if GTEST_FOR_GOOGLE_ ColoredPrintf(COLOR_RED, "For more details, see http://wiki/Main/ValidGUnitMain.\n"); #endif // GTEST_FOR_GOOGLE_ } return !failed; } // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded() { const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); if (test_shard_file != nullptr) { FILE* const file = posix::FOpen(test_shard_file, "w"); if (file == nullptr) { ColoredPrintf(COLOR_RED, "Could not write to the test shard status file \"%s\" " "specified by the %s environment variable.\n", test_shard_file, kTestShardStatusFile); fflush(stdout); exit(EXIT_FAILURE); } fclose(file); } } // Checks whether sharding is enabled by examining the relevant // environment variable values. If the variables are present, // but inconsistent (i.e., shard_index >= total_shards), prints // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. bool ShouldShard(const char* total_shards_env, const char* shard_index_env, bool in_subprocess_for_death_test) { if (in_subprocess_for_death_test) { return false; } const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); if (total_shards == -1 && shard_index == -1) { return false; } else if (total_shards == -1 && shard_index != -1) { const Message msg = Message() << "Invalid environment variables: you have " << kTestShardIndex << " = " << shard_index << ", but have left " << kTestTotalShards << " unset.\n"; ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (total_shards != -1 && shard_index == -1) { const Message msg = Message() << "Invalid environment variables: you have " << kTestTotalShards << " = " << total_shards << ", but have left " << kTestShardIndex << " unset.\n"; ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (shard_index < 0 || shard_index >= total_shards) { const Message msg = Message() << "Invalid environment variables: we require 0 <= " << kTestShardIndex << " < " << kTestTotalShards << ", but you have " << kTestShardIndex << "=" << shard_index << ", " << kTestTotalShards << "=" << total_shards << ".\n"; ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } return total_shards > 1; } // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error // and aborts. Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { const char* str_val = posix::GetEnv(var); if (str_val == nullptr) { return default_val; } Int32 result; if (!ParseInt32(Message() << "The value of environment variable " << var, str_val, &result)) { exit(EXIT_FAILURE); } return result; } // Given the total number of shards, the shard index, and the test id, // returns true if and only if the test should be run on this shard. The test id // is some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { return (test_id % total_shards) == shard_index; } // Compares the name of each test with the user-specified filter to // decide whether the test should be run, then records the result in // each TestSuite and TestInfo object. // If shard_tests == true, further filters tests based on sharding // variables in the environment - see // https://github.com/google/googletest/blob/master/googletest/docs/advanced.md // . Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestTotalShards, -1) : -1; const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestShardIndex, -1) : -1; // num_runnable_tests are the number of tests that will // run across all shards (i.e., match filter and are not disabled). // num_selected_tests are the number of tests to be run on // this shard. int num_runnable_tests = 0; int num_selected_tests = 0; for (auto* test_suite : test_suites_) { const std::string& test_suite_name = test_suite->name(); test_suite->set_should_run(false); for (size_t j = 0; j < test_suite->test_info_list().size(); j++) { TestInfo* const test_info = test_suite->test_info_list()[j]; const std::string test_name(test_info->name()); // A test is disabled if test suite name or test name matches // kDisableTestFilter. const bool is_disabled = internal::UnitTestOptions::MatchesFilter( test_suite_name, kDisableTestFilter) || internal::UnitTestOptions::MatchesFilter( test_name, kDisableTestFilter); test_info->is_disabled_ = is_disabled; const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest( test_suite_name, test_name); test_info->matches_filter_ = matches_filter; const bool is_runnable = (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && matches_filter; const bool is_in_another_shard = shard_tests != IGNORE_SHARDING_PROTOCOL && !ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests); test_info->is_in_another_shard_ = is_in_another_shard; const bool is_selected = is_runnable && !is_in_another_shard; num_runnable_tests += is_runnable; num_selected_tests += is_selected; test_info->should_run_ = is_selected; test_suite->set_should_run(test_suite->should_run() || is_selected); } } return num_selected_tests; } // Prints the given C-string on a single line by replacing all '\n' // characters with string "\\n". If the output takes more than // max_length characters, only prints the first max_length characters // and "...". static void PrintOnOneLine(const char* str, int max_length) { if (str != nullptr) { for (int i = 0; *str != '\0'; ++str) { if (i >= max_length) { printf("..."); break; } if (*str == '\n') { printf("\\n"); i += 2; } else { printf("%c", *str); ++i; } } } } // Prints the names of the tests matching the user-specified filter flag. void UnitTestImpl::ListTestsMatchingFilter() { // Print at most this many characters for each type/value parameter. const int kMaxParamLength = 250; for (auto* test_suite : test_suites_) { bool printed_test_suite_name = false; for (size_t j = 0; j < test_suite->test_info_list().size(); j++) { const TestInfo* const test_info = test_suite->test_info_list()[j]; if (test_info->matches_filter_) { if (!printed_test_suite_name) { printed_test_suite_name = true; printf("%s.", test_suite->name()); if (test_suite->type_param() != nullptr) { printf(" # %s = ", kTypeParamLabel); // We print the type parameter on a single line to make // the output easy to parse by a program. PrintOnOneLine(test_suite->type_param(), kMaxParamLength); } printf("\n"); } printf(" %s", test_info->name()); if (test_info->value_param() != nullptr) { printf(" # %s = ", kValueParamLabel); // We print the value parameter on a single line to make the // output easy to parse by a program. PrintOnOneLine(test_info->value_param(), kMaxParamLength); } printf("\n"); } } } fflush(stdout); const std::string& output_format = UnitTestOptions::GetOutputFormat(); if (output_format == "xml" || output_format == "json") { FILE* fileout = OpenFileForWriting( UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); std::stringstream stream; if (output_format == "xml") { XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) .PrintXmlTestsList(&stream, test_suites_); } else if (output_format == "json") { JsonUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) .PrintJsonTestList(&stream, test_suites_); } fprintf(fileout, "%s", StringStreamToString(&stream).c_str()); fclose(fileout); } } // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter are // the same; otherwise, deletes the old getter and makes the input the // current getter. void UnitTestImpl::set_os_stack_trace_getter( OsStackTraceGetterInterface* getter) { if (os_stack_trace_getter_ != getter) { delete os_stack_trace_getter_; os_stack_trace_getter_ = getter; } } // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { if (os_stack_trace_getter_ == nullptr) { #ifdef GTEST_OS_STACK_TRACE_GETTER_ os_stack_trace_getter_ = new GTEST_OS_STACK_TRACE_GETTER_; #else os_stack_trace_getter_ = new OsStackTraceGetter; #endif // GTEST_OS_STACK_TRACE_GETTER_ } return os_stack_trace_getter_; } // Returns the most specific TestResult currently running. TestResult* UnitTestImpl::current_test_result() { if (current_test_info_ != nullptr) { return ¤t_test_info_->result_; } if (current_test_suite_ != nullptr) { return ¤t_test_suite_->ad_hoc_test_result_; } return &ad_hoc_test_result_; } // Shuffles all test suites, and the tests within each test suite, // making sure that death tests are still run first. void UnitTestImpl::ShuffleTests() { // Shuffles the death test suites. ShuffleRange(random(), 0, last_death_test_suite_ + 1, &test_suite_indices_); // Shuffles the non-death test suites. ShuffleRange(random(), last_death_test_suite_ + 1, static_cast(test_suites_.size()), &test_suite_indices_); // Shuffles the tests inside each test suite. for (auto& test_suite : test_suites_) { test_suite->ShuffleTests(random()); } } // Restores the test suites and tests to their order before the first shuffle. void UnitTestImpl::UnshuffleTests() { for (size_t i = 0; i < test_suites_.size(); i++) { // Unshuffles the tests in each test suite. test_suites_[i]->UnshuffleTests(); // Resets the index of each test suite. test_suite_indices_[i] = static_cast(i); } } // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, int skip_count) { // We pass skip_count + 1 to skip this wrapper function in addition // to what the user really wants to skip. return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); } // Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to // suppress unreachable code warnings. namespace { class ClassUniqueToAlwaysTrue {}; } bool IsTrue(bool condition) { return condition; } bool AlwaysTrue() { #if GTEST_HAS_EXCEPTIONS // This condition is always false so AlwaysTrue() never actually throws, // but it makes the compiler think that it may throw. if (IsTrue(false)) throw ClassUniqueToAlwaysTrue(); #endif // GTEST_HAS_EXCEPTIONS return true; } // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. bool SkipPrefix(const char* prefix, const char** pstr) { const size_t prefix_len = strlen(prefix); if (strncmp(*pstr, prefix, prefix_len) == 0) { *pstr += prefix_len; return true; } return false; } // Parses a string as a command line flag. The string should have // the format "--flag=value". When def_optional is true, the "=value" // part can be omitted. // // Returns the value of the flag, or NULL if the parsing failed. static const char* ParseFlagValue(const char* str, const char* flag, bool def_optional) { // str and flag must not be NULL. if (str == nullptr || flag == nullptr) return nullptr; // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag; const size_t flag_len = flag_str.length(); if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr; // Skips the flag name. const char* flag_end = str + flag_len; // When def_optional is true, it's OK to not have a "=value" part. if (def_optional && (flag_end[0] == '\0')) { return flag_end; } // If def_optional is true and there are more characters after the // flag name, or if def_optional is false, there must be a '=' after // the flag name. if (flag_end[0] != '=') return nullptr; // Returns the string after "=". return flag_end + 1; } // Parses a string for a bool flag, in the form of either // "--flag=value" or "--flag". // // In the former case, the value is taken as true as long as it does // not start with '0', 'f', or 'F'. // // In the latter case, the value is taken as true. // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. static bool ParseBoolFlag(const char* str, const char* flag, bool* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, true); // Aborts if the parsing failed. if (value_str == nullptr) return false; // Converts the string value to a bool. *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); return true; } // Parses a string for an Int32 flag, in the form of // "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. if (value_str == nullptr) return false; // Sets *value to the value of the flag. return ParseInt32(Message() << "The value of flag --" << flag, value_str, value); } // Parses a string for a string flag, in the form of // "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. template static bool ParseStringFlag(const char* str, const char* flag, String* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. if (value_str == nullptr) return false; // Sets *value to the value of the flag. *value = value_str; return true; } // Determines whether a string has a prefix that Google Test uses for its // flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. // If Google Test detects that a command line flag has its prefix but is not // recognized, it will print its help message. Flags starting with // GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test // internal flags and do not trigger the help message. static bool HasGoogleTestFlagPrefix(const char* str) { return (SkipPrefix("--", &str) || SkipPrefix("-", &str) || SkipPrefix("/", &str)) && !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); } // Prints a string containing code-encoded text. The following escape // sequences can be used in the string to control the text color: // // @@ prints a single '@' character. // @R changes the color to red. // @G changes the color to green. // @Y changes the color to yellow. // @D changes to the default terminal text color. // static void PrintColorEncoded(const char* str) { GTestColor color = COLOR_DEFAULT; // The current color. // Conceptually, we split the string into segments divided by escape // sequences. Then we print one segment at a time. At the end of // each iteration, the str pointer advances to the beginning of the // next segment. for (;;) { const char* p = strchr(str, '@'); if (p == nullptr) { ColoredPrintf(color, "%s", str); return; } ColoredPrintf(color, "%s", std::string(str, p).c_str()); const char ch = p[1]; str = p + 2; if (ch == '@') { ColoredPrintf(color, "@"); } else if (ch == 'D') { color = COLOR_DEFAULT; } else if (ch == 'R') { color = COLOR_RED; } else if (ch == 'G') { color = COLOR_GREEN; } else if (ch == 'Y') { color = COLOR_YELLOW; } else { --str; } } } static const char kColorEncodedHelpMessage[] = "This program contains tests written using " GTEST_NAME_ ". You can use the\n" "following command line flags to control its behavior:\n" "\n" "Test Selection:\n" " @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" " List the names of all tests instead of running them. The name of\n" " TEST(Foo, Bar) is \"Foo.Bar\".\n" " @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" "[@G-@YNEGATIVE_PATTERNS]@D\n" " Run only the tests whose name matches one of the positive patterns but\n" " none of the negative patterns. '?' matches any single character; '*'\n" " matches any substring; ':' separates two patterns.\n" " @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" " Run all disabled tests too.\n" "\n" "Test Execution:\n" " @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" " Run the tests repeatedly; use a negative count to repeat forever.\n" " @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" " Randomize tests' orders on every iteration.\n" " @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" " Random number seed to use for shuffling test orders (between 1 and\n" " 99999, or 0 to use a seed based on the current time).\n" "\n" "Test Output:\n" " @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" " Enable/disable colored output. The default is @Gauto@D.\n" " -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" " Don't print the elapsed time of each test.\n" " @G--" GTEST_FLAG_PREFIX_ "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" " Generate a JSON or XML report in the given directory or with the given\n" " file name. @YFILE_PATH@D defaults to @Gtest_detail.xml@D.\n" # if GTEST_CAN_STREAM_RESULTS_ " @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" " Stream test results to the given server.\n" # endif // GTEST_CAN_STREAM_RESULTS_ "\n" "Assertion Behavior:\n" # if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" " Set the default death test style.\n" # endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" " Turn assertion failures into C++ exceptions for use by an external\n" " test framework.\n" " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" " Do not report exceptions as test failures. Instead, allow them\n" " to crash the program or throw a pop-up (on Windows).\n" "\n" "Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " "the corresponding\n" "environment variable of a flag (all letters in upper-case). For example, to\n" "disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ "color=no@D or set\n" "the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" "\n" "For more information, please read the " GTEST_NAME_ " documentation at\n" "@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" "(not one in your own code or tests), please report it to\n" "@G<" GTEST_DEV_EMAIL_ ">@D.\n"; static bool ParseGoogleTestFlag(const char* const arg) { return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, >EST_FLAG(also_run_disabled_tests)) || ParseBoolFlag(arg, kBreakOnFailureFlag, >EST_FLAG(break_on_failure)) || ParseBoolFlag(arg, kCatchExceptionsFlag, >EST_FLAG(catch_exceptions)) || ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || ParseStringFlag(arg, kDeathTestStyleFlag, >EST_FLAG(death_test_style)) || ParseBoolFlag(arg, kDeathTestUseFork, >EST_FLAG(death_test_use_fork)) || ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || ParseStringFlag(arg, kInternalRunDeathTestFlag, >EST_FLAG(internal_run_death_test)) || ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || ParseBoolFlag(arg, kPrintUTF8Flag, >EST_FLAG(print_utf8)) || ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || ParseInt32Flag(arg, kStackTraceDepthFlag, >EST_FLAG(stack_trace_depth)) || ParseStringFlag(arg, kStreamResultToFlag, >EST_FLAG(stream_result_to)) || ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)); } #if GTEST_USE_OWN_FLAGFILE_FLAG_ static void LoadFlagsFromFile(const std::string& path) { FILE* flagfile = posix::FOpen(path.c_str(), "r"); if (!flagfile) { GTEST_LOG_(FATAL) << "Unable to open file \"" << GTEST_FLAG(flagfile) << "\""; } std::string contents(ReadEntireFile(flagfile)); posix::FClose(flagfile); std::vector lines; SplitString(contents, '\n', &lines); for (size_t i = 0; i < lines.size(); ++i) { if (lines[i].empty()) continue; if (!ParseGoogleTestFlag(lines[i].c_str())) g_help_flag = true; } } #endif // GTEST_USE_OWN_FLAGFILE_FLAG_ // Parses the command line for Google Test flags, without initializing // other parts of Google Test. The type parameter CharType can be // instantiated to either char or wchar_t. template void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { for (int i = 1; i < *argc; i++) { const std::string arg_string = StreamableToString(argv[i]); const char* const arg = arg_string.c_str(); using internal::ParseBoolFlag; using internal::ParseInt32Flag; using internal::ParseStringFlag; bool remove_flag = false; if (ParseGoogleTestFlag(arg)) { remove_flag = true; #if GTEST_USE_OWN_FLAGFILE_FLAG_ } else if (ParseStringFlag(arg, kFlagfileFlag, >EST_FLAG(flagfile))) { LoadFlagsFromFile(GTEST_FLAG(flagfile)); remove_flag = true; #endif // GTEST_USE_OWN_FLAGFILE_FLAG_ } else if (arg_string == "--help" || arg_string == "-h" || arg_string == "-?" || arg_string == "/?" || HasGoogleTestFlagPrefix(arg)) { // Both help flag and unrecognized Google Test flags (excluding // internal ones) trigger help display. g_help_flag = true; } if (remove_flag) { // Shift the remainder of the argv list left by one. Note // that argv has (*argc + 1) elements, the last one always being // NULL. The following loop moves the trailing NULL element as // well. for (int j = i; j != *argc; j++) { argv[j] = argv[j + 1]; } // Decrements the argument count. (*argc)--; // We also need to decrement the iterator as we just removed // an element. i--; } } if (g_help_flag) { // We print the help here instead of in RUN_ALL_TESTS(), as the // latter may not be called at all if the user is using Google // Test with another testing framework. PrintColorEncoded(kColorEncodedHelpMessage); } } // Parses the command line for Google Test flags, without initializing // other parts of Google Test. void ParseGoogleTestFlagsOnly(int* argc, char** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); // Fix the value of *_NSGetArgc() on macOS, but if and only if // *_NSGetArgv() == argv // Only applicable to char** version of argv #if GTEST_OS_MAC #ifndef GTEST_OS_IOS if (*_NSGetArgv() == argv) { *_NSGetArgc() = *argc; } #endif #endif } void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); } // The internal implementation of InitGoogleTest(). // // The type parameter CharType can be instantiated to either char or // wchar_t. template void InitGoogleTestImpl(int* argc, CharType** argv) { // We don't want to run the initialization code twice. if (GTestIsInitialized()) return; if (*argc <= 0) return; g_argvs.clear(); for (int i = 0; i != *argc; i++) { g_argvs.push_back(StreamableToString(argv[i])); } #if GTEST_HAS_ABSL absl::InitializeSymbolizer(g_argvs[0].c_str()); #endif // GTEST_HAS_ABSL ParseGoogleTestFlagsOnly(argc, argv); GetUnitTestImpl()->PostFlagParsingInit(); } } // namespace internal // Initializes Google Test. This must be called before calling // RUN_ALL_TESTS(). In particular, it parses a command line for the // flags that Google Test recognizes. Whenever a Google Test flag is // seen, it is removed from argv, and *argc is decremented. // // No value is returned. Instead, the Google Test flag variables are // updated. // // Calling the function for the second time has no user-visible effect. void InitGoogleTest(int* argc, char** argv) { #if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); #else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) internal::InitGoogleTestImpl(argc, argv); #endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) } // This overloaded version can be used in Windows programs compiled in // UNICODE mode. void InitGoogleTest(int* argc, wchar_t** argv) { #if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); #else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) internal::InitGoogleTestImpl(argc, argv); #endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) } // This overloaded version can be used on Arduino/embedded platforms where // there is no argc/argv. void InitGoogleTest() { // Since Arduino doesn't have a command line, fake out the argc/argv arguments int argc = 1; const auto arg0 = "dummy"; char* argv0 = const_cast(arg0); char** argv = &argv0; #if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(&argc, argv); #else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) internal::InitGoogleTestImpl(&argc, argv); #endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) } std::string TempDir() { #if defined(GTEST_CUSTOM_TEMPDIR_FUNCTION_) return GTEST_CUSTOM_TEMPDIR_FUNCTION_(); #endif #if GTEST_OS_WINDOWS_MOBILE return "\\temp\\"; #elif GTEST_OS_WINDOWS const char* temp_dir = internal::posix::GetEnv("TEMP"); if (temp_dir == nullptr || temp_dir[0] == '\0') return "\\temp\\"; else if (temp_dir[strlen(temp_dir) - 1] == '\\') return temp_dir; else return std::string(temp_dir) + "\\"; #elif GTEST_OS_LINUX_ANDROID return "/sdcard/"; #else return "/tmp/"; #endif // GTEST_OS_WINDOWS_MOBILE } // Class ScopedTrace // Pushes the given source file location and message onto a per-thread // trace stack maintained by Google Test. void ScopedTrace::PushTrace(const char* file, int line, std::string message) { internal::TraceInfo trace; trace.file = file; trace.line = line; trace.message.swap(message); UnitTest::GetInstance()->PushGTestTrace(trace); } // Pops the info pushed by the c'tor. ScopedTrace::~ScopedTrace() GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { UnitTest::GetInstance()->PopGTestTrace(); } } // namespace testing openzwave-1.6.1914/cpp/test/src/gtest_main.cc0000644000175200017520000000366014032142455015716 00000000000000// Copyright 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "gtest/gtest.h" #if GTEST_OS_ESP8266 || GTEST_OS_ESP32 #if GTEST_OS_ESP8266 extern "C" { #endif void setup() { testing::InitGoogleTest(); } void loop() { RUN_ALL_TESTS(); } #if GTEST_OS_ESP8266 } #endif #else GTEST_API_ int main(int argc, char **argv) { printf("Running main() from %s\n", __FILE__); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } #endif openzwave-1.6.1914/cpp/test/src/gtest-matchers.cc0000644000175200017520000000717514032142455016523 00000000000000// Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // The Google C++ Testing and Mocking Framework (Google Test) // // This file implements just enough of the matcher interface to allow // EXPECT_DEATH and friends to accept a matcher argument. #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-port.h" #include "gtest/gtest-matchers.h" #include namespace testing { // Constructs a matcher that matches a const std::string& whose value is // equal to s. Matcher::Matcher(const std::string& s) { *this = Eq(s); } // Constructs a matcher that matches a const std::string& whose value is // equal to s. Matcher::Matcher(const char* s) { *this = Eq(std::string(s)); } // Constructs a matcher that matches a std::string whose value is equal to // s. Matcher::Matcher(const std::string& s) { *this = Eq(s); } // Constructs a matcher that matches a std::string whose value is equal to // s. Matcher::Matcher(const char* s) { *this = Eq(std::string(s)); } #if GTEST_HAS_ABSL // Constructs a matcher that matches a const absl::string_view& whose value is // equal to s. Matcher::Matcher(const std::string& s) { *this = Eq(s); } // Constructs a matcher that matches a const absl::string_view& whose value is // equal to s. Matcher::Matcher(const char* s) { *this = Eq(std::string(s)); } // Constructs a matcher that matches a const absl::string_view& whose value is // equal to s. Matcher::Matcher(absl::string_view s) { *this = Eq(std::string(s)); } // Constructs a matcher that matches a absl::string_view whose value is equal to // s. Matcher::Matcher(const std::string& s) { *this = Eq(s); } // Constructs a matcher that matches a absl::string_view whose value is equal to // s. Matcher::Matcher(const char* s) { *this = Eq(std::string(s)); } // Constructs a matcher that matches a absl::string_view whose value is equal to // s. Matcher::Matcher(absl::string_view s) { *this = Eq(std::string(s)); } #endif // GTEST_HAS_ABSL } // namespace testing openzwave-1.6.1914/cpp/test/src/gtest-death-test.cc0000644000175200017520000017135314032142455016757 00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // This file implements death tests. #include "gtest/gtest-death-test.h" #include #include "gtest/internal/gtest-port.h" #include "gtest/internal/custom/gtest.h" #if GTEST_HAS_DEATH_TEST # if GTEST_OS_MAC # include # endif // GTEST_OS_MAC # include # include # include # if GTEST_OS_LINUX # include # endif // GTEST_OS_LINUX # include # if GTEST_OS_WINDOWS # include # else # include # include # endif // GTEST_OS_WINDOWS # if GTEST_OS_QNX # include # endif // GTEST_OS_QNX # if GTEST_OS_FUCHSIA # include # include # include # include # include # include # include # include # include # include # include # endif // GTEST_OS_FUCHSIA #endif // GTEST_HAS_DEATH_TEST #include "gtest/gtest-message.h" #include "gtest/internal/gtest-string.h" #include "src/gtest-internal-inl.h" namespace testing { // Constants. // The default death test style. // // This is defined in internal/gtest-port.h as "fast", but can be overridden by // a definition in internal/custom/gtest-port.h. The recommended value, which is // used internally at Google, is "threadsafe". static const char kDefaultDeathTestStyle[] = GTEST_DEFAULT_DEATH_TEST_STYLE; GTEST_DEFINE_string_( death_test_style, internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), "Indicates how to run a death test in a forked child process: " "\"threadsafe\" (child process re-executes the test binary " "from the beginning, running only the specific death test) or " "\"fast\" (child process runs the death test immediately " "after forking)."); GTEST_DEFINE_bool_( death_test_use_fork, internal::BoolFromGTestEnv("death_test_use_fork", false), "Instructs to use fork()/_exit() instead of clone() in death tests. " "Ignored and always uses fork() on POSIX systems where clone() is not " "implemented. Useful when running under valgrind or similar tools if " "those do not support clone(). Valgrind 3.3.1 will just fail if " "it sees an unsupported combination of clone() flags. " "It is not recommended to use this flag w/o valgrind though it will " "work in 99% of the cases. Once valgrind is fixed, this flag will " "most likely be removed."); namespace internal { GTEST_DEFINE_string_( internal_run_death_test, "", "Indicates the file, line number, temporal index of " "the single death test to run, and a file descriptor to " "which a success code may be sent, all separated by " "the '|' characters. This flag is specified if and only if the " "current process is a sub-process launched for running a thread-safe " "death test. FOR INTERNAL USE ONLY."); } // namespace internal #if GTEST_HAS_DEATH_TEST namespace internal { // Valid only for fast death tests. Indicates the code is running in the // child process of a fast style death test. # if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA static bool g_in_fast_death_test_child = false; # endif // Returns a Boolean value indicating whether the caller is currently // executing in the context of the death test child process. Tools such as // Valgrind heap checkers may need this to modify their behavior in death // tests. IMPORTANT: This is an internal utility. Using it may break the // implementation of death tests. User code MUST NOT use it. bool InDeathTestChild() { # if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA // On Windows and Fuchsia, death tests are thread-safe regardless of the value // of the death_test_style flag. return !GTEST_FLAG(internal_run_death_test).empty(); # else if (GTEST_FLAG(death_test_style) == "threadsafe") return !GTEST_FLAG(internal_run_death_test).empty(); else return g_in_fast_death_test_child; #endif } } // namespace internal // ExitedWithCode constructor. ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { } // ExitedWithCode function-call operator. bool ExitedWithCode::operator()(int exit_status) const { # if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA return exit_status == exit_code_; # else return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; # endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA } # if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // KilledBySignal constructor. KilledBySignal::KilledBySignal(int signum) : signum_(signum) { } // KilledBySignal function-call operator. bool KilledBySignal::operator()(int exit_status) const { # if defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) { bool result; if (GTEST_KILLED_BY_SIGNAL_OVERRIDE_(signum_, exit_status, &result)) { return result; } } # endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } # endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA namespace internal { // Utilities needed for death tests. // Generates a textual description of a given exit code, in the format // specified by wait(2). static std::string ExitSummary(int exit_code) { Message m; # if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA m << "Exited with exit status " << exit_code; # else if (WIFEXITED(exit_code)) { m << "Exited with exit status " << WEXITSTATUS(exit_code); } else if (WIFSIGNALED(exit_code)) { m << "Terminated by signal " << WTERMSIG(exit_code); } # ifdef WCOREDUMP if (WCOREDUMP(exit_code)) { m << " (core dumped)"; } # endif # endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA return m.GetString(); } // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } # if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Generates a textual failure message when a death test finds more than // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the // caller not to pass a thread_count of 1. static std::string DeathTestThreadWarning(size_t thread_count) { Message msg; msg << "Death tests use fork(), which is unsafe particularly" << " in a threaded context. For this test, " << GTEST_NAME_ << " "; if (thread_count == 0) { msg << "couldn't detect the number of threads."; } else { msg << "detected " << thread_count << " threads."; } msg << " See " "https://github.com/google/googletest/blob/master/googletest/docs/" "advanced.md#death-tests-and-threads" << " for more explanation and suggested solutions, especially if" << " this is the last message you see before your test times out."; return msg.GetString(); } # endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; static const char kDeathTestReturned = 'R'; static const char kDeathTestThrew = 'T'; static const char kDeathTestInternalError = 'I'; #if GTEST_OS_FUCHSIA // File descriptor used for the pipe in the child process. static const int kFuchsiaReadPipeFd = 3; #endif // An enumeration describing all of the possible ways that a death test can // conclude. DIED means that the process died while executing the test // code; LIVED means that process lived beyond the end of the test code; // RETURNED means that the test statement attempted to execute a return // statement, which is not allowed; THREW means that the test statement // returned control by throwing an exception. IN_PROGRESS means the test // has not yet concluded. enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // Routine for aborting the program which is safe to call from an // exec-style death test child process, in which case the error // message is propagated back to the parent process. Otherwise, the // message is simply printed to stderr. In either case, the program // then exits with status 1. static void DeathTestAbort(const std::string& message) { // On a POSIX system, this function may be called from a threadsafe-style // death test child process, which operates on a very small stack. Use // the heap for any additional non-minuscule memory requirements. const InternalRunDeathTestFlag* const flag = GetUnitTestImpl()->internal_run_death_test_flag(); if (flag != nullptr) { FILE* parent = posix::FDOpen(flag->write_fd(), "w"); fputc(kDeathTestInternalError, parent); fprintf(parent, "%s", message.c_str()); fflush(parent); _exit(1); } else { fprintf(stderr, "%s", message.c_str()); fflush(stderr); posix::Abort(); } } // A replacement for CHECK that calls DeathTestAbort if the assertion // fails. # define GTEST_DEATH_TEST_CHECK_(expression) \ do { \ if (!::testing::internal::IsTrue(expression)) { \ DeathTestAbort( \ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + ::testing::internal::StreamableToString(__LINE__) + ": " \ + #expression); \ } \ } while (::testing::internal::AlwaysFalse()) // This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for // evaluating any system call that fulfills two conditions: it must return // -1 on failure, and set errno to EINTR when it is interrupted and // should be tried again. The macro expands to a loop that repeatedly // evaluates the expression as long as it evaluates to -1 and sets // errno to EINTR. If the expression evaluates to -1 but errno is // something other than EINTR, DeathTestAbort is called. # define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ do { \ int gtest_retval; \ do { \ gtest_retval = (expression); \ } while (gtest_retval == -1 && errno == EINTR); \ if (gtest_retval == -1) { \ DeathTestAbort( \ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + ::testing::internal::StreamableToString(__LINE__) + ": " \ + #expression + " != -1"); \ } \ } while (::testing::internal::AlwaysFalse()) // Returns the message describing the last system error in errno. std::string GetLastErrnoDescription() { return errno == 0 ? "" : posix::StrError(errno); } // This is called from a death test parent process to read a failure // message from the death test child process and log it with the FATAL // severity. On Windows, the message is read from a pipe handle. On other // platforms, it is read from a file descriptor. static void FailFromInternalError(int fd) { Message error; char buffer[256]; int num_read; do { while ((num_read = posix::Read(fd, buffer, 255)) > 0) { buffer[num_read] = '\0'; error << buffer; } } while (num_read == -1 && errno == EINTR); if (num_read == 0) { GTEST_LOG_(FATAL) << error.GetString(); } else { const int last_error = errno; GTEST_LOG_(FATAL) << "Error while reading death test internal: " << GetLastErrnoDescription() << " [" << last_error << "]"; } } // Death test constructor. Increments the running death test count // for the current test. DeathTest::DeathTest() { TestInfo* const info = GetUnitTestImpl()->current_test_info(); if (info == nullptr) { DeathTestAbort("Cannot run a death test outside of a TEST or " "TEST_F construct"); } } // Creates and returns a death test by dispatching to the current // death test factory. bool DeathTest::Create(const char* statement, Matcher matcher, const char* file, int line, DeathTest** test) { return GetUnitTestImpl()->death_test_factory()->Create( statement, std::move(matcher), file, line, test); } const char* DeathTest::LastMessage() { return last_death_test_message_.c_str(); } void DeathTest::set_last_death_test_message(const std::string& message) { last_death_test_message_ = message; } std::string DeathTest::last_death_test_message_; // Provides cross platform implementation for some death functionality. class DeathTestImpl : public DeathTest { protected: DeathTestImpl(const char* a_statement, Matcher matcher) : statement_(a_statement), matcher_(std::move(matcher)), spawned_(false), status_(-1), outcome_(IN_PROGRESS), read_fd_(-1), write_fd_(-1) {} // read_fd_ is expected to be closed and cleared by a derived class. ~DeathTestImpl() override { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } void Abort(AbortReason reason) override; bool Passed(bool status_ok) override; const char* statement() const { return statement_; } bool spawned() const { return spawned_; } void set_spawned(bool is_spawned) { spawned_ = is_spawned; } int status() const { return status_; } void set_status(int a_status) { status_ = a_status; } DeathTestOutcome outcome() const { return outcome_; } void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } int read_fd() const { return read_fd_; } void set_read_fd(int fd) { read_fd_ = fd; } int write_fd() const { return write_fd_; } void set_write_fd(int fd) { write_fd_ = fd; } // Called in the parent process only. Reads the result code of the death // test child process via a pipe, interprets it to set the outcome_ // member, and closes read_fd_. Outputs diagnostics and terminates in // case of unexpected codes. void ReadAndInterpretStatusByte(); // Returns stderr output from the child process. virtual std::string GetErrorLogs(); private: // The textual content of the code this object is testing. This class // doesn't own this string and should not attempt to delete it. const char* const statement_; // A matcher that's expected to match the stderr output by the child process. Matcher matcher_; // True if the death test child process has been successfully spawned. bool spawned_; // The exit status of the child process. int status_; // How the death test concluded. DeathTestOutcome outcome_; // Descriptor to the read end of the pipe to the child process. It is // always -1 in the child process. The child keeps its write end of the // pipe in write_fd_. int read_fd_; // Descriptor to the child's write end of the pipe to the parent process. // It is always -1 in the parent process. The parent keeps its end of the // pipe in read_fd_. int write_fd_; }; // Called in the parent process only. Reads the result code of the death // test child process via a pipe, interprets it to set the outcome_ // member, and closes read_fd_. Outputs diagnostics and terminates in // case of unexpected codes. void DeathTestImpl::ReadAndInterpretStatusByte() { char flag; int bytes_read; // The read() here blocks until data is available (signifying the // failure of the death test) or until the pipe is closed (signifying // its success), so it's okay to call this in the parent before // the child process has exited. do { bytes_read = posix::Read(read_fd(), &flag, 1); } while (bytes_read == -1 && errno == EINTR); if (bytes_read == 0) { set_outcome(DIED); } else if (bytes_read == 1) { switch (flag) { case kDeathTestReturned: set_outcome(RETURNED); break; case kDeathTestThrew: set_outcome(THREW); break; case kDeathTestLived: set_outcome(LIVED); break; case kDeathTestInternalError: FailFromInternalError(read_fd()); // Does not return. break; default: GTEST_LOG_(FATAL) << "Death test child process reported " << "unexpected status byte (" << static_cast(flag) << ")"; } } else { GTEST_LOG_(FATAL) << "Read from death test child process failed: " << GetLastErrnoDescription(); } GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); set_read_fd(-1); } std::string DeathTestImpl::GetErrorLogs() { return GetCapturedStderr(); } // Signals that the death test code which should have exited, didn't. // Should be called only in a death test child process. // Writes a status byte to the child's status file descriptor, then // calls _exit(1). void DeathTestImpl::Abort(AbortReason reason) { // The parent process considers the death test to be a failure if // it finds any data in our pipe. So, here we write a single flag byte // to the pipe, then exit. const char status_ch = reason == TEST_DID_NOT_DIE ? kDeathTestLived : reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); // We are leaking the descriptor here because on some platforms (i.e., // when built as Windows DLL), destructors of global objects will still // run after calling _exit(). On such systems, write_fd_ will be // indirectly closed from the destructor of UnitTestImpl, causing double // close if it is also closed here. On debug configurations, double close // may assert. As there are no in-process buffers to flush here, we are // relying on the OS to close the descriptor after the process terminates // when the destructors are not run. _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) } // Returns an indented copy of stderr output for a death test. // This makes distinguishing death test output lines from regular log lines // much easier. static ::std::string FormatDeathTestOutput(const ::std::string& output) { ::std::string ret; for (size_t at = 0; ; ) { const size_t line_end = output.find('\n', at); ret += "[ DEATH ] "; if (line_end == ::std::string::npos) { ret += output.substr(at); break; } ret += output.substr(at, line_end + 1 - at); at = line_end + 1; } return ret; } // Assesses the success or failure of a death test, using both private // members which have previously been set, and one argument: // // Private data members: // outcome: An enumeration describing how the death test // concluded: DIED, LIVED, THREW, or RETURNED. The death test // fails in the latter three cases. // status: The exit status of the child process. On *nix, it is in the // in the format specified by wait(2). On Windows, this is the // value supplied to the ExitProcess() API or a numeric code // of the exception that terminated the program. // matcher_: A matcher that's expected to match the stderr output by the child // process. // // Argument: // status_ok: true if exit_status is acceptable in the context of // this particular death test, which fails if it is false // // Returns true if and only if all of the above conditions are met. Otherwise, // the first failing condition, in the order given above, is the one that is // reported. Also sets the last death test message string. bool DeathTestImpl::Passed(bool status_ok) { if (!spawned()) return false; const std::string error_message = GetErrorLogs(); bool success = false; Message buffer; buffer << "Death test: " << statement() << "\n"; switch (outcome()) { case LIVED: buffer << " Result: failed to die.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case THREW: buffer << " Result: threw an exception.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case RETURNED: buffer << " Result: illegal return in test statement.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case DIED: if (status_ok) { if (matcher_.Matches(error_message)) { success = true; } else { std::ostringstream stream; matcher_.DescribeTo(&stream); buffer << " Result: died but not with expected error.\n" << " Expected: " << stream.str() << "\n" << "Actual msg:\n" << FormatDeathTestOutput(error_message); } } else { buffer << " Result: died but not with expected exit code:\n" << " " << ExitSummary(status()) << "\n" << "Actual msg:\n" << FormatDeathTestOutput(error_message); } break; case IN_PROGRESS: default: GTEST_LOG_(FATAL) << "DeathTest::Passed somehow called before conclusion of test"; } DeathTest::set_last_death_test_message(buffer.GetString()); return success; } # if GTEST_OS_WINDOWS // WindowsDeathTest implements death tests on Windows. Due to the // specifics of starting new processes on Windows, death tests there are // always threadsafe, and Google Test considers the // --gtest_death_test_style=fast setting to be equivalent to // --gtest_death_test_style=threadsafe there. // // A few implementation notes: Like the Linux version, the Windows // implementation uses pipes for child-to-parent communication. But due to // the specifics of pipes on Windows, some extra steps are required: // // 1. The parent creates a communication pipe and stores handles to both // ends of it. // 2. The parent starts the child and provides it with the information // necessary to acquire the handle to the write end of the pipe. // 3. The child acquires the write end of the pipe and signals the parent // using a Windows event. // 4. Now the parent can release the write end of the pipe on its side. If // this is done before step 3, the object's reference count goes down to // 0 and it is destroyed, preventing the child from acquiring it. The // parent now has to release it, or read operations on the read end of // the pipe will not return when the child terminates. // 5. The parent reads child's output through the pipe (outcome code and // any possible error messages) from the pipe, and its stderr and then // determines whether to fail the test. // // Note: to distinguish Win32 API calls from the local method and function // calls, the former are explicitly resolved in the global namespace. // class WindowsDeathTest : public DeathTestImpl { public: WindowsDeathTest(const char* a_statement, Matcher matcher, const char* file, int line) : DeathTestImpl(a_statement, std::move(matcher)), file_(file), line_(line) {} // All of these virtual functions are inherited from DeathTest. virtual int Wait(); virtual TestRole AssumeRole(); private: // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; // Handle to the write end of the pipe to the child process. AutoHandle write_handle_; // Child process handle. AutoHandle child_handle_; // Event the child process uses to signal the parent that it has // acquired the handle to the write end of the pipe. After seeing this // event the parent can release its own handles to make sure its // ReadFile() calls return when the child terminates. AutoHandle event_handle_; }; // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int WindowsDeathTest::Wait() { if (!spawned()) return 0; // Wait until the child either signals that it has acquired the write end // of the pipe or it dies. const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; switch (::WaitForMultipleObjects(2, wait_handles, FALSE, // Waits for any of the handles. INFINITE)) { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: break; default: GTEST_DEATH_TEST_CHECK_(false); // Should not get here. } // The child has acquired the write end of the pipe or exited. // We release the handle on our side and continue. write_handle_.Reset(); event_handle_.Reset(); ReadAndInterpretStatusByte(); // Waits for the child process to exit if it haven't already. This // returns immediately if the child has already exited, regardless of // whether previous calls to WaitForMultipleObjects synchronized on this // handle or not. GTEST_DEATH_TEST_CHECK_( WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), INFINITE)); DWORD status_code; GTEST_DEATH_TEST_CHECK_( ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); child_handle_.Reset(); set_status(static_cast(status_code)); return status(); } // The AssumeRole process for a Windows death test. It creates a child // process with the same executable as the current process to run the // death test. The child process is given the --gtest_filter and // --gtest_internal_run_death_test flags such that it knows to run the // current death test only. DeathTest::TestRole WindowsDeathTest::AssumeRole() { const UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); if (flag != nullptr) { // ParseInternalRunDeathTestFlag() has performed all the necessary // processing. set_write_fd(flag->write_fd()); return EXECUTE_TEST; } // WindowsDeathTest uses an anonymous pipe to communicate results of // a death test. SECURITY_ATTRIBUTES handles_are_inheritable = {sizeof(SECURITY_ATTRIBUTES), nullptr, TRUE}; HANDLE read_handle, write_handle; GTEST_DEATH_TEST_CHECK_( ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, 0) // Default buffer size. != FALSE); set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), O_RDONLY)); write_handle_.Reset(write_handle); event_handle_.Reset(::CreateEvent( &handles_are_inheritable, TRUE, // The event will automatically reset to non-signaled state. FALSE, // The initial state is non-signalled. nullptr)); // The even is unnamed. GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != nullptr); const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + info->test_suite_name() + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + StreamableToString(death_test_index) + "|" + StreamableToString(static_cast(::GetCurrentProcessId())) + // size_t has the same width as pointers on both 32-bit and 64-bit // Windows platforms. // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. "|" + StreamableToString(reinterpret_cast(write_handle)) + "|" + StreamableToString(reinterpret_cast(event_handle_.Get())); char executable_path[_MAX_PATH + 1]; // NOLINT GTEST_DEATH_TEST_CHECK_(_MAX_PATH + 1 != ::GetModuleFileNameA(nullptr, executable_path, _MAX_PATH)); std::string command_line = std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + internal_flag + "\""; DeathTest::set_last_death_test_message(""); CaptureStderr(); // Flush the log buffers since the log streams are shared with the child. FlushInfoLog(); // The child process will share the standard handles with the parent. STARTUPINFOA startup_info; memset(&startup_info, 0, sizeof(STARTUPINFO)); startup_info.dwFlags = STARTF_USESTDHANDLES; startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); PROCESS_INFORMATION process_info; GTEST_DEATH_TEST_CHECK_( ::CreateProcessA( executable_path, const_cast(command_line.c_str()), nullptr, // Retuned process handle is not inheritable. nullptr, // Retuned thread handle is not inheritable. TRUE, // Child inherits all inheritable handles (for write_handle_). 0x0, // Default creation flags. nullptr, // Inherit the parent's environment. UnitTest::GetInstance()->original_working_dir(), &startup_info, &process_info) != FALSE); child_handle_.Reset(process_info.hProcess); ::CloseHandle(process_info.hThread); set_spawned(true); return OVERSEE_TEST; } # elif GTEST_OS_FUCHSIA class FuchsiaDeathTest : public DeathTestImpl { public: FuchsiaDeathTest(const char* a_statement, Matcher matcher, const char* file, int line) : DeathTestImpl(a_statement, std::move(matcher)), file_(file), line_(line) {} // All of these virtual functions are inherited from DeathTest. int Wait() override; TestRole AssumeRole() override; std::string GetErrorLogs() override; private: // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; // The stderr data captured by the child process. std::string captured_stderr_; zx::process child_process_; zx::channel exception_channel_; zx::socket stderr_socket_; }; // Utility class for accumulating command-line arguments. class Arguments { public: Arguments() { args_.push_back(nullptr); } ~Arguments() { for (std::vector::iterator i = args_.begin(); i != args_.end(); ++i) { free(*i); } } void AddArgument(const char* argument) { args_.insert(args_.end() - 1, posix::StrDup(argument)); } template void AddArguments(const ::std::vector& arguments) { for (typename ::std::vector::const_iterator i = arguments.begin(); i != arguments.end(); ++i) { args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); } } char* const* Argv() { return &args_[0]; } int size() { return args_.size() - 1; } private: std::vector args_; }; // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int FuchsiaDeathTest::Wait() { const int kProcessKey = 0; const int kSocketKey = 1; const int kExceptionKey = 2; if (!spawned()) return 0; // Create a port to wait for socket/task/exception events. zx_status_t status_zx; zx::port port; status_zx = zx::port::create(0, &port); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); // Register to wait for the child process to terminate. status_zx = child_process_.wait_async( port, kProcessKey, ZX_PROCESS_TERMINATED, ZX_WAIT_ASYNC_ONCE); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); // Register to wait for the socket to be readable or closed. status_zx = stderr_socket_.wait_async( port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, ZX_WAIT_ASYNC_ONCE); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); // Register to wait for an exception. status_zx = exception_channel_.wait_async( port, kExceptionKey, ZX_CHANNEL_READABLE, ZX_WAIT_ASYNC_ONCE); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); bool process_terminated = false; bool socket_closed = false; do { zx_port_packet_t packet = {}; status_zx = port.wait(zx::time::infinite(), &packet); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); if (packet.key == kExceptionKey) { // Process encountered an exception. Kill it directly rather than // letting other handlers process the event. We will get a kProcessKey // event when the process actually terminates. status_zx = child_process_.kill(); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); } else if (packet.key == kProcessKey) { // Process terminated. GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED); process_terminated = true; } else if (packet.key == kSocketKey) { GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); if (packet.signal.observed & ZX_SOCKET_READABLE) { // Read data from the socket. constexpr size_t kBufferSize = 1024; do { size_t old_length = captured_stderr_.length(); size_t bytes_read = 0; captured_stderr_.resize(old_length + kBufferSize); status_zx = stderr_socket_.read( 0, &captured_stderr_.front() + old_length, kBufferSize, &bytes_read); captured_stderr_.resize(old_length + bytes_read); } while (status_zx == ZX_OK); if (status_zx == ZX_ERR_PEER_CLOSED) { socket_closed = true; } else { GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT); status_zx = stderr_socket_.wait_async( port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, ZX_WAIT_ASYNC_ONCE); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); } } else { GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_SOCKET_PEER_CLOSED); socket_closed = true; } } } while (!process_terminated && !socket_closed); ReadAndInterpretStatusByte(); zx_info_process_t buffer; status_zx = child_process_.get_info( ZX_INFO_PROCESS, &buffer, sizeof(buffer), nullptr, nullptr); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); GTEST_DEATH_TEST_CHECK_(buffer.exited); set_status(buffer.return_code); return status(); } // The AssumeRole process for a Fuchsia death test. It creates a child // process with the same executable as the current process to run the // death test. The child process is given the --gtest_filter and // --gtest_internal_run_death_test flags such that it knows to run the // current death test only. DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { const UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); if (flag != nullptr) { // ParseInternalRunDeathTestFlag() has performed all the necessary // processing. set_write_fd(kFuchsiaReadPipeFd); return EXECUTE_TEST; } // Flush the log buffers since the log streams are shared with the child. FlushInfoLog(); // Build the child process command line. const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + info->test_suite_name() + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + StreamableToString(death_test_index); Arguments args; args.AddArguments(GetInjectableArgvs()); args.AddArgument(filter_flag.c_str()); args.AddArgument(internal_flag.c_str()); // Build the pipe for communication with the child. zx_status_t status; zx_handle_t child_pipe_handle; int child_pipe_fd; status = fdio_pipe_half(&child_pipe_fd, &child_pipe_handle); GTEST_DEATH_TEST_CHECK_(status == ZX_OK); set_read_fd(child_pipe_fd); // Set the pipe handle for the child. fdio_spawn_action_t spawn_actions[2] = {}; fdio_spawn_action_t* add_handle_action = &spawn_actions[0]; add_handle_action->action = FDIO_SPAWN_ACTION_ADD_HANDLE; add_handle_action->h.id = PA_HND(PA_FD, kFuchsiaReadPipeFd); add_handle_action->h.handle = child_pipe_handle; // Create a socket pair will be used to receive the child process' stderr. zx::socket stderr_producer_socket; status = zx::socket::create(0, &stderr_producer_socket, &stderr_socket_); GTEST_DEATH_TEST_CHECK_(status >= 0); int stderr_producer_fd = -1; status = fdio_fd_create(stderr_producer_socket.release(), &stderr_producer_fd); GTEST_DEATH_TEST_CHECK_(status >= 0); // Make the stderr socket nonblocking. GTEST_DEATH_TEST_CHECK_(fcntl(stderr_producer_fd, F_SETFL, 0) == 0); fdio_spawn_action_t* add_stderr_action = &spawn_actions[1]; add_stderr_action->action = FDIO_SPAWN_ACTION_CLONE_FD; add_stderr_action->fd.local_fd = stderr_producer_fd; add_stderr_action->fd.target_fd = STDERR_FILENO; // Create a child job. zx_handle_t child_job = ZX_HANDLE_INVALID; status = zx_job_create(zx_job_default(), 0, & child_job); GTEST_DEATH_TEST_CHECK_(status == ZX_OK); zx_policy_basic_t policy; policy.condition = ZX_POL_NEW_ANY; policy.policy = ZX_POL_ACTION_ALLOW; status = zx_job_set_policy( child_job, ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC, &policy, 1); GTEST_DEATH_TEST_CHECK_(status == ZX_OK); // Create an exception channel attached to the |child_job|, to allow // us to suppress the system default exception handler from firing. status = zx_task_create_exception_channel( child_job, 0, exception_channel_.reset_and_get_address()); GTEST_DEATH_TEST_CHECK_(status == ZX_OK); // Spawn the child process. status = fdio_spawn_etc( child_job, FDIO_SPAWN_CLONE_ALL, args.Argv()[0], args.Argv(), nullptr, 2, spawn_actions, child_process_.reset_and_get_address(), nullptr); GTEST_DEATH_TEST_CHECK_(status == ZX_OK); set_spawned(true); return OVERSEE_TEST; } std::string FuchsiaDeathTest::GetErrorLogs() { return captured_stderr_; } #else // We are neither on Windows, nor on Fuchsia. // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is // left undefined. class ForkingDeathTest : public DeathTestImpl { public: ForkingDeathTest(const char* statement, Matcher matcher); // All of these virtual functions are inherited from DeathTest. int Wait() override; protected: void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } private: // PID of child process during death test; 0 in the child process itself. pid_t child_pid_; }; // Constructs a ForkingDeathTest. ForkingDeathTest::ForkingDeathTest(const char* a_statement, Matcher matcher) : DeathTestImpl(a_statement, std::move(matcher)), child_pid_(-1) {} // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int ForkingDeathTest::Wait() { if (!spawned()) return 0; ReadAndInterpretStatusByte(); int status_value; GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); set_status(status_value); return status_value; } // A concrete death test class that forks, then immediately runs the test // in the child process. class NoExecDeathTest : public ForkingDeathTest { public: NoExecDeathTest(const char* a_statement, Matcher matcher) : ForkingDeathTest(a_statement, std::move(matcher)) {} TestRole AssumeRole() override; }; // The AssumeRole process for a fork-and-run death test. It implements a // straightforward fork, with a simple pipe to transmit the status byte. DeathTest::TestRole NoExecDeathTest::AssumeRole() { const size_t thread_count = GetThreadCount(); if (thread_count != 1) { GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); } int pipe_fd[2]; GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); DeathTest::set_last_death_test_message(""); CaptureStderr(); // When we fork the process below, the log file buffers are copied, but the // file descriptors are shared. We flush all log files here so that closing // the file descriptors in the child process doesn't throw off the // synchronization between descriptors and buffers in the parent process. // This is as close to the fork as possible to avoid a race condition in case // there are multiple threads running before the death test, and another // thread writes to the log file. FlushInfoLog(); const pid_t child_pid = fork(); GTEST_DEATH_TEST_CHECK_(child_pid != -1); set_child_pid(child_pid); if (child_pid == 0) { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); set_write_fd(pipe_fd[1]); // Redirects all logging to stderr in the child process to prevent // concurrent writes to the log files. We capture stderr in the parent // process and append the child process' output to a log. LogToStderr(); // Event forwarding to the listeners of event listener API mush be shut // down in death test subprocesses. GetUnitTestImpl()->listeners()->SuppressEventForwarding(); g_in_fast_death_test_child = true; return EXECUTE_TEST; } else { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_read_fd(pipe_fd[0]); set_spawned(true); return OVERSEE_TEST; } } // A concrete death test class that forks and re-executes the main // program from the beginning, with command-line flags set that cause // only this specific death test to be run. class ExecDeathTest : public ForkingDeathTest { public: ExecDeathTest(const char* a_statement, Matcher matcher, const char* file, int line) : ForkingDeathTest(a_statement, std::move(matcher)), file_(file), line_(line) {} TestRole AssumeRole() override; private: static ::std::vector GetArgvsForDeathTestChildProcess() { ::std::vector args = GetInjectableArgvs(); # if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) ::std::vector extra_args = GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_(); args.insert(args.end(), extra_args.begin(), extra_args.end()); # endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) return args; } // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; }; // Utility class for accumulating command-line arguments. class Arguments { public: Arguments() { args_.push_back(nullptr); } ~Arguments() { for (std::vector::iterator i = args_.begin(); i != args_.end(); ++i) { free(*i); } } void AddArgument(const char* argument) { args_.insert(args_.end() - 1, posix::StrDup(argument)); } template void AddArguments(const ::std::vector& arguments) { for (typename ::std::vector::const_iterator i = arguments.begin(); i != arguments.end(); ++i) { args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); } } char* const* Argv() { return &args_[0]; } private: std::vector args_; }; // A struct that encompasses the arguments to the child process of a // threadsafe-style death test process. struct ExecDeathTestArgs { char* const* argv; // Command-line arguments for the child's call to exec int close_fd; // File descriptor to close; the read end of a pipe }; # if GTEST_OS_MAC inline char** GetEnviron() { // When Google Test is built as a framework on MacOS X, the environ variable // is unavailable. Apple's documentation (man environ) recommends using // _NSGetEnviron() instead. return *_NSGetEnviron(); } # else // Some POSIX platforms expect you to declare environ. extern "C" makes // it reside in the global namespace. extern "C" char** environ; inline char** GetEnviron() { return environ; } # endif // GTEST_OS_MAC # if !GTEST_OS_QNX // The main function for a threadsafe-style death test child process. // This function is called in a clone()-ed process and thus must avoid // any potentially unsafe operations like malloc or libc functions. static int ExecDeathTestChildMain(void* child_arg) { ExecDeathTestArgs* const args = static_cast(child_arg); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); // We need to execute the test program in the same environment where // it was originally invoked. Therefore we change to the original // working directory first. const char* const original_dir = UnitTest::GetInstance()->original_working_dir(); // We can safely call chdir() as it's a direct system call. if (chdir(original_dir) != 0) { DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } // We can safely call execve() as it's a direct system call. We // cannot use execvp() as it's a libc function and thus potentially // unsafe. Since execve() doesn't search the PATH, the user must // invoke the test program via a valid path that contains at least // one path separator. execve(args->argv[0], args->argv, GetEnviron()); DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " + original_dir + " failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } # endif // !GTEST_OS_QNX # if GTEST_HAS_CLONE // Two utility routines that together determine the direction the stack // grows. // This could be accomplished more elegantly by a single recursive // function, but we want to guard against the unlikely possibility of // a smart compiler optimizing the recursion away. // // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining // StackLowerThanAddress into StackGrowsDown, which then doesn't give // correct answer. static void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; // HWAddressSanitizer add a random tag to the MSB of the local variable address, // making comparison result unpredictable. GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ static void StackLowerThanAddress(const void* ptr, bool* result) { int dummy; *result = (&dummy < ptr); } // Make sure AddressSanitizer does not tamper with the stack here. GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ static bool StackGrowsDown() { int dummy; bool result; StackLowerThanAddress(&dummy, &result); return result; } # endif // GTEST_HAS_CLONE // Spawns a child process with the same executable as the current process in // a thread-safe manner and instructs it to run the death test. The // implementation uses fork(2) + exec. On systems where clone(2) is // available, it is used instead, being slightly more thread-safe. On QNX, // fork supports only single-threaded environments, so this function uses // spawn(2) there instead. The function dies with an error message if // anything goes wrong. static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { ExecDeathTestArgs args = { argv, close_fd }; pid_t child_pid = -1; # if GTEST_OS_QNX // Obtains the current directory and sets it to be closed in the child // process. const int cwd_fd = open(".", O_RDONLY); GTEST_DEATH_TEST_CHECK_(cwd_fd != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC)); // We need to execute the test program in the same environment where // it was originally invoked. Therefore we change to the original // working directory first. const char* const original_dir = UnitTest::GetInstance()->original_working_dir(); // We can safely call chdir() as it's a direct system call. if (chdir(original_dir) != 0) { DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } int fd_flags; // Set close_fd to be closed after spawn. GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, fd_flags | FD_CLOEXEC)); struct inheritance inherit = {0}; // spawn is a system call. child_pid = spawn(args.argv[0], 0, nullptr, &inherit, args.argv, GetEnviron()); // Restores the current working directory. GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); # else // GTEST_OS_QNX # if GTEST_OS_LINUX // When a SIGPROF signal is received while fork() or clone() are executing, // the process may hang. To avoid this, we ignore SIGPROF here and re-enable // it after the call to fork()/clone() is complete. struct sigaction saved_sigprof_action; struct sigaction ignore_sigprof_action; memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action)); sigemptyset(&ignore_sigprof_action.sa_mask); ignore_sigprof_action.sa_handler = SIG_IGN; GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); # endif // GTEST_OS_LINUX # if GTEST_HAS_CLONE const bool use_fork = GTEST_FLAG(death_test_use_fork); if (!use_fork) { static const bool stack_grows_down = StackGrowsDown(); const auto stack_size = static_cast(getpagesize()); // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. void* const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); // Maximum stack alignment in bytes: For a downward-growing stack, this // amount is subtracted from size of the stack space to get an address // that is within the stack space and is aligned on all systems we care // about. As far as I know there is no ABI with stack alignment greater // than 64. We assume stack and stack_size already have alignment of // kMaxStackAlignment. const size_t kMaxStackAlignment = 64; void* const stack_top = static_cast(stack) + (stack_grows_down ? stack_size - kMaxStackAlignment : 0); GTEST_DEATH_TEST_CHECK_( static_cast(stack_size) > kMaxStackAlignment && reinterpret_cast(stack_top) % kMaxStackAlignment == 0); child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); } # else const bool use_fork = true; # endif // GTEST_HAS_CLONE if (use_fork && (child_pid = fork()) == 0) { ExecDeathTestChildMain(&args); _exit(0); } # endif // GTEST_OS_QNX # if GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_SYSCALL_( sigaction(SIGPROF, &saved_sigprof_action, nullptr)); # endif // GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_(child_pid != -1); return child_pid; } // The AssumeRole process for a fork-and-exec death test. It re-executes the // main program from the beginning, setting the --gtest_filter // and --gtest_internal_run_death_test flags to cause only the current // death test to be re-run. DeathTest::TestRole ExecDeathTest::AssumeRole() { const UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); if (flag != nullptr) { set_write_fd(flag->write_fd()); return EXECUTE_TEST; } int pipe_fd[2]; GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); // Clear the close-on-exec flag on the write end of the pipe, lest // it be closed when the child process does an exec: GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + info->test_suite_name() + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + StreamableToString(death_test_index) + "|" + StreamableToString(pipe_fd[1]); Arguments args; args.AddArguments(GetArgvsForDeathTestChildProcess()); args.AddArgument(filter_flag.c_str()); args.AddArgument(internal_flag.c_str()); DeathTest::set_last_death_test_message(""); CaptureStderr(); // See the comment in NoExecDeathTest::AssumeRole for why the next line // is necessary. FlushInfoLog(); const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_child_pid(child_pid); set_read_fd(pipe_fd[0]); set_spawned(true); return OVERSEE_TEST; } # endif // !GTEST_OS_WINDOWS // Creates a concrete DeathTest-derived class that depends on the // --gtest_death_test_style flag, and sets the pointer pointed to // by the "test" argument to its address. If the test should be // skipped, sets that pointer to NULL. Returns true, unless the // flag is set to an invalid value. bool DefaultDeathTestFactory::Create(const char* statement, Matcher matcher, const char* file, int line, DeathTest** test) { UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const int death_test_index = impl->current_test_info() ->increment_death_test_count(); if (flag != nullptr) { if (death_test_index > flag->index()) { DeathTest::set_last_death_test_message( "Death test count (" + StreamableToString(death_test_index) + ") somehow exceeded expected maximum (" + StreamableToString(flag->index()) + ")"); return false; } if (!(flag->file() == file && flag->line() == line && flag->index() == death_test_index)) { *test = nullptr; return true; } } # if GTEST_OS_WINDOWS if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { *test = new WindowsDeathTest(statement, std::move(matcher), file, line); } # elif GTEST_OS_FUCHSIA if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { *test = new FuchsiaDeathTest(statement, std::move(matcher), file, line); } # else if (GTEST_FLAG(death_test_style) == "threadsafe") { *test = new ExecDeathTest(statement, std::move(matcher), file, line); } else if (GTEST_FLAG(death_test_style) == "fast") { *test = new NoExecDeathTest(statement, std::move(matcher)); } # endif // GTEST_OS_WINDOWS else { // NOLINT - this is more readable than unbalanced brackets inside #if. DeathTest::set_last_death_test_message( "Unknown death test style \"" + GTEST_FLAG(death_test_style) + "\" encountered"); return false; } return true; } # if GTEST_OS_WINDOWS // Recreates the pipe and event handles from the provided parameters, // signals the event, and returns a file descriptor wrapped around the pipe // handle. This function is called in the child process only. static int GetStatusFileDescriptor(unsigned int parent_process_id, size_t write_handle_as_size_t, size_t event_handle_as_size_t) { AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, FALSE, // Non-inheritable. parent_process_id)); if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { DeathTestAbort("Unable to open parent process " + StreamableToString(parent_process_id)); } GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); const HANDLE write_handle = reinterpret_cast(write_handle_as_size_t); HANDLE dup_write_handle; // The newly initialized handle is accessible only in the parent // process. To obtain one accessible within the child, we need to use // DuplicateHandle. if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, ::GetCurrentProcess(), &dup_write_handle, 0x0, // Requested privileges ignored since // DUPLICATE_SAME_ACCESS is used. FALSE, // Request non-inheritable handler. DUPLICATE_SAME_ACCESS)) { DeathTestAbort("Unable to duplicate the pipe handle " + StreamableToString(write_handle_as_size_t) + " from the parent process " + StreamableToString(parent_process_id)); } const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); HANDLE dup_event_handle; if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, ::GetCurrentProcess(), &dup_event_handle, 0x0, FALSE, DUPLICATE_SAME_ACCESS)) { DeathTestAbort("Unable to duplicate the event handle " + StreamableToString(event_handle_as_size_t) + " from the parent process " + StreamableToString(parent_process_id)); } const int write_fd = ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); if (write_fd == -1) { DeathTestAbort("Unable to convert pipe handle " + StreamableToString(write_handle_as_size_t) + " to a file descriptor"); } // Signals the parent that the write end of the pipe has been acquired // so the parent can release its own write end. ::SetEvent(dup_event_handle); return write_fd; } # endif // GTEST_OS_WINDOWS // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { if (GTEST_FLAG(internal_run_death_test) == "") return nullptr; // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we // can use it here. int line = -1; int index = -1; ::std::vector< ::std::string> fields; SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); int write_fd = -1; # if GTEST_OS_WINDOWS unsigned int parent_process_id = 0; size_t write_handle_as_size_t = 0; size_t event_handle_as_size_t = 0; if (fields.size() != 6 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &parent_process_id) || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + GTEST_FLAG(internal_run_death_test)); } write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, event_handle_as_size_t); # elif GTEST_OS_FUCHSIA if (fields.size() != 3 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index)) { DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + GTEST_FLAG(internal_run_death_test)); } # else if (fields.size() != 4 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &write_fd)) { DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + GTEST_FLAG(internal_run_death_test)); } # endif // GTEST_OS_WINDOWS return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); } } // namespace internal #endif // GTEST_HAS_DEATH_TEST } // namespace testing openzwave-1.6.1914/cpp/test/src/gtest-port.cc0000644000175200017520000013255214032142455015677 00000000000000// Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "gtest/internal/gtest-port.h" #include #include #include #include #include #include #if GTEST_OS_WINDOWS # include # include # include # include // Used in ThreadLocal. # ifdef _MSC_VER # include # endif // _MSC_VER #else # include #endif // GTEST_OS_WINDOWS #if GTEST_OS_MAC # include # include # include #endif // GTEST_OS_MAC #if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \ GTEST_OS_NETBSD || GTEST_OS_OPENBSD # include # if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD # include # endif #endif #if GTEST_OS_QNX # include # include # include #endif // GTEST_OS_QNX #if GTEST_OS_AIX # include # include #endif // GTEST_OS_AIX #if GTEST_OS_FUCHSIA # include # include #endif // GTEST_OS_FUCHSIA #include "gtest/gtest-spi.h" #include "gtest/gtest-message.h" #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" #include "src/gtest-internal-inl.h" namespace testing { namespace internal { #if defined(_MSC_VER) || defined(__BORLANDC__) // MSVC and C++Builder do not provide a definition of STDERR_FILENO. const int kStdOutFileno = 1; const int kStdErrFileno = 2; #else const int kStdOutFileno = STDOUT_FILENO; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER #if GTEST_OS_LINUX namespace { template T ReadProcFileField(const std::string& filename, int field) { std::string dummy; std::ifstream file(filename.c_str()); while (field-- > 0) { file >> dummy; } T output = 0; file >> output; return output; } } // namespace // Returns the number of active threads, or 0 when there is an error. size_t GetThreadCount() { const std::string filename = (Message() << "/proc/" << getpid() << "/stat").GetString(); return ReadProcFileField(filename, 19); } #elif GTEST_OS_MAC size_t GetThreadCount() { const task_t task = mach_task_self(); mach_msg_type_number_t thread_count; thread_act_array_t thread_list; const kern_return_t status = task_threads(task, &thread_list, &thread_count); if (status == KERN_SUCCESS) { // task_threads allocates resources in thread_list and we need to free them // to avoid leaks. vm_deallocate(task, reinterpret_cast(thread_list), sizeof(thread_t) * thread_count); return static_cast(thread_count); } else { return 0; } } #elif GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \ GTEST_OS_NETBSD #if GTEST_OS_NETBSD #undef KERN_PROC #define KERN_PROC KERN_PROC2 #define kinfo_proc kinfo_proc2 #endif #if GTEST_OS_DRAGONFLY #define KP_NLWP(kp) (kp.kp_nthreads) #elif GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD #define KP_NLWP(kp) (kp.ki_numthreads) #elif GTEST_OS_NETBSD #define KP_NLWP(kp) (kp.p_nlwps) #endif // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. size_t GetThreadCount() { int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid(), #if GTEST_OS_NETBSD sizeof(struct kinfo_proc), 1, #endif }; u_int miblen = sizeof(mib) / sizeof(mib[0]); struct kinfo_proc info; size_t size = sizeof(info); if (sysctl(mib, miblen, &info, &size, NULL, 0)) { return 0; } return static_cast(KP_NLWP(info)); } #elif GTEST_OS_OPENBSD // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. size_t GetThreadCount() { int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_SHOW_THREADS, getpid(), sizeof(struct kinfo_proc), 0, }; u_int miblen = sizeof(mib) / sizeof(mib[0]); // get number of structs size_t size; if (sysctl(mib, miblen, NULL, &size, NULL, 0)) { return 0; } mib[5] = size / mib[4]; // populate array of structs struct kinfo_proc info[mib[5]]; if (sysctl(mib, miblen, &info, &size, NULL, 0)) { return 0; } // exclude empty members int nthreads = 0; for (int i = 0; i < size / mib[4]; i++) { if (info[i].p_tid != -1) nthreads++; } return nthreads; } #elif GTEST_OS_QNX // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. size_t GetThreadCount() { const int fd = open("/proc/self/as", O_RDONLY); if (fd < 0) { return 0; } procfs_info process_info; const int status = devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), nullptr); close(fd); if (status == EOK) { return static_cast(process_info.num_threads); } else { return 0; } } #elif GTEST_OS_AIX size_t GetThreadCount() { struct procentry64 entry; pid_t pid = getpid(); int status = getprocs64(&entry, sizeof(entry), nullptr, 0, &pid, 1); if (status == 1) { return entry.pi_thcount; } else { return 0; } } #elif GTEST_OS_FUCHSIA size_t GetThreadCount() { int dummy_buffer; size_t avail; zx_status_t status = zx_object_get_info( zx_process_self(), ZX_INFO_PROCESS_THREADS, &dummy_buffer, 0, nullptr, &avail); if (status == ZX_OK) { return avail; } else { return 0; } } #else size_t GetThreadCount() { // There's no portable way to detect the number of threads, so we just // return 0 to indicate that we cannot detect it. return 0; } #endif // GTEST_OS_LINUX #if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS void SleepMilliseconds(int n) { ::Sleep(static_cast(n)); } AutoHandle::AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} AutoHandle::AutoHandle(Handle handle) : handle_(handle) {} AutoHandle::~AutoHandle() { Reset(); } AutoHandle::Handle AutoHandle::Get() const { return handle_; } void AutoHandle::Reset() { Reset(INVALID_HANDLE_VALUE); } void AutoHandle::Reset(HANDLE handle) { // Resetting with the same handle we already own is invalid. if (handle_ != handle) { if (IsCloseable()) { ::CloseHandle(handle_); } handle_ = handle; } else { GTEST_CHECK_(!IsCloseable()) << "Resetting a valid handle to itself is likely a programmer error " "and thus not allowed."; } } bool AutoHandle::IsCloseable() const { // Different Windows APIs may use either of these values to represent an // invalid handle. return handle_ != nullptr && handle_ != INVALID_HANDLE_VALUE; } Notification::Notification() : event_(::CreateEvent(nullptr, // Default security attributes. TRUE, // Do not reset automatically. FALSE, // Initially unset. nullptr)) { // Anonymous event. GTEST_CHECK_(event_.Get() != nullptr); } void Notification::Notify() { GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE); } void Notification::WaitForNotification() { GTEST_CHECK_( ::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0); } Mutex::Mutex() : owner_thread_id_(0), type_(kDynamic), critical_section_init_phase_(0), critical_section_(new CRITICAL_SECTION) { ::InitializeCriticalSection(critical_section_); } Mutex::~Mutex() { // Static mutexes are leaked intentionally. It is not thread-safe to try // to clean them up. if (type_ == kDynamic) { ::DeleteCriticalSection(critical_section_); delete critical_section_; critical_section_ = nullptr; } } void Mutex::Lock() { ThreadSafeLazyInit(); ::EnterCriticalSection(critical_section_); owner_thread_id_ = ::GetCurrentThreadId(); } void Mutex::Unlock() { ThreadSafeLazyInit(); // We don't protect writing to owner_thread_id_ here, as it's the // caller's responsibility to ensure that the current thread holds the // mutex when this is called. owner_thread_id_ = 0; ::LeaveCriticalSection(critical_section_); } // Does nothing if the current thread holds the mutex. Otherwise, crashes // with high probability. void Mutex::AssertHeld() { ThreadSafeLazyInit(); GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId()) << "The current thread is not holding the mutex @" << this; } namespace { #ifdef _MSC_VER // Use the RAII idiom to flag mem allocs that are intentionally never // deallocated. The motivation is to silence the false positive mem leaks // that are reported by the debug version of MS's CRT which can only detect // if an alloc is missing a matching deallocation. // Example: // MemoryIsNotDeallocated memory_is_not_deallocated; // critical_section_ = new CRITICAL_SECTION; // class MemoryIsNotDeallocated { public: MemoryIsNotDeallocated() : old_crtdbg_flag_(0) { old_crtdbg_flag_ = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); // Set heap allocation block type to _IGNORE_BLOCK so that MS debug CRT // doesn't report mem leak if there's no matching deallocation. _CrtSetDbgFlag(old_crtdbg_flag_ & ~_CRTDBG_ALLOC_MEM_DF); } ~MemoryIsNotDeallocated() { // Restore the original _CRTDBG_ALLOC_MEM_DF flag _CrtSetDbgFlag(old_crtdbg_flag_); } private: int old_crtdbg_flag_; GTEST_DISALLOW_COPY_AND_ASSIGN_(MemoryIsNotDeallocated); }; #endif // _MSC_VER } // namespace // Initializes owner_thread_id_ and critical_section_ in static mutexes. void Mutex::ThreadSafeLazyInit() { // Dynamic mutexes are initialized in the constructor. if (type_ == kStatic) { switch ( ::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) { case 0: // If critical_section_init_phase_ was 0 before the exchange, we // are the first to test it and need to perform the initialization. owner_thread_id_ = 0; { // Use RAII to flag that following mem alloc is never deallocated. #ifdef _MSC_VER MemoryIsNotDeallocated memory_is_not_deallocated; #endif // _MSC_VER critical_section_ = new CRITICAL_SECTION; } ::InitializeCriticalSection(critical_section_); // Updates the critical_section_init_phase_ to 2 to signal // initialization complete. GTEST_CHECK_(::InterlockedCompareExchange( &critical_section_init_phase_, 2L, 1L) == 1L); break; case 1: // Somebody else is already initializing the mutex; spin until they // are done. while (::InterlockedCompareExchange(&critical_section_init_phase_, 2L, 2L) != 2L) { // Possibly yields the rest of the thread's time slice to other // threads. ::Sleep(0); } break; case 2: break; // The mutex is already initialized and ready for use. default: GTEST_CHECK_(false) << "Unexpected value of critical_section_init_phase_ " << "while initializing a static mutex."; } } } namespace { class ThreadWithParamSupport : public ThreadWithParamBase { public: static HANDLE CreateThread(Runnable* runnable, Notification* thread_can_start) { ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start); DWORD thread_id; HANDLE thread_handle = ::CreateThread( nullptr, // Default security. 0, // Default stack size. &ThreadWithParamSupport::ThreadMain, param, // Parameter to ThreadMainStatic 0x0, // Default creation flags. &thread_id); // Need a valid pointer for the call to work under Win98. GTEST_CHECK_(thread_handle != nullptr) << "CreateThread failed with error " << ::GetLastError() << "."; if (thread_handle == nullptr) { delete param; } return thread_handle; } private: struct ThreadMainParam { ThreadMainParam(Runnable* runnable, Notification* thread_can_start) : runnable_(runnable), thread_can_start_(thread_can_start) { } std::unique_ptr runnable_; // Does not own. Notification* thread_can_start_; }; static DWORD WINAPI ThreadMain(void* ptr) { // Transfers ownership. std::unique_ptr param(static_cast(ptr)); if (param->thread_can_start_ != nullptr) param->thread_can_start_->WaitForNotification(); param->runnable_->Run(); return 0; } // Prohibit instantiation. ThreadWithParamSupport(); GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParamSupport); }; } // namespace ThreadWithParamBase::ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start) : thread_(ThreadWithParamSupport::CreateThread(runnable, thread_can_start)) { } ThreadWithParamBase::~ThreadWithParamBase() { Join(); } void ThreadWithParamBase::Join() { GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0) << "Failed to join the thread with error " << ::GetLastError() << "."; } // Maps a thread to a set of ThreadIdToThreadLocals that have values // instantiated on that thread and notifies them when the thread exits. A // ThreadLocal instance is expected to persist until all threads it has // values on have terminated. class ThreadLocalRegistryImpl { public: // Registers thread_local_instance as having value on the current thread. // Returns a value that can be used to identify the thread from other threads. static ThreadLocalValueHolderBase* GetValueOnCurrentThread( const ThreadLocalBase* thread_local_instance) { DWORD current_thread = ::GetCurrentThreadId(); MutexLock lock(&mutex_); ThreadIdToThreadLocals* const thread_to_thread_locals = GetThreadLocalsMapLocked(); ThreadIdToThreadLocals::iterator thread_local_pos = thread_to_thread_locals->find(current_thread); if (thread_local_pos == thread_to_thread_locals->end()) { thread_local_pos = thread_to_thread_locals->insert( std::make_pair(current_thread, ThreadLocalValues())).first; StartWatcherThreadFor(current_thread); } ThreadLocalValues& thread_local_values = thread_local_pos->second; ThreadLocalValues::iterator value_pos = thread_local_values.find(thread_local_instance); if (value_pos == thread_local_values.end()) { value_pos = thread_local_values .insert(std::make_pair( thread_local_instance, std::shared_ptr( thread_local_instance->NewValueForCurrentThread()))) .first; } return value_pos->second.get(); } static void OnThreadLocalDestroyed( const ThreadLocalBase* thread_local_instance) { std::vector > value_holders; // Clean up the ThreadLocalValues data structure while holding the lock, but // defer the destruction of the ThreadLocalValueHolderBases. { MutexLock lock(&mutex_); ThreadIdToThreadLocals* const thread_to_thread_locals = GetThreadLocalsMapLocked(); for (ThreadIdToThreadLocals::iterator it = thread_to_thread_locals->begin(); it != thread_to_thread_locals->end(); ++it) { ThreadLocalValues& thread_local_values = it->second; ThreadLocalValues::iterator value_pos = thread_local_values.find(thread_local_instance); if (value_pos != thread_local_values.end()) { value_holders.push_back(value_pos->second); thread_local_values.erase(value_pos); // This 'if' can only be successful at most once, so theoretically we // could break out of the loop here, but we don't bother doing so. } } } // Outside the lock, let the destructor for 'value_holders' deallocate the // ThreadLocalValueHolderBases. } static void OnThreadExit(DWORD thread_id) { GTEST_CHECK_(thread_id != 0) << ::GetLastError(); std::vector > value_holders; // Clean up the ThreadIdToThreadLocals data structure while holding the // lock, but defer the destruction of the ThreadLocalValueHolderBases. { MutexLock lock(&mutex_); ThreadIdToThreadLocals* const thread_to_thread_locals = GetThreadLocalsMapLocked(); ThreadIdToThreadLocals::iterator thread_local_pos = thread_to_thread_locals->find(thread_id); if (thread_local_pos != thread_to_thread_locals->end()) { ThreadLocalValues& thread_local_values = thread_local_pos->second; for (ThreadLocalValues::iterator value_pos = thread_local_values.begin(); value_pos != thread_local_values.end(); ++value_pos) { value_holders.push_back(value_pos->second); } thread_to_thread_locals->erase(thread_local_pos); } } // Outside the lock, let the destructor for 'value_holders' deallocate the // ThreadLocalValueHolderBases. } private: // In a particular thread, maps a ThreadLocal object to its value. typedef std::map > ThreadLocalValues; // Stores all ThreadIdToThreadLocals having values in a thread, indexed by // thread's ID. typedef std::map ThreadIdToThreadLocals; // Holds the thread id and thread handle that we pass from // StartWatcherThreadFor to WatcherThreadFunc. typedef std::pair ThreadIdAndHandle; static void StartWatcherThreadFor(DWORD thread_id) { // The returned handle will be kept in thread_map and closed by // watcher_thread in WatcherThreadFunc. HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, FALSE, thread_id); GTEST_CHECK_(thread != nullptr); // We need to pass a valid thread ID pointer into CreateThread for it // to work correctly under Win98. DWORD watcher_thread_id; HANDLE watcher_thread = ::CreateThread( nullptr, // Default security. 0, // Default stack size &ThreadLocalRegistryImpl::WatcherThreadFunc, reinterpret_cast(new ThreadIdAndHandle(thread_id, thread)), CREATE_SUSPENDED, &watcher_thread_id); GTEST_CHECK_(watcher_thread != nullptr); // Give the watcher thread the same priority as ours to avoid being // blocked by it. ::SetThreadPriority(watcher_thread, ::GetThreadPriority(::GetCurrentThread())); ::ResumeThread(watcher_thread); ::CloseHandle(watcher_thread); } // Monitors exit from a given thread and notifies those // ThreadIdToThreadLocals about thread termination. static DWORD WINAPI WatcherThreadFunc(LPVOID param) { const ThreadIdAndHandle* tah = reinterpret_cast(param); GTEST_CHECK_( ::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0); OnThreadExit(tah->first); ::CloseHandle(tah->second); delete tah; return 0; } // Returns map of thread local instances. static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() { mutex_.AssertHeld(); #ifdef _MSC_VER MemoryIsNotDeallocated memory_is_not_deallocated; #endif // _MSC_VER static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals(); return map; } // Protects access to GetThreadLocalsMapLocked() and its return value. static Mutex mutex_; // Protects access to GetThreadMapLocked() and its return value. static Mutex thread_map_mutex_; }; Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex); ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread( const ThreadLocalBase* thread_local_instance) { return ThreadLocalRegistryImpl::GetValueOnCurrentThread( thread_local_instance); } void ThreadLocalRegistry::OnThreadLocalDestroyed( const ThreadLocalBase* thread_local_instance) { ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance); } #endif // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS #if GTEST_USES_POSIX_RE // Implements RE. Currently only needed for death tests. RE::~RE() { if (is_valid_) { // regfree'ing an invalid regex might crash because the content // of the regex is undefined. Since the regex's are essentially // the same, one cannot be valid (or invalid) without the other // being so too. regfree(&partial_regex_); regfree(&full_regex_); } free(const_cast(pattern_)); } // Returns true if and only if regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; regmatch_t match; return regexec(&re.full_regex_, str, 1, &match, 0) == 0; } // Returns true if and only if regular expression re matches a substring of // str (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; regmatch_t match; return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; } // Initializes an RE from its string representation. void RE::Init(const char* regex) { pattern_ = posix::StrDup(regex); // Reserves enough bytes to hold the regular expression used for a // full match. const size_t full_regex_len = strlen(regex) + 10; char* const full_pattern = new char[full_regex_len]; snprintf(full_pattern, full_regex_len, "^(%s)$", regex); is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; // We want to call regcomp(&partial_regex_, ...) even if the // previous expression returns false. Otherwise partial_regex_ may // not be properly initialized can may cause trouble when it's // freed. // // Some implementation of POSIX regex (e.g. on at least some // versions of Cygwin) doesn't accept the empty string as a valid // regex. We change it to an equivalent form "()" to be safe. if (is_valid_) { const char* const partial_regex = (*regex == '\0') ? "()" : regex; is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; } EXPECT_TRUE(is_valid_) << "Regular expression \"" << regex << "\" is not a valid POSIX Extended regular expression."; delete[] full_pattern; } #elif GTEST_USES_SIMPLE_RE // Returns true if and only if ch appears anywhere in str (excluding the // terminating '\0' character). bool IsInSet(char ch, const char* str) { return ch != '\0' && strchr(str, ch) != nullptr; } // Returns true if and only if ch belongs to the given classification. // Unlike similar functions in , these aren't affected by the // current locale. bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } bool IsAsciiPunct(char ch) { return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); } bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } bool IsAsciiWordChar(char ch) { return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('0' <= ch && ch <= '9') || ch == '_'; } // Returns true if and only if "\\c" is a supported escape sequence. bool IsValidEscape(char c) { return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); } // Returns true if and only if the given atom (specified by escaped and // pattern) matches ch. The result is undefined if the atom is invalid. bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { if (escaped) { // "\\p" where p is pattern_char. switch (pattern_char) { case 'd': return IsAsciiDigit(ch); case 'D': return !IsAsciiDigit(ch); case 'f': return ch == '\f'; case 'n': return ch == '\n'; case 'r': return ch == '\r'; case 's': return IsAsciiWhiteSpace(ch); case 'S': return !IsAsciiWhiteSpace(ch); case 't': return ch == '\t'; case 'v': return ch == '\v'; case 'w': return IsAsciiWordChar(ch); case 'W': return !IsAsciiWordChar(ch); } return IsAsciiPunct(pattern_char) && pattern_char == ch; } return (pattern_char == '.' && ch != '\n') || pattern_char == ch; } // Helper function used by ValidateRegex() to format error messages. static std::string FormatRegexSyntaxError(const char* regex, int index) { return (Message() << "Syntax error at index " << index << " in simple regular expression \"" << regex << "\": ").GetString(); } // Generates non-fatal failures and returns false if regex is invalid; // otherwise returns true. bool ValidateRegex(const char* regex) { if (regex == nullptr) { ADD_FAILURE() << "NULL is not a valid simple regular expression."; return false; } bool is_valid = true; // True if and only if ?, *, or + can follow the previous atom. bool prev_repeatable = false; for (int i = 0; regex[i]; i++) { if (regex[i] == '\\') { // An escape sequence i++; if (regex[i] == '\0') { ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) << "'\\' cannot appear at the end."; return false; } if (!IsValidEscape(regex[i])) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) << "invalid escape sequence \"\\" << regex[i] << "\"."; is_valid = false; } prev_repeatable = true; } else { // Not an escape sequence. const char ch = regex[i]; if (ch == '^' && i > 0) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'^' can only appear at the beginning."; is_valid = false; } else if (ch == '$' && regex[i + 1] != '\0') { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'$' can only appear at the end."; is_valid = false; } else if (IsInSet(ch, "()[]{}|")) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'" << ch << "' is unsupported."; is_valid = false; } else if (IsRepeat(ch) && !prev_repeatable) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'" << ch << "' can only follow a repeatable token."; is_valid = false; } prev_repeatable = !IsInSet(ch, "^$?*+"); } } return is_valid; } // Matches a repeated regex atom followed by a valid simple regular // expression. The regex atom is defined as c if escaped is false, // or \c otherwise. repeat is the repetition meta character (?, *, // or +). The behavior is undefined if str contains too many // characters to be indexable by size_t, in which case the test will // probably time out anyway. We are fine with this limitation as // std::string has it too. bool MatchRepetitionAndRegexAtHead( bool escaped, char c, char repeat, const char* regex, const char* str) { const size_t min_count = (repeat == '+') ? 1 : 0; const size_t max_count = (repeat == '?') ? 1 : static_cast(-1) - 1; // We cannot call numeric_limits::max() as it conflicts with the // max() macro on Windows. for (size_t i = 0; i <= max_count; ++i) { // We know that the atom matches each of the first i characters in str. if (i >= min_count && MatchRegexAtHead(regex, str + i)) { // We have enough matches at the head, and the tail matches too. // Since we only care about *whether* the pattern matches str // (as opposed to *how* it matches), there is no need to find a // greedy match. return true; } if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) return false; } return false; } // Returns true if and only if regex matches a prefix of str. regex must // be a valid simple regular expression and not start with "^", or the // result is undefined. bool MatchRegexAtHead(const char* regex, const char* str) { if (*regex == '\0') // An empty regex matches a prefix of anything. return true; // "$" only matches the end of a string. Note that regex being // valid guarantees that there's nothing after "$" in it. if (*regex == '$') return *str == '\0'; // Is the first thing in regex an escape sequence? const bool escaped = *regex == '\\'; if (escaped) ++regex; if (IsRepeat(regex[1])) { // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so // here's an indirect recursion. It terminates as the regex gets // shorter in each recursion. return MatchRepetitionAndRegexAtHead( escaped, regex[0], regex[1], regex + 2, str); } else { // regex isn't empty, isn't "$", and doesn't start with a // repetition. We match the first atom of regex with the first // character of str and recurse. return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && MatchRegexAtHead(regex + 1, str + 1); } } // Returns true if and only if regex matches any substring of str. regex must // be a valid simple regular expression, or the result is undefined. // // The algorithm is recursive, but the recursion depth doesn't exceed // the regex length, so we won't need to worry about running out of // stack space normally. In rare cases the time complexity can be // exponential with respect to the regex length + the string length, // but usually it's must faster (often close to linear). bool MatchRegexAnywhere(const char* regex, const char* str) { if (regex == nullptr || str == nullptr) return false; if (*regex == '^') return MatchRegexAtHead(regex + 1, str); // A successful match can be anywhere in str. do { if (MatchRegexAtHead(regex, str)) return true; } while (*str++ != '\0'); return false; } // Implements the RE class. RE::~RE() { free(const_cast(pattern_)); free(const_cast(full_pattern_)); } // Returns true if and only if regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); } // Returns true if and only if regular expression re matches a substring of // str (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); } // Initializes an RE from its string representation. void RE::Init(const char* regex) { pattern_ = full_pattern_ = nullptr; if (regex != nullptr) { pattern_ = posix::StrDup(regex); } is_valid_ = ValidateRegex(regex); if (!is_valid_) { // No need to calculate the full pattern when the regex is invalid. return; } const size_t len = strlen(regex); // Reserves enough bytes to hold the regular expression used for a // full match: we need space to prepend a '^', append a '$', and // terminate the string with '\0'. char* buffer = static_cast(malloc(len + 3)); full_pattern_ = buffer; if (*regex != '^') *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. // We don't use snprintf or strncpy, as they trigger a warning when // compiled with VC++ 8.0. memcpy(buffer, regex, len); buffer += len; if (len == 0 || regex[len - 1] != '$') *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. *buffer = '\0'; } #endif // GTEST_USES_POSIX_RE const char kUnknownFile[] = "unknown file"; // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { const std::string file_name(file == nullptr ? kUnknownFile : file); if (line < 0) { return file_name + ":"; } #ifdef _MSC_VER return file_name + "(" + StreamableToString(line) + "):"; #else return file_name + ":" + StreamableToString(line) + ":"; #endif // _MSC_VER } // Formats a file location for compiler-independent XML output. // Although this function is not platform dependent, we put it next to // FormatFileLocation in order to contrast the two functions. // Note that FormatCompilerIndependentFileLocation() does NOT append colon // to the file location it produces, unlike FormatFileLocation(). GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( const char* file, int line) { const std::string file_name(file == nullptr ? kUnknownFile : file); if (line < 0) return file_name; else return file_name + ":" + StreamableToString(line); } GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) : severity_(severity) { const char* const marker = severity == GTEST_INFO ? "[ INFO ]" : severity == GTEST_WARNING ? "[WARNING]" : severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; GetStream() << ::std::endl << marker << " " << FormatFileLocation(file, line).c_str() << ": "; } // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. GTestLog::~GTestLog() { GetStream() << ::std::endl; if (severity_ == GTEST_FATAL) { fflush(stderr); posix::Abort(); } } // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) GTEST_DISABLE_MSC_DEPRECATED_PUSH_() #if GTEST_HAS_STREAM_REDIRECTION // Object that captures an output stream (stdout/stderr). class CapturedStream { public: // The ctor redirects the stream to a temporary file. explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { # if GTEST_OS_WINDOWS char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); const UINT success = ::GetTempFileNameA(temp_dir_path, "gtest_redir", 0, // Generate unique file name. temp_file_path); GTEST_CHECK_(success != 0) << "Unable to create a temporary file in " << temp_dir_path; const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " << temp_file_path; filename_ = temp_file_path; # else // There's no guarantee that a test has write access to the current // directory, so we create the temporary file in the /tmp directory // instead. We use /tmp on most systems, and /sdcard on Android. // That's because Android doesn't have /tmp. # if GTEST_OS_LINUX_ANDROID // Note: Android applications are expected to call the framework's // Context.getExternalStorageDirectory() method through JNI to get // the location of the world-writable SD Card directory. However, // this requires a Context handle, which cannot be retrieved // globally from native code. Doing so also precludes running the // code as part of a regular standalone executable, which doesn't // run in a Dalvik process (e.g. when running it through 'adb shell'). // // The location /data/local/tmp is directly accessible from native code. // '/sdcard' and other variants cannot be relied on, as they are not // guaranteed to be mounted, or may have a delay in mounting. char name_template[] = "/data/local/tmp/gtest_captured_stream.XXXXXX"; # else char name_template[] = "/tmp/captured_stream.XXXXXX"; # endif // GTEST_OS_LINUX_ANDROID const int captured_fd = mkstemp(name_template); if (captured_fd == -1) { GTEST_LOG_(WARNING) << "Failed to create tmp file " << name_template << " for test; does the test have access to the /tmp directory?"; } filename_ = name_template; # endif // GTEST_OS_WINDOWS fflush(nullptr); dup2(captured_fd, fd_); close(captured_fd); } ~CapturedStream() { remove(filename_.c_str()); } std::string GetCapturedString() { if (uncaptured_fd_ != -1) { // Restores the original stream. fflush(nullptr); dup2(uncaptured_fd_, fd_); close(uncaptured_fd_); uncaptured_fd_ = -1; } FILE* const file = posix::FOpen(filename_.c_str(), "r"); if (file == nullptr) { GTEST_LOG_(FATAL) << "Failed to open tmp file " << filename_ << " for capturing stream."; } const std::string content = ReadEntireFile(file); posix::FClose(file); return content; } private: const int fd_; // A stream to capture. int uncaptured_fd_; // Name of the temporary file holding the stderr output. ::std::string filename_; GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); }; GTEST_DISABLE_MSC_DEPRECATED_POP_() static CapturedStream* g_captured_stderr = nullptr; static CapturedStream* g_captured_stdout = nullptr; // Starts capturing an output stream (stdout/stderr). static void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { if (*stream != nullptr) { GTEST_LOG_(FATAL) << "Only one " << stream_name << " capturer can exist at a time."; } *stream = new CapturedStream(fd); } // Stops capturing the output stream and returns the captured string. static std::string GetCapturedStream(CapturedStream** captured_stream) { const std::string content = (*captured_stream)->GetCapturedString(); delete *captured_stream; *captured_stream = nullptr; return content; } // Starts capturing stdout. void CaptureStdout() { CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); } // Starts capturing stderr. void CaptureStderr() { CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); } // Stops capturing stdout and returns the captured string. std::string GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } // Stops capturing stderr and returns the captured string. std::string GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } #endif // GTEST_HAS_STREAM_REDIRECTION size_t GetFileSize(FILE* file) { fseek(file, 0, SEEK_END); return static_cast(ftell(file)); } std::string ReadEntireFile(FILE* file) { const size_t file_size = GetFileSize(file); char* const buffer = new char[file_size]; size_t bytes_last_read = 0; // # of bytes read in the last fread() size_t bytes_read = 0; // # of bytes read so far fseek(file, 0, SEEK_SET); // Keeps reading the file until we cannot read further or the // pre-determined file size is reached. do { bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); bytes_read += bytes_last_read; } while (bytes_last_read > 0 && bytes_read < file_size); const std::string content(buffer, bytes_read); delete[] buffer; return content; } #if GTEST_HAS_DEATH_TEST static const std::vector* g_injected_test_argvs = nullptr; // Owned. std::vector GetInjectableArgvs() { if (g_injected_test_argvs != nullptr) { return *g_injected_test_argvs; } return GetArgvs(); } void SetInjectableArgvs(const std::vector* new_argvs) { if (g_injected_test_argvs != new_argvs) delete g_injected_test_argvs; g_injected_test_argvs = new_argvs; } void SetInjectableArgvs(const std::vector& new_argvs) { SetInjectableArgvs( new std::vector(new_argvs.begin(), new_argvs.end())); } void ClearInjectableArgvs() { delete g_injected_test_argvs; g_injected_test_argvs = nullptr; } #endif // GTEST_HAS_DEATH_TEST #if GTEST_OS_WINDOWS_MOBILE namespace posix { void Abort() { DebugBreak(); TerminateProcess(GetCurrentProcess(), 1); } } // namespace posix #endif // GTEST_OS_WINDOWS_MOBILE // Returns the name of the environment variable corresponding to the // given flag. For example, FlagToEnvVar("foo") will return // "GTEST_FOO" in the open-source version. static std::string FlagToEnvVar(const char* flag) { const std::string full_flag = (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); Message env_var; for (size_t i = 0; i != full_flag.length(); i++) { env_var << ToUpper(full_flag.c_str()[i]); } return env_var.GetString(); } // Parses 'str' for a 32-bit signed integer. If successful, writes // the result to *value and returns true; otherwise leaves *value // unchanged and returns false. bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // Parses the environment variable as a decimal integer. char* end = nullptr; const long long_value = strtol(str, &end, 10); // NOLINT // Has strtol() consumed all characters in the string? if (*end != '\0') { // No - an invalid character was encountered. Message msg; msg << "WARNING: " << src_text << " is expected to be a 32-bit integer, but actually" << " has value \"" << str << "\".\n"; printf("%s", msg.GetString().c_str()); fflush(stdout); return false; } // Is the parsed value in the range of an Int32? const Int32 result = static_cast(long_value); if (long_value == LONG_MAX || long_value == LONG_MIN || // The parsed value overflows as a long. (strtol() returns // LONG_MAX or LONG_MIN when the input overflows.) result != long_value // The parsed value overflows as an Int32. ) { Message msg; msg << "WARNING: " << src_text << " is expected to be a 32-bit integer, but actually" << " has value " << str << ", which overflows.\n"; printf("%s", msg.GetString().c_str()); fflush(stdout); return false; } *value = result; return true; } // Reads and returns the Boolean environment variable corresponding to // the given flag; if it's not set, returns default_value. // // The value is considered true if and only if it's not "0". bool BoolFromGTestEnv(const char* flag, bool default_value) { #if defined(GTEST_GET_BOOL_FROM_ENV_) return GTEST_GET_BOOL_FROM_ENV_(flag, default_value); #else const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); return string_value == nullptr ? default_value : strcmp(string_value, "0") != 0; #endif // defined(GTEST_GET_BOOL_FROM_ENV_) } // Reads and returns a 32-bit integer stored in the environment // variable corresponding to the given flag; if it isn't set or // doesn't represent a valid 32-bit integer, returns default_value. Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { #if defined(GTEST_GET_INT32_FROM_ENV_) return GTEST_GET_INT32_FROM_ENV_(flag, default_value); #else const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); if (string_value == nullptr) { // The environment variable is not set. return default_value; } Int32 result = default_value; if (!ParseInt32(Message() << "Environment variable " << env_var, string_value, &result)) { printf("The default value %s is used.\n", (Message() << default_value).GetString().c_str()); fflush(stdout); return default_value; } return result; #endif // defined(GTEST_GET_INT32_FROM_ENV_) } // As a special case for the 'output' flag, if GTEST_OUTPUT is not // set, we look for XML_OUTPUT_FILE, which is set by the Bazel build // system. The value of XML_OUTPUT_FILE is a filename without the // "xml:" prefix of GTEST_OUTPUT. // Note that this is meant to be called at the call site so it does // not check that the flag is 'output' // In essence this checks an env variable called XML_OUTPUT_FILE // and if it is set we prepend "xml:" to its value, if it not set we return "" std::string OutputFlagAlsoCheckEnvVar(){ std::string default_value_for_output_flag = ""; const char* xml_output_file_env = posix::GetEnv("XML_OUTPUT_FILE"); if (nullptr != xml_output_file_env) { default_value_for_output_flag = std::string("xml:") + xml_output_file_env; } return default_value_for_output_flag; } // Reads and returns the string environment variable corresponding to // the given flag; if it's not set, returns default_value. const char* StringFromGTestEnv(const char* flag, const char* default_value) { #if defined(GTEST_GET_STRING_FROM_ENV_) return GTEST_GET_STRING_FROM_ENV_(flag, default_value); #else const std::string env_var = FlagToEnvVar(flag); const char* const value = posix::GetEnv(env_var.c_str()); return value == nullptr ? default_value : value; #endif // defined(GTEST_GET_STRING_FROM_ENV_) } } // namespace internal } // namespace testing openzwave-1.6.1914/cpp/test/src/gtest-printers.cc0000644000175200017520000003456714032142455016570 00000000000000// Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Google Test - The Google C++ Testing and Mocking Framework // // This file implements a universal value printer that can print a // value of any type T: // // void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); // // It uses the << operator when possible, and prints the bytes in the // object otherwise. A user can override its behavior for a class // type Foo by defining either operator<<(::std::ostream&, const Foo&) // or void PrintTo(const Foo&, ::std::ostream*) in the namespace that // defines Foo. #include "gtest/gtest-printers.h" #include #include #include #include // NOLINT #include #include "gtest/internal/gtest-port.h" #include "src/gtest-internal-inl.h" namespace testing { namespace { using ::std::ostream; // Prints a segment of bytes in the given object. GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, size_t count, ostream* os) { char text[5] = ""; for (size_t i = 0; i != count; i++) { const size_t j = start + i; if (i != 0) { // Organizes the bytes into groups of 2 for easy parsing by // human. if ((j % 2) == 0) *os << ' '; else *os << '-'; } GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]); *os << text; } } // Prints the bytes in the given value to the given ostream. void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, ostream* os) { // Tells the user how big the object is. *os << count << "-byte object <"; const size_t kThreshold = 132; const size_t kChunkSize = 64; // If the object size is bigger than kThreshold, we'll have to omit // some details by printing only the first and the last kChunkSize // bytes. if (count < kThreshold) { PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); } else { PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); *os << " ... "; // Rounds up to 2-byte boundary. const size_t resume_pos = (count - kChunkSize + 1)/2*2; PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); } *os << ">"; } } // namespace namespace internal2 { // Delegates to PrintBytesInObjectToImpl() to print the bytes in the // given object. The delegation simplifies the implementation, which // uses the << operator and thus is easier done outside of the // ::testing::internal namespace, which contains a << operator that // sometimes conflicts with the one in STL. void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, ostream* os) { PrintBytesInObjectToImpl(obj_bytes, count, os); } } // namespace internal2 namespace internal { // Depending on the value of a char (or wchar_t), we print it in one // of three formats: // - as is if it's a printable ASCII (e.g. 'a', '2', ' '), // - as a hexadecimal escape sequence (e.g. '\x7F'), or // - as a special escape sequence (e.g. '\r', '\n'). enum CharFormat { kAsIs, kHexEscape, kSpecialEscape }; // Returns true if c is a printable ASCII character. We test the // value of c directly instead of calling isprint(), which is buggy on // Windows Mobile. inline bool IsPrintableAscii(wchar_t c) { return 0x20 <= c && c <= 0x7E; } // Prints a wide or narrow char c as a character literal without the // quotes, escaping it when necessary; returns how c was formatted. // The template argument UnsignedChar is the unsigned version of Char, // which is the type of c. template static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { wchar_t w_c = static_cast(c); switch (w_c) { case L'\0': *os << "\\0"; break; case L'\'': *os << "\\'"; break; case L'\\': *os << "\\\\"; break; case L'\a': *os << "\\a"; break; case L'\b': *os << "\\b"; break; case L'\f': *os << "\\f"; break; case L'\n': *os << "\\n"; break; case L'\r': *os << "\\r"; break; case L'\t': *os << "\\t"; break; case L'\v': *os << "\\v"; break; default: if (IsPrintableAscii(w_c)) { *os << static_cast(c); return kAsIs; } else { ostream::fmtflags flags = os->flags(); *os << "\\x" << std::hex << std::uppercase << static_cast(static_cast(c)); os->flags(flags); return kHexEscape; } } return kSpecialEscape; } // Prints a wchar_t c as if it's part of a string literal, escaping it when // necessary; returns how c was formatted. static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) { switch (c) { case L'\'': *os << "'"; return kAsIs; case L'"': *os << "\\\""; return kSpecialEscape; default: return PrintAsCharLiteralTo(c, os); } } // Prints a char c as if it's part of a string literal, escaping it when // necessary; returns how c was formatted. static CharFormat PrintAsStringLiteralTo(char c, ostream* os) { return PrintAsStringLiteralTo( static_cast(static_cast(c)), os); } // Prints a wide or narrow character c and its code. '\0' is printed // as "'\\0'", other unprintable characters are also properly escaped // using the standard C++ escape sequence. The template argument // UnsignedChar is the unsigned version of Char, which is the type of c. template void PrintCharAndCodeTo(Char c, ostream* os) { // First, print c as a literal in the most readable form we can find. *os << ((sizeof(c) > 1) ? "L'" : "'"); const CharFormat format = PrintAsCharLiteralTo(c, os); *os << "'"; // To aid user debugging, we also print c's code in decimal, unless // it's 0 (in which case c was printed as '\\0', making the code // obvious). if (c == 0) return; *os << " (" << static_cast(c); // For more convenience, we print c's code again in hexadecimal, // unless c was already printed in the form '\x##' or the code is in // [1, 9]. if (format == kHexEscape || (1 <= c && c <= 9)) { // Do nothing. } else { *os << ", 0x" << String::FormatHexInt(static_cast(c)); } *os << ")"; } void PrintTo(unsigned char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); } void PrintTo(signed char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); } // Prints a wchar_t as a symbol if it is printable or as its internal // code otherwise and also as its code. L'\0' is printed as "L'\\0'". void PrintTo(wchar_t wc, ostream* os) { PrintCharAndCodeTo(wc, os); } // Prints the given array of characters to the ostream. CharType must be either // char or wchar_t. // The array starts at begin, the length is len, it may include '\0' characters // and may not be NUL-terminated. template GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static CharFormat PrintCharsAsStringTo( const CharType* begin, size_t len, ostream* os) { const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; *os << kQuoteBegin; bool is_previous_hex = false; CharFormat print_format = kAsIs; for (size_t index = 0; index < len; ++index) { const CharType cur = begin[index]; if (is_previous_hex && IsXDigit(cur)) { // Previous character is of '\x..' form and this character can be // interpreted as another hexadecimal digit in its number. Break string to // disambiguate. *os << "\" " << kQuoteBegin; } is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; // Remember if any characters required hex escaping. if (is_previous_hex) { print_format = kHexEscape; } } *os << "\""; return print_format; } // Prints a (const) char/wchar_t array of 'len' elements, starting at address // 'begin'. CharType must be either char or wchar_t. template GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static void UniversalPrintCharArray( const CharType* begin, size_t len, ostream* os) { // The code // const char kFoo[] = "foo"; // generates an array of 4, not 3, elements, with the last one being '\0'. // // Therefore when printing a char array, we don't print the last element if // it's '\0', such that the output matches the string literal as it's // written in the source code. if (len > 0 && begin[len - 1] == '\0') { PrintCharsAsStringTo(begin, len - 1, os); return; } // If, however, the last element in the array is not '\0', e.g. // const char kFoo[] = { 'f', 'o', 'o' }; // we must print the entire array. We also print a message to indicate // that the array is not NUL-terminated. PrintCharsAsStringTo(begin, len, os); *os << " (no terminating NUL)"; } // Prints a (const) char array of 'len' elements, starting at address 'begin'. void UniversalPrintArray(const char* begin, size_t len, ostream* os) { UniversalPrintCharArray(begin, len, os); } // Prints a (const) wchar_t array of 'len' elements, starting at address // 'begin'. void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { UniversalPrintCharArray(begin, len, os); } // Prints the given C string to the ostream. void PrintTo(const char* s, ostream* os) { if (s == nullptr) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; PrintCharsAsStringTo(s, strlen(s), os); } } // MSVC compiler can be configured to define whar_t as a typedef // of unsigned short. Defining an overload for const wchar_t* in that case // would cause pointers to unsigned shorts be printed as wide strings, // possibly accessing more memory than intended and causing invalid // memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when // wchar_t is implemented as a native type. #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // Prints the given wide C string to the ostream. void PrintTo(const wchar_t* s, ostream* os) { if (s == nullptr) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; PrintCharsAsStringTo(s, wcslen(s), os); } } #endif // wchar_t is native namespace { bool ContainsUnprintableControlCodes(const char* str, size_t length) { const unsigned char *s = reinterpret_cast(str); for (size_t i = 0; i < length; i++) { unsigned char ch = *s++; if (std::iscntrl(ch)) { switch (ch) { case '\t': case '\n': case '\r': break; default: return true; } } } return false; } bool IsUTF8TrailByte(unsigned char t) { return 0x80 <= t && t<= 0xbf; } bool IsValidUTF8(const char* str, size_t length) { const unsigned char *s = reinterpret_cast(str); for (size_t i = 0; i < length;) { unsigned char lead = s[i++]; if (lead <= 0x7f) { continue; // single-byte character (ASCII) 0..7F } if (lead < 0xc2) { return false; // trail byte or non-shortest form } else if (lead <= 0xdf && (i + 1) <= length && IsUTF8TrailByte(s[i])) { ++i; // 2-byte character } else if (0xe0 <= lead && lead <= 0xef && (i + 2) <= length && IsUTF8TrailByte(s[i]) && IsUTF8TrailByte(s[i + 1]) && // check for non-shortest form and surrogate (lead != 0xe0 || s[i] >= 0xa0) && (lead != 0xed || s[i] < 0xa0)) { i += 2; // 3-byte character } else if (0xf0 <= lead && lead <= 0xf4 && (i + 3) <= length && IsUTF8TrailByte(s[i]) && IsUTF8TrailByte(s[i + 1]) && IsUTF8TrailByte(s[i + 2]) && // check for non-shortest form (lead != 0xf0 || s[i] >= 0x90) && (lead != 0xf4 || s[i] < 0x90)) { i += 3; // 4-byte character } else { return false; } } return true; } void ConditionalPrintAsText(const char* str, size_t length, ostream* os) { if (!ContainsUnprintableControlCodes(str, length) && IsValidUTF8(str, length)) { *os << "\n As Text: \"" << str << "\""; } } } // anonymous namespace void PrintStringTo(const ::std::string& s, ostream* os) { if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { if (GTEST_FLAG(print_utf8)) { ConditionalPrintAsText(s.data(), s.size(), os); } } } #if GTEST_HAS_STD_WSTRING void PrintWideStringTo(const ::std::wstring& s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif // GTEST_HAS_STD_WSTRING } // namespace internal } // namespace testing openzwave-1.6.1914/cpp/test/ValueID_test.cpp0000644000175200017520000001320414032142455015515 00000000000000//----------------------------------------------------------------------------- // // ValueID_test.cpp // // Test Framework for ValueID's // // Copyright (c) 2017 Justin Hammond // // SOFTWARE NOTICE AND LICENSE // // This file is part of OpenZWave. // // OpenZWave is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // OpenZWave 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with OpenZWave. If not, see . // //----------------------------------------------------------------------------- #include "gtest/gtest.h" #include "value_classes/ValueID.h" extern uint16_t ozw_vers_major; extern uint16_t ozw_vers_minor; extern uint16_t ozw_vers_revision; namespace OpenZWave { namespace Testing { TEST(OpenZWave, Version) { EXPECT_EQ(ozw_vers_major, 1); EXPECT_EQ(ozw_vers_minor, 6); // Allow ozw_vers_revision to be zero, to avoid build server failure: // "ValueID_test.cpp:42: Failure" // "Expected: (ozw_vers_revision) >= (900), actual: 0 vs 900 [ FAILED ] OpenZWave.Version (0 ms)"" if (ozw_vers_revision != 0) { EXPECT_GE(ozw_vers_revision, 992); } } TEST(ValueID, Constructor) { ValueID *vid = new ValueID(0xFFFFu, 0x1, ValueID::ValueGenre_Basic, 0xCC, 0x02, 0x04, ValueID::ValueType_BitSet); EXPECT_EQ(vid->GetCommandClassId(), 0xCC); EXPECT_EQ(vid->GetGenre(), ValueID::ValueGenre_Basic); EXPECT_EQ(vid->GetHomeId(), 0xFFFFu); EXPECT_EQ(vid->GetIndex(), 0x04); EXPECT_EQ(vid->GetInstance(), 0x02); EXPECT_EQ(vid->GetNodeId(), 0x01); EXPECT_EQ(vid->GetType(), ValueID::ValueType_BitSet); EXPECT_EQ(vid->GetId(), 0x400000133002Au); delete vid; } TEST(ValueID, KeyConstructor) { // static cast needed to avoid: "call to constructor of 'OpenZWave::ValueID' is ambiguous" ValueID *vid = new ValueID(0xFFFFu, static_cast(0x400000133002Au)); EXPECT_EQ(vid->GetCommandClassId(), 0xCC); EXPECT_EQ(vid->GetGenre(), ValueID::ValueGenre_Basic); EXPECT_EQ(vid->GetHomeId(), 0xFFFFu); EXPECT_EQ(vid->GetIndex(), 0x04); EXPECT_EQ(vid->GetInstance(), 0x02); EXPECT_EQ(vid->GetNodeId(), 0x01); EXPECT_EQ(vid->GetType(), ValueID::ValueType_BitSet); delete vid; } TEST(ValueID, Comparision) { EXPECT_EQ( ValueID(0xFFFF, (uint64)0x400000133002A), ValueID(0xFFFF, 0x1, ValueID::ValueGenre_Basic, 0xCC, 0x02, 0x04, ValueID::ValueType_BitSet)); EXPECT_NE( ValueID(0xFFFF, (uint64)0x01), ValueID(0xFFFF, 0x1, ValueID::ValueGenre_Basic, 0xCC, 0x02, 0x04, ValueID::ValueType_BitSet)); } TEST(ValueID, GetStoreKey) { ValueID *vid1 = new ValueID(0xFFFFu, 0x1, ValueID::ValueGenre_Basic, 0xCC, 0x02, 0x04, ValueID::ValueType_BitSet); ValueID *vid2 = new ValueID(0xFFFFu, 0x1, ValueID::ValueGenre_Basic, 0x01, 0x01, 0x01, ValueID::ValueType_BitSet); ValueID *vid3 = new ValueID(0xFFFFu, 0x1, ValueID::ValueGenre_Basic, 0x80, 0x80, 0x80, ValueID::ValueType_BitSet); EXPECT_EQ(vid1->GetValueStoreKey(), ValueID::GetValueStoreKey(0xCC, 0x02, 0x04)); EXPECT_EQ(vid2->GetValueStoreKey(), ValueID::GetValueStoreKey(0x01, 0x01, 0x01)); EXPECT_EQ(vid3->GetValueStoreKey(), ValueID::GetValueStoreKey(0x80, 0x80, 0x80)); EXPECT_NE(vid1->GetValueStoreKey(), vid2->GetValueStoreKey()); EXPECT_NE(vid1->GetValueStoreKey(), vid3->GetValueStoreKey()); EXPECT_NE(vid2->GetValueStoreKey(), vid3->GetValueStoreKey()); // See if we've all three contributing parts (CC, instance and index) in the mix. EXPECT_NE(ValueID::GetValueStoreKey(0x80, 0x80, 0x80), ValueID::GetValueStoreKey(0x81, 0x80, 0x80)); EXPECT_NE(ValueID::GetValueStoreKey(0x80, 0x80, 0x80), ValueID::GetValueStoreKey(0x80, 0x81, 0x80)); EXPECT_NE(ValueID::GetValueStoreKey(0x80, 0x80, 0x80), ValueID::GetValueStoreKey(0x80, 0x80, 0x81)); ValueID *vid4 = new ValueID(0xFFFFu, 0x1, ValueID::ValueGenre_Basic, 0x81, 0x80, 0x80, ValueID::ValueType_BitSet); ValueID *vid5 = new ValueID(0xFFFFu, 0x1, ValueID::ValueGenre_Basic, 0x80, 0x81, 0x80, ValueID::ValueType_BitSet); ValueID *vid6 = new ValueID(0xFFFFu, 0x1, ValueID::ValueGenre_Basic, 0x80, 0x80, 0x81, ValueID::ValueType_BitSet); EXPECT_NE(vid3->GetValueStoreKey(), vid4->GetValueStoreKey()); EXPECT_NE(vid3->GetValueStoreKey(), vid5->GetValueStoreKey()); EXPECT_NE(vid3->GetValueStoreKey(), vid6->GetValueStoreKey()); EXPECT_NE(vid4->GetValueStoreKey(), vid5->GetValueStoreKey()); EXPECT_NE(vid4->GetValueStoreKey(), vid6->GetValueStoreKey()); EXPECT_NE(vid5->GetValueStoreKey(), vid6->GetValueStoreKey()); delete vid1; delete vid2; delete vid3; delete vid4; delete vid5; delete vid6; } TEST(ValueID, GetAsString) { EXPECT_EQ( ValueID(0xFFFF, static_cast(0x400000133002A)).GetAsString(), "HomeID: 0x0000ffff, ValueID: (Id 0x000400000133002a, NodeID 1, Genre basic, CC 0xcc, Instance 2, Index 4, Type bitset)"); EXPECT_EQ( ValueID(static_cast(0x1), 0x02, ValueID::ValueGenre_System, 0x04, 5, 6, ValueID::ValueType_String).GetAsString(), "HomeID: 0x00000001, ValueID: (Id 0x0006000002c10057, NodeID 2, Genre system, CC 0x04, Instance 5, Index 6, Type string)"); EXPECT_EQ( ValueID(static_cast(0xABCDEF01), static_cast(0x0123456789ABCDEF)).GetAsString(), "HomeID: 0xabcdef01, ValueID: (Id 0x0123456789abcdef, NodeID 137, Genre config, CC 0xaf, Instance 222, Index 291, Type invalid type)"); } } // namespace Testing } // namespace OpenZWaveopenzwave-1.6.1914/cpp/test/Makefile0000644000175200017520000000562414032142455014130 00000000000000# # Makefile for OpenzWave Mac OS X applications # Greg Satz # GNU make only # requires libudev-dev .SUFFIXES: .d .cpp .o .a .PHONY: default clean # 2019-10 added this test because there are path issues, hings go wrong when you try to run # "make" in the cpp/test subdirectory. One of the offending statements is "top_builddir ?= $(CURDIR)" # Needs some work to get a proper fix. ifeq ($(top_builddir),) $(error Variable top_builddir is undefined, please run "make" from root of OpenzWave repository only.) endif COMMON_FLAGS := -std=c++11 -Wall -Wno-unknown-pragmas -Wsign-compare DEBUG_CFLAGS := -ggdb -DDEBUG $(CPPFLAGS) $(COMMON_FLAGS) RELEASE_CFLAGS := -O3 $(CPPFLAGS) $(COMMON_FLAGS) DEBUG_LDFLAGS := -g top_srcdir := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))../../) #where is put the temporary library LIBDIR ?= $(top_builddir) INCLUDES := -I $(top_srcdir)/cpp/test/ -I $(top_srcdir)/cpp/test/include/ -I $(top_srcdir)/cpp/src -I $(top_srcdir)/cpp/tinyxml/ -I $(top_srcdir)/cpp/hidapi/hidapi/ OZW_LIB = $(wildcard $(LIBDIR)/*.a ) LIBS = $(OZW_LIB) ifneq ($(UNAME),FreeBSD) LIBS += -lresolv endif #LIBSDIR = $(abspath $(dir $(firstword $(LIBS)))) SOURCES := $(top_srcdir)/cpp/test/src/ $(top_srcdir)/cpp/test/ gtestsrc := $(notdir $(wildcard $(top_srcdir)/cpp/test/src/*.cc)) testsrc := $(notdir $(wildcard $(top_srcdir)/cpp/test/*.cpp)) VPATH := $(top_srcdir)/cpp/test/:$(top_srcdir)/cpp/test/src/ top_builddir ?= $(CURDIR) default: $(top_builddir)/gtest-main include $(top_srcdir)/cpp/build/support.mk -include $(patsubst %.cc,$(DEPDIR)/%.d,$(gtestsrc)) -include $(patsubst %.cpp,$(DEPDIR)/%.d,$(testsrc)) #if we are on a Mac, add these flags and libs to the compile and link phases ifeq ($(UNAME),Darwin) CFLAGS += -DDARWIN TARCH += -arch x86_64 endif # Dup from main makefile, but that is not included when building here.. ifeq ($(UNAME),FreeBSD) LDFLAGS+= -lusb ifeq ($(shell test $$(uname -U) -ge 1002000; echo $$?),1) ifeq (,$(wildcard /usr/local/include/iconv.h)) $(error FreeBSD pre 10.2: Please install libiconv from ports) else CFLAGS += -I/usr/local/include LDFLAGS+= -L/usr/local/lib -liconv endif endif endif $(OBJDIR)/%.o : %.cc @echo "Building $(notdir $@)" @$(CXX) -MM $(CFLAGS) $(INCLUDES) $< > $(DEPDIR)/$*.d @mv -f $(DEPDIR)/$*.d $(DEPDIR)/$*.d.tmp @$(SED) -e 's|.*:|$(OBJDIR)/$*.o: $(DEPDIR)/$*.d|' < $(DEPDIR)/$*.d.tmp > $(DEPDIR)/$*.d; @$(SED) -e 's/.*://' -e 's/\\$$//' < $(DEPDIR)/$*.d.tmp | fmt -1 | \ $(SED) -e 's/^ *//' -e 's/$$/:/' >> $(DEPDIR)/.$*.d; @rm -f $(DEPDIR)/$*.d.tmp @$(CXX) $(CFLAGS) $(TARCH) $(INCLUDES) -o $@ $< $(top_builddir)/gtest-main: $(patsubst %.cc,$(OBJDIR)/%.o,$(gtestsrc)) \ $(patsubst %.cpp,$(OBJDIR)/%.o,$(testsrc)) $(OZW_LIB) @echo "Linking $@" @$(LD) $(LDFLAGS) $(TARCH) -o $@ $+ $(LIBS) -pthread test: $(top_builddir)/gtest-main $(top_builddir)/gtest-main clean: @rm -rf $(DEPDIR) $(OBJDIR) $(top_builddir)/gtest-main .SUFFIXES: .d .cpp .cc .o .a openzwave-1.6.1914/cpp/tinyxml/0000777000175200017520000000000014032143201013260 500000000000000openzwave-1.6.1914/cpp/tinyxml/tinyxmlparser.cpp0000644000175200017520000011105614032142455016637 00000000000000/* www.sourceforge.net/projects/tinyxml Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include "tinyxml.h" //#define DEBUG_PARSER #if defined( DEBUG_PARSER ) # if defined( DEBUG ) && defined( _MSC_VER ) # include # define TIXML_LOG OutputDebugString # else # define TIXML_LOG printf # endif #endif // Note tha "PutString" hardcodes the same list. This // is less flexible than it appears. Changing the entries // or order will break putstring. TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = { { "&", 5, '&' }, { "<", 4, '<' }, { ">", 4, '>' }, { """, 6, '\"' }, { "'", 6, '\'' } }; // Bunch of unicode info at: // http://www.unicode.org/faq/utf_bom.html // Including the basic of this table, which determines the #bytes in the // sequence from the lead byte. 1 placed for invalid sequences -- // although the result will be junk, pass it through as much as possible. // Beware of the non-characters in UTF-8: // ef bb bf (Microsoft "lead bytes") // ef bf be // ef bf bf const unsigned char TIXML_UTF_LEAD_0 = 0xefU; const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; const int TiXmlBase::utf8ByteTable[256] = { // 0 1 2 3 4 5 6 7 8 9 a b c d e f 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid }; void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) { const unsigned long BYTE_MASK = 0xBF; const unsigned long BYTE_MARK = 0x80; const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; if (input < 0x80) *length = 1; else if ( input < 0x800 ) *length = 2; else if ( input < 0x10000 ) *length = 3; else if ( input < 0x200000 ) *length = 4; else { *length = 0; return; } // This code won't covert this correctly anyway. output += *length; // Scary scary fall throughs. switch (*length) { case 4: --output; *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 3: --output; *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 2: --output; *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 1: --output; *output = (char)(input | FIRST_BYTE_MARK[*length]); } } /*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) { // This will only work for low-ascii, everything else is assumed to be a valid // letter. I'm not sure this is the best approach, but it is quite tricky trying // to figure out alhabetical vs. not across encoding. So take a very // conservative approach. // if ( encoding == TIXML_ENCODING_UTF8 ) // { if ( anyByte < 127 ) return isalpha( anyByte ); else return 1; // What else to do? The unicode set is huge...get the english ones right. // } // else // { // return isalpha( anyByte ); // } } /*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) { // This will only work for low-ascii, everything else is assumed to be a valid // letter. I'm not sure this is the best approach, but it is quite tricky trying // to figure out alhabetical vs. not across encoding. So take a very // conservative approach. // if ( encoding == TIXML_ENCODING_UTF8 ) // { if ( anyByte < 127 ) return isalnum( anyByte ); else return 1; // What else to do? The unicode set is huge...get the english ones right. // } // else // { // return isalnum( anyByte ); // } } class TiXmlParsingData { friend class TiXmlDocument; public: void Stamp( const char* now, TiXmlEncoding encoding ); const TiXmlCursor& Cursor() { return cursor; } private: // Only used by the document! TiXmlParsingData( const char* start, int _tabsize, int row, int col ) { assert( start ); stamp = start; tabsize = _tabsize; cursor.row = row; cursor.col = col; } TiXmlCursor cursor; const char* stamp; int tabsize; }; void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) { assert( now ); // Do nothing if the tabsize is 0. if ( tabsize < 1 ) { return; } // Get the current row, column. int row = cursor.row; int col = cursor.col; const char* p = stamp; assert( p ); while ( p < now ) { // Treat p as unsigned, so we have a happy compiler. const unsigned char* pU = (const unsigned char*)p; // Code contributed by Fletcher Dunn: (modified by lee) switch (*pU) { case 0: // We *should* never get here, but in case we do, don't // advance past the terminating null character, ever return; case '\r': // bump down to the next line ++row; col = 0; // Eat the character ++p; // Check for \r\n sequence, and treat this as a single character if (*p == '\n') { ++p; } break; case '\n': // bump down to the next line ++row; col = 0; // Eat the character ++p; // Check for \n\r sequence, and treat this as a single // character. (Yes, this bizarre thing does occur still // on some arcane platforms...) if (*p == '\r') { ++p; } break; case '\t': // Eat the character ++p; // Skip to next tab stop col = (col / tabsize + 1) * tabsize; break; case TIXML_UTF_LEAD_0: if ( encoding == TIXML_ENCODING_UTF8 ) { if ( *(p+1) && *(p+2) ) { // In these cases, don't advance the column. These are // 0-width spaces. if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) p += 3; else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) p += 3; else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) p += 3; else { p +=3; ++col; } // A normal character. } } else { ++p; ++col; } break; default: if ( encoding == TIXML_ENCODING_UTF8 ) { // Eat the 1 to 4 byte utf8 character. int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; if ( step == 0 ) step = 1; // Error case from bad encoding, but handle gracefully. p += step; // Just advance one column, of course. ++col; } else { ++p; ++col; } break; } } cursor.row = row; cursor.col = col; assert( cursor.row >= -1 ); assert( cursor.col >= -1 ); stamp = p; assert( stamp ); } const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) { if ( !p || !*p ) { return 0; } if ( encoding == TIXML_ENCODING_UTF8 ) { while ( *p ) { const unsigned char* pU = (const unsigned char*)p; // Skip the stupid Microsoft UTF-8 Byte order marks if ( *(pU+0)==TIXML_UTF_LEAD_0 && *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) { p += 3; continue; } else if(*(pU+0)==TIXML_UTF_LEAD_0 && *(pU+1)==0xbfU && *(pU+2)==0xbeU ) { p += 3; continue; } else if(*(pU+0)==TIXML_UTF_LEAD_0 && *(pU+1)==0xbfU && *(pU+2)==0xbfU ) { p += 3; continue; } if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space. ++p; else break; } } else { while ( (*p) && ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) ) ++p; } return p; } #ifdef TIXML_USE_STL /*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) { for( ;; ) { if ( !in->good() ) return false; int c = in->peek(); // At this scope, we can't get to a document. So fail silently. if ( !IsWhiteSpace( c ) || c <= 0 ) return true; *tag += (char) in->get(); } } /*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) { //assert( character > 0 && character < 128 ); // else it won't work in utf-8 while ( in->good() ) { int c = in->peek(); if ( c == character ) return true; if ( c <= 0 ) // Silent failure: can't get document at this scope return false; in->get(); *tag += (char) c; } return false; } #endif // One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The // "assign" optimization removes over 10% of the execution time. // const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) { // Oddly, not supported on some comilers, //name->clear(); // So use this: *name = ""; assert( p ); // Names start with letters or underscores. // Of course, in unicode, tinyxml has no idea what a letter *is*. The // algorithm is generous. // // After that, they can be letters, underscores, numbers, // hyphens, or colons. (Colons are valid ony for namespaces, // but tinyxml can't tell namespaces from names.) if ( p && *p && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) { const char* start = p; while( p && *p && ( IsAlphaNum( (unsigned char ) *p, encoding ) || *p == '_' || *p == '-' || *p == '.' || *p == ':' ) ) { //(*name) += *p; // expensive ++p; } if ( p-start > 0 ) { name->assign( start, p-start ); } return p; } return 0; } const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) { // Presume an entity, and pull it out. TIXML_STRING ent; int i; *length = 0; if ( *(p+1) && *(p+1) == '#' && *(p+2) ) { unsigned long ucs = 0; ptrdiff_t delta = 0; unsigned mult = 1; if ( *(p+2) == 'x' ) { // Hexadecimal. if ( !*(p+3) ) return 0; const char* q = p+3; q = strchr( q, ';' ); if ( !q || !*q ) return 0; delta = q-p; --q; while ( *q != 'x' ) { if ( *q >= '0' && *q <= '9' ) ucs += mult * (*q - '0'); else if ( *q >= 'a' && *q <= 'f' ) ucs += mult * (*q - 'a' + 10); else if ( *q >= 'A' && *q <= 'F' ) ucs += mult * (*q - 'A' + 10 ); else return 0; mult *= 16; --q; } } else { // Decimal. if ( !*(p+2) ) return 0; const char* q = p+2; q = strchr( q, ';' ); if ( !q || !*q ) return 0; delta = q-p; --q; while ( *q != '#' ) { if ( *q >= '0' && *q <= '9' ) ucs += mult * (*q - '0'); else return 0; mult *= 10; --q; } } if ( encoding == TIXML_ENCODING_UTF8 ) { // convert the UCS to UTF-8 ConvertUTF32ToUTF8( ucs, value, length ); } else { *value = (char)ucs; *length = 1; } return p + delta + 1; } // Now try to match it. for( i=0; iappend( cArr, len ); } } else { bool whitespace = false; // Remove leading white space: p = SkipWhiteSpace( p, encoding ); while ( p && *p && !StringEqual( p, endTag, caseInsensitive, encoding ) ) { if ( *p == '\r' || *p == '\n' ) { whitespace = true; ++p; } else if ( IsWhiteSpace( *p ) ) { whitespace = true; ++p; } else { // If we've found whitespace, add it before the // new character. Any whitespace just becomes a space. if ( whitespace ) { (*text) += ' '; whitespace = false; } int len; char cArr[4] = { 0, 0, 0, 0 }; p = GetChar( p, cArr, &len, encoding ); if ( len == 1 ) (*text) += cArr[0]; // more efficient else text->append( cArr, len ); } } } if ( p ) p += strlen( endTag ); return p; } #ifdef TIXML_USE_STL void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) { // The basic issue with a document is that we don't know what we're // streaming. Read something presumed to be a tag (and hope), then // identify it, and call the appropriate stream method on the tag. // // This "pre-streaming" will never read the closing ">" so the // sub-tag can orient itself. if ( !StreamTo( in, '<', tag ) ) { SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } while ( in->good() ) { int tagIndex = (int) tag->length(); while ( in->good() && in->peek() != '>' ) { int c = in->get(); if ( c <= 0 ) { SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); break; } (*tag) += (char) c; } if ( in->good() ) { // We now have something we presume to be a node of // some sort. Identify it, and call the node to // continue streaming. TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); if ( node ) { node->StreamIn( in, tag ); bool isElement = node->ToElement() != 0; delete node; node = 0; // If this is the root element, we're done. Parsing will be // done by the >> operator. if ( isElement ) { return; } } else { SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } } } // We should have returned sooner. SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); } #endif const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) { ClearError(); // Parse away, at the document level. Since a document // contains nothing but other tags, most of what happens // here is skipping white space. if ( !p || !*p ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } // Note that, for a document, this needs to come // before the while space skip, so that parsing // starts from the pointer we are given. location.Clear(); if ( prevData ) { location.row = prevData->cursor.row; location.col = prevData->cursor.col; } else { location.row = 0; location.col = 0; } TiXmlParsingData data( p, TabSize(), location.row, location.col ); location = data.Cursor(); if ( encoding == TIXML_ENCODING_UNKNOWN ) { // Check for the Microsoft UTF-8 lead bytes. const unsigned char* pU = (const unsigned char*)p; if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) { encoding = TIXML_ENCODING_UTF8; useMicrosoftBOM = true; } } p = SkipWhiteSpace( p, encoding ); if ( !p ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } while ( p && *p ) { TiXmlNode* node = Identify( p, encoding ); if ( node ) { p = node->Parse( p, &data, encoding ); LinkEndChild( node ); } else { break; } // Did we get encoding info? if ( encoding == TIXML_ENCODING_UNKNOWN && node->ToDeclaration() ) { TiXmlDeclaration* dec = node->ToDeclaration(); const char* enc = dec->Encoding(); assert( enc ); if ( *enc == 0 ) encoding = TIXML_ENCODING_UTF8; else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) encoding = TIXML_ENCODING_UTF8; else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice else encoding = TIXML_ENCODING_LEGACY; } p = SkipWhiteSpace( p, encoding ); } // Was this empty? if ( !firstChild ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); return 0; } // All is well. return p; } void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) { // The first error in a chain is more accurate - don't set again! if ( error ) return; assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); error = true; errorId = err; errorDesc = errorString[ errorId ]; errorLocation.Clear(); if ( pError && data ) { data->Stamp( pError, encoding ); errorLocation = data->Cursor(); } } TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) { TiXmlNode* returnNode = 0; p = SkipWhiteSpace( p, encoding ); if( !p || !*p || *p != '<' ) { return 0; } TiXmlDocument* doc = GetDocument(); p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) { return 0; } // What is this thing? // - Elements start with a letter or underscore, but xml is reserved. // - Comments: "; if ( !StringEqual( p, startTag, false, encoding ) ) { document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); return 0; } p += strlen( startTag ); // [ 1475201 ] TinyXML parses entities in comments // Oops - ReadText doesn't work, because we don't want to parse the entities. // p = ReadText( p, &value, false, endTag, false, encoding ); // // from the XML spec: /* [Definition: Comments may appear anywhere in a document outside other markup; in addition, they may appear within the document type declaration at places allowed by the grammar. They are not part of the document's character data; an XML processor MAY, but need not, make it possible for an application to retrieve the text of comments. For compatibility, the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity references MUST NOT be recognized within comments. An example of a comment: */ value = ""; // Keep all the white space. while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) { value.append( p, 1 ); ++p; } if ( p ) p += strlen( endTag ); return p; } const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) { p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) return 0; // int tabsize = 4; // if ( document ) // tabsize = document->TabSize(); if ( data ) { data->Stamp( p, encoding ); location = data->Cursor(); } // Read the name, the '=' and the value. const char* pErr = p; p = ReadName( p, &name, encoding ); if ( !p || !*p ) { if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); return 0; } p = SkipWhiteSpace( p, encoding ); if ( !p || !*p || *p != '=' ) { if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); return 0; } ++p; // skip '=' p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) { if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); return 0; } const char* end; const char SINGLE_QUOTE = '\''; const char DOUBLE_QUOTE = '\"'; if ( *p == SINGLE_QUOTE ) { ++p; end = "\'"; // single quote in string p = ReadText( p, &value, false, end, false, encoding ); } else if ( *p == DOUBLE_QUOTE ) { ++p; end = "\""; // double quote in string p = ReadText( p, &value, false, end, false, encoding ); } else { // All attribute values should be in single or double quotes. // But this is such a common error that the parser will try // its best, even without them. value = ""; while ( p && *p // existence && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace && *p != '/' && *p != '>' ) // tag end { if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { // [ 1451649 ] Attribute values with trailing quotes not handled correctly // We did not have an opening quote but seem to have a // closing one. Give up and throw an error. if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); return 0; } value += *p; ++p; } } return p; } #ifdef TIXML_USE_STL void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) { while ( in->good() ) { int c = in->peek(); if ( !cdata && (c == '<' ) ) { return; } if ( c <= 0 ) { TiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } (*tag) += (char) c; in->get(); // "commits" the peek made above if ( cdata && c == '>' && tag->size() >= 3 ) { size_t len = tag->size(); if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { // terminator of cdata. return; } } } } #endif const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) { value = ""; TiXmlDocument* document = GetDocument(); if ( data ) { data->Stamp( p, encoding ); location = data->Cursor(); } const char* const startTag = ""; if ( cdata || StringEqual( p, startTag, false, encoding ) ) { cdata = true; if ( !StringEqual( p, startTag, false, encoding ) ) { document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); return 0; } p += strlen( startTag ); // Keep all the white space, ignore the encoding, etc. while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) { value += *p; ++p; } TIXML_STRING dummy; p = ReadText( p, &dummy, false, endTag, false, encoding ); return p; } else { bool ignoreWhite = true; const char* end = "<"; p = ReadText( p, &value, ignoreWhite, end, false, encoding ); if ( p ) return p-1; // don't truncate the '<' return 0; } } #ifdef TIXML_USE_STL void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) { while ( in->good() ) { int c = in->get(); if ( c <= 0 ) { TiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } (*tag) += (char) c; if ( c == '>' ) { // All is well. return; } } } #endif const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) { p = SkipWhiteSpace( p, _encoding ); // Find the beginning, find the end, and look for // the stuff in-between. TiXmlDocument* document = GetDocument(); if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); return 0; } if ( data ) { data->Stamp( p, _encoding ); location = data->Cursor(); } p += 5; version = ""; encoding = ""; standalone = ""; while ( p && *p ) { if ( *p == '>' ) { ++p; return p; } p = SkipWhiteSpace( p, _encoding ); if ( StringEqual( p, "version", true, _encoding ) ) { TiXmlAttribute attrib; p = attrib.Parse( p, data, _encoding ); version = attrib.Value(); } else if ( StringEqual( p, "encoding", true, _encoding ) ) { TiXmlAttribute attrib; p = attrib.Parse( p, data, _encoding ); encoding = attrib.Value(); } else if ( StringEqual( p, "standalone", true, _encoding ) ) { TiXmlAttribute attrib; p = attrib.Parse( p, data, _encoding ); standalone = attrib.Value(); } else { // Read over whatever it is. while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) ++p; } } return 0; } bool TiXmlText::Blank() const { for ( unsigned i=0; i(-1); // Null rep. TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; void TiXmlString::reserve (size_type cap) { if (cap > capacity()) { TiXmlString tmp; tmp.init(length(), cap); memcpy(tmp.start(), data(), length()); swap(tmp); } } TiXmlString& TiXmlString::assign(const char* str, size_type len) { size_type cap = capacity(); if (len > cap || cap > 3*(len + 8)) { TiXmlString tmp; tmp.init(len); memcpy(tmp.start(), str, len); swap(tmp); } else { memmove(start(), str, len); set_size(len); } return *this; } TiXmlString& TiXmlString::append(const char* str, size_type len) { size_type newsize = length() + len; if (newsize > capacity()) { reserve (newsize + capacity()); } memmove(finish(), str, len); set_size(newsize); return *this; } TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) { TiXmlString tmp; tmp.reserve(a.length() + b.length()); tmp += a; tmp += b; return tmp; } TiXmlString operator + (const TiXmlString & a, const char* b) { TiXmlString tmp; TiXmlString::size_type b_len = static_cast( strlen(b) ); tmp.reserve(a.length() + b_len); tmp += a; tmp.append(b, b_len); return tmp; } TiXmlString operator + (const char* a, const TiXmlString & b) { TiXmlString tmp; TiXmlString::size_type a_len = static_cast( strlen(a) ); tmp.reserve(a_len + b.length()); tmp.append(a, a_len); tmp += b; return tmp; } #endif // TIXML_USE_STL openzwave-1.6.1914/cpp/tinyxml/tinystr.h0000644000175200017520000002111114032142455015067 00000000000000/* www.sourceforge.net/projects/tinyxml Original file by Yves Berquin. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ /* * THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005. * * - completely rewritten. compact, clean, and fast implementation. * - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems) * - fixed reserve() to work as per specification. * - fixed buggy compares operator==(), operator<(), and operator>() * - fixed operator+=() to take a const ref argument, following spec. * - added "copy" constructor with length, and most compare operators. * - added swap(), clear(), size(), capacity(), operator+(). */ #ifndef TIXML_USE_STL #ifndef TIXML_STRING_INCLUDED #define TIXML_STRING_INCLUDED #include #include /* The support for explicit isn't that universal, and it isn't really required - it is used to check that the TiXmlString class isn't incorrectly used. Be nice to old compilers and macro it here: */ #if defined(_MSC_VER) && (_MSC_VER >= 1200 ) // Microsoft visual studio, version 6 and higher. #define TIXML_EXPLICIT explicit #elif defined(__GNUC__) && (__GNUC__ >= 3 ) // GCC version 3 and higher.s #define TIXML_EXPLICIT explicit #else #define TIXML_EXPLICIT #endif /* TiXmlString is an emulation of a subset of the std::string template. Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. Only the member functions relevant to the TinyXML project have been implemented. The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase a string and there's no more room, we allocate a buffer twice as big as we need. */ class TiXmlString { public : // The size type used typedef size_t size_type; // Error value for find primitive static const size_type npos; // = -1; // TiXmlString empty constructor TiXmlString () : rep_(&nullrep_) { } // TiXmlString copy constructor TiXmlString ( const TiXmlString & copy) : rep_(0) { init(copy.length()); memcpy(start(), copy.data(), length()); } // TiXmlString constructor, based on a string TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) { init( static_cast( strlen(copy) )); memcpy(start(), copy, length()); } // TiXmlString constructor, based on a string TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) { init(len); memcpy(start(), str, len); } // TiXmlString destructor ~TiXmlString () { quit(); } // = operator TiXmlString& operator = (const char * copy) { return assign( copy, (size_type)strlen(copy)); } // = operator TiXmlString& operator = (const TiXmlString & copy) { return assign(copy.start(), copy.length()); } // += operator. Maps to append TiXmlString& operator += (const char * suffix) { return append(suffix, static_cast( strlen(suffix) )); } // += operator. Maps to append TiXmlString& operator += (char single) { return append(&single, 1); } // += operator. Maps to append TiXmlString& operator += (const TiXmlString & suffix) { return append(suffix.data(), suffix.length()); } // Convert a TiXmlString into a null-terminated char * const char * c_str () const { return rep_->str; } // Convert a TiXmlString into a char * (need not be null terminated). const char * data () const { return rep_->str; } // Return the length of a TiXmlString size_type length () const { return rep_->size; } // Alias for length() size_type size () const { return rep_->size; } // Checks if a TiXmlString is empty bool empty () const { return rep_->size == 0; } // Return capacity of string size_type capacity () const { return rep_->capacity; } // single char extraction const char& at (size_type index) const { assert( index < length() ); return rep_->str[ index ]; } // [] operator char& operator [] (size_type index) const { assert( index < length() ); return rep_->str[ index ]; } // find a char in a string. Return TiXmlString::npos if not found size_type find (char lookup) const { return find(lookup, 0); } // find a char in a string from an offset. Return TiXmlString::npos if not found size_type find (char tofind, size_type offset) const { if (offset >= length()) return npos; for (const char* p = c_str() + offset; *p != '\0'; ++p) { if (*p == tofind) return static_cast< size_type >( p - c_str() ); } return npos; } void clear () { //Lee: //The original was just too strange, though correct: // TiXmlString().swap(*this); //Instead use the quit & re-init: quit(); init(0,0); } /* Function to reserve a big amount of data when we know we'll need it. Be aware that this function DOES NOT clear the content of the TiXmlString if any exists. */ void reserve (size_type cap); TiXmlString& assign (const char* str, size_type len); TiXmlString& append (const char* str, size_type len); void swap (TiXmlString& other) { Rep* r = rep_; rep_ = other.rep_; other.rep_ = r; } private: void init(size_type sz) { init(sz, sz); } void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } char* start() const { return rep_->str; } char* finish() const { return rep_->str + rep_->size; } struct Rep { size_type size, capacity; char str[1]; }; void init(size_type sz, size_type cap) { if (cap) { // Lee: the original form: // rep_ = static_cast(operator new(sizeof(Rep) + cap)); // doesn't work in some cases of new being overloaded. Switching // to the normal allocation, although use an 'int' for systems // that are overly picky about structure alignment. const size_type bytesNeeded = sizeof(Rep) + cap; const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); rep_ = reinterpret_cast( new int[ intsNeeded ] ); rep_->str[ rep_->size = sz ] = '\0'; rep_->capacity = cap; } else { rep_ = &nullrep_; } } void quit() { if (rep_ != &nullrep_) { // The rep_ is really an array of ints. (see the allocator, above). // Cast it back before delete, so the compiler won't incorrectly call destructors. delete [] ( reinterpret_cast( rep_ ) ); } } Rep * rep_; static Rep nullrep_; } ; inline bool operator == (const TiXmlString & a, const TiXmlString & b) { return ( a.length() == b.length() ) // optimization on some platforms && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare } inline bool operator < (const TiXmlString & a, const TiXmlString & b) { return strcmp(a.c_str(), b.c_str()) < 0; } inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); TiXmlString operator + (const TiXmlString & a, const char* b); TiXmlString operator + (const char* a, const TiXmlString & b); /* TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. Only the operators that we need for TinyXML have been developped. */ class TiXmlOutStream : public TiXmlString { public : // TiXmlOutStream << operator. TiXmlOutStream & operator << (const TiXmlString & in) { *this += in; return *this; } // TiXmlOutStream << operator. TiXmlOutStream & operator << (const char * in) { *this += in; return *this; } } ; #endif // TIXML_STRING_INCLUDED #endif // TIXML_USE_STL openzwave-1.6.1914/cpp/tinyxml/tinyxml.cpp0000644000175200017520000011036514032142455015424 00000000000000/* www.sourceforge.net/projects/tinyxml Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include #ifdef TIXML_USE_STL #include #include #endif #include #include "tinyxml.h" bool TiXmlBase::condenseWhiteSpace = true; // Microsoft compiler security FILE* TiXmlFOpen( const char* filename, const char* mode ) { #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) FILE* fp = 0; errno_t err = fopen_s( &fp, filename, mode ); if ( !err && fp ) return fp; return 0; #else return fopen( filename, mode ); #endif } void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString ) { int i=0; while( i<(int)str.length() ) { unsigned char c = (unsigned char) str[i]; if ( c == '&' && i < ( (int)str.length() - 2 ) && str[i+1] == '#' && str[i+2] == 'x' ) { // Hexadecimal character reference. // Pass through unchanged. // © -- copyright symbol, for example. // // The -1 is a bug fix from Rob Laveaux. It keeps // an overflow from happening if there is no ';'. // There are actually 2 ways to exit this loop - // while fails (error case) and break (semicolon found). // However, there is no mechanism (currently) for // this function to return an error. while ( i<(int)str.length()-1 ) { outString->append( str.c_str() + i, 1 ); ++i; if ( str[i] == ';' ) break; } } else if ( c == '&' ) { outString->append( entity[0].str, entity[0].strLength ); ++i; } else if ( c == '<' ) { outString->append( entity[1].str, entity[1].strLength ); ++i; } else if ( c == '>' ) { outString->append( entity[2].str, entity[2].strLength ); ++i; } else if ( c == '\"' ) { outString->append( entity[3].str, entity[3].strLength ); ++i; } else if ( c == '\'' ) { outString->append( entity[4].str, entity[4].strLength ); ++i; } else if ( c < 32 ) { // Easy pass at non-alpha/numeric/symbol // Below 32 is symbolic. char buf[ 32 ]; #if defined(TIXML_SNPRINTF) TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); #else sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); #endif //*ME: warning C4267: convert 'size_t' to 'int' //*ME: Int-Cast to make compiler happy ... outString->append( buf, (int)strlen( buf ) ); ++i; } else { //char realc = (char) c; //outString->append( &realc, 1 ); *outString += (char) c; // somewhat more efficient function call. ++i; } } } TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() { parent = 0; type = _type; firstChild = 0; lastChild = 0; prev = 0; next = 0; } TiXmlNode::~TiXmlNode() { TiXmlNode* node = firstChild; TiXmlNode* temp = 0; while ( node ) { temp = node; node = node->next; delete temp; } } void TiXmlNode::CopyTo( TiXmlNode* target ) const { target->SetValue (value.c_str() ); target->userData = userData; } void TiXmlNode::Clear() { TiXmlNode* node = firstChild; TiXmlNode* temp = 0; while ( node ) { temp = node; node = node->next; delete temp; } firstChild = 0; lastChild = 0; } TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) { assert( node->parent == 0 || node->parent == this ); assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); if ( node->Type() == TiXmlNode::DOCUMENT ) { delete node; if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } node->parent = this; node->prev = lastChild; node->next = 0; if ( lastChild ) lastChild->next = node; else firstChild = node; // it was an empty list. lastChild = node; return node; } TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) { if ( addThis.Type() == TiXmlNode::DOCUMENT ) { if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = addThis.Clone(); if ( !node ) return 0; return LinkEndChild( node ); } TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) { if ( !beforeThis || beforeThis->parent != this ) { return 0; } if ( addThis.Type() == TiXmlNode::DOCUMENT ) { if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = addThis.Clone(); if ( !node ) return 0; node->parent = this; node->next = beforeThis; node->prev = beforeThis->prev; if ( beforeThis->prev ) { beforeThis->prev->next = node; } else { assert( firstChild == beforeThis ); firstChild = node; } beforeThis->prev = node; return node; } TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) { if ( !afterThis || afterThis->parent != this ) { return 0; } if ( addThis.Type() == TiXmlNode::DOCUMENT ) { if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = addThis.Clone(); if ( !node ) return 0; node->parent = this; node->prev = afterThis; node->next = afterThis->next; if ( afterThis->next ) { afterThis->next->prev = node; } else { assert( lastChild == afterThis ); lastChild = node; } afterThis->next = node; return node; } TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) { if ( replaceThis->parent != this ) return 0; TiXmlNode* node = withThis.Clone(); if ( !node ) return 0; node->next = replaceThis->next; node->prev = replaceThis->prev; if ( replaceThis->next ) replaceThis->next->prev = node; else lastChild = node; if ( replaceThis->prev ) replaceThis->prev->next = node; else firstChild = node; delete replaceThis; node->parent = this; return node; } bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) { if ( removeThis->parent != this ) { assert( 0 ); return false; } if ( removeThis->next ) removeThis->next->prev = removeThis->prev; else lastChild = removeThis->prev; if ( removeThis->prev ) removeThis->prev->next = removeThis->next; else firstChild = removeThis->next; delete removeThis; return true; } const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const { const TiXmlNode* node; for ( node = firstChild; node; node = node->next ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const { const TiXmlNode* node; for ( node = lastChild; node; node = node->prev ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const { if ( !previous ) { return FirstChild(); } else { assert( previous->parent == this ); return previous->NextSibling(); } } const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const { if ( !previous ) { return FirstChild( val ); } else { assert( previous->parent == this ); return previous->NextSibling( val ); } } const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const { const TiXmlNode* node; for ( node = next; node; node = node->next ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const { const TiXmlNode* node; for ( node = prev; node; node = node->prev ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } void TiXmlElement::RemoveAttribute( const char * name ) { #ifdef TIXML_USE_STL TIXML_STRING str( name ); TiXmlAttribute* node = attributeSet.Find( str ); #else TiXmlAttribute* node = attributeSet.Find( name ); #endif if ( node ) { attributeSet.Remove( node ); delete node; } } const TiXmlElement* TiXmlNode::FirstChildElement() const { const TiXmlNode* node; for ( node = FirstChild(); node; node = node->NextSibling() ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const { const TiXmlNode* node; for ( node = FirstChild( _value ); node; node = node->NextSibling( _value ) ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlElement* TiXmlNode::NextSiblingElement() const { const TiXmlNode* node; for ( node = NextSibling(); node; node = node->NextSibling() ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const { const TiXmlNode* node; for ( node = NextSibling( _value ); node; node = node->NextSibling( _value ) ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlDocument* TiXmlNode::GetDocument() const { const TiXmlNode* node; for( node = this; node; node = node->parent ) { if ( node->ToDocument() ) return node->ToDocument(); } return 0; } TiXmlElement::TiXmlElement (const char * _value) : TiXmlNode( TiXmlNode::ELEMENT ) { firstChild = lastChild = 0; value = _value; } #ifdef TIXML_USE_STL TiXmlElement::TiXmlElement( const std::string& _value ) : TiXmlNode( TiXmlNode::ELEMENT ) { firstChild = lastChild = 0; value = _value; } #endif TiXmlElement::TiXmlElement( const TiXmlElement& copy) : TiXmlNode( TiXmlNode::ELEMENT ) { firstChild = lastChild = 0; copy.CopyTo( this ); } void TiXmlElement::operator=( const TiXmlElement& base ) { ClearThis(); base.CopyTo( this ); } TiXmlElement::~TiXmlElement() { ClearThis(); } void TiXmlElement::ClearThis() { Clear(); while( attributeSet.First() ) { TiXmlAttribute* node = attributeSet.First(); attributeSet.Remove( node ); delete node; } } const char* TiXmlElement::Attribute( const char* name ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( node ) return node->Value(); return 0; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( node ) return &node->ValueStr(); return 0; } #endif const char* TiXmlElement::Attribute( const char* name, int* i ) const { const char* s = Attribute( name ); if ( i ) { if ( s ) { *i = atoi( s ); } else { *i = 0; } } return s; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const { const std::string* s = Attribute( name ); if ( i ) { if ( s ) { *i = atoi( s->c_str() ); } else { *i = 0; } } return s; } #endif const char* TiXmlElement::Attribute( const char* name, double* d ) const { const char* s = Attribute( name ); if ( d ) { if ( s ) { *d = atof( s ); } else { *d = 0; } } return s; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const { const std::string* s = Attribute( name ); if ( d ) { if ( s ) { *d = atof( s->c_str() ); } else { *d = 0; } } return s; } #endif int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; return node->QueryIntValue( ival ); } #ifdef TIXML_USE_STL int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; return node->QueryIntValue( ival ); } #endif int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; return node->QueryDoubleValue( dval ); } #ifdef TIXML_USE_STL int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; return node->QueryDoubleValue( dval ); } #endif void TiXmlElement::SetAttribute( const char * name, int val ) { char buf[64]; #if defined(TIXML_SNPRINTF) TIXML_SNPRINTF( buf, sizeof(buf), "%d", val ); #else sprintf( buf, "%d", val ); #endif SetAttribute( name, buf ); } #ifdef TIXML_USE_STL void TiXmlElement::SetAttribute( const std::string& name, int val ) { std::ostringstream oss; oss << val; SetAttribute( name, oss.str() ); } #endif void TiXmlElement::SetDoubleAttribute( const char * name, double val ) { char buf[256]; #if defined(TIXML_SNPRINTF) TIXML_SNPRINTF( buf, sizeof(buf), "%f", val ); #else sprintf( buf, "%f", val ); #endif SetAttribute( name, buf ); } void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) { #ifdef TIXML_USE_STL TIXML_STRING _name( cname ); TIXML_STRING _value( cvalue ); #else const char* _name = cname; const char* _value = cvalue; #endif TiXmlAttribute* node = attributeSet.Find( _name ); if ( node ) { node->SetValue( _value ); return; } TiXmlAttribute* attrib = new (std::nothrow) TiXmlAttribute( cname, cvalue ); if ( attrib ) { attributeSet.Add( attrib ); } else { TiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); } } #ifdef TIXML_USE_STL void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value ) { TiXmlAttribute* node = attributeSet.Find( name ); if ( node ) { node->SetValue( _value ); return; } TiXmlAttribute* attrib = new (std::nothrow) TiXmlAttribute( name, _value ); if ( attrib ) { attributeSet.Add( attrib ); } else { TiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); } } #endif void TiXmlElement::Print( FILE* cfile, int depth ) const { int i; assert( cfile ); for ( i=0; iNext() ) { fprintf( cfile, " " ); attrib->Print( cfile, depth ); } // There are 3 different formatting approaches: // 1) An element without children is printed as a node // 2) An element with only a text child is printed as text // 3) An element with children is printed on multiple lines. TiXmlNode* node; if ( !firstChild ) { fprintf( cfile, " />" ); } else if ( firstChild == lastChild && firstChild->ToText() ) { fprintf( cfile, ">" ); firstChild->Print( cfile, depth + 1 ); fprintf( cfile, "", value.c_str() ); } else { fprintf( cfile, ">" ); for ( node = firstChild; node; node=node->NextSibling() ) { if ( !node->ToText() ) { fprintf( cfile, "\n" ); } node->Print( cfile, depth+1 ); } fprintf( cfile, "\n" ); for( i=0; i", value.c_str() ); } } void TiXmlElement::CopyTo( TiXmlElement* target ) const { // superclass: TiXmlNode::CopyTo( target ); // Element class: // Clone the attributes, then clone the children. const TiXmlAttribute* attribute = 0; for( attribute = attributeSet.First(); attribute; attribute = attribute->Next() ) { target->SetAttribute( attribute->Name(), attribute->Value() ); } TiXmlNode* node = 0; for ( node = firstChild; node; node = node->NextSibling() ) { target->LinkEndChild( node->Clone() ); } } bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const { if ( visitor->VisitEnter( *this, attributeSet.First() ) ) { for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) { if ( !node->Accept( visitor ) ) break; } } return visitor->VisitExit( *this ); } TiXmlNode* TiXmlElement::Clone() const { TiXmlElement* clone = new (std::nothrow) TiXmlElement( Value() ); if ( !clone ) return 0; CopyTo( clone ); return clone; } const char* TiXmlElement::GetText() const { const TiXmlNode* child = this->FirstChild(); if ( child ) { const TiXmlText* childText = child->ToText(); if ( childText ) { return childText->Value(); } } return 0; } TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; ClearError(); } TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; value = documentName; ClearError(); } #ifdef TIXML_USE_STL TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; value = documentName; ClearError(); } #endif TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT ) { copy.CopyTo( this ); } void TiXmlDocument::operator=( const TiXmlDocument& copy ) { Clear(); copy.CopyTo( this ); } bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) { // See STL_STRING_BUG below. //StringToBuffer buf( value ); return LoadFile( Value(), encoding ); } bool TiXmlDocument::SaveFile() const { // See STL_STRING_BUG below. // StringToBuffer buf( value ); // // if ( buf.buffer && SaveFile( buf.buffer ) ) // return true; // // return false; return SaveFile( Value() ); } bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) { // There was a really terrifying little bug here. The code: // value = filename // in the STL case, cause the assignment method of the std::string to // be called. What is strange, is that the std::string had the same // address as its c_str() method, and so bad things happen. Looks // like a bug in the Microsoft STL implementation. // Add an extra string to avoid the crash. TIXML_STRING filename( _filename ); value = filename; // reading in binary mode so that tinyxml can normalize the EOL FILE* file = TiXmlFOpen( value.c_str (), "rb" ); if ( file ) { bool result = LoadFile( file, encoding ); fclose( file ); return result; } else { SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } } bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) { if ( !file ) { SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } // Delete the existing data: Clear(); location.Clear(); // Get the file size, so we can pre-allocate the string. HUGE speed impact. long length = 0; fseek( file, 0, SEEK_END ); length = ftell( file ); fseek( file, 0, SEEK_SET ); // Strange case, but good to handle up front. if ( length <= 0 ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } // If we have a file, assume it is all one big XML file, and read it in. // The document parser may decide the document ends sooner than the entire file, however. TIXML_STRING data; data.reserve( length ); // Subtle bug here. TinyXml did use fgets. But from the XML spec: // 2.11 End-of-Line Handling // // // ...the XML processor MUST behave as if it normalized all line breaks in external // parsed entities (including the document entity) on input, before parsing, by translating // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to // a single #xA character. // // // It is not clear fgets does that, and certainly isn't clear it works cross platform. // Generally, you expect fgets to translate from the convention of the OS to the c/unix // convention, and not work generally. /* while( fgets( buf, sizeof(buf), file ) ) { data += buf; } */ char* buf = new char[ length+1 ]; buf[0] = 0; if ( fread( buf, length, 1, file ) != 1 ) { delete [] buf; SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } const char* lastPos = buf; const char* p = buf; buf[length] = 0; while( *p ) { assert( p < (buf+length) ); if ( *p == 0xa ) { // Newline character. No special rules for this. Append all the characters // since the last string, and include the newline. data.append( lastPos, (p-lastPos+1) ); // append, include the newline ++p; // move past the newline lastPos = p; // and point to the new buffer (may be 0) assert( p <= (buf+length) ); } else if ( *p == 0xd ) { // Carriage return. Append what we have so far, then // handle moving forward in the buffer. if ( (p-lastPos) > 0 ) { data.append( lastPos, p-lastPos ); // do not add the CR } data += (char)0xa; // a proper newline if ( *(p+1) == 0xa ) { // Carriage return - new line sequence p += 2; lastPos = p; assert( p <= (buf+length) ); } else { // it was followed by something else...that is presumably characters again. ++p; lastPos = p; assert( p <= (buf+length) ); } } else { ++p; } } // Handle any left over characters. if ( p-lastPos ) { data.append( lastPos, p-lastPos ); } delete [] buf; buf = 0; Parse( data.c_str(), 0, encoding ); if ( Error() ) return false; else return true; } bool TiXmlDocument::SaveFile( const char * filename ) const { // The old c stuff lives on... FILE* fp = TiXmlFOpen( filename, "w" ); if ( fp ) { bool result = SaveFile( fp ); fclose( fp ); return result; } return false; } bool TiXmlDocument::SaveFile( FILE* fp ) const { if ( useMicrosoftBOM ) { const unsigned char TIXML_UTF_LEAD_0 = 0xefU; const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; fputc( TIXML_UTF_LEAD_0, fp ); fputc( TIXML_UTF_LEAD_1, fp ); fputc( TIXML_UTF_LEAD_2, fp ); } Print( fp, 0 ); return (ferror(fp) == 0); } void TiXmlDocument::CopyTo( TiXmlDocument* target ) const { TiXmlNode::CopyTo( target ); target->error = error; target->errorId = errorId; target->errorDesc = errorDesc; target->tabsize = tabsize; target->errorLocation = errorLocation; target->useMicrosoftBOM = useMicrosoftBOM; TiXmlNode* node = 0; for ( node = firstChild; node; node = node->NextSibling() ) { TiXmlNode* clonedNode=node->Clone(); if (clonedNode!=NULL) target->LinkEndChild( clonedNode ); } } TiXmlNode* TiXmlDocument::Clone() const { TiXmlDocument* clone = new (std::nothrow) TiXmlDocument(); if ( !clone ) return 0; CopyTo( clone ); return clone; } void TiXmlDocument::Print( FILE* cfile, int depth ) const { assert( cfile ); for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) { node->Print( cfile, depth ); fprintf( cfile, "\n" ); } } bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const { if ( visitor->VisitEnter( *this ) ) { for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) { if ( !node->Accept( visitor ) ) break; } } return visitor->VisitExit( *this ); } const TiXmlAttribute* TiXmlAttribute::Next() const { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( next->value.empty() && next->name.empty() ) return 0; return next; } /* TiXmlAttribute* TiXmlAttribute::Next() { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( next->value.empty() && next->name.empty() ) return 0; return next; } */ const TiXmlAttribute* TiXmlAttribute::Previous() const { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( prev->value.empty() && prev->name.empty() ) return 0; return prev; } /* TiXmlAttribute* TiXmlAttribute::Previous() { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( prev->value.empty() && prev->name.empty() ) return 0; return prev; } */ void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const { TIXML_STRING n, v; EncodeString( name, &n ); EncodeString( value, &v ); if (value.find ('\"') == TIXML_STRING::npos) { if ( cfile ) { fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); } if ( str ) { (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; } } else { if ( cfile ) { fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); } if ( str ) { (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; } } } int TiXmlAttribute::QueryIntValue( int* ival ) const { if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 ) return TIXML_SUCCESS; return TIXML_WRONG_TYPE; } int TiXmlAttribute::QueryDoubleValue( double* dval ) const { if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) return TIXML_SUCCESS; return TIXML_WRONG_TYPE; } void TiXmlAttribute::SetIntValue( int _value ) { char buf [64]; #if defined(TIXML_SNPRINTF) TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); #else sprintf (buf, "%d", _value); #endif SetValue (buf); } void TiXmlAttribute::SetDoubleValue( double _value ) { char buf [256]; #if defined(TIXML_SNPRINTF) TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value); #else sprintf (buf, "%lf", _value); #endif SetValue (buf); } int TiXmlAttribute::IntValue() const { return atoi (value.c_str ()); } double TiXmlAttribute::DoubleValue() const { return atof (value.c_str ()); } TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT ) { copy.CopyTo( this ); } void TiXmlComment::operator=( const TiXmlComment& base ) { Clear(); base.CopyTo( this ); } void TiXmlComment::Print( FILE* cfile, int depth ) const { assert( cfile ); for ( int i=0; i", value.c_str() ); } void TiXmlComment::CopyTo( TiXmlComment* target ) const { TiXmlNode::CopyTo( target ); } bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlComment::Clone() const { TiXmlComment* clone = new (std::nothrow) TiXmlComment(); if ( !clone ) return 0; CopyTo( clone ); return clone; } void TiXmlText::Print( FILE* cfile, int depth ) const { assert( cfile ); if ( cdata ) { int i; fprintf( cfile, "\n" ); for ( i=0; i\n", value.c_str() ); // unformatted output } else { TIXML_STRING buffer; EncodeString( value, &buffer ); fprintf( cfile, "%s", buffer.c_str() ); } } void TiXmlText::CopyTo( TiXmlText* target ) const { TiXmlNode::CopyTo( target ); target->cdata = cdata; } bool TiXmlText::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlText::Clone() const { TiXmlText* clone = 0; clone = new (std::nothrow) TiXmlText( "" ); if ( !clone ) return 0; CopyTo( clone ); return clone; } TiXmlDeclaration::TiXmlDeclaration( const char * _version, const char * _encoding, const char * _standalone ) : TiXmlNode( TiXmlNode::DECLARATION ) { version = _version; encoding = _encoding; standalone = _standalone; } #ifdef TIXML_USE_STL TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, const std::string& _encoding, const std::string& _standalone ) : TiXmlNode( TiXmlNode::DECLARATION ) { version = _version; encoding = _encoding; standalone = _standalone; } #endif TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) : TiXmlNode( TiXmlNode::DECLARATION ) { copy.CopyTo( this ); } void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) { Clear(); copy.CopyTo( this ); } void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const { if ( cfile ) fprintf( cfile, "" ); if ( str ) (*str) += "?>"; } void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const { TiXmlNode::CopyTo( target ); target->version = version; target->encoding = encoding; target->standalone = standalone; } bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlDeclaration::Clone() const { TiXmlDeclaration* clone = new (std::nothrow) TiXmlDeclaration(); if ( !clone ) return 0; CopyTo( clone ); return clone; } void TiXmlUnknown::Print( FILE* cfile, int depth ) const { for ( int i=0; i", value.c_str() ); } void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const { TiXmlNode::CopyTo( target ); } bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlUnknown::Clone() const { TiXmlUnknown* clone = new (std::nothrow) TiXmlUnknown(); if ( !clone ) return 0; CopyTo( clone ); return clone; } TiXmlAttributeSet::TiXmlAttributeSet() { sentinel.next = &sentinel; sentinel.prev = &sentinel; } TiXmlAttributeSet::~TiXmlAttributeSet() { assert( sentinel.next == &sentinel ); assert( sentinel.prev == &sentinel ); } void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) { #ifdef TIXML_USE_STL assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. #else assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. #endif addMe->next = &sentinel; addMe->prev = sentinel.prev; sentinel.prev->next = addMe; sentinel.prev = addMe; } void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) { TiXmlAttribute* node; for( node = sentinel.next; node != &sentinel; node = node->next ) { if ( node == removeMe ) { node->prev->next = node->next; node->next->prev = node->prev; node->next = 0; node->prev = 0; return; } } assert( 0 ); // we tried to remove a non-linked attribute. } #ifdef TIXML_USE_STL const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const { for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) { if ( node->name == name ) return node; } return 0; } /* TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) { for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) { if ( node->name == name ) return node; } return 0; } */ #endif const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const { for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) { if ( strcmp( node->name.c_str(), name ) == 0 ) return node; } return 0; } /* TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) { for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) { if ( strcmp( node->name.c_str(), name ) == 0 ) return node; } return 0; } */ #ifdef TIXML_USE_STL std::istream& operator>> (std::istream & in, TiXmlNode & base) { TIXML_STRING tag; tag.reserve( 8 * 1000 ); base.StreamIn( &in, &tag ); base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); return in; } #endif #ifdef TIXML_USE_STL std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) { TiXmlPrinter printer; printer.SetStreamPrinting(); base.Accept( &printer ); out << printer.Str(); return out; } std::string& operator<< (std::string& out, const TiXmlNode& base ) { TiXmlPrinter printer; printer.SetStreamPrinting(); base.Accept( &printer ); out.append( printer.Str() ); return out; } #endif TiXmlHandle TiXmlHandle::FirstChild() const { if ( node ) { TiXmlNode* child = node->FirstChild(); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const { if ( node ) { TiXmlNode* child = node->FirstChild( value ); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::FirstChildElement() const { if ( node ) { TiXmlElement* child = node->FirstChildElement(); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const { if ( node ) { TiXmlElement* child = node->FirstChildElement( value ); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::Child( int count ) const { if ( node ) { int i; TiXmlNode* child = node->FirstChild(); for ( i=0; child && iNextSibling(), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const { if ( node ) { int i; TiXmlNode* child = node->FirstChild( value ); for ( i=0; child && iNextSibling( value ), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::ChildElement( int count ) const { if ( node ) { int i; TiXmlElement* child = node->FirstChildElement(); for ( i=0; child && iNextSiblingElement(), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const { if ( node ) { int i; TiXmlElement* child = node->FirstChildElement( value ); for ( i=0; child && iNextSiblingElement( value ), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) { return true; } bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) { return true; } bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) { DoIndent(); buffer += "<"; buffer += element.Value(); for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) { buffer += " "; attrib->Print( 0, 0, &buffer ); } if ( !element.FirstChild() ) { buffer += " />"; DoLineBreak(); } else { buffer += ">"; if ( element.FirstChild()->ToText() && element.LastChild() == element.FirstChild() && element.FirstChild()->ToText()->CDATA() == false ) { simpleTextPrint = true; // no DoLineBreak()! } else { DoLineBreak(); } } ++depth; return true; } bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) { --depth; if ( !element.FirstChild() ) { // nothing. } else { if ( simpleTextPrint ) { simpleTextPrint = false; } else { DoIndent(); } buffer += ""; DoLineBreak(); } return true; } bool TiXmlPrinter::Visit( const TiXmlText& text ) { if ( text.CDATA() ) { DoIndent(); buffer += ""; DoLineBreak(); } else if ( simpleTextPrint ) { TIXML_STRING str; TiXmlBase::EncodeString( text.ValueTStr(), &str ); buffer += str; } else { DoIndent(); TIXML_STRING str; TiXmlBase::EncodeString( text.ValueTStr(), &str ); buffer += str; DoLineBreak(); } return true; } bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) { DoIndent(); declaration.Print( 0, 0, &buffer ); DoLineBreak(); return true; } bool TiXmlPrinter::Visit( const TiXmlComment& comment ) { DoIndent(); buffer += ""; DoLineBreak(); return true; } bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) { DoIndent(); buffer += "<"; buffer += unknown.Value(); buffer += ">"; DoLineBreak(); return true; } openzwave-1.6.1914/cpp/tinyxml/Makefile0000644000175200017520000000671014032142455014652 00000000000000#**************************************************************************** # # Makefile for TinyXml test. # Lee Thomason # www.grinninglizard.com # # This is a GNU make (gmake) makefile #**************************************************************************** # DEBUG can be set to YES to include debugging info, or NO otherwise DEBUG := YES # PROFILE can be set to YES to include profiling info, or NO otherwise PROFILE := NO # TINYXML_USE_STL can be used to turn on STL support. NO, then STL # will not be used. YES will include the STL files. TINYXML_USE_STL := YES #**************************************************************************** CC := gcc CXX := g++ LD := g++ AR := ar rc RANLIB := ranlib DEBUG_CFLAGS := -Wall -Wno-format -g -DDEBUG $(CPPFLAGS) RELEASE_CFLAGS := -Wall -Wno-unknown-pragmas -Wno-format -O3 $(CPPFLAGS) LIBS := DEBUG_CXXFLAGS := ${DEBUG_CFLAGS} RELEASE_CXXFLAGS := ${RELEASE_CFLAGS} DEBUG_LDFLAGS := -g RELEASE_LDFLAGS := ifeq (YES, ${DEBUG}) CFLAGS := ${DEBUG_CFLAGS} CXXFLAGS := ${DEBUG_CXXFLAGS} LDFLAGS := ${DEBUG_LDFLAGS} else CFLAGS := ${RELEASE_CFLAGS} CXXFLAGS := ${RELEASE_CXXFLAGS} LDFLAGS := ${RELEASE_LDFLAGS} endif ifeq (YES, ${PROFILE}) CFLAGS := ${CFLAGS} -pg -O3 CXXFLAGS := ${CXXFLAGS} -pg -O3 LDFLAGS := ${LDFLAGS} -pg endif #**************************************************************************** # Preprocessor directives #**************************************************************************** ifeq (YES, ${TINYXML_USE_STL}) DEFS := -DTIXML_USE_STL else DEFS := endif #**************************************************************************** # Include paths #**************************************************************************** #INCS := -I/usr/include/g++-2 -I/usr/local/include INCS := #**************************************************************************** # Makefile code common to all platforms #**************************************************************************** CFLAGS := ${CFLAGS} ${DEFS} CXXFLAGS := ${CXXFLAGS} ${DEFS} #**************************************************************************** # Targets of the build #**************************************************************************** OUTPUT := xmltest all: ${OUTPUT} #**************************************************************************** # Source files #**************************************************************************** SRCS := tinyxml.cpp tinyxmlparser.cpp xmltest.cpp tinyxmlerror.cpp tinystr.cpp # Add on the sources for libraries SRCS := ${SRCS} OBJS := $(addsuffix .o,$(basename ${SRCS})) #**************************************************************************** # Output #**************************************************************************** ${OUTPUT}: ${OBJS} ${LD} -o $@ ${LDFLAGS} ${OBJS} ${LIBS} ${EXTRA_LIBS} #**************************************************************************** # common rules #**************************************************************************** # Rules for compiling source files to object files %.o : %.cpp ${CXX} -c ${CXXFLAGS} ${INCS} $< -o $@ %.o : %.c ${CC} -c ${CFLAGS} ${INCS} $< -o $@ dist: bash makedistlinux clean: -rm -f core ${OBJS} ${OUTPUT} depend: #makedepend ${INCS} ${SRCS} tinyxml.o: tinyxml.h tinystr.h tinyxmlparser.o: tinyxml.h tinystr.h xmltest.o: tinyxml.h tinystr.h tinyxmlerror.o: tinyxml.h tinystr.h openzwave-1.6.1914/cpp/tinyxml/tinyxml.h0000644000175200017520000017550014032142455015073 00000000000000/* www.sourceforge.net/projects/tinyxml Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #ifndef TINYXML_INCLUDED #define TINYXML_INCLUDED #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4530 ) #pragma warning( disable : 4786 ) #endif #include #include #include #include #include // Help out windows: #if defined( _DEBUG ) && !defined( DEBUG ) #define DEBUG #endif #ifdef TIXML_USE_STL #include #include #include #define TIXML_STRING std::string #else #include "tinystr.h" #define TIXML_STRING TiXmlString #endif // Deprecated library function hell. Compilers want to use the // new safe versions. This probably doesn't fully address the problem, // but it gets closer. There are too many compilers for me to fully // test. If you get compilation troubles, undefine TIXML_SAFE #define TIXML_SAFE #ifdef TIXML_SAFE #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) // Microsoft visual studio, version 2005 and higher. #define TIXML_SNPRINTF _snprintf_s #define TIXML_SNSCANF _snscanf_s #define TIXML_SSCANF sscanf_s #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) // Microsoft visual studio, version 6 and higher. //#pragma message( "Using _sn* functions." ) #define TIXML_SNPRINTF _snprintf #define TIXML_SNSCANF _snscanf #define TIXML_SSCANF sscanf #elif defined(__GNUC__) && (__GNUC__ >= 3 ) // GCC version 3 and higher.s //#warning( "Using sn* functions." ) #define TIXML_SNPRINTF snprintf #define TIXML_SNSCANF snscanf #define TIXML_SSCANF sscanf #else #define TIXML_SSCANF sscanf #endif #endif class TiXmlDocument; class TiXmlElement; class TiXmlComment; class TiXmlUnknown; class TiXmlAttribute; class TiXmlText; class TiXmlDeclaration; class TiXmlParsingData; const int TIXML_MAJOR_VERSION = 2; const int TIXML_MINOR_VERSION = 5; const int TIXML_PATCH_VERSION = 3; /* Internal structure for tracking location of items in the XML file. */ struct TiXmlCursor { TiXmlCursor() { Clear(); } void Clear() { row = col = -1; } int row; // 0 based. int col; // 0 based. }; /** If you call the Accept() method, it requires being passed a TiXmlVisitor class to handle callbacks. For nodes that contain other nodes (Document, Element) you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves are simple called with Visit(). If you return 'true' from a Visit method, recursive parsing will continue. If you return false, no children of this node or its sibilings will be Visited. All flavors of Visit methods have a default implementation that returns 'true' (continue visiting). You need to only override methods that are interesting to you. Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting. You should never change the document from a callback. \see TiXmlNode::Accept() */ class TiXmlVisitor { public: virtual ~TiXmlVisitor() {} /// Visit a document. virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; } /// Visit a document. virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; } /// Visit an element. virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; } /// Visit an element. virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; } /// Visit a declaration virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; } /// Visit a text node virtual bool Visit( const TiXmlText& /*text*/ ) { return true; } /// Visit a comment node virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; } /// Visit an unknow node virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; } }; // Only used by Attribute::Query functions enum { TIXML_SUCCESS, TIXML_NO_ATTRIBUTE, TIXML_WRONG_TYPE }; // Used by the parsing routines. enum TiXmlEncoding { TIXML_ENCODING_UNKNOWN, TIXML_ENCODING_UTF8, TIXML_ENCODING_LEGACY }; const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; /** TiXmlBase is a base class for every class in TinyXml. It does little except to establish that TinyXml classes can be printed and provide some utility functions. In XML, the document and elements can contain other elements and other types of nodes. \verbatim A Document can contain: Element (container or leaf) Comment (leaf) Unknown (leaf) Declaration( leaf ) An Element can contain: Element (container or leaf) Text (leaf) Attributes (not on tree) Comment (leaf) Unknown (leaf) A Decleration contains: Attributes (not on tree) \endverbatim */ class TiXmlBase { friend class TiXmlNode; friend class TiXmlElement; friend class TiXmlDocument; public: TiXmlBase() : userData(0) {} virtual ~TiXmlBase() {} /** All TinyXml classes can print themselves to a filestream or the string class (TiXmlString in non-STL mode, std::string in STL mode.) Either or both cfile and str can be null. This is a formatted print, and will insert tabs and newlines. (For an unformatted stream, use the << operator.) */ virtual void Print( FILE* cfile, int depth ) const = 0; /** The world does not agree on whether white space should be kept or not. In order to make everyone happy, these global, static functions are provided to set whether or not TinyXml will condense all white space into a single space or not. The default is to condense. Note changing this value is not thread safe. */ static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } /// Return the current white space setting. static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } /** Return the position, in the original source file, of this node or attribute. The row and column are 1-based. (That is the first row and first column is 1,1). If the returns values are 0 or less, then the parser does not have a row and column value. Generally, the row and column value will be set when the TiXmlDocument::Load(), TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set when the DOM was created from operator>>. The values reflect the initial load. Once the DOM is modified programmatically (by adding or changing nodes and attributes) the new values will NOT update to reflect changes in the document. There is a minor performance cost to computing the row and column. Computation can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. \see TiXmlDocument::SetTabSize() */ int Row() const { return location.row + 1; } int Column() const { return location.col + 1; } ///< See Row() void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data. void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data. const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data. // Table that returs, for a given lead byte, the total number of bytes // in the UTF-8 sequence. static const int utf8ByteTable[256]; virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc, or they will be transformed into entities! */ static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out ); enum { TIXML_NO_ERROR = 0, TIXML_ERROR, TIXML_ERROR_OPENING_FILE, TIXML_ERROR_OUT_OF_MEMORY, TIXML_ERROR_PARSING_ELEMENT, TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, TIXML_ERROR_READING_ELEMENT_VALUE, TIXML_ERROR_READING_ATTRIBUTES, TIXML_ERROR_PARSING_EMPTY, TIXML_ERROR_READING_END_TAG, TIXML_ERROR_PARSING_UNKNOWN, TIXML_ERROR_PARSING_COMMENT, TIXML_ERROR_PARSING_DECLARATION, TIXML_ERROR_DOCUMENT_EMPTY, TIXML_ERROR_EMBEDDED_NULL, TIXML_ERROR_PARSING_CDATA, TIXML_ERROR_DOCUMENT_TOP_ONLY, TIXML_ERROR_STRING_COUNT }; protected: static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); inline static bool IsWhiteSpace( char c ) { return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); } inline static bool IsWhiteSpace( int c ) { if ( c < 256 ) return IsWhiteSpace( (char) c ); return false; // Again, only truly correct for English/Latin...but usually works. } #ifdef TIXML_USE_STL static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ); static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag ); #endif /* Reads an XML name into the string provided. Returns a pointer just past the last character of the name, or 0 if the function has an error. */ static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); /* Reads text. Returns a pointer past the given end tag. Wickedly complex options, but it keeps the (sensitive) code in one place. */ static const char* ReadText( const char* in, // where to start TIXML_STRING* text, // the string read bool ignoreWhiteSpace, // whether to keep the white space const char* endTag, // what ends this text bool ignoreCase, // whether to ignore case in the end tag TiXmlEncoding encoding ); // the current encoding // If an entity has been found, transform it into a character. static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); // Get a character, while interpreting entities. // The length can be from 0 to 4 bytes. inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) { assert( p ); if ( encoding == TIXML_ENCODING_UTF8 ) { *length = utf8ByteTable[ *((const unsigned char*)p) ]; assert( *length >= 0 && *length < 5 ); } else { *length = 1; } if ( *length == 1 ) { if ( *p == '&' ) return GetEntity( p, _value, length, encoding ); *_value = *p; return p+1; } else if ( *length ) { //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), // and the null terminator isn't needed for( int i=0; p[i] && i<*length; ++i ) { _value[i] = p[i]; } return p + (*length); } else { // Not valid text. return 0; } } // Return true if the next characters in the stream are any of the endTag sequences. // Ignore case only works for english, and should only be relied on when comparing // to English words: StringEqual( p, "version", true ) is fine. static bool StringEqual( const char* p, const char* endTag, bool ignoreCase, TiXmlEncoding encoding ); static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; TiXmlCursor location; /// Field containing a generic user pointer void* userData; // None of these methods are reliable for any language except English. // Good for approximation, not great for accuracy. static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); inline static int ToLower( int v, TiXmlEncoding encoding ) { if ( encoding == TIXML_ENCODING_UTF8 ) { if ( v < 128 ) return tolower( v ); return v; } else { return tolower( v ); } } static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); private: TiXmlBase( const TiXmlBase& ); // not implemented. void operator=( const TiXmlBase& base ); // not allowed. struct Entity { const char* str; unsigned int strLength; char chr; }; enum { NUM_ENTITY = 5, MAX_ENTITY_LENGTH = 6 }; static Entity entity[ NUM_ENTITY ]; static bool condenseWhiteSpace; }; /** The parent class for everything in the Document Object Model. (Except for attributes). Nodes have siblings, a parent, and children. A node can be in a document, or stand on its own. The type of a TiXmlNode can be queried, and it can be cast to its more defined type. */ class TiXmlNode : public TiXmlBase { friend class TiXmlDocument; friend class TiXmlElement; public: #ifdef TIXML_USE_STL /** An input stream operator, for every class. Tolerant of newlines and formatting, but doesn't expect them. */ friend std::istream& operator >> (std::istream& in, TiXmlNode& base); /** An output stream operator, for every class. Note that this outputs without any newlines or formatting, as opposed to Print(), which includes tabs and new lines. The operator<< and operator>> are not completely symmetric. Writing a node to a stream is very well defined. You'll get a nice stream of output, without any extra whitespace or newlines. But reading is not as well defined. (As it always is.) If you create a TiXmlElement (for example) and read that from an input stream, the text needs to define an element or junk will result. This is true of all input streams, but it's worth keeping in mind. A TiXmlDocument will read nodes until it reads a root element, and all the children of that root element. */ friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); /// Appends the XML node or attribute to a std::string. friend std::string& operator<< (std::string& out, const TiXmlNode& base ); #endif /** The types of XML nodes supported by TinyXml. (All the unsupported types are picked up by UNKNOWN.) */ enum NodeType { DOCUMENT, ELEMENT, COMMENT, UNKNOWN, TEXT, DECLARATION, TYPECOUNT }; virtual ~TiXmlNode(); /** The meaning of 'value' changes for the specific type of TiXmlNode. \verbatim Document: filename of the xml file Element: name of the element Comment: the comment text Unknown: the tag contents Text: the text string \endverbatim The subclasses will wrap this function. */ const char *Value() const { return value.c_str (); } #ifdef TIXML_USE_STL /** Return Value() as a std::string. If you only use STL, this is more efficient than calling Value(). Only available in STL mode. */ const std::string& ValueStr() const { return value; } #endif const TIXML_STRING& ValueTStr() const { return value; } /** Changes the value of the node. Defined as: \verbatim Document: filename of the xml file Element: name of the element Comment: the comment text Unknown: the tag contents Text: the text string \endverbatim */ void SetValue(const char * _value) { value = _value;} #ifdef TIXML_USE_STL /// STL std::string form. void SetValue( const std::string& _value ) { value = _value; } #endif /// Delete all the children of this node. Does not affect 'this'. void Clear(); /// One step up the DOM. TiXmlNode* Parent() { return parent; } const TiXmlNode* Parent() const { return parent; } const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. TiXmlNode* FirstChild() { return firstChild; } const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. /// The first child of this node with the matching 'value'. Will be null if none found. TiXmlNode* FirstChild( const char * _value ) { // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) // call the method, cast the return back to non-const. return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value )); } const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. TiXmlNode* LastChild() { return lastChild; } const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. TiXmlNode* LastChild( const char * _value ) { return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value )); } #ifdef TIXML_USE_STL const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form. const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form. #endif /** An alternate way to walk the children of a node. One way to iterate over nodes is: \verbatim for( child = parent->FirstChild(); child; child = child->NextSibling() ) \endverbatim IterateChildren does the same thing with the syntax: \verbatim child = 0; while( child = parent->IterateChildren( child ) ) \endverbatim IterateChildren takes the previous child as input and finds the next one. If the previous child is null, it returns the first. IterateChildren will return null when done. */ const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const; TiXmlNode* IterateChildren( const TiXmlNode* previous ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) ); } /// This flavor of IterateChildren searches for children with a particular 'value' const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const; TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) ); } #ifdef TIXML_USE_STL const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. #endif /** Add a new node related to this. Adds a child past the LastChild. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); /** Add a new node related to this. Adds a child past the LastChild. NOTE: the node to be added is passed by pointer, and will be henceforth owned (and deleted) by tinyXml. This method is efficient and avoids an extra copy, but should be used with care as it uses a different memory model than the other insert functions. \sa InsertEndChild */ TiXmlNode* LinkEndChild( TiXmlNode* addThis ); /** Add a new node related to this. Adds a child before the specified child. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); /** Add a new node related to this. Adds a child after the specified child. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); /** Replace a child of this node. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); /// Delete a child of this node. bool RemoveChild( TiXmlNode* removeThis ); /// Navigate to a sibling node. const TiXmlNode* PreviousSibling() const { return prev; } TiXmlNode* PreviousSibling() { return prev; } /// Navigate to a sibling node. const TiXmlNode* PreviousSibling( const char * ) const; TiXmlNode* PreviousSibling( const char *_prev ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) ); } #ifdef TIXML_USE_STL const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form. #endif /// Navigate to a sibling node. const TiXmlNode* NextSibling() const { return next; } TiXmlNode* NextSibling() { return next; } /// Navigate to a sibling node with the given 'value'. const TiXmlNode* NextSibling( const char * ) const; TiXmlNode* NextSibling( const char* _next ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) ); } /** Convenience function to get through elements. Calls NextSibling and ToElement. Will skip all non-Element nodes. Returns 0 if there is not another element. */ const TiXmlElement* NextSiblingElement() const; TiXmlElement* NextSiblingElement() { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() ); } /** Convenience function to get through elements. Calls NextSibling and ToElement. Will skip all non-Element nodes. Returns 0 if there is not another element. */ const TiXmlElement* NextSiblingElement( const char * ) const; TiXmlElement* NextSiblingElement( const char *_next ) { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) ); } #ifdef TIXML_USE_STL const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. #endif /// Convenience function to get through elements. const TiXmlElement* FirstChildElement() const; TiXmlElement* FirstChildElement() { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() ); } /// Convenience function to get through elements. const TiXmlElement* FirstChildElement( const char * _value ) const; TiXmlElement* FirstChildElement( const char * _value ) { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) ); } #ifdef TIXML_USE_STL const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. #endif /** Query the type (as an enumerated value, above) of this node. The possible types are: DOCUMENT, ELEMENT, COMMENT, UNKNOWN, TEXT, and DECLARATION. */ int Type() const { return type; } /** Return a pointer to the Document this node lives in. Returns null if not in a document. */ const TiXmlDocument* GetDocument() const; TiXmlDocument* GetDocument() { return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() ); } /// Returns true if this node has no children. bool NoChildren() const { return !firstChild; } virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. /** Create an exact duplicate of this node and return it. The memory must be deleted by the caller. */ virtual TiXmlNode* Clone() const = 0; /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the XML tree will be conditionally visited and the host will be called back via the TiXmlVisitor interface. This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse the XML for the callbacks, so the performance of TinyXML is unchanged by using this interface versus any other.) The interface has been based on ideas from: - http://www.saxproject.org/ - http://c2.com/cgi/wiki?HierarchicalVisitorPattern Which are both good references for "visiting". An example of using Accept(): \verbatim TiXmlPrinter printer; tinyxmlDoc.Accept( &printer ); const char* xmlcstr = printer.CStr(); \endverbatim */ virtual bool Accept( TiXmlVisitor* visitor ) const = 0; protected: TiXmlNode( NodeType _type ); // Copy to the allocated object. Shared functionality between Clone, Copy constructor, // and the assignment operator. void CopyTo( TiXmlNode* target ) const; #ifdef TIXML_USE_STL // The real work of the input operator. virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0; #endif // Figure out what is at *p, and parse it. Returns null if it is not an xml node. TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); TiXmlNode* parent; NodeType type; TiXmlNode* firstChild; TiXmlNode* lastChild; TIXML_STRING value; TiXmlNode* prev; TiXmlNode* next; private: TiXmlNode( const TiXmlNode& ); // not implemented. void operator=( const TiXmlNode& base ); // not allowed. }; /** An attribute is a name-value pair. Elements have an arbitrary number of attributes, each with a unique name. \note The attributes are not TiXmlNodes, since they are not part of the tinyXML document object model. There are other suggested ways to look at this problem. */ class TiXmlAttribute : public TiXmlBase { friend class TiXmlAttributeSet; public: /// Construct an empty attribute. TiXmlAttribute() : TiXmlBase() { document = 0; prev = next = 0; } #ifdef TIXML_USE_STL /// std::string constructor. TiXmlAttribute( const std::string& _name, const std::string& _value ) { name = _name; value = _value; document = 0; prev = next = 0; } #endif /// Construct an attribute with a name and value. TiXmlAttribute( const char * _name, const char * _value ) { name = _name; value = _value; document = 0; prev = next = 0; } const char* Name() const { return name.c_str(); } ///< Return the name of this attribute. const char* Value() const { return value.c_str(); } ///< Return the value of this attribute. #ifdef TIXML_USE_STL const std::string& ValueStr() const { return value; } ///< Return the value of this attribute. #endif int IntValue() const; ///< Return the value of this attribute, converted to an integer. double DoubleValue() const; ///< Return the value of this attribute, converted to a double. // Get the tinyxml string representation const TIXML_STRING& NameTStr() const { return name; } /** QueryIntValue examines the value string. It is an alternative to the IntValue() method with richer error checking. If the value is an integer, it is stored in 'value' and the call returns TIXML_SUCCESS. If it is not an integer, it returns TIXML_WRONG_TYPE. A specialized but useful call. Note that for success it returns 0, which is the opposite of almost all other TinyXml calls. */ int QueryIntValue( int* _value ) const; /// QueryDoubleValue examines the value string. See QueryIntValue(). int QueryDoubleValue( double* _value ) const; void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. void SetValue( const char* _value ) { value = _value; } ///< Set the value. void SetIntValue( int _value ); ///< Set the value from an integer. void SetDoubleValue( double _value ); ///< Set the value from a double. #ifdef TIXML_USE_STL /// STL std::string form. void SetName( const std::string& _name ) { name = _name; } /// STL std::string form. void SetValue( const std::string& _value ) { value = _value; } #endif /// Get the next sibling attribute in the DOM. Returns null at end. const TiXmlAttribute* Next() const; TiXmlAttribute* Next() { return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); } /// Get the previous sibling attribute in the DOM. Returns null at beginning. const TiXmlAttribute* Previous() const; TiXmlAttribute* Previous() { return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); } bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } /* Attribute parsing starts: first letter of the name returns: the next char after the value end quote */ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); // Prints this Attribute to a FILE stream. virtual void Print( FILE* cfile, int depth ) const { Print( cfile, depth, 0 ); } void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; // [internal use] // Set the document pointer so the attribute can report errors. void SetDocument( TiXmlDocument* doc ) { document = doc; } private: TiXmlAttribute( const TiXmlAttribute& ); // not implemented. void operator=( const TiXmlAttribute& base ); // not allowed. TiXmlDocument* document; // A pointer back to a document, for error reporting. TIXML_STRING name; TIXML_STRING value; TiXmlAttribute* prev; TiXmlAttribute* next; }; /* A class used to manage a group of attributes. It is only used internally, both by the ELEMENT and the DECLARATION. The set can be changed transparent to the Element and Declaration classes that use it, but NOT transparent to the Attribute which has to implement a next() and previous() method. Which makes it a bit problematic and prevents the use of STL. This version is implemented with circular lists because: - I like circular lists - it demonstrates some independence from the (typical) doubly linked list. */ class TiXmlAttributeSet { public: TiXmlAttributeSet(); ~TiXmlAttributeSet(); void Add( TiXmlAttribute* attribute ); void Remove( TiXmlAttribute* attribute ); const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } const TiXmlAttribute* Find( const char* _name ) const; TiXmlAttribute* Find( const char* _name ) { return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); } #ifdef TIXML_USE_STL const TiXmlAttribute* Find( const std::string& _name ) const; TiXmlAttribute* Find( const std::string& _name ) { return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); } #endif private: //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), //*ME: this class must be also use a hidden/disabled copy-constructor !!! TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute) TiXmlAttribute sentinel; }; /** The element is a container class. It has a value, the element name, and can contain other elements, text, comments, and unknowns. Elements also contain an arbitrary number of attributes. */ class TiXmlElement : public TiXmlNode { public: /// Construct an element. TiXmlElement (const char * in_value); #ifdef TIXML_USE_STL /// std::string constructor. TiXmlElement( const std::string& _value ); #endif TiXmlElement( const TiXmlElement& ); void operator=( const TiXmlElement& base ); virtual ~TiXmlElement(); /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists. */ const char* Attribute( const char* name ) const; /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists. If the attribute exists and can be converted to an integer, the integer value will be put in the return 'i', if 'i' is non-null. */ const char* Attribute( const char* name, int* i ) const; /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists. If the attribute exists and can be converted to an double, the double value will be put in the return 'd', if 'd' is non-null. */ const char* Attribute( const char* name, double* d ) const; /** QueryIntAttribute examines the attribute - it is an alternative to the Attribute() method with richer error checking. If the attribute is an integer, it is stored in 'value' and the call returns TIXML_SUCCESS. If it is not an integer, it returns TIXML_WRONG_TYPE. If the attribute does not exist, then TIXML_NO_ATTRIBUTE is returned. */ int QueryIntAttribute( const char* name, int* _value ) const; /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). int QueryDoubleAttribute( const char* name, double* _value ) const; /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). int QueryFloatAttribute( const char* name, float* _value ) const { double d; int result = QueryDoubleAttribute( name, &d ); if ( result == TIXML_SUCCESS ) { *_value = (float)d; } return result; } #ifdef TIXML_USE_STL /** Template form of the attribute query which will try to read the attribute into the specified type. Very easy, very powerful, but be careful to make sure to call this with the correct type. NOTE: This method doesn't work correctly for 'string' types. \return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE */ template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; std::stringstream sstream( node->ValueStr() ); sstream >> *outValue; if ( !sstream.fail() ) return TIXML_SUCCESS; return TIXML_WRONG_TYPE; } /* This is - in theory - a bug fix for "QueryValueAtribute returns truncated std::string" but template specialization is hard to get working cross-compiler. Leaving the bug for now. // The above will fail for std::string because the space character is used as a seperator. // Specialize for strings. Bug [ 1695429 ] QueryValueAtribute returns truncated std::string template<> int QueryValueAttribute( const std::string& name, std::string* outValue ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; *outValue = node->ValueStr(); return TIXML_SUCCESS; } */ #endif /** Sets an attribute of name to a given value. The attribute will be created if it does not exist, or changed if it does. */ void SetAttribute( const char* name, const char * _value ); #ifdef TIXML_USE_STL const std::string* Attribute( const std::string& name ) const; const std::string* Attribute( const std::string& name, int* i ) const; const std::string* Attribute( const std::string& name, double* d ) const; int QueryIntAttribute( const std::string& name, int* _value ) const; int QueryDoubleAttribute( const std::string& name, double* _value ) const; /// STL std::string form. void SetAttribute( const std::string& name, const std::string& _value ); ///< STL std::string form. void SetAttribute( const std::string& name, int _value ); #endif /** Sets an attribute of name to a given value. The attribute will be created if it does not exist, or changed if it does. */ void SetAttribute( const char * name, int value ); /** Sets an attribute of name to a given value. The attribute will be created if it does not exist, or changed if it does. */ void SetDoubleAttribute( const char * name, double value ); /** Deletes an attribute with the given name. */ void RemoveAttribute( const char * name ); #ifdef TIXML_USE_STL void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. #endif const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. TiXmlAttribute* FirstAttribute() { return attributeSet.First(); } const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. TiXmlAttribute* LastAttribute() { return attributeSet.Last(); } /** Convenience function for easy access to the text inside an element. Although easy and concise, GetText() is limited compared to getting the TiXmlText child and accessing it directly. If the first child of 'this' is a TiXmlText, the GetText() returns the character string of the Text node, else null is returned. This is a convenient method for getting the text of simple contained text: \verbatim This is text const char* str = fooElement->GetText(); \endverbatim 'str' will be a pointer to "This is text". Note that this function can be misleading. If the element foo was created from this XML: \verbatim This is text \endverbatim then the value of str would be null. The first child node isn't a text node, it is another element. From this XML: \verbatim This is text \endverbatim GetText() will return "This is ". WARNING: GetText() accesses a child node - don't become confused with the similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are safe type casts on the referenced node. */ const char* GetText() const; /// Creates a new Element and returns it - the returned element is a copy. virtual TiXmlNode* Clone() const; // Print the Element to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; /* Attribtue parsing starts: next char past '<' returns: next char past '>' */ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* visitor ) const; protected: void CopyTo( TiXmlElement* target ) const; void ClearThis(); // like clear, but initializes 'this' object as well // Used to be public [internal use] #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif /* [internal use] Reads the "value" of the element -- another element, or text. This should terminate with the current end tag. */ const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); private: TiXmlAttributeSet attributeSet; }; /** An XML comment. */ class TiXmlComment : public TiXmlNode { public: /// Constructs an empty comment. TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} /// Construct a comment from text. TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::COMMENT ) { SetValue( _value ); } TiXmlComment( const TiXmlComment& ); void operator=( const TiXmlComment& base ); virtual ~TiXmlComment() {} /// Returns a copy of this Comment. virtual TiXmlNode* Clone() const; // Write this Comment to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; /* Attribtue parsing starts: at the ! of the !-- returns: next char past '>' */ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* visitor ) const; protected: void CopyTo( TiXmlComment* target ) const; // used to be public #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif // virtual void StreamOut( TIXML_OSTREAM * out ) const; private: }; /** XML text. A text node can have 2 ways to output the next. "normal" output and CDATA. It will default to the mode it was parsed from the XML file and you generally want to leave it alone, but you can change the output mode with SetCDATA() and query it with CDATA(). */ class TiXmlText : public TiXmlNode { friend class TiXmlElement; public: /** Constructor for text element. By default, it is treated as normal, encoded text. If you want it be output as a CDATA text element, set the parameter _cdata to 'true' */ TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TEXT) { SetValue( initValue ); cdata = false; } virtual ~TiXmlText() {} #ifdef TIXML_USE_STL /// Constructor. TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) { SetValue( initValue ); cdata = false; } #endif TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); } void operator=( const TiXmlText& base ) { base.CopyTo( this ); } // Write this text object to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; /// Queries whether this represents text using a CDATA section. bool CDATA() const { return cdata; } /// Turns on or off a CDATA representation of text. void SetCDATA( bool _cdata ) { cdata = _cdata; } virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* content ) const; protected : /// [internal use] Creates a new Element and returns it. virtual TiXmlNode* Clone() const; void CopyTo( TiXmlText* target ) const; bool Blank() const; // returns true if all white space and new lines // [internal use] #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: bool cdata; // true if this should be input and output as a CDATA style text element }; /** In correct XML the declaration is the first entry in the file. \verbatim \endverbatim TinyXml will happily read or write files without a declaration, however. There are 3 possible attributes to the declaration: version, encoding, and standalone. Note: In this version of the code, the attributes are handled as special cases, not generic attributes, simply because there can only be at most 3 and they are always the same. */ class TiXmlDeclaration : public TiXmlNode { public: /// Construct an empty declaration. TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} #ifdef TIXML_USE_STL /// Constructor. TiXmlDeclaration( const std::string& _version, const std::string& _encoding, const std::string& _standalone ); #endif /// Construct. TiXmlDeclaration( const char* _version, const char* _encoding, const char* _standalone ); TiXmlDeclaration( const TiXmlDeclaration& copy ); void operator=( const TiXmlDeclaration& copy ); virtual ~TiXmlDeclaration() {} /// Version. Will return an empty string if none was found. const char *Version() const { return version.c_str (); } /// Encoding. Will return an empty string if none was found. const char *Encoding() const { return encoding.c_str (); } /// Is this a standalone document? const char *Standalone() const { return standalone.c_str (); } /// Creates a copy of this Declaration and returns it. virtual TiXmlNode* Clone() const; // Print this declaration to a FILE stream. virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; virtual void Print( FILE* cfile, int depth ) const { Print( cfile, depth, 0 ); } virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* visitor ) const; protected: void CopyTo( TiXmlDeclaration* target ) const; // used to be public #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: TIXML_STRING version; TIXML_STRING encoding; TIXML_STRING standalone; }; /** Any tag that tinyXml doesn't recognize is saved as an unknown. It is a tag of text, but should not be modified. It will be written back to the XML, unchanged, when the file is saved. DTD tags get thrown into TiXmlUnknowns. */ class TiXmlUnknown : public TiXmlNode { public: TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} virtual ~TiXmlUnknown() {} TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); } void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); } /// Creates a copy of this Unknown and returns it. virtual TiXmlNode* Clone() const; // Print this Unknown to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* content ) const; protected: void CopyTo( TiXmlUnknown* target ) const; #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: }; /** Always the top level node. A document binds together all the XML pieces. It can be saved, loaded, and printed to the screen. The 'value' of a document node is the xml file name. */ class TiXmlDocument : public TiXmlNode { public: /// Create an empty document, that has no name. TiXmlDocument(); /// Create a document with a name. The name of the document is also the filename of the xml. TiXmlDocument( const char * documentName ); #ifdef TIXML_USE_STL /// Constructor. TiXmlDocument( const std::string& documentName ); #endif TiXmlDocument( const TiXmlDocument& copy ); void operator=( const TiXmlDocument& copy ); virtual ~TiXmlDocument() {} /** Load a file using the current document value. Returns true if successful. Will delete any existing document data before loading. */ bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /// Save a file using the current document value. Returns true if successful. bool SaveFile() const; /// Load a file using the given filename. Returns true if successful. bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /// Save a file using the given filename. Returns true if successful. bool SaveFile( const char * filename ) const; /** Load a file using the given FILE*. Returns true if successful. Note that this method doesn't stream - the entire object pointed at by the FILE* will be interpreted as an XML file. TinyXML doesn't stream in XML from the current file location. Streaming may be added in the future. */ bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /// Save a file using the given FILE*. Returns true if successful. bool SaveFile( FILE* ) const; #ifdef TIXML_USE_STL bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. { // StringToBuffer f( filename ); // return ( f.buffer && LoadFile( f.buffer, encoding )); return LoadFile( filename.c_str(), encoding ); } bool SaveFile( const std::string& filename ) const ///< STL std::string version. { // StringToBuffer f( filename ); // return ( f.buffer && SaveFile( f.buffer )); return SaveFile( filename.c_str() ); } #endif /** Parse the given null terminated block of xml data. Passing in an encoding to this method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml to use that encoding, regardless of what TinyXml might otherwise try to detect. */ virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /** Get the root element -- the only top level element -- of the document. In well formed XML, there should only be one. TinyXml is tolerant of multiple elements at the document level. */ const TiXmlElement* RootElement() const { return FirstChildElement(); } TiXmlElement* RootElement() { return FirstChildElement(); } /** If an error occurs, Error will be set to true. Also, - The ErrorId() will contain the integer identifier of the error (not generally useful) - The ErrorDesc() method will return the name of the error. (very useful) - The ErrorRow() and ErrorCol() will return the location of the error (if known) */ bool Error() const { return error; } /// Contains a textual (english) description of the error if one occurs. const char * ErrorDesc() const { return errorDesc.c_str (); } /** Generally, you probably want the error string ( ErrorDesc() ). But if you prefer the ErrorId, this function will fetch it. */ int ErrorId() const { return errorId; } /** Returns the location (if known) of the error. The first column is column 1, and the first row is row 1. A value of 0 means the row and column wasn't applicable (memory errors, for example, have no row/column) or the parser lost the error. (An error in the error reporting, in that case.) \see SetTabSize, Row, Column */ int ErrorRow() const { return errorLocation.row+1; } int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) to report the correct values for row and column. It does not change the output or input in any way. By calling this method, with a tab size greater than 0, the row and column of each node and attribute is stored when the file is loaded. Very useful for tracking the DOM back in to the source file. The tab size is required for calculating the location of nodes. If not set, the default of 4 is used. The tabsize is set per document. Setting the tabsize to 0 disables row/column tracking. Note that row and column tracking is not supported when using operator>>. The tab size needs to be enabled before the parse or load. Correct usage: \verbatim TiXmlDocument doc; doc.SetTabSize( 8 ); doc.Load( "myfile.xml" ); \endverbatim \see Row, Column */ void SetTabSize( int _tabsize ) { tabsize = _tabsize; } int TabSize() const { return tabsize; } /** If you have handled the error, it can be reset with this call. The error state is automatically cleared if you Parse a new XML block. */ void ClearError() { error = false; errorId = 0; errorDesc = ""; errorLocation.row = errorLocation.col = 0; //errorLocation.last = 0; } /** Write the document to standard out using formatted printing ("pretty print"). */ void Print() const { Print( stdout, 0 ); } /* Write the document to a string using formatted printing ("pretty print"). This will allocate a character array (new char[]) and return it as a pointer. The calling code pust call delete[] on the return char* to avoid a memory leak. */ //char* PrintToMemory() const; /// Print this Document to a FILE stream. virtual void Print( FILE* cfile, int depth = 0 ) const; // [internal use] void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* content ) const; protected : // [internal use] virtual TiXmlNode* Clone() const; #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: void CopyTo( TiXmlDocument* target ) const; bool error; int errorId; TIXML_STRING errorDesc; int tabsize; TiXmlCursor errorLocation; bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. }; /** A TiXmlHandle is a class that wraps a node pointer with null checks; this is an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml DOM structure. It is a separate utility class. Take an example: \verbatim \endverbatim Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very easy to write a *lot* of code that looks like: \verbatim TiXmlElement* root = document.FirstChildElement( "Document" ); if ( root ) { TiXmlElement* element = root->FirstChildElement( "Element" ); if ( element ) { TiXmlElement* child = element->FirstChildElement( "Child" ); if ( child ) { TiXmlElement* child2 = child->NextSiblingElement( "Child" ); if ( child2 ) { // Finally do something useful. \endverbatim And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity of such code. A TiXmlHandle checks for null pointers so it is perfectly safe and correct to use: \verbatim TiXmlHandle docHandle( &document ); TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); if ( child2 ) { // do something useful \endverbatim Which is MUCH more concise and useful. It is also safe to copy handles - internally they are nothing more than node pointers. \verbatim TiXmlHandle handleCopy = handle; \endverbatim What they should not be used for is iteration: \verbatim int i=0; while ( true ) { TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); if ( !child ) break; // do something ++i; } \endverbatim It seems reasonable, but it is in fact two embedded while loops. The Child method is a linear walk to find the element, so this code would iterate much more than it needs to. Instead, prefer: \verbatim TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); for( child; child; child=child->NextSiblingElement() ) { // do something } \endverbatim */ class TiXmlHandle { public: /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } /// Copy constructor TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; } /// Return a handle to the first child node. TiXmlHandle FirstChild() const; /// Return a handle to the first child node with the given name. TiXmlHandle FirstChild( const char * value ) const; /// Return a handle to the first child element. TiXmlHandle FirstChildElement() const; /// Return a handle to the first child element with the given name. TiXmlHandle FirstChildElement( const char * value ) const; /** Return a handle to the "index" child with the given name. The first child is 0, the second 1, etc. */ TiXmlHandle Child( const char* value, int index ) const; /** Return a handle to the "index" child. The first child is 0, the second 1, etc. */ TiXmlHandle Child( int index ) const; /** Return a handle to the "index" child element with the given name. The first child element is 0, the second 1, etc. Note that only TiXmlElements are indexed: other types are not counted. */ TiXmlHandle ChildElement( const char* value, int index ) const; /** Return a handle to the "index" child element. The first child element is 0, the second 1, etc. Note that only TiXmlElements are indexed: other types are not counted. */ TiXmlHandle ChildElement( int index ) const; #ifdef TIXML_USE_STL TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } #endif /** Return the handle as a TiXmlNode. This may return null. */ TiXmlNode* ToNode() const { return node; } /** Return the handle as a TiXmlElement. This may return null. */ TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } /** Return the handle as a TiXmlText. This may return null. */ TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } /** Return the handle as a TiXmlUnknown. This may return null. */ TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } /** \deprecated use ToNode. Return the handle as a TiXmlNode. This may return null. */ TiXmlNode* Node() const { return ToNode(); } /** \deprecated use ToElement. Return the handle as a TiXmlElement. This may return null. */ TiXmlElement* Element() const { return ToElement(); } /** \deprecated use ToText() Return the handle as a TiXmlText. This may return null. */ TiXmlText* Text() const { return ToText(); } /** \deprecated use ToUnknown() Return the handle as a TiXmlUnknown. This may return null. */ TiXmlUnknown* Unknown() const { return ToUnknown(); } private: TiXmlNode* node; }; /** Print to memory functionality. The TiXmlPrinter is useful when you need to: -# Print to memory (especially in non-STL mode) -# Control formatting (line endings, etc.) When constructed, the TiXmlPrinter is in its default "pretty printing" mode. Before calling Accept() you can call methods to control the printing of the XML document. After TiXmlNode::Accept() is called, the printed document can be accessed via the CStr(), Str(), and Size() methods. TiXmlPrinter uses the Visitor API. \verbatim TiXmlPrinter printer; printer.SetIndent( "\t" ); doc.Accept( &printer ); fprintf( stdout, "%s", printer.CStr() ); \endverbatim */ class TiXmlPrinter : public TiXmlVisitor { public: TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ), buffer(), indent( " " ), lineBreak( "\n" ) {} virtual bool VisitEnter( const TiXmlDocument& doc ); virtual bool VisitExit( const TiXmlDocument& doc ); virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ); virtual bool VisitExit( const TiXmlElement& element ); virtual bool Visit( const TiXmlDeclaration& declaration ); virtual bool Visit( const TiXmlText& text ); virtual bool Visit( const TiXmlComment& comment ); virtual bool Visit( const TiXmlUnknown& unknown ); /** Set the indent characters for printing. By default 4 spaces but tab (\t) is also useful, or null/empty string for no indentation. */ void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; } /// Query the indention string. const char* Indent() { return indent.c_str(); } /** Set the line breaking string. By default set to newline (\n). Some operating systems prefer other characters, or can be set to the null/empty string for no indenation. */ void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; } /// Query the current line breaking string. const char* LineBreak() { return lineBreak.c_str(); } /** Switch over to "stream printing" which is the most dense formatting without linebreaks. Common when the XML is needed for network transmission. */ void SetStreamPrinting() { indent = ""; lineBreak = ""; } /// Return the result. const char* CStr() { return buffer.c_str(); } /// Return the length of the result string. size_t Size() { return buffer.size(); } #ifdef TIXML_USE_STL /// Return the result. const std::string& Str() { return buffer; } #endif private: void DoIndent() { for( int i=0; i Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . openzwave-1.6.1914/cpp/hidapi/libusb/0000777000175200017520000000000014032143200014271 500000000000000openzwave-1.6.1914/cpp/hidapi/libusb/Makefile.linux0000644000175200017520000000204314032142455017015 00000000000000########################################### # Simple Makefile for HIDAPI test program # # Alan Ott # Signal 11 Software # 2010-06-01 ########################################### all: hidtest-libusb libs libs: libhidapi-libusb.so CC ?= gcc CFLAGS ?= -Wall -g -fpic CXX ?= g++ CXXFLAGS ?= -Wall -g -fpic LDFLAGS ?= -Wall -g COBJS_LIBUSB = hid.o COBJS = $(COBJS_LIBUSB) CPPOBJS = ../hidtest/hidtest.o OBJS = $(COBJS) $(CPPOBJS) LIBS_USB = `pkg-config libusb-1.0 --libs` -lrt -lpthread LIBS = $(LIBS_USB) INCLUDES ?= -I../hidapi `pkg-config libusb-1.0 --cflags` # Console Test Program hidtest-libusb: $(COBJS_LIBUSB) $(CPPOBJS) $(CXX) $(LDFLAGS) $^ $(LIBS_USB) -o $@ # Shared Libs libhidapi-libusb.so: $(COBJS_LIBUSB) $(CC) $(LDFLAGS) $(LIBS_USB) -shared -fpic -Wl,-soname,$@.0 $^ -o $@ # Objects $(COBJS): %.o: %.c $(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@ $(CPPOBJS): %.o: %.cpp $(CXX) $(CXXFLAGS) -c $(INCLUDES) $< -o $@ clean: rm -f $(OBJS) hidtest-libusb libhidapi-libusb.so ../hidtest/hidtest.o .PHONY: clean libs openzwave-1.6.1914/cpp/hidapi/libusb/Makefile.freebsd0000644000175200017520000000160714032142455017275 00000000000000########################################### # Simple Makefile for HIDAPI test program # # Alan Ott # Signal 11 Software # 2010-06-01 ########################################### all: hidtest libs libs: libhidapi.so CC ?= cc CFLAGS ?= -Wall -g -fPIC CXX ?= c++ CXXFLAGS ?= -Wall -g COBJS = hid.o CPPOBJS = ../hidtest/hidtest.o OBJS = $(COBJS) $(CPPOBJS) INCLUDES = -I../hidapi -I/usr/local/include LDFLAGS = -L/usr/local/lib LIBS = -lusb -liconv -pthread # Console Test Program hidtest: $(OBJS) $(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS) # Shared Libs libhidapi.so: $(COBJS) $(CC) $(LDFLAGS) -shared -Wl,-soname,$@.0 $^ -o $@ $(LIBS) # Objects $(COBJS): %.o: %.c $(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@ $(CPPOBJS): %.o: %.cpp $(CXX) $(CXXFLAGS) -c $(INCLUDES) $< -o $@ clean: rm -f $(OBJS) hidtest libhidapi.so ../hidtest/hidtest.o .PHONY: clean libs openzwave-1.6.1914/cpp/hidapi/libusb/Makefile.am0000644000175200017520000000075514032142455016263 00000000000000AM_CPPFLAGS = -I$(top_srcdir)/hidapi $(CFLAGS_LIBUSB) if OS_LINUX lib_LTLIBRARIES = libhidapi-libusb.la libhidapi_libusb_la_SOURCES = hid.c libhidapi_libusb_la_LDFLAGS = $(LTLDFLAGS) libhidapi_libusb_la_LIBADD = $(LIBS_LIBUSB) endif if OS_FREEBSD lib_LTLIBRARIES = libhidapi.la libhidapi_la_SOURCES = hid.c libhidapi_la_LDFLAGS = $(LTLDFLAGS) libhidapi_la_LIBADD = $(LIBS_LIBUSB) endif hdrdir = $(includedir)/hidapi hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h EXTRA_DIST = Makefile-manual openzwave-1.6.1914/cpp/hidapi/libusb/hid.c0000644000175200017520000011351114032142455015132 00000000000000/******************************************************* HIDAPI - Multi-Platform library for communication with HID devices. Alan Ott Signal 11 Software 8/22/2009 Linux Version - 6/2/2010 Libusb Version - 8/13/2010 FreeBSD Version - 11/1/2011 Copyright 2009, All Rights Reserved. At the discretion of the user of this library, this software may be licensed under the terms of the GNU Public License v3, a BSD-Style license, or the original HIDAPI license as outlined in the LICENSE.txt, LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt files located at the root of the source distribution. These files may also be found in the public source code repository located at: http://github.com/signal11/hidapi . ********************************************************/ #define _GNU_SOURCE /* needed for wcsdup() before glibc 2.10 */ /* C */ #include #include #include #include #include #include /* Unix */ #include #include #include #include #include #include #include #include /* GNU / LibUSB */ #include "libusb.h" #include "iconv.h" #include "hidapi.h" #ifdef __cplusplus extern "C" { #endif #ifdef DEBUG_PRINTF #define LOG(...) fprintf(stderr, __VA_ARGS__) #else #define LOG(...) do {} while (0) #endif #if defined(__NetBSD__) || defined(__sun) #define ICONV_CONST const #else #define ICONV_CONST #endif #ifndef __FreeBSD__ #define DETACH_KERNEL_DRIVER #else /* Get __FreeBSD_version */ #include #endif /* Uncomment to enable the retrieval of Usage and Usage Page in hid_enumerate(). Warning, on platforms different from FreeBSD this is very invasive as it requires the detach and re-attach of the kernel driver. See comments inside hid_enumerate(). libusb HIDAPI programs are encouraged to use the interface number instead to differentiate between interfaces on a composite HID device. */ /*#define INVASIVE_GET_USAGE*/ /* Linked List of input reports received from the device. */ struct input_report { uint8_t *data; size_t len; struct input_report *next; }; struct hid_device_ { /* Handle to the actual device. */ libusb_device_handle *device_handle; /* Endpoint information */ int input_endpoint; int output_endpoint; int input_ep_max_packet_size; /* The interface number of the HID */ int interface; /* Indexes of Strings */ int manufacturer_index; int product_index; int serial_index; /* Whether blocking reads are used */ int blocking; /* boolean */ /* Read thread objects */ pthread_t thread; pthread_mutex_t mutex; /* Protects input_reports */ pthread_cond_t condition; pthread_barrier_t barrier; /* Ensures correct startup sequence */ int shutdown_thread; struct libusb_transfer *transfer; /* List of received input reports. */ struct input_report *input_reports; }; static libusb_context *usb_context = NULL; uint16_t get_usb_code_for_current_locale(void); static int return_data(hid_device *dev, unsigned char *data, size_t length); static hid_device *new_hid_device(void) { hid_device *dev = calloc(1, sizeof(hid_device)); dev->blocking = 1; pthread_mutex_init(&dev->mutex, NULL); pthread_cond_init(&dev->condition, NULL); pthread_barrier_init(&dev->barrier, NULL, 2); return dev; } static void free_hid_device(hid_device *dev) { /* Clean up the thread objects */ pthread_barrier_destroy(&dev->barrier); pthread_cond_destroy(&dev->condition); pthread_mutex_destroy(&dev->mutex); /* Free the device itself */ free(dev); } #if 0 /*TODO: Implement this funciton on hidapi/libusb.. */ static void register_error(hid_device *device, const char *op) { } #endif #ifdef INVASIVE_GET_USAGE /* Get bytes from a HID Report Descriptor. Only call with a num_bytes of 0, 1, 2, or 4. */ static uint32_t get_bytes(uint8_t *rpt, size_t len, size_t num_bytes, size_t cur) { /* Return if there aren't enough bytes. */ if (cur + num_bytes >= len) return 0; if (num_bytes == 0) return 0; else if (num_bytes == 1) { return rpt[cur+1]; } else if (num_bytes == 2) { return (rpt[cur+2] * 256 + rpt[cur+1]); } else if (num_bytes == 4) { return (rpt[cur+4] * 0x01000000 + rpt[cur+3] * 0x00010000 + rpt[cur+2] * 0x00000100 + rpt[cur+1] * 0x00000001); } else return 0; } /* Retrieves the device's Usage Page and Usage from the report descriptor. The algorithm is simple, as it just returns the first Usage and Usage Page that it finds in the descriptor. The return value is 0 on success and -1 on failure. */ static int get_usage(uint8_t *report_descriptor, size_t size, unsigned short *usage_page, unsigned short *usage) { unsigned int i = 0; int size_code; int data_len, key_size; int usage_found = 0, usage_page_found = 0; while (i < size) { int key = report_descriptor[i]; int key_cmd = key & 0xfc; //printf("key: %02hhx\n", key); if ((key & 0xf0) == 0xf0) { /* This is a Long Item. The next byte contains the length of the data section (value) for this key. See the HID specification, version 1.11, section 6.2.2.3, titled "Long Items." */ if (i+1 < size) data_len = report_descriptor[i+1]; else data_len = 0; /* malformed report */ key_size = 3; } else { /* This is a Short Item. The bottom two bits of the key contain the size code for the data section (value) for this key. Refer to the HID specification, version 1.11, section 6.2.2.2, titled "Short Items." */ size_code = key & 0x3; switch (size_code) { case 0: case 1: case 2: data_len = size_code; break; case 3: data_len = 4; break; default: /* Can't ever happen since size_code is & 0x3 */ data_len = 0; break; }; key_size = 1; } if (key_cmd == 0x4) { *usage_page = get_bytes(report_descriptor, size, data_len, i); usage_page_found = 1; //printf("Usage Page: %x\n", (uint32_t)*usage_page); } if (key_cmd == 0x8) { *usage = get_bytes(report_descriptor, size, data_len, i); usage_found = 1; //printf("Usage: %x\n", (uint32_t)*usage); } if (usage_page_found && usage_found) return 0; /* success */ /* Skip over this key and it's associated data */ i += data_len + key_size; } return -1; /* failure */ } #endif /* INVASIVE_GET_USAGE */ #if defined(__FreeBSD__) && __FreeBSD_version < 1000000 /* The FreeBSD version of libusb doesn't have this funciton. In mainline libusb, it's inlined in libusb.h. This function will bear a striking resemblence to that one, because there's about one way to code it. Note that the data parameter is Unicode in UTF-16LE encoding. Return value is the number of bytes in data, or LIBUSB_ERROR_*. */ static inline int libusb_get_string_descriptor(libusb_device_handle *dev, uint8_t descriptor_index, uint16_t lang_id, unsigned char *data, int length) { return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN | 0x0, /* Endpoint 0 IN */ LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | descriptor_index, lang_id, data, (uint16_t) length, 1000); } #endif /* Get the first language the device says it reports. This comes from USB string #0. */ static uint16_t get_first_language(libusb_device_handle *dev) { uint16_t buf[32]; int len; /* Get the string from libusb. */ len = libusb_get_string_descriptor(dev, 0x0, /* String ID */ 0x0, /* Language */ (unsigned char*)buf, sizeof(buf)); if (len < 4) return 0x0; return buf[1]; /* First two bytes are len and descriptor type. */ } static int is_language_supported(libusb_device_handle *dev, uint16_t lang) { uint16_t buf[32]; int len; int i; /* Get the string from libusb. */ len = libusb_get_string_descriptor(dev, 0x0, /* String ID */ 0x0, /* Language */ (unsigned char*)buf, sizeof(buf)); if (len < 4) return 0x0; len /= 2; /* language IDs are two-bytes each. */ /* Start at index 1 because there are two bytes of protocol data. */ for (i = 1; i < len; i++) { if (buf[i] == lang) return 1; } return 0; } /* This function returns a newly allocated wide string containing the USB device string numbered by the index. The returned string must be freed by using free(). */ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx) { char buf[512]; int len; wchar_t *str = NULL; wchar_t wbuf[256]; /* iconv variables */ iconv_t ic; size_t inbytes; size_t outbytes; size_t res; char *inptr; char *outptr; /* Determine which language to use. */ uint16_t lang; lang = get_usb_code_for_current_locale(); if (!is_language_supported(dev, lang)) lang = get_first_language(dev); /* Get the string from libusb. */ len = libusb_get_string_descriptor(dev, idx, lang, (unsigned char*)buf, sizeof(buf)); if (len < 0) return NULL; /* buf does not need to be explicitly NULL-terminated because it is only passed into iconv() which does not need it. */ /* Initialize iconv. */ ic = iconv_open("WCHAR_T", "UTF-16LE"); if (ic == (iconv_t)-1) { LOG("iconv_open() failed\n"); return NULL; } /* Convert to native wchar_t (UTF-32 on glibc/BSD systems). Skip the first character (2-bytes). */ inptr = buf+2; inbytes = len-2; outptr = (char*) wbuf; outbytes = sizeof(wbuf); res = iconv(ic, (ICONV_CONST char **)&inptr, &inbytes, &outptr, &outbytes); if (res == (size_t)-1) { LOG("iconv() failed\n"); goto err; } /* Write the terminating NULL. */ wbuf[sizeof(wbuf)/sizeof(wbuf[0])-1] = 0x00000000; if (outbytes >= sizeof(wbuf[0])) *((wchar_t*)outptr) = 0x00000000; /* Allocate and copy the string. */ str = wcsdup(wbuf); err: iconv_close(ic); return str; } static char *make_path(libusb_device *dev, int interface_number) { char str[64]; snprintf(str, sizeof(str), "%04x:%04x:%02x", libusb_get_bus_number(dev), libusb_get_device_address(dev), interface_number); str[sizeof(str)-1] = '\0'; return strdup(str); } int HID_API_EXPORT hid_init(void) { if (!usb_context) { const char *locale; /* Init Libusb */ if (libusb_init(&usb_context)) return -1; /* Set the locale if it's not set. */ locale = setlocale(LC_CTYPE, NULL); if (!locale) setlocale(LC_CTYPE, ""); } return 0; } int HID_API_EXPORT hid_exit(void) { if (usb_context) { libusb_exit(usb_context); usb_context = NULL; } return 0; } struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) { libusb_device **devs; libusb_device *dev; libusb_device_handle *handle; ssize_t num_devs; int i = 0; struct hid_device_info *root = NULL; /* return object */ struct hid_device_info *cur_dev = NULL; hid_init(); num_devs = libusb_get_device_list(usb_context, &devs); if (num_devs < 0) return NULL; while ((dev = devs[i++]) != NULL) { struct libusb_device_descriptor desc; struct libusb_config_descriptor *conf_desc = NULL; int j, k; int interface_num = 0; int res = libusb_get_device_descriptor(dev, &desc); unsigned short dev_vid = desc.idVendor; unsigned short dev_pid = desc.idProduct; /* HID's are defined at the interface level. */ if (desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE) continue; res = libusb_get_active_config_descriptor(dev, &conf_desc); if (res < 0) libusb_get_config_descriptor(dev, 0, &conf_desc); if (conf_desc) { for (j = 0; j < conf_desc->bNumInterfaces; j++) { const struct libusb_interface *intf = &conf_desc->interface[j]; for (k = 0; k < intf->num_altsetting; k++) { const struct libusb_interface_descriptor *intf_desc; intf_desc = &intf->altsetting[k]; if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) { interface_num = intf_desc->bInterfaceNumber; /* Check the VID/PID against the arguments */ if ((vendor_id == 0x0 || vendor_id == dev_vid) && (product_id == 0x0 || product_id == dev_pid)) { struct hid_device_info *tmp; /* VID/PID match. Create the record. */ tmp = calloc(1, sizeof(struct hid_device_info)); if (cur_dev) { cur_dev->next = tmp; } else { root = tmp; } cur_dev = tmp; /* Fill out the record */ cur_dev->next = NULL; cur_dev->path = make_path(dev, interface_num); res = libusb_open(dev, &handle); if (res >= 0) { /* Serial Number */ if (desc.iSerialNumber > 0) cur_dev->serial_number = get_usb_string(handle, desc.iSerialNumber); /* Manufacturer and Product strings */ if (desc.iManufacturer > 0) cur_dev->manufacturer_string = get_usb_string(handle, desc.iManufacturer); if (desc.iProduct > 0) cur_dev->product_string = get_usb_string(handle, desc.iProduct); #ifdef INVASIVE_GET_USAGE { /* This section is removed because it is too invasive on the system. Getting a Usage Page and Usage requires parsing the HID Report descriptor. Getting a HID Report descriptor involves claiming the interface. Claiming the interface involves detaching the kernel driver. Detaching the kernel driver is hard on the system because it will unclaim interfaces (if another app has them claimed) and the re-attachment of the driver will sometimes change /dev entry names. It is for these reasons that this section is #if 0. For composite devices, use the interface field in the hid_device_info struct to distinguish between interfaces. */ unsigned char data[256]; #ifdef DETACH_KERNEL_DRIVER int detached = 0; /* Usage Page and Usage */ res = libusb_kernel_driver_active(handle, interface_num); if (res == 1) { res = libusb_detach_kernel_driver(handle, interface_num); if (res < 0) LOG("Couldn't detach kernel driver, even though a kernel driver was attached."); else detached = 1; } #endif res = libusb_claim_interface(handle, interface_num); if (res >= 0) { /* Get the HID Report Descriptor. */ res = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8)|interface_num, 0, data, sizeof(data), 5000); if (res >= 0) { unsigned short page=0, usage=0; /* Parse the usage and usage page out of the report descriptor. */ get_usage(data, res, &page, &usage); cur_dev->usage_page = page; cur_dev->usage = usage; } else LOG("libusb_control_transfer() for getting the HID report failed with %d\n", res); /* Release the interface */ res = libusb_release_interface(handle, interface_num); if (res < 0) LOG("Can't release the interface.\n"); } else LOG("Can't claim interface %d\n", res); #ifdef DETACH_KERNEL_DRIVER /* Re-attach kernel driver if necessary. */ if (detached) { res = libusb_attach_kernel_driver(handle, interface_num); if (res < 0) LOG("Couldn't re-attach kernel driver.\n"); } #endif } #endif /* INVASIVE_GET_USAGE */ libusb_close(handle); } /* VID/PID */ cur_dev->vendor_id = dev_vid; cur_dev->product_id = dev_pid; /* Release Number */ cur_dev->release_number = desc.bcdDevice; /* Interface Number */ cur_dev->interface_number = interface_num; } } } /* altsettings */ } /* interfaces */ libusb_free_config_descriptor(conf_desc); } } libusb_free_device_list(devs, 1); return root; } void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs) { struct hid_device_info *d = devs; while (d) { struct hid_device_info *next = d->next; free(d->path); free(d->serial_number); free(d->manufacturer_string); free(d->product_string); free(d); d = next; } } hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) { struct hid_device_info *devs, *cur_dev; const char *path_to_open = NULL; hid_device *handle = NULL; devs = hid_enumerate(vendor_id, product_id); cur_dev = devs; while (cur_dev) { if (cur_dev->vendor_id == vendor_id && cur_dev->product_id == product_id) { if (serial_number) { if (wcscmp(serial_number, cur_dev->serial_number) == 0) { path_to_open = cur_dev->path; break; } } else { path_to_open = cur_dev->path; break; } } cur_dev = cur_dev->next; } if (path_to_open) { /* Open the device */ handle = hid_open_path(path_to_open); } hid_free_enumeration(devs); return handle; } static void read_callback(struct libusb_transfer *transfer) { hid_device *dev = transfer->user_data; int res; if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { struct input_report *rpt = malloc(sizeof(*rpt)); rpt->data = malloc(transfer->actual_length); memcpy(rpt->data, transfer->buffer, transfer->actual_length); rpt->len = transfer->actual_length; rpt->next = NULL; pthread_mutex_lock(&dev->mutex); /* Attach the new report object to the end of the list. */ if (dev->input_reports == NULL) { /* The list is empty. Put it at the root. */ dev->input_reports = rpt; pthread_cond_signal(&dev->condition); } else { /* Find the end of the list and attach. */ struct input_report *cur = dev->input_reports; int num_queued = 0; while (cur->next != NULL) { cur = cur->next; num_queued++; } cur->next = rpt; /* Pop one off if we've reached 30 in the queue. This way we don't grow forever if the user never reads anything from the device. */ if (num_queued > 30) { return_data(dev, NULL, 0); } } pthread_mutex_unlock(&dev->mutex); } else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { dev->shutdown_thread = 1; return; } else if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) { dev->shutdown_thread = 1; return; } else if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) { //LOG("Timeout (normal)\n"); } else { LOG("Unknown transfer code: %d\n", transfer->status); } /* Re-submit the transfer object. */ res = libusb_submit_transfer(transfer); if (res != 0) { LOG("Unable to submit URB. libusb error code: %d\n", res); dev->shutdown_thread = 1; } } static void *read_thread(void *param) { hid_device *dev = param; unsigned char *buf; const size_t length = dev->input_ep_max_packet_size; /* Set up the transfer object. */ buf = malloc(length); dev->transfer = libusb_alloc_transfer(0); libusb_fill_interrupt_transfer(dev->transfer, dev->device_handle, dev->input_endpoint, buf, length, read_callback, dev, 5000/*timeout*/); /* Make the first submission. Further submissions are made from inside read_callback() */ libusb_submit_transfer(dev->transfer); /* Notify the main thread that the read thread is up and running. */ pthread_barrier_wait(&dev->barrier); /* Handle all the events. */ while (!dev->shutdown_thread) { int res; res = libusb_handle_events(usb_context); if (res < 0) { /* There was an error. */ LOG("read_thread(): libusb reports error # %d\n", res); /* Break out of this loop only on fatal error.*/ if (res != LIBUSB_ERROR_BUSY && res != LIBUSB_ERROR_TIMEOUT && res != LIBUSB_ERROR_OVERFLOW && res != LIBUSB_ERROR_INTERRUPTED) { break; } } } /* Cancel any transfer that may be pending. This call will fail if no transfers are pending, but that's OK. */ if (libusb_cancel_transfer(dev->transfer) == 0) { /* The transfer was cancelled, so wait for its completion. */ libusb_handle_events(usb_context); } /* Now that the read thread is stopping, Wake any threads which are waiting on data (in hid_read_timeout()). Do this under a mutex to make sure that a thread which is about to go to sleep waiting on the condition acutally will go to sleep before the condition is signaled. */ pthread_mutex_lock(&dev->mutex); pthread_cond_broadcast(&dev->condition); pthread_mutex_unlock(&dev->mutex); /* The dev->transfer->buffer and dev->transfer objects are cleaned up in hid_close(). They are not cleaned up here because this thread could end either due to a disconnect or due to a user call to hid_close(). In both cases the objects can be safely cleaned up after the call to pthread_join() (in hid_close()), but since hid_close() calls libusb_cancel_transfer(), on these objects, they can not be cleaned up here. */ return NULL; } hid_device * HID_API_EXPORT hid_open_path(const char *path) { hid_device *dev = NULL; libusb_device **devs; libusb_device *usb_dev; int res; int d = 0; int good_open = 0; dev = new_hid_device(); hid_init(); libusb_get_device_list(usb_context, &devs); while ((usb_dev = devs[d++]) != NULL) { struct libusb_device_descriptor desc; struct libusb_config_descriptor *conf_desc = NULL; int i,j,k; libusb_get_device_descriptor(usb_dev, &desc); if (libusb_get_active_config_descriptor(usb_dev, &conf_desc) < 0) continue; for (j = 0; j < conf_desc->bNumInterfaces; j++) { const struct libusb_interface *intf = &conf_desc->interface[j]; for (k = 0; k < intf->num_altsetting; k++) { const struct libusb_interface_descriptor *intf_desc; intf_desc = &intf->altsetting[k]; if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) { char *dev_path = make_path(usb_dev, intf_desc->bInterfaceNumber); if (!strcmp(dev_path, path)) { /* Matched Paths. Open this device */ /* OPEN HERE */ res = libusb_open(usb_dev, &dev->device_handle); if (res < 0) { LOG("can't open device\n"); free(dev_path); break; } good_open = 1; #ifdef DETACH_KERNEL_DRIVER /* Detach the kernel driver, but only if the device is managed by the kernel */ if (libusb_kernel_driver_active(dev->device_handle, intf_desc->bInterfaceNumber) == 1) { res = libusb_detach_kernel_driver(dev->device_handle, intf_desc->bInterfaceNumber); if (res < 0) { libusb_close(dev->device_handle); LOG("Unable to detach Kernel Driver\n"); free(dev_path); good_open = 0; break; } } #endif res = libusb_claim_interface(dev->device_handle, intf_desc->bInterfaceNumber); if (res < 0) { LOG("can't claim interface %d: %d\n", intf_desc->bInterfaceNumber, res); free(dev_path); libusb_close(dev->device_handle); good_open = 0; break; } /* Store off the string descriptor indexes */ dev->manufacturer_index = desc.iManufacturer; dev->product_index = desc.iProduct; dev->serial_index = desc.iSerialNumber; /* Store off the interface number */ dev->interface = intf_desc->bInterfaceNumber; /* Find the INPUT and OUTPUT endpoints. An OUTPUT endpoint is not required. */ for (i = 0; i < intf_desc->bNumEndpoints; i++) { const struct libusb_endpoint_descriptor *ep = &intf_desc->endpoint[i]; /* Determine the type and direction of this endpoint. */ int is_interrupt = (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_INTERRUPT; int is_output = (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT; int is_input = (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN; /* Decide whether to use it for intput or output. */ if (dev->input_endpoint == 0 && is_interrupt && is_input) { /* Use this endpoint for INPUT */ dev->input_endpoint = ep->bEndpointAddress; dev->input_ep_max_packet_size = ep->wMaxPacketSize; } if (dev->output_endpoint == 0 && is_interrupt && is_output) { /* Use this endpoint for OUTPUT */ dev->output_endpoint = ep->bEndpointAddress; } } pthread_create(&dev->thread, NULL, read_thread, dev); /* Wait here for the read thread to be initialized. */ pthread_barrier_wait(&dev->barrier); } free(dev_path); } } } libusb_free_config_descriptor(conf_desc); } libusb_free_device_list(devs, 1); /* If we have a good handle, return it. */ if (good_open) { return dev; } else { /* Unable to open any devices. */ free_hid_device(dev); return NULL; } } int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) { int res; int report_number = data[0]; int skipped_report_id = 0; if (report_number == 0x0) { data++; length--; skipped_report_id = 1; } if (dev->output_endpoint <= 0) { /* No interrput out endpoint. Use the Control Endpoint */ res = libusb_control_transfer(dev->device_handle, LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT, 0x09/*HID Set_Report*/, (2/*HID output*/ << 8) | report_number, dev->interface, (unsigned char *)data, length, 1000/*timeout millis*/); if (res < 0) return -1; if (skipped_report_id) length++; return length; } else { /* Use the interrupt out endpoint */ int actual_length; res = libusb_interrupt_transfer(dev->device_handle, dev->output_endpoint, (unsigned char*)data, length, &actual_length, 1000); if (res < 0) return -1; if (skipped_report_id) actual_length++; return actual_length; } } /* Helper function, to simplify hid_read(). This should be called with dev->mutex locked. */ static int return_data(hid_device *dev, unsigned char *data, size_t length) { /* Copy the data out of the linked list item (rpt) into the return buffer (data), and delete the liked list item. */ struct input_report *rpt = dev->input_reports; size_t len = (length < rpt->len)? length: rpt->len; if (len > 0) memcpy(data, rpt->data, len); dev->input_reports = rpt->next; free(rpt->data); free(rpt); return len; } static void cleanup_mutex(void *param) { hid_device *dev = param; pthread_mutex_unlock(&dev->mutex); } int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) { int bytes_read = -1; #if 0 int transferred; int res = libusb_interrupt_transfer(dev->device_handle, dev->input_endpoint, data, length, &transferred, 5000); LOG("transferred: %d\n", transferred); return transferred; #endif pthread_mutex_lock(&dev->mutex); pthread_cleanup_push(&cleanup_mutex, dev); /* There's an input report queued up. Return it. */ if (dev->input_reports) { /* Return the first one */ bytes_read = return_data(dev, data, length); goto ret; } if (dev->shutdown_thread) { /* This means the device has been disconnected. An error code of -1 should be returned. */ bytes_read = -1; goto ret; } if (milliseconds == -1) { /* Blocking */ while (!dev->input_reports && !dev->shutdown_thread) { pthread_cond_wait(&dev->condition, &dev->mutex); } if (dev->input_reports) { bytes_read = return_data(dev, data, length); } } else if (milliseconds > 0) { /* Non-blocking, but called with timeout. */ int res; struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += milliseconds / 1000; ts.tv_nsec += (milliseconds % 1000) * 1000000; if (ts.tv_nsec >= 1000000000L) { ts.tv_sec++; ts.tv_nsec -= 1000000000L; } while (!dev->input_reports && !dev->shutdown_thread) { res = pthread_cond_timedwait(&dev->condition, &dev->mutex, &ts); if (res == 0) { if (dev->input_reports) { bytes_read = return_data(dev, data, length); break; } /* If we're here, there was a spurious wake up or the read thread was shutdown. Run the loop again (ie: don't break). */ } else if (res == ETIMEDOUT) { /* Timed out. */ bytes_read = 0; break; } else { /* Error. */ bytes_read = -1; break; } } } else { /* Purely non-blocking */ bytes_read = 0; } ret: pthread_mutex_unlock(&dev->mutex); pthread_cleanup_pop(0); return bytes_read; } int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length) { return hid_read_timeout(dev, data, length, dev->blocking ? -1 : 0); } int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) { dev->blocking = !nonblock; return 0; } int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) { int res = -1; int skipped_report_id = 0; int report_number = data[0]; if (report_number == 0x0) { data++; length--; skipped_report_id = 1; } res = libusb_control_transfer(dev->device_handle, LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT, 0x09/*HID set_report*/, (3/*HID feature*/ << 8) | report_number, dev->interface, (unsigned char *)data, length, 1000/*timeout millis*/); if (res < 0) return -1; /* Account for the report ID */ if (skipped_report_id) length++; return length; } int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) { int res = -1; int skipped_report_id = 0; int report_number = data[0]; if (report_number == 0x0) { /* Offset the return buffer by 1, so that the report ID will remain in byte 0. */ data++; length--; skipped_report_id = 1; } res = libusb_control_transfer(dev->device_handle, LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_IN, 0x01/*HID get_report*/, (3/*HID feature*/ << 8) | report_number, dev->interface, (unsigned char *)data, length, 1000/*timeout millis*/); if (res < 0) return -1; if (skipped_report_id) res++; return res; } void HID_API_EXPORT hid_close(hid_device *dev) { if (!dev) return; /* Cause read_thread() to stop. */ dev->shutdown_thread = 1; libusb_cancel_transfer(dev->transfer); /* Wait for read_thread() to end. */ pthread_join(dev->thread, NULL); /* Clean up the Transfer objects allocated in read_thread(). */ free(dev->transfer->buffer); libusb_free_transfer(dev->transfer); /* release the interface */ libusb_release_interface(dev->device_handle, dev->interface); /* Close the handle */ libusb_close(dev->device_handle); /* Clear out the queue of received reports. */ pthread_mutex_lock(&dev->mutex); while (dev->input_reports) { return_data(dev, NULL, 0); } pthread_mutex_unlock(&dev->mutex); free_hid_device(dev); } int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) { return hid_get_indexed_string(dev, dev->manufacturer_index, string, maxlen); } int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) { return hid_get_indexed_string(dev, dev->product_index, string, maxlen); } int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) { return hid_get_indexed_string(dev, dev->serial_index, string, maxlen); } int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) { wchar_t *str; str = get_usb_string(dev->device_handle, string_index); if (str) { wcsncpy(string, str, maxlen); string[maxlen-1] = L'\0'; free(str); return 0; } else return -1; } HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) { return NULL; } struct lang_map_entry { const char *name; const char *string_code; uint16_t usb_code; }; #define LANG(name,code,usb_code) { name, code, usb_code } static struct lang_map_entry lang_map[] = { LANG("Afrikaans", "af", 0x0436), LANG("Albanian", "sq", 0x041C), LANG("Arabic - United Arab Emirates", "ar_ae", 0x3801), LANG("Arabic - Bahrain", "ar_bh", 0x3C01), LANG("Arabic - Algeria", "ar_dz", 0x1401), LANG("Arabic - Egypt", "ar_eg", 0x0C01), LANG("Arabic - Iraq", "ar_iq", 0x0801), LANG("Arabic - Jordan", "ar_jo", 0x2C01), LANG("Arabic - Kuwait", "ar_kw", 0x3401), LANG("Arabic - Lebanon", "ar_lb", 0x3001), LANG("Arabic - Libya", "ar_ly", 0x1001), LANG("Arabic - Morocco", "ar_ma", 0x1801), LANG("Arabic - Oman", "ar_om", 0x2001), LANG("Arabic - Qatar", "ar_qa", 0x4001), LANG("Arabic - Saudi Arabia", "ar_sa", 0x0401), LANG("Arabic - Syria", "ar_sy", 0x2801), LANG("Arabic - Tunisia", "ar_tn", 0x1C01), LANG("Arabic - Yemen", "ar_ye", 0x2401), LANG("Armenian", "hy", 0x042B), LANG("Azeri - Latin", "az_az", 0x042C), LANG("Azeri - Cyrillic", "az_az", 0x082C), LANG("Basque", "eu", 0x042D), LANG("Belarusian", "be", 0x0423), LANG("Bulgarian", "bg", 0x0402), LANG("Catalan", "ca", 0x0403), LANG("Chinese - China", "zh_cn", 0x0804), LANG("Chinese - Hong Kong SAR", "zh_hk", 0x0C04), LANG("Chinese - Macau SAR", "zh_mo", 0x1404), LANG("Chinese - Singapore", "zh_sg", 0x1004), LANG("Chinese - Taiwan", "zh_tw", 0x0404), LANG("Croatian", "hr", 0x041A), LANG("Czech", "cs", 0x0405), LANG("Danish", "da", 0x0406), LANG("Dutch - Netherlands", "nl_nl", 0x0413), LANG("Dutch - Belgium", "nl_be", 0x0813), LANG("English - Australia", "en_au", 0x0C09), LANG("English - Belize", "en_bz", 0x2809), LANG("English - Canada", "en_ca", 0x1009), LANG("English - Caribbean", "en_cb", 0x2409), LANG("English - Ireland", "en_ie", 0x1809), LANG("English - Jamaica", "en_jm", 0x2009), LANG("English - New Zealand", "en_nz", 0x1409), LANG("English - Phillippines", "en_ph", 0x3409), LANG("English - Southern Africa", "en_za", 0x1C09), LANG("English - Trinidad", "en_tt", 0x2C09), LANG("English - Great Britain", "en_gb", 0x0809), LANG("English - United States", "en_us", 0x0409), LANG("Estonian", "et", 0x0425), LANG("Farsi", "fa", 0x0429), LANG("Finnish", "fi", 0x040B), LANG("Faroese", "fo", 0x0438), LANG("French - France", "fr_fr", 0x040C), LANG("French - Belgium", "fr_be", 0x080C), LANG("French - Canada", "fr_ca", 0x0C0C), LANG("French - Luxembourg", "fr_lu", 0x140C), LANG("French - Switzerland", "fr_ch", 0x100C), LANG("Gaelic - Ireland", "gd_ie", 0x083C), LANG("Gaelic - Scotland", "gd", 0x043C), LANG("German - Germany", "de_de", 0x0407), LANG("German - Austria", "de_at", 0x0C07), LANG("German - Liechtenstein", "de_li", 0x1407), LANG("German - Luxembourg", "de_lu", 0x1007), LANG("German - Switzerland", "de_ch", 0x0807), LANG("Greek", "el", 0x0408), LANG("Hebrew", "he", 0x040D), LANG("Hindi", "hi", 0x0439), LANG("Hungarian", "hu", 0x040E), LANG("Icelandic", "is", 0x040F), LANG("Indonesian", "id", 0x0421), LANG("Italian - Italy", "it_it", 0x0410), LANG("Italian - Switzerland", "it_ch", 0x0810), LANG("Japanese", "ja", 0x0411), LANG("Korean", "ko", 0x0412), LANG("Latvian", "lv", 0x0426), LANG("Lithuanian", "lt", 0x0427), LANG("F.Y.R.O. Macedonia", "mk", 0x042F), LANG("Malay - Malaysia", "ms_my", 0x043E), LANG("Malay – Brunei", "ms_bn", 0x083E), LANG("Maltese", "mt", 0x043A), LANG("Marathi", "mr", 0x044E), LANG("Norwegian - Bokml", "no_no", 0x0414), LANG("Norwegian - Nynorsk", "no_no", 0x0814), LANG("Polish", "pl", 0x0415), LANG("Portuguese - Portugal", "pt_pt", 0x0816), LANG("Portuguese - Brazil", "pt_br", 0x0416), LANG("Raeto-Romance", "rm", 0x0417), LANG("Romanian - Romania", "ro", 0x0418), LANG("Romanian - Republic of Moldova", "ro_mo", 0x0818), LANG("Russian", "ru", 0x0419), LANG("Russian - Republic of Moldova", "ru_mo", 0x0819), LANG("Sanskrit", "sa", 0x044F), LANG("Serbian - Cyrillic", "sr_sp", 0x0C1A), LANG("Serbian - Latin", "sr_sp", 0x081A), LANG("Setsuana", "tn", 0x0432), LANG("Slovenian", "sl", 0x0424), LANG("Slovak", "sk", 0x041B), LANG("Sorbian", "sb", 0x042E), LANG("Spanish - Spain (Traditional)", "es_es", 0x040A), LANG("Spanish - Argentina", "es_ar", 0x2C0A), LANG("Spanish - Bolivia", "es_bo", 0x400A), LANG("Spanish - Chile", "es_cl", 0x340A), LANG("Spanish - Colombia", "es_co", 0x240A), LANG("Spanish - Costa Rica", "es_cr", 0x140A), LANG("Spanish - Dominican Republic", "es_do", 0x1C0A), LANG("Spanish - Ecuador", "es_ec", 0x300A), LANG("Spanish - Guatemala", "es_gt", 0x100A), LANG("Spanish - Honduras", "es_hn", 0x480A), LANG("Spanish - Mexico", "es_mx", 0x080A), LANG("Spanish - Nicaragua", "es_ni", 0x4C0A), LANG("Spanish - Panama", "es_pa", 0x180A), LANG("Spanish - Peru", "es_pe", 0x280A), LANG("Spanish - Puerto Rico", "es_pr", 0x500A), LANG("Spanish - Paraguay", "es_py", 0x3C0A), LANG("Spanish - El Salvador", "es_sv", 0x440A), LANG("Spanish - Uruguay", "es_uy", 0x380A), LANG("Spanish - Venezuela", "es_ve", 0x200A), LANG("Southern Sotho", "st", 0x0430), LANG("Swahili", "sw", 0x0441), LANG("Swedish - Sweden", "sv_se", 0x041D), LANG("Swedish - Finland", "sv_fi", 0x081D), LANG("Tamil", "ta", 0x0449), LANG("Tatar", "tt", 0X0444), LANG("Thai", "th", 0x041E), LANG("Turkish", "tr", 0x041F), LANG("Tsonga", "ts", 0x0431), LANG("Ukrainian", "uk", 0x0422), LANG("Urdu", "ur", 0x0420), LANG("Uzbek - Cyrillic", "uz_uz", 0x0843), LANG("Uzbek – Latin", "uz_uz", 0x0443), LANG("Vietnamese", "vi", 0x042A), LANG("Xhosa", "xh", 0x0434), LANG("Yiddish", "yi", 0x043D), LANG("Zulu", "zu", 0x0435), LANG(NULL, NULL, 0x0), }; uint16_t get_usb_code_for_current_locale(void) { char *locale; char search_string[64]; char *ptr; struct lang_map_entry *lang; /* Get the current locale. */ locale = setlocale(0, NULL); if (!locale) return 0x0; /* Make a copy of the current locale string. */ strncpy(search_string, locale, sizeof(search_string)); search_string[sizeof(search_string)-1] = '\0'; /* Chop off the encoding part, and make it lower case. */ ptr = search_string; while (*ptr) { *ptr = tolower(*ptr); if (*ptr == '.') { *ptr = '\0'; break; } ptr++; } /* Find the entry which matches the string code of our locale. */ lang = lang_map; while (lang->string_code) { if (!strcmp(lang->string_code, search_string)) { return lang->usb_code; } lang++; } /* There was no match. Find with just the language only. */ /* Chop off the variant. Chop it off at the '_'. */ ptr = search_string; while (*ptr) { *ptr = tolower(*ptr); if (*ptr == '_') { *ptr = '\0'; break; } ptr++; } #if 0 /* TODO: Do we need this? */ /* Find the entry which matches the string code of our language. */ lang = lang_map; while (lang->string_code) { if (!strcmp(lang->string_code, search_string)) { return lang->usb_code; } lang++; } #endif /* Found nothing. */ return 0x0; } #ifdef __cplusplus } #endif openzwave-1.6.1914/cpp/hidapi/libusb/Makefile-manual0000644000175200017520000000036414032142455017136 00000000000000 OS=$(shell uname) ifeq ($(OS), Linux) FILE=Makefile.linux endif ifeq ($(OS), FreeBSD) FILE=Makefile.freebsd endif ifeq ($(FILE), ) all: $(error Your platform ${OS} is not supported by hidapi/libusb at this time.) endif include $(FILE) openzwave-1.6.1914/cpp/hidapi/mac/0000777000175200017520000000000014032143200013551 500000000000000openzwave-1.6.1914/cpp/hidapi/mac/.gitignore0000644000175200017520000000012414032142455015465 00000000000000Debug Release *.exp *.ilk *.lib *.suo *.vcproj.* *.ncb *.suo *.dll *.pdb *.o hidtestopenzwave-1.6.1914/cpp/hidapi/mac/Makefile.am0000644000175200017520000000035714032142455015541 00000000000000lib_LTLIBRARIES = libhidapi.la libhidapi_la_SOURCES = hid.c libhidapi_la_LDFLAGS = $(LTLDFLAGS) AM_CPPFLAGS = -I$(top_srcdir)/hidapi/ hdrdir = $(includedir)/hidapi hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h EXTRA_DIST = Makefile-manual openzwave-1.6.1914/cpp/hidapi/mac/hid.c0000644000175200017520000006731514032142455014424 00000000000000/******************************************************* HIDAPI - Multi-Platform library for communication with HID devices. Alan Ott Signal 11 Software 2010-07-03 Copyright 2010, All Rights Reserved. At the discretion of the user of this library, this software may be licensed under the terms of the GNU Public License v3, a BSD-Style license, or the original HIDAPI license as outlined in the LICENSE.txt, LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt files located at the root of the source distribution. These files may also be found in the public source code repository located at: http://github.com/signal11/hidapi . ********************************************************/ /* See Apple Technical Note TN2187 for details on IOHidManager. */ #include #include #include #include #include #include #include #include #include "hidapi.h" /* Barrier implementation because Mac OSX doesn't have pthread_barrier. It also doesn't have clock_gettime(). So much for POSIX and SUSv2. This implementation came from Brent Priddy and was posted on StackOverflow. It is used with his permission. */ typedef int pthread_barrierattr_t; typedef struct pthread_barrier { pthread_mutex_t mutex; pthread_cond_t cond; int count; int trip_count; } pthread_barrier_t; static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count) { if(count == 0) { errno = EINVAL; return -1; } if(pthread_mutex_init(&barrier->mutex, 0) < 0) { return -1; } if(pthread_cond_init(&barrier->cond, 0) < 0) { pthread_mutex_destroy(&barrier->mutex); return -1; } barrier->trip_count = count; barrier->count = 0; return 0; } static int pthread_barrier_destroy(pthread_barrier_t *barrier) { pthread_cond_destroy(&barrier->cond); pthread_mutex_destroy(&barrier->mutex); return 0; } static int pthread_barrier_wait(pthread_barrier_t *barrier) { pthread_mutex_lock(&barrier->mutex); ++(barrier->count); if(barrier->count >= barrier->trip_count) { barrier->count = 0; pthread_cond_broadcast(&barrier->cond); pthread_mutex_unlock(&barrier->mutex); return 1; } else { pthread_cond_wait(&barrier->cond, &(barrier->mutex)); pthread_mutex_unlock(&barrier->mutex); return 0; } } static int return_data(hid_device *dev, unsigned char *data, size_t length); /* Linked List of input reports received from the device. */ struct input_report { uint8_t *data; size_t len; struct input_report *next; }; struct hid_device_ { IOHIDDeviceRef device_handle; int blocking; int uses_numbered_reports; int disconnected; CFStringRef run_loop_mode; CFRunLoopRef run_loop; CFRunLoopSourceRef source; uint8_t *input_report_buf; CFIndex max_input_report_len; struct input_report *input_reports; pthread_t thread; pthread_mutex_t mutex; /* Protects input_reports */ pthread_cond_t condition; pthread_barrier_t barrier; /* Ensures correct startup sequence */ pthread_barrier_t shutdown_barrier; /* Ensures correct shutdown sequence */ int shutdown_thread; }; static hid_device *new_hid_device(void) { hid_device *dev = calloc(1, sizeof(hid_device)); dev->device_handle = NULL; dev->blocking = 1; dev->uses_numbered_reports = 0; dev->disconnected = 0; dev->run_loop_mode = NULL; dev->run_loop = NULL; dev->source = NULL; dev->input_report_buf = NULL; dev->input_reports = NULL; dev->shutdown_thread = 0; /* Thread objects */ pthread_mutex_init(&dev->mutex, NULL); pthread_cond_init(&dev->condition, NULL); pthread_barrier_init(&dev->barrier, NULL, 2); pthread_barrier_init(&dev->shutdown_barrier, NULL, 2); return dev; } static void free_hid_device(hid_device *dev) { if (!dev) return; /* Delete any input reports still left over. */ struct input_report *rpt = dev->input_reports; while (rpt) { struct input_report *next = rpt->next; free(rpt->data); free(rpt); rpt = next; } /* Free the string and the report buffer. The check for NULL is necessary here as CFRelease() doesn't handle NULL like free() and others do. */ if (dev->run_loop_mode) CFRelease(dev->run_loop_mode); if (dev->source) CFRelease(dev->source); free(dev->input_report_buf); /* Clean up the thread objects */ pthread_barrier_destroy(&dev->shutdown_barrier); pthread_barrier_destroy(&dev->barrier); pthread_cond_destroy(&dev->condition); pthread_mutex_destroy(&dev->mutex); /* Free the structure itself. */ free(dev); } static IOHIDManagerRef hid_mgr = 0x0; #if 0 static void register_error(hid_device *device, const char *op) { } #endif static int32_t get_int_property(IOHIDDeviceRef device, CFStringRef key) { CFTypeRef ref; int32_t value; ref = IOHIDDeviceGetProperty(device, key); if (ref) { if (CFGetTypeID(ref) == CFNumberGetTypeID()) { CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &value); return value; } } return 0; } static unsigned short get_vendor_id(IOHIDDeviceRef device) { return get_int_property(device, CFSTR(kIOHIDVendorIDKey)); } static unsigned short get_product_id(IOHIDDeviceRef device) { return get_int_property(device, CFSTR(kIOHIDProductIDKey)); } static int32_t get_location_id(IOHIDDeviceRef device) { return get_int_property(device, CFSTR(kIOHIDLocationIDKey)); } static int32_t get_max_report_length(IOHIDDeviceRef device) { return get_int_property(device, CFSTR(kIOHIDMaxInputReportSizeKey)); } static int get_string_property(IOHIDDeviceRef device, CFStringRef prop, wchar_t *buf, size_t len) { CFStringRef str; if (!len) return 0; str = IOHIDDeviceGetProperty(device, prop); buf[0] = 0; if (str) { CFIndex str_len = CFStringGetLength(str); CFRange range; CFIndex used_buf_len; CFIndex chars_copied; len --; range.location = 0; range.length = ((size_t)str_len > len)? len: (size_t)str_len; chars_copied = CFStringGetBytes(str, range, kCFStringEncodingUTF32LE, (char)'?', FALSE, (UInt8*)buf, len * sizeof(wchar_t), &used_buf_len); if (chars_copied == len) buf[len] = 0; /* len is decremented above */ else buf[chars_copied] = 0; return 0; } else return -1; } static int get_string_property_utf8(IOHIDDeviceRef device, CFStringRef prop, char *buf, size_t len) { CFStringRef str; if (!len) return 0; str = IOHIDDeviceGetProperty(device, prop); buf[0] = 0; if (str) { len--; CFIndex str_len = CFStringGetLength(str); CFRange range; range.location = 0; range.length = str_len; CFIndex used_buf_len; CFIndex chars_copied; chars_copied = CFStringGetBytes(str, range, kCFStringEncodingUTF8, (char)'?', FALSE, (UInt8*)buf, len, &used_buf_len); if (used_buf_len == len) buf[len] = 0; /* len is decremented above */ else buf[used_buf_len] = 0; return used_buf_len; } else return 0; } static int get_serial_number(IOHIDDeviceRef device, wchar_t *buf, size_t len) { return get_string_property(device, CFSTR(kIOHIDSerialNumberKey), buf, len); } static int get_manufacturer_string(IOHIDDeviceRef device, wchar_t *buf, size_t len) { return get_string_property(device, CFSTR(kIOHIDManufacturerKey), buf, len); } static int get_product_string(IOHIDDeviceRef device, wchar_t *buf, size_t len) { return get_string_property(device, CFSTR(kIOHIDProductKey), buf, len); } /* Implementation of wcsdup() for Mac. */ static wchar_t *dup_wcs(const wchar_t *s) { size_t len = wcslen(s); wchar_t *ret = malloc((len+1)*sizeof(wchar_t)); wcscpy(ret, s); return ret; } static int make_path(IOHIDDeviceRef device, char *buf, size_t len) { int res; unsigned short vid, pid; char transport[32]; int32_t location; buf[0] = '\0'; res = get_string_property_utf8( device, CFSTR(kIOHIDTransportKey), transport, sizeof(transport)); if (!res) return -1; location = get_location_id(device); vid = get_vendor_id(device); pid = get_product_id(device); res = snprintf(buf, len, "%s_%04hx_%04hx_%x", transport, vid, pid, location); buf[len-1] = '\0'; return res+1; } /* Initialize the IOHIDManager. Return 0 for success and -1 for failure. */ static int init_hid_manager(void) { /* Initialize all the HID Manager Objects */ hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); if (hid_mgr) { IOHIDManagerSetDeviceMatching(hid_mgr, NULL); IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); return 0; } return -1; } /* Initialize the IOHIDManager if necessary. This is the public function, and it is safe to call this function repeatedly. Return 0 for success and -1 for failure. */ int HID_API_EXPORT hid_init(void) { if (!hid_mgr) { return init_hid_manager(); } /* Already initialized. */ return 0; } int HID_API_EXPORT hid_exit(void) { if (hid_mgr) { /* Close the HID manager. */ IOHIDManagerClose(hid_mgr, kIOHIDOptionsTypeNone); CFRelease(hid_mgr); hid_mgr = NULL; } return 0; } static void process_pending_events(void) { SInt32 res; do { res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, FALSE); } while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut); } struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) { struct hid_device_info *root = NULL; /* return object */ struct hid_device_info *cur_dev = NULL; CFIndex num_devices; int i; /* Set up the HID Manager if it hasn't been done */ if (hid_init() < 0) return NULL; /* give the IOHIDManager a chance to update itself */ process_pending_events(); /* Get a list of the Devices */ CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr); /* Convert the list into a C array so we can iterate easily. */ num_devices = CFSetGetCount(device_set); IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef)); CFSetGetValues(device_set, (const void **) device_array); /* Iterate over each device, making an entry for it. */ for (i = 0; i < num_devices; i++) { unsigned short dev_vid; unsigned short dev_pid; #define BUF_LEN 256 wchar_t buf[BUF_LEN]; char cbuf[BUF_LEN]; IOHIDDeviceRef dev = device_array[i]; if (!dev) { continue; } dev_vid = get_vendor_id(dev); dev_pid = get_product_id(dev); /* Check the VID/PID against the arguments */ if ((vendor_id == 0x0 || vendor_id == dev_vid) && (product_id == 0x0 || product_id == dev_pid)) { struct hid_device_info *tmp; size_t len; /* VID/PID match. Create the record. */ tmp = malloc(sizeof(struct hid_device_info)); if (cur_dev) { cur_dev->next = tmp; } else { root = tmp; } cur_dev = tmp; /* Get the Usage Page and Usage for this device. */ cur_dev->usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey)); cur_dev->usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey)); /* Fill out the record */ cur_dev->next = NULL; len = make_path(dev, cbuf, sizeof(cbuf)); cur_dev->path = strdup(cbuf); /* Serial Number */ get_serial_number(dev, buf, BUF_LEN); cur_dev->serial_number = dup_wcs(buf); /* Manufacturer and Product strings */ get_manufacturer_string(dev, buf, BUF_LEN); cur_dev->manufacturer_string = dup_wcs(buf); get_product_string(dev, buf, BUF_LEN); cur_dev->product_string = dup_wcs(buf); /* VID/PID */ cur_dev->vendor_id = dev_vid; cur_dev->product_id = dev_pid; /* Release Number */ cur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey)); /* Interface Number (Unsupported on Mac)*/ cur_dev->interface_number = -1; } } free(device_array); CFRelease(device_set); return root; } void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs) { /* This function is identical to the Linux version. Platform independent. */ struct hid_device_info *d = devs; while (d) { struct hid_device_info *next = d->next; free(d->path); free(d->serial_number); free(d->manufacturer_string); free(d->product_string); free(d); d = next; } } hid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) { /* This function is identical to the Linux version. Platform independent. */ struct hid_device_info *devs, *cur_dev; const char *path_to_open = NULL; hid_device * handle = NULL; devs = hid_enumerate(vendor_id, product_id); cur_dev = devs; while (cur_dev) { if (cur_dev->vendor_id == vendor_id && cur_dev->product_id == product_id) { if (serial_number) { if (wcscmp(serial_number, cur_dev->serial_number) == 0) { path_to_open = cur_dev->path; break; } } else { path_to_open = cur_dev->path; break; } } cur_dev = cur_dev->next; } if (path_to_open) { /* Open the device */ handle = hid_open_path(path_to_open); } hid_free_enumeration(devs); return handle; } static void hid_device_removal_callback(void *context, IOReturn result, void *sender) { /* Stop the Run Loop for this device. */ hid_device *d = context; d->disconnected = 1; CFRunLoopStop(d->run_loop); } /* The Run Loop calls this function for each input report received. This function puts the data into a linked list to be picked up by hid_read(). */ static void hid_report_callback(void *context, IOReturn result, void *sender, IOHIDReportType report_type, uint32_t report_id, uint8_t *report, CFIndex report_length) { struct input_report *rpt; hid_device *dev = context; /* Make a new Input Report object */ rpt = calloc(1, sizeof(struct input_report)); rpt->data = calloc(1, report_length); memcpy(rpt->data, report, report_length); rpt->len = report_length; rpt->next = NULL; /* Lock this section */ pthread_mutex_lock(&dev->mutex); /* Attach the new report object to the end of the list. */ if (dev->input_reports == NULL) { /* The list is empty. Put it at the root. */ dev->input_reports = rpt; } else { /* Find the end of the list and attach. */ struct input_report *cur = dev->input_reports; int num_queued = 0; while (cur->next != NULL) { cur = cur->next; num_queued++; } cur->next = rpt; /* Pop one off if we've reached 30 in the queue. This way we don't grow forever if the user never reads anything from the device. */ if (num_queued > 30) { return_data(dev, NULL, 0); } } /* Signal a waiting thread that there is data. */ pthread_cond_signal(&dev->condition); /* Unlock */ pthread_mutex_unlock(&dev->mutex); } /* This gets called when the read_thred's run loop gets signaled by hid_close(), and serves to stop the read_thread's run loop. */ static void perform_signal_callback(void *context) { hid_device *dev = context; CFRunLoopStop(dev->run_loop); /*TODO: CFRunLoopGetCurrent()*/ } static void *read_thread(void *param) { hid_device *dev = param; SInt32 code; /* Move the device's run loop to this thread. */ IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev->run_loop_mode); /* Create the RunLoopSource which is used to signal the event loop to stop when hid_close() is called. */ CFRunLoopSourceContext ctx; memset(&ctx, 0, sizeof(ctx)); ctx.version = 0; ctx.info = dev; ctx.perform = &perform_signal_callback; dev->source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0/*order*/, &ctx); CFRunLoopAddSource(CFRunLoopGetCurrent(), dev->source, dev->run_loop_mode); /* Store off the Run Loop so it can be stopped from hid_close() and on device disconnection. */ dev->run_loop = CFRunLoopGetCurrent(); /* Notify the main thread that the read thread is up and running. */ pthread_barrier_wait(&dev->barrier); /* Run the Event Loop. CFRunLoopRunInMode() will dispatch HID input reports into the hid_report_callback(). */ while (!dev->shutdown_thread && !dev->disconnected) { code = CFRunLoopRunInMode(dev->run_loop_mode, 1000/*sec*/, FALSE); /* Return if the device has been disconnected */ if (code == kCFRunLoopRunFinished) { dev->disconnected = 1; break; } /* Break if The Run Loop returns Finished or Stopped. */ if (code != kCFRunLoopRunTimedOut && code != kCFRunLoopRunHandledSource) { /* There was some kind of error. Setting shutdown seems to make sense, but there may be something else more appropriate */ dev->shutdown_thread = 1; break; } } /* Now that the read thread is stopping, Wake any threads which are waiting on data (in hid_read_timeout()). Do this under a mutex to make sure that a thread which is about to go to sleep waiting on the condition acutally will go to sleep before the condition is signaled. */ pthread_mutex_lock(&dev->mutex); pthread_cond_broadcast(&dev->condition); pthread_mutex_unlock(&dev->mutex); /* Wait here until hid_close() is called and makes it past the call to CFRunLoopWakeUp(). This thread still needs to be valid when that function is called on the other thread. */ pthread_barrier_wait(&dev->shutdown_barrier); return NULL; } hid_device * HID_API_EXPORT hid_open_path(const char *path) { int i; hid_device *dev = NULL; CFIndex num_devices; dev = new_hid_device(); /* Set up the HID Manager if it hasn't been done */ if (hid_init() < 0) return NULL; /* give the IOHIDManager a chance to update itself */ process_pending_events(); CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr); num_devices = CFSetGetCount(device_set); IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef)); CFSetGetValues(device_set, (const void **) device_array); for (i = 0; i < num_devices; i++) { char cbuf[BUF_LEN]; size_t len; IOHIDDeviceRef os_dev = device_array[i]; len = make_path(os_dev, cbuf, sizeof(cbuf)); if (!strcmp(cbuf, path)) { /* Matched Paths. Open this Device. */ IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeSeizeDevice); if (ret == kIOReturnSuccess) { char str[32]; free(device_array); CFRetain(os_dev); CFRelease(device_set); dev->device_handle = os_dev; /* Create the buffers for receiving data */ dev->max_input_report_len = (CFIndex) get_max_report_length(os_dev); dev->input_report_buf = calloc(dev->max_input_report_len, sizeof(uint8_t)); /* Create the Run Loop Mode for this device. printing the reference seems to work. */ sprintf(str, "HIDAPI_%p", os_dev); dev->run_loop_mode = CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII); /* Attach the device to a Run Loop */ IOHIDDeviceRegisterInputReportCallback( os_dev, dev->input_report_buf, dev->max_input_report_len, &hid_report_callback, dev); IOHIDDeviceRegisterRemovalCallback(dev->device_handle, hid_device_removal_callback, dev); /* Start the read thread */ pthread_create(&dev->thread, NULL, read_thread, dev); /* Wait here for the read thread to be initialized. */ pthread_barrier_wait(&dev->barrier); return dev; } else { goto return_error; } } } return_error: free(device_array); CFRelease(device_set); free_hid_device(dev); return NULL; } static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char *data, size_t length) { const unsigned char *data_to_send; size_t length_to_send; IOReturn res; /* Return if the device has been disconnected. */ if (dev->disconnected) return -1; if (data[0] == 0x0) { /* Not using numbered Reports. Don't send the report number. */ data_to_send = data+1; length_to_send = length-1; } else { /* Using numbered Reports. Send the Report Number */ data_to_send = data; length_to_send = length; } if (!dev->disconnected) { res = IOHIDDeviceSetReport(dev->device_handle, type, data[0], /* Report ID*/ data_to_send, length_to_send); if (res == kIOReturnSuccess) { return length; } else return -1; } return -1; } int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) { return set_report(dev, kIOHIDReportTypeOutput, data, length); } /* Helper function, so that this isn't duplicated in hid_read(). */ static int return_data(hid_device *dev, unsigned char *data, size_t length) { /* Copy the data out of the linked list item (rpt) into the return buffer (data), and delete the liked list item. */ struct input_report *rpt = dev->input_reports; size_t len = (length < rpt->len)? length: rpt->len; memcpy(data, rpt->data, len); dev->input_reports = rpt->next; free(rpt->data); free(rpt); return len; } static int cond_wait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex) { while (!dev->input_reports) { int res = pthread_cond_wait(cond, mutex); if (res != 0) return res; /* A res of 0 means we may have been signaled or it may be a spurious wakeup. Check to see that there's acutally data in the queue before returning, and if not, go back to sleep. See the pthread_cond_timedwait() man page for details. */ if (dev->shutdown_thread || dev->disconnected) return -1; } return 0; } static int cond_timedwait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) { while (!dev->input_reports) { int res = pthread_cond_timedwait(cond, mutex, abstime); if (res != 0) return res; /* A res of 0 means we may have been signaled or it may be a spurious wakeup. Check to see that there's acutally data in the queue before returning, and if not, go back to sleep. See the pthread_cond_timedwait() man page for details. */ if (dev->shutdown_thread || dev->disconnected) return -1; } return 0; } int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) { int bytes_read = -1; /* Lock the access to the report list. */ pthread_mutex_lock(&dev->mutex); /* There's an input report queued up. Return it. */ if (dev->input_reports) { /* Return the first one */ bytes_read = return_data(dev, data, length); goto ret; } /* Return if the device has been disconnected. */ if (dev->disconnected) { bytes_read = -1; goto ret; } if (dev->shutdown_thread) { /* This means the device has been closed (or there has been an error. An error code of -1 should be returned. */ bytes_read = -1; goto ret; } /* There is no data. Go to sleep and wait for data. */ if (milliseconds == -1) { /* Blocking */ int res; res = cond_wait(dev, &dev->condition, &dev->mutex); if (res == 0) bytes_read = return_data(dev, data, length); else { /* There was an error, or a device disconnection. */ bytes_read = -1; } } else if (milliseconds > 0) { /* Non-blocking, but called with timeout. */ int res; struct timespec ts; struct timeval tv; gettimeofday(&tv, NULL); TIMEVAL_TO_TIMESPEC(&tv, &ts); ts.tv_sec += milliseconds / 1000; ts.tv_nsec += (milliseconds % 1000) * 1000000; if (ts.tv_nsec >= 1000000000L) { ts.tv_sec++; ts.tv_nsec -= 1000000000L; } res = cond_timedwait(dev, &dev->condition, &dev->mutex, &ts); if (res == 0) bytes_read = return_data(dev, data, length); else if (res == ETIMEDOUT) bytes_read = 0; else bytes_read = -1; } else { /* Purely non-blocking */ bytes_read = 0; } ret: /* Unlock */ pthread_mutex_unlock(&dev->mutex); return bytes_read; } int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length) { return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); } int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) { /* All Nonblocking operation is handled by the library. */ dev->blocking = !nonblock; return 0; } int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) { return set_report(dev, kIOHIDReportTypeFeature, data, length); } int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) { CFIndex len = length; IOReturn res; /* Return if the device has been unplugged. */ if (dev->disconnected) return -1; res = IOHIDDeviceGetReport(dev->device_handle, kIOHIDReportTypeFeature, data[0], /* Report ID */ data, &len); if (res == kIOReturnSuccess) return len; else return -1; } void HID_API_EXPORT hid_close(hid_device *dev) { if (!dev) return; /* Disconnect the report callback before close. */ if (!dev->disconnected) { IOHIDDeviceRegisterInputReportCallback( dev->device_handle, dev->input_report_buf, dev->max_input_report_len, NULL, dev); IOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, NULL, dev); IOHIDDeviceUnscheduleFromRunLoop(dev->device_handle, dev->run_loop, dev->run_loop_mode); IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode); } /* Cause read_thread() to stop. */ dev->shutdown_thread = 1; /* Wake up the run thread's event loop so that the thread can exit. */ CFRunLoopSourceSignal(dev->source); CFRunLoopWakeUp(dev->run_loop); /* Notify the read thread that it can shut down now. */ pthread_barrier_wait(&dev->shutdown_barrier); /* Wait for read_thread() to end. */ pthread_join(dev->thread, NULL); /* Close the OS handle to the device, but only if it's not been unplugged. If it's been unplugged, then calling IOHIDDeviceClose() will crash. */ if (!dev->disconnected) { IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeSeizeDevice); } /* Clear out the queue of received reports. */ pthread_mutex_lock(&dev->mutex); while (dev->input_reports) { return_data(dev, NULL, 0); } pthread_mutex_unlock(&dev->mutex); CFRelease(dev->device_handle); free_hid_device(dev); } int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) { return get_manufacturer_string(dev->device_handle, string, maxlen); } int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) { return get_product_string(dev->device_handle, string, maxlen); } int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) { return get_serial_number(dev->device_handle, string, maxlen); } int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) { /* TODO: */ return 0; } HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) { /* TODO: */ return NULL; } #if 0 static int32_t get_usage(IOHIDDeviceRef device) { int32_t res; res = get_int_property(device, CFSTR(kIOHIDDeviceUsageKey)); if (!res) res = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey)); return res; } static int32_t get_usage_page(IOHIDDeviceRef device) { int32_t res; res = get_int_property(device, CFSTR(kIOHIDDeviceUsagePageKey)); if (!res) res = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey)); return res; } static int get_transport(IOHIDDeviceRef device, wchar_t *buf, size_t len) { return get_string_property(device, CFSTR(kIOHIDTransportKey), buf, len); } int main(void) { IOHIDManagerRef mgr; int i; mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); IOHIDManagerSetDeviceMatching(mgr, NULL); IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone); CFSetRef device_set = IOHIDManagerCopyDevices(mgr); CFIndex num_devices = CFSetGetCount(device_set); IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef)); CFSetGetValues(device_set, (const void **) device_array); for (i = 0; i < num_devices; i++) { IOHIDDeviceRef dev = device_array[i]; printf("Device: %p\n", dev); printf(" %04hx %04hx\n", get_vendor_id(dev), get_product_id(dev)); wchar_t serial[256], buf[256]; char cbuf[256]; get_serial_number(dev, serial, 256); printf(" Serial: %ls\n", serial); printf(" Loc: %ld\n", get_location_id(dev)); get_transport(dev, buf, 256); printf(" Trans: %ls\n", buf); make_path(dev, cbuf, 256); printf(" Path: %s\n", cbuf); } return 0; } #endif openzwave-1.6.1914/cpp/hidapi/mac/Makefile-manual0000644000175200017520000000105714032142455016416 00000000000000########################################### # Simple Makefile for HIDAPI test program # # Alan Ott # Signal 11 Software # 2010-07-03 ########################################### all: hidtest CC=gcc CXX=g++ COBJS=hid.o CPPOBJS=../hidtest/hidtest.o OBJS=$(COBJS) $(CPPOBJS) CFLAGS+=-I../hidapi -Wall -g -c LIBS=-framework IOKit -framework CoreFoundation hidtest: $(OBJS) g++ -Wall -g $^ $(LIBS) -o hidtest $(COBJS): %.o: %.c $(CC) $(CFLAGS) $< -o $@ $(CPPOBJS): %.o: %.cpp $(CXX) $(CFLAGS) $< -o $@ clean: rm -f *.o hidtest $(CPPOBJS) .PHONY: clean openzwave-1.6.1914/cpp/hidapi/pc/0000777000175200017520000000000014032143200013413 500000000000000openzwave-1.6.1914/cpp/hidapi/pc/hidapi-libusb.pc.in0000644000175200017520000000047314032142455017013 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: hidapi-libusb Description: C Library for USB HID device access from Linux, Mac OS X, FreeBSD, and Windows. This is the libusb implementation. Version: @VERSION@ Libs: -L${libdir} -lhidapi-libusb Cflags: -I${includedir}/hidapi openzwave-1.6.1914/cpp/hidapi/pc/hidapi.pc.in0000644000175200017520000000042414032142455015531 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: hidapi Description: C Library for USB/Bluetooth HID device access from Linux, Mac OS X, FreeBSD, and Windows. Version: @VERSION@ Libs: -L${libdir} -lhidapi Cflags: -I${includedir}/hidapi openzwave-1.6.1914/cpp/hidapi/pc/hidapi-hidraw.pc.in0000644000175200017520000000050514032142455017005 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: hidapi-hidraw Description: C Library for USB/Bluetooth HID device access from Linux, Mac OS X, FreeBSD, and Windows. This is the hidraw implementation. Version: @VERSION@ Libs: -L${libdir} -lhidapi-hidraw Cflags: -I${includedir}/hidapi openzwave-1.6.1914/cpp/hidapi/configure.ac0000644000175200017520000001455614032142455015241 00000000000000AC_PREREQ(2.63) # Version number. This is currently the only place. m4_define([HIDAPI_MAJOR], 0) m4_define([HIDAPI_MINOR], 7) m4_define([HIDAPI_RELEASE], 0) m4_define([HIDAPI_RC], +) m4_define([VERSION_STRING], HIDAPI_MAJOR[.]HIDAPI_MINOR[.]HIDAPI_RELEASE[]HIDAPI_RC) AC_INIT([hidapi],[VERSION_STRING],[alan@signal11.us]) # Library soname version # Follow the following rules (particularly the ones in the second link): # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html # http://sourceware.org/autobook/autobook/autobook_91.html lt_current="0" lt_revision="0" lt_age="0" LTLDFLAGS="-version-info ${lt_current}:${lt_revision}:${lt_age}" AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE([foreign -Wall -Werror]) AC_CONFIG_MACRO_DIR([m4]) m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) LT_INIT AC_PROG_CC AC_PROG_CXX AC_PROG_OBJC PKG_PROG_PKG_CONFIG m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) hidapi_lib_error() { echo "" echo " Library $1 was not found on this system." echo " Please install it and re-run ./configure" echo "" exit 1 } hidapi_prog_error() { echo "" echo " Program $1 was not found on this system." echo " This program is part of $2." echo " Please install it and re-run ./configure" echo "" exit 1 } AC_MSG_CHECKING([operating system]) AC_MSG_RESULT($host) case $host in *-linux*) AC_MSG_RESULT([ (Linux back-end)]) AC_DEFINE(OS_LINUX, 1, [Linux implementations]) AC_SUBST(OS_LINUX) backend="linux" os="linux" threads="pthreads" # HIDAPI/hidraw libs PKG_CHECK_MODULES([libudev], [libudev], true, [hidapi_lib_error libudev]) LIBS_HIDRAW_PR+=" $libudev_LIBS" CFLAGS_HIDRAW+=" $libudev_CFLAGS" # HIDAPI/libusb libs AC_CHECK_LIB([rt], [clock_gettime], [LIBS_LIBUSB_PRIVATE+=" -lrt"], [hidapi_lib_error librt]) PKG_CHECK_MODULES([libusb], [libusb-1.0], true, [hidapi_lib_error libusb-1.0]) LIBS_LIBUSB_PRIVATE+=" $libusb_LIBS" CFLAGS_LIBUSB+=" $libusb_CFLAGS" ;; *-darwin*) AC_MSG_RESULT([ (Mac OS X back-end)]) AC_DEFINE(OS_DARWIN, 1, [Mac implementation]) AC_SUBST(OS_DARWIN) backend="mac" os="darwin" threads="pthreads" LIBS="${LIBS} -framework IOKit -framework CoreFoundation" ;; *-freebsd*) AC_MSG_RESULT([ (FreeBSD back-end)]) AC_DEFINE(OS_FREEBSD, 1, [FreeBSD implementation]) AC_SUBST(OS_FREEBSD) backend="libusb" os="freebsd" threads="pthreads" CFLAGS="$CFLAGS -I/usr/local/include" LDFLAGS="$LDFLAGS -L/usr/local/lib" LIBS="${LIBS}" AC_CHECK_LIB([usb], [libusb_init], [LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} -lusb"], [hidapi_lib_error libusb]) AC_CHECK_LIB([iconv], [iconv_open], [LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} -liconv"], [hidapi_lib_error libiconv]) echo libs_priv: $LIBS_LIBUSB_PRIVATE ;; *-mingw*) AC_MSG_RESULT([ (Windows back-end, using MinGW)]) backend="windows" os="windows" threads="windows" win_implementation="mingw" ;; *-cygwin*) AC_MSG_RESULT([ (Windows back-end, using Cygwin)]) backend="windows" os="windows" threads="windows" win_implementation="cygwin" ;; *) AC_MSG_ERROR([HIDAPI is not supported on your operating system yet]) esac LIBS_HIDRAW="${LIBS} ${LIBS_HIDRAW_PR}" LIBS_LIBUSB="${LIBS} ${LIBS_LIBUSB_PRIVATE}" AC_SUBST([LIBS_HIDRAW]) AC_SUBST([LIBS_LIBUSB]) AC_SUBST([CFLAGS_LIBUSB]) AC_SUBST([CFLAGS_HIDRAW]) if test "x$os" = xwindows; then AC_DEFINE(OS_WINDOWS, 1, [Windows implementations]) AC_SUBST(OS_WINDOWS) LDFLAGS="${LDFLAGS} -no-undefined" LIBS="${LIBS} -lsetupapi" fi if test "x$threads" = xpthreads; then AX_PTHREAD([found_pthreads=yes], [found_pthreads=no]) if test "x$found_pthreads" = xyes; then if test "x$os" = xlinux; then # Only use pthreads for libusb implementation on Linux. LIBS_LIBUSB="$PTHREAD_LIBS $LIBS_LIBUSB" CFLAGS_LIBUSB="$CFLAGS_LIBUSB $PTHREAD_CFLAGS" # There's no separate CC on Linux for threading, # so it's ok that both implementations use $PTHREAD_CC CC="$PTHREAD_CC" else LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" CC="$PTHREAD_CC" fi fi fi # Test GUI AC_ARG_ENABLE([testgui], [AS_HELP_STRING([--enable-testgui], [enable building of test GUI (default n)])], [testgui_enabled=$enableval], [testgui_enabled='no']) AM_CONDITIONAL([BUILD_TESTGUI], [test "x$testgui_enabled" != "xno"]) # Configure the MacOS TestGUI app bundle rm -Rf testgui/TestGUI.app mkdir -p testgui/TestGUI.app cp -R ${srcdir}/testgui/TestGUI.app.in/* testgui/TestGUI.app chmod -R u+w testgui/TestGUI.app mkdir testgui/TestGUI.app/Contents/MacOS/ if test "x$testgui_enabled" != "xno"; then if test "x$os" = xdarwin; then # On Mac OS, don't use pkg-config. AC_CHECK_PROG([foxconfig], [fox-config], [fox-config], false) if test "x$foxconfig" = "xfalse"; then hidapi_prog_error fox-config "FOX Toolkit" fi LIBS_TESTGUI+=`$foxconfig --libs` LIBS_TESTGUI+=" -framework Cocoa -L/usr/X11R6/lib" CFLAGS_TESTGUI+=`$foxconfig --cflags` OBJCFLAGS+=" -x objective-c++" elif test "x$os" = xwindows; then # On Windows, just set the paths for Fox toolkit if test "x$win_implementation" = xmingw; then CFLAGS_TESTGUI="-I\$(srcdir)/../../hidapi-externals/fox/include -g -c" LIBS_TESTGUI=" -mwindows \$(srcdir)/../../hidapi-externals/fox/lib/libFOX-1.6.a -lgdi32 -Wl,--enable-auto-import -static-libgcc -static-libstdc++ -lkernel32" else # Cygwin CFLAGS_TESTGUI="-DWIN32 -I\$(srcdir)/../../hidapi-externals/fox/include -g -c" LIBS_TESTGUI="\$(srcdir)/../../hidapi-externals/fox/lib/libFOX-cygwin-1.6.a -lgdi32 -Wl,--enable-auto-import -static-libgcc -static-libstdc++ -lkernel32" fi else # On Linux and FreeBSD platforms, use pkg-config to find fox. PKG_CHECK_MODULES([fox], [fox]) LIBS_TESTGUI="${LIBS_TESTGUI} $fox_LIBS" if test "x$os" = xfreebsd; then LIBS_TESTGUI="${LIBS_TESTGUI} -L/usr/local/lib" fi CFLAGS_TESTGUI="${CFLAGS_TESTGUI} $fox_CFLAGS" fi fi AC_SUBST([LIBS_TESTGUI]) AC_SUBST([CFLAGS_TESTGUI]) AC_SUBST([backend]) # OS info for Automake AM_CONDITIONAL(OS_LINUX, test "x$os" = xlinux) AM_CONDITIONAL(OS_DARWIN, test "x$os" = xdarwin) AM_CONDITIONAL(OS_FREEBSD, test "x$os" = xfreebsd) AM_CONDITIONAL(OS_WINDOWS, test "x$os" = xwindows) AC_CONFIG_HEADERS([config.h]) if test "x$os" = "xlinux"; then AC_CONFIG_FILES([pc/hidapi-hidraw.pc]) AC_CONFIG_FILES([pc/hidapi-libusb.pc]) else AC_CONFIG_FILES([pc/hidapi.pc]) fi AC_SUBST(LTLDFLAGS) AC_CONFIG_FILES([Makefile \ hidtest/Makefile \ libusb/Makefile \ linux/Makefile \ mac/Makefile \ testgui/Makefile \ windows/Makefile]) AC_OUTPUT openzwave-1.6.1914/cpp/hidapi/LICENSE-bsd.txt0000644000175200017520000000277614032142455015345 00000000000000Copyright (c) 2010, Alan Ott, Signal 11 Software All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Signal 11 Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. openzwave-1.6.1914/cpp/hidapi/linux/0000777000175200017520000000000014032143200014150 500000000000000openzwave-1.6.1914/cpp/hidapi/linux/README.txt0000644000175200017520000000575514032142455015611 00000000000000 There are two implementations of HIDAPI for Linux. One (hid.c) uses the Linux hidraw driver, and the other (hid-libusb.c) uses libusb. Which one you use depends on your application. Complete functionality of the hidraw version depends on patches to the Linux kernel which are not currently in the mainline. These patches have to do with sending and receiving feature reports. The libusb implementation uses libusb to talk directly to the device, bypassing any Linux HID driver. The disadvantage of the libusb version is that it will only work with USB devices, while the hidraw implementation will work with Bluetooth devices as well. To use HIDAPI, simply drop either hid.c or hid-libusb.c into your application and build using the build parameters in the Makefile. By default, on Linux, the Makefile in this directory is configured to use the libusb implementation. To switch to the hidraw implementation, simply change hid-libusb.c to hid.c in the Makefile. Libusb Implementation notes ---------------------------- For the libusb implementation, libusb-1.0 must be installed. Libusb 1.0 is different than the legacy libusb 0.1 which is installed on many systems. To install libusb-1.0 on Ubuntu and other Debian-based systems, run: sudo apt-get install libusb-1.0-0-dev Hidraw Implementation notes ---------------------------- For the hidraw implementation, libudev headers and libraries are required to build hidapi programs. To install libudev libraries on Ubuntu, and other Debian-based systems, run: sudo apt-get install libudev-dev On Redhat-based systems, run the following as root: yum install libudev-devel Unfortunately, the hidraw driver, which the linux version of hidapi is based on, contains bugs in kernel versions < 2.6.36, which the client application should be aware of. Bugs (hidraw implementation only): ----------------------------------- On Kernel versions < 2.6.34, if your device uses numbered reports, an extra byte will be returned at the beginning of all reports returned from read() for hidraw devices. This is worked around in the libary. No action should be necessary in the client library. On Kernel versions < 2.6.35, reports will only be sent using a Set_Report transfer on the CONTROL endpoint. No data will ever be sent on an Interrupt Out endpoint if one exists. This is fixed in 2.6.35. In 2.6.35, OUTPUT reports will be sent to the device on the first INTERRUPT OUT endpoint if it exists; If it does not exist, OUTPUT reports will be sent on the CONTROL endpoint. On Kernel versions < 2.6.36, add an extra byte containing the report number to sent reports if numbered reports are used, and the device does not contain an INTERRPUT OUT endpoint for OUTPUT transfers. For example, if your device uses numbered reports and wants to send {0x2 0xff 0xff 0xff} to the device (0x2 is the report number), you must send {0x2 0x2 0xff 0xff 0xff}. If your device has the optional Interrupt OUT endpoint, this does not apply (but really on 2.6.35 only, because 2.6.34 won't use the interrupt out endpoint). openzwave-1.6.1914/cpp/hidapi/linux/.gitignore0000644000175200017520000000012414032142455016064 00000000000000Debug Release *.exp *.ilk *.lib *.suo *.vcproj.* *.ncb *.suo *.dll *.pdb *.o hidtestopenzwave-1.6.1914/cpp/hidapi/linux/Makefile.am0000644000175200017520000000050114032142455016127 00000000000000lib_LTLIBRARIES = libhidapi-hidraw.la libhidapi_hidraw_la_SOURCES = hid.c libhidapi_hidraw_la_LDFLAGS = $(LTLDFLAGS) AM_CPPFLAGS = -I$(top_srcdir)/hidapi/ $(CFLAGS_HIDRAW) libhidapi_hidraw_la_LIBADD = $(LIBS_HIDRAW) hdrdir = $(includedir)/hidapi hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h EXTRA_DIST = Makefile-manual openzwave-1.6.1914/cpp/hidapi/linux/hid.c0000644000175200017520000004620714032142455015020 00000000000000/******************************************************* HIDAPI - Multi-Platform library for communication with HID devices. Alan Ott Signal 11 Software 8/22/2009 Linux Version - 6/2/2009 Copyright 2009, All Rights Reserved. At the discretion of the user of this library, this software may be licensed under the terms of the GNU Public License v3, a BSD-Style license, or the original HIDAPI license as outlined in the LICENSE.txt, LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt files located at the root of the source distribution. These files may also be found in the public source code repository located at: http://github.com/signal11/hidapi . ********************************************************/ #define _GNU_SOURCE /* needed for wcsdup() before glibc 2.10 */ /* C */ #include #include #include #include #include /* Unix */ #include #include #include #include #include #include #include /* Linux */ #include #include #include #include #include "hidapi.h" /* Definitions from linux/hidraw.h. Since these are new, some distros may not have header files which contain them. */ #ifndef HIDIOCSFEATURE #define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len) #endif #ifndef HIDIOCGFEATURE #define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len) #endif /* USB HID device property names */ const char *device_string_names[] = { "manufacturer", "product", "serial", }; /* Symbolic names for the properties above */ enum device_string_id { DEVICE_STRING_MANUFACTURER, DEVICE_STRING_PRODUCT, DEVICE_STRING_SERIAL, DEVICE_STRING_COUNT, }; struct hid_device_ { int device_handle; int blocking; int uses_numbered_reports; }; static __u32 kernel_version = 0; static hid_device *new_hid_device(void) { hid_device *dev = calloc(1, sizeof(hid_device)); dev->device_handle = -1; dev->blocking = 1; dev->uses_numbered_reports = 0; return dev; } /* The caller must free the returned string with free(). */ static wchar_t *utf8_to_wchar_t(const char *utf8) { wchar_t *ret = NULL; if (utf8) { size_t wlen = mbstowcs(NULL, utf8, 0); if ((size_t) -1 == wlen) { return wcsdup(L""); } ret = calloc(wlen+1, sizeof(wchar_t)); mbstowcs(ret, utf8, wlen+1); ret[wlen] = 0x0000; } return ret; } /* Get an attribute value from a udev_device and return it as a whar_t string. The returned string must be freed with free() when done.*/ static wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name) { return utf8_to_wchar_t(udev_device_get_sysattr_value(dev, udev_name)); } /* uses_numbered_reports() returns 1 if report_descriptor describes a device which contains numbered reports. */ static int uses_numbered_reports(__u8 *report_descriptor, __u32 size) { unsigned int i = 0; int size_code; int data_len, key_size; while (i < size) { int key = report_descriptor[i]; /* Check for the Report ID key */ if (key == 0x85/*Report ID*/) { /* This device has a Report ID, which means it uses numbered reports. */ return 1; } //printf("key: %02hhx\n", key); if ((key & 0xf0) == 0xf0) { /* This is a Long Item. The next byte contains the length of the data section (value) for this key. See the HID specification, version 1.11, section 6.2.2.3, titled "Long Items." */ if (i+1 < size) data_len = report_descriptor[i+1]; else data_len = 0; /* malformed report */ key_size = 3; } else { /* This is a Short Item. The bottom two bits of the key contain the size code for the data section (value) for this key. Refer to the HID specification, version 1.11, section 6.2.2.2, titled "Short Items." */ size_code = key & 0x3; switch (size_code) { case 0: case 1: case 2: data_len = size_code; break; case 3: data_len = 4; break; default: /* Can't ever happen since size_code is & 0x3 */ data_len = 0; break; }; key_size = 1; } /* Skip over this key and it's associated data */ i += data_len + key_size; } /* Didn't find a Report ID key. Device doesn't use numbered reports. */ return 0; } /* * The caller is responsible for free()ing the (newly-allocated) character * strings pointed to by serial_number_utf8 and product_name_utf8 after use. */ static int parse_uevent_info(const char *uevent, int *bus_type, unsigned short *vendor_id, unsigned short *product_id, char **serial_number_utf8, char **product_name_utf8) { char *tmp = strdup(uevent); char *saveptr = NULL; char *line; char *key; char *value; int found_id = 0; int found_serial = 0; int found_name = 0; line = strtok_r(tmp, "\n", &saveptr); while (line != NULL) { /* line: "KEY=value" */ key = line; value = strchr(line, '='); if (!value) { goto next_line; } *value = '\0'; value++; if (strcmp(key, "HID_ID") == 0) { /** * type vendor product * HID_ID=0003:000005AC:00008242 **/ int ret = sscanf(value, "%x:%hx:%hx", bus_type, vendor_id, product_id); if (ret == 3) { found_id = 1; } } else if (strcmp(key, "HID_NAME") == 0) { /* The caller has to free the product name */ *product_name_utf8 = strdup(value); found_name = 1; } else if (strcmp(key, "HID_UNIQ") == 0) { /* The caller has to free the serial number */ *serial_number_utf8 = strdup(value); found_serial = 1; } next_line: line = strtok_r(NULL, "\n", &saveptr); } free(tmp); return (found_id && found_name && found_serial); } static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t *string, size_t maxlen) { struct udev *udev; struct udev_device *udev_dev, *parent, *hid_dev; struct stat s; int ret = -1; char *serial_number_utf8 = NULL; char *product_name_utf8 = NULL; /* Create the udev object */ udev = udev_new(); if (!udev) { printf("Can't create udev\n"); return -1; } /* Get the dev_t (major/minor numbers) from the file handle. */ fstat(dev->device_handle, &s); /* Open a udev device from the dev_t. 'c' means character device. */ udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev); if (udev_dev) { hid_dev = udev_device_get_parent_with_subsystem_devtype( udev_dev, "hid", NULL); if (hid_dev) { unsigned short dev_vid; unsigned short dev_pid; int bus_type; size_t retm; ret = parse_uevent_info( udev_device_get_sysattr_value(hid_dev, "uevent"), &bus_type, &dev_vid, &dev_pid, &serial_number_utf8, &product_name_utf8); if (bus_type == BUS_BLUETOOTH) { switch (key) { case DEVICE_STRING_MANUFACTURER: wcsncpy(string, L"", maxlen); ret = 0; break; case DEVICE_STRING_PRODUCT: retm = mbstowcs(string, product_name_utf8, maxlen); ret = (retm == (size_t)-1)? -1: 0; break; case DEVICE_STRING_SERIAL: retm = mbstowcs(string, serial_number_utf8, maxlen); ret = (retm == (size_t)-1)? -1: 0; break; case DEVICE_STRING_COUNT: default: ret = -1; break; } } else { /* This is a USB device. Find its parent USB Device node. */ parent = udev_device_get_parent_with_subsystem_devtype( udev_dev, "usb", "usb_device"); if (parent) { const char *str; const char *key_str = NULL; if (key >= 0 && key < DEVICE_STRING_COUNT) { key_str = device_string_names[key]; } else { ret = -1; goto end; } str = udev_device_get_sysattr_value(parent, key_str); if (str) { /* Convert the string from UTF-8 to wchar_t */ retm = mbstowcs(string, str, maxlen); ret = (retm == (size_t)-1)? -1: 0; goto end; } } } } } end: free(serial_number_utf8); free(product_name_utf8); udev_device_unref(udev_dev); /* parent and hid_dev don't need to be (and can't be) unref'd. I'm not sure why, but they'll throw double-free() errors. */ udev_unref(udev); return ret; } int HID_API_EXPORT hid_init(void) { /* Refer to http://code.google.com/p/open-zwave/issues/detail?id=254 * We should not be setting the Locale and let the application set it */ // const char *locale; /* Set the locale if it's not set. */ // locale = setlocale(LC_CTYPE, NULL); // if (!locale) // setlocale(LC_CTYPE, ""); return 0; } int HID_API_EXPORT hid_exit(void) { /* Nothing to do for this in the Linux/hidraw implementation. */ return 0; } struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id) { struct udev *udev; struct udev_enumerate *enumerate; struct udev_list_entry *devices, *dev_list_entry; struct hid_device_info *root = NULL; /* return object */ struct hid_device_info *cur_dev = NULL; struct hid_device_info *prev_dev = NULL; /* previous device */ hid_init(); /* Create the udev object */ udev = udev_new(); if (!udev) { printf("Can't create udev\n"); return NULL; } /* Create a list of the devices in the 'hidraw' subsystem. */ enumerate = udev_enumerate_new(udev); udev_enumerate_add_match_subsystem(enumerate, "hidraw"); udev_enumerate_scan_devices(enumerate); devices = udev_enumerate_get_list_entry(enumerate); /* For each item, see if it matches the vid/pid, and if so create a udev_device record for it */ udev_list_entry_foreach(dev_list_entry, devices) { const char *sysfs_path; const char *dev_path; const char *str; struct udev_device *raw_dev; /* The device's hidraw udev node. */ struct udev_device *hid_dev; /* The device's HID udev node. */ struct udev_device *usb_dev; /* The device's USB udev node. */ struct udev_device *intf_dev; /* The device's interface (in the USB sense). */ unsigned short dev_vid; unsigned short dev_pid; char *serial_number_utf8 = NULL; char *product_name_utf8 = NULL; int bus_type; int result; /* Get the filename of the /sys entry for the device and create a udev_device object (dev) representing it */ sysfs_path = udev_list_entry_get_name(dev_list_entry); raw_dev = udev_device_new_from_syspath(udev, sysfs_path); dev_path = udev_device_get_devnode(raw_dev); hid_dev = udev_device_get_parent_with_subsystem_devtype( raw_dev, "hid", NULL); if (!hid_dev) { /* Unable to find parent hid device. */ goto next; } result = parse_uevent_info( udev_device_get_sysattr_value(hid_dev, "uevent"), &bus_type, &dev_vid, &dev_pid, &serial_number_utf8, &product_name_utf8); if (!result) { /* parse_uevent_info() failed for at least one field. */ goto next; } if (bus_type != BUS_USB && bus_type != BUS_BLUETOOTH) { /* We only know how to handle USB and BT devices. */ goto next; } /* Check the VID/PID against the arguments */ if ((vendor_id == 0x0 || vendor_id == dev_vid) && (product_id == 0x0 || product_id == dev_pid)) { struct hid_device_info *tmp; /* VID/PID match. Create the record. */ tmp = malloc(sizeof(struct hid_device_info)); if (cur_dev) { cur_dev->next = tmp; } else { root = tmp; } prev_dev = cur_dev; cur_dev = tmp; /* Fill out the record */ cur_dev->next = NULL; cur_dev->path = dev_path? strdup(dev_path): NULL; /* VID/PID */ cur_dev->vendor_id = dev_vid; cur_dev->product_id = dev_pid; /* Serial Number */ cur_dev->serial_number = utf8_to_wchar_t(serial_number_utf8); /* Release Number */ cur_dev->release_number = 0x0; /* Interface Number */ cur_dev->interface_number = -1; switch (bus_type) { case BUS_USB: /* The device pointed to by raw_dev contains information about the hidraw device. In order to get information about the USB device, get the parent device with the subsystem/devtype pair of "usb"/"usb_device". This will be several levels up the tree, but the function will find it. */ usb_dev = udev_device_get_parent_with_subsystem_devtype( raw_dev, "usb", "usb_device"); if (!usb_dev) { /* Free this device */ free(cur_dev->serial_number); free(cur_dev->path); free(cur_dev); /* Take it off the device list. */ if (prev_dev) { prev_dev->next = NULL; cur_dev = prev_dev; } else { cur_dev = root = NULL; } goto next; } /* Manufacturer and Product strings */ cur_dev->manufacturer_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_MANUFACTURER]); cur_dev->product_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_PRODUCT]); /* Release Number */ str = udev_device_get_sysattr_value(usb_dev, "bcdDevice"); cur_dev->release_number = (str)? strtol(str, NULL, 16): 0x0; /* Get a handle to the interface's udev node. */ intf_dev = udev_device_get_parent_with_subsystem_devtype( raw_dev, "usb", "usb_interface"); if (intf_dev) { str = udev_device_get_sysattr_value(intf_dev, "bInterfaceNumber"); cur_dev->interface_number = (str)? strtol(str, NULL, 16): -1; } break; case BUS_BLUETOOTH: /* Manufacturer and Product strings */ cur_dev->manufacturer_string = wcsdup(L""); cur_dev->product_string = utf8_to_wchar_t(product_name_utf8); break; default: /* Unknown device type - this should never happen, as we * check for USB and Bluetooth devices above */ break; } } next: free(serial_number_utf8); free(product_name_utf8); udev_device_unref(raw_dev); /* hid_dev, usb_dev and intf_dev don't need to be (and can't be) unref()d. It will cause a double-free() error. I'm not sure why. */ } /* Free the enumerator and udev objects. */ udev_enumerate_unref(enumerate); udev_unref(udev); return root; } void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs) { struct hid_device_info *d = devs; while (d) { struct hid_device_info *next = d->next; free(d->path); free(d->serial_number); free(d->manufacturer_string); free(d->product_string); free(d); d = next; } } hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) { struct hid_device_info *devs, *cur_dev; const char *path_to_open = NULL; hid_device *handle = NULL; devs = hid_enumerate(vendor_id, product_id); cur_dev = devs; while (cur_dev) { if (cur_dev->vendor_id == vendor_id && cur_dev->product_id == product_id) { if (serial_number) { if (wcscmp(serial_number, cur_dev->serial_number) == 0) { path_to_open = cur_dev->path; break; } } else { path_to_open = cur_dev->path; break; } } cur_dev = cur_dev->next; } if (path_to_open) { /* Open the device */ handle = hid_open_path(path_to_open); } hid_free_enumeration(devs); return handle; } hid_device * HID_API_EXPORT hid_open_path(const char *path) { hid_device *dev = NULL; hid_init(); dev = new_hid_device(); if (kernel_version == 0) { struct utsname name; int major, minor, release; int ret; uname(&name); ret = sscanf(name.release, "%d.%d.%d", &major, &minor, &release); if (ret == 3) { kernel_version = major << 16 | minor << 8 | release; //printf("Kernel Version: %d\n", kernel_version); } else { printf("Couldn't sscanf() version string %s\n", name.release); } } /* OPEN HERE */ dev->device_handle = open(path, O_RDWR); /* If we have a good handle, return it. */ if (dev->device_handle > 0) { /* Get the report descriptor */ int res, desc_size = 0; struct hidraw_report_descriptor rpt_desc; memset(&rpt_desc, 0x0, sizeof(rpt_desc)); /* Get Report Descriptor Size */ res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size); if (res < 0) perror("HIDIOCGRDESCSIZE"); /* Get Report Descriptor */ rpt_desc.size = desc_size; res = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc); if (res < 0) { perror("HIDIOCGRDESC"); } else { /* Determine if this device uses numbered reports. */ dev->uses_numbered_reports = uses_numbered_reports(rpt_desc.value, rpt_desc.size); } return dev; } else { /* Unable to open any devices. */ free(dev); return NULL; } } int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length) { int bytes_written; bytes_written = write(dev->device_handle, data, length); return bytes_written; } int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) { int bytes_read; if (milliseconds != 0) { /* milliseconds is -1 or > 0. In both cases, we want to call poll() and wait for data to arrive. -1 means INFINITE. */ int ret; struct pollfd fds; fds.fd = dev->device_handle; fds.events = POLLIN; fds.revents = 0; ret = poll(&fds, 1, milliseconds); if (ret == -1 || ret == 0) /* Error or timeout */ return ret; } bytes_read = read(dev->device_handle, data, length); if (bytes_read < 0 && (errno == EAGAIN || errno == EINPROGRESS)) bytes_read = 0; if (bytes_read >= 0 && kernel_version < KERNEL_VERSION(2,6,34) && dev->uses_numbered_reports) { /* Work around a kernel bug. Chop off the first byte. */ memmove(data, data+1, bytes_read); bytes_read--; } return bytes_read; } int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length) { return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); } int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock) { int flags, res; flags = fcntl(dev->device_handle, F_GETFL, 0); if (flags >= 0) { if (nonblock) res = fcntl(dev->device_handle, F_SETFL, flags | O_NONBLOCK); else res = fcntl(dev->device_handle, F_SETFL, flags & ~O_NONBLOCK); } else return -1; if (res < 0) { return -1; } else { dev->blocking = !nonblock; return 0; /* Success */ } } int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) { int res; res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data); if (res < 0) perror("ioctl (SFEATURE)"); return res; } int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) { int res; res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data); if (res < 0) perror("ioctl (GFEATURE)"); return res; } void HID_API_EXPORT hid_close(hid_device *dev) { if (!dev) return; close(dev->device_handle); free(dev); } int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) { return get_device_string(dev, DEVICE_STRING_MANUFACTURER, string, maxlen); } int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) { return get_device_string(dev, DEVICE_STRING_PRODUCT, string, maxlen); } int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) { return get_device_string(dev, DEVICE_STRING_SERIAL, string, maxlen); } int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) { return -1; } HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) { return NULL; } openzwave-1.6.1914/cpp/hidapi/linux/Makefile-manual0000644000175200017520000000176114032142455017017 00000000000000########################################### # Simple Makefile for HIDAPI test program # # Alan Ott # Signal 11 Software # 2010-06-01 ########################################### all: hidtest-hidraw libs libs: libhidapi-hidraw.so CC ?= gcc CFLAGS ?= -Wall -g -fpic CXX ?= g++ CXXFLAGS ?= -Wall -g -fpic LDFLAGS ?= -Wall -g COBJS = hid.o CPPOBJS = ../hidtest/hidtest.o OBJS = $(COBJS) $(CPPOBJS) LIBS_UDEV = `pkg-config libudev --libs` -lrt LIBS = $(LIBS_UDEV) INCLUDES ?= -I../hidapi `pkg-config libusb-1.0 --cflags` # Console Test Program hidtest-hidraw: $(COBJS) $(CPPOBJS) $(CXX) $(LDFLAGS) $^ $(LIBS_UDEV) -o $@ # Shared Libs libhidapi-hidraw.so: $(COBJS) $(CC) $(LDFLAGS) $(LIBS_UDEV) -shared -fpic -Wl,-soname,$@.0 $^ -o $@ # Objects $(COBJS): %.o: %.c $(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@ $(CPPOBJS): %.o: %.cpp $(CXX) $(CXXFLAGS) -c $(INCLUDES) $< -o $@ clean: rm -f $(OBJS) hidtest-hidraw libhidapi-hidraw.so ../hidtest/hidtest.o .PHONY: clean libs openzwave-1.6.1914/cpp/hidapi/AUTHORS.txt0000644000175200017520000000054414032142455014631 00000000000000 HIDAPI Authors: Alan Ott : Original Author and Maintainer Linux, Windows, and Mac implementations Ludovic Rousseau : Formatting for Doxygen documentation Bug fixes Correctness fixes For a comprehensive list of contributions, see the commit list at github: http://github.com/signal11/hidapi/commits/master openzwave-1.6.1914/cpp/hidapi/LICENSE-orig.txt0000644000175200017520000000041014032142455015514 00000000000000 HIDAPI - Multi-Platform library for communication with HID devices. Copyright 2009, Alan Ott, Signal 11 Software. All Rights Reserved. This software may be used by anyone for any reason so long as the copyright notice in the source files remains intact. openzwave-1.6.1914/cpp/hidapi/README.txt0000644000175200017520000002762014032142455014445 00000000000000 HIDAPI library for Windows, Linux, FreeBSD and Mac OS X ========================================================= About ====== HIDAPI is a multi-platform library which allows an application to interface with USB and Bluetooth HID-Class devices on Windows, Linux, FreeBSD, and Mac OS X. HIDAPI can be either built as a shared library (.so or .dll) or can be embedded directly into a target application by adding a single source file (per platform) and a single header. HIDAPI has four back-ends: * Windows (using hid.dll) * Linux/hidraw (using the Kernel's hidraw driver) * Linux/libusb (using libusb-1.0) * FreeBSD (using libusb-1.0) * Mac (using IOHidManager) On Linux, either the hidraw or the libusb back-end can be used. There are tradeoffs, and the functionality supported is slightly different. Linux/hidraw (linux/hid.c): This back-end uses the hidraw interface in the Linux kernel. While this back-end will support both USB and Bluetooth, it has some limitations on kernels prior to 2.6.39, including the inability to send or receive feature reports. In addition, it will only communicate with devices which have hidraw nodes associated with them. Keyboards, mice, and some other devices which are blacklisted from having hidraw nodes will not work. Fortunately, for nearly all the uses of hidraw, this is not a problem. Linux/FreeBSD/libusb (libusb/hid-libusb.c): This back-end uses libusb-1.0 to communicate directly to a USB device. This back-end will of course not work with Bluetooth devices. HIDAPI also comes with a Test GUI. The Test GUI is cross-platform and uses Fox Toolkit (http://www.fox-toolkit.org). It will build on every platform which HIDAPI supports. Since it relies on a 3rd party library, building it is optional but recommended because it is so useful when debugging hardware. What Does the API Look Like? ============================= The API provides the the most commonly used HID functions including sending and receiving of input, output, and feature reports. The sample program, which communicates with a heavily hacked up version of the Microchip USB Generic HID sample looks like this (with error checking removed for simplicity): #ifdef WIN32 #include #endif #include #include #include "hidapi.h" #define MAX_STR 255 int main(int argc, char* argv[]) { int res; unsigned char buf[65]; wchar_t wstr[MAX_STR]; hid_device *handle; int i; // Initialize the hidapi library res = hid_init(); // Open the device using the VID, PID, // and optionally the Serial number. handle = hid_open(0x4d8, 0x3f, NULL); // Read the Manufacturer String res = hid_get_manufacturer_string(handle, wstr, MAX_STR); wprintf(L"Manufacturer String: %s\n", wstr); // Read the Product String res = hid_get_product_string(handle, wstr, MAX_STR); wprintf(L"Product String: %s\n", wstr); // Read the Serial Number String res = hid_get_serial_number_string(handle, wstr, MAX_STR); wprintf(L"Serial Number String: (%d) %s\n", wstr[0], wstr); // Read Indexed String 1 res = hid_get_indexed_string(handle, 1, wstr, MAX_STR); wprintf(L"Indexed String 1: %s\n", wstr); // Toggle LED (cmd 0x80). The first byte is the report number (0x0). buf[0] = 0x0; buf[1] = 0x80; res = hid_write(handle, buf, 65); // Request state (cmd 0x81). The first byte is the report number (0x0). buf[0] = 0x0; buf[1] = 0x81; res = hid_write(handle, buf, 65); // Read requested state res = hid_read(handle, buf, 65); // Print out the returned buffer. for (i = 0; i < 4; i++) printf("buf[%d]: %d\n", i, buf[i]); // Finalize the hidapi library res = hid_exit(); return 0; } If you have your own simple test programs which communicate with standard hardware development boards (such as those from Microchip, TI, Atmel, FreeScale and others), please consider sending me something like the above for inclusion into the HIDAPI source. This will help others who have the same hardware as you do. License ======== HIDAPI may be used by one of three licenses as outlined in LICENSE.txt. Download ========= HIDAPI can be downloaded from github git clone git://github.com/signal11/hidapi.git Build Instructions =================== This section is long. Don't be put off by this. It's not long because it's complicated to build HIDAPI; it's quite the opposite. This section is long because of the flexibility of HIDAPI and the large number of ways in which it can be built and used. You will likely pick a single build method. HIDAPI can be built in several different ways. If you elect to build a shared library, you will need to build it from the HIDAPI source distribution. If you choose instead to embed HIDAPI directly into your application, you can skip the building and look at the provided platform Makefiles for guidance. These platform Makefiles are located in linux/ libusb/ mac/ and windows/ and are called Makefile-manual. In addition, Visual Studio projects are provided. Even if you're going to embed HIDAPI into your project, it is still beneficial to build the example programs. Prerequisites: --------------- Linux: ------- On Linux, you will need to install development packages for libudev, libusb and optionally Fox-toolkit (for the test GUI). On Debian/Ubuntu systems these can be installed by running: sudo apt-get install libudev-dev libusb-1.0-0-dev libfox-1.6-dev If you downloaded the source directly from the git repository (using git clone), you'll need Autotools: sudo apt-get install autotools-dev FreeBSD: --------- On FreeBSD you will need to install GNU make, libiconv, and optionally Fox-Toolkit (for the test GUI). This is done by running the following: pkg_add -r gmake libiconv fox16 If you downloaded the source directly from the git repository (using git clone), you'll need Autotools: pkg_add -r autotools Mac: ----- On Mac, you will need to install Fox-Toolkit if you wish to build the Test GUI. There are two ways to do this, and each has a slight complication. Which method you use depends on your use case. If you wish to build the Test GUI just for your own testing on your own computer, then the easiest method is to install Fox-Toolkit using ports: sudo port install fox If you wish to build the TestGUI app bundle to redistribute to others, you will need to install Fox-toolkit from source. This is because the version of fox that gets installed using ports uses the ports X11 libraries which are not compatible with the Apple X11 libraries. If you install Fox with ports and then try to distribute your built app bundle, it will simply fail to run on other systems. To install Fox-Toolkit manually, download the source package from http://www.fox-toolkit.org, extract it, and run the following from within the extracted source: ./configure && make && make install Windows: --------- On Windows, if you want to build the test GUI, you will need to get the hidapi-externals.zip package from the download site. This contains pre-built binaries for Fox-toolkit. Extract hidapi-externals.zip just outside of hidapi, so that hidapi-externals and hidapi are on the same level, as shown: Parent_Folder | +hidapi +hidapi-externals Again, this step is not required if you do not wish to build the test GUI. Building HIDAPI into a shared library on Unix Platforms: --------------------------------------------------------- On Unix-like systems such as Linux, FreeBSD, Mac, and even Windows, using Mingw or Cygwin, the easiest way to build a standard system-installed shared library is to use the GNU Autotools build system. If you checked out the source from the git repository, run the following: ./bootstrap ./configure make make install <----- as root, or using sudo If you downloaded a source package (ie: if you did not run git clone), you can skip the ./bootstrap step. ./configure can take several arguments which control the build. The two most likely to be used are: --enable-testgui Enable build of the Test GUI. This requires Fox toolkit to be installed. Instructions for installing Fox-Toolkit on each platform are in the Prerequisites section above. --prefix=/usr Specify where you want the output headers and libraries to be installed. The example above will put the headers in /usr/include and the binaries in /usr/lib. The default is to install into /usr/local which is fine on most systems. Building the manual way on Unix platforms: ------------------------------------------- Manual Makefiles are provided mostly to give the user and idea what it takes to build a program which embeds HIDAPI directly inside of it. These should really be used as examples only. If you want to build a system-wide shared library, use the Autotools method described above. To build HIDAPI using the manual makefiles, change to the directory of your platform and run make. For example, on Linux run: cd linux/ make -f Makefile-manual To build the Test GUI using the manual makefiles: cd testgui/ make -f Makefile-manual Building on Windows: --------------------- To build the HIDAPI DLL on Windows using Visual Studio, build the .sln file in the windows/ directory. To build the Test GUI on windows using Visual Studio, build the .sln file in the testgui/ directory. To build HIDAPI using MinGW or Cygwin using Autotools, use the instructions in the section titled "Building HIDAPI into a shared library on Unix Platforms" above. Note that building the Test GUI with MinGW or Cygwin will require the Windows procedure in the Prerequisites section above (ie: hidapi-externals.zip). To build HIDAPI using MinGW using the Manual Makefiles, see the section "Building the manual way on Unix platforms" above. HIDAPI can also be built using the Windows DDK (now also called the Windows Driver Kit or WDK). This method was originally required for the HIDAPI build but not anymore. However, some users still prefer this method. It is not as well supported anymore but should still work. Patches are welcome if it does not. To build using the DDK: 1. Install the Windows Driver Kit (WDK) from Microsoft. 2. From the Start menu, in the Windows Driver Kits folder, select Build Environments, then your operating system, then the x86 Free Build Environment (or one that is appropriate for your system). 3. From the console, change directory to the windows/ddk_build/ directory, which is part of the HIDAPI distribution. 4. Type build. 5. You can find the output files (DLL and LIB) in a subdirectory created by the build system which is appropriate for your environment. On Windows XP, this directory is objfre_wxp_x86/i386. Cross Compiling ================ This section talks about cross compiling HIDAPI for Linux using autotools. This is useful for using HIDAPI on embedded Linux targets. These instructions assume the most raw kind of embedded Linux build, where all prerequisites will need to be built first. This process will of course vary based on your embedded Linux build system if you are using one, such as OpenEmbedded or Buildroot. For the purpose of this section, it will be assumed that the following environment variables are exported. $ export STAGING=$HOME/out $ export HOST=arm-linux STAGING and HOST can be modified to suit your setup. Prerequisites -------------- Note that the build of libudev is the very basic configuration. Build Libusb. From the libusb source directory, run: ./configure --host=$HOST --prefix=$STAGING make make install Build libudev. From the libudev source directory, run: ./configure --disable-gudev --disable-introspection --disable-hwdb \ --host=$HOST --prefix=$STAGING make make install Building HIDAPI ---------------- Build HIDAPI: PKG_CONFIG_DIR= \ PKG_CONFIG_LIBDIR=$STAGING/lib/pkgconfig:$STAGING/share/pkgconfig \ PKG_CONFIG_SYSROOT_DIR=$STAGING \ ./configure --host=$HOST --prefix=$STAGING Signal 11 Software - 2010-04-11 2010-07-28 2011-09-10 2012-05-01 2012-07-03 openzwave-1.6.1914/cpp/hidapi/doxygen/0000777000175200017520000000000014032143200014466 500000000000000openzwave-1.6.1914/cpp/hidapi/doxygen/Doxyfile0000644000175200017520000020447414032142455016136 00000000000000# Doxyfile 1.7.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = hidapi # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penality. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will rougly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. The create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../hidapi # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the stylesheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvances is that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = FreeSans.ttf # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = YES # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES openzwave-1.6.1914/cpp/hidapi/bootstrap0000755000175200017520000000006414032142455014703 00000000000000#!/bin/sh -x autoreconf --install --verbose --force openzwave-1.6.1914/cpp/hidapi/Makefile.am0000644000175200017520000000210014032142455014765 00000000000000 ACLOCAL_AMFLAGS = -I m4 if OS_FREEBSD pkgconfigdir=$(prefix)/libdata/pkgconfig else pkgconfigdir=$(libdir)/pkgconfig endif if OS_LINUX pkgconfig_DATA=pc/hidapi-hidraw.pc pc/hidapi-libusb.pc else pkgconfig_DATA=pc/hidapi.pc endif SUBDIRS= if OS_LINUX SUBDIRS += linux libusb endif if OS_DARWIN SUBDIRS += mac endif if OS_FREEBSD SUBDIRS += libusb endif if OS_WINDOWS SUBDIRS += windows endif SUBDIRS += hidtest if BUILD_TESTGUI SUBDIRS += testgui endif EXTRA_DIST = udev doxygen dist_doc_DATA = \ README.txt \ AUTHORS.txt \ LICENSE-bsd.txt \ LICENSE-gpl3.txt \ LICENSE-orig.txt \ LICENSE.txt SCMCLEAN_TARGETS= \ aclocal.m4 \ config.guess \ config.sub \ configure \ config.h.in \ depcomp \ install-sh \ ltmain.sh \ missing \ mac/Makefile.in \ testgui/Makefile.in \ libusb/Makefile.in \ Makefile.in \ linux/Makefile.in \ windows/Makefile.in \ m4/libtool.m4 \ m4/lt~obsolete.m4 \ m4/ltoptions.m4 \ m4/ltsugar.m4 \ m4/ltversion.m4 SCMCLEAN_DIR_TARGETS = \ autom4te.cache scm-clean: distclean rm -f $(SCMCLEAN_TARGETS) rm -Rf $(SCMCLEAN_DIR_TARGETS) openzwave-1.6.1914/cpp/hidapi/m4/0000777000175200017520000000000014032143200013331 500000000000000openzwave-1.6.1914/cpp/hidapi/m4/pkg.m40000644000175200017520000001214514032142455014306 00000000000000# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # # Copyright © 2004 Scott James Remnant . # # 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. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # # Similar to PKG_CHECK_MODULES, make sure that the first instance of # this or PKG_CHECK_MODULES is called, or make sure to call # PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_ifval([$2], [$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$PKG_CONFIG"; then if test -n "$$1"; then pkg_cv_[]$1="$$1" else PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], [pkg_failed=yes]) fi else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"` else $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD ifelse([$4], , [AC_MSG_ERROR(dnl [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT ])], [AC_MSG_RESULT([no]) $4]) elif test $pkg_failed = untried; then ifelse([$4], , [AC_MSG_FAILURE(dnl [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])], [$4]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) ifelse([$3], , :, [$3]) fi[]dnl ])# PKG_CHECK_MODULES openzwave-1.6.1914/cpp/hidapi/m4/ax_pthread.m40000644000175200017520000003036614032142455015651 00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_pthread.html # =========================================================================== # # SYNOPSIS # # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. It # sets the PTHREAD_LIBS output variable to the threads library and linker # flags, and the PTHREAD_CFLAGS output variable to any special C compiler # flags that are needed. (The user can also force certain compiler # flags/libs to be tested by setting these environment variables.) # # Also sets PTHREAD_CC to any special C compiler that is needed for # multi-threaded programs (defaults to the value of CC otherwise). (This # is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, # but also link it with them as well. e.g. you should link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # # If you are only building threads programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant # has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name # (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with # PTHREAD_CFLAGS. # # ACTION-IF-FOUND is a list of shell commands to run if a threads library # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it # is not found. If ACTION-IF-FOUND is not specified, the default action # will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or if # you have any other suggestions or comments. This macro was based on work # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by # Alejandro Forero Cuervo to the autoconf macro repository. We are also # grateful for the helpful feedback of numerous users. # # Updated for Autoconf 2.68 by Daniel Richard G. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2011 Daniel Richard G. # # 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 3 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, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 18 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes) AC_MSG_RESULT($ax_pthread_ok) if test x"$ax_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case ${host_os} in solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" ;; darwin*) ax_pthread_flags="-pthread $ax_pthread_flags" ;; esac if test x"$ax_pthread_ok" = xno; then for flag in $ax_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no) if test x"$ax_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE([AC_LANG_PROGRAM([#include static void routine(void *a) { a = 0; } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */])], [ax_pthread_ok=yes], []) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($ax_pthread_ok) if test "x$ax_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$ax_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [int attr = $attr; return attr /* ; */])], [attr_name=$attr; break], []) done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case ${host_os} in aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; osf* | hpux*) flag="-D_REENTRANT";; solaris*) if test "$GCC" = "yes"; then flag="-D_REENTRANT" else flag="-mt -D_REENTRANT" fi ;; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], ax_cv_PTHREAD_PRIO_INHERIT, [ AC_LINK_IFELSE([ AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT;]])], [ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.])) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) else PTHREAD_CC=$CC fi else PTHREAD_CC="$CC" fi AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$ax_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else ax_pthread_ok=no $2 fi AC_LANG_POP ])dnl AX_PTHREAD openzwave-1.6.1914/cpp/hidapi/udev/0000777000175200017520000000000014032143200013754 500000000000000openzwave-1.6.1914/cpp/hidapi/udev/99-hid.rules0000644000175200017520000000276414032142455015773 00000000000000# This is a sample udev file for HIDAPI devices which changes the permissions # to 0666 (world readable/writable) for a specified device on Linux systems. # If you are using the libusb implementation of hidapi (hid-libusb.c), then # use something like the following line, substituting the VID and PID with # those of your device. Note that for kernels before 2.6.24, you will need # to substitute "usb" with "usb_device". It shouldn't hurt to use two lines # (one each way) for compatibility with older systems. # HIDAPI/libusb SUBSYSTEM=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="003f", MODE="0666" # If you are using the hidraw implementation, then do something like the # following, substituting the VID and PID with your device. Busnum 1 is USB. # HIDAPI/hidraw KERNEL=="hidraw*", ATTRS{busnum}=="1", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="003f", MODE="0666" # Once done, optionally rename this file for your device, and drop it into # /etc/udev/rules.d and unplug and re-plug your device. This is all that is # necessary to see the new permissions. Udev does not have to be restarted. # Note that the hexadecimal values for VID and PID are case sensitive and # must be lower case. # If you think permissions of 0666 are too loose, then see: # http://reactivated.net/writing_udev_rules.html for more information on finer # grained permission setting. For example, it might be sufficient to just # set the group or user owner for specific devices (for example the plugdev # group on some systems). openzwave-1.6.1914/cpp/hidapi/LICENSE.txt0000644000175200017520000000101214032142455014555 00000000000000HIDAPI can be used under one of three licenses. 1. The GNU Public License, version 3.0, in LICENSE-gpl3.txt 2. A BSD-Style License, in LICENSE-bsd.txt. 3. The more liberal original HIDAPI license. LICENSE-orig.txt The license chosen is at the discretion of the user of HIDAPI. For example: 1. An author of GPL software would likely use HIDAPI under the terms of the GPL. 2. An author of commercial closed-source software would likely use HIDAPI under the terms of the BSD-style license or the original HIDAPI license. openzwave-1.6.1914/cpp/hidapi/HACKING.txt0000644000175200017520000000054714032142455014553 00000000000000This file is mostly for the maintainer. 1. Build hidapi.dll 2. Build hidtest.exe in DEBUG and RELEASE 3. Commit all 4. Run the Following export VERSION=0.1.0 export TAG_NAME=hidapi-$VERSION git tag $TAG_NAME git archive --format zip --prefix $TAG_NAME/ $TAG_NAME >../$TAG_NAME.zip 5. Test the zip file. 6. Run the following: git push origin $TAG_NAME openzwave-1.6.1914/cpp/hidapi/hidapi/0000777000175200017520000000000014032143200014247 500000000000000openzwave-1.6.1914/cpp/hidapi/hidapi/hidapi.h0000644000175200017520000003216514032142455015614 00000000000000/******************************************************* HIDAPI - Multi-Platform library for communication with HID devices. Alan Ott Signal 11 Software 8/22/2009 Copyright 2009, All Rights Reserved. At the discretion of the user of this library, this software may be licensed under the terms of the GNU Public License v3, a BSD-Style license, or the original HIDAPI license as outlined in the LICENSE.txt, LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt files located at the root of the source distribution. These files may also be found in the public source code repository located at: http://github.com/signal11/hidapi . ********************************************************/ /** @file * @defgroup API hidapi API */ #ifndef HIDAPI_H__ #define HIDAPI_H__ #include #ifdef _WIN32 #define HID_API_EXPORT __declspec(dllexport) #define HID_API_CALL #else #define HID_API_EXPORT /**< API export macro */ #define HID_API_CALL /**< API call macro */ #endif #define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/ #ifdef __cplusplus extern "C" { #endif struct hid_device_; typedef struct hid_device_ hid_device; /**< opaque hidapi structure */ /** hidapi info structure */ struct hid_device_info { /** Platform-specific device path */ char *path; /** Device Vendor ID */ unsigned short vendor_id; /** Device Product ID */ unsigned short product_id; /** Serial Number */ wchar_t *serial_number; /** Device Release Number in binary-coded decimal, also known as Device Version Number */ unsigned short release_number; /** Manufacturer String */ wchar_t *manufacturer_string; /** Product string */ wchar_t *product_string; /** Usage Page for this Device/Interface (Windows/Mac only). */ unsigned short usage_page; /** Usage for this Device/Interface (Windows/Mac only).*/ unsigned short usage; /** The USB interface which this logical device represents. Valid on both Linux implementations in all cases, and valid on the Windows implementation only if the device contains more than one interface. */ int interface_number; /** Pointer to the next device */ struct hid_device_info *next; }; /** @brief Initialize the HIDAPI library. This function initializes the HIDAPI library. Calling it is not strictly necessary, as it will be called automatically by hid_enumerate() and any of the hid_open_*() functions if it is needed. This function should be called at the beginning of execution however, if there is a chance of HIDAPI handles being opened by different threads simultaneously. @ingroup API @returns This function returns 0 on success and -1 on error. */ int HID_API_EXPORT HID_API_CALL hid_init(void); /** @brief Finalize the HIDAPI library. This function frees all of the static data associated with HIDAPI. It should be called at the end of execution to avoid memory leaks. @ingroup API @returns This function returns 0 on success and -1 on error. */ int HID_API_EXPORT HID_API_CALL hid_exit(void); /** @brief Enumerate the HID Devices. This function returns a linked list of all the HID devices attached to the system which match vendor_id and product_id. If @p vendor_id is set to 0 then any vendor matches. If @p product_id is set to 0 then any product matches. If @p vendor_id and @p product_id are both set to 0, then all HID devices will be returned. @ingroup API @param vendor_id The Vendor ID (VID) of the types of device to open. @param product_id The Product ID (PID) of the types of device to open. @returns This function returns a pointer to a linked list of type struct #hid_device, containing information about the HID devices attached to the system, or NULL in the case of failure. Free this linked list by calling hid_free_enumeration(). */ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id); /** @brief Free an enumeration Linked List This function frees a linked list created by hid_enumerate(). @ingroup API @param devs Pointer to a list of struct_device returned from hid_enumerate(). */ void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs); /** @brief Open a HID device using a Vendor ID (VID), Product ID (PID) and optionally a serial number. If @p serial_number is NULL, the first device with the specified VID and PID is opened. @ingroup API @param vendor_id The Vendor ID (VID) of the device to open. @param product_id The Product ID (PID) of the device to open. @param serial_number The Serial Number of the device to open (Optionally NULL). @returns This function returns a pointer to a #hid_device object on success or NULL on failure. */ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number); /** @brief Open a HID device by its path name. The path name be determined by calling hid_enumerate(), or a platform-specific path name can be used (eg: /dev/hidraw0 on Linux). @ingroup API @param path The path name of the device to open @returns This function returns a pointer to a #hid_device object on success or NULL on failure. */ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path); /** @brief Write an Output report to a HID device. The first byte of @p data[] must contain the Report ID. For devices which only support a single report, this must be set to 0x0. The remaining bytes contain the report data. Since the Report ID is mandatory, calls to hid_write() will always contain one more byte than the report contains. For example, if a hid report is 16 bytes long, 17 bytes must be passed to hid_write(), the Report ID (or 0x0, for devices with a single report), followed by the report data (16 bytes). In this example, the length passed in would be 17. hid_write() will send the data on the first OUT endpoint, if one exists. If it does not, it will send the data through the Control Endpoint (Endpoint 0). @ingroup API @param device A device handle returned from hid_open(). @param data The data to send, including the report number as the first byte. @param length The length in bytes of the data to send. @returns This function returns the actual number of bytes written and -1 on error. */ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length); /** @brief Read an Input report from a HID device with timeout. Input reports are returned to the host through the INTERRUPT IN endpoint. The first byte will contain the Report number if the device uses numbered reports. @ingroup API @param device A device handle returned from hid_open(). @param data A buffer to put the read data into. @param length The number of bytes to read. For devices with multiple reports, make sure to read an extra byte for the report number. @param milliseconds timeout in milliseconds or -1 for blocking wait. @returns This function returns the actual number of bytes read and -1 on error. */ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds); /** @brief Read an Input report from a HID device. Input reports are returned to the host through the INTERRUPT IN endpoint. The first byte will contain the Report number if the device uses numbered reports. @ingroup API @param device A device handle returned from hid_open(). @param data A buffer to put the read data into. @param length The number of bytes to read. For devices with multiple reports, make sure to read an extra byte for the report number. @returns This function returns the actual number of bytes read and -1 on error. */ int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length); /** @brief Set the device handle to be non-blocking. In non-blocking mode calls to hid_read() will return immediately with a value of 0 if there is no data to be read. In blocking mode, hid_read() will wait (block) until there is data to read before returning. Nonblocking can be turned on and off at any time. @ingroup API @param device A device handle returned from hid_open(). @param nonblock enable or not the nonblocking reads - 1 to enable nonblocking - 0 to disable nonblocking. @returns This function returns 0 on success and -1 on error. */ int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock); /** @brief Send a Feature report to the device. Feature reports are sent over the Control endpoint as a Set_Report transfer. The first byte of @p data[] must contain the Report ID. For devices which only support a single report, this must be set to 0x0. The remaining bytes contain the report data. Since the Report ID is mandatory, calls to hid_send_feature_report() will always contain one more byte than the report contains. For example, if a hid report is 16 bytes long, 17 bytes must be passed to hid_send_feature_report(): the Report ID (or 0x0, for devices which do not use numbered reports), followed by the report data (16 bytes). In this example, the length passed in would be 17. @ingroup API @param device A device handle returned from hid_open(). @param data The data to send, including the report number as the first byte. @param length The length in bytes of the data to send, including the report number. @returns This function returns the actual number of bytes written and -1 on error. */ int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length); /** @brief Get a feature report from a HID device. Make sure to set the first byte of @p data[] to the Report ID of the report to be read. Make sure to allow space for this extra byte in @p data[]. @ingroup API @param device A device handle returned from hid_open(). @param data A buffer to put the read data into, including the Report ID. Set the first byte of @p data[] to the Report ID of the report to be read. @param length The number of bytes to read, including an extra byte for the report ID. The buffer can be longer than the actual report. @returns This function returns the number of bytes read and -1 on error. */ int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length); /** @brief Close a HID device. @ingroup API @param device A device handle returned from hid_open(). */ void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device); /** @brief Get The Manufacturer String from a HID device. @ingroup API @param device A device handle returned from hid_open(). @param string A wide string buffer to put the data into. @param maxlen The length of the buffer in multiples of wchar_t. @returns This function returns 0 on success and -1 on error. */ int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen); /** @brief Get The Product String from a HID device. @ingroup API @param device A device handle returned from hid_open(). @param string A wide string buffer to put the data into. @param maxlen The length of the buffer in multiples of wchar_t. @returns This function returns 0 on success and -1 on error. */ int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen); /** @brief Get The Serial Number String from a HID device. @ingroup API @param device A device handle returned from hid_open(). @param string A wide string buffer to put the data into. @param maxlen The length of the buffer in multiples of wchar_t. @returns This function returns 0 on success and -1 on error. */ int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen); /** @brief Get a string from a HID device, based on its string index. @ingroup API @param device A device handle returned from hid_open(). @param string_index The index of the string to get. @param string A wide string buffer to put the data into. @param maxlen The length of the buffer in multiples of wchar_t. @returns This function returns 0 on success and -1 on error. */ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen); /** @brief Get a string describing the last error which occurred. @ingroup API @param device A device handle returned from hid_open(). @returns This function returns a string containing the last error which occurred or NULL if none has occurred. */ HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device); #ifdef __cplusplus } #endif #endif openzwave-1.6.1914/.gitignore0000644000175200017520000000217414032142454012713 00000000000000.dep/ .lib/ MinOZW cpp/src/vers.cpp libopenzwave.a libopenzwave.pc libopenzwave.so* libopenzwave.so *.obj /cpp/build/windows/vs2010/Debug/*.log /cpp/build/windows/vs2010/Debug/OpenZWave.tlog/*.tlog /cpp/build/windows/vs2010/Debug/OpenZWave.tlog/*.lastbuildstate /cpp/build/windows/mingw32/*.o /cpp/build/windows/mingw32/*.d /cpp/build/windows/mingw32/*.d.* /cpp/build/windows/mingw32/vers.c /cpp/lib/windows-mingw32 *.idb *.pdb *.log *.tlog /dotnet/build/vs2010/Debug/app.res Debug /dotnet/examples/OZWForm/src/OZWForm.csproj /dotnet/examples/OZWForm/src/OZWForm.sdf /dotnet/examples/OZWForm/src/OZWForm.sln /dotnet/examples/OZWForm/src/OZWForm.v12.suo *.cache *.res *.lib *.dll *.metagen *.exp *.exe OZWForm.exe.config OZWForm.vshost.exe.config OZWForm.vshost.exe.manifest *.resources /dotnet/examples/OZWForm/src/bin/x86/Release/OZW_Log.txt /dotnet/examples/OZWForm/src/bin/x86/Release /dotnet/examples/OZWForm/src/obj/x86/Release .gitignore /cpp/build/windows/winversion.cpp .distfiles *.dylib *.txt ozw_config .project *~ /.cproject /zwscene.xml /ozwcache_*.xml .idea/ .idea/* ozw_config gtest-main cpp/src/command_classes/\.DS_Store .DS_Store openzwave-1.6.1914/tools/0000777000175200017520000000000014032143202012133 500000000000000openzwave-1.6.1914/tools/imagedownload.pl0000755000175200017520000000103214032142455015226 00000000000000#!/usr/bin/perl -w use Image::Resize; use File::Fetch; use POSIX; use open qw/ :std :encoding(utf-8) /; BEGIN { $| = 1; } my $imgurl = $ARGV[0]; print "Downloading $imgurl...."; my $download = File::Fetch->new(uri => $imgurl); my $file = $download->fetch() or die $download->error; File::Copy::move($file, 'productimage.png'); print "Done\n\nResizing...."; my $img = Image::Resize->new('productimage.png'); my $gd = $img->resize(200,200); $gd->_file('productimage.png'); print "Done\n\nSaved as productimage.png\n"; openzwave-1.6.1914/docs/0000777000175200017520000000000014032143202011723 500000000000000openzwave-1.6.1914/docs/general/0000777000175200017520000000000014032143202013340 500000000000000openzwave-1.6.1914/docs/general/MakingDocumentation.html0000644000175200017520000000702714032142455020121 00000000000000 Creating OpenZWave Documentation
Logo Creating OpenZWave
Documentation

Introduction

OpenZWave is still under development, and new features, bug fixes and interface changes are being made on a frequent basis.  So it's premature to focus too much energy on producing user documentation at this point.  However, several users have asked whether there is documentation available.

So here is a guide to producing your own version of the documentation (such as it is).

Doxygen-style comments

Much of the source code for the OpenZWave library and the OpenZWaveDotNet wrapper has been documented via comments in the .h header files associated with these projects.  So, if you're working with OpenZWave in a development environment (which most users will be, since only source code is available at this point), you can find many functions documented in these files.

The format of the comments is designed to allow an external program, called Doxygen, to produce documentation (for example, a series of .html files) by scanning the project files, interpreting these comments and producing the .html code to organize and display the documentation in a sensible manner. So, to produce the most up-to-date copy of the documentation, a user can run Doxygen on the project folder in question (OpenZWave or OpenZWaveDotNet).

Getting and Using Doxygen

The Doxygen program can be downloaded from http://www.doxygen.org.  Versions of Doxygen are available for Windows, linux and Mac operating systems (as well as source code).

Once Doxygen has been downloaded and installed you can produce documentation by running Doxywizard.exe.  If you're new to Doxygen, here are some step-by-step instructions for creating OpenZWave documentation.

Other Documentation Sources

In addition to the documentation that can be generated with Doxygen, there are a variety of other sources of information on OpenZWave and on the ZWave protocol more generally. Some of these are linked here.

 

openzwave-1.6.1914/docs/general/DoxygenStepByStep.html0000644000175200017520000001011514032142455017551 00000000000000 Creating OpenZWave Documentation
Logo Doxygen Step-by-Step

Introduction

To produce simple doxygen documentation for the OpenZWave libary, follow the steps below.  Once you've successfully produced the base documentation, you may want to use doxygen's Expert mode to customize the output.

Using Doxygen to generate OpenZWave documentation: Step 1

Once Doxygen has been downloaded and installed, run Doxywizard.exe. Here is a screen shot of the first step of the Wizard completed.  

  • Make sure the source code directory points to the OpenZWave cpp/src directory on your system.

  • Select the destination directory of your choice.

Using Doxygen to generate OpenZWave documentation: Step 2

The Mode selections allow you to control how much information is generated and to customize the output for a variety of programming languages. 

You can reduce the amount of documentation generated by selecting "Documented entities only" and de-selecting the "Include cross-referenced..." check box.  If you are using Doxygen to produce documentation for OpenZWaveDotNet, you might prefer "Optimize for C++/CLI output."

a


Using Doxygen to generate OpenZWave documentation: Step 3

The Output step determines what form the generated documentation should take. I generally prefer HTML with a navigation tree, searchable, but others are available.  

a


Using Doxygen to generate OpenZWave documentation: Step 4

The Diagrams step determines whether Doxygen will produce class diagrams.  

a


Using Doxygen to generate OpenZWave documentation: Step 5

That's it!  Select the Run tab, then Run doxygen to produce the documentation files.

a

That's it! You should now have a version of OpenZWave documentation in your destination directory.  Navigate into the .../html directory and load index.htm to display the top level of the documentation.

openzwave-1.6.1914/docs/general/Notifications.html0000644000175200017520000003220614032142455016767 00000000000000 Notification Messages and Sequence
Logo Notification Messages
and Sequence

Purpose

Several questions from developers using the OpenZWave library have suggested confusion about the meaning of notifications sent by the library. This document is intended to clarify and document the notifications sent by the library and to indicate what information is “known” at the time the notifications are sent. This will, hopefully, assist developers in designing the actions to take upon receipt of each notification.

Important Note

You should be aware that notifications are blocking. That is, when a notification is sent to an application, the OpenZWave library will wait until the callback function returns. So, for example, if you put a modal dialog box (for Windows users) in the notification handler in your application, OpenZWave will essentially stop communicating with the Z-Wave controller until the dialog box is dismissed and the notification handler returns.

This "feature" may be changed in the future, but for now developers must be aware of this issue.


Format

The table presented below lists notifications in the order they might typically be received, and grouped into a few logically related categories.  Of course, given the variety of ZWave controllers, devices and network configurations the actual sequence will vary (somewhat).  The descriptions below the notification name (in square brackets) identify whether the notification is always sent (unless there’s a significant error in the network or software) or potentially sent during the execution sequence.


Driver Initialization Notification

The notification below is sent when OpenZWave has successfully connected to a physical ZWave controller.

DriverReady
[always sent]
Sent when the driver (representing a connection between OpenZWave and a Z-Wave controller attached to the specified serial (or HID) port) has been initialized.

At the time this notification is sent, only certain information about the controller itself is known:
  • Controller Z-Wave version
  • Network HomeID
  • Controller capabilities
  • Controller Application Version & Manufacturer/Product ID
  • Nodes included in the network

Node Initialization Notifications

As OpenZWave starts, it identifies and reads information about each node in the network. The following notifications may be sent during the initialization process.

NodeNew
[potentially sent]
Sent when a new node has been identified as part of the Z-Wave network. It is not sent if the node was identified in a prior execution of the OpenZWave library and stored in the zwcfg*.xml file.

At the time this notification is sent, very little is known about the node itself...only that it is new to OpenZWave. This message is sent once for each new node identified.
   
NodeAdded
[always sent (for each node associated with the controller)]
Sent when a node has been added to OpenZWaves list of nodes. It can be triggered either as the zwcfg*.xml file is being read, when a new node is found on startup (see NodeNew notification above), or if a new node is included in the network while OpenZWave is running.

As with NodeNew, very little is known about the node at the time the notification is sentjust the fact that a new node has been identified and its assigned NodeID.
 
NodeProtocolInfo
[potentially sent]
Sent after a nodes protocol information has been successfully read from the controller.

At the time this notification is sent, only certain information about the node is known:
  • Whether it is a listening or sleeping device
  • Whether the node is capable of routing messages
  • Maximum baud rate for communication
  • Version number
  • Security byte
NodeNaming
[potentially sent]
Sent when a nodes name has been set or changed (although it may be set to or NULL).
ValueAdded
[potentially sent]
Sent when a new value has been associated with the node.

At the time this notification is sent, the new value may or may not have live data associated with it. It may be populated, but it may alternatively just be a placeholder for a value that has not been read at the time the notification is sent.
NodeQueriesComplete
[always sent (for each node associated with the controller that has been successfully queried)]
Sent when a nodes values and attributes have been fully queried. At the time this notification is sent, the nodes information has been fully read at least once. So this notification might trigger full display of the nodes information, values, etc. If this notification is not sent, it indicates that there has been a problem initializing the device. The most common issue is that the node is a sleeping device. The NodeQueriesComplete notification will be sent when the node wakes up and the query process completes.

Initialization Complete Notifications

As indicated above, when OpenZWave starts it reads certain information from a file, from the controller and from the network. The following notifications identify when this initialization/querying process is complete.

AwakeNodesQueried
[always sent]
Sent when all listeningalways-ondevices have been queried successfully. It also indicates, by implication, that there are some sleeping nodes that will not complete their queries until they wake up. This notification should be sent relatively quickly after start-up. (Of course, it depends on the number of devices on the ZWave network and whether there are any messages that time out without a proper response.)
AllNodesQueried
[potentially sent]
Sent when all nodes have been successfully queried.

This notification should be sent relatively quickly if there are no sleeping nodes. But it might be sent quite a while after start-up if there are sleeping nodes and at least one of these nodes has a long wake-up interval.

Other Notifications

In addition to the notifications described above, which are primarily initialization notifications that are sent during program start-up, the following notifications may be sent as a result of user actions, external program control, etc.

ValueChanged Sent when a value associated with a node has changed. Receipt of this notification indicates that it may be a good time to read the new value and display or otherwise process it accordingly.
ValueRemoved Sent when a value associated with a node has been removed.
Group Sent when a nodes group association has changed.
NodeRemoved Sent when a node has been removed from the ZWave network.
NodeEvent Sent when a node sends a Basic_Set command to the controller.  This notification can be generated by certain sensors, for example, motion detectors, to indicate that an event has been sensed.
PollingEnabled Sent when node/value polling has been enabled.
PollingDisabled Sent when node/value polling has been disabled.
DriverReset Sent to indicate when a controller has been reset. This notification is intended to replace the potentially hundreds of notifications representing each value and node removed from the network.
openzwave-1.6.1914/docs/general/Index.htm0000644000175200017520000000336414032142455015054 00000000000000 Other OpenZWave Documents
Logo OpenZWave Information

The following pages provide additional information about the ZWave protocol and the OpenZWave library.

General

Getting Help with OpenZWave

Generating OpenZWave Documentation

OpenZWave Architecture and Use

Notification Messages and Sequence

The Z-Wave Protocol

 

Z-Wave Devices

 

External Links to Other Z-Wave Information

 

openzwave-1.6.1914/docs/general/GettingHelp.html0000644000175200017520000001361314032142455016371 00000000000000 Getting Help with OpenZWave
Logo Getting Help
With OpenZWave

Need Help?

Since the OpenZWave library is still in early stages of development, you should not be surprised if it doesn't work as you might expect (despite our continuing efforts to stamp out bugs and add features). 

In particular, given the wide variety of Z-Wave devices and the fact that the developers of OpenZWave do not have access to the full protocol, certain portions of the code have not been tested with actual devices, so some problems are (unfortunately) inevitable. However, with more users testing the library with new Z-Wave devices, we should be able to identify and eliminate any faulty assumptions or logical (or careless) errors.

Based on the questions raised in the OpenZWave forum (link), here are some pointers to getting your questions answered.

I.  Generate and Review the Documentation

Although OpenZWave doesn't have user documentation as yet, the source code has been commented in a way that will allow an external program, Doxygen, to produce HTML documentation for the library.  Here is a description of how to generate this documentation.

II.  Isolate the Problem Using the MinOZW or OZWForm Examples

Some users' issues with OpenZWave have proven to be related to either their own (calling) code or a misunderstanding about how the library is supposed to work.  The documentation (see I above) should help reduce misunderstandings.  And reproducing the problem using small changes to the example code will help other developers and users try to replicate the issue.  Once you can reproduce the problem, post a forum message identifying:

  1. The nature of the problem (what's wrong?)
  2. What changes you made to MinOZW or OZWForm to replicate the issue (if they're substantial, you may want to attach the modified source code file(s) to your post)
  3. What hardware is involved (in particular, the Z-Wave controller attached to the PC and the device/node in question)--manufacturer and model number
  4. Where the problem is evident in an OZWlog.txt file (and attaching the log file to your post--see below)

III.  The OpenZWave Execution Log: OZWlog.txt

The OpenZWave library generates an execution log whenever it is run. (The library has been designed to allow this feature to be turned off, but at this early stage in development it should always be produced.)  The log file can be very helpful in diagnosing problems with OpenZWave.  It identifies the startup steps, communication between the OpenZWave library and the controller (and, through the controller, with the various nodes on the Z-Wave network).  It can help identify whether there is a problem with the library, the controller or a Z-Wave node).

So, if you're having a problem, try the following:

  1. Stop the OpenZWave application (if one is running)
  2. Locate and delete any copies of the zwcfg*.xml file. (The actual file name will have the Z-Wave network's HomeID in place of the '*' in the file name.)  This will cause the OpenZWave library to identify each node on the network as "New" and poll each device for its capabilities, settings, etc.
  3. Run the application using OpenZWave until the problem occurs.
  4. Exit the program and review the OZWlog.txt file that was created. Are there any unusual errors on startup?  Do the Z-Wave devices report the capabilities (command classes handled) that you expect?  Do the static, session and dynamic values look right?  Can you identify where execution went "off track" (sent a new command? unexpected response received? no response received to a command?)?
  5. Review of the log file may help you identify what went wrong with your code (or what's wrong with the OpenZWave library).
  6. If you can't figure out what's going wrong from the review of the log and the other suggestions outlined on this page, consider posting a message to the discussion forum and attach a copy of the OZWlog.txt file.  But keep in mind, it is often very helpful to have a "clean" log file to work with...one that shows the nodes in the network as "New," and not as "Known."  (See Step 2 above.)
openzwave-1.6.1914/docs/Doxyfile.in0000644000175200017520000030227414032142455013773 00000000000000# Doxyfile 1.8.5 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "OpenZWave Library" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = @VERSION@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is included in # the documentation. The maximum height of the logo should not exceed 55 pixels # and the maximum width should not exceed 200 pixels. Doxygen will copy the logo # to the output directory. PROJECT_LOGO = @TOPSRC_DIR@/docs/images+css/image003.gif # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = @OUTPUT_DIR@ # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese- # Traditional, Croatian, Czech, Danish, Dutch, English, Esperanto, Farsi, # Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en, # Korean, Korean-en, Latvian, Norwegian, Macedonian, Persian, Polish, # Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, # Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = No # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a # new page for each member. If set to NO, the documentation of a member will be # part of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. # # Note For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by by putting a % sign in front of the word # or globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined # locally in source files will be included in the documentation. If set to NO # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = NO # This flag is only useful for Objective-C code. When set to YES local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO these classes will be included in the various overviews. This option has # no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO the members will appear in declaration order. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the # todo list. This list is created by putting \todo commands in the # documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the # test list. This list is created by putting \test commands in the # documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES the list # will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. Do not use file names with spaces, bibtex cannot handle them. See # also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = NO # If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = NO # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO doxygen will only warn about wrong or incomplete parameter # documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = doxygen.log #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. # Note: If this tag is empty the current directory is searched. INPUT = @TOPSRC_DIR@/cpp/src/ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank the # following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, # *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, # *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. FILE_PATTERNS = # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = @TOPSRC_DIR@/cpp/src/platform/unix/ @TOPSRC_DIR@/cpp/src/platform/windows/ @TOPSRC_DIR@/cpp/src/platform/winRT @TOPSRC_DIR@/cpp/src/aes/ # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = @(TOPSRC_DIR)/cpp/examples/ # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = YES # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = @TOPSRC_DIR@/docs/images+css/ # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER ) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES, then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. # SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- # defined cascading style sheet that is included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefor more robust against future updates. # Doxygen will copy the style sheet file to the output directory. For an example # see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to NO can help when comparing the output of multiple runs. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler ( hhc.exe). If non-empty # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated ( # YES) or that it should be included in the master .chm file ( NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated ( # YES) or a normal table of contents ( NO) in the .chm file. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. # MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /