1 /**
2  * Copyright © 2017 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "argument.hpp"
18 #include "evdevpp/evdev.hpp"
19 #include "sdevent/event.hpp"
20 #include "sdevent/io.hpp"
21 #include "utility.hpp"
22 
23 #include <algorithm>
24 #include <cassert>
25 #include <iostream>
26 #include <iterator>
27 #include <memory>
28 
29 namespace phosphor
30 {
31 namespace fan
32 {
33 namespace util
34 {
35 
36 ArgumentParser::ArgumentParser(int argc, char** argv)
37 {
38     auto option = 0;
39     while (-1 != (option = getopt_long(argc, argv, optionstr, options, NULL)))
40     {
41         if ((option == '?') || (option == 'h'))
42         {
43             usage(argv);
44             exit(1);
45         }
46 
47         auto i = &options[0];
48         while ((i->val != option) && (i->val != 0))
49         {
50             ++i;
51         }
52 
53         if (i->val)
54         {
55             arguments[i->name] = (i->has_arg ? optarg : true_string);
56         }
57     }
58 }
59 
60 const std::string& ArgumentParser::operator[](const std::string& opt)
61 {
62     auto i = arguments.find(opt);
63     if (i == arguments.end())
64     {
65         return empty_string;
66     }
67     else
68     {
69         return i->second;
70     }
71 }
72 
73 void ArgumentParser::usage(char** argv)
74 {
75     std::cerr << "Usage: " << argv[0] << " [options]\n";
76     std::cerr << "Options:\n";
77     std::cerr << "    --path               evdev devpath\n";
78     std::cerr << "    --type               evdev type\n";
79     std::cerr << "    --code               evdev code\n";
80     std::cerr << std::flush;
81 }
82 
83 const option ArgumentParser::options[] = {
84     {"path", required_argument, NULL, 'p'},
85     {"type", required_argument, NULL, 't'},
86     {"code", required_argument, NULL, 'c'},
87     {0, 0, 0, 0},
88 };
89 
90 const char* ArgumentParser::optionstr = "p:t:c:";
91 
92 const std::string ArgumentParser::true_string = "true";
93 const std::string ArgumentParser::empty_string = "";
94 
95 static void exit_with_error(const char* err, char** argv)
96 {
97     ArgumentParser::usage(argv);
98     std::cerr << "\n";
99     std::cerr << "ERROR: " << err << "\n";
100     exit(1);
101 }
102 
103 } // namespace util
104 } // namespace fan
105 } // namespace phosphor
106 
107 int main(int argc, char* argv[])
108 {
109     using namespace phosphor::fan::util;
110 
111     auto options = std::make_unique<ArgumentParser>(argc, argv);
112     auto path = (*options)["path"];
113     auto stype = (*options)["type"];
114     auto scode = (*options)["code"];
115     unsigned int type = EV_KEY;
116 
117     if (path == ArgumentParser::empty_string)
118     {
119         exit_with_error("Path not specified or invalid.", argv);
120     }
121     if (stype != ArgumentParser::empty_string)
122     {
123         type = stoul(stype);
124     }
125 
126     if (scode == ArgumentParser::empty_string)
127     {
128         exit_with_error("Keycode not specified or invalid.", argv);
129     }
130     options.reset();
131 
132     auto loop = sdevent::event::newDefault();
133     phosphor::fan::util::FileDescriptor fd(
134         open(path.c_str(), O_RDONLY | O_NONBLOCK));
135     auto evdev = evdevpp::evdev::newFromFD(fd());
136     sdevent::event::io::IO callback(loop, fd(), [&evdev](auto& s) {
137         unsigned int type, code, value;
138         std::tie(type, code, value) = evdev.next();
139         std::cout << "type: " << libevdev_event_type_get_name(type)
140                   << " code: " << libevdev_event_code_get_name(type, code)
141                   << " value: " << value << "\n";
142     });
143 
144     auto value = evdev.fetch(type, stoul(scode));
145     std::cout << "type: " << libevdev_event_type_get_name(type)
146               << " code: " << libevdev_event_code_get_name(type, stoul(scode))
147               << " value: " << value << "\n";
148 
149     loop.loop();
150 
151     return 0;
152 }
153