blob: d56b72e4611906203a7152c816922d41d3a8ae56 [file] [log] [blame]
Adedeji Adebisi12c5f112021-07-22 18:07:52 +00001// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "main.hpp"
16
17#include "analyzer.hpp"
18#include "bargraph.hpp"
19#include "dbus_capture.hpp"
20#include "histogram.hpp"
21#include "menu.hpp"
22#include "sensorhelper.hpp"
23#include "views.hpp"
24
25#include <fmt/printf.h>
26#include <ncurses.h>
27#include <stdio.h>
28#include <unistd.h>
29
30#include <iomanip>
31#include <sstream>
32#include <thread>
33
34DBusTopWindow* g_current_active_view;
35SummaryView* g_summary_window;
36SensorDetailView* g_sensor_detail_view;
37DBusStatListView* g_dbus_stat_list_view;
38FooterView* g_footer_view;
39BarGraph<float>* g_bargraph = nullptr;
40Histogram<float>* g_histogram;
41std::vector<DBusTopWindow*> g_views;
42int g_highlighted_view_index = INVALID;
43sd_bus* g_bus = nullptr;
44SensorSnapshot* g_sensor_snapshot;
45DBusConnectionSnapshot* g_connection_snapshot;
46DBusTopStatistics* g_dbus_statistics; // At every update interval,
47 // dbus_top_analyzer::g_dbus_statistics's
48 // value is copied to this one for display
49void ReinitializeUI();
50int maxx, maxy, halfx, halfy;
51
52void ActivateWindowA()
53{
54 g_views[0]->visible_=true;
55 g_views[0]->maximize_=true;
56 g_views[1]->visible_=false;
57 g_views[2]->visible_=false;
58}
59
60void ActivateWindowB()
61{
62 g_views[1]->visible_=true;
63 g_views[1]->maximize_=true;
64 g_views[0]->visible_=false;
65 g_views[2]->visible_=false;
66}
67void ActivateWindowC()
68{
69 g_views[2]->visible_=true;
70 g_views[2]->maximize_=true;
71 g_views[0]->visible_=false;
72 g_views[1]->visible_=false;
73}
74void ActivateAllWindows()
75{
76 g_views[0]->maximize_ = false;
77 g_views[1]->maximize_=false;
78 g_views[2]->maximize_=false;
79 g_views[0]->visible_=true;
80 g_views[1]->visible_=true;
81 g_views[2]->visible_= true;
82}
83
84void InitColorPairs()
85{
86 init_pair(1, COLOR_WHITE, COLOR_BLACK); // Does not work on actual machine
87 init_pair(2, COLOR_BLACK, COLOR_WHITE);
88}
89
90// Returns number of lines drawn
91int DrawTextWithWidthLimit(WINDOW* win, std::string txt, int y, int x,
92 int width, const std::string& delimiters)
93{
94 int ret = 0;
95 std::string curr_word, curr_line;
96 while (txt.empty() == false)
97 {
98 ret++;
99 if (static_cast<int>(txt.size()) > width)
100 {
101 mvwprintw(win, y, x, txt.substr(0, width).c_str());
102 txt = txt.substr(width);
103 }
104 else
105 {
106 mvwprintw(win, y, x, txt.c_str());
107 break;
108 }
109 y++;
110 }
111 return ret;
112}
113
114void UpdateWindowSizes()
115{
116 /* calculate window sizes and locations */
117 if (getenv("FIXED_TERMINAL_SIZE"))
118 {
119 maxx = 100;
120 maxy = 30;
121 }
122 else
123 {
124 getmaxyx(stdscr, maxy, maxx);
125 halfx = maxx >> 1;
126 halfy = maxy >> 1;
127 }
128 for (DBusTopWindow* v : g_views)
129 {
130 v->OnResize(maxx, maxy);
131 if(v->maximize_){
132 v->rect={0,0,maxx,maxy-MARGIN_BOTTOM};
133 v->UpdateWindowSizeAndPosition();
134 }
135 }
136}
137
138std::string FloatToString(float value)
139{
140 return fmt::sprintf("%.2f", value);
141}
142
143void DBusTopRefresh()
144{
145 UpdateWindowSizes();
146 for (DBusTopWindow* v : g_views)
147 {
148 v->Render();
149 }
150 DBusTopWindow* focused_view = g_current_active_view;
151 if (focused_view)
152 {
153 focused_view->DrawBorderIfNeeded(); // focused view border: on top
154 }
155 refresh();
156}
157
158// This function is called by the Capture thread
159void DBusTopStatisticsCallback(DBusTopStatistics* stat, Histogram<float>* hist)
160{
161 if (stat == nullptr)
162 return;
163 // Makes a copy for display
164 // TODO: Add a mutex here for safety
165 stat->Assign(g_dbus_statistics);
166 hist->Assign(g_histogram);
167 float interval_secs = stat->seconds_since_last_sample_;
168 if (interval_secs == 0)
169 {
170 interval_secs = GetSummaryIntervalInMillises() / 1000.0f;
171 }
172 g_summary_window->UpdateDBusTopStatistics(stat);
173 stat->SetSortFieldsAndReset(g_dbus_stat_list_view->GetSortFields());
174 // ReinitializeUI(); // Don't do it here, only when user presses [R]
175 DBusTopRefresh();
176}
177
178void CycleHighlightedView()
179{
180 int new_index = 0;
181 if (g_highlighted_view_index == INVALID)
182 {
183 new_index = 0;
184 }
185 else
186 {
187 new_index = g_highlighted_view_index + 1;
188 }
189 while (new_index < static_cast<int>(g_views.size()) &&
190 g_views[new_index]->selectable_ == false)
191 {
192 new_index++;
193 }
194 if (new_index >= static_cast<int>(g_views.size()))
195 {
196 new_index = INVALID;
197 }
198 // Un-highlight all
199 for (DBusTopWindow* v : g_views)
200 {
201 v->focused_ = false;
202 }
203 if (new_index != INVALID)
204 {
205 g_views[new_index]->focused_ = true;
206 g_current_active_view = g_views[new_index];
207 }
208 else
209 {
210 g_current_active_view = nullptr;
211 }
212 g_highlighted_view_index = new_index;
213 DBusTopRefresh();
214}
215
216int UserInputThread()
217{
218 while (true)
219 {
220 int c = getch();
221 DBusTopWindow* curr_view = g_current_active_view;
222 // If a view is currently focused on
223 if (curr_view)
224 {
225 switch (c)
226 {
227 case '\e': // 27 in dec, 0x1B in hex, escape key
228 {
229 getch();
230 c = getch();
231 switch (c)
232 {
233 case 'A':
234 curr_view->OnKeyDown("up");
235 break;
236 case 'B':
237 curr_view->OnKeyDown("down");
238 break;
239 case 'C':
240 curr_view->OnKeyDown("right");
241 break;
242 case 'D':
243 curr_view->OnKeyDown("left");
244 break;
245 case '\e':
246 curr_view->OnKeyDown("escape");
247 break;
248 }
249 break;
250 }
251 case '\n': // 10 in dec, 0x0A in hex, line feed
252 {
253 curr_view->OnKeyDown("enter");
254 break;
255 }
256 case 'q':
257 case 'Q': // Q key
258 {
259 curr_view->OnKeyDown("escape");
260 break;
261 }
262 case 'a':
263 case 'A': // A key
264 {
265 curr_view->OnKeyDown("a");
266 break;
267 }
268 case 'd':
269 case 'D': // D key
270 {
271 curr_view->OnKeyDown("d");
272 break;
273 }
274 case 33: // Page up
275 {
276 curr_view->OnKeyDown("pageup");
277 break;
278 }
279 case 34: // Page down
280 {
281 curr_view->OnKeyDown("pagedown");
282 break;
283 }
284 case ' ': // Spacebar
285 {
286 curr_view->OnKeyDown("space");
287 break;
288 }
289 }
290 }
291 // The following keys are registered both when a view is selected and
292 // when it is not
293 switch (c)
294 {
295 case '\t': // 9 in dec, 0x09 in hex, tab
296 {
297 CycleHighlightedView();
298 break;
299 }
300 case 'r':
301 case 'R':
302 {
303 ReinitializeUI();
304 DBusTopRefresh();
305 break;
306 }
307 case 'x':
308 case 'X':
309 {
310 clear();
311 ActivateWindowA();
312 break;
313 }
314 case 'y':
315 case 'Y':
316 {
317 clear();
318 ActivateWindowB();
319 break;
320 }
321 case 'z':
322 case 'Z':
323 {
324 clear();
325 ActivateWindowC();
326 break;
327 }
328 case 'h':
329 case 'H':
330 {
331 ActivateAllWindows();
332 DBusTopRefresh();
333 }
334 default:
335 break;
336 }
337 }
338 exit(0);
339}
340
341void ReinitializeUI()
342{
343 endwin();
344 initscr();
345 use_default_colors();
346 noecho();
347 for (int i = 0; i < static_cast<int>(g_views.size()); i++)
348 {
349 g_views[i]->RecreateWindow();
350 }
351}
352
353int main(int argc, char** argv)
354{
355 int r = AcquireBus(&g_bus);
356 if (r <= 0)
357 {
358 printf("Error acquiring bus for monitoring\n");
359 exit(0);
360 }
361
362 printf("Listing all sensors for display\n");
363 // ListAllSensors creates connection snapshot and sensor snapshot
364 dbus_top_analyzer::ListAllSensors();
365 g_bargraph = new BarGraph<float>(300);
366 g_histogram = new Histogram<float>();
367
368 initscr();
369 use_default_colors();
370 start_color();
371 noecho();
372
373 clear();
374 g_dbus_statistics = new DBusTopStatistics();
375 g_summary_window = new SummaryView();
376 g_sensor_detail_view = new SensorDetailView();
377 g_dbus_stat_list_view = new DBusStatListView();
378 g_footer_view = new FooterView();
379 g_views.push_back(g_summary_window);
380 g_views.push_back(g_sensor_detail_view);
381 g_views.push_back(g_dbus_stat_list_view);
382 g_views.push_back(g_footer_view);
383
384 g_sensor_detail_view->UpdateSensorSnapshot(g_sensor_snapshot);
385 UpdateWindowSizes();
386 dbus_top_analyzer::SetDBusTopStatisticsCallback(&DBusTopStatisticsCallback);
387 std::thread capture_thread(DbusCaptureThread);
388 std::thread user_input_thread(UserInputThread);
389 capture_thread.join();
390
391 return 0;
392}