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