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 <algorithm>
18 #include <cassert>
19 #include <iostream>
20 #include <iterator>
21 #include <memory>
22 #include "argument.hpp"
23 #include "evdevpp/evdev.hpp"
24 #include "sdevent/event.hpp"
25 #include "sdevent/io.hpp"
26 #include "utility.hpp"
27 
28 namespace phosphor
29 {
30 namespace fan
31 {
32 namespace util
33 {
34 
35 ArgumentParser::ArgumentParser(int argc, char** argv)
36 {
37     auto option = 0;
38     while (-1 != (option = getopt_long(argc, argv, optionstr, options, NULL)))
39     {
40         if ((option == '?') || (option == 'h'))
41         {
42             usage(argv);
43             exit(-1);
44         }
45 
46         auto i = &options[0];
47         while ((i->val != option) && (i->val != 0))
48         {
49             ++i;
50         }
51 
52         if (i->val)
53         {
54             arguments[i->name] = (i->has_arg ? optarg : true_string);
55         }
56     }
57 }
58 
59 const std::string& ArgumentParser::operator[](const std::string& opt)
60 {
61     auto i = arguments.find(opt);
62     if (i == arguments.end())
63     {
64         return empty_string;
65     }
66     else
67     {
68         return i->second;
69     }
70 }
71 
72 void ArgumentParser::usage(char** argv)
73 {
74     std::cerr << "Usage: " << argv[0] << " [options]\n";
75     std::cerr << "Options:\n";
76     std::cerr << "    --path               evdev devpath\n";
77     std::cerr << "    --type               evdev type\n";
78     std::cerr << "    --code               evdev code\n";
79     std::cerr << std::flush;
80 }
81 
82 const option ArgumentParser::options[] =
83 {
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(
137             loop,
138             fd(),
139             [&evdev](auto& s)
140             {
141                 unsigned int type, code, value;
142                 std::tie(type, code, value) = evdev.next();
143                 std::cout <<
144                     "type: " << libevdev_event_type_get_name(type) <<
145                     " code: " << libevdev_event_code_get_name(type, code) <<
146                     " value: " << value << "\n";
147             });
148 
149     auto value = evdev.fetch(type, stoul(scode));
150     std::cout <<
151         "type: " << libevdev_event_type_get_name(type) <<
152         " code: " << libevdev_event_code_get_name(type, stoul(scode)) <<
153         " value: " << value << "\n";
154 
155     loop.loop();
156 
157     return 0;
158 }
159