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

# 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 25 #include <sqlite3.h>
27    
28 douglas 26 #include "Display.hpp"
29    
30     bool debug(false);
31    
32 douglas 39 class DashInterface
33 douglas 33 {
34 douglas 41 enum Mode { Uname, Music, English, Metric, Nautical, Menu } mode, previous;
35 douglas 40 enum { Running, Audio };
36     enum { Stopped, Paused, Playing } audio;
37 douglas 41 enum Level { Top, Artist, Album, Song } level;
38 douglas 39 Timing::Time now;
39 douglas 41 IConv::IConv ascii;
40 douglas 39 Display display;
41     Pthreads::ThreadMutex displayLock;
42 douglas 40 Audacious::Audacious audacious;
43 douglas 39 //GPS::GPS gps;
44    
45 douglas 41 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 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 40 display.Set(0, 1, artist.size() > 20 ? artist.erase(20) : artist.append(20 - artist.size(), ' '));
67    
68 douglas 41 std::string title(Filter(audacious.GetTupleFieldData(_B("title"), position)));
69 douglas 40
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 douglas 39 case English:
91     case Metric:
92     case Nautical:
93 douglas 41 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 douglas 39 case Menu:
99 douglas 41 if (change)
100     level = Top;
101 douglas 39 }
102     }
103 douglas 33
104 douglas 39 void Uname_(bool change = false)
105     {
106     if (!now || change)
107     {
108     utsname os;
109 douglas 33
110 douglas 39 ::uname(&os);
111 douglas 33
112 douglas 39 static Pcre::RegEx version(_B("^(\\d+\\.\\d+)-([A-Z])[A-Z]*(-p\\d+)?.*$"));
113     Pcre::RegEx::Match match(version(os.release));
114 douglas 40 std::string name(os.sysname + _B(" ") + match[1] + match[2] + match[3]);
115 douglas 33
116 douglas 40 display.Set(0, 1, name.append(20 - name.size(), ' '));
117 douglas 39 }
118 douglas 33
119 douglas 39 int mib[] = { CTL_KERN, KERN_BOOTTIME };
120     timeval boottime;
121     size_t size(sizeof (boottime));
122 douglas 33
123 douglas 39 if (now && ::sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0)
124     {
125     time_t uptime(now - boottime.tv_sec);
126 douglas 33
127 douglas 39 if (uptime > 60)
128     uptime += 30;
129 douglas 33
130 douglas 39 char *when;
131     int days(uptime / 86400);
132 douglas 33
133 douglas 39 uptime %= 86400;
134 douglas 33
135 douglas 39 int hours(uptime / 3600);
136 douglas 33
137 douglas 39 uptime %= 3600;
138 douglas 35
139 douglas 39 int minutes(uptime / 60), seconds(uptime % 60);
140 douglas 35
141 douglas 39 ::asprintf(&when, "%i+%02i:%02i:%02i", days, hours, minutes, seconds);
142 douglas 35
143 douglas 39 std::string then(when);
144 douglas 35
145 douglas 39 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 douglas 35 else
155 douglas 39 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 douglas 33 }
172    
173 douglas 39 void Buttons(Display::KeyActivity activity)
174     {
175     _synchronized (displayLock)
176     if (mode != Menu)
177     {
178     bool change(false);
179 douglas 33
180 douglas 39 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 douglas 41 if (audacious.IsRunning())
192     audacious.PlaylistPrevious();
193 douglas 39
194     goto update;
195     case Display::RightPress:
196 douglas 41 if (audacious.IsRunning())
197     audacious.PlaylistNext();
198 douglas 39
199     goto update;
200     case Display::EnterPress:
201 douglas 41 previous = mode;
202 douglas 39 mode = Menu;
203    
204     goto change;
205     case Display::ExitPress:
206 douglas 41 if (audacious.IsRunning())
207     audacious.PlayPause();
208 douglas 39
209     goto update;
210     default:
211     return;
212     }
213    
214     change: change = true;
215    
216     update: Mode_(change);
217     }
218     else
219 douglas 41 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 douglas 39 }
238    
239     public:
240 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)
241 douglas 33 {
242 douglas 39 _synchronized (displayLock)
243     {
244     display.Clear();
245     display.SetBacklight(100);
246     display.Set(2, 0, _B("--:--:-- -- ---"));
247 douglas 33
248 douglas 39 display.Set(Running, Display::Green, 0);
249     display.Set(Running, Display::Red, 100);
250 douglas 40 display.Set(Audio, Display::Green, 0);
251     display.Set(Audio, Display::Red, 100);
252 douglas 33
253 douglas 39 uint8_t mask(Display::Up | Display::Enter | Display::Cancel | Display::Left | Display::Right | Display::Down);
254 douglas 35
255 douglas 39 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 douglas 33 }
264    
265 douglas 39 void Run()
266     {
267     _forever
268     {
269     _synchronized (displayLock)
270     {
271     now = Timing::GetTimeOfDay();
272 douglas 37
273 douglas 39 if (mode != Menu)
274     {
275     char when[16];
276 douglas 37
277 douglas 39 std::strftime(when, sizeof (when), "%l:%M:%S %p %Z", std::localtime(now));
278 douglas 37
279 douglas 39 display.Set(2, 0, when);
280     }
281    
282 douglas 40 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 douglas 39 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 douglas 22 int main(int argc, char *argv[])
335     {
336 douglas 26 std::string device;
337    
338 douglas 25 {
339 douglas 26 Pcre::RegEx devicePath(_B("^-device=(/.+)$"));
340     Pcre::RegEx deviceNumber(_B("^-device=([0-9]+)$"));
341     Pcre::RegEx deviceName(_B("^-device=(.+)$"));
342 douglas 25
343 douglas 26 for (char **arg = argv + 1; *arg; ++arg)
344 douglas 25 {
345 douglas 26 Pcre::RegEx::Match match;
346 douglas 25
347 douglas 26 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 douglas 25 }
358     }
359 douglas 26
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 douglas 39 DashInterface interface(device);
370 douglas 26
371 douglas 39 interface.Run();
372 douglas 26 }
373 douglas 25 catch (const std::exception &exception)
374     {
375     std::cerr << argv[0] << _B(": ") << exception.what() << std::endl;
376    
377     return 1;
378     }
379    
380 douglas 22 return 0;
381     }

Properties

Name Value
svn:keywords Id