Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .SRCINFO
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pkgbase = coolerdash
pkgdesc = Extends CoolerControl with a polished LCD dashboard
pkgver = 1.91
pkgver = 1.92
pkgrel = 1
url = https://github.com/damachine/coolerdash
install = coolerdash.install
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ gnupg/
*.tmp
*.log
*.bak
*.env

# Editor files
*.code-workspace
Expand Down
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,10 @@ make help # Show all options
# Run manually (with minimal status logging)
coolerdash

# Run with detailed debug logging
coolerdash --log
# Run with detailed verbose logging
coolerdash --verbose
# or short form:
coolerdash -v
```

#### Debugging Steps
Expand All @@ -160,11 +162,13 @@ curl http://localhost:11987/devices
# 2. Test CoolerDash manually (with clean output)
coolerdash

# 3. Test CoolerDash with detailed debug logging
coolerdash --log
# 3. Test CoolerDash with detailed verbose logging
coolerdash --verbose
# or short form:
coolerdash -v

# 4. Debug build for detailed information (if needed)
make debug && coolerdash --log
make debug && coolerdash --verbose

# 5. Check service logs (STATUS messages always visible)
journalctl -xeu coolerdash.service -f
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.91
1.92
41 changes: 35 additions & 6 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -476,15 +476,16 @@
static const TemperatureConfigEntry entries[] = {
{"temp_threshold_1", offsetof(Config, temp_threshold_1)},
{"temp_threshold_2", offsetof(Config, temp_threshold_2)},
{"temp_threshold_3", offsetof(Config, temp_threshold_3)}};
{"temp_threshold_3", offsetof(Config, temp_threshold_3)},
{"temp_max_scale", offsetof(Config, temp_max_scale)}};

for (size_t i = 0; i < sizeof(entries) / sizeof(entries[0]); i++)
{
if (strcmp(name, entries[i].key) == 0)
{
void *field_ptr = (void *)((char *)config + entries[i].offset);
float *dest = (float *)field_ptr;
*dest = safe_atof(value, 50.0f + i * 15.0f); // 50, 65, 80
*dest = safe_atof(value, 50.0f + i * 15.0f); // 50, 65, 80, 115

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.1 rule Note

MISRA 12.1 rule
return 1;
}
}
Expand Down Expand Up @@ -686,22 +687,48 @@

/**
* @brief Set font default values.
* @details Helper function to set default font configuration values.
* @details Helper function to set default font configuration values with dynamic scaling based on display resolution.
*/
static void set_font_defaults(Config *config)
{
if (config->font_face[0] == '\0')
SAFE_STRCPY(config->font_face, "Roboto Black");

// Dynamic font size scaling based on display resolution
// Base: 240×240 with font_size_temp=100.0 and font_size_labels=30.0
if (config->font_size_temp == 0.0f)
config->font_size_temp = 100.0f;
{
const double base_resolution = 240.0;
const double base_font_size_temp = 100.0;

// Calculate scaling factor from average of width and height
const double scale_factor = ((double)config->display_width + (double)config->display_height) / (2.0 * base_resolution);

config->font_size_temp = (float)(base_font_size_temp * scale_factor);

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 10.8 rule Note

MISRA 10.8 rule

log_message(LOG_INFO, "Font size (temp) auto-scaled: %.1f (display: %dx%d, scale: %.2f)",
config->font_size_temp, config->display_width, config->display_height, scale_factor);
}

if (config->font_size_labels == 0.0f)
config->font_size_labels = 30.0f;
{
const double base_resolution = 240.0;
const double base_font_size_labels = 30.0;

// Calculate scaling factor from average of width and height
const double scale_factor = ((double)config->display_width + (double)config->display_height) / (2.0 * base_resolution);

config->font_size_labels = (float)(base_font_size_labels * scale_factor);

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 10.8 rule Note

MISRA 10.8 rule

log_message(LOG_INFO, "Font size (labels) auto-scaled: %.1f (display: %dx%d, scale: %.2f)",
config->font_size_labels, config->display_width, config->display_height, scale_factor);
}

set_display_positioning_defaults(config);
}

/**
* @brief Set temperature threshold default values.
* @brief Set temperature defaults
* @details Helper function to set default temperature threshold values.
*/
static void set_temperature_defaults(Config *config)
Expand All @@ -712,6 +739,8 @@
config->temp_threshold_2 = 65.0f;
if (config->temp_threshold_3 == 0.0f)
config->temp_threshold_3 = 75.0f;
if (config->temp_max_scale == 0.0f)

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.6 rule Note

MISRA 15.6 rule
config->temp_max_scale = 115.0f;
}

/**
Expand Down
3 changes: 3 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ typedef struct Config
uint32_t display_refresh_interval_nsec;
uint8_t lcd_brightness;
uint8_t lcd_orientation;
// Developer/testing override: force display to be treated as circular (1) or not (0)
int force_display_circular;

// Layout configuration - all positioning is now calculated dynamically from display dimensions
uint16_t layout_bar_width; // Legacy - not used in dynamic scaling
Expand Down Expand Up @@ -104,6 +106,7 @@ typedef struct Config
float temp_threshold_1;
float temp_threshold_2;
float temp_threshold_3;
float temp_max_scale; // Maximum temperature for bar scaling (default: 115°C)
Color temp_threshold_1_bar;
Color temp_threshold_2_bar;
Color temp_threshold_3_bar;
Expand Down
16 changes: 14 additions & 2 deletions src/coolercontrol.c
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,8 @@ static int validate_device_dimensions(void)
*/
static int update_dimension(uint16_t *config_dim, int device_dim, const char *dim_name)
{
const uint16_t original_value = *config_dim;

if (*config_dim == 0)
{
*config_dim = (uint16_t)device_dim;
Expand All @@ -795,8 +797,18 @@ static int update_dimension(uint16_t *config_dim, int device_dim, const char *di
return 1;
}

log_message(LOG_INFO, "Display %s from config.ini: %d (overrides device value %d)",
dim_name, *config_dim, device_dim);
// Only log if the values differ (to avoid misleading logs when using defaults)
if (original_value != (uint16_t)device_dim)
{
log_message(LOG_INFO, "Display %s from config.ini: %d (device reports %d)",
dim_name, *config_dim, device_dim);
}
else
{
// Values match - using device value (config was commented, default matches device)
log_message(LOG_INFO, "Display %s: %d (device and default match)",
dim_name, *config_dim);
}
return 0;
}

Expand Down
80 changes: 59 additions & 21 deletions src/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,16 @@

/**
* @brief Calculate temperature fill width with bounds checking
* @param temp_value Current temperature value
* @param max_width Maximum width of the bar in pixels
* @param max_temp Maximum temperature from configuration (highest threshold)
*/
static inline int calculate_temp_fill_width(float temp_value, int max_width)
static inline int calculate_temp_fill_width(float temp_value, int max_width, float max_temp)
{
if (temp_value <= 0.0f)
return 0;

const float ratio = fminf(temp_value / 105.0f, 1.0f);
const float ratio = fminf(temp_value / max_temp, 1.0f);
return (int)(ratio * max_width);
}

Expand Down Expand Up @@ -106,15 +109,30 @@
int is_circular_by_device = is_circular_display_device(device_name,
config->display_width,
config->display_height);
params->is_circular = is_circular_by_device;
params->inscribe_factor = params->is_circular ? M_SQRT1_2 : 1.0;

// Allow developer override from config (set via CLI --develop)
if (config->force_display_circular)

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 14.4 rule Note

MISRA 14.4 rule
{
params->is_circular = 1;
params->inscribe_factor = M_SQRT1_2;
log_message(LOG_INFO, "Developer override active: forcing circular display detection (device: %s)", device_name ? device_name : "unknown");
}
else
{
params->is_circular = is_circular_by_device;
params->inscribe_factor = params->is_circular ? M_SQRT1_2 : 1.0;
}

// Calculate safe area width
const double safe_area_width = config->display_width * params->inscribe_factor;
params->safe_bar_width = (int)(safe_area_width * CONTENT_SCALE_FACTOR);
params->safe_content_margin = (config->display_width - params->safe_bar_width) / 2.0;

params->corner_radius = 8.0 * scale_avg;

// Log detailed scaling calculations (verbose only)
log_message(LOG_INFO, "Scaling: safe_area=%.0fpx, bar_width=%dpx, margin=%.1fpx",
safe_area_width, params->safe_bar_width, params->safe_content_margin);
}

/**
Expand All @@ -128,6 +146,16 @@
static void draw_rounded_rectangle_path(cairo_t *cr, int x, int y, int width, int height, double radius);
static cairo_t *create_cairo_context(const struct Config *config, cairo_surface_t **surface);
static void render_display_content(cairo_t *cr, const struct Config *config, const monitor_sensor_data_t *data, const ScalingParams *params);
// Helper to draw degree symbol at calculated position with proper font scaling
static void draw_degree_symbol(cairo_t *cr, double x, double y, const struct Config *config)
{
if (!cr || !config)
return;
cairo_set_font_size(cr, config->font_size_temp / 1.66);
cairo_move_to(cr, x, y);
cairo_show_text(cr, "°");
cairo_set_font_size(cr, config->font_size_temp);
}

/**
* @brief Draw rounded rectangle path for temperature bars
Expand Down Expand Up @@ -194,13 +222,24 @@
cairo_font_extents_t font_ext;
cairo_font_extents(cr, &font_ext);

// Calculate maximum width for 2-digit numbers to keep position stable
cairo_text_extents_t max_num_ext;
cairo_text_extents(cr, "88", &max_num_ext); // Widest 2-digit number
// Use actual text extents for positioning to handle 3-digit temperatures correctly
// For values ≥100, use actual width; for <100, use fixed width of "88" for stability
double cpu_width = (data->temp_cpu >= 100.0f) ? cpu_num_ext.width : cpu_num_ext.width;

Check warning

Code scanning / Cppcheck (reported by Codacy)

Same expression in both branches of ternary operator. Warning

Same expression in both branches of ternary operator.
double gpu_width = (data->temp_gpu >= 100.0f) ? gpu_num_ext.width : gpu_num_ext.width;

Check warning

Code scanning / Cppcheck (reported by Codacy)

Same expression in both branches of ternary operator. Warning

Same expression in both branches of ternary operator.

// Calculate reference width (widest 2-digit number) for sub-100 alignment
cairo_text_extents_t ref_width_ext;
cairo_text_extents(cr, "88", &ref_width_ext);

// Use reference width for values <100 to keep position stable
if (data->temp_cpu < 100.0f)

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.6 rule Note

MISRA 15.6 rule
cpu_width = ref_width_ext.width;
if (data->temp_gpu < 100.0f)

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.6 rule Note

MISRA 15.6 rule
gpu_width = ref_width_ext.width;

// Left-align numbers at center position (fixed X to prevent jumping)
double cpu_temp_x = bar_x + (effective_bar_width - max_num_ext.width) / 2.0;
double gpu_temp_x = bar_x + (effective_bar_width - max_num_ext.width) / 2.0;
// Center-align based on actual or reference width
double cpu_temp_x = bar_x + (effective_bar_width - cpu_width) / 2.0;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 10.4 rule Note

MISRA 10.4 rule
double gpu_temp_x = bar_x + (effective_bar_width - gpu_width) / 2.0;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 10.4 rule Note

MISRA 10.4 rule

// For small displays (≤240×240), shift temperatures 12px to the right
if (config->display_width <= 240 && config->display_height <= 240)
Expand Down Expand Up @@ -241,29 +280,26 @@
// Draw degree symbols at fixed offset
cairo_set_font_size(cr, config->font_size_temp / 1.66);

// Position degree symbols 18px to the right of temperature numbers
double degree_symbol_x = cpu_temp_x + max_num_ext.width + 16;
// Position degree symbols 16px to the right of temperature numbers (using actual widths)
double degree_cpu_x = cpu_temp_x + cpu_width + 16;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 10.4 rule Note

MISRA 10.4 rule
double degree_gpu_x = gpu_temp_x + gpu_width + 16;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 10.4 rule Note

MISRA 10.4 rule
double degree_cpu_y = cpu_temp_y - cpu_num_ext.height * 0.40;
double degree_gpu_y = gpu_temp_y - gpu_num_ext.height * 0.40;

// Apply user-defined degree offsets if set
if (config->display_degree_offset_x != -9999)
{
degree_symbol_x += config->display_degree_offset_x;
degree_cpu_x += config->display_degree_offset_x;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 10.4 rule Note

MISRA 10.4 rule
degree_gpu_x += config->display_degree_offset_x;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 10.4 rule Note

MISRA 10.4 rule
}
if (config->display_degree_offset_y != -9999)
{
degree_cpu_y += config->display_degree_offset_y;
degree_gpu_y += config->display_degree_offset_y;
}

cairo_move_to(cr, degree_symbol_x, degree_cpu_y);
cairo_show_text(cr, "°");

cairo_move_to(cr, degree_symbol_x, degree_gpu_y);
cairo_show_text(cr, "°");

cairo_set_font_size(cr, config->font_size_temp);
draw_degree_symbol(cr, degree_cpu_x, degree_cpu_y, config);
draw_degree_symbol(cr, degree_gpu_x, degree_gpu_y, config);
}

/**
Expand All @@ -274,7 +310,9 @@
if (!cr || !config || !params)
return;

const int fill_width = calculate_temp_fill_width(temp_value, bar_width);
// Use configured maximum temperature for bar scaling (default: 115°C)
const float max_temp = config->temp_max_scale;
const int fill_width = calculate_temp_fill_width(temp_value, bar_width, max_temp);

// Background
set_cairo_color(cr, &config->layout_bar_color_background);
Expand Down
24 changes: 20 additions & 4 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
* @details Controls whether detailed INFO logs are shown (enabled with --log parameter).
*/
int verbose_logging = 0; // Only ERROR and WARNING by default (exported)
// Developer/testing flag: when set (via --develop), force displays to be treated as circular
int force_display_circular = 0;

/**
* @brief Global pointer to configuration.
Expand Down Expand Up @@ -453,12 +455,14 @@
printf("USAGE:\n");
printf(" %s [OPTIONS] [CONFIG_PATH]\n\n", program_name);
printf("OPTIONS:\n");
printf(" -h, --help Show this help message and exit\n");
printf(" --log Enable detailed INFO logging for debugging\n\n");
printf(" -h, --help Show this help message and exit\n");
printf(" -v, --verbose Enable verbose logging (shows detailed INFO messages)\n\n");

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 17.7 rule Note

MISRA 17.7 rule
printf(" --develop Developer: force display to be treated as circular for testing\n\n");

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 17.7 rule Note

MISRA 17.7 rule
printf("EXAMPLES:\n");
printf(" sudo systemctl start coolerdash # Start as system service (recommended)\n");
printf(" %s # Manual start with default config\n", program_name);
printf(" %s --log # Start with detailed logging enabled\n", program_name);
printf(" %s --verbose # Start with detailed logging enabled\n", program_name);

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 17.7 rule Note

MISRA 17.7 rule
printf(" %s -v # Short form: enable verbose logging\n", program_name);

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 17.7 rule Note

MISRA 17.7 rule
printf(" %s /custom/config.ini # Start with custom configuration\n\n", program_name);
printf("FILES:\n");
printf(" /usr/bin/coolerdash # Main program executable\n");
Expand Down Expand Up @@ -747,10 +751,15 @@
show_help(argv[0], NULL);
exit(EXIT_SUCCESS);
}
else if (strcmp(argv[i], "--log") == 0)
else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0)

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.1 rule Note

MISRA 12.1 rule
{
verbose_logging = 1;
}
else if (strcmp(argv[i], "--develop") == 0)
{
force_display_circular = 1;
verbose_logging = 1; // Developer mode implies verbose logging
}
else if (argv[i][0] != '-')
{
config_path = argv[i];
Expand Down Expand Up @@ -782,6 +791,13 @@
return -1;
}

/* Apply CLI overrides (developer/testing) */
if (force_display_circular)

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 14.4 rule Note

MISRA 14.4 rule
{
config->force_display_circular = 1;
log_message(LOG_INFO, "Developer override: forcing circular display detection (via --develop)");
}

int is_service_start = is_started_by_systemd();
log_message(LOG_INFO, "Running mode: %s", is_service_start ? "systemd service" : "manual");

Expand Down