ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/truck/DashInterface/DashInterface.cpp
Revision: 44
Committed: 2008-03-06T15:21:03-08:00 (17 years, 4 months ago) by douglas
File size: 8396 byte(s)
Log Message:
Cleanup!

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

Properties

Name Value
svn:keywords Id