]> git.vomp.tv Git - vompclient.git/blob - src/inputlirc.cc
Type change: UCHAR -> u1
[vompclient.git] / src / inputlirc.cc
1 /*
2     Copyright 2020 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <sstream>
21 #include <algorithm>
22 #include <stdexcept>
23
24 #include "config.h"
25 #include "log.h"
26
27 #include "inputman.h"
28
29 #include "inputlirc.h"
30
31 static const char* TAG = "InputLIRC";
32
33 const char* InputLIRC::myModName = "InputLIRC";
34
35 bool InputLIRC::init()
36 {
37   if (initted) return false;
38   initted = true;
39   log = LogNT::getInstance();
40   log->debug(TAG, "Starting InputLIRC");
41
42   if (!tcp.init())
43   {
44     log->debug(TAG, "TCP init error");
45     initted = false;
46     return false;
47   }
48
49   bool arraySuccess = Config::getInstance()->foreachInArray("input_lirc", "remotes", [&] (const std::string& remoteName)
50   {
51     log->debug(TAG, "Remote name: {}", remoteName);
52
53
54     bool objSuccess = Config::getInstance()->foreachPairInObject("input_lirc", remoteName, [&] (const std::string& lircName, const std::string& vompName)
55     {
56       u1 keyNumber = InputMan::getVompKeyNumber(vompName.c_str());
57
58       log->debug(TAG, "  Lirc: {}, vomp: {}, vomp-number {}", lircName, vompName, keyNumber);
59
60       remotes[remoteName][lircName] = keyNumber;
61     });
62
63     if (!objSuccess)
64     {
65       log->error(TAG, "Error reading config for remote {}", remoteName);
66     }
67   });
68
69   if (!arraySuccess)
70   {
71     log->debug(TAG, "Error reading remotes list");
72   }
73   else
74   {
75     log->debug(TAG, "Remotes array read OK");
76   }
77
78
79   using RemotesType = std::map<std::string, std::map<std::string, u1>>;
80   using ButtonsType = std::map<std::string, u1>;
81
82   for(RemotesType::iterator i = remotes.begin(); i != remotes.end(); i++)
83   {
84     ButtonsType& b = i->second;
85     for(ButtonsType:: iterator j = b.begin(); j != b.end(); j++)
86     {
87       log->debug(TAG, "{} - {} - {}", i->first.c_str(), j->first.c_str(), j->second);
88     }
89   }
90
91   return true;
92 }
93
94 void InputLIRC::shutdown()
95 {
96   stop();
97
98   remotes.clear(); // FIXME ?
99
100   initted = false;
101 }
102
103 bool InputLIRC::start()
104 {
105   log->debug(TAG, "Start called");
106
107
108
109   std::string lircIP;
110   bool checkA = Config::getInstance()->getString("input_lirc", "lirc_ip", lircIP);
111   int lircPort = 8765;
112   /* bool checkB = */ Config::getInstance()->getInt("input_lirc", "lirc_port", lircPort);
113   std::string lircSocket;
114   bool checkC = Config::getInstance()->getString("input_lirc", "lirc_socket", lircSocket);
115
116   bool tr{};
117
118   // Prefer socket
119   if (checkC)
120   {
121     LogNT::getInstance()->info(TAG, "Starting with unix socket: {}", lircSocket);
122     tr = tcp.connectSocket(lircSocket);
123   }
124   else if (checkA) // If no checkC, must be checkA
125   {
126     LogNT::getInstance()->info(TAG, "Starting with IP: {} {}", lircIP, lircPort);
127     tr = tcp.connect(lircIP, static_cast<u2>(lircPort));
128   }
129
130   if (!tr)
131   {
132     log->debug(TAG, "TCP connect failed");
133     return false;
134   }
135
136   threadStartProtect.lock(); // Make sure listenThread is fully initted before start returns
137   listenThread = std::thread( [this]
138   {
139     threadStartProtect.lock();
140     threadStartProtect.unlock();
141     listenLoop();
142   });
143   threadStartProtect.unlock();
144
145   log->debug(TAG, "Started");
146   return true;
147 }
148
149 void InputLIRC::stop()
150 {
151   std::lock_guard<std::mutex> lg(threadStartProtect); // Also use it to protect against starting while stopping
152
153   if (!tcp.status()) return;
154
155   if (listenThread.joinable())
156   {
157     threadReqStop = true;
158     tcp.abortCall();
159     listenThread.join();
160     threadReqStop = false;
161   }
162
163   tcp.shutdown();  
164 }
165
166 void InputLIRC::listenLoop()
167 {
168   bool readSuccess;
169
170   while(1)
171   {
172     std::stringstream ss = tcp.readString(&readSuccess, 0);
173
174     if (threadReqStop) return;
175
176     if (!readSuccess)
177     {
178       if (!tcp.status())
179       {
180         log->crit(TAG, "TCP status fail");
181         return;
182       } // return to stop this thread
183
184       continue;
185     }
186
187     log->debug(TAG, "got data: {}", ss.str());
188
189     std::string remoteName, remoteButton;
190     int repeatCount;
191     if (parse(ss.str(), remoteName, remoteButton, repeatCount))
192       log->debug(TAG, "Remote: '{}', Button: '{}', Count: '{}'", remoteName, remoteButton, repeatCount);
193     else
194       log->error(TAG, "Parse error");
195     
196     u1 button;
197     try
198     {
199       button = remotes.at(remoteName).at(remoteButton);
200     }
201     catch (std::exception& e)
202     {
203       log->error(TAG, "Remote button not found");
204       continue;
205     }
206     
207     log->debug(TAG, "Submitting vomp key: '{}'", button);
208     if (repeatCount == 0) sendInputKey(button);
209   }
210 }
211
212 bool InputLIRC::parse(const std::string& input, std::string& remoteName, std::string& remoteButton, int& repeatCount)
213 {
214   u4 pos{}, found{};
215   found = input.find(" ", pos);
216   if (found == std::string::npos) return false;
217   pos = found + 1; // pos at 00
218   found = input.find(" ", pos);
219   if (found == std::string::npos) return false;
220   std::string rcString = input.substr(pos, found - pos);
221   try { repeatCount = std::stoi(rcString, 0, 16); } catch (std::exception& e) { return false; }
222   pos = found + 1; // pos at KE
223   found = input.find(" ", pos);
224   if (found == std::string::npos)
225   {
226     remoteButton = input.substr(pos);
227     return true;
228   }
229   remoteButton = input.substr(pos, found - pos);
230   pos = found + 1;
231   if ((input.length() - pos) > 0)
232     remoteName = input.substr(pos);
233   return true;
234 }
235
236
237 // const char* InputLIRC::getHardCodedHardwareKeyNamesForVompKey(u1 /* vompKey */)
238 // {
239 //   return "";
240 // }
241
242 std::string InputLIRC::getHardwareKeyName(HWC_TYPE /* hardwareKey */)
243 {
244   std::string retval;
245   return retval;
246 }