194f69966SJacob Pan /* 294f69966SJacob Pan * tui.c ncurses text user interface for TMON program 394f69966SJacob Pan * 494f69966SJacob Pan * Copyright (C) 2013 Intel Corporation. All rights reserved. 594f69966SJacob Pan * 694f69966SJacob Pan * This program is free software; you can redistribute it and/or 794f69966SJacob Pan * modify it under the terms of the GNU General Public License version 894f69966SJacob Pan * 2 or later as published by the Free Software Foundation. 994f69966SJacob Pan * 1094f69966SJacob Pan * This program is distributed in the hope that it will be useful, 1194f69966SJacob Pan * but WITHOUT ANY WARRANTY; without even the implied warranty of 1294f69966SJacob Pan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1394f69966SJacob Pan * GNU General Public License for more details. 1494f69966SJacob Pan * 1594f69966SJacob Pan * Author: Jacob Pan <jacob.jun.pan@linux.intel.com> 1694f69966SJacob Pan * 1794f69966SJacob Pan */ 1894f69966SJacob Pan 1994f69966SJacob Pan #include <unistd.h> 2094f69966SJacob Pan #include <stdio.h> 2194f69966SJacob Pan #include <stdlib.h> 2294f69966SJacob Pan #include <string.h> 2394f69966SJacob Pan #include <stdint.h> 2494f69966SJacob Pan #include <ncurses.h> 2594f69966SJacob Pan #include <time.h> 2694f69966SJacob Pan #include <syslog.h> 2794f69966SJacob Pan #include <panel.h> 2894f69966SJacob Pan #include <pthread.h> 2994f69966SJacob Pan #include <signal.h> 3094f69966SJacob Pan 3194f69966SJacob Pan #include "tmon.h" 3294f69966SJacob Pan 33a90b6b00SBrian Norris #define min(x, y) ({ \ 34a90b6b00SBrian Norris typeof(x) _min1 = (x); \ 35a90b6b00SBrian Norris typeof(y) _min2 = (y); \ 36a90b6b00SBrian Norris (void) (&_min1 == &_min2); \ 37a90b6b00SBrian Norris _min1 < _min2 ? _min1 : _min2; }) 38a90b6b00SBrian Norris 39a90b6b00SBrian Norris #define max(x, y) ({ \ 40a90b6b00SBrian Norris typeof(x) _max1 = (x); \ 41a90b6b00SBrian Norris typeof(y) _max2 = (y); \ 42a90b6b00SBrian Norris (void) (&_max1 == &_max2); \ 43a90b6b00SBrian Norris _max1 > _max2 ? _max1 : _max2; }) 44a90b6b00SBrian Norris 4594f69966SJacob Pan static PANEL *data_panel; 4694f69966SJacob Pan static PANEL *dialogue_panel; 4794f69966SJacob Pan static PANEL *top; 4894f69966SJacob Pan 4994f69966SJacob Pan static WINDOW *title_bar_window; 5094f69966SJacob Pan static WINDOW *tz_sensor_window; 5194f69966SJacob Pan static WINDOW *cooling_device_window; 5294f69966SJacob Pan static WINDOW *control_window; 5394f69966SJacob Pan static WINDOW *status_bar_window; 5494f69966SJacob Pan static WINDOW *thermal_data_window; 5594f69966SJacob Pan static WINDOW *dialogue_window; 5694f69966SJacob Pan 5794f69966SJacob Pan char status_bar_slots[10][40]; 5894f69966SJacob Pan static void draw_hbar(WINDOW *win, int y, int start, int len, 5994f69966SJacob Pan unsigned long pattern, bool end); 6094f69966SJacob Pan 6194f69966SJacob Pan static int maxx, maxy; 6294f69966SJacob Pan static int maxwidth = 200; 6394f69966SJacob Pan 6494f69966SJacob Pan #define TITLE_BAR_HIGHT 1 6594f69966SJacob Pan #define SENSOR_WIN_HIGHT 4 /* one row for tz name, one for trip points */ 6694f69966SJacob Pan 6794f69966SJacob Pan 6894f69966SJacob Pan /* daemon mode flag (set by startup parameter -d) */ 6994f69966SJacob Pan static int tui_disabled; 7094f69966SJacob Pan 7194f69966SJacob Pan static void close_panel(PANEL *p) 7294f69966SJacob Pan { 7394f69966SJacob Pan if (p) { 7494f69966SJacob Pan del_panel(p); 7594f69966SJacob Pan p = NULL; 7694f69966SJacob Pan } 7794f69966SJacob Pan } 7894f69966SJacob Pan 7994f69966SJacob Pan static void close_window(WINDOW *win) 8094f69966SJacob Pan { 8194f69966SJacob Pan if (win) { 8294f69966SJacob Pan delwin(win); 8394f69966SJacob Pan win = NULL; 8494f69966SJacob Pan } 8594f69966SJacob Pan } 8694f69966SJacob Pan 8794f69966SJacob Pan void close_windows(void) 8894f69966SJacob Pan { 8994f69966SJacob Pan if (tui_disabled) 9094f69966SJacob Pan return; 9194f69966SJacob Pan /* must delete panels before their attached windows */ 9294f69966SJacob Pan if (dialogue_window) 9394f69966SJacob Pan close_panel(dialogue_panel); 9494f69966SJacob Pan if (cooling_device_window) 9594f69966SJacob Pan close_panel(data_panel); 9694f69966SJacob Pan 9794f69966SJacob Pan close_window(title_bar_window); 9894f69966SJacob Pan close_window(tz_sensor_window); 9994f69966SJacob Pan close_window(status_bar_window); 10094f69966SJacob Pan close_window(cooling_device_window); 10194f69966SJacob Pan close_window(control_window); 10294f69966SJacob Pan close_window(thermal_data_window); 10394f69966SJacob Pan close_window(dialogue_window); 10494f69966SJacob Pan 10594f69966SJacob Pan } 10694f69966SJacob Pan 10794f69966SJacob Pan void write_status_bar(int x, char *line) 10894f69966SJacob Pan { 10994f69966SJacob Pan mvwprintw(status_bar_window, 0, x, "%s", line); 11094f69966SJacob Pan wrefresh(status_bar_window); 11194f69966SJacob Pan } 11294f69966SJacob Pan 11394f69966SJacob Pan void setup_windows(void) 11494f69966SJacob Pan { 11594f69966SJacob Pan int y_begin = 1; 11694f69966SJacob Pan 11794f69966SJacob Pan if (tui_disabled) 11894f69966SJacob Pan return; 11994f69966SJacob Pan 12094f69966SJacob Pan getmaxyx(stdscr, maxy, maxx); 12194f69966SJacob Pan resizeterm(maxy, maxx); 12294f69966SJacob Pan 12394f69966SJacob Pan title_bar_window = subwin(stdscr, TITLE_BAR_HIGHT, maxx, 0, 0); 12494f69966SJacob Pan y_begin += TITLE_BAR_HIGHT; 12594f69966SJacob Pan 12694f69966SJacob Pan tz_sensor_window = subwin(stdscr, SENSOR_WIN_HIGHT, maxx, y_begin, 0); 12794f69966SJacob Pan y_begin += SENSOR_WIN_HIGHT; 12894f69966SJacob Pan 12994f69966SJacob Pan cooling_device_window = subwin(stdscr, ptdata.nr_cooling_dev + 3, maxx, 13094f69966SJacob Pan y_begin, 0); 13194f69966SJacob Pan y_begin += ptdata.nr_cooling_dev + 3; /* 2 lines for border */ 13294f69966SJacob Pan /* two lines to show borders, one line per tz show trip point position 13394f69966SJacob Pan * and value. 13494f69966SJacob Pan * dialogue window is a pop-up, when needed it lays on top of cdev win 13594f69966SJacob Pan */ 13694f69966SJacob Pan 13794f69966SJacob Pan dialogue_window = subwin(stdscr, ptdata.nr_cooling_dev+5, maxx-50, 13894f69966SJacob Pan DIAG_Y, DIAG_X); 13994f69966SJacob Pan 14094f69966SJacob Pan thermal_data_window = subwin(stdscr, ptdata.nr_tz_sensor * 14194f69966SJacob Pan NR_LINES_TZDATA + 3, maxx, y_begin, 0); 14294f69966SJacob Pan y_begin += ptdata.nr_tz_sensor * NR_LINES_TZDATA + 3; 14394f69966SJacob Pan control_window = subwin(stdscr, 4, maxx, y_begin, 0); 14494f69966SJacob Pan 14594f69966SJacob Pan scrollok(cooling_device_window, TRUE); 14694f69966SJacob Pan maxwidth = maxx - 18; 14794f69966SJacob Pan status_bar_window = subwin(stdscr, 1, maxx, maxy-1, 0); 14894f69966SJacob Pan 14994f69966SJacob Pan strcpy(status_bar_slots[0], " Ctrl-c - Quit "); 15094f69966SJacob Pan strcpy(status_bar_slots[1], " TAB - Tuning "); 15194f69966SJacob Pan wmove(status_bar_window, 1, 30); 15294f69966SJacob Pan 15394f69966SJacob Pan /* prepare panels for dialogue, if panel already created then we must 15494f69966SJacob Pan * be doing resizing, so just replace windows with new ones, old ones 15594f69966SJacob Pan * should have been deleted by close_window 15694f69966SJacob Pan */ 15794f69966SJacob Pan data_panel = new_panel(cooling_device_window); 15894f69966SJacob Pan if (!data_panel) 15994f69966SJacob Pan syslog(LOG_DEBUG, "No data panel\n"); 16094f69966SJacob Pan else { 16194f69966SJacob Pan if (dialogue_window) { 16294f69966SJacob Pan dialogue_panel = new_panel(dialogue_window); 16394f69966SJacob Pan if (!dialogue_panel) 16494f69966SJacob Pan syslog(LOG_DEBUG, "No dialogue panel\n"); 16594f69966SJacob Pan else { 16694f69966SJacob Pan /* Set up the user pointer to the next panel*/ 16794f69966SJacob Pan set_panel_userptr(data_panel, dialogue_panel); 16894f69966SJacob Pan set_panel_userptr(dialogue_panel, data_panel); 16994f69966SJacob Pan top = data_panel; 17094f69966SJacob Pan } 17194f69966SJacob Pan } else 17294f69966SJacob Pan syslog(LOG_INFO, "no dialogue win, term too small\n"); 17394f69966SJacob Pan } 17494f69966SJacob Pan doupdate(); 17594f69966SJacob Pan werase(stdscr); 17694f69966SJacob Pan refresh(); 17794f69966SJacob Pan } 17894f69966SJacob Pan 17994f69966SJacob Pan void resize_handler(int sig) 18094f69966SJacob Pan { 18194f69966SJacob Pan /* start over when term gets resized, but first we clean up */ 18294f69966SJacob Pan close_windows(); 18394f69966SJacob Pan endwin(); 18494f69966SJacob Pan refresh(); 18594f69966SJacob Pan clear(); 18694f69966SJacob Pan getmaxyx(stdscr, maxy, maxx); /* get the new screen size */ 18794f69966SJacob Pan setup_windows(); 18894f69966SJacob Pan /* rate limit */ 18994f69966SJacob Pan sleep(1); 19094f69966SJacob Pan syslog(LOG_DEBUG, "SIG %d, term resized to %d x %d\n", 19194f69966SJacob Pan sig, maxy, maxx); 19294f69966SJacob Pan signal(SIGWINCH, resize_handler); 19394f69966SJacob Pan } 19494f69966SJacob Pan 19594f69966SJacob Pan const char cdev_title[] = " COOLING DEVICES "; 19694f69966SJacob Pan void show_cooling_device(void) 19794f69966SJacob Pan { 19894f69966SJacob Pan int i, j, x, y = 0; 19994f69966SJacob Pan 20094f69966SJacob Pan if (tui_disabled || !cooling_device_window) 20194f69966SJacob Pan return; 20294f69966SJacob Pan 20394f69966SJacob Pan werase(cooling_device_window); 20494f69966SJacob Pan wattron(cooling_device_window, A_BOLD); 20594f69966SJacob Pan mvwprintw(cooling_device_window, 1, 1, 20694f69966SJacob Pan "ID Cooling Dev Cur Max Thermal Zone Binding"); 20794f69966SJacob Pan wattroff(cooling_device_window, A_BOLD); 20894f69966SJacob Pan for (j = 0; j < ptdata.nr_cooling_dev; j++) { 20994f69966SJacob Pan /* draw cooling device list on the left in the order of 21094f69966SJacob Pan * cooling device instances. skip unused idr. 21194f69966SJacob Pan */ 21294f69966SJacob Pan mvwprintw(cooling_device_window, j + 2, 1, 21394f69966SJacob Pan "%02d %12.12s%6d %6d", 21494f69966SJacob Pan ptdata.cdi[j].instance, 21594f69966SJacob Pan ptdata.cdi[j].type, 21694f69966SJacob Pan ptdata.cdi[j].cur_state, 21794f69966SJacob Pan ptdata.cdi[j].max_state); 21894f69966SJacob Pan } 21994f69966SJacob Pan 22094f69966SJacob Pan /* show cdev binding, y is the global cooling device instance */ 22194f69966SJacob Pan for (i = 0; i < ptdata.nr_tz_sensor; i++) { 22294f69966SJacob Pan int tz_inst = ptdata.tzi[i].instance; 22394f69966SJacob Pan for (j = 0; j < ptdata.nr_cooling_dev; j++) { 22494f69966SJacob Pan int cdev_inst; 22594f69966SJacob Pan y = j; 22694f69966SJacob Pan x = tz_inst * TZONE_RECORD_SIZE + TZ_LEFT_ALIGN; 22794f69966SJacob Pan 22894f69966SJacob Pan draw_hbar(cooling_device_window, y+2, x, 22994f69966SJacob Pan TZONE_RECORD_SIZE-1, ACS_VLINE, false); 23094f69966SJacob Pan 23194f69966SJacob Pan /* draw a column of spaces to separate thermal zones */ 23294f69966SJacob Pan mvwprintw(cooling_device_window, y+2, x-1, " "); 23394f69966SJacob Pan if (ptdata.tzi[i].cdev_binding) { 23494f69966SJacob Pan cdev_inst = ptdata.cdi[j].instance; 23594f69966SJacob Pan unsigned long trip_binding = 23694f69966SJacob Pan ptdata.tzi[i].trip_binding[cdev_inst]; 23794f69966SJacob Pan int k = 0; /* per zone trip point id that 23894f69966SJacob Pan * binded to this cdev, one to 23994f69966SJacob Pan * many possible based on the 24094f69966SJacob Pan * binding bitmask. 24194f69966SJacob Pan */ 24294f69966SJacob Pan syslog(LOG_DEBUG, 24394f69966SJacob Pan "bind tz%d cdev%d tp%lx %d cdev%lx\n", 24494f69966SJacob Pan i, j, trip_binding, y, 24594f69966SJacob Pan ptdata.tzi[i].cdev_binding); 24694f69966SJacob Pan /* draw each trip binding for the cdev */ 24794f69966SJacob Pan while (trip_binding >>= 1) { 24894f69966SJacob Pan k++; 24994f69966SJacob Pan if (!(trip_binding & 1)) 25094f69966SJacob Pan continue; 25194f69966SJacob Pan /* draw '*' to show binding */ 25294f69966SJacob Pan mvwprintw(cooling_device_window, 25394f69966SJacob Pan y + 2, 25494f69966SJacob Pan x + ptdata.tzi[i].nr_trip_pts - 25594f69966SJacob Pan k - 1, "*"); 25694f69966SJacob Pan } 25794f69966SJacob Pan } 25894f69966SJacob Pan } 25994f69966SJacob Pan } 26094f69966SJacob Pan /* draw border after data so that border will not be messed up 26194f69966SJacob Pan * even there is not enough space for all the data to be shown 26294f69966SJacob Pan */ 26394f69966SJacob Pan wborder(cooling_device_window, 0, 0, 0, 0, 0, 0, 0, 0); 26494f69966SJacob Pan wattron(cooling_device_window, A_BOLD); 26594f69966SJacob Pan mvwprintw(cooling_device_window, 0, maxx/2 - sizeof(cdev_title), 26694f69966SJacob Pan cdev_title); 26794f69966SJacob Pan wattroff(cooling_device_window, A_BOLD); 26894f69966SJacob Pan 26994f69966SJacob Pan wrefresh(cooling_device_window); 27094f69966SJacob Pan } 27194f69966SJacob Pan 27294f69966SJacob Pan const char DIAG_TITLE[] = "[ TUNABLES ]"; 27394f69966SJacob Pan #define DIAG_DEV_ROWS 5 27494f69966SJacob Pan void show_dialogue(void) 27594f69966SJacob Pan { 27694f69966SJacob Pan int j, x = 0, y = 0; 2770e7b766dSBrian Norris int rows, cols; 27894f69966SJacob Pan WINDOW *w = dialogue_window; 27994f69966SJacob Pan 28094f69966SJacob Pan if (tui_disabled || !w) 28194f69966SJacob Pan return; 28294f69966SJacob Pan 2830e7b766dSBrian Norris getmaxyx(w, rows, cols); 2840e7b766dSBrian Norris 28594f69966SJacob Pan werase(w); 28694f69966SJacob Pan box(w, 0, 0); 28794f69966SJacob Pan mvwprintw(w, 0, maxx/4, DIAG_TITLE); 28894f69966SJacob Pan /* list all the available tunables */ 28994f69966SJacob Pan for (j = 0; j <= ptdata.nr_cooling_dev; j++) { 29094f69966SJacob Pan y = j % DIAG_DEV_ROWS; 29194f69966SJacob Pan if (y == 0 && j != 0) 29294f69966SJacob Pan x += 20; 29394f69966SJacob Pan if (j == ptdata.nr_cooling_dev) 29494f69966SJacob Pan /* save last choice for target temp */ 29594f69966SJacob Pan mvwprintw(w, y+1, x+1, "%C-%.12s", 'A'+j, "Set Temp"); 29694f69966SJacob Pan else 29794f69966SJacob Pan mvwprintw(w, y+1, x+1, "%C-%.10s-%2d", 'A'+j, 29894f69966SJacob Pan ptdata.cdi[j].type, ptdata.cdi[j].instance); 29994f69966SJacob Pan } 30094f69966SJacob Pan wattron(w, A_BOLD); 30194f69966SJacob Pan mvwprintw(w, DIAG_DEV_ROWS+1, 1, "Enter Choice [A-Z]?"); 30294f69966SJacob Pan wattroff(w, A_BOLD); 3030e7b766dSBrian Norris /* print legend at the bottom line */ 3040e7b766dSBrian Norris mvwprintw(w, rows - 2, 1, 30594f69966SJacob Pan "Legend: A=Active, P=Passive, C=Critical"); 30694f69966SJacob Pan 30794f69966SJacob Pan wrefresh(dialogue_window); 30894f69966SJacob Pan } 30994f69966SJacob Pan 31094f69966SJacob Pan void write_dialogue_win(char *buf, int y, int x) 31194f69966SJacob Pan { 31294f69966SJacob Pan WINDOW *w = dialogue_window; 31394f69966SJacob Pan 31494f69966SJacob Pan mvwprintw(w, y, x, "%s", buf); 31594f69966SJacob Pan } 31694f69966SJacob Pan 31794f69966SJacob Pan const char control_title[] = " CONTROLS "; 31894f69966SJacob Pan void show_control_w(void) 31994f69966SJacob Pan { 32094f69966SJacob Pan unsigned long state; 32194f69966SJacob Pan 32294f69966SJacob Pan get_ctrl_state(&state); 32394f69966SJacob Pan 32494f69966SJacob Pan if (tui_disabled || !control_window) 32594f69966SJacob Pan return; 32694f69966SJacob Pan 32794f69966SJacob Pan werase(control_window); 32894f69966SJacob Pan mvwprintw(control_window, 1, 1, 32994f69966SJacob Pan "PID gain: kp=%2.2f ki=%2.2f kd=%2.2f Output %2.2f", 33094f69966SJacob Pan p_param.kp, p_param.ki, p_param.kd, p_param.y_k); 33194f69966SJacob Pan 33294f69966SJacob Pan mvwprintw(control_window, 2, 1, 33394f69966SJacob Pan "Target Temp: %2.1fC, Zone: %d, Control Device: %.12s", 33494f69966SJacob Pan p_param.t_target, target_thermal_zone, ctrl_cdev); 33594f69966SJacob Pan 33694f69966SJacob Pan /* draw border last such that everything is within boundary */ 33794f69966SJacob Pan wborder(control_window, 0, 0, 0, 0, 0, 0, 0, 0); 33894f69966SJacob Pan wattron(control_window, A_BOLD); 33994f69966SJacob Pan mvwprintw(control_window, 0, maxx/2 - sizeof(control_title), 34094f69966SJacob Pan control_title); 34194f69966SJacob Pan wattroff(control_window, A_BOLD); 34294f69966SJacob Pan 34394f69966SJacob Pan wrefresh(control_window); 34494f69966SJacob Pan } 34594f69966SJacob Pan 34694f69966SJacob Pan void initialize_curses(void) 34794f69966SJacob Pan { 34894f69966SJacob Pan if (tui_disabled) 34994f69966SJacob Pan return; 35094f69966SJacob Pan 35194f69966SJacob Pan initscr(); 35294f69966SJacob Pan start_color(); 35394f69966SJacob Pan keypad(stdscr, TRUE); /* enable keyboard mapping */ 35494f69966SJacob Pan nonl(); /* tell curses not to do NL->CR/NL on output */ 35594f69966SJacob Pan cbreak(); /* take input chars one at a time */ 35694f69966SJacob Pan noecho(); /* dont echo input */ 35794f69966SJacob Pan curs_set(0); /* turn off cursor */ 35894f69966SJacob Pan use_default_colors(); 35994f69966SJacob Pan 36094f69966SJacob Pan init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK); 36194f69966SJacob Pan init_pair(PT_COLOR_HEADER_BAR, COLOR_BLACK, COLOR_WHITE); 36294f69966SJacob Pan init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED); 36394f69966SJacob Pan init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED); 36494f69966SJacob Pan init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW); 36594f69966SJacob Pan init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN); 36694f69966SJacob Pan init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE); 36794f69966SJacob Pan init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK); 36894f69966SJacob Pan 36994f69966SJacob Pan } 37094f69966SJacob Pan 37194f69966SJacob Pan void show_title_bar(void) 37294f69966SJacob Pan { 37394f69966SJacob Pan int i; 37494f69966SJacob Pan int x = 0; 37594f69966SJacob Pan 37694f69966SJacob Pan if (tui_disabled || !title_bar_window) 37794f69966SJacob Pan return; 37894f69966SJacob Pan 37994f69966SJacob Pan wattrset(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR)); 38094f69966SJacob Pan wbkgd(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR)); 38194f69966SJacob Pan werase(title_bar_window); 38294f69966SJacob Pan 38394f69966SJacob Pan mvwprintw(title_bar_window, 0, 0, 38494f69966SJacob Pan " TMON v%s", VERSION); 38594f69966SJacob Pan 38694f69966SJacob Pan wrefresh(title_bar_window); 38794f69966SJacob Pan 38894f69966SJacob Pan werase(status_bar_window); 38994f69966SJacob Pan 39094f69966SJacob Pan for (i = 0; i < 10; i++) { 39194f69966SJacob Pan if (strlen(status_bar_slots[i]) == 0) 39294f69966SJacob Pan continue; 39394f69966SJacob Pan wattron(status_bar_window, A_REVERSE); 39494f69966SJacob Pan mvwprintw(status_bar_window, 0, x, "%s", status_bar_slots[i]); 39594f69966SJacob Pan wattroff(status_bar_window, A_REVERSE); 39694f69966SJacob Pan x += strlen(status_bar_slots[i]) + 1; 39794f69966SJacob Pan } 39894f69966SJacob Pan wrefresh(status_bar_window); 39994f69966SJacob Pan } 40094f69966SJacob Pan 40194f69966SJacob Pan static void handle_input_val(int ch) 40294f69966SJacob Pan { 40394f69966SJacob Pan char buf[32]; 40494f69966SJacob Pan int val; 40594f69966SJacob Pan char path[256]; 40694f69966SJacob Pan WINDOW *w = dialogue_window; 40794f69966SJacob Pan 40894f69966SJacob Pan echo(); 40994f69966SJacob Pan keypad(w, TRUE); 41094f69966SJacob Pan wgetnstr(w, buf, 31); 41194f69966SJacob Pan val = atoi(buf); 41294f69966SJacob Pan 41394f69966SJacob Pan if (ch == ptdata.nr_cooling_dev) { 41494f69966SJacob Pan snprintf(buf, 31, "Invalid Temp %d! %d-%d", val, 41594f69966SJacob Pan MIN_CTRL_TEMP, MAX_CTRL_TEMP); 41694f69966SJacob Pan if (val < MIN_CTRL_TEMP || val > MAX_CTRL_TEMP) 41794f69966SJacob Pan write_status_bar(40, buf); 41894f69966SJacob Pan else { 41994f69966SJacob Pan p_param.t_target = val; 42094f69966SJacob Pan snprintf(buf, 31, "Set New Target Temp %d", val); 42194f69966SJacob Pan write_status_bar(40, buf); 42294f69966SJacob Pan } 42394f69966SJacob Pan } else { 42494f69966SJacob Pan snprintf(path, 256, "%s/%s%d", THERMAL_SYSFS, 42594f69966SJacob Pan CDEV, ptdata.cdi[ch].instance); 42694f69966SJacob Pan sysfs_set_ulong(path, "cur_state", val); 42794f69966SJacob Pan } 42894f69966SJacob Pan noecho(); 42994f69966SJacob Pan dialogue_on = 0; 43094f69966SJacob Pan show_data_w(); 43194f69966SJacob Pan show_control_w(); 43294f69966SJacob Pan 43394f69966SJacob Pan top = (PANEL *)panel_userptr(top); 43494f69966SJacob Pan top_panel(top); 43594f69966SJacob Pan } 43694f69966SJacob Pan 43794f69966SJacob Pan static void handle_input_choice(int ch) 43894f69966SJacob Pan { 43994f69966SJacob Pan char buf[48]; 44094f69966SJacob Pan int base = 0; 44194f69966SJacob Pan int cdev_id = 0; 44294f69966SJacob Pan 44394f69966SJacob Pan if ((ch >= 'A' && ch <= 'A' + ptdata.nr_cooling_dev) || 44494f69966SJacob Pan (ch >= 'a' && ch <= 'a' + ptdata.nr_cooling_dev)) { 44594f69966SJacob Pan base = (ch < 'a') ? 'A' : 'a'; 44694f69966SJacob Pan cdev_id = ch - base; 44794f69966SJacob Pan if (ptdata.nr_cooling_dev == cdev_id) 44894f69966SJacob Pan snprintf(buf, sizeof(buf), "New Target Temp:"); 44994f69966SJacob Pan else 45094f69966SJacob Pan snprintf(buf, sizeof(buf), "New Value for %.10s-%2d: ", 45194f69966SJacob Pan ptdata.cdi[cdev_id].type, 45294f69966SJacob Pan ptdata.cdi[cdev_id].instance); 45394f69966SJacob Pan write_dialogue_win(buf, DIAG_DEV_ROWS+2, 2); 45494f69966SJacob Pan handle_input_val(cdev_id); 45594f69966SJacob Pan } else { 45694f69966SJacob Pan snprintf(buf, sizeof(buf), "Invalid selection %d", ch); 45794f69966SJacob Pan write_dialogue_win(buf, 8, 2); 45894f69966SJacob Pan } 45994f69966SJacob Pan } 46094f69966SJacob Pan 46194f69966SJacob Pan void *handle_tui_events(void *arg) 46294f69966SJacob Pan { 46394f69966SJacob Pan int ch; 46494f69966SJacob Pan 46594f69966SJacob Pan keypad(cooling_device_window, TRUE); 46694f69966SJacob Pan while ((ch = wgetch(cooling_device_window)) != EOF) { 46794f69966SJacob Pan if (tmon_exit) 46894f69966SJacob Pan break; 46994f69966SJacob Pan /* when term size is too small, no dialogue panels are set. 47094f69966SJacob Pan * we need to filter out such cases. 47194f69966SJacob Pan */ 47294f69966SJacob Pan if (!data_panel || !dialogue_panel || 47394f69966SJacob Pan !cooling_device_window || 47494f69966SJacob Pan !dialogue_window) { 47594f69966SJacob Pan 47694f69966SJacob Pan continue; 47794f69966SJacob Pan } 47894f69966SJacob Pan pthread_mutex_lock(&input_lock); 47994f69966SJacob Pan if (dialogue_on) { 48094f69966SJacob Pan handle_input_choice(ch); 48194f69966SJacob Pan /* top panel filter */ 48294f69966SJacob Pan if (ch == 'q' || ch == 'Q') 48394f69966SJacob Pan ch = 0; 48494f69966SJacob Pan } 48594f69966SJacob Pan switch (ch) { 48694f69966SJacob Pan case KEY_LEFT: 48794f69966SJacob Pan box(cooling_device_window, 10, 0); 48894f69966SJacob Pan break; 48994f69966SJacob Pan case 9: /* TAB */ 49094f69966SJacob Pan top = (PANEL *)panel_userptr(top); 49194f69966SJacob Pan top_panel(top); 49294f69966SJacob Pan if (top == dialogue_panel) { 49394f69966SJacob Pan dialogue_on = 1; 49494f69966SJacob Pan show_dialogue(); 49594f69966SJacob Pan } else { 49694f69966SJacob Pan dialogue_on = 0; 49794f69966SJacob Pan /* force refresh */ 49894f69966SJacob Pan show_data_w(); 49994f69966SJacob Pan show_control_w(); 50094f69966SJacob Pan } 50194f69966SJacob Pan break; 50294f69966SJacob Pan case 'q': 50394f69966SJacob Pan case 'Q': 50494f69966SJacob Pan tmon_exit = 1; 50594f69966SJacob Pan break; 50694f69966SJacob Pan } 50794f69966SJacob Pan update_panels(); 50894f69966SJacob Pan doupdate(); 50994f69966SJacob Pan pthread_mutex_unlock(&input_lock); 51094f69966SJacob Pan } 51194f69966SJacob Pan 51294f69966SJacob Pan if (arg) 51394f69966SJacob Pan *(int *)arg = 0; /* make gcc happy */ 51494f69966SJacob Pan 51594f69966SJacob Pan return NULL; 51694f69966SJacob Pan } 51794f69966SJacob Pan 51894f69966SJacob Pan /* draw a horizontal bar in given pattern */ 51994f69966SJacob Pan static void draw_hbar(WINDOW *win, int y, int start, int len, unsigned long ptn, 52094f69966SJacob Pan bool end) 52194f69966SJacob Pan { 52294f69966SJacob Pan mvwaddch(win, y, start, ptn); 52394f69966SJacob Pan whline(win, ptn, len); 52494f69966SJacob Pan if (end) 52594f69966SJacob Pan mvwaddch(win, y, MAX_DISP_TEMP+TDATA_LEFT, ']'); 52694f69966SJacob Pan } 52794f69966SJacob Pan 52894f69966SJacob Pan static char trip_type_to_char(int type) 52994f69966SJacob Pan { 53094f69966SJacob Pan switch (type) { 53194f69966SJacob Pan case THERMAL_TRIP_CRITICAL: return 'C'; 53294f69966SJacob Pan case THERMAL_TRIP_HOT: return 'H'; 53394f69966SJacob Pan case THERMAL_TRIP_PASSIVE: return 'P'; 53494f69966SJacob Pan case THERMAL_TRIP_ACTIVE: return 'A'; 53594f69966SJacob Pan default: 53694f69966SJacob Pan return '?'; 53794f69966SJacob Pan } 53894f69966SJacob Pan } 53994f69966SJacob Pan 54094f69966SJacob Pan /* fill a string with trip point type and value in one line 54194f69966SJacob Pan * e.g. P(56) C(106) 54294f69966SJacob Pan * maintain the distance one degree per char 54394f69966SJacob Pan */ 54494f69966SJacob Pan static void draw_tp_line(int tz, int y) 54594f69966SJacob Pan { 54694f69966SJacob Pan int j; 54794f69966SJacob Pan int x; 54894f69966SJacob Pan 54994f69966SJacob Pan for (j = 0; j < ptdata.tzi[tz].nr_trip_pts; j++) { 55094f69966SJacob Pan x = ptdata.tzi[tz].tp[j].temp / 1000; 55194f69966SJacob Pan mvwprintw(thermal_data_window, y + 0, x + TDATA_LEFT, 55294f69966SJacob Pan "%c%d", trip_type_to_char(ptdata.tzi[tz].tp[j].type), 55394f69966SJacob Pan x); 55494f69966SJacob Pan syslog(LOG_INFO, "%s:tz %d tp %d temp = %lu\n", __func__, 55594f69966SJacob Pan tz, j, ptdata.tzi[tz].tp[j].temp); 55694f69966SJacob Pan } 55794f69966SJacob Pan } 55894f69966SJacob Pan 55994f69966SJacob Pan const char data_win_title[] = " THERMAL DATA "; 56094f69966SJacob Pan void show_data_w(void) 56194f69966SJacob Pan { 56294f69966SJacob Pan int i; 56394f69966SJacob Pan 56494f69966SJacob Pan 56594f69966SJacob Pan if (tui_disabled || !thermal_data_window) 56694f69966SJacob Pan return; 56794f69966SJacob Pan 56894f69966SJacob Pan werase(thermal_data_window); 56994f69966SJacob Pan wattron(thermal_data_window, A_BOLD); 57094f69966SJacob Pan mvwprintw(thermal_data_window, 0, maxx/2 - sizeof(data_win_title), 57194f69966SJacob Pan data_win_title); 57294f69966SJacob Pan wattroff(thermal_data_window, A_BOLD); 57394f69966SJacob Pan /* draw a line as ruler */ 57494f69966SJacob Pan for (i = 10; i < MAX_DISP_TEMP; i += 10) 57594f69966SJacob Pan mvwprintw(thermal_data_window, 1, i+TDATA_LEFT, "%2d", i); 57694f69966SJacob Pan 57794f69966SJacob Pan for (i = 0; i < ptdata.nr_tz_sensor; i++) { 57894f69966SJacob Pan int temp = trec[cur_thermal_record].temp[i] / 1000; 57994f69966SJacob Pan int y = 0; 58094f69966SJacob Pan 58194f69966SJacob Pan y = i * NR_LINES_TZDATA + 2; 58294f69966SJacob Pan /* y at tz temp data line */ 58394f69966SJacob Pan mvwprintw(thermal_data_window, y, 1, "%6.6s%2d:[%3d][", 58494f69966SJacob Pan ptdata.tzi[i].type, 58594f69966SJacob Pan ptdata.tzi[i].instance, temp); 58694f69966SJacob Pan draw_hbar(thermal_data_window, y, TDATA_LEFT, temp, ACS_RARROW, 58794f69966SJacob Pan true); 58894f69966SJacob Pan draw_tp_line(i, y); 58994f69966SJacob Pan } 59094f69966SJacob Pan wborder(thermal_data_window, 0, 0, 0, 0, 0, 0, 0, 0); 59194f69966SJacob Pan wrefresh(thermal_data_window); 59294f69966SJacob Pan } 59394f69966SJacob Pan 59494f69966SJacob Pan const char tz_title[] = "THERMAL ZONES(SENSORS)"; 59594f69966SJacob Pan 59694f69966SJacob Pan void show_sensors_w(void) 59794f69966SJacob Pan { 59894f69966SJacob Pan int i, j; 59994f69966SJacob Pan char buffer[512]; 60094f69966SJacob Pan 60194f69966SJacob Pan if (tui_disabled || !tz_sensor_window) 60294f69966SJacob Pan return; 60394f69966SJacob Pan 60494f69966SJacob Pan werase(tz_sensor_window); 60594f69966SJacob Pan 60694f69966SJacob Pan memset(buffer, 0, sizeof(buffer)); 60794f69966SJacob Pan wattron(tz_sensor_window, A_BOLD); 60894f69966SJacob Pan mvwprintw(tz_sensor_window, 1, 1, "Thermal Zones:"); 60994f69966SJacob Pan wattroff(tz_sensor_window, A_BOLD); 61094f69966SJacob Pan 61194f69966SJacob Pan mvwprintw(tz_sensor_window, 1, TZ_LEFT_ALIGN, "%s", buffer); 61294f69966SJacob Pan /* fill trip points for each tzone */ 61394f69966SJacob Pan wattron(tz_sensor_window, A_BOLD); 61494f69966SJacob Pan mvwprintw(tz_sensor_window, 2, 1, "Trip Points:"); 61594f69966SJacob Pan wattroff(tz_sensor_window, A_BOLD); 61694f69966SJacob Pan 61794f69966SJacob Pan /* draw trip point from low to high for each tz */ 61894f69966SJacob Pan for (i = 0; i < ptdata.nr_tz_sensor; i++) { 61994f69966SJacob Pan int inst = ptdata.tzi[i].instance; 62094f69966SJacob Pan 62194f69966SJacob Pan mvwprintw(tz_sensor_window, 1, 62294f69966SJacob Pan TZ_LEFT_ALIGN+TZONE_RECORD_SIZE * inst, "%.9s%02d", 62394f69966SJacob Pan ptdata.tzi[i].type, ptdata.tzi[i].instance); 62494f69966SJacob Pan for (j = ptdata.tzi[i].nr_trip_pts - 1; j >= 0; j--) { 62594f69966SJacob Pan /* loop through all trip points */ 62694f69966SJacob Pan char type; 62794f69966SJacob Pan int tp_pos; 62894f69966SJacob Pan /* reverse the order here since trips are sorted 62994f69966SJacob Pan * in ascending order in terms of temperature. 63094f69966SJacob Pan */ 63194f69966SJacob Pan tp_pos = ptdata.tzi[i].nr_trip_pts - j - 1; 63294f69966SJacob Pan 63394f69966SJacob Pan type = trip_type_to_char(ptdata.tzi[i].tp[j].type); 63494f69966SJacob Pan mvwaddch(tz_sensor_window, 2, 63594f69966SJacob Pan inst * TZONE_RECORD_SIZE + TZ_LEFT_ALIGN + 63694f69966SJacob Pan tp_pos, type); 63794f69966SJacob Pan syslog(LOG_DEBUG, "draw tz %d tp %d ch:%c\n", 63894f69966SJacob Pan inst, j, type); 63994f69966SJacob Pan } 64094f69966SJacob Pan } 64194f69966SJacob Pan wborder(tz_sensor_window, 0, 0, 0, 0, 0, 0, 0, 0); 64294f69966SJacob Pan wattron(tz_sensor_window, A_BOLD); 64394f69966SJacob Pan mvwprintw(tz_sensor_window, 0, maxx/2 - sizeof(tz_title), tz_title); 64494f69966SJacob Pan wattroff(tz_sensor_window, A_BOLD); 64594f69966SJacob Pan wrefresh(tz_sensor_window); 64694f69966SJacob Pan } 64794f69966SJacob Pan 64894f69966SJacob Pan void disable_tui(void) 64994f69966SJacob Pan { 65094f69966SJacob Pan tui_disabled = 1; 65194f69966SJacob Pan } 652