tui.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. /*
  2. * tui.c ncurses text user interface for TMON program
  3. *
  4. * Copyright (C) 2013 Intel Corporation. All rights reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License version
  8. * 2 or later as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * Author: Jacob Pan <jacob.jun.pan@linux.intel.com>
  16. *
  17. */
  18. #include <unistd.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <stdint.h>
  23. #include <ncurses.h>
  24. #include <time.h>
  25. #include <syslog.h>
  26. #include <panel.h>
  27. #include <pthread.h>
  28. #include <signal.h>
  29. #include "tmon.h"
  30. #define min(x, y) ({ \
  31. typeof(x) _min1 = (x); \
  32. typeof(y) _min2 = (y); \
  33. (void) (&_min1 == &_min2); \
  34. _min1 < _min2 ? _min1 : _min2; })
  35. #define max(x, y) ({ \
  36. typeof(x) _max1 = (x); \
  37. typeof(y) _max2 = (y); \
  38. (void) (&_max1 == &_max2); \
  39. _max1 > _max2 ? _max1 : _max2; })
  40. static PANEL *data_panel;
  41. static PANEL *dialogue_panel;
  42. static PANEL *top;
  43. static WINDOW *title_bar_window;
  44. static WINDOW *tz_sensor_window;
  45. static WINDOW *cooling_device_window;
  46. static WINDOW *control_window;
  47. static WINDOW *status_bar_window;
  48. static WINDOW *thermal_data_window;
  49. static WINDOW *dialogue_window;
  50. char status_bar_slots[10][40];
  51. static void draw_hbar(WINDOW *win, int y, int start, int len,
  52. unsigned long pattern, bool end);
  53. static int maxx, maxy;
  54. static int maxwidth = 200;
  55. #define TITLE_BAR_HIGHT 1
  56. #define SENSOR_WIN_HIGHT 4 /* one row for tz name, one for trip points */
  57. /* daemon mode flag (set by startup parameter -d) */
  58. static int tui_disabled;
  59. static void close_panel(PANEL *p)
  60. {
  61. if (p) {
  62. del_panel(p);
  63. p = NULL;
  64. }
  65. }
  66. static void close_window(WINDOW *win)
  67. {
  68. if (win) {
  69. delwin(win);
  70. win = NULL;
  71. }
  72. }
  73. void close_windows(void)
  74. {
  75. if (tui_disabled)
  76. return;
  77. /* must delete panels before their attached windows */
  78. if (dialogue_window)
  79. close_panel(dialogue_panel);
  80. if (cooling_device_window)
  81. close_panel(data_panel);
  82. close_window(title_bar_window);
  83. close_window(tz_sensor_window);
  84. close_window(status_bar_window);
  85. close_window(cooling_device_window);
  86. close_window(control_window);
  87. close_window(thermal_data_window);
  88. close_window(dialogue_window);
  89. }
  90. void write_status_bar(int x, char *line)
  91. {
  92. mvwprintw(status_bar_window, 0, x, "%s", line);
  93. wrefresh(status_bar_window);
  94. }
  95. /* wrap at 5 */
  96. #define DIAG_DEV_ROWS 5
  97. /*
  98. * list cooling devices + "set temp" entry; wraps after 5 rows, if they fit
  99. */
  100. static int diag_dev_rows(void)
  101. {
  102. int entries = ptdata.nr_cooling_dev + 1;
  103. int rows = max(DIAG_DEV_ROWS, (entries + 1) / 2);
  104. return min(rows, entries);
  105. }
  106. void setup_windows(void)
  107. {
  108. int y_begin = 1;
  109. if (tui_disabled)
  110. return;
  111. getmaxyx(stdscr, maxy, maxx);
  112. resizeterm(maxy, maxx);
  113. title_bar_window = subwin(stdscr, TITLE_BAR_HIGHT, maxx, 0, 0);
  114. y_begin += TITLE_BAR_HIGHT;
  115. tz_sensor_window = subwin(stdscr, SENSOR_WIN_HIGHT, maxx, y_begin, 0);
  116. y_begin += SENSOR_WIN_HIGHT;
  117. cooling_device_window = subwin(stdscr, ptdata.nr_cooling_dev + 3, maxx,
  118. y_begin, 0);
  119. y_begin += ptdata.nr_cooling_dev + 3; /* 2 lines for border */
  120. /* two lines to show borders, one line per tz show trip point position
  121. * and value.
  122. * dialogue window is a pop-up, when needed it lays on top of cdev win
  123. */
  124. dialogue_window = subwin(stdscr, diag_dev_rows() + 5, maxx-50,
  125. DIAG_Y, DIAG_X);
  126. thermal_data_window = subwin(stdscr, ptdata.nr_tz_sensor *
  127. NR_LINES_TZDATA + 3, maxx, y_begin, 0);
  128. y_begin += ptdata.nr_tz_sensor * NR_LINES_TZDATA + 3;
  129. control_window = subwin(stdscr, 4, maxx, y_begin, 0);
  130. scrollok(cooling_device_window, TRUE);
  131. maxwidth = maxx - 18;
  132. status_bar_window = subwin(stdscr, 1, maxx, maxy-1, 0);
  133. strcpy(status_bar_slots[0], " Ctrl-c - Quit ");
  134. strcpy(status_bar_slots[1], " TAB - Tuning ");
  135. wmove(status_bar_window, 1, 30);
  136. /* prepare panels for dialogue, if panel already created then we must
  137. * be doing resizing, so just replace windows with new ones, old ones
  138. * should have been deleted by close_window
  139. */
  140. data_panel = new_panel(cooling_device_window);
  141. if (!data_panel)
  142. syslog(LOG_DEBUG, "No data panel\n");
  143. else {
  144. if (dialogue_window) {
  145. dialogue_panel = new_panel(dialogue_window);
  146. if (!dialogue_panel)
  147. syslog(LOG_DEBUG, "No dialogue panel\n");
  148. else {
  149. /* Set up the user pointer to the next panel*/
  150. set_panel_userptr(data_panel, dialogue_panel);
  151. set_panel_userptr(dialogue_panel, data_panel);
  152. top = data_panel;
  153. }
  154. } else
  155. syslog(LOG_INFO, "no dialogue win, term too small\n");
  156. }
  157. doupdate();
  158. werase(stdscr);
  159. refresh();
  160. }
  161. void resize_handler(int sig)
  162. {
  163. /* start over when term gets resized, but first we clean up */
  164. close_windows();
  165. endwin();
  166. refresh();
  167. clear();
  168. getmaxyx(stdscr, maxy, maxx); /* get the new screen size */
  169. setup_windows();
  170. /* rate limit */
  171. sleep(1);
  172. syslog(LOG_DEBUG, "SIG %d, term resized to %d x %d\n",
  173. sig, maxy, maxx);
  174. signal(SIGWINCH, resize_handler);
  175. }
  176. const char cdev_title[] = " COOLING DEVICES ";
  177. void show_cooling_device(void)
  178. {
  179. int i, j, x, y = 0;
  180. if (tui_disabled || !cooling_device_window)
  181. return;
  182. werase(cooling_device_window);
  183. wattron(cooling_device_window, A_BOLD);
  184. mvwprintw(cooling_device_window, 1, 1,
  185. "ID Cooling Dev Cur Max Thermal Zone Binding");
  186. wattroff(cooling_device_window, A_BOLD);
  187. for (j = 0; j < ptdata.nr_cooling_dev; j++) {
  188. /* draw cooling device list on the left in the order of
  189. * cooling device instances. skip unused idr.
  190. */
  191. mvwprintw(cooling_device_window, j + 2, 1,
  192. "%02d %12.12s%6d %6d",
  193. ptdata.cdi[j].instance,
  194. ptdata.cdi[j].type,
  195. ptdata.cdi[j].cur_state,
  196. ptdata.cdi[j].max_state);
  197. }
  198. /* show cdev binding, y is the global cooling device instance */
  199. for (i = 0; i < ptdata.nr_tz_sensor; i++) {
  200. int tz_inst = ptdata.tzi[i].instance;
  201. for (j = 0; j < ptdata.nr_cooling_dev; j++) {
  202. int cdev_inst;
  203. y = j;
  204. x = tz_inst * TZONE_RECORD_SIZE + TZ_LEFT_ALIGN;
  205. draw_hbar(cooling_device_window, y+2, x,
  206. TZONE_RECORD_SIZE-1, ACS_VLINE, false);
  207. /* draw a column of spaces to separate thermal zones */
  208. mvwprintw(cooling_device_window, y+2, x-1, " ");
  209. if (ptdata.tzi[i].cdev_binding) {
  210. cdev_inst = ptdata.cdi[j].instance;
  211. unsigned long trip_binding =
  212. ptdata.tzi[i].trip_binding[cdev_inst];
  213. int k = 0; /* per zone trip point id that
  214. * binded to this cdev, one to
  215. * many possible based on the
  216. * binding bitmask.
  217. */
  218. syslog(LOG_DEBUG,
  219. "bind tz%d cdev%d tp%lx %d cdev%lx\n",
  220. i, j, trip_binding, y,
  221. ptdata.tzi[i].cdev_binding);
  222. /* draw each trip binding for the cdev */
  223. while (trip_binding >>= 1) {
  224. k++;
  225. if (!(trip_binding & 1))
  226. continue;
  227. /* draw '*' to show binding */
  228. mvwprintw(cooling_device_window,
  229. y + 2,
  230. x + ptdata.tzi[i].nr_trip_pts -
  231. k - 1, "*");
  232. }
  233. }
  234. }
  235. }
  236. /* draw border after data so that border will not be messed up
  237. * even there is not enough space for all the data to be shown
  238. */
  239. wborder(cooling_device_window, 0, 0, 0, 0, 0, 0, 0, 0);
  240. wattron(cooling_device_window, A_BOLD);
  241. mvwprintw(cooling_device_window, 0, maxx/2 - sizeof(cdev_title),
  242. cdev_title);
  243. wattroff(cooling_device_window, A_BOLD);
  244. wrefresh(cooling_device_window);
  245. }
  246. const char DIAG_TITLE[] = "[ TUNABLES ]";
  247. void show_dialogue(void)
  248. {
  249. int j, x = 0, y = 0;
  250. int rows, cols;
  251. WINDOW *w = dialogue_window;
  252. if (tui_disabled || !w)
  253. return;
  254. getmaxyx(w, rows, cols);
  255. /* Silence compiler 'unused' warnings */
  256. (void)cols;
  257. werase(w);
  258. box(w, 0, 0);
  259. mvwprintw(w, 0, maxx/4, DIAG_TITLE);
  260. /* list all the available tunables */
  261. for (j = 0; j <= ptdata.nr_cooling_dev; j++) {
  262. y = j % diag_dev_rows();
  263. if (y == 0 && j != 0)
  264. x += 20;
  265. if (j == ptdata.nr_cooling_dev)
  266. /* save last choice for target temp */
  267. mvwprintw(w, y+1, x+1, "%C-%.12s", 'A'+j, "Set Temp");
  268. else
  269. mvwprintw(w, y+1, x+1, "%C-%.10s-%2d", 'A'+j,
  270. ptdata.cdi[j].type, ptdata.cdi[j].instance);
  271. }
  272. wattron(w, A_BOLD);
  273. mvwprintw(w, diag_dev_rows()+1, 1, "Enter Choice [A-Z]?");
  274. wattroff(w, A_BOLD);
  275. /* print legend at the bottom line */
  276. mvwprintw(w, rows - 2, 1,
  277. "Legend: A=Active, P=Passive, C=Critical");
  278. wrefresh(dialogue_window);
  279. }
  280. void write_dialogue_win(char *buf, int y, int x)
  281. {
  282. WINDOW *w = dialogue_window;
  283. mvwprintw(w, y, x, "%s", buf);
  284. }
  285. const char control_title[] = " CONTROLS ";
  286. void show_control_w(void)
  287. {
  288. unsigned long state;
  289. get_ctrl_state(&state);
  290. if (tui_disabled || !control_window)
  291. return;
  292. werase(control_window);
  293. mvwprintw(control_window, 1, 1,
  294. "PID gain: kp=%2.2f ki=%2.2f kd=%2.2f Output %2.2f",
  295. p_param.kp, p_param.ki, p_param.kd, p_param.y_k);
  296. mvwprintw(control_window, 2, 1,
  297. "Target Temp: %2.1fC, Zone: %d, Control Device: %.12s",
  298. p_param.t_target, target_thermal_zone, ctrl_cdev);
  299. /* draw border last such that everything is within boundary */
  300. wborder(control_window, 0, 0, 0, 0, 0, 0, 0, 0);
  301. wattron(control_window, A_BOLD);
  302. mvwprintw(control_window, 0, maxx/2 - sizeof(control_title),
  303. control_title);
  304. wattroff(control_window, A_BOLD);
  305. wrefresh(control_window);
  306. }
  307. void initialize_curses(void)
  308. {
  309. if (tui_disabled)
  310. return;
  311. initscr();
  312. start_color();
  313. keypad(stdscr, TRUE); /* enable keyboard mapping */
  314. nonl(); /* tell curses not to do NL->CR/NL on output */
  315. cbreak(); /* take input chars one at a time */
  316. noecho(); /* dont echo input */
  317. curs_set(0); /* turn off cursor */
  318. use_default_colors();
  319. init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK);
  320. init_pair(PT_COLOR_HEADER_BAR, COLOR_BLACK, COLOR_WHITE);
  321. init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED);
  322. init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED);
  323. init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW);
  324. init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN);
  325. init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE);
  326. init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK);
  327. }
  328. void show_title_bar(void)
  329. {
  330. int i;
  331. int x = 0;
  332. if (tui_disabled || !title_bar_window)
  333. return;
  334. wattrset(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR));
  335. wbkgd(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR));
  336. werase(title_bar_window);
  337. mvwprintw(title_bar_window, 0, 0,
  338. " TMON v%s", VERSION);
  339. wrefresh(title_bar_window);
  340. werase(status_bar_window);
  341. for (i = 0; i < 10; i++) {
  342. if (strlen(status_bar_slots[i]) == 0)
  343. continue;
  344. wattron(status_bar_window, A_REVERSE);
  345. mvwprintw(status_bar_window, 0, x, "%s", status_bar_slots[i]);
  346. wattroff(status_bar_window, A_REVERSE);
  347. x += strlen(status_bar_slots[i]) + 1;
  348. }
  349. wrefresh(status_bar_window);
  350. }
  351. static void handle_input_val(int ch)
  352. {
  353. char buf[32];
  354. int val;
  355. char path[256];
  356. WINDOW *w = dialogue_window;
  357. echo();
  358. keypad(w, TRUE);
  359. wgetnstr(w, buf, 31);
  360. val = atoi(buf);
  361. if (ch == ptdata.nr_cooling_dev) {
  362. snprintf(buf, 31, "Invalid Temp %d! %d-%d", val,
  363. MIN_CTRL_TEMP, MAX_CTRL_TEMP);
  364. if (val < MIN_CTRL_TEMP || val > MAX_CTRL_TEMP)
  365. write_status_bar(40, buf);
  366. else {
  367. p_param.t_target = val;
  368. snprintf(buf, 31, "Set New Target Temp %d", val);
  369. write_status_bar(40, buf);
  370. }
  371. } else {
  372. snprintf(path, 256, "%s/%s%d", THERMAL_SYSFS,
  373. CDEV, ptdata.cdi[ch].instance);
  374. sysfs_set_ulong(path, "cur_state", val);
  375. }
  376. noecho();
  377. dialogue_on = 0;
  378. show_data_w();
  379. show_control_w();
  380. top = (PANEL *)panel_userptr(top);
  381. top_panel(top);
  382. }
  383. static void handle_input_choice(int ch)
  384. {
  385. char buf[48];
  386. int base = 0;
  387. int cdev_id = 0;
  388. if ((ch >= 'A' && ch <= 'A' + ptdata.nr_cooling_dev) ||
  389. (ch >= 'a' && ch <= 'a' + ptdata.nr_cooling_dev)) {
  390. base = (ch < 'a') ? 'A' : 'a';
  391. cdev_id = ch - base;
  392. if (ptdata.nr_cooling_dev == cdev_id)
  393. snprintf(buf, sizeof(buf), "New Target Temp:");
  394. else
  395. snprintf(buf, sizeof(buf), "New Value for %.10s-%2d: ",
  396. ptdata.cdi[cdev_id].type,
  397. ptdata.cdi[cdev_id].instance);
  398. write_dialogue_win(buf, diag_dev_rows() + 2, 2);
  399. handle_input_val(cdev_id);
  400. } else {
  401. snprintf(buf, sizeof(buf), "Invalid selection %d", ch);
  402. write_dialogue_win(buf, 8, 2);
  403. }
  404. }
  405. void *handle_tui_events(void *arg)
  406. {
  407. int ch;
  408. keypad(cooling_device_window, TRUE);
  409. while ((ch = wgetch(cooling_device_window)) != EOF) {
  410. if (tmon_exit)
  411. break;
  412. /* when term size is too small, no dialogue panels are set.
  413. * we need to filter out such cases.
  414. */
  415. if (!data_panel || !dialogue_panel ||
  416. !cooling_device_window ||
  417. !dialogue_window) {
  418. continue;
  419. }
  420. pthread_mutex_lock(&input_lock);
  421. if (dialogue_on) {
  422. handle_input_choice(ch);
  423. /* top panel filter */
  424. if (ch == 'q' || ch == 'Q')
  425. ch = 0;
  426. }
  427. switch (ch) {
  428. case KEY_LEFT:
  429. box(cooling_device_window, 10, 0);
  430. break;
  431. case 9: /* TAB */
  432. top = (PANEL *)panel_userptr(top);
  433. top_panel(top);
  434. if (top == dialogue_panel) {
  435. dialogue_on = 1;
  436. show_dialogue();
  437. } else {
  438. dialogue_on = 0;
  439. /* force refresh */
  440. show_data_w();
  441. show_control_w();
  442. }
  443. break;
  444. case 'q':
  445. case 'Q':
  446. tmon_exit = 1;
  447. break;
  448. }
  449. update_panels();
  450. doupdate();
  451. pthread_mutex_unlock(&input_lock);
  452. }
  453. if (arg)
  454. *(int *)arg = 0; /* make gcc happy */
  455. return NULL;
  456. }
  457. /* draw a horizontal bar in given pattern */
  458. static void draw_hbar(WINDOW *win, int y, int start, int len, unsigned long ptn,
  459. bool end)
  460. {
  461. mvwaddch(win, y, start, ptn);
  462. whline(win, ptn, len);
  463. if (end)
  464. mvwaddch(win, y, MAX_DISP_TEMP+TDATA_LEFT, ']');
  465. }
  466. static char trip_type_to_char(int type)
  467. {
  468. switch (type) {
  469. case THERMAL_TRIP_CRITICAL: return 'C';
  470. case THERMAL_TRIP_HOT: return 'H';
  471. case THERMAL_TRIP_PASSIVE: return 'P';
  472. case THERMAL_TRIP_ACTIVE: return 'A';
  473. default:
  474. return '?';
  475. }
  476. }
  477. /* fill a string with trip point type and value in one line
  478. * e.g. P(56) C(106)
  479. * maintain the distance one degree per char
  480. */
  481. static void draw_tp_line(int tz, int y)
  482. {
  483. int j;
  484. int x;
  485. for (j = 0; j < ptdata.tzi[tz].nr_trip_pts; j++) {
  486. x = ptdata.tzi[tz].tp[j].temp / 1000;
  487. mvwprintw(thermal_data_window, y + 0, x + TDATA_LEFT,
  488. "%c%d", trip_type_to_char(ptdata.tzi[tz].tp[j].type),
  489. x);
  490. syslog(LOG_INFO, "%s:tz %d tp %d temp = %lu\n", __func__,
  491. tz, j, ptdata.tzi[tz].tp[j].temp);
  492. }
  493. }
  494. const char data_win_title[] = " THERMAL DATA ";
  495. void show_data_w(void)
  496. {
  497. int i;
  498. if (tui_disabled || !thermal_data_window)
  499. return;
  500. werase(thermal_data_window);
  501. wattron(thermal_data_window, A_BOLD);
  502. mvwprintw(thermal_data_window, 0, maxx/2 - sizeof(data_win_title),
  503. data_win_title);
  504. wattroff(thermal_data_window, A_BOLD);
  505. /* draw a line as ruler */
  506. for (i = 10; i < MAX_DISP_TEMP; i += 10)
  507. mvwprintw(thermal_data_window, 1, i+TDATA_LEFT, "%2d", i);
  508. for (i = 0; i < ptdata.nr_tz_sensor; i++) {
  509. int temp = trec[cur_thermal_record].temp[i] / 1000;
  510. int y = 0;
  511. y = i * NR_LINES_TZDATA + 2;
  512. /* y at tz temp data line */
  513. mvwprintw(thermal_data_window, y, 1, "%6.6s%2d:[%3d][",
  514. ptdata.tzi[i].type,
  515. ptdata.tzi[i].instance, temp);
  516. draw_hbar(thermal_data_window, y, TDATA_LEFT, temp, ACS_RARROW,
  517. true);
  518. draw_tp_line(i, y);
  519. }
  520. wborder(thermal_data_window, 0, 0, 0, 0, 0, 0, 0, 0);
  521. wrefresh(thermal_data_window);
  522. }
  523. const char tz_title[] = "THERMAL ZONES(SENSORS)";
  524. void show_sensors_w(void)
  525. {
  526. int i, j;
  527. char buffer[512];
  528. if (tui_disabled || !tz_sensor_window)
  529. return;
  530. werase(tz_sensor_window);
  531. memset(buffer, 0, sizeof(buffer));
  532. wattron(tz_sensor_window, A_BOLD);
  533. mvwprintw(tz_sensor_window, 1, 1, "Thermal Zones:");
  534. wattroff(tz_sensor_window, A_BOLD);
  535. mvwprintw(tz_sensor_window, 1, TZ_LEFT_ALIGN, "%s", buffer);
  536. /* fill trip points for each tzone */
  537. wattron(tz_sensor_window, A_BOLD);
  538. mvwprintw(tz_sensor_window, 2, 1, "Trip Points:");
  539. wattroff(tz_sensor_window, A_BOLD);
  540. /* draw trip point from low to high for each tz */
  541. for (i = 0; i < ptdata.nr_tz_sensor; i++) {
  542. int inst = ptdata.tzi[i].instance;
  543. mvwprintw(tz_sensor_window, 1,
  544. TZ_LEFT_ALIGN+TZONE_RECORD_SIZE * inst, "%.9s%02d",
  545. ptdata.tzi[i].type, ptdata.tzi[i].instance);
  546. for (j = ptdata.tzi[i].nr_trip_pts - 1; j >= 0; j--) {
  547. /* loop through all trip points */
  548. char type;
  549. int tp_pos;
  550. /* reverse the order here since trips are sorted
  551. * in ascending order in terms of temperature.
  552. */
  553. tp_pos = ptdata.tzi[i].nr_trip_pts - j - 1;
  554. type = trip_type_to_char(ptdata.tzi[i].tp[j].type);
  555. mvwaddch(tz_sensor_window, 2,
  556. inst * TZONE_RECORD_SIZE + TZ_LEFT_ALIGN +
  557. tp_pos, type);
  558. syslog(LOG_DEBUG, "draw tz %d tp %d ch:%c\n",
  559. inst, j, type);
  560. }
  561. }
  562. wborder(tz_sensor_window, 0, 0, 0, 0, 0, 0, 0, 0);
  563. wattron(tz_sensor_window, A_BOLD);
  564. mvwprintw(tz_sensor_window, 0, maxx/2 - sizeof(tz_title), tz_title);
  565. wattroff(tz_sensor_window, A_BOLD);
  566. wrefresh(tz_sensor_window);
  567. }
  568. void disable_tui(void)
  569. {
  570. tui_disabled = 1;
  571. }