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 // TODO https://github.com/openbmc/phosphor-fan-presence/issues/22
20 // #include "sdevent/event.hpp"
21 // #include "sdevent/io.hpp"
22 #include "utility.hpp"
23 
24 #include <algorithm>
25 #include <cassert>
26 #include <iostream>
27 #include <iterator>
28 #include <memory>
29 
30 namespace phosphor
31 {
32 namespace fan
33 {
34 namespace util
35 {
36 
37 ArgumentParser::ArgumentParser(int argc, char** argv)
38 {
39     auto option = 0;
40     while (-1 != (option = getopt_long(argc, argv, optionstr, options, NULL)))
41     {
42         if ((option == '?') || (option == 'h'))
43         {
44             usage(argv);
45             exit(1);
46         }
47 
48         auto i = &options[0];
49         while ((i->val != option) && (i->val != 0))
50         {
51             ++i;
52         }
53 
54         if (i->val)
55         {
56             arguments[i->name] = (i->has_arg ? optarg : true_string);
57         }
58     }
59 }
60 
61 const std::string& ArgumentParser::operator[](const std::string& opt)
62 {
63     auto i = arguments.find(opt);
64     if (i == arguments.end())
65     {
66         return empty_string;
67     }
68     else
69     {
70         return i->second;
71     }
72 }
73 
74 void ArgumentParser::usage(char** argv)
75 {
76     std::cerr << "Usage: " << argv[0] << " [options]\n";
77     std::cerr << "Options:\n";
78     std::cerr << "    --path               evdev devpath\n";
79     std::cerr << "    --type               evdev type\n";
80     std::cerr << "    --code               evdev code\n";
81     std::cerr << std::flush;
82 }
83 
84 const option ArgumentParser::options[] = {
85     {"path", required_argument, NULL, 'p'},
86     {"type", required_argument, NULL, 't'},
87     {"code", required_argument, NULL, 'c'},
88     {0, 0, 0, 0},
89 };
90 
91 const char* ArgumentParser::optionstr = "p:t:c:";
92 
93 const std::string ArgumentParser::true_string = "true";
94 const std::string ArgumentParser::empty_string = "";
95 
96 static void exit_with_error(const char* err, char** argv)
97 {
98     ArgumentParser::usage(argv);
99     std::cerr << "\n";
100     std::cerr << "ERROR: " << err << "\n";
101     exit(1);
102 }
103 
104 } // namespace util
105 } // namespace fan
106 } // namespace phosphor
107 
108 int main(int argc, char* argv[])
109 {
110     using namespace phosphor::fan::util;
111 
112     auto options = std::make_unique<ArgumentParser>(argc, argv);
113     auto path = (*options)["path"];
114     auto stype = (*options)["type"];
115     auto scode = (*options)["code"];
116     unsigned int type = EV_KEY;
117 
118     if (path == ArgumentParser::empty_string)
119     {
120         exit_with_error("Path not specified or invalid.", argv);
121     }
122     if (stype != ArgumentParser::empty_string)
123     {
124         type = stoul(stype);
125     }
126 
127     if (scode == ArgumentParser::empty_string)
128     {
129         exit_with_error("Keycode not specified or invalid.", argv);
130     }
131     options.reset();
132 
133     // TODO https://github.com/openbmc/phosphor-fan-presence/issues/22
134     // auto loop = sdevent::event::newDefault();
135     phosphor::fan::util::FileDescriptor fd(
136         open(path.c_str(), O_RDONLY | O_NONBLOCK));
137     auto evdev = evdevpp::evdev::newFromFD(fd());
138     // sdevent::event::io::IO callback(loop, fd(), [&evdev](auto& s) {
139     //     unsigned int type, code, value;
140     //     std::tie(type, code, value) = evdev.next();
141     //     std::cout << "type: " << libevdev_event_type_get_name(type)
142     //               << " code: " << libevdev_event_code_get_name(type, code)
143     //               << " value: " << value << "\n";
144     // });
145 
146     auto value = evdev.fetch(type, stoul(scode));
147     std::cout << "type: " << libevdev_event_type_get_name(type)
148               << " code: " << libevdev_event_code_get_name(type, stoul(scode))
149               << " value: " << value << "\n";
150 
151     // loop.loop();
152 
153     return 0;
154 }
155