162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * tui.c ncurses text user interface for TMON program 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2013 Intel Corporation. All rights reserved. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Jacob Pan <jacob.jun.pan@linux.intel.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <unistd.h> 1162306a36Sopenharmony_ci#include <stdio.h> 1262306a36Sopenharmony_ci#include <stdlib.h> 1362306a36Sopenharmony_ci#include <string.h> 1462306a36Sopenharmony_ci#include <stdint.h> 1562306a36Sopenharmony_ci#include <ncurses.h> 1662306a36Sopenharmony_ci#include <time.h> 1762306a36Sopenharmony_ci#include <syslog.h> 1862306a36Sopenharmony_ci#include <panel.h> 1962306a36Sopenharmony_ci#include <pthread.h> 2062306a36Sopenharmony_ci#include <signal.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "tmon.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define min(x, y) ({ \ 2562306a36Sopenharmony_ci typeof(x) _min1 = (x); \ 2662306a36Sopenharmony_ci typeof(y) _min2 = (y); \ 2762306a36Sopenharmony_ci (void) (&_min1 == &_min2); \ 2862306a36Sopenharmony_ci _min1 < _min2 ? _min1 : _min2; }) 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define max(x, y) ({ \ 3162306a36Sopenharmony_ci typeof(x) _max1 = (x); \ 3262306a36Sopenharmony_ci typeof(y) _max2 = (y); \ 3362306a36Sopenharmony_ci (void) (&_max1 == &_max2); \ 3462306a36Sopenharmony_ci _max1 > _max2 ? _max1 : _max2; }) 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic PANEL *data_panel; 3762306a36Sopenharmony_cistatic PANEL *dialogue_panel; 3862306a36Sopenharmony_cistatic PANEL *top; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic WINDOW *title_bar_window; 4162306a36Sopenharmony_cistatic WINDOW *tz_sensor_window; 4262306a36Sopenharmony_cistatic WINDOW *cooling_device_window; 4362306a36Sopenharmony_cistatic WINDOW *control_window; 4462306a36Sopenharmony_cistatic WINDOW *status_bar_window; 4562306a36Sopenharmony_cistatic WINDOW *thermal_data_window; 4662306a36Sopenharmony_cistatic WINDOW *dialogue_window; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cichar status_bar_slots[10][40]; 4962306a36Sopenharmony_cistatic void draw_hbar(WINDOW *win, int y, int start, int len, 5062306a36Sopenharmony_ci unsigned long pattern, bool end); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic int maxx, maxy; 5362306a36Sopenharmony_cistatic int maxwidth = 200; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define TITLE_BAR_HIGHT 1 5662306a36Sopenharmony_ci#define SENSOR_WIN_HIGHT 4 /* one row for tz name, one for trip points */ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* daemon mode flag (set by startup parameter -d) */ 6062306a36Sopenharmony_cistatic int tui_disabled; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic void close_panel(PANEL *p) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci if (p) { 6562306a36Sopenharmony_ci del_panel(p); 6662306a36Sopenharmony_ci p = NULL; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic void close_window(WINDOW *win) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci if (win) { 7362306a36Sopenharmony_ci delwin(win); 7462306a36Sopenharmony_ci win = NULL; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_civoid close_windows(void) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci if (tui_disabled) 8162306a36Sopenharmony_ci return; 8262306a36Sopenharmony_ci /* must delete panels before their attached windows */ 8362306a36Sopenharmony_ci if (dialogue_window) 8462306a36Sopenharmony_ci close_panel(dialogue_panel); 8562306a36Sopenharmony_ci if (cooling_device_window) 8662306a36Sopenharmony_ci close_panel(data_panel); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci close_window(title_bar_window); 8962306a36Sopenharmony_ci close_window(tz_sensor_window); 9062306a36Sopenharmony_ci close_window(status_bar_window); 9162306a36Sopenharmony_ci close_window(cooling_device_window); 9262306a36Sopenharmony_ci close_window(control_window); 9362306a36Sopenharmony_ci close_window(thermal_data_window); 9462306a36Sopenharmony_ci close_window(dialogue_window); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_civoid write_status_bar(int x, char *line) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci mvwprintw(status_bar_window, 0, x, "%s", line); 10162306a36Sopenharmony_ci wrefresh(status_bar_window); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* wrap at 5 */ 10562306a36Sopenharmony_ci#define DIAG_DEV_ROWS 5 10662306a36Sopenharmony_ci/* 10762306a36Sopenharmony_ci * list cooling devices + "set temp" entry; wraps after 5 rows, if they fit 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_cistatic int diag_dev_rows(void) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci int entries = ptdata.nr_cooling_dev + 1; 11262306a36Sopenharmony_ci int rows = max(DIAG_DEV_ROWS, (entries + 1) / 2); 11362306a36Sopenharmony_ci return min(rows, entries); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_civoid setup_windows(void) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci int y_begin = 1; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (tui_disabled) 12162306a36Sopenharmony_ci return; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci getmaxyx(stdscr, maxy, maxx); 12462306a36Sopenharmony_ci resizeterm(maxy, maxx); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci title_bar_window = subwin(stdscr, TITLE_BAR_HIGHT, maxx, 0, 0); 12762306a36Sopenharmony_ci y_begin += TITLE_BAR_HIGHT; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci tz_sensor_window = subwin(stdscr, SENSOR_WIN_HIGHT, maxx, y_begin, 0); 13062306a36Sopenharmony_ci y_begin += SENSOR_WIN_HIGHT; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci cooling_device_window = subwin(stdscr, ptdata.nr_cooling_dev + 3, maxx, 13362306a36Sopenharmony_ci y_begin, 0); 13462306a36Sopenharmony_ci y_begin += ptdata.nr_cooling_dev + 3; /* 2 lines for border */ 13562306a36Sopenharmony_ci /* two lines to show borders, one line per tz show trip point position 13662306a36Sopenharmony_ci * and value. 13762306a36Sopenharmony_ci * dialogue window is a pop-up, when needed it lays on top of cdev win 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci dialogue_window = subwin(stdscr, diag_dev_rows() + 5, maxx-50, 14162306a36Sopenharmony_ci DIAG_Y, DIAG_X); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci thermal_data_window = subwin(stdscr, ptdata.nr_tz_sensor * 14462306a36Sopenharmony_ci NR_LINES_TZDATA + 3, maxx, y_begin, 0); 14562306a36Sopenharmony_ci y_begin += ptdata.nr_tz_sensor * NR_LINES_TZDATA + 3; 14662306a36Sopenharmony_ci control_window = subwin(stdscr, 4, maxx, y_begin, 0); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci scrollok(cooling_device_window, TRUE); 14962306a36Sopenharmony_ci maxwidth = maxx - 18; 15062306a36Sopenharmony_ci status_bar_window = subwin(stdscr, 1, maxx, maxy-1, 0); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci strcpy(status_bar_slots[0], " Ctrl-c - Quit "); 15362306a36Sopenharmony_ci strcpy(status_bar_slots[1], " TAB - Tuning "); 15462306a36Sopenharmony_ci wmove(status_bar_window, 1, 30); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* prepare panels for dialogue, if panel already created then we must 15762306a36Sopenharmony_ci * be doing resizing, so just replace windows with new ones, old ones 15862306a36Sopenharmony_ci * should have been deleted by close_window 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_ci data_panel = new_panel(cooling_device_window); 16162306a36Sopenharmony_ci if (!data_panel) 16262306a36Sopenharmony_ci syslog(LOG_DEBUG, "No data panel\n"); 16362306a36Sopenharmony_ci else { 16462306a36Sopenharmony_ci if (dialogue_window) { 16562306a36Sopenharmony_ci dialogue_panel = new_panel(dialogue_window); 16662306a36Sopenharmony_ci if (!dialogue_panel) 16762306a36Sopenharmony_ci syslog(LOG_DEBUG, "No dialogue panel\n"); 16862306a36Sopenharmony_ci else { 16962306a36Sopenharmony_ci /* Set up the user pointer to the next panel*/ 17062306a36Sopenharmony_ci set_panel_userptr(data_panel, dialogue_panel); 17162306a36Sopenharmony_ci set_panel_userptr(dialogue_panel, data_panel); 17262306a36Sopenharmony_ci top = data_panel; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci } else 17562306a36Sopenharmony_ci syslog(LOG_INFO, "no dialogue win, term too small\n"); 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci doupdate(); 17862306a36Sopenharmony_ci werase(stdscr); 17962306a36Sopenharmony_ci refresh(); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_civoid resize_handler(int sig) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci /* start over when term gets resized, but first we clean up */ 18562306a36Sopenharmony_ci close_windows(); 18662306a36Sopenharmony_ci endwin(); 18762306a36Sopenharmony_ci refresh(); 18862306a36Sopenharmony_ci clear(); 18962306a36Sopenharmony_ci getmaxyx(stdscr, maxy, maxx); /* get the new screen size */ 19062306a36Sopenharmony_ci setup_windows(); 19162306a36Sopenharmony_ci /* rate limit */ 19262306a36Sopenharmony_ci sleep(1); 19362306a36Sopenharmony_ci syslog(LOG_DEBUG, "SIG %d, term resized to %d x %d\n", 19462306a36Sopenharmony_ci sig, maxy, maxx); 19562306a36Sopenharmony_ci signal(SIGWINCH, resize_handler); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ciconst char cdev_title[] = " COOLING DEVICES "; 19962306a36Sopenharmony_civoid show_cooling_device(void) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci int i, j, x, y = 0; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (tui_disabled || !cooling_device_window) 20462306a36Sopenharmony_ci return; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci werase(cooling_device_window); 20762306a36Sopenharmony_ci wattron(cooling_device_window, A_BOLD); 20862306a36Sopenharmony_ci mvwprintw(cooling_device_window, 1, 1, 20962306a36Sopenharmony_ci "ID Cooling Dev Cur Max Thermal Zone Binding"); 21062306a36Sopenharmony_ci wattroff(cooling_device_window, A_BOLD); 21162306a36Sopenharmony_ci for (j = 0; j < ptdata.nr_cooling_dev; j++) { 21262306a36Sopenharmony_ci /* draw cooling device list on the left in the order of 21362306a36Sopenharmony_ci * cooling device instances. skip unused idr. 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_ci mvwprintw(cooling_device_window, j + 2, 1, 21662306a36Sopenharmony_ci "%02d %12.12s%6d %6d", 21762306a36Sopenharmony_ci ptdata.cdi[j].instance, 21862306a36Sopenharmony_ci ptdata.cdi[j].type, 21962306a36Sopenharmony_ci ptdata.cdi[j].cur_state, 22062306a36Sopenharmony_ci ptdata.cdi[j].max_state); 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* show cdev binding, y is the global cooling device instance */ 22462306a36Sopenharmony_ci for (i = 0; i < ptdata.nr_tz_sensor; i++) { 22562306a36Sopenharmony_ci int tz_inst = ptdata.tzi[i].instance; 22662306a36Sopenharmony_ci for (j = 0; j < ptdata.nr_cooling_dev; j++) { 22762306a36Sopenharmony_ci int cdev_inst; 22862306a36Sopenharmony_ci y = j; 22962306a36Sopenharmony_ci x = tz_inst * TZONE_RECORD_SIZE + TZ_LEFT_ALIGN; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci draw_hbar(cooling_device_window, y+2, x, 23262306a36Sopenharmony_ci TZONE_RECORD_SIZE-1, ACS_VLINE, false); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* draw a column of spaces to separate thermal zones */ 23562306a36Sopenharmony_ci mvwprintw(cooling_device_window, y+2, x-1, " "); 23662306a36Sopenharmony_ci if (ptdata.tzi[i].cdev_binding) { 23762306a36Sopenharmony_ci cdev_inst = ptdata.cdi[j].instance; 23862306a36Sopenharmony_ci unsigned long trip_binding = 23962306a36Sopenharmony_ci ptdata.tzi[i].trip_binding[cdev_inst]; 24062306a36Sopenharmony_ci int k = 0; /* per zone trip point id that 24162306a36Sopenharmony_ci * binded to this cdev, one to 24262306a36Sopenharmony_ci * many possible based on the 24362306a36Sopenharmony_ci * binding bitmask. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ci syslog(LOG_DEBUG, 24662306a36Sopenharmony_ci "bind tz%d cdev%d tp%lx %d cdev%lx\n", 24762306a36Sopenharmony_ci i, j, trip_binding, y, 24862306a36Sopenharmony_ci ptdata.tzi[i].cdev_binding); 24962306a36Sopenharmony_ci /* draw each trip binding for the cdev */ 25062306a36Sopenharmony_ci while (trip_binding >>= 1) { 25162306a36Sopenharmony_ci k++; 25262306a36Sopenharmony_ci if (!(trip_binding & 1)) 25362306a36Sopenharmony_ci continue; 25462306a36Sopenharmony_ci /* draw '*' to show binding */ 25562306a36Sopenharmony_ci mvwprintw(cooling_device_window, 25662306a36Sopenharmony_ci y + 2, 25762306a36Sopenharmony_ci x + ptdata.tzi[i].nr_trip_pts - 25862306a36Sopenharmony_ci k - 1, "*"); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci /* draw border after data so that border will not be messed up 26462306a36Sopenharmony_ci * even there is not enough space for all the data to be shown 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_ci wborder(cooling_device_window, 0, 0, 0, 0, 0, 0, 0, 0); 26762306a36Sopenharmony_ci wattron(cooling_device_window, A_BOLD); 26862306a36Sopenharmony_ci mvwprintw(cooling_device_window, 0, maxx/2 - sizeof(cdev_title), 26962306a36Sopenharmony_ci cdev_title); 27062306a36Sopenharmony_ci wattroff(cooling_device_window, A_BOLD); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci wrefresh(cooling_device_window); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ciconst char DIAG_TITLE[] = "[ TUNABLES ]"; 27662306a36Sopenharmony_civoid show_dialogue(void) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci int j, x = 0, y = 0; 27962306a36Sopenharmony_ci int rows, cols; 28062306a36Sopenharmony_ci WINDOW *w = dialogue_window; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (tui_disabled || !w) 28362306a36Sopenharmony_ci return; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci getmaxyx(w, rows, cols); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* Silence compiler 'unused' warnings */ 28862306a36Sopenharmony_ci (void)cols; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci werase(w); 29162306a36Sopenharmony_ci box(w, 0, 0); 29262306a36Sopenharmony_ci mvwprintw(w, 0, maxx/4, DIAG_TITLE); 29362306a36Sopenharmony_ci /* list all the available tunables */ 29462306a36Sopenharmony_ci for (j = 0; j <= ptdata.nr_cooling_dev; j++) { 29562306a36Sopenharmony_ci y = j % diag_dev_rows(); 29662306a36Sopenharmony_ci if (y == 0 && j != 0) 29762306a36Sopenharmony_ci x += 20; 29862306a36Sopenharmony_ci if (j == ptdata.nr_cooling_dev) 29962306a36Sopenharmony_ci /* save last choice for target temp */ 30062306a36Sopenharmony_ci mvwprintw(w, y+1, x+1, "%C-%.12s", 'A'+j, "Set Temp"); 30162306a36Sopenharmony_ci else 30262306a36Sopenharmony_ci mvwprintw(w, y+1, x+1, "%C-%.10s-%2d", 'A'+j, 30362306a36Sopenharmony_ci ptdata.cdi[j].type, ptdata.cdi[j].instance); 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci wattron(w, A_BOLD); 30662306a36Sopenharmony_ci mvwprintw(w, diag_dev_rows()+1, 1, "Enter Choice [A-Z]?"); 30762306a36Sopenharmony_ci wattroff(w, A_BOLD); 30862306a36Sopenharmony_ci /* print legend at the bottom line */ 30962306a36Sopenharmony_ci mvwprintw(w, rows - 2, 1, 31062306a36Sopenharmony_ci "Legend: A=Active, P=Passive, C=Critical"); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci wrefresh(dialogue_window); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_civoid write_dialogue_win(char *buf, int y, int x) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci WINDOW *w = dialogue_window; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci mvwprintw(w, y, x, "%s", buf); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ciconst char control_title[] = " CONTROLS "; 32362306a36Sopenharmony_civoid show_control_w(void) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci unsigned long state; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci get_ctrl_state(&state); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (tui_disabled || !control_window) 33062306a36Sopenharmony_ci return; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci werase(control_window); 33362306a36Sopenharmony_ci mvwprintw(control_window, 1, 1, 33462306a36Sopenharmony_ci "PID gain: kp=%2.2f ki=%2.2f kd=%2.2f Output %2.2f", 33562306a36Sopenharmony_ci p_param.kp, p_param.ki, p_param.kd, p_param.y_k); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci mvwprintw(control_window, 2, 1, 33862306a36Sopenharmony_ci "Target Temp: %2.1fC, Zone: %d, Control Device: %.12s", 33962306a36Sopenharmony_ci p_param.t_target, target_thermal_zone, ctrl_cdev); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* draw border last such that everything is within boundary */ 34262306a36Sopenharmony_ci wborder(control_window, 0, 0, 0, 0, 0, 0, 0, 0); 34362306a36Sopenharmony_ci wattron(control_window, A_BOLD); 34462306a36Sopenharmony_ci mvwprintw(control_window, 0, maxx/2 - sizeof(control_title), 34562306a36Sopenharmony_ci control_title); 34662306a36Sopenharmony_ci wattroff(control_window, A_BOLD); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci wrefresh(control_window); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_civoid initialize_curses(void) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci if (tui_disabled) 35462306a36Sopenharmony_ci return; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci initscr(); 35762306a36Sopenharmony_ci start_color(); 35862306a36Sopenharmony_ci keypad(stdscr, TRUE); /* enable keyboard mapping */ 35962306a36Sopenharmony_ci nonl(); /* tell curses not to do NL->CR/NL on output */ 36062306a36Sopenharmony_ci cbreak(); /* take input chars one at a time */ 36162306a36Sopenharmony_ci noecho(); /* dont echo input */ 36262306a36Sopenharmony_ci curs_set(0); /* turn off cursor */ 36362306a36Sopenharmony_ci use_default_colors(); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK); 36662306a36Sopenharmony_ci init_pair(PT_COLOR_HEADER_BAR, COLOR_BLACK, COLOR_WHITE); 36762306a36Sopenharmony_ci init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED); 36862306a36Sopenharmony_ci init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED); 36962306a36Sopenharmony_ci init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW); 37062306a36Sopenharmony_ci init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN); 37162306a36Sopenharmony_ci init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE); 37262306a36Sopenharmony_ci init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_civoid show_title_bar(void) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci int i; 37962306a36Sopenharmony_ci int x = 0; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (tui_disabled || !title_bar_window) 38262306a36Sopenharmony_ci return; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci wattrset(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR)); 38562306a36Sopenharmony_ci wbkgd(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR)); 38662306a36Sopenharmony_ci werase(title_bar_window); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci mvwprintw(title_bar_window, 0, 0, 38962306a36Sopenharmony_ci " TMON v%s", VERSION); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci wrefresh(title_bar_window); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci werase(status_bar_window); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci for (i = 0; i < 10; i++) { 39662306a36Sopenharmony_ci if (strlen(status_bar_slots[i]) == 0) 39762306a36Sopenharmony_ci continue; 39862306a36Sopenharmony_ci wattron(status_bar_window, A_REVERSE); 39962306a36Sopenharmony_ci mvwprintw(status_bar_window, 0, x, "%s", status_bar_slots[i]); 40062306a36Sopenharmony_ci wattroff(status_bar_window, A_REVERSE); 40162306a36Sopenharmony_ci x += strlen(status_bar_slots[i]) + 1; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci wrefresh(status_bar_window); 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic void handle_input_val(int ch) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci char buf[32]; 40962306a36Sopenharmony_ci int val; 41062306a36Sopenharmony_ci char path[256]; 41162306a36Sopenharmony_ci WINDOW *w = dialogue_window; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci echo(); 41462306a36Sopenharmony_ci keypad(w, TRUE); 41562306a36Sopenharmony_ci wgetnstr(w, buf, 31); 41662306a36Sopenharmony_ci val = atoi(buf); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (ch == ptdata.nr_cooling_dev) { 41962306a36Sopenharmony_ci snprintf(buf, 31, "Invalid Temp %d! %d-%d", val, 42062306a36Sopenharmony_ci MIN_CTRL_TEMP, MAX_CTRL_TEMP); 42162306a36Sopenharmony_ci if (val < MIN_CTRL_TEMP || val > MAX_CTRL_TEMP) 42262306a36Sopenharmony_ci write_status_bar(40, buf); 42362306a36Sopenharmony_ci else { 42462306a36Sopenharmony_ci p_param.t_target = val; 42562306a36Sopenharmony_ci snprintf(buf, 31, "Set New Target Temp %d", val); 42662306a36Sopenharmony_ci write_status_bar(40, buf); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci } else { 42962306a36Sopenharmony_ci snprintf(path, 256, "%s/%s%d", THERMAL_SYSFS, 43062306a36Sopenharmony_ci CDEV, ptdata.cdi[ch].instance); 43162306a36Sopenharmony_ci sysfs_set_ulong(path, "cur_state", val); 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci noecho(); 43462306a36Sopenharmony_ci dialogue_on = 0; 43562306a36Sopenharmony_ci show_data_w(); 43662306a36Sopenharmony_ci show_control_w(); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci top = (PANEL *)panel_userptr(top); 43962306a36Sopenharmony_ci top_panel(top); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic void handle_input_choice(int ch) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci char buf[48]; 44562306a36Sopenharmony_ci int base = 0; 44662306a36Sopenharmony_ci int cdev_id = 0; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if ((ch >= 'A' && ch <= 'A' + ptdata.nr_cooling_dev) || 44962306a36Sopenharmony_ci (ch >= 'a' && ch <= 'a' + ptdata.nr_cooling_dev)) { 45062306a36Sopenharmony_ci base = (ch < 'a') ? 'A' : 'a'; 45162306a36Sopenharmony_ci cdev_id = ch - base; 45262306a36Sopenharmony_ci if (ptdata.nr_cooling_dev == cdev_id) 45362306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "New Target Temp:"); 45462306a36Sopenharmony_ci else 45562306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "New Value for %.10s-%2d: ", 45662306a36Sopenharmony_ci ptdata.cdi[cdev_id].type, 45762306a36Sopenharmony_ci ptdata.cdi[cdev_id].instance); 45862306a36Sopenharmony_ci write_dialogue_win(buf, diag_dev_rows() + 2, 2); 45962306a36Sopenharmony_ci handle_input_val(cdev_id); 46062306a36Sopenharmony_ci } else { 46162306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "Invalid selection %d", ch); 46262306a36Sopenharmony_ci write_dialogue_win(buf, 8, 2); 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_civoid *handle_tui_events(void *arg) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci int ch; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci keypad(cooling_device_window, TRUE); 47162306a36Sopenharmony_ci while ((ch = wgetch(cooling_device_window)) != EOF) { 47262306a36Sopenharmony_ci if (tmon_exit) 47362306a36Sopenharmony_ci break; 47462306a36Sopenharmony_ci /* when term size is too small, no dialogue panels are set. 47562306a36Sopenharmony_ci * we need to filter out such cases. 47662306a36Sopenharmony_ci */ 47762306a36Sopenharmony_ci if (!data_panel || !dialogue_panel || 47862306a36Sopenharmony_ci !cooling_device_window || 47962306a36Sopenharmony_ci !dialogue_window) { 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci continue; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci pthread_mutex_lock(&input_lock); 48462306a36Sopenharmony_ci if (dialogue_on) { 48562306a36Sopenharmony_ci handle_input_choice(ch); 48662306a36Sopenharmony_ci /* top panel filter */ 48762306a36Sopenharmony_ci if (ch == 'q' || ch == 'Q') 48862306a36Sopenharmony_ci ch = 0; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci switch (ch) { 49162306a36Sopenharmony_ci case KEY_LEFT: 49262306a36Sopenharmony_ci box(cooling_device_window, 10, 0); 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci case 9: /* TAB */ 49562306a36Sopenharmony_ci top = (PANEL *)panel_userptr(top); 49662306a36Sopenharmony_ci top_panel(top); 49762306a36Sopenharmony_ci if (top == dialogue_panel) { 49862306a36Sopenharmony_ci dialogue_on = 1; 49962306a36Sopenharmony_ci show_dialogue(); 50062306a36Sopenharmony_ci } else { 50162306a36Sopenharmony_ci dialogue_on = 0; 50262306a36Sopenharmony_ci /* force refresh */ 50362306a36Sopenharmony_ci show_data_w(); 50462306a36Sopenharmony_ci show_control_w(); 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci break; 50762306a36Sopenharmony_ci case 'q': 50862306a36Sopenharmony_ci case 'Q': 50962306a36Sopenharmony_ci tmon_exit = 1; 51062306a36Sopenharmony_ci break; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci update_panels(); 51362306a36Sopenharmony_ci doupdate(); 51462306a36Sopenharmony_ci pthread_mutex_unlock(&input_lock); 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci if (arg) 51862306a36Sopenharmony_ci *(int *)arg = 0; /* make gcc happy */ 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return NULL; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci/* draw a horizontal bar in given pattern */ 52462306a36Sopenharmony_cistatic void draw_hbar(WINDOW *win, int y, int start, int len, unsigned long ptn, 52562306a36Sopenharmony_ci bool end) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci mvwaddch(win, y, start, ptn); 52862306a36Sopenharmony_ci whline(win, ptn, len); 52962306a36Sopenharmony_ci if (end) 53062306a36Sopenharmony_ci mvwaddch(win, y, MAX_DISP_TEMP+TDATA_LEFT, ']'); 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic char trip_type_to_char(int type) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci switch (type) { 53662306a36Sopenharmony_ci case THERMAL_TRIP_CRITICAL: return 'C'; 53762306a36Sopenharmony_ci case THERMAL_TRIP_HOT: return 'H'; 53862306a36Sopenharmony_ci case THERMAL_TRIP_PASSIVE: return 'P'; 53962306a36Sopenharmony_ci case THERMAL_TRIP_ACTIVE: return 'A'; 54062306a36Sopenharmony_ci default: 54162306a36Sopenharmony_ci return '?'; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci/* fill a string with trip point type and value in one line 54662306a36Sopenharmony_ci * e.g. P(56) C(106) 54762306a36Sopenharmony_ci * maintain the distance one degree per char 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_cistatic void draw_tp_line(int tz, int y) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci int j; 55262306a36Sopenharmony_ci int x; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci for (j = 0; j < ptdata.tzi[tz].nr_trip_pts; j++) { 55562306a36Sopenharmony_ci x = ptdata.tzi[tz].tp[j].temp / 1000; 55662306a36Sopenharmony_ci mvwprintw(thermal_data_window, y + 0, x + TDATA_LEFT, 55762306a36Sopenharmony_ci "%c%d", trip_type_to_char(ptdata.tzi[tz].tp[j].type), 55862306a36Sopenharmony_ci x); 55962306a36Sopenharmony_ci syslog(LOG_INFO, "%s:tz %d tp %d temp = %lu\n", __func__, 56062306a36Sopenharmony_ci tz, j, ptdata.tzi[tz].tp[j].temp); 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ciconst char data_win_title[] = " THERMAL DATA "; 56562306a36Sopenharmony_civoid show_data_w(void) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci int i; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (tui_disabled || !thermal_data_window) 57162306a36Sopenharmony_ci return; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci werase(thermal_data_window); 57462306a36Sopenharmony_ci wattron(thermal_data_window, A_BOLD); 57562306a36Sopenharmony_ci mvwprintw(thermal_data_window, 0, maxx/2 - sizeof(data_win_title), 57662306a36Sopenharmony_ci data_win_title); 57762306a36Sopenharmony_ci wattroff(thermal_data_window, A_BOLD); 57862306a36Sopenharmony_ci /* draw a line as ruler */ 57962306a36Sopenharmony_ci for (i = 10; i < MAX_DISP_TEMP; i += 10) 58062306a36Sopenharmony_ci mvwprintw(thermal_data_window, 1, i+TDATA_LEFT, "%2d", i); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci for (i = 0; i < ptdata.nr_tz_sensor; i++) { 58362306a36Sopenharmony_ci int temp = trec[cur_thermal_record].temp[i] / 1000; 58462306a36Sopenharmony_ci int y = 0; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci y = i * NR_LINES_TZDATA + 2; 58762306a36Sopenharmony_ci /* y at tz temp data line */ 58862306a36Sopenharmony_ci mvwprintw(thermal_data_window, y, 1, "%6.6s%2d:[%3d][", 58962306a36Sopenharmony_ci ptdata.tzi[i].type, 59062306a36Sopenharmony_ci ptdata.tzi[i].instance, temp); 59162306a36Sopenharmony_ci draw_hbar(thermal_data_window, y, TDATA_LEFT, temp, ACS_RARROW, 59262306a36Sopenharmony_ci true); 59362306a36Sopenharmony_ci draw_tp_line(i, y); 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci wborder(thermal_data_window, 0, 0, 0, 0, 0, 0, 0, 0); 59662306a36Sopenharmony_ci wrefresh(thermal_data_window); 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ciconst char tz_title[] = "THERMAL ZONES(SENSORS)"; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_civoid show_sensors_w(void) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci int i, j; 60462306a36Sopenharmony_ci char buffer[512]; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (tui_disabled || !tz_sensor_window) 60762306a36Sopenharmony_ci return; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci werase(tz_sensor_window); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci memset(buffer, 0, sizeof(buffer)); 61262306a36Sopenharmony_ci wattron(tz_sensor_window, A_BOLD); 61362306a36Sopenharmony_ci mvwprintw(tz_sensor_window, 1, 1, "Thermal Zones:"); 61462306a36Sopenharmony_ci wattroff(tz_sensor_window, A_BOLD); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci mvwprintw(tz_sensor_window, 1, TZ_LEFT_ALIGN, "%s", buffer); 61762306a36Sopenharmony_ci /* fill trip points for each tzone */ 61862306a36Sopenharmony_ci wattron(tz_sensor_window, A_BOLD); 61962306a36Sopenharmony_ci mvwprintw(tz_sensor_window, 2, 1, "Trip Points:"); 62062306a36Sopenharmony_ci wattroff(tz_sensor_window, A_BOLD); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* draw trip point from low to high for each tz */ 62362306a36Sopenharmony_ci for (i = 0; i < ptdata.nr_tz_sensor; i++) { 62462306a36Sopenharmony_ci int inst = ptdata.tzi[i].instance; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci mvwprintw(tz_sensor_window, 1, 62762306a36Sopenharmony_ci TZ_LEFT_ALIGN+TZONE_RECORD_SIZE * inst, "%.9s%02d", 62862306a36Sopenharmony_ci ptdata.tzi[i].type, ptdata.tzi[i].instance); 62962306a36Sopenharmony_ci for (j = ptdata.tzi[i].nr_trip_pts - 1; j >= 0; j--) { 63062306a36Sopenharmony_ci /* loop through all trip points */ 63162306a36Sopenharmony_ci char type; 63262306a36Sopenharmony_ci int tp_pos; 63362306a36Sopenharmony_ci /* reverse the order here since trips are sorted 63462306a36Sopenharmony_ci * in ascending order in terms of temperature. 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_ci tp_pos = ptdata.tzi[i].nr_trip_pts - j - 1; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci type = trip_type_to_char(ptdata.tzi[i].tp[j].type); 63962306a36Sopenharmony_ci mvwaddch(tz_sensor_window, 2, 64062306a36Sopenharmony_ci inst * TZONE_RECORD_SIZE + TZ_LEFT_ALIGN + 64162306a36Sopenharmony_ci tp_pos, type); 64262306a36Sopenharmony_ci syslog(LOG_DEBUG, "draw tz %d tp %d ch:%c\n", 64362306a36Sopenharmony_ci inst, j, type); 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci wborder(tz_sensor_window, 0, 0, 0, 0, 0, 0, 0, 0); 64762306a36Sopenharmony_ci wattron(tz_sensor_window, A_BOLD); 64862306a36Sopenharmony_ci mvwprintw(tz_sensor_window, 0, maxx/2 - sizeof(tz_title), tz_title); 64962306a36Sopenharmony_ci wattroff(tz_sensor_window, A_BOLD); 65062306a36Sopenharmony_ci wrefresh(tz_sensor_window); 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_civoid disable_tui(void) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci tui_disabled = 1; 65662306a36Sopenharmony_ci} 657