1/*
2 * Copyright 2007, Intel Corporation
3 *
4 * This file is part of PowerTOP
5 *
6 * This program file is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 * for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program in a file named COPYING; if not, write to the
17 * Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
20 *
21 * Authors:
22 * 	Arjan van de Ven <arjan@linux.intel.com>
23 */
24
25#include <unistd.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <stdint.h>
30#include <sys/types.h>
31#include <dirent.h>
32#include <ncurses.h>
33#include <time.h>
34#include <wchar.h>
35
36#include "powertop.h"
37
38static WINDOW *title_bar_window;
39static WINDOW *cstate_window;
40static WINDOW *wakeup_window;
41static WINDOW *battery_power_window;
42static WINDOW *timerstat_window;
43static WINDOW *suggestion_window;
44static WINDOW *status_bar_window;
45
46#define print(win, y, x, fmt, args...) do { if (dump) printf(fmt, ## args); else mvwprintw(win, y, x, fmt, ## args); } while (0)
47
48char status_bar_slots[10][40];
49
50static void cleanup_curses(void) {
51	endwin();
52}
53
54static void zap_windows(void)
55{
56	if (title_bar_window) {
57		delwin(title_bar_window);
58		title_bar_window = NULL;
59	}
60	if (cstate_window) {
61		delwin(cstate_window);
62		cstate_window = NULL;
63	}
64	if (wakeup_window) {
65		delwin(wakeup_window);
66		wakeup_window = NULL;
67	}
68	if (battery_power_window) {
69		delwin(battery_power_window);
70		battery_power_window = NULL;
71	}
72	if (timerstat_window) {
73		delwin(timerstat_window);
74		timerstat_window = NULL;
75	}
76	if (suggestion_window) {
77		delwin(suggestion_window);
78		suggestion_window = NULL;
79	}
80	if (status_bar_window) {
81		delwin(status_bar_window);
82		status_bar_window = NULL;
83	}
84}
85
86
87int maxx, maxy;
88
89int maxtimerstats = 50;
90int maxwidth = 200;
91
92void setup_windows(void)
93{
94	getmaxyx(stdscr, maxy, maxx);
95
96	zap_windows();
97
98	title_bar_window = subwin(stdscr, 1, maxx, 0, 0);
99	cstate_window = subwin(stdscr, 7, maxx, 2, 0);
100	wakeup_window = subwin(stdscr, 1, maxx, 9, 0);
101	battery_power_window = subwin(stdscr, 2, maxx, 10, 0);
102	timerstat_window = subwin(stdscr, maxy-16, maxx, 12, 0);
103	maxtimerstats = maxy-16  -2;
104	maxwidth = maxx - 18;
105	suggestion_window = subwin(stdscr, 3, maxx, maxy-4, 0);
106	status_bar_window = subwin(stdscr, 1, maxx, maxy-1, 0);
107
108	strcpy(status_bar_slots[0], _(" Q - Quit "));
109	strcpy(status_bar_slots[1], _(" R - Refresh "));
110
111	werase(stdscr);
112	refresh();
113}
114
115void initialize_curses(void)
116{
117	initscr();
118	start_color();
119	keypad(stdscr, TRUE);	/* enable keyboard mapping */
120	nonl();			/* tell curses not to do NL->CR/NL on output */
121	cbreak();		/* take input chars one at a time, no wait for \n */
122	noecho();		/* dont echo input */
123	curs_set(0);		/* turn off cursor */
124	use_default_colors();
125
126	init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK);
127	init_pair(PT_COLOR_HEADER_BAR, COLOR_BLACK, COLOR_WHITE);
128	init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED);
129	init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED);
130	init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW);
131	init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN);
132	init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE);
133	init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK);
134
135	atexit(cleanup_curses);
136}
137
138void show_title_bar(void)
139{
140	int i;
141	int x;
142	wattrset(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR));
143	wbkgd(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR));
144	werase(title_bar_window);
145
146	print(title_bar_window, 0, 0,  "     PowerTOP version 1.11      (C) 2007 Intel Corporation");
147
148	wrefresh(title_bar_window);
149
150	werase(status_bar_window);
151
152	x = 0;
153	for (i=0; i<10; i++) {
154		if (strlen(status_bar_slots[i])==0)
155			continue;
156		wattron(status_bar_window, A_REVERSE);
157		print(status_bar_window, 0, x, status_bar_slots[i]);
158		wattroff(status_bar_window, A_REVERSE);
159		x+= strlen(status_bar_slots[i])+1;
160	}
161	wrefresh(status_bar_window);
162}
163
164void show_cstates(void)
165{
166	int i, count = 0;
167	werase(cstate_window);
168
169	for (i=0; i < 10; i++) {
170		if (i == topcstate+1)
171			wattron(cstate_window, A_BOLD);
172		else
173			wattroff(cstate_window, A_BOLD);
174		if (strlen(cstate_lines[i]) && count <= 6) {
175			print(cstate_window, count, 0, "%s", cstate_lines[i]);
176			count++;
177		}
178	}
179
180	for (i=0; i<6; i++) {
181		if (i == topfreq+1)
182			wattron(cstate_window, A_BOLD);
183		else
184			wattroff(cstate_window, A_BOLD);
185		print(cstate_window, i, 38, "%s", cpufreqstrings[i]);
186	}
187
188	wrefresh(cstate_window);
189}
190
191
192void show_acpi_power_line(double rate, double cap, double capdelta, time_t ti)
193{
194	char buffer[1024];
195
196	sprintf(buffer,  _("no ACPI power usage estimate available") );
197
198	werase(battery_power_window);
199	if (rate > 0.001) {
200		char *c;
201		sprintf(buffer, _("Power usage (ACPI estimate): %3.1fW (%3.1f hours)"), rate, cap/rate);
202		strcat(buffer, " ");
203		c = &buffer[strlen(buffer)];
204		if (ti>180 && capdelta > 0)
205			sprintf(c, _("(long term: %3.1fW,/%3.1fh)"), 3600*capdelta / ti, cap / (3600*capdelta/ti+0.01));
206	}
207	else if (ti>120 && capdelta > 0.001)
208		sprintf(buffer, _("Power usage (5 minute ACPI estimate) : %5.1f W (%3.1f hours left)"), 3600*capdelta / ti, cap / (3600*capdelta/ti+0.01));
209
210	print(battery_power_window, 0, 0, "%s\n", buffer);
211	wrefresh(battery_power_window);
212}
213
214void show_pmu_power_line(unsigned sum_voltage_mV,
215                         unsigned sum_charge_mAh, unsigned sum_max_charge_mAh,
216                         int sum_discharge_mA)
217{
218	char buffer[1024];
219
220	if (sum_discharge_mA != 0)
221	{
222		unsigned remaining_charge_mAh;
223
224		if (sum_discharge_mA < 0)
225		{
226			/* we are currently discharging */
227			sum_discharge_mA = -sum_discharge_mA;
228			remaining_charge_mAh = sum_charge_mAh;
229		}
230		else
231		{
232			/* we are currently charging */
233			remaining_charge_mAh = (sum_max_charge_mAh
234						- sum_charge_mAh);
235		}
236
237		snprintf(buffer, sizeof(buffer),
238			 _("Power usage: %3.1fW (%3.1f hours)"),
239			 sum_voltage_mV * sum_discharge_mA / 1e6,
240			 (double)remaining_charge_mAh / sum_discharge_mA);
241	}
242	else
243		snprintf(buffer, sizeof(buffer),
244			 _("no power usage estimate available") );
245
246	werase(battery_power_window);
247	print(battery_power_window, 0, 0, "%s\n", buffer);
248	wrefresh(battery_power_window);
249}
250
251
252void show_wakeups(double d, double interval, double C0time)
253{
254	werase(wakeup_window);
255
256	wbkgd(wakeup_window, COLOR_PAIR(PT_COLOR_RED));
257	if (d <= 25.0)
258		wbkgd(wakeup_window, COLOR_PAIR(PT_COLOR_YELLOW));
259	if (d <= 10.0)
260		wbkgd(wakeup_window, COLOR_PAIR(PT_COLOR_GREEN));
261
262	/*
263	 * if the cpu is really busy.... then make it blue to indicate
264	 * that it's not the primary power consumer anymore
265	 */
266	if (C0time > 25.0)
267		wbkgd(wakeup_window, COLOR_PAIR(PT_COLOR_BLUE));
268
269	wattron(wakeup_window, A_BOLD);
270	print(wakeup_window, 0, 0, _("Wakeups-from-idle per second : %4.1f\tinterval: %0.1fs\n"), d, interval);
271	wrefresh(wakeup_window);
272}
273
274void show_timerstats(int nostats, int ticktime)
275{
276	int i;
277	werase(timerstat_window);
278
279	if (!nostats) {
280		int counter = 0;
281		print(timerstat_window, 0, 0, _("Top causes for wakeups:\n"));
282		for (i = 0; i < linehead; i++)
283			if (lines[i].count > 0 && counter++ < maxtimerstats) {
284				if ((lines[i].count * 1.0 / ticktime) >= 10.0)
285					wattron(timerstat_window, A_BOLD);
286				else
287					wattroff(timerstat_window, A_BOLD);
288				if (showpids)
289					print(timerstat_window, i+1, 0," %5.1f%% (%5.1f)   [%6s] %s \n", lines[i].count * 100.0 / linectotal,
290						lines[i].count * 1.0 / ticktime,
291						lines[i].pid, lines[i].string);
292				else
293					print(timerstat_window, i+1, 0," %5.1f%% (%5.1f)   %s \n", lines[i].count * 100.0 / linectotal,
294						lines[i].count * 1.0 / ticktime,
295						lines[i].string);
296				}
297	} else {
298		if (geteuid() == 0) {
299			print(timerstat_window, 0, 0, _("No detailed statistics available; please enable the CONFIG_TIMER_STATS kernel option\n"));
300			print(timerstat_window, 1, 0, _("This option is located in the Kernel Debugging section of menuconfig\n"));
301			print(timerstat_window, 2, 0, _("(which is CONFIG_DEBUG_KERNEL=y in the config file)\n"));
302			print(timerstat_window, 3, 0, _("Note: this is only available in 2.6.21 and later kernels\n"));
303		} else
304			print(timerstat_window, 0, 0, _("No detailed statistics available; PowerTOP needs root privileges for that\n"));
305	}
306
307
308	wrefresh(timerstat_window);
309}
310
311void show_suggestion(char *sug)
312{
313	werase(suggestion_window);
314	print(suggestion_window, 0, 0, "%s", sug);
315	wrefresh(suggestion_window);
316}
317