summaryrefslogtreecommitdiffstats
path: root/monitor.hpp
blob: 68bf4472cf5d33cc2e350c01842a0b2f57424bdf (plain)
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
#pragma once

#include <unistd.h>
#include <string>
#include <linux/input.h>
#include <libevdev/libevdev.h>
#include <systemd/sd-event.h>
#include <sdbusplus/bus.hpp>
#include "file.hpp"
namespace phosphor
{
namespace gpio
{

/* Need a custom deleter for freeing up sd_event */
struct EventDeleter
{
    void operator()(sd_event* event) const
    {
        event = sd_event_unref(event);
    }
};
using EventPtr = std::unique_ptr<sd_event, EventDeleter>;

/* Need a custom deleter for freeing up sd_event_source */
struct EventSourceDeleter
{
    void operator()(sd_event_source* eventSource) const
    {
        eventSource = sd_event_source_unref(eventSource);
    }
};
using EventSourcePtr = std::unique_ptr<sd_event_source, EventSourceDeleter>;

/* Need a custom deleter for freeing up evdev struct */
struct EvdevDeleter
{
    void operator()(struct libevdev* device) const
    {
        libevdev_free(device);
    }
};
using EvdevPtr = std::unique_ptr<struct libevdev, EvdevDeleter>;

/** @class Monitor
 *  @brief Responsible for catching GPIO state change
 *  condition and taking actions
 */
class Monitor
{
    public:
        Monitor() = delete;
        ~Monitor() = default;
        Monitor(const Monitor&) = delete;
        Monitor& operator=(const Monitor&) = delete;
        Monitor(Monitor&&) = delete;
        Monitor& operator=(Monitor&&) = delete;

        /** @brief Constructs Monitor object.
         *
         *  @param[in] path     - Path to gpio input device
         *  @param[in] key      - GPIO key to monitor
         *  @param[in] polarity - GPIO assertion polarity to look for
         *  @param[in] target   - systemd unit to be started on GPIO
         *                        value change
         *  @param[in] event    - sd_event handler
         *  @param[in] handler  - IO callback handler. Defaults to one in this
         *                        class
         */
        Monitor(const std::string& path,
                decltype(input_event::code) key,
                decltype(input_event::value) polarity,
                const std::string& target,
                EventPtr& event,
                sd_event_io_handler_t handler = Monitor::processEvents)
            : path(path),
              key(key),
              polarity(polarity),
              target(target),
              event(event),
              callbackHandler(handler),
              fd(openDevice())
        {
            // And register callback handler when FD has some data
            registerCallback();
        }

        /** @brief Callback handler when the FD has some activity on it
         *
         *  @param[in] es       - Populated event source
         *  @param[in] fd       - Associated File descriptor
         *  @param[in] revents  - Type of event
         *  @param[in] userData - User data that was passed during registration
         *
         *  @return             - 0 or positive number on success and negative
         *                        errno otherwise
         */
        static int processEvents(sd_event_source* es, int fd,
                                 uint32_t revents, void* userData);

        /** @brief Returns the completion state of this handler */
        inline auto completed() const
        {
            return complete;
        }

    private:
        /** @brief Absolute path of GPIO input device */
        const std::string& path;

        /** @brief GPIO key code that is of interest */
        decltype(input_event::code) key;

        /** @brief GPIO key value that is of interest */
        decltype(input_event::value) polarity;

        /** @brief Systemd unit to be started when the condition is met */
        const std::string& target;

        /** @brief Monitor to sd_event */
        EventPtr& event;

        /** @brief event source */
        EventSourcePtr eventSource;

        /** @brief Callback handler when the FD has some data */
        sd_event_io_handler_t callbackHandler;

        /** @brief File descriptor manager */
        FileDescriptor fd;

        /** event structure */
        EvdevPtr device;

        /** @brief Completion indicator */
        bool complete = false;

        /** @brief Opens the device and populates the descriptor */
        int openDevice();

        /** @brief attaches FD to events and sets up callback handler */
        void registerCallback();

        /** @brief Analyzes the GPIO event and starts configured target */
        void analyzeEvent();

        /** @brief Initializes evdev handle with the fd */
        void initEvDev();
};

} // namespace gpio
} // namespace phosphor
OpenPOWER on IntegriCloud