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 (14 years, 8 months ago) by douglas
File size: 8396 byte(s)
Log Message:
Cleanup!

File Contents

# User Rev Content
1 douglas 22 // Dash Interface
2     //
3     // Douglas Thrift
4     //
5     // $Id$
6    
7 douglas 41 #include <algorithm>
8 douglas 33 #include <iomanip>
9 douglas 25 #include <iostream>
10 douglas 33 #include <sstream>
11 douglas 25
12     #include <foreach.hpp>
13     #include <hash.hpp>
14 douglas 41 #include <iconv.hpp>
15 douglas 26 #include <regex.hpp>
16 douglas 39 #include <scopes.hpp>
17 douglas 37 #include <timing.hpp>
18 douglas 25
19 douglas 24 #include <Audacious.hpp>
20     #include <GPS.hpp>
21    
22 douglas 33 #include <sys/types.h>
23     #include <sys/sysctl.h>
24     #include <sys/utsname.h>
25    
26 douglas 26 #include "Display.hpp"
27 douglas 44 #include "MenuList.hpp"
28 douglas 26
29     bool debug(false);
30    
31 douglas 39 class DashInterface
32 douglas 33 {
33 douglas 41 enum Mode { Uname, Music, English, Metric, Nautical, Menu } mode, previous;
34 douglas 40 enum { Running, Audio };
35     enum { Stopped, Paused, Playing } audio;
36 douglas 39 Timing::Time now;
37 douglas 41 IConv::IConv ascii;
38 douglas 39 Display display;
39     Pthreads::ThreadMutex displayLock;
40 douglas 40 Audacious::Audacious audacious;
41 douglas 39 //GPS::GPS gps;
42 douglas 44 MenuList *list;
43     bool append;
44 douglas 39
45 douglas 41 inline std::string Filter(const std::string input)
46     {
47     std::string output(ascii.Convert(input));
48    
49 douglas 42 std::replace(output.begin(), output.end(), '~', '\xce');
50 douglas 41
51     return output;
52     }
53    
54 douglas 39 void Mode_(bool change = false)
55 douglas 35 {
56 douglas 39 switch (mode)
57     {
58     case Uname:
59 douglas 40 return Uname_(change);
60     case Music:
61     if (audacious.IsRunning())
62     {
63     int position(audacious.GetPlaylistPosition());
64 douglas 41 std::string artist(Filter(audacious.GetTupleFieldData(_B("artist"), position)));
65 douglas 33
66 douglas 42 artist.resize(20, ' ');
67     display.Set(0, 1, artist);
68 douglas 40
69 douglas 41 std::string title(Filter(audacious.GetTupleFieldData(_B("title"), position)));
70 douglas 40
71 douglas 42 title.resize(20, ' ');
72     display.Set(0, 2, title);
73 douglas 40
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 douglas 42 std::string times_(times);
81 douglas 40
82     std::free(times);
83 douglas 42
84     times_.resize(20, ' ');
85     display.Set(0, 3, times_);
86 douglas 40 }
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 douglas 39 case English:
96     case Metric:
97     case Nautical:
98 douglas 41 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 douglas 39 case Menu:
104 douglas 41 if (change)
105 douglas 44 {
106     display.SetCursorStyle(Display::InvertingBlinkingBlock);
107    
108     append = true;
109     list = new TopList(display, audacious, append);
110    
111     list->Render();
112     }
113 douglas 39 }
114     }
115 douglas 33
116 douglas 39 void Uname_(bool change = false)
117     {
118     if (!now || change)
119     {
120     utsname os;
121 douglas 33
122 douglas 39 ::uname(&os);
123 douglas 33
124 douglas 39 static Pcre::RegEx version(_B("^(\\d+\\.\\d+)-([A-Z])[A-Z]*(-p\\d+)?.*$"));
125     Pcre::RegEx::Match match(version(os.release));
126 douglas 40 std::string name(os.sysname + _B(" ") + match[1] + match[2] + match[3]);
127 douglas 33
128 douglas 42 name.resize(20, ' ');
129     display.Set(0, 1, name);
130 douglas 39 }
131 douglas 33
132 douglas 39 int mib[] = { CTL_KERN, KERN_BOOTTIME };
133     timeval boottime;
134     size_t size(sizeof (boottime));
135 douglas 33
136 douglas 39 if (now && ::sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0)
137     {
138     time_t uptime(now - boottime.tv_sec);
139 douglas 33
140 douglas 39 if (uptime > 60)
141     uptime += 30;
142 douglas 33
143 douglas 39 char *when;
144     int days(uptime / 86400);
145 douglas 33
146 douglas 39 uptime %= 86400;
147 douglas 33
148 douglas 39 int hours(uptime / 3600);
149 douglas 33
150 douglas 39 uptime %= 3600;
151 douglas 35
152 douglas 39 int minutes(uptime / 60), seconds(uptime % 60);
153 douglas 35
154 douglas 39 ::asprintf(&when, "%i+%02i:%02i:%02i", days, hours, minutes, seconds);
155 douglas 35
156 douglas 39 std::string then(when);
157 douglas 35
158 douglas 39 std::free(when);
159    
160 douglas 42 then.resize(17, ' ');
161    
162 douglas 39 if (change)
163     display.Set(0, 2, _B("up ") + then);
164     else
165     display.Set(3, 2, then);
166     }
167 douglas 35 else
168 douglas 39 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 douglas 42 std::string load_(load);
181 douglas 39
182     std::free(load);
183 douglas 42
184     load_.resize(20, ' ');
185     display.Set(0, 3, load_);
186 douglas 39 }
187 douglas 33 }
188    
189 douglas 39 void Buttons(Display::KeyActivity activity)
190     {
191     _synchronized (displayLock)
192     if (mode != Menu)
193     {
194     bool change(false);
195 douglas 33
196 douglas 39 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 douglas 41 if (audacious.IsRunning())
208     audacious.PlaylistPrevious();
209 douglas 39
210     goto update;
211     case Display::RightPress:
212 douglas 41 if (audacious.IsRunning())
213     audacious.PlaylistNext();
214 douglas 39
215     goto update;
216     case Display::EnterPress:
217 douglas 41 previous = mode;
218 douglas 39 mode = Menu;
219    
220     goto change;
221     case Display::ExitPress:
222 douglas 41 if (audacious.IsRunning())
223     audacious.PlayPause();
224 douglas 39
225     goto update;
226     default:
227     return;
228     }
229    
230     change: change = true;
231    
232     update: Mode_(change);
233     }
234     else
235 douglas 41 switch (activity)
236     {
237     case Display::UpPress:
238 douglas 44 return (++*list).Render();
239 douglas 41 case Display::DownPress:
240 douglas 44 return (--*list).Render();
241 douglas 41 case Display::LeftPress:
242 douglas 44 list = list->Left();
243    
244     goto render;
245 douglas 41 case Display::RightPress:
246 douglas 44 list = list->Right();
247    
248     goto render;
249 douglas 41 case Display::EnterPress:
250 douglas 44 list = list->Enter();
251    
252     render: if (list != NULL)
253     return list->Render();
254    
255     goto exit;
256 douglas 41 case Display::ExitPress:
257 douglas 44 delete list;
258 douglas 41
259 douglas 44 exit: mode = previous;
260    
261     display.SetCursorStyle(Display::NoCursor);
262 douglas 41 display.Set(0, 0, _B(" "));
263     display.Set(18, 0, _B(" "));
264    
265     Mode_(true);
266     default:
267     return;
268     }
269 douglas 39 }
270    
271     public:
272 douglas 41 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 douglas 33 {
274 douglas 39 _synchronized (displayLock)
275     {
276     display.Clear();
277     display.SetBacklight(100);
278     display.Set(2, 0, _B("--:--:-- -- ---"));
279 douglas 33
280 douglas 39 display.Set(Running, Display::Green, 0);
281     display.Set(Running, Display::Red, 100);
282 douglas 40 display.Set(Audio, Display::Green, 0);
283     display.Set(Audio, Display::Red, 100);
284 douglas 33
285 douglas 39 uint8_t mask(Display::Up | Display::Enter | Display::Cancel | Display::Left | Display::Right | Display::Down);
286 douglas 35
287 douglas 39 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 douglas 33 }
296    
297 douglas 39 void Run()
298     {
299     _forever
300     {
301     _synchronized (displayLock)
302     {
303     now = Timing::GetTimeOfDay();
304 douglas 37
305 douglas 39 if (mode != Menu)
306     {
307     char when[16];
308 douglas 37
309 douglas 39 std::strftime(when, sizeof (when), "%l:%M:%S %p %Z", std::localtime(now));
310 douglas 37
311 douglas 39 display.Set(2, 0, when);
312     }
313    
314 douglas 40 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 douglas 39 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 douglas 22 int main(int argc, char *argv[])
367     {
368 douglas 26 std::string device;
369    
370 douglas 25 {
371 douglas 26 Pcre::RegEx devicePath(_B("^-device=(/.+)$"));
372     Pcre::RegEx deviceNumber(_B("^-device=([0-9]+)$"));
373     Pcre::RegEx deviceName(_B("^-device=(.+)$"));
374 douglas 25
375 douglas 26 for (char **arg = argv + 1; *arg; ++arg)
376 douglas 25 {
377 douglas 26 Pcre::RegEx::Match match;
378 douglas 25
379 douglas 26 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 douglas 25 }
390     }
391 douglas 26
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 douglas 39 DashInterface interface(device);
402 douglas 26
403 douglas 39 interface.Run();
404 douglas 26 }
405 douglas 25 catch (const std::exception &exception)
406     {
407     std::cerr << argv[0] << _B(": ") << exception.what() << std::endl;
408    
409     return 1;
410     }
411    
412 douglas 22 return 0;
413     }

Properties

Name Value
svn:keywords Id