Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for custom layout on OLED screens. #50

Merged
merged 2 commits into from
Aug 17, 2023
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
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ endif()

target_compile_options(fanpico PRIVATE -Wall)
target_compile_definitions(fanpico PRIVATE USBD_MANUFACTURER="TJKO Industries")
target_compile_definitions(fanpico PRIVATE USBD_PRODUCT="FanPico-${FANPICO_BOARD}")
target_compile_definitions(fanpico PRIVATE USBD_PRODUCT="FanPico-${FANPICO_BOARD} Fan Controller")
target_compile_definitions(fanpico PRIVATE USBD_DESC_STR_MAX=32)
target_compile_definitions(fanpico PRIVATE PARAM_ASSERTIONS_ENABLE_ALL=1)
target_compile_definitions(fanpico PRIVATE PICO_MALLOC_PANIC=0)
target_compile_definitions(fanpico PRIVATE PICO_DEBUG_MALLOC=0)
Expand Down
48 changes: 47 additions & 1 deletion commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@ Fanpico supports following commands:
* [SYStem:SYSLOG?](#systemsyslog-1)
* [SYStem:DISPlay](#systemdisplay)
* [SYStem:DISPlay?](#systemdisplay)
* [SYStem:DISPlay:LAYOUTR](#systemdisplaylayoutr)
* [SYStem:DISPlay:LAYOUTR?](#systemdisplaylayoutr-1)
* [SYStem:DISPlay:THEMe](#systemdisplaytheme)
* [SYStem:DISPlay:THEME?](#systemdisplaytheme-1)
* [SYStem:DISPlay:THEMe?](#systemdisplaytheme-1)
* [SYStem:ECHO](#systemecho)
* [SYStem:ECHO?](#systemecho)
* [SYStem:FANS?](#systemfans)
Expand Down Expand Up @@ -1423,6 +1425,50 @@ SYS:DISP?
132x64,flip,invert,brightness=75
```

#### SYStem:DISPlay:LAYOUTR
Configure (OLED) Display layout for the right side of the screen.

Layout is specified as a comma delimited string descibing what to
display on each row (8 rows available if using 128x64 OLEd module, 10 rows available with 128x128 pixel modules).

Syntax: <R1>,<R2>,...<R8>

Wehre tow specifications can be one of the following:

Type|Description|Notes
----|-----------|-----
Mn|MBFan input n|n=1..4
Sn|Sensor input n|n=1..3
Vn|Virtual Sensor input n|n=1..8
-|Horizontal Line|
Ltext|Line with "text"|Max lenght 9 characters.


Default: <not set>

When this setting is not set following defaults are used based
on the OLED module size:

Screen Size|Available Rows|Default Configuration
-----------|--------------|---------------------
128x64|8|M1,M2,M3,M4,-,S1,S2,S3
128x128|10|LMB Inputs,M1,M2,M3,M4,-,LSensors,S1,S2,S3

Example: configure custom theme (for 128x64 display):
```
SYS:DISP:LAYOUTR M1,M2,-,S1,S2,S3,V1,V2
```

#### SYStem:DISPlay:THEMe?
Display currently configured (OLED) Display layout for the right side of the screen.

Example:
```
SYS:DISP:THEME?
M1,M2,-,S1,S2,S3,V1,V2
```


#### SYStem:DISPlay:THEMe
Configure (LCD) Display theme to use.

Expand Down
11 changes: 11 additions & 0 deletions src/command.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,16 @@ int cmd_display_theme(const char *cmd, const char *args, int query, char *prev_c
return 0;
}

int cmd_display_layout_r(const char *cmd, const char *args, int query, char *prev_cmd)
{
if (query) {
printf("%s\n", conf->display_layout_r);
} else {
strncopy(conf->display_layout_r, args, sizeof(conf->display_layout_r));
}
return 0;
}

int cmd_reset(const char *cmd, const char *args, int query, char *prev_cmd)
{
const char *msg[] = {
Expand Down Expand Up @@ -1989,6 +1999,7 @@ int cmd_spi(const char *cmd, const char *args, int query, char *prev_cmd)

struct cmd_t display_commands[] = {
{ "THEMe", 4, NULL, cmd_display_theme },
{ "LAYOUTR", 4, NULL, cmd_display_layout_r },
{ 0, 0, 0, 0 }
};
struct cmd_t wifi_commands[] = {
Expand Down
7 changes: 7 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ void clear_config(struct fanpico_config *cfg)
strncopy(cfg->name, "fanpico1", sizeof(cfg->name));
strncopy(cfg->display_type, "default", sizeof(cfg->display_type));
strncopy(cfg->display_theme, "default", sizeof(cfg->display_theme));
strncopy(cfg->display_layout_r, "", sizeof(cfg->display_layout_r));
#ifdef WIFI_SUPPORT
cfg->wifi_ssid[0] = 0;
cfg->wifi_passwd[0] = 0;
Expand Down Expand Up @@ -465,6 +466,8 @@ cJSON *config_to_json(const struct fanpico_config *cfg)
cJSON_AddItemToObject(config, "display_type", cJSON_CreateString(cfg->display_type));
if (strlen(cfg->display_theme) > 0)
cJSON_AddItemToObject(config, "display_theme", cJSON_CreateString(cfg->display_theme));
if (strlen(cfg->display_layout_r) > 0)
cJSON_AddItemToObject(config, "display_layout_r", cJSON_CreateString(cfg->display_layout_r));
if (strlen(cfg->name) > 0)
cJSON_AddItemToObject(config, "name", cJSON_CreateString(cfg->name));

Expand Down Expand Up @@ -644,6 +647,10 @@ int json_to_config(cJSON *config, struct fanpico_config *cfg)
if ((val = cJSON_GetStringValue(ref)))
strncopy(cfg->display_theme, val, sizeof(cfg->display_theme));
}
if ((ref = cJSON_GetObjectItem(config, "display_layout_r"))) {
if ((val = cJSON_GetStringValue(ref)))
strncopy(cfg->display_layout_r, val, sizeof(cfg->display_layout_r));
}
if ((ref = cJSON_GetObjectItem(config, "name"))) {
if ((val = cJSON_GetStringValue(ref)))
strncopy(cfg->name, val, sizeof(cfg->name));
Expand Down
177 changes: 138 additions & 39 deletions src/display_oled.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,90 @@

#ifdef OLED_DISPLAY

enum layout_item_types {
BLANK = 0,
LABEL = 1,
LINE = 2,
MBFAN = 3,
SENSOR = 4,
VSENSOR = 5,
};

struct layout_item {
enum layout_item_types type;
uint8_t idx;
const char *label;
};

#define R_LAYOUT_MAX 10

static SSOLED oled;
static uint8_t ucBuffer[(128*128)/8];
static uint8_t oled_width = 128;
static uint8_t oled_height = 64;
static uint8_t oled_found = 0;
static uint8_t r_lines = 8;
static struct layout_item r_layout[R_LAYOUT_MAX];


/* Default screen layouts for inputs/sensors */
#define R_LAYOUT_128x64 "M1,M2,M3,M4,-,S1,S2,S3"
#define R_LAYOUT_128x128 "LMB Inputs,M1,M2,M3,M4,-,LSensors,S1,S2,S3"


void parse_r_layout(const char *layout)
{
int i;
char *tok, *saveptr, *tmp;

for (i = 0; i < R_LAYOUT_MAX; i++) {
r_layout[i].type = BLANK;
r_layout[i].idx = 0;
r_layout[i].label = NULL;
}

if (!layout)
return;

tmp = strdup(layout);
if (!tmp)
return;

log_msg(LOG_DEBUG, "parse OLED right layout: '%s", tmp);

i = 0;
tok = strtok_r(tmp, ",", &saveptr);
while (tok && i < r_lines) {
switch (tok[0]) {
case '-':
r_layout[i].type = LINE;
break;
case 'L':
r_layout[i].type = LABEL;
r_layout[i].idx = strlen(tok) - 1;
r_layout[i].label = layout + (tok - tmp) + 1;
break;
case 'M':
r_layout[i].type = MBFAN;
r_layout[i].idx = clamp_int(atoi(tok + 1), 1, MBFAN_COUNT) - 1;
break;
case 'S':
r_layout[i].type = SENSOR;
r_layout[i].idx = clamp_int(atoi(tok + 1), 1, SENSOR_COUNT) - 1;
break;
case 'V':
r_layout[i].type = VSENSOR;
r_layout[i].idx = clamp_int(atoi(tok + 1), 1, VSENSOR_COUNT) - 1;
break;

};

tok = strtok_r(NULL, ",", &saveptr);
i++;
}

free(tmp);
}


void oled_display_init()
Expand All @@ -63,6 +142,7 @@ void oled_display_init()
if (!strncmp(tok, "128x128", 7)) {
dtype = OLED_128x128;
oled_height = 128;
r_lines = 10;
}
else if (!strncmp(tok, "invert", 6))
invert = 1;
Expand All @@ -81,6 +161,12 @@ void oled_display_init()
}
}

if (strlen(cfg->display_layout_r) > 1) {
parse_r_layout(cfg->display_layout_r);
} else {
parse_r_layout(r_lines == 8 ? R_LAYOUT_128x64 : R_LAYOUT_128x128);
}

disp_brightness = (brightness / 100.0) * 255;
log_msg(LOG_DEBUG, "Set display brightness: %u%% (0x%x)\n",
brightness, disp_brightness);
Expand Down Expand Up @@ -156,60 +242,73 @@ void oled_display_status(const struct fanpico_state *state,
if (!oled_found || !state)
return;

int h_pos = 70;
int fan_row_offset = (oled_height > 64 ? 1 : 0);

if (!bg_drawn) {
/* Draw "background" only once... */
oled_clear_display();

if (oled_height > 64) {
oledWriteString(&oled, 0, 0, 0, "Fans", FONT_6x8, 0, 1);
oledWriteString(&oled, 0, 74, 0, "MB Inputs", FONT_6x8, 0, 1);
oledWriteString(&oled, 0, 74, 6, "Sensors", FONT_6x8, 0, 1);
oledDrawLine(&oled, 72, 44, oled_width - 1, 44, 1);
oledDrawLine(&oled, 72, 0, 72, 79, 1);
} else {
oledDrawLine(&oled, 70, 35, oled_width - 1, 35, 1);
oledDrawLine(&oled, 70, 0, 70, 63, 1);
}

for (i = 0; i < r_lines; i++) {
struct layout_item *l = &r_layout[i];
char label[16];
int y = i * 8;

if (l->type == LINE) {
oledDrawLine(&oled, h_pos, y + 4, oled_width - 1, y + 4, 1);
}
else if (l->type == LABEL) {
int len = l->idx;
if (len >= sizeof(label))
len = sizeof(label) - 1;
memcpy(label, l->label, len);
label[len] = 0;
oledWriteString(&oled, 0, h_pos + 2, i, label, FONT_6x8, 0, 1);
}
}
oledDrawLine(&oled, h_pos, 0, h_pos, r_lines * 8 - 1, 1);
bg_drawn = 1;
}

if (oled_height <= 64) {
for (i = 0; i < FAN_COUNT; i++) {
rpm = state->fan_freq[i] * 60 / conf->fans[i].rpm_factor;
pwm = state->fan_duty[i];
snprintf(buf, sizeof(buf), "%d:%4.0lf %3.0lf%%", i + 1, rpm, pwm);
oledWriteString(&oled, 0 , 0, i, buf, FONT_6x8, 0, 1);

for (i = 0; i < FAN_COUNT; i++) {
rpm = state->fan_freq[i] * 60 / conf->fans[i].rpm_factor;
pwm = state->fan_duty[i];
snprintf(buf, sizeof(buf), "%d:%4.0lf %3.0lf%%", i + 1, rpm, pwm);
oledWriteString(&oled, 0 , 0, i + fan_row_offset, buf, FONT_6x8, 0, 1);
}
for (i = 0; i < r_lines; i++) {
struct layout_item *l = &r_layout[i];
int write_buf = 0;

if (l->type == MBFAN) {
pwm = state->mbfan_duty[l->idx];
snprintf(buf, sizeof(buf), "%d: %4.0lf%% ", l->idx + 1, pwm);
write_buf = 1;
}
else if (l->type == SENSOR) {
temp = state->temp[l->idx];
snprintf(buf, sizeof(buf), "s%d:%5.1lfC", l->idx + 1, temp);
write_buf = 1;
}
for (i = 0; i < MBFAN_COUNT; i++) {
pwm = state->mbfan_duty[i];
snprintf(buf, sizeof(buf), "%d: %4.0lf%% ", i + 1, pwm);
oledWriteString(&oled, 0 , 74, i + 0, buf, FONT_6x8, 0, 1);
else if (l->type == VSENSOR) {
temp = state->vtemp[l->idx];
snprintf(buf, sizeof(buf), "v%d:%5.1lfC", l->idx + 1, temp);
write_buf = 1;
}
for (i = 0; i < SENSOR_COUNT; i++) {
temp = state->temp[i];
snprintf(buf, sizeof(buf), "%d:%5.1lfC ", i + 1, temp);
if (i == 2) {
if (write_buf) {
if (oled_height <= 64 && i == 0) {
buf[8] = (counter++ % 2 == 0 ? '*' : ' ');
}
oledWriteString(&oled, 0 , 74, i + 5, buf, FONT_6x8, 0, 1);
oledWriteString(&oled, 0 , h_pos + 2, i, buf, FONT_6x8, 0, 1);
}
}
else {
for (i = 0; i < FAN_COUNT; i++) {
rpm = state->fan_freq[i] * 60 / conf->fans[i].rpm_factor;
pwm = state->fan_duty[i];
snprintf(buf, sizeof(buf), "%d:%4.0lf %3.0lf%% ", i + 1, rpm, pwm);
oledWriteString(&oled, 0 , 0, i + 1, buf, FONT_6x8, 0, 1);
}
for (i = 0; i < MBFAN_COUNT; i++) {
pwm = state->mbfan_duty[i];
snprintf(buf, sizeof(buf), "%d: %4.0lf%% ", i + 1, pwm);
oledWriteString(&oled, 0 , 78, i + 1, buf, FONT_6x8, 0, 1);
}
for (i = 0; i < SENSOR_COUNT; i++) {
temp = state->temp[i];
snprintf(buf, sizeof(buf), "%d:%5.1lfC ", i + 1, temp);
oledWriteString(&oled, 0 , 78, i + 7, buf, FONT_6x8, 0, 1);
}

if (oled_height > 64) {
/* IP */
const char *ip = network_ip();
if (ip) {
Expand Down
2 changes: 2 additions & 0 deletions src/fanpico.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ struct fanpico_config {
uint8_t led_mode;
char display_type[64];
char display_theme[16];
char display_layout_r[64];
char name[32];
bool spi_active;
bool serial_active;
Expand Down Expand Up @@ -362,6 +363,7 @@ struct tm *datetime_to_tm(const datetime_t *t, struct tm *tm);
time_t datetime_to_time(const datetime_t *datetime);
void watchdog_disable();
int getstring_timeout_ms(char *str, uint32_t maxlen, uint32_t timeout);
int clamp_int(int val, int min, int max);

/* crc32.c */
unsigned int xcrc32 (const unsigned char *buf, int len, unsigned int init);
Expand Down
13 changes: 13 additions & 0 deletions src/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,4 +436,17 @@ int getstring_timeout_ms(char *str, uint32_t maxlen, uint32_t timeout)
return res;
}


int clamp_int(int val, int min, int max)
{
int res = val;

if (res < min)
res = min;
if (res > max)
res = max;

return res;
}

/* eof */