diff --git a/src/temperature.c b/src/temperature.c index 1bf736e..331e83f 100644 --- a/src/temperature.c +++ b/src/temperature.c @@ -14,6 +14,7 @@ #include #include #include +#include #define HWMON_PATH "/sys/class/hwmon" #define THERMAL_PATH "/sys/class/thermal" @@ -451,6 +452,97 @@ static int browseTemperatureSensor(struct dmctx *dmctx, DMNODE *parent_node, voi return 0; } +static struct uci_section *get_temperature_dmmap_section(const char *instance, bool create) +{ + struct uci_section *s = NULL, *dmmap = NULL; + + uci_path_foreach_option_eq(bbfdm, "dmmap", "temperature", "temperature_instance", instance, s) + return s; + + if (!create) + return NULL; + + dmuci_add_section_bbfdm("dmmap", "temperature", &dmmap); + dmuci_set_value_by_section(dmmap, "temperature_instance", instance); + return dmmap; +} + +static int get_temperature_monitor_enable(const char *instance) +{ + char *enable = NULL; + struct uci_section *s = get_temperature_dmmap_section(instance, false); + + if (!s) + return 1; /* default enabled */ + + dmuci_get_value_by_section_string(s, "enable", &enable); + if (!enable || enable[0] == '\0') + return 1; + return (DM_STRTOL(enable) != 0); +} + +static int get_temperature_sensor_int(json_object *obj, int *temperature) +{ + const char *val; + char *endptr; + long n; + + if (!obj || !temperature) + return -1; + + val = dmjson_get_value(obj, 1, "temperature"); + if (!val || val[0] == '\0') + return -1; + + n = strtol(val, &endptr, 10); + if (endptr == val || n < INT_MIN || n > INT_MAX) + return -1; + + *temperature = (int)n; + return 0; +} + +static void update_temperature_monitor_runtime(struct dm_data *sensor_data, const char *instance) +{ + struct uci_section *s; + json_object *obj; + int temp, low_alarm = -274, high_alarm = -274; + int now = (int)time(NULL); + char *low_alarm_time = NULL, *high_alarm_time = NULL; + char buf[32]; + + if (!sensor_data || !sensor_data->json_object || !instance) + return; + + if (!get_temperature_monitor_enable(instance)) + return; + + obj = sensor_data->json_object; + if (get_temperature_sensor_int(obj, &temp) != 0) + return; + + s = get_temperature_dmmap_section(instance, true); + if (!s) + return; + + snprintf(buf, sizeof(buf), "%d", now); + dmuci_set_value_by_section(s, "last_update", buf); + + /* Low alarm timestamp: set once when threshold is crossed until explicitly reset */ + if (read_alarm_value(dmjson_get_value(obj, 1, "sysfs_path"), 1, "crit", &low_alarm) == 0 && low_alarm != -274000) { + dmuci_get_value_by_section_string(s, "low_alarm_time", &low_alarm_time); + if (temp <= (low_alarm / 1000) && (!low_alarm_time || DM_STRTOL(low_alarm_time) <= 0)) + dmuci_set_value_by_section(s, "low_alarm_time", buf); + } + + /* High alarm timestamp: set once when threshold is crossed until explicitly reset */ + if (read_alarm_value(dmjson_get_value(obj, 1, "sysfs_path"), 0, "max", &high_alarm) == 0 && high_alarm != -274000) { + dmuci_get_value_by_section_string(s, "high_alarm_time", &high_alarm_time); + if (temp >= (high_alarm / 1000) && (!high_alarm_time || DM_STRTOL(high_alarm_time) <= 0)) + dmuci_set_value_by_section(s, "high_alarm_time", buf); + } +} + /************************************************************* * GET/SET PARAMETER FUNCTIONS *************************************************************/ @@ -496,6 +588,50 @@ static int set_TemperatureSensor_alias(char *refparam, struct dmctx *ctx, void * return 0; } +static int get_TemperatureSensor_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmasprintf(value, "%d", get_temperature_monitor_enable(instance)); + return 0; +} + +static int set_TemperatureSensor_enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + bool b; + struct uci_section *s; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + s = get_temperature_dmmap_section(instance, true); + if (!s) + return FAULT_9002; + string_to_bool(value, &b); + dmuci_set_value_by_section(s, "enable", b ? "1" : "0"); + break; + } + return 0; +} + +static int get_TemperatureSensor_status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + json_object *obj = ((struct dm_data *)data)->json_object; + int temp; + + if (!get_temperature_monitor_enable(instance)) { + *value = "Disabled"; + return 0; + } + + if (get_temperature_sensor_int(obj, &temp) == 0) + *value = "Enabled"; + else + *value = "Error"; + return 0; +} + static int get_TemperatureSensor_name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { json_object *obj = ((struct dm_data *)data)->json_object; @@ -506,7 +642,58 @@ static int get_TemperatureSensor_name(char *refparam, struct dmctx *ctx, void *d static int get_TemperatureSensor_value(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { json_object *obj = ((struct dm_data *)data)->json_object; + *value = dmjson_get_value(obj, 1, "temperature"); + update_temperature_monitor_runtime((struct dm_data *)data, instance); + return 0; +} + +static int get_TemperatureSensor_last_update(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *last_update = NULL; + struct uci_section *s = get_temperature_dmmap_section(instance, false); + + if (!s) + return dm_time_utc_format(0, value); + + dmuci_get_value_by_section_string(s, "last_update", &last_update); + return dm_time_utc_format(DM_STRTOL(last_update), value); +} + +static int get_TemperatureSensor_polling_interval(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *interval = NULL; + struct uci_section *s = get_temperature_dmmap_section(instance, false); + + if (!s) { + *value = "0"; + return 0; + } + + dmuci_get_value_by_section_string(s, "polling_interval", &interval); + if (!interval || interval[0] == '\0') + *value = "0"; + else + *value = interval; + return 0; +} + +static int set_TemperatureSensor_polling_interval(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct uci_section *s; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1)) + return FAULT_9007; + break; + case VALUESET: + s = get_temperature_dmmap_section(instance, true); + if (!s) + return FAULT_9002; + dmuci_set_value_by_section(s, "polling_interval", value); + break; + } return 0; } @@ -573,8 +760,32 @@ static int get_TemperatureSensor_low_alarm_value(char *refparam, struct dmctx *c static int set_TemperatureSensor_low_alarm_value(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { + int ret; + struct uci_section *s; + /* trip_point_1_temp for thermal zones, temp*_crit for hwmon */ - return set_alarm_value_common(ctx, data, value, action, 1, "crit"); + ret = set_alarm_value_common(ctx, data, value, action, 1, "crit"); + if (ret != 0) + return ret; + + if (action == VALUESET) { + s = get_temperature_dmmap_section(instance, true); + if (s) + dmuci_set_value_by_section(s, "low_alarm_time", "0"); + } + return 0; +} + +static int get_TemperatureSensor_low_alarm_time(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *low_alarm_time = NULL; + struct uci_section *s = get_temperature_dmmap_section(instance, false); + + if (!s) + return dm_time_utc_format(0, value); + + dmuci_get_value_by_section_string(s, "low_alarm_time", &low_alarm_time); + return dm_time_utc_format(DM_STRTOL(low_alarm_time), value); } static int get_TemperatureSensor_high_alarm_value(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) @@ -598,8 +809,32 @@ static int get_TemperatureSensor_high_alarm_value(char *refparam, struct dmctx * static int set_TemperatureSensor_high_alarm_value(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { + int ret; + struct uci_section *s; + /* trip_point_0_temp for thermal zones, temp*_max for hwmon */ - return set_alarm_value_common(ctx, data, value, action, 0, "max"); + ret = set_alarm_value_common(ctx, data, value, action, 0, "max"); + if (ret != 0) + return ret; + + if (action == VALUESET) { + s = get_temperature_dmmap_section(instance, true); + if (s) + dmuci_set_value_by_section(s, "high_alarm_time", "0"); + } + return 0; +} + +static int get_TemperatureSensor_high_alarm_time(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *high_alarm_time = NULL; + struct uci_section *s = get_temperature_dmmap_section(instance, false); + + if (!s) + return dm_time_utc_format(0, value); + + dmuci_get_value_by_section_string(s, "high_alarm_time", &high_alarm_time); + return dm_time_utc_format(DM_STRTOL(high_alarm_time), value); } /****************************************************************************************************************************** @@ -608,10 +843,16 @@ static int set_TemperatureSensor_high_alarm_value(char *refparam, struct dmctx * static DMLEAF tTemperatureStatusTemperatureSensorParams[] = { /* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/ {"Alias", &DMWRITE, DMT_STRING, get_TemperatureSensor_alias, set_TemperatureSensor_alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, +{"Enable", &DMWRITE, DMT_BOOL, get_TemperatureSensor_enable, set_TemperatureSensor_enable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_TemperatureSensor_status, NULL, BBFDM_BOTH}, {"Name", &DMREAD, DMT_STRING, get_TemperatureSensor_name, NULL, BBFDM_BOTH, DM_FLAG_UNIQUE}, {"Value", &DMREAD, DMT_INT, get_TemperatureSensor_value, NULL, BBFDM_BOTH}, +{"LastUpdate", &DMREAD, DMT_TIME, get_TemperatureSensor_last_update, NULL, BBFDM_BOTH}, {"LowAlarmValue", &DMWRITE, DMT_INT, get_TemperatureSensor_low_alarm_value, set_TemperatureSensor_low_alarm_value, BBFDM_BOTH}, +{"LowAlarmTime", &DMREAD, DMT_TIME, get_TemperatureSensor_low_alarm_time, NULL, BBFDM_BOTH}, {"HighAlarmValue", &DMWRITE, DMT_INT, get_TemperatureSensor_high_alarm_value, set_TemperatureSensor_high_alarm_value, BBFDM_BOTH}, +{"PollingInterval", &DMWRITE, DMT_UNINT, get_TemperatureSensor_polling_interval, set_TemperatureSensor_polling_interval, BBFDM_BOTH}, +{"HighAlarmTime", &DMREAD, DMT_TIME, get_TemperatureSensor_high_alarm_time, NULL, BBFDM_BOTH}, {0} };