18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * tui.c ncurses text user interface for TMON program 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013 Intel Corporation. All rights reserved. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Jacob Pan <jacob.jun.pan@linux.intel.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <unistd.h> 118c2ecf20Sopenharmony_ci#include <stdio.h> 128c2ecf20Sopenharmony_ci#include <stdlib.h> 138c2ecf20Sopenharmony_ci#include <string.h> 148c2ecf20Sopenharmony_ci#include <stdint.h> 158c2ecf20Sopenharmony_ci#include <ncurses.h> 168c2ecf20Sopenharmony_ci#include <time.h> 178c2ecf20Sopenharmony_ci#include <syslog.h> 188c2ecf20Sopenharmony_ci#include <panel.h> 198c2ecf20Sopenharmony_ci#include <pthread.h> 208c2ecf20Sopenharmony_ci#include <signal.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "tmon.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define min(x, y) ({ \ 258c2ecf20Sopenharmony_ci typeof(x) _min1 = (x); \ 268c2ecf20Sopenharmony_ci typeof(y) _min2 = (y); \ 278c2ecf20Sopenharmony_ci (void) (&_min1 == &_min2); \ 288c2ecf20Sopenharmony_ci _min1 < _min2 ? _min1 : _min2; }) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define max(x, y) ({ \ 318c2ecf20Sopenharmony_ci typeof(x) _max1 = (x); \ 328c2ecf20Sopenharmony_ci typeof(y) _max2 = (y); \ 338c2ecf20Sopenharmony_ci (void) (&_max1 == &_max2); \ 348c2ecf20Sopenharmony_ci _max1 > _max2 ? _max1 : _max2; }) 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic PANEL *data_panel; 378c2ecf20Sopenharmony_cistatic PANEL *dialogue_panel; 388c2ecf20Sopenharmony_cistatic PANEL *top; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic WINDOW *title_bar_window; 418c2ecf20Sopenharmony_cistatic WINDOW *tz_sensor_window; 428c2ecf20Sopenharmony_cistatic WINDOW *cooling_device_window; 438c2ecf20Sopenharmony_cistatic WINDOW *control_window; 448c2ecf20Sopenharmony_cistatic WINDOW *status_bar_window; 458c2ecf20Sopenharmony_cistatic WINDOW *thermal_data_window; 468c2ecf20Sopenharmony_cistatic WINDOW *dialogue_window; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cichar status_bar_slots[10][40]; 498c2ecf20Sopenharmony_cistatic void draw_hbar(WINDOW *win, int y, int start, int len, 508c2ecf20Sopenharmony_ci unsigned long pattern, bool end); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int maxx, maxy; 538c2ecf20Sopenharmony_cistatic int maxwidth = 200; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define TITLE_BAR_HIGHT 1 568c2ecf20Sopenharmony_ci#define SENSOR_WIN_HIGHT 4 /* one row for tz name, one for trip points */ 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* daemon mode flag (set by startup parameter -d) */ 608c2ecf20Sopenharmony_cistatic int tui_disabled; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void close_panel(PANEL *p) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci if (p) { 658c2ecf20Sopenharmony_ci del_panel(p); 668c2ecf20Sopenharmony_ci p = NULL; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic void close_window(WINDOW *win) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci if (win) { 738c2ecf20Sopenharmony_ci delwin(win); 748c2ecf20Sopenharmony_ci win = NULL; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_civoid close_windows(void) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci if (tui_disabled) 818c2ecf20Sopenharmony_ci return; 828c2ecf20Sopenharmony_ci /* must delete panels before their attached windows */ 838c2ecf20Sopenharmony_ci if (dialogue_window) 848c2ecf20Sopenharmony_ci close_panel(dialogue_panel); 858c2ecf20Sopenharmony_ci if (cooling_device_window) 868c2ecf20Sopenharmony_ci close_panel(data_panel); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci close_window(title_bar_window); 898c2ecf20Sopenharmony_ci close_window(tz_sensor_window); 908c2ecf20Sopenharmony_ci close_window(status_bar_window); 918c2ecf20Sopenharmony_ci close_window(cooling_device_window); 928c2ecf20Sopenharmony_ci close_window(control_window); 938c2ecf20Sopenharmony_ci close_window(thermal_data_window); 948c2ecf20Sopenharmony_ci close_window(dialogue_window); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_civoid write_status_bar(int x, char *line) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci mvwprintw(status_bar_window, 0, x, "%s", line); 1018c2ecf20Sopenharmony_ci wrefresh(status_bar_window); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* wrap at 5 */ 1058c2ecf20Sopenharmony_ci#define DIAG_DEV_ROWS 5 1068c2ecf20Sopenharmony_ci/* 1078c2ecf20Sopenharmony_ci * list cooling devices + "set temp" entry; wraps after 5 rows, if they fit 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_cistatic int diag_dev_rows(void) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci int entries = ptdata.nr_cooling_dev + 1; 1128c2ecf20Sopenharmony_ci int rows = max(DIAG_DEV_ROWS, (entries + 1) / 2); 1138c2ecf20Sopenharmony_ci return min(rows, entries); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_civoid setup_windows(void) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci int y_begin = 1; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (tui_disabled) 1218c2ecf20Sopenharmony_ci return; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci getmaxyx(stdscr, maxy, maxx); 1248c2ecf20Sopenharmony_ci resizeterm(maxy, maxx); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci title_bar_window = subwin(stdscr, TITLE_BAR_HIGHT, maxx, 0, 0); 1278c2ecf20Sopenharmony_ci y_begin += TITLE_BAR_HIGHT; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci tz_sensor_window = subwin(stdscr, SENSOR_WIN_HIGHT, maxx, y_begin, 0); 1308c2ecf20Sopenharmony_ci y_begin += SENSOR_WIN_HIGHT; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci cooling_device_window = subwin(stdscr, ptdata.nr_cooling_dev + 3, maxx, 1338c2ecf20Sopenharmony_ci y_begin, 0); 1348c2ecf20Sopenharmony_ci y_begin += ptdata.nr_cooling_dev + 3; /* 2 lines for border */ 1358c2ecf20Sopenharmony_ci /* two lines to show borders, one line per tz show trip point position 1368c2ecf20Sopenharmony_ci * and value. 1378c2ecf20Sopenharmony_ci * dialogue window is a pop-up, when needed it lays on top of cdev win 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci dialogue_window = subwin(stdscr, diag_dev_rows() + 5, maxx-50, 1418c2ecf20Sopenharmony_ci DIAG_Y, DIAG_X); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci thermal_data_window = subwin(stdscr, ptdata.nr_tz_sensor * 1448c2ecf20Sopenharmony_ci NR_LINES_TZDATA + 3, maxx, y_begin, 0); 1458c2ecf20Sopenharmony_ci y_begin += ptdata.nr_tz_sensor * NR_LINES_TZDATA + 3; 1468c2ecf20Sopenharmony_ci control_window = subwin(stdscr, 4, maxx, y_begin, 0); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci scrollok(cooling_device_window, TRUE); 1498c2ecf20Sopenharmony_ci maxwidth = maxx - 18; 1508c2ecf20Sopenharmony_ci status_bar_window = subwin(stdscr, 1, maxx, maxy-1, 0); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci strcpy(status_bar_slots[0], " Ctrl-c - Quit "); 1538c2ecf20Sopenharmony_ci strcpy(status_bar_slots[1], " TAB - Tuning "); 1548c2ecf20Sopenharmony_ci wmove(status_bar_window, 1, 30); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* prepare panels for dialogue, if panel already created then we must 1578c2ecf20Sopenharmony_ci * be doing resizing, so just replace windows with new ones, old ones 1588c2ecf20Sopenharmony_ci * should have been deleted by close_window 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_ci data_panel = new_panel(cooling_device_window); 1618c2ecf20Sopenharmony_ci if (!data_panel) 1628c2ecf20Sopenharmony_ci syslog(LOG_DEBUG, "No data panel\n"); 1638c2ecf20Sopenharmony_ci else { 1648c2ecf20Sopenharmony_ci if (dialogue_window) { 1658c2ecf20Sopenharmony_ci dialogue_panel = new_panel(dialogue_window); 1668c2ecf20Sopenharmony_ci if (!dialogue_panel) 1678c2ecf20Sopenharmony_ci syslog(LOG_DEBUG, "No dialogue panel\n"); 1688c2ecf20Sopenharmony_ci else { 1698c2ecf20Sopenharmony_ci /* Set up the user pointer to the next panel*/ 1708c2ecf20Sopenharmony_ci set_panel_userptr(data_panel, dialogue_panel); 1718c2ecf20Sopenharmony_ci set_panel_userptr(dialogue_panel, data_panel); 1728c2ecf20Sopenharmony_ci top = data_panel; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci } else 1758c2ecf20Sopenharmony_ci syslog(LOG_INFO, "no dialogue win, term too small\n"); 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci doupdate(); 1788c2ecf20Sopenharmony_ci werase(stdscr); 1798c2ecf20Sopenharmony_ci refresh(); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_civoid resize_handler(int sig) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci /* start over when term gets resized, but first we clean up */ 1858c2ecf20Sopenharmony_ci close_windows(); 1868c2ecf20Sopenharmony_ci endwin(); 1878c2ecf20Sopenharmony_ci refresh(); 1888c2ecf20Sopenharmony_ci clear(); 1898c2ecf20Sopenharmony_ci getmaxyx(stdscr, maxy, maxx); /* get the new screen size */ 1908c2ecf20Sopenharmony_ci setup_windows(); 1918c2ecf20Sopenharmony_ci /* rate limit */ 1928c2ecf20Sopenharmony_ci sleep(1); 1938c2ecf20Sopenharmony_ci syslog(LOG_DEBUG, "SIG %d, term resized to %d x %d\n", 1948c2ecf20Sopenharmony_ci sig, maxy, maxx); 1958c2ecf20Sopenharmony_ci signal(SIGWINCH, resize_handler); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ciconst char cdev_title[] = " COOLING DEVICES "; 1998c2ecf20Sopenharmony_civoid show_cooling_device(void) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci int i, j, x, y = 0; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (tui_disabled || !cooling_device_window) 2048c2ecf20Sopenharmony_ci return; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci werase(cooling_device_window); 2078c2ecf20Sopenharmony_ci wattron(cooling_device_window, A_BOLD); 2088c2ecf20Sopenharmony_ci mvwprintw(cooling_device_window, 1, 1, 2098c2ecf20Sopenharmony_ci "ID Cooling Dev Cur Max Thermal Zone Binding"); 2108c2ecf20Sopenharmony_ci wattroff(cooling_device_window, A_BOLD); 2118c2ecf20Sopenharmony_ci for (j = 0; j < ptdata.nr_cooling_dev; j++) { 2128c2ecf20Sopenharmony_ci /* draw cooling device list on the left in the order of 2138c2ecf20Sopenharmony_ci * cooling device instances. skip unused idr. 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_ci mvwprintw(cooling_device_window, j + 2, 1, 2168c2ecf20Sopenharmony_ci "%02d %12.12s%6d %6d", 2178c2ecf20Sopenharmony_ci ptdata.cdi[j].instance, 2188c2ecf20Sopenharmony_ci ptdata.cdi[j].type, 2198c2ecf20Sopenharmony_ci ptdata.cdi[j].cur_state, 2208c2ecf20Sopenharmony_ci ptdata.cdi[j].max_state); 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* show cdev binding, y is the global cooling device instance */ 2248c2ecf20Sopenharmony_ci for (i = 0; i < ptdata.nr_tz_sensor; i++) { 2258c2ecf20Sopenharmony_ci int tz_inst = ptdata.tzi[i].instance; 2268c2ecf20Sopenharmony_ci for (j = 0; j < ptdata.nr_cooling_dev; j++) { 2278c2ecf20Sopenharmony_ci int cdev_inst; 2288c2ecf20Sopenharmony_ci y = j; 2298c2ecf20Sopenharmony_ci x = tz_inst * TZONE_RECORD_SIZE + TZ_LEFT_ALIGN; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci draw_hbar(cooling_device_window, y+2, x, 2328c2ecf20Sopenharmony_ci TZONE_RECORD_SIZE-1, ACS_VLINE, false); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* draw a column of spaces to separate thermal zones */ 2358c2ecf20Sopenharmony_ci mvwprintw(cooling_device_window, y+2, x-1, " "); 2368c2ecf20Sopenharmony_ci if (ptdata.tzi[i].cdev_binding) { 2378c2ecf20Sopenharmony_ci cdev_inst = ptdata.cdi[j].instance; 2388c2ecf20Sopenharmony_ci unsigned long trip_binding = 2398c2ecf20Sopenharmony_ci ptdata.tzi[i].trip_binding[cdev_inst]; 2408c2ecf20Sopenharmony_ci int k = 0; /* per zone trip point id that 2418c2ecf20Sopenharmony_ci * binded to this cdev, one to 2428c2ecf20Sopenharmony_ci * many possible based on the 2438c2ecf20Sopenharmony_ci * binding bitmask. 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci syslog(LOG_DEBUG, 2468c2ecf20Sopenharmony_ci "bind tz%d cdev%d tp%lx %d cdev%lx\n", 2478c2ecf20Sopenharmony_ci i, j, trip_binding, y, 2488c2ecf20Sopenharmony_ci ptdata.tzi[i].cdev_binding); 2498c2ecf20Sopenharmony_ci /* draw each trip binding for the cdev */ 2508c2ecf20Sopenharmony_ci while (trip_binding >>= 1) { 2518c2ecf20Sopenharmony_ci k++; 2528c2ecf20Sopenharmony_ci if (!(trip_binding & 1)) 2538c2ecf20Sopenharmony_ci continue; 2548c2ecf20Sopenharmony_ci /* draw '*' to show binding */ 2558c2ecf20Sopenharmony_ci mvwprintw(cooling_device_window, 2568c2ecf20Sopenharmony_ci y + 2, 2578c2ecf20Sopenharmony_ci x + ptdata.tzi[i].nr_trip_pts - 2588c2ecf20Sopenharmony_ci k - 1, "*"); 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci /* draw border after data so that border will not be messed up 2648c2ecf20Sopenharmony_ci * even there is not enough space for all the data to be shown 2658c2ecf20Sopenharmony_ci */ 2668c2ecf20Sopenharmony_ci wborder(cooling_device_window, 0, 0, 0, 0, 0, 0, 0, 0); 2678c2ecf20Sopenharmony_ci wattron(cooling_device_window, A_BOLD); 2688c2ecf20Sopenharmony_ci mvwprintw(cooling_device_window, 0, maxx/2 - sizeof(cdev_title), 2698c2ecf20Sopenharmony_ci cdev_title); 2708c2ecf20Sopenharmony_ci wattroff(cooling_device_window, A_BOLD); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci wrefresh(cooling_device_window); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ciconst char DIAG_TITLE[] = "[ TUNABLES ]"; 2768c2ecf20Sopenharmony_civoid show_dialogue(void) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci int j, x = 0, y = 0; 2798c2ecf20Sopenharmony_ci int rows, cols; 2808c2ecf20Sopenharmony_ci WINDOW *w = dialogue_window; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (tui_disabled || !w) 2838c2ecf20Sopenharmony_ci return; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci getmaxyx(w, rows, cols); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* Silence compiler 'unused' warnings */ 2888c2ecf20Sopenharmony_ci (void)cols; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci werase(w); 2918c2ecf20Sopenharmony_ci box(w, 0, 0); 2928c2ecf20Sopenharmony_ci mvwprintw(w, 0, maxx/4, DIAG_TITLE); 2938c2ecf20Sopenharmony_ci /* list all the available tunables */ 2948c2ecf20Sopenharmony_ci for (j = 0; j <= ptdata.nr_cooling_dev; j++) { 2958c2ecf20Sopenharmony_ci y = j % diag_dev_rows(); 2968c2ecf20Sopenharmony_ci if (y == 0 && j != 0) 2978c2ecf20Sopenharmony_ci x += 20; 2988c2ecf20Sopenharmony_ci if (j == ptdata.nr_cooling_dev) 2998c2ecf20Sopenharmony_ci /* save last choice for target temp */ 3008c2ecf20Sopenharmony_ci mvwprintw(w, y+1, x+1, "%C-%.12s", 'A'+j, "Set Temp"); 3018c2ecf20Sopenharmony_ci else 3028c2ecf20Sopenharmony_ci mvwprintw(w, y+1, x+1, "%C-%.10s-%2d", 'A'+j, 3038c2ecf20Sopenharmony_ci ptdata.cdi[j].type, ptdata.cdi[j].instance); 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci wattron(w, A_BOLD); 3068c2ecf20Sopenharmony_ci mvwprintw(w, diag_dev_rows()+1, 1, "Enter Choice [A-Z]?"); 3078c2ecf20Sopenharmony_ci wattroff(w, A_BOLD); 3088c2ecf20Sopenharmony_ci /* print legend at the bottom line */ 3098c2ecf20Sopenharmony_ci mvwprintw(w, rows - 2, 1, 3108c2ecf20Sopenharmony_ci "Legend: A=Active, P=Passive, C=Critical"); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci wrefresh(dialogue_window); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_civoid write_dialogue_win(char *buf, int y, int x) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci WINDOW *w = dialogue_window; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci mvwprintw(w, y, x, "%s", buf); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ciconst char control_title[] = " CONTROLS "; 3238c2ecf20Sopenharmony_civoid show_control_w(void) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci unsigned long state; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci get_ctrl_state(&state); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (tui_disabled || !control_window) 3308c2ecf20Sopenharmony_ci return; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci werase(control_window); 3338c2ecf20Sopenharmony_ci mvwprintw(control_window, 1, 1, 3348c2ecf20Sopenharmony_ci "PID gain: kp=%2.2f ki=%2.2f kd=%2.2f Output %2.2f", 3358c2ecf20Sopenharmony_ci p_param.kp, p_param.ki, p_param.kd, p_param.y_k); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci mvwprintw(control_window, 2, 1, 3388c2ecf20Sopenharmony_ci "Target Temp: %2.1fC, Zone: %d, Control Device: %.12s", 3398c2ecf20Sopenharmony_ci p_param.t_target, target_thermal_zone, ctrl_cdev); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* draw border last such that everything is within boundary */ 3428c2ecf20Sopenharmony_ci wborder(control_window, 0, 0, 0, 0, 0, 0, 0, 0); 3438c2ecf20Sopenharmony_ci wattron(control_window, A_BOLD); 3448c2ecf20Sopenharmony_ci mvwprintw(control_window, 0, maxx/2 - sizeof(control_title), 3458c2ecf20Sopenharmony_ci control_title); 3468c2ecf20Sopenharmony_ci wattroff(control_window, A_BOLD); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci wrefresh(control_window); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_civoid initialize_curses(void) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci if (tui_disabled) 3548c2ecf20Sopenharmony_ci return; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci initscr(); 3578c2ecf20Sopenharmony_ci start_color(); 3588c2ecf20Sopenharmony_ci keypad(stdscr, TRUE); /* enable keyboard mapping */ 3598c2ecf20Sopenharmony_ci nonl(); /* tell curses not to do NL->CR/NL on output */ 3608c2ecf20Sopenharmony_ci cbreak(); /* take input chars one at a time */ 3618c2ecf20Sopenharmony_ci noecho(); /* dont echo input */ 3628c2ecf20Sopenharmony_ci curs_set(0); /* turn off cursor */ 3638c2ecf20Sopenharmony_ci use_default_colors(); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK); 3668c2ecf20Sopenharmony_ci init_pair(PT_COLOR_HEADER_BAR, COLOR_BLACK, COLOR_WHITE); 3678c2ecf20Sopenharmony_ci init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED); 3688c2ecf20Sopenharmony_ci init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED); 3698c2ecf20Sopenharmony_ci init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW); 3708c2ecf20Sopenharmony_ci init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN); 3718c2ecf20Sopenharmony_ci init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE); 3728c2ecf20Sopenharmony_ci init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_civoid show_title_bar(void) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci int i; 3798c2ecf20Sopenharmony_ci int x = 0; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (tui_disabled || !title_bar_window) 3828c2ecf20Sopenharmony_ci return; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci wattrset(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR)); 3858c2ecf20Sopenharmony_ci wbkgd(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR)); 3868c2ecf20Sopenharmony_ci werase(title_bar_window); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci mvwprintw(title_bar_window, 0, 0, 3898c2ecf20Sopenharmony_ci " TMON v%s", VERSION); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci wrefresh(title_bar_window); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci werase(status_bar_window); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 3968c2ecf20Sopenharmony_ci if (strlen(status_bar_slots[i]) == 0) 3978c2ecf20Sopenharmony_ci continue; 3988c2ecf20Sopenharmony_ci wattron(status_bar_window, A_REVERSE); 3998c2ecf20Sopenharmony_ci mvwprintw(status_bar_window, 0, x, "%s", status_bar_slots[i]); 4008c2ecf20Sopenharmony_ci wattroff(status_bar_window, A_REVERSE); 4018c2ecf20Sopenharmony_ci x += strlen(status_bar_slots[i]) + 1; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci wrefresh(status_bar_window); 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic void handle_input_val(int ch) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci char buf[32]; 4098c2ecf20Sopenharmony_ci int val; 4108c2ecf20Sopenharmony_ci char path[256]; 4118c2ecf20Sopenharmony_ci WINDOW *w = dialogue_window; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci echo(); 4148c2ecf20Sopenharmony_ci keypad(w, TRUE); 4158c2ecf20Sopenharmony_ci wgetnstr(w, buf, 31); 4168c2ecf20Sopenharmony_ci val = atoi(buf); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (ch == ptdata.nr_cooling_dev) { 4198c2ecf20Sopenharmony_ci snprintf(buf, 31, "Invalid Temp %d! %d-%d", val, 4208c2ecf20Sopenharmony_ci MIN_CTRL_TEMP, MAX_CTRL_TEMP); 4218c2ecf20Sopenharmony_ci if (val < MIN_CTRL_TEMP || val > MAX_CTRL_TEMP) 4228c2ecf20Sopenharmony_ci write_status_bar(40, buf); 4238c2ecf20Sopenharmony_ci else { 4248c2ecf20Sopenharmony_ci p_param.t_target = val; 4258c2ecf20Sopenharmony_ci snprintf(buf, 31, "Set New Target Temp %d", val); 4268c2ecf20Sopenharmony_ci write_status_bar(40, buf); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci } else { 4298c2ecf20Sopenharmony_ci snprintf(path, 256, "%s/%s%d", THERMAL_SYSFS, 4308c2ecf20Sopenharmony_ci CDEV, ptdata.cdi[ch].instance); 4318c2ecf20Sopenharmony_ci sysfs_set_ulong(path, "cur_state", val); 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci noecho(); 4348c2ecf20Sopenharmony_ci dialogue_on = 0; 4358c2ecf20Sopenharmony_ci show_data_w(); 4368c2ecf20Sopenharmony_ci show_control_w(); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci top = (PANEL *)panel_userptr(top); 4398c2ecf20Sopenharmony_ci top_panel(top); 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic void handle_input_choice(int ch) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci char buf[48]; 4458c2ecf20Sopenharmony_ci int base = 0; 4468c2ecf20Sopenharmony_ci int cdev_id = 0; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if ((ch >= 'A' && ch <= 'A' + ptdata.nr_cooling_dev) || 4498c2ecf20Sopenharmony_ci (ch >= 'a' && ch <= 'a' + ptdata.nr_cooling_dev)) { 4508c2ecf20Sopenharmony_ci base = (ch < 'a') ? 'A' : 'a'; 4518c2ecf20Sopenharmony_ci cdev_id = ch - base; 4528c2ecf20Sopenharmony_ci if (ptdata.nr_cooling_dev == cdev_id) 4538c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "New Target Temp:"); 4548c2ecf20Sopenharmony_ci else 4558c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "New Value for %.10s-%2d: ", 4568c2ecf20Sopenharmony_ci ptdata.cdi[cdev_id].type, 4578c2ecf20Sopenharmony_ci ptdata.cdi[cdev_id].instance); 4588c2ecf20Sopenharmony_ci write_dialogue_win(buf, diag_dev_rows() + 2, 2); 4598c2ecf20Sopenharmony_ci handle_input_val(cdev_id); 4608c2ecf20Sopenharmony_ci } else { 4618c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "Invalid selection %d", ch); 4628c2ecf20Sopenharmony_ci write_dialogue_win(buf, 8, 2); 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_civoid *handle_tui_events(void *arg) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci int ch; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci keypad(cooling_device_window, TRUE); 4718c2ecf20Sopenharmony_ci while ((ch = wgetch(cooling_device_window)) != EOF) { 4728c2ecf20Sopenharmony_ci if (tmon_exit) 4738c2ecf20Sopenharmony_ci break; 4748c2ecf20Sopenharmony_ci /* when term size is too small, no dialogue panels are set. 4758c2ecf20Sopenharmony_ci * we need to filter out such cases. 4768c2ecf20Sopenharmony_ci */ 4778c2ecf20Sopenharmony_ci if (!data_panel || !dialogue_panel || 4788c2ecf20Sopenharmony_ci !cooling_device_window || 4798c2ecf20Sopenharmony_ci !dialogue_window) { 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci continue; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci pthread_mutex_lock(&input_lock); 4848c2ecf20Sopenharmony_ci if (dialogue_on) { 4858c2ecf20Sopenharmony_ci handle_input_choice(ch); 4868c2ecf20Sopenharmony_ci /* top panel filter */ 4878c2ecf20Sopenharmony_ci if (ch == 'q' || ch == 'Q') 4888c2ecf20Sopenharmony_ci ch = 0; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci switch (ch) { 4918c2ecf20Sopenharmony_ci case KEY_LEFT: 4928c2ecf20Sopenharmony_ci box(cooling_device_window, 10, 0); 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci case 9: /* TAB */ 4958c2ecf20Sopenharmony_ci top = (PANEL *)panel_userptr(top); 4968c2ecf20Sopenharmony_ci top_panel(top); 4978c2ecf20Sopenharmony_ci if (top == dialogue_panel) { 4988c2ecf20Sopenharmony_ci dialogue_on = 1; 4998c2ecf20Sopenharmony_ci show_dialogue(); 5008c2ecf20Sopenharmony_ci } else { 5018c2ecf20Sopenharmony_ci dialogue_on = 0; 5028c2ecf20Sopenharmony_ci /* force refresh */ 5038c2ecf20Sopenharmony_ci show_data_w(); 5048c2ecf20Sopenharmony_ci show_control_w(); 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci break; 5078c2ecf20Sopenharmony_ci case 'q': 5088c2ecf20Sopenharmony_ci case 'Q': 5098c2ecf20Sopenharmony_ci tmon_exit = 1; 5108c2ecf20Sopenharmony_ci break; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci update_panels(); 5138c2ecf20Sopenharmony_ci doupdate(); 5148c2ecf20Sopenharmony_ci pthread_mutex_unlock(&input_lock); 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (arg) 5188c2ecf20Sopenharmony_ci *(int *)arg = 0; /* make gcc happy */ 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return NULL; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci/* draw a horizontal bar in given pattern */ 5248c2ecf20Sopenharmony_cistatic void draw_hbar(WINDOW *win, int y, int start, int len, unsigned long ptn, 5258c2ecf20Sopenharmony_ci bool end) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci mvwaddch(win, y, start, ptn); 5288c2ecf20Sopenharmony_ci whline(win, ptn, len); 5298c2ecf20Sopenharmony_ci if (end) 5308c2ecf20Sopenharmony_ci mvwaddch(win, y, MAX_DISP_TEMP+TDATA_LEFT, ']'); 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic char trip_type_to_char(int type) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci switch (type) { 5368c2ecf20Sopenharmony_ci case THERMAL_TRIP_CRITICAL: return 'C'; 5378c2ecf20Sopenharmony_ci case THERMAL_TRIP_HOT: return 'H'; 5388c2ecf20Sopenharmony_ci case THERMAL_TRIP_PASSIVE: return 'P'; 5398c2ecf20Sopenharmony_ci case THERMAL_TRIP_ACTIVE: return 'A'; 5408c2ecf20Sopenharmony_ci default: 5418c2ecf20Sopenharmony_ci return '?'; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci/* fill a string with trip point type and value in one line 5468c2ecf20Sopenharmony_ci * e.g. P(56) C(106) 5478c2ecf20Sopenharmony_ci * maintain the distance one degree per char 5488c2ecf20Sopenharmony_ci */ 5498c2ecf20Sopenharmony_cistatic void draw_tp_line(int tz, int y) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci int j; 5528c2ecf20Sopenharmony_ci int x; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci for (j = 0; j < ptdata.tzi[tz].nr_trip_pts; j++) { 5558c2ecf20Sopenharmony_ci x = ptdata.tzi[tz].tp[j].temp / 1000; 5568c2ecf20Sopenharmony_ci mvwprintw(thermal_data_window, y + 0, x + TDATA_LEFT, 5578c2ecf20Sopenharmony_ci "%c%d", trip_type_to_char(ptdata.tzi[tz].tp[j].type), 5588c2ecf20Sopenharmony_ci x); 5598c2ecf20Sopenharmony_ci syslog(LOG_INFO, "%s:tz %d tp %d temp = %lu\n", __func__, 5608c2ecf20Sopenharmony_ci tz, j, ptdata.tzi[tz].tp[j].temp); 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ciconst char data_win_title[] = " THERMAL DATA "; 5658c2ecf20Sopenharmony_civoid show_data_w(void) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci int i; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (tui_disabled || !thermal_data_window) 5718c2ecf20Sopenharmony_ci return; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci werase(thermal_data_window); 5748c2ecf20Sopenharmony_ci wattron(thermal_data_window, A_BOLD); 5758c2ecf20Sopenharmony_ci mvwprintw(thermal_data_window, 0, maxx/2 - sizeof(data_win_title), 5768c2ecf20Sopenharmony_ci data_win_title); 5778c2ecf20Sopenharmony_ci wattroff(thermal_data_window, A_BOLD); 5788c2ecf20Sopenharmony_ci /* draw a line as ruler */ 5798c2ecf20Sopenharmony_ci for (i = 10; i < MAX_DISP_TEMP; i += 10) 5808c2ecf20Sopenharmony_ci mvwprintw(thermal_data_window, 1, i+TDATA_LEFT, "%2d", i); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci for (i = 0; i < ptdata.nr_tz_sensor; i++) { 5838c2ecf20Sopenharmony_ci int temp = trec[cur_thermal_record].temp[i] / 1000; 5848c2ecf20Sopenharmony_ci int y = 0; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci y = i * NR_LINES_TZDATA + 2; 5878c2ecf20Sopenharmony_ci /* y at tz temp data line */ 5888c2ecf20Sopenharmony_ci mvwprintw(thermal_data_window, y, 1, "%6.6s%2d:[%3d][", 5898c2ecf20Sopenharmony_ci ptdata.tzi[i].type, 5908c2ecf20Sopenharmony_ci ptdata.tzi[i].instance, temp); 5918c2ecf20Sopenharmony_ci draw_hbar(thermal_data_window, y, TDATA_LEFT, temp, ACS_RARROW, 5928c2ecf20Sopenharmony_ci true); 5938c2ecf20Sopenharmony_ci draw_tp_line(i, y); 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci wborder(thermal_data_window, 0, 0, 0, 0, 0, 0, 0, 0); 5968c2ecf20Sopenharmony_ci wrefresh(thermal_data_window); 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ciconst char tz_title[] = "THERMAL ZONES(SENSORS)"; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_civoid show_sensors_w(void) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci int i, j; 6048c2ecf20Sopenharmony_ci char buffer[512]; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if (tui_disabled || !tz_sensor_window) 6078c2ecf20Sopenharmony_ci return; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci werase(tz_sensor_window); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci memset(buffer, 0, sizeof(buffer)); 6128c2ecf20Sopenharmony_ci wattron(tz_sensor_window, A_BOLD); 6138c2ecf20Sopenharmony_ci mvwprintw(tz_sensor_window, 1, 1, "Thermal Zones:"); 6148c2ecf20Sopenharmony_ci wattroff(tz_sensor_window, A_BOLD); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci mvwprintw(tz_sensor_window, 1, TZ_LEFT_ALIGN, "%s", buffer); 6178c2ecf20Sopenharmony_ci /* fill trip points for each tzone */ 6188c2ecf20Sopenharmony_ci wattron(tz_sensor_window, A_BOLD); 6198c2ecf20Sopenharmony_ci mvwprintw(tz_sensor_window, 2, 1, "Trip Points:"); 6208c2ecf20Sopenharmony_ci wattroff(tz_sensor_window, A_BOLD); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* draw trip point from low to high for each tz */ 6238c2ecf20Sopenharmony_ci for (i = 0; i < ptdata.nr_tz_sensor; i++) { 6248c2ecf20Sopenharmony_ci int inst = ptdata.tzi[i].instance; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci mvwprintw(tz_sensor_window, 1, 6278c2ecf20Sopenharmony_ci TZ_LEFT_ALIGN+TZONE_RECORD_SIZE * inst, "%.9s%02d", 6288c2ecf20Sopenharmony_ci ptdata.tzi[i].type, ptdata.tzi[i].instance); 6298c2ecf20Sopenharmony_ci for (j = ptdata.tzi[i].nr_trip_pts - 1; j >= 0; j--) { 6308c2ecf20Sopenharmony_ci /* loop through all trip points */ 6318c2ecf20Sopenharmony_ci char type; 6328c2ecf20Sopenharmony_ci int tp_pos; 6338c2ecf20Sopenharmony_ci /* reverse the order here since trips are sorted 6348c2ecf20Sopenharmony_ci * in ascending order in terms of temperature. 6358c2ecf20Sopenharmony_ci */ 6368c2ecf20Sopenharmony_ci tp_pos = ptdata.tzi[i].nr_trip_pts - j - 1; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci type = trip_type_to_char(ptdata.tzi[i].tp[j].type); 6398c2ecf20Sopenharmony_ci mvwaddch(tz_sensor_window, 2, 6408c2ecf20Sopenharmony_ci inst * TZONE_RECORD_SIZE + TZ_LEFT_ALIGN + 6418c2ecf20Sopenharmony_ci tp_pos, type); 6428c2ecf20Sopenharmony_ci syslog(LOG_DEBUG, "draw tz %d tp %d ch:%c\n", 6438c2ecf20Sopenharmony_ci inst, j, type); 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci wborder(tz_sensor_window, 0, 0, 0, 0, 0, 0, 0, 0); 6478c2ecf20Sopenharmony_ci wattron(tz_sensor_window, A_BOLD); 6488c2ecf20Sopenharmony_ci mvwprintw(tz_sensor_window, 0, maxx/2 - sizeof(tz_title), tz_title); 6498c2ecf20Sopenharmony_ci wattroff(tz_sensor_window, A_BOLD); 6508c2ecf20Sopenharmony_ci wrefresh(tz_sensor_window); 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_civoid disable_tui(void) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci tui_disabled = 1; 6568c2ecf20Sopenharmony_ci} 657