ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/truck/DashInterface/DashInterface.cpp
Revision: 41
Committed: 2008-03-06T02:41:40-08:00 (17 years, 3 months ago) by douglas
File size: 8032 byte(s)
Log Message:
Moar progress!

File Contents

# Content
1 // Dash Interface
2 //
3 // Douglas Thrift
4 //
5 // $Id$
6
7 #include <algorithm>
8 #include <iomanip>
9 #include <iostream>
10 #include <sstream>
11
12 #include <foreach.hpp>
13 #include <hash.hpp>
14 #include <iconv.hpp>
15 #include <regex.hpp>
16 #include <scopes.hpp>
17 #include <timing.hpp>
18
19 #include <Audacious.hpp>
20 #include <GPS.hpp>
21
22 #include <sys/types.h>
23 #include <sys/sysctl.h>
24 #include <sys/utsname.h>
25
26 #include <sqlite3.h>
27
28 #include "Display.hpp"
29
30 bool debug(false);
31
32 class DashInterface
33 {
34 enum Mode { Uname, Music, English, Metric, Nautical, Menu } mode, previous;
35 enum { Running, Audio };
36 enum { Stopped, Paused, Playing } audio;
37 enum Level { Top, Artist, Album, Song } level;
38 Timing::Time now;
39 IConv::IConv ascii;
40 Display display;
41 Pthreads::ThreadMutex displayLock;
42 Audacious::Audacious audacious;
43 //GPS::GPS gps;
44
45 inline std::string Filter(const std::string input)
46 {
47 std::string output(ascii.Convert(input));
48
49 std::replace(output.begin(), output.end(), '~', char(206));
50
51 return output;
52 }
53
54 void Mode_(bool change = false)
55 {
56 switch (mode)
57 {
58 case Uname:
59 return Uname_(change);
60 case Music:
61 if (audacious.IsRunning())
62 {
63 int position(audacious.GetPlaylistPosition());
64 std::string artist(Filter(audacious.GetTupleFieldData(_B("artist"), position)));
65
66 display.Set(0, 1, artist.size() > 20 ? artist.erase(20) : artist.append(20 - artist.size(), ' '));
67
68 std::string title(Filter(audacious.GetTupleFieldData(_B("title"), position)));
69
70 display.Set(0, 2, title.size() > 20 ? title.erase(20) : title.append(20 - title.size(), ' '));
71
72 int played(audacious.GetOutputTime() / 1000);
73 int left(audacious.GetPlaylistTime(position) / 1000 - played);
74 char *times;
75
76 ::asprintf(&times, "%2i:%02i -%2i:%02i", played / 60, played % 60, left / 60, left % 60);
77
78 display.Set(0, 3, times + std::string(20 - std::strlen(times), ' '));
79
80 std::free(times);
81 }
82 else
83 {
84 display.Set(0, 1, std::string(20, ' '));
85 display.Set(0, 2, std::string(20, ' '));
86 display.Set(0, 3, _B(" -:-- - -:-- "));
87 }
88
89 return;
90 case English:
91 case Metric:
92 case Nautical:
93 display.Set(0, 1, _B("STUB: GPS ") + (mode == English ? _B("English ") : mode == Metric ? _B("Metric ") : _B("Nautical ")));
94 display.Set(0, 2, std::string(20, ' '));
95 display.Set(0, 3, std::string(20, ' '));
96
97 return;
98 case Menu:
99 if (change)
100 level = Top;
101 }
102 }
103
104 void Uname_(bool change = false)
105 {
106 if (!now || change)
107 {
108 utsname os;
109
110 ::uname(&os);
111
112 static Pcre::RegEx version(_B("^(\\d+\\.\\d+)-([A-Z])[A-Z]*(-p\\d+)?.*$"));
113 Pcre::RegEx::Match match(version(os.release));
114 std::string name(os.sysname + _B(" ") + match[1] + match[2] + match[3]);
115
116 display.Set(0, 1, name.append(20 - name.size(), ' '));
117 }
118
119 int mib[] = { CTL_KERN, KERN_BOOTTIME };
120 timeval boottime;
121 size_t size(sizeof (boottime));
122
123 if (now && ::sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0)
124 {
125 time_t uptime(now - boottime.tv_sec);
126
127 if (uptime > 60)
128 uptime += 30;
129
130 char *when;
131 int days(uptime / 86400);
132
133 uptime %= 86400;
134
135 int hours(uptime / 3600);
136
137 uptime %= 3600;
138
139 int minutes(uptime / 60), seconds(uptime % 60);
140
141 ::asprintf(&when, "%i+%02i:%02i:%02i", days, hours, minutes, seconds);
142
143 std::string then(when);
144
145 then.append(17 - std::strlen(when), ' ');
146
147 std::free(when);
148
149 if (change)
150 display.Set(0, 2, _B("up ") + then);
151 else
152 display.Set(3, 2, then);
153 }
154 else
155 display.Set(0, 2, _B("up -+--:--:-- "));
156
157 double averages[3];
158
159 if (::getloadavg(averages, 3) == -1 || !now)
160 display.Set(0, 3, _B("-.--, -.--, -.-- "));
161 else
162 {
163 char *load;
164
165 ::asprintf(&load, "%.2f, %.2f, %.2f", averages[0], averages[1] , averages[2]);
166
167 display.Set(0, 3, load + std::string(20 - std::strlen(load), ' '));
168
169 std::free(load);
170 }
171 }
172
173 void Buttons(Display::KeyActivity activity)
174 {
175 _synchronized (displayLock)
176 if (mode != Menu)
177 {
178 bool change(false);
179
180 switch (activity)
181 {
182 case Display::UpPress:
183 --mode;
184
185 goto change;
186 case Display::DownPress:
187 ++mode;
188
189 goto change;
190 case Display::LeftPress:
191 if (audacious.IsRunning())
192 audacious.PlaylistPrevious();
193
194 goto update;
195 case Display::RightPress:
196 if (audacious.IsRunning())
197 audacious.PlaylistNext();
198
199 goto update;
200 case Display::EnterPress:
201 previous = mode;
202 mode = Menu;
203
204 goto change;
205 case Display::ExitPress:
206 if (audacious.IsRunning())
207 audacious.PlayPause();
208
209 goto update;
210 default:
211 return;
212 }
213
214 change: change = true;
215
216 update: Mode_(change);
217 }
218 else
219 switch (activity)
220 {
221 case Display::UpPress:
222 case Display::DownPress:
223 case Display::LeftPress:
224 case Display::RightPress:
225 case Display::EnterPress:
226 return;
227 case Display::ExitPress:
228 mode = previous;
229
230 display.Set(0, 0, _B(" "));
231 display.Set(18, 0, _B(" "));
232
233 Mode_(true);
234 default:
235 return;
236 }
237 }
238
239 public:
240 DashInterface(const std::string &device) : mode(Uname), audio(Stopped), ascii(_B("ASCII//TRANSLIT//IGNORE"), _B("UTF-8")), display(device, reinterpret_cast<Display::Callback>(::Buttons), this)
241 {
242 _synchronized (displayLock)
243 {
244 display.Clear();
245 display.SetBacklight(100);
246 display.Set(2, 0, _B("--:--:-- -- ---"));
247
248 display.Set(Running, Display::Green, 0);
249 display.Set(Running, Display::Red, 100);
250 display.Set(Audio, Display::Green, 0);
251 display.Set(Audio, Display::Red, 100);
252
253 uint8_t mask(Display::Up | Display::Enter | Display::Cancel | Display::Left | Display::Right | Display::Down);
254
255 display.KeyReporting(mask, mask);
256
257 Uname_();
258
259 display.Store();
260 display.Set(Running, Display::Green, 100);
261 display.Set(Running, Display::Red, 0);
262 }
263 }
264
265 void Run()
266 {
267 _forever
268 {
269 _synchronized (displayLock)
270 {
271 now = Timing::GetTimeOfDay();
272
273 if (mode != Menu)
274 {
275 char when[16];
276
277 std::strftime(when, sizeof (when), "%l:%M:%S %p %Z", std::localtime(now));
278
279 display.Set(2, 0, when);
280 }
281
282 if (audacious.IsRunning() && audacious.IsPlaying())
283 if (audacious.IsPaused())
284 {
285 if (audio != Paused)
286 {
287 display.Set(Audio, Display::Green, 100);
288 display.Set(Audio, Display::Red, 100);
289
290 audio = Paused;
291 }
292 }
293 else
294 {
295 if (audio != Playing)
296 {
297 display.Set(Audio, Display::Green, 100);
298 display.Set(Audio, Display::Red, 0);
299
300 audio = Playing;
301 }
302 }
303 else if (audio != Stopped)
304 {
305 display.Set(Audio, Display::Green, 0);
306 display.Set(Audio, Display::Red, 100);
307
308 audio = Stopped;
309 }
310
311 Mode_();
312 }
313
314 Timing::NanoSleep(Timing::Time(1) -= Timing::GetTimeOfDay().GetNanoseconds());
315 }
316 }
317
318 friend void Buttons(Display::KeyActivity activity, DashInterface *interface)
319 {
320 interface->Buttons(activity);
321 }
322
323 inline friend Mode &operator ++(Mode &mode)
324 {
325 return mode = Mode((mode + 1) % Menu);
326 }
327
328 inline friend Mode &operator --(Mode &mode)
329 {
330 return mode = Mode((Menu + mode - 1) % Menu);
331 }
332 };
333
334 int main(int argc, char *argv[])
335 {
336 std::string device;
337
338 {
339 Pcre::RegEx devicePath(_B("^-device=(/.+)$"));
340 Pcre::RegEx deviceNumber(_B("^-device=([0-9]+)$"));
341 Pcre::RegEx deviceName(_B("^-device=(.+)$"));
342
343 for (char **arg = argv + 1; *arg; ++arg)
344 {
345 Pcre::RegEx::Match match;
346
347 if (*arg == _B("-debug"))
348 debug = true;
349 else if (match = devicePath(*arg))
350 device = match[1];
351 else if (match = deviceNumber(*arg))
352 device = _B("/dev/cuaU") + match[1];
353 else if (match = deviceName(*arg))
354 device = _B("/dev/") + match[1];
355 else
356 goto usage;
357 }
358 }
359
360 if (device.empty())
361 {
362 usage: std::cout << _B("Usage: ") << argv[0] << _B(" [-debug] [-device=device]") << std::endl;
363
364 return 2;
365 }
366
367 try
368 {
369 DashInterface interface(device);
370
371 interface.Run();
372 }
373 catch (const std::exception &exception)
374 {
375 std::cerr << argv[0] << _B(": ") << exception.what() << std::endl;
376
377 return 1;
378 }
379
380 return 0;
381 }

Properties

Name Value
svn:keywords Id