ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/truck/DashInterface/DashInterface.cpp
Revision: 46
Committed: 2008-03-06T19:47:57-08:00 (17 years, 3 months ago) by douglas
File size: 8468 byte(s)
Log Message:
Woo, actually tested that! Note to self: this is why you test early and often, but you knew that already.

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

Properties

Name Value
svn:keywords Id