xref: /openbmc/phosphor-logging/extensions/openpower-pels/dbus_watcher.hpp (revision 075c79237505ea3b810a461f5f514e4d520a0c44)
12a28c936SMatt Spinler #pragma once
22a28c936SMatt Spinler 
32a28c936SMatt Spinler #include "dbus_types.hpp"
42a28c936SMatt Spinler 
52a28c936SMatt Spinler #include <sdbusplus/bus/match.hpp>
62a28c936SMatt Spinler 
72a28c936SMatt Spinler namespace openpower::pels
82a28c936SMatt Spinler {
92a28c936SMatt Spinler 
102a28c936SMatt Spinler namespace match_rules = sdbusplus::bus::match::rules;
112a28c936SMatt Spinler 
122a28c936SMatt Spinler /**
132a28c936SMatt Spinler  * @class DBusWatcher
142a28c936SMatt Spinler  *
152a28c936SMatt Spinler  * The base class for the PropertyWatcher and InterfaceWatcher classes.
162a28c936SMatt Spinler  */
172a28c936SMatt Spinler class DBusWatcher
182a28c936SMatt Spinler {
192a28c936SMatt Spinler   public:
202a28c936SMatt Spinler     DBusWatcher() = delete;
212a28c936SMatt Spinler     virtual ~DBusWatcher() = default;
222a28c936SMatt Spinler     DBusWatcher(const DBusWatcher&) = default;
232a28c936SMatt Spinler     DBusWatcher& operator=(const DBusWatcher&) = default;
242a28c936SMatt Spinler     DBusWatcher(DBusWatcher&&) = default;
252a28c936SMatt Spinler     DBusWatcher& operator=(DBusWatcher&&) = default;
262a28c936SMatt Spinler 
272a28c936SMatt Spinler     /**
282a28c936SMatt Spinler      * @brief Constructor
292a28c936SMatt Spinler      *
302a28c936SMatt Spinler      * @param[in] path - The D-Bus path that will be watched
312a28c936SMatt Spinler      * @param[in] interface - The D-Bus interface that will be watched
322a28c936SMatt Spinler      */
DBusWatcher(const std::string & path,const std::string & interface)332a28c936SMatt Spinler     DBusWatcher(const std::string& path, const std::string& interface) :
342a28c936SMatt Spinler         _path(path), _interface(interface)
352544b419SPatrick Williams     {}
362a28c936SMatt Spinler 
372a28c936SMatt Spinler   protected:
382a28c936SMatt Spinler     /**
392a28c936SMatt Spinler      * @brief The D-Bus path
402a28c936SMatt Spinler      */
412a28c936SMatt Spinler     std::string _path;
422a28c936SMatt Spinler 
432a28c936SMatt Spinler     /**
442a28c936SMatt Spinler      * @brief The D-Bus interface
452a28c936SMatt Spinler      */
462a28c936SMatt Spinler     std::string _interface;
472a28c936SMatt Spinler 
482a28c936SMatt Spinler     /**
492a28c936SMatt Spinler      * @brief The match objects for the propertiesChanged and
502a28c936SMatt Spinler      *        interfacesAdded signals.
512a28c936SMatt Spinler      */
522a28c936SMatt Spinler     std::vector<sdbusplus::bus::match_t> _matches;
532a28c936SMatt Spinler };
542a28c936SMatt Spinler 
552a28c936SMatt Spinler /**
562a28c936SMatt Spinler  * @class PropertyWatcher
572a28c936SMatt Spinler  *
582a28c936SMatt Spinler  * This class allows the user to be kept up to data with a D-Bus
592a28c936SMatt Spinler  * property's value.  It does this by calling a user specified function
602a28c936SMatt Spinler  * that is passed the variant that contains the property's value when:
612a28c936SMatt Spinler  *
622a28c936SMatt Spinler  * 1) The property is read when the class is constructed, if
632a28c936SMatt Spinler  *    the property is on D-Bus at the time.
642a28c936SMatt Spinler  * 2) The property changes (via a property changed signal).
652a28c936SMatt Spinler  * 3) An interfacesAdded signal is received with that property.
662a28c936SMatt Spinler  *
672a28c936SMatt Spinler  * The DataInterface class is used to access D-Bus, and is a template
682a28c936SMatt Spinler  * to avoid any circular include issues as that class is one of the
692a28c936SMatt Spinler  * users of this one.
702a28c936SMatt Spinler  */
712a28c936SMatt Spinler template <typename DataIface>
722a28c936SMatt Spinler class PropertyWatcher : public DBusWatcher
732a28c936SMatt Spinler {
742a28c936SMatt Spinler   public:
752a28c936SMatt Spinler     PropertyWatcher() = delete;
762a28c936SMatt Spinler     ~PropertyWatcher() = default;
772a28c936SMatt Spinler     PropertyWatcher(const PropertyWatcher&) = delete;
782a28c936SMatt Spinler     PropertyWatcher& operator=(const PropertyWatcher&) = delete;
792a28c936SMatt Spinler     PropertyWatcher(PropertyWatcher&&) = delete;
802a28c936SMatt Spinler     PropertyWatcher& operator=(PropertyWatcher&&) = delete;
812a28c936SMatt Spinler 
822a28c936SMatt Spinler     using PropertySetFunc = std::function<void(const DBusValue&)>;
832a28c936SMatt Spinler 
842a28c936SMatt Spinler     /**
852a28c936SMatt Spinler      * @brief Constructor
862a28c936SMatt Spinler      *
872a28c936SMatt Spinler      * Reads the property if it is on D-Bus, and sets up the match
882a28c936SMatt Spinler      * objects for the propertiesChanged and interfacesAdded signals.
892a28c936SMatt Spinler      *
902a28c936SMatt Spinler      * @param[in] bus - The sdbusplus bus object
912a28c936SMatt Spinler      * @param[in] path - The D-Bus path of the property
922a28c936SMatt Spinler      * @param[in] interface - The D-Bus interface that contains the property
932a28c936SMatt Spinler      * @param[in] propertyName - The property name
94c1746f6aSMatt Spinler      * @param[in] service - The D-Bus service to use for the property read.
95c1746f6aSMatt Spinler      *                      Can be empty to look it up instead.
962a28c936SMatt Spinler      * @param[in] dataIface - The DataInterface object
972a28c936SMatt Spinler      * @param[in] func - The callback used any time the property is read
982a28c936SMatt Spinler      */
PropertyWatcher(sdbusplus::bus_t & bus,const std::string & path,const std::string & interface,const std::string & propertyName,const std::string & service,const DataIface & dataIface,PropertySetFunc func)9945e83521SPatrick Williams     PropertyWatcher(sdbusplus::bus_t& bus, const std::string& path,
1002a28c936SMatt Spinler                     const std::string& interface,
101c1746f6aSMatt Spinler                     const std::string& propertyName, const std::string& service,
102c1746f6aSMatt Spinler                     const DataIface& dataIface, PropertySetFunc func) :
103*075c7923SPatrick Williams         DBusWatcher(path, interface), _name(propertyName), _setFunc(func)
1042a28c936SMatt Spinler     {
1052a28c936SMatt Spinler         _matches.emplace_back(
1062a28c936SMatt Spinler             bus, match_rules::propertiesChanged(_path, _interface),
1072a28c936SMatt Spinler             std::bind(std::mem_fn(&PropertyWatcher::propChanged), this,
1082a28c936SMatt Spinler                       std::placeholders::_1));
1092a28c936SMatt Spinler 
1102a28c936SMatt Spinler         _matches.emplace_back(
1112a28c936SMatt Spinler             bus,
1122a28c936SMatt Spinler             match_rules::interfacesAdded() + match_rules::argNpath(0, _path),
1132a28c936SMatt Spinler             std::bind(std::mem_fn(&PropertyWatcher::interfaceAdded), this,
1142a28c936SMatt Spinler                       std::placeholders::_1));
11551e927ccSMatt Spinler 
11651e927ccSMatt Spinler         try
11751e927ccSMatt Spinler         {
11851e927ccSMatt Spinler             read(dataIface, service);
11951e927ccSMatt Spinler         }
12045e83521SPatrick Williams         catch (const sdbusplus::exception_t& e)
12151e927ccSMatt Spinler         {
12251e927ccSMatt Spinler             // Path doesn't exist now
12351e927ccSMatt Spinler         }
1242a28c936SMatt Spinler     }
1252a28c936SMatt Spinler 
1262a28c936SMatt Spinler     /**
127c1746f6aSMatt Spinler      * @brief Constructor
128c1746f6aSMatt Spinler      *
129c1746f6aSMatt Spinler      * Reads the property if it is on D-Bus, and sets up the match
130c1746f6aSMatt Spinler      * objects for the propertiesChanged and interfacesAdded signals.
131c1746f6aSMatt Spinler      *
132c1746f6aSMatt Spinler      * Unlike the other constructor, this contructor doesn't take the
133c1746f6aSMatt Spinler      * service to use for the property read so it will look it up with
134c1746f6aSMatt Spinler      * an ObjectMapper GetObject call.
135c1746f6aSMatt Spinler      *
136c1746f6aSMatt Spinler      * @param[in] bus - The sdbusplus bus object
137c1746f6aSMatt Spinler      * @param[in] path - The D-Bus path of the property
138c1746f6aSMatt Spinler      * @param[in] interface - The D-Bus interface that contains the property
139c1746f6aSMatt Spinler      * @param[in] propertyName - The property name
140c1746f6aSMatt Spinler      * @param[in] dataIface - The DataInterface object
141c1746f6aSMatt Spinler      * @param[in] func - The callback used any time the property is read
142c1746f6aSMatt Spinler      */
PropertyWatcher(sdbusplus::bus_t & bus,const std::string & path,const std::string & interface,const std::string & propertyName,const DataIface & dataIface,PropertySetFunc func)14345e83521SPatrick Williams     PropertyWatcher(sdbusplus::bus_t& bus, const std::string& path,
144c1746f6aSMatt Spinler                     const std::string& interface,
145c1746f6aSMatt Spinler                     const std::string& propertyName, const DataIface& dataIface,
146c1746f6aSMatt Spinler                     PropertySetFunc func) :
147c1746f6aSMatt Spinler         PropertyWatcher(bus, path, interface, propertyName, "", dataIface, func)
1482544b419SPatrick Williams     {}
149c1746f6aSMatt Spinler 
150c1746f6aSMatt Spinler     /**
1512a28c936SMatt Spinler      * @brief Reads the property on D-Bus, and calls
1522a28c936SMatt Spinler      *        the user defined function with the value.
1532a28c936SMatt Spinler      *
154c1746f6aSMatt Spinler      * If the passed in service is empty, look up the service to use.
155c1746f6aSMatt Spinler      *
1562a28c936SMatt Spinler      * @param[in] dataIface - The DataInterface object
157c1746f6aSMatt Spinler      * @param[in] service - The D-Bus service to make the getProperty
158c1746f6aSMatt Spinler      *                      call with, if not empty
1592a28c936SMatt Spinler      */
read(const DataIface & dataIface,std::string service)160c1746f6aSMatt Spinler     void read(const DataIface& dataIface, std::string service)
1612a28c936SMatt Spinler     {
162c1746f6aSMatt Spinler         if (service.empty())
163c1746f6aSMatt Spinler         {
164c1746f6aSMatt Spinler             service = dataIface.getService(_path, _interface);
165c1746f6aSMatt Spinler         }
166c1746f6aSMatt Spinler 
1672a28c936SMatt Spinler         if (!service.empty())
1682a28c936SMatt Spinler         {
1692a28c936SMatt Spinler             DBusValue value;
1702a28c936SMatt Spinler             dataIface.getProperty(service, _path, _interface, _name, value);
1712a28c936SMatt Spinler 
1722a28c936SMatt Spinler             _setFunc(value);
1732a28c936SMatt Spinler         }
1742a28c936SMatt Spinler     }
1752a28c936SMatt Spinler 
1762a28c936SMatt Spinler     /**
1772a28c936SMatt Spinler      * @brief The propertiesChanged callback
1782a28c936SMatt Spinler      *
1792a28c936SMatt Spinler      * Calls the user defined function with the property value
1802a28c936SMatt Spinler      *
1812a28c936SMatt Spinler      * @param[in] msg - The sdbusplus message object
1822a28c936SMatt Spinler      */
propChanged(sdbusplus::message_t & msg)18345e83521SPatrick Williams     void propChanged(sdbusplus::message_t& msg)
1842a28c936SMatt Spinler     {
1852a28c936SMatt Spinler         DBusInterface interface;
1862a28c936SMatt Spinler         DBusPropertyMap properties;
1872a28c936SMatt Spinler 
1882a28c936SMatt Spinler         msg.read(interface, properties);
1892a28c936SMatt Spinler 
1902a28c936SMatt Spinler         auto prop = properties.find(_name);
1912a28c936SMatt Spinler         if (prop != properties.end())
1922a28c936SMatt Spinler         {
1932a28c936SMatt Spinler             _setFunc(prop->second);
1942a28c936SMatt Spinler         }
1952a28c936SMatt Spinler     }
1962a28c936SMatt Spinler 
1972a28c936SMatt Spinler     /**
1982a28c936SMatt Spinler      * @brief The interfacesAdded callback
1992a28c936SMatt Spinler      *
2002a28c936SMatt Spinler      * Calls the user defined function with the property value
2012a28c936SMatt Spinler      *
2022a28c936SMatt Spinler      * @param[in] msg - The sdbusplus message object
2032a28c936SMatt Spinler      */
interfaceAdded(sdbusplus::message_t & msg)20445e83521SPatrick Williams     void interfaceAdded(sdbusplus::message_t& msg)
2052a28c936SMatt Spinler     {
2062a28c936SMatt Spinler         sdbusplus::message::object_path path;
2072a28c936SMatt Spinler         DBusInterfaceMap interfaces;
2082a28c936SMatt Spinler 
2092a28c936SMatt Spinler         msg.read(path, interfaces);
2102a28c936SMatt Spinler 
2112a28c936SMatt Spinler         auto iface = interfaces.find(_interface);
2122a28c936SMatt Spinler         if (iface != interfaces.end())
2132a28c936SMatt Spinler         {
2142a28c936SMatt Spinler             auto prop = iface->second.find(_name);
2152a28c936SMatt Spinler             if (prop != iface->second.end())
2162a28c936SMatt Spinler             {
2172a28c936SMatt Spinler                 _setFunc(prop->second);
2182a28c936SMatt Spinler             }
2192a28c936SMatt Spinler         }
2202a28c936SMatt Spinler     }
2212a28c936SMatt Spinler 
2222a28c936SMatt Spinler   private:
2232a28c936SMatt Spinler     /**
2242a28c936SMatt Spinler      * @brief The D-Bus property name
2252a28c936SMatt Spinler      */
2262a28c936SMatt Spinler     std::string _name;
2272a28c936SMatt Spinler 
2282a28c936SMatt Spinler     /**
2292a28c936SMatt Spinler      * @brief The function that will be called any time the
2302a28c936SMatt Spinler      *        property is read.
2312a28c936SMatt Spinler      */
2322a28c936SMatt Spinler     PropertySetFunc _setFunc;
2332a28c936SMatt Spinler };
2342a28c936SMatt Spinler 
2352a28c936SMatt Spinler /**
2362a28c936SMatt Spinler  * @class InterfaceWatcher
2372a28c936SMatt Spinler  *
2382a28c936SMatt Spinler  * This class allows the user to be kept up to data with a D-Bus
2392a28c936SMatt Spinler  * interface's properties..  It does this by calling a user specified
2402a28c936SMatt Spinler  * function that is passed a map of the D-Bus property names and values
2412a28c936SMatt Spinler  * on that interface when:
2422a28c936SMatt Spinler  *
2432a28c936SMatt Spinler  * 1) The interface is read when the class is constructed, if
2442a28c936SMatt Spinler  *    the interface is on D-Bus at the time.
2452a28c936SMatt Spinler  * 2) The interface has a property that changes (via a property changed signal).
2462a28c936SMatt Spinler  * 3) An interfacesAdded signal is received.
2472a28c936SMatt Spinler  *
2482a28c936SMatt Spinler  * The DataInterface class is used to access D-Bus, and is a template
2492a28c936SMatt Spinler  * to avoid any circular include issues as that class is one of the
2502a28c936SMatt Spinler  * users of this one.
2512a28c936SMatt Spinler  */
2522a28c936SMatt Spinler template <typename DataIface>
2532a28c936SMatt Spinler class InterfaceWatcher : public DBusWatcher
2542a28c936SMatt Spinler {
2552a28c936SMatt Spinler   public:
2562a28c936SMatt Spinler     InterfaceWatcher() = delete;
2572a28c936SMatt Spinler     ~InterfaceWatcher() = default;
2582a28c936SMatt Spinler     InterfaceWatcher(const InterfaceWatcher&) = delete;
2592a28c936SMatt Spinler     InterfaceWatcher& operator=(const InterfaceWatcher&) = delete;
2602a28c936SMatt Spinler     InterfaceWatcher(InterfaceWatcher&&) = delete;
2612a28c936SMatt Spinler     InterfaceWatcher& operator=(InterfaceWatcher&&) = delete;
2622a28c936SMatt Spinler 
2632a28c936SMatt Spinler     using InterfaceSetFunc = std::function<void(const DBusPropertyMap&)>;
2642a28c936SMatt Spinler 
2652a28c936SMatt Spinler     /**
2662a28c936SMatt Spinler      * @brief Constructor
2672a28c936SMatt Spinler      *
2682a28c936SMatt Spinler      * Reads all properties on the interface if it is on D-Bus,
2692a28c936SMatt Spinler      * and sets up the match objects for the propertiesChanged
2702a28c936SMatt Spinler      * and interfacesAdded signals.
2712a28c936SMatt Spinler      *
2722a28c936SMatt Spinler      * @param[in] bus - The sdbusplus bus object
2732a28c936SMatt Spinler      * @param[in] path - The D-Bus path of the property
2742a28c936SMatt Spinler      * @param[in] interface - The D-Bus interface that contains the property
2752a28c936SMatt Spinler      * @param[in] dataIface - The DataInterface object
2762a28c936SMatt Spinler      * @param[in] func - The callback used any time the property is read
2772a28c936SMatt Spinler      */
InterfaceWatcher(sdbusplus::bus_t & bus,const std::string & path,const std::string & interface,const DataIface & dataIface,InterfaceSetFunc func)27845e83521SPatrick Williams     InterfaceWatcher(sdbusplus::bus_t& bus, const std::string& path,
2792a28c936SMatt Spinler                      const std::string& interface, const DataIface& dataIface,
2802a28c936SMatt Spinler                      InterfaceSetFunc func) :
281*075c7923SPatrick Williams         DBusWatcher(path, interface), _setFunc(func)
2822a28c936SMatt Spinler     {
2832a28c936SMatt Spinler         _matches.emplace_back(
2842a28c936SMatt Spinler             bus, match_rules::propertiesChanged(_path, _interface),
2852a28c936SMatt Spinler             std::bind(std::mem_fn(&InterfaceWatcher::propChanged), this,
2862a28c936SMatt Spinler                       std::placeholders::_1));
2872a28c936SMatt Spinler 
2882a28c936SMatt Spinler         _matches.emplace_back(
2892a28c936SMatt Spinler             bus,
2902a28c936SMatt Spinler             match_rules::interfacesAdded() + match_rules::argNpath(0, _path),
2912a28c936SMatt Spinler             std::bind(std::mem_fn(&InterfaceWatcher::interfaceAdded), this,
2922a28c936SMatt Spinler                       std::placeholders::_1));
29351e927ccSMatt Spinler 
29451e927ccSMatt Spinler         try
29551e927ccSMatt Spinler         {
29651e927ccSMatt Spinler             read(dataIface);
29751e927ccSMatt Spinler         }
29845e83521SPatrick Williams         catch (const sdbusplus::exception_t& e)
29951e927ccSMatt Spinler         {
30051e927ccSMatt Spinler             // Path doesn't exist now
30151e927ccSMatt Spinler         }
3022a28c936SMatt Spinler     }
3032a28c936SMatt Spinler 
3042a28c936SMatt Spinler     /**
3052a28c936SMatt Spinler      * @brief Reads the interface's properties on D-Bus, and
3062a28c936SMatt Spinler      * calls the the user defined function with the property map.
3072a28c936SMatt Spinler      *
3082a28c936SMatt Spinler      * @param[in] dataIface - The DataInterface object
3092a28c936SMatt Spinler      */
read(const DataIface & dataIface)3102a28c936SMatt Spinler     void read(const DataIface& dataIface)
3112a28c936SMatt Spinler     {
3122a28c936SMatt Spinler         auto service = dataIface.getService(_path, _interface);
3132a28c936SMatt Spinler         if (!service.empty())
3142a28c936SMatt Spinler         {
315*075c7923SPatrick Williams             auto properties =
316*075c7923SPatrick Williams                 dataIface.getAllProperties(service, _path, _interface);
3172a28c936SMatt Spinler 
3182a28c936SMatt Spinler             _setFunc(properties);
3192a28c936SMatt Spinler         }
3202a28c936SMatt Spinler     }
3212a28c936SMatt Spinler 
3222a28c936SMatt Spinler     /**
3232a28c936SMatt Spinler      * @brief The propertiesChanged callback
3242a28c936SMatt Spinler      *
3252a28c936SMatt Spinler      * Calls the user defined function with the property map.  Only the
3262a28c936SMatt Spinler      * properties that changed will be in the map.
3272a28c936SMatt Spinler      *
3282a28c936SMatt Spinler      * @param[in] msg - The sdbusplus message object
3292a28c936SMatt Spinler      */
propChanged(sdbusplus::message_t & msg)33045e83521SPatrick Williams     void propChanged(sdbusplus::message_t& msg)
3312a28c936SMatt Spinler     {
3322a28c936SMatt Spinler         DBusInterface interface;
3332a28c936SMatt Spinler         DBusPropertyMap properties;
3342a28c936SMatt Spinler 
3352a28c936SMatt Spinler         msg.read(interface, properties);
3362a28c936SMatt Spinler 
3372a28c936SMatt Spinler         _setFunc(properties);
3382a28c936SMatt Spinler     }
3392a28c936SMatt Spinler 
3402a28c936SMatt Spinler     /**
3412a28c936SMatt Spinler      * @brief The interfacesAdded callback
3422a28c936SMatt Spinler      *
3432a28c936SMatt Spinler      * Calls the user defined function with the property map
3442a28c936SMatt Spinler      *
3452a28c936SMatt Spinler      * @param[in] msg - The sdbusplus message object
3462a28c936SMatt Spinler      */
interfaceAdded(sdbusplus::message_t & msg)34745e83521SPatrick Williams     void interfaceAdded(sdbusplus::message_t& msg)
3482a28c936SMatt Spinler     {
3492a28c936SMatt Spinler         sdbusplus::message::object_path path;
3502a28c936SMatt Spinler         DBusInterfaceMap interfaces;
3512a28c936SMatt Spinler 
3522a28c936SMatt Spinler         msg.read(path, interfaces);
3532a28c936SMatt Spinler 
3542a28c936SMatt Spinler         auto iface = interfaces.find(_interface);
3552a28c936SMatt Spinler         if (iface != interfaces.end())
3562a28c936SMatt Spinler         {
3572a28c936SMatt Spinler             _setFunc(iface->second);
3582a28c936SMatt Spinler         }
3592a28c936SMatt Spinler     }
3602a28c936SMatt Spinler 
3612a28c936SMatt Spinler   private:
3622a28c936SMatt Spinler     /**
3632a28c936SMatt Spinler      * @brief The function that will be called any time the
3642a28c936SMatt Spinler      *        interface is read.
3652a28c936SMatt Spinler      */
3662a28c936SMatt Spinler     InterfaceSetFunc _setFunc;
3672a28c936SMatt Spinler };
3682a28c936SMatt Spinler 
3692a28c936SMatt Spinler } // namespace openpower::pels
370