Add current limit configuration for VIN, MAIN, and USB

- Integrated current limit settings in `nconfig`.
- Enabled API support for managing current limits.
- Added UI components for configuring current limits.
- Implemented backend logic for handling validations and updates.

Signed-off-by: YoungSoo Shin <shinys000114@gmail.com>
This commit is contained in:
2025-09-04 12:26:31 +09:00
parent 679f8d297c
commit 7b8ba3e12b
13 changed files with 374 additions and 60 deletions

View File

@@ -58,6 +58,13 @@ menu "ODROID-MONITOR"
help
GPIO number for LED.
config GPIO_EXPANDER_RESET
int "Trigger reset GPIO Num"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 8
help
GPIO number for Reset expander.
config EXPANDER_GPIO_SW_12V
int "12v Load Switch GPIO Num"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX

View File

@@ -39,6 +39,9 @@ enum nconfig_type
NETIF_DNS2, ///< The secondary DNS server address.
NETIF_TYPE, ///< The network interface type (e.g., "dhcp" or "static").
UART_BAUD_RATE, ///< The baud rate for the UART communication.
VIN_CURRENT_LIMIT, ///< The maximum current limit for the VIN.
MAIN_CURRENT_LIMIT, ///< The maximum current limit for the MAIN out.
USB_CURRENT_LIMIT, ///< The maximum current limit for the USB out.
NCONFIG_TYPE_MAX, ///< Sentinel for the maximum number of configuration types.
};

View File

@@ -10,10 +10,22 @@
static nvs_handle_t handle;
const static char* keys[NCONFIG_TYPE_MAX] = {
[WIFI_SSID] = "wifi_ssid", [WIFI_PASSWORD] = "wifi_pw", [WIFI_MODE] = "wifi_mode", [AP_SSID] = "ap_ssid",
[AP_PASSWORD] = "ap_pw", [NETIF_HOSTNAME] = "hostname", [NETIF_IP] = "ip", [NETIF_GATEWAY] = "gw",
[NETIF_SUBNET] = "sn", [NETIF_DNS1] = "dns1", [NETIF_DNS2] = "dns2", [NETIF_TYPE] = "dhcp",
[WIFI_SSID] = "wifi_ssid",
[WIFI_PASSWORD] = "wifi_pw",
[WIFI_MODE] = "wifi_mode",
[AP_SSID] = "ap_ssid",
[AP_PASSWORD] = "ap_pw",
[NETIF_HOSTNAME] = "hostname",
[NETIF_IP] = "ip",
[NETIF_GATEWAY] = "gw",
[NETIF_SUBNET] = "sn",
[NETIF_DNS1] = "dns1",
[NETIF_DNS2] = "dns2",
[NETIF_TYPE] = "dhcp",
[UART_BAUD_RATE] = "baudrate",
[VIN_CURRENT_LIMIT] = "vin_climit",
[MAIN_CURRENT_LIMIT] = "main_climit",
[USB_CURRENT_LIMIT] = "usb_climit",
};
struct default_value
@@ -33,6 +45,9 @@ struct default_value const default_values[] = {
{WIFI_MODE, "apsta"},
{AP_SSID, "odroid-pm"},
{AP_PASSWORD, "powermate"},
{VIN_CURRENT_LIMIT, "8.0"},
{MAIN_CURRENT_LIMIT, "7.0"},
{USB_CURRENT_LIMIT, "5.0"},
};
esp_err_t init_nconfig()

21
main/service/climit.h Normal file
View File

@@ -0,0 +1,21 @@
//
// Created by shinys on 25. 9. 4..
//
#ifndef ODROID_POWER_MATE_CLIMIT_H
#define ODROID_POWER_MATE_CLIMIT_H
#include "esp_err.h"
#include <stdbool.h>
#define VIN_CURRENT_LIMIT_MAX 8.0f
#define MAIN_CURRENT_LIMIT_MAX 7.0f
#define USB_CURRENT_LIMIT_MAX 5.0f
esp_err_t climit_set_vin(double value);
esp_err_t climit_set_main(double value);
esp_err_t climit_set_usb(double value);
bool is_overcurrent();
#endif // ODROID_POWER_MATE_CLIMIT_H

View File

@@ -3,27 +3,44 @@
//
#include "monitor.h"
#include <nconfig.h>
#include <time.h>
#include "climit.h"
#include "datalog.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_timer.h"
#include "esp_wifi_types_generic.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h" // Added for FreeRTOS tasks
#include "ina3221.h"
#include "pb.h"
#include "pb_encode.h"
#include "status.pb.h"
#include "sw.h"
#include "webserver.h"
#include "wifi.h"
#define CHANNEL_VIN INA3221_CHANNEL_3
#define CHANNEL_MAIN INA3221_CHANNEL_2
#define CHANNEL_USB INA3221_CHANNEL_1
#define PM_SDA CONFIG_I2C_GPIO_SDA
#define PM_SCL CONFIG_I2C_GPIO_SCL
#define PM_INT_CRITICAL CONFIG_GPIO_INA3221_INT_CRITICAL
#define PM_EXPANDER_RST CONFIG_GPIO_EXPANDER_RESET
#define PB_BUFFER_SIZE 256
static const char* TAG = "monitor";
static esp_timer_handle_t sensor_timer;
static esp_timer_handle_t wifi_status_timer;
// static esp_timer_handle_t shutdown_load_sw; // No longer needed
static TaskHandle_t shutdown_task_handle = NULL; // Global task handle
ina3221_t ina3221 = {
.shunt = {10, 10, 10},
.mask.mask_register = INA3221_DEFAULT_MASK,
@@ -138,12 +155,92 @@ static void status_wifi_callback(void* arg)
send_pb_message(StatusMessage_fields, &message);
}
static esp_timer_handle_t sensor_timer;
static esp_timer_handle_t wifi_status_timer;
// New FreeRTOS task for shutdown logic
static void shutdown_load_sw_task(void* pvParameters)
{
while (1)
{
// Wait indefinitely for a notification from the ISR
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
ESP_LOGW(TAG, "critical interrupt triggered (via task)");
gpio_set_level(PM_EXPANDER_RST, 0);
vTaskDelay(100 / portTICK_PERIOD_MS);
gpio_set_level(PM_EXPANDER_RST, 1);
config_sw();
}
}
static void IRAM_ATTR critical_isr_handler(void* arg)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (shutdown_task_handle != NULL)
{
vTaskNotifyGiveFromISR(shutdown_task_handle, &xHigherPriorityTaskWoken);
}
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
static void gpio_init()
{
// critical int
gpio_set_intr_type(PM_INT_CRITICAL, GPIO_INTR_NEGEDGE);
gpio_set_direction(PM_INT_CRITICAL, GPIO_MODE_INPUT);
gpio_install_isr_service(0);
gpio_isr_handler_add(PM_INT_CRITICAL, critical_isr_handler, (void*)PM_INT_CRITICAL);
// rst expander
gpio_set_level(PM_EXPANDER_RST, 1);
gpio_set_direction(PM_EXPANDER_RST, GPIO_MODE_OUTPUT);
}
esp_err_t climit_set_vin(double value)
{
float lim = (float)(value * 1000);
ESP_LOGI(TAG, "Setting VIN current limit to: %fmA", lim);
if (value > 0.0f)
return ina3221_set_critical_alert(&ina3221, CHANNEL_VIN, lim);
return ina3221_set_critical_alert(&ina3221, CHANNEL_VIN, (15.0f * 1000.0f));
}
esp_err_t climit_set_main(double value)
{
float lim = (float)(value * 1000);
ESP_LOGI(TAG, "Setting MAIN current limit to: %fmA", lim);
if (value > 0.0f)
return ina3221_set_critical_alert(&ina3221, CHANNEL_MAIN, lim);
return ina3221_set_critical_alert(&ina3221, CHANNEL_VIN, (15.0f * 1000.0f));
}
esp_err_t climit_set_usb(double value)
{
float lim = (float)(value * 1000);
ESP_LOGI(TAG, "Setting USB current limit to: %fmA", lim);
if (value > 0.0f)
return ina3221_set_critical_alert(&ina3221, CHANNEL_USB, lim);
return ina3221_set_critical_alert(&ina3221, CHANNEL_VIN, (15.0f * 1000.0f));
}
void init_status_monitor()
{
gpio_init();
ESP_ERROR_CHECK(ina3221_init_desc(&ina3221, 0x40, 0, PM_SDA, PM_SCL));
double lim;
char buf[10];
nconfig_read(VIN_CURRENT_LIMIT, buf, sizeof(buf));
lim = atof(buf);
climit_set_vin(lim);
nconfig_read(MAIN_CURRENT_LIMIT, buf, sizeof(buf));
lim = atof(buf);
climit_set_main(lim);
nconfig_read(USB_CURRENT_LIMIT, buf, sizeof(buf));
lim = atof(buf);
climit_set_usb(lim);
datalog_init();
const esp_timer_create_args_t sensor_timer_args = {.callback = &sensor_timer_callback,
@@ -153,6 +250,8 @@ void init_status_monitor()
ESP_ERROR_CHECK(esp_timer_create(&sensor_timer_args, &sensor_timer));
ESP_ERROR_CHECK(esp_timer_create(&wifi_timer_args, &wifi_status_timer));
xTaskCreate(shutdown_load_sw_task, "shutdown_sw_task", configMINIMAL_STACK_SIZE * 3, NULL, 15, &shutdown_task_handle);
ESP_ERROR_CHECK(esp_timer_start_periodic(sensor_timer, 1000000));
ESP_ERROR_CHECK(esp_timer_start_periodic(wifi_status_timer, 1000000 * 5));
}

View File

@@ -1,10 +1,11 @@
#include <stdlib.h>
#include "cJSON.h"
#include "climit.h"
#include "esp_http_server.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_timer.h"
#include "nconfig.h"
#include "system.h"
#include "webserver.h"
#include "wifi.h"
@@ -15,31 +16,42 @@ static esp_err_t setting_get_handler(httpd_req_t* req)
wifi_ap_record_t ap_info;
cJSON* root = cJSON_CreateObject();
char mode_buf[16];
if (nconfig_read(WIFI_MODE, mode_buf, sizeof(mode_buf)) == ESP_OK)
char buf[16];
if (nconfig_read(WIFI_MODE, buf, sizeof(buf)) == ESP_OK)
{
cJSON_AddStringToObject(root, "mode", mode_buf);
cJSON_AddStringToObject(root, "mode", buf);
}
else
{
cJSON_AddStringToObject(root, "mode", "sta"); // Default to sta
}
char net_type_buf[16];
if (nconfig_read(NETIF_TYPE, net_type_buf, sizeof(net_type_buf)) == ESP_OK)
if (nconfig_read(NETIF_TYPE, buf, sizeof(buf)) == ESP_OK)
{
cJSON_AddStringToObject(root, "net_type", net_type_buf);
cJSON_AddStringToObject(root, "net_type", buf);
}
else
{
cJSON_AddStringToObject(root, "net_type", "dhcp"); // Default to dhcp
}
// Add baudrate to the response
char baud_buf[16];
if (nconfig_read(UART_BAUD_RATE, baud_buf, sizeof(baud_buf)) == ESP_OK)
if (nconfig_read(UART_BAUD_RATE, buf, sizeof(buf)) == ESP_OK)
{
cJSON_AddStringToObject(root, "baudrate", baud_buf);
cJSON_AddStringToObject(root, "baudrate", buf);
}
// Add current limits to the response
if (nconfig_read(VIN_CURRENT_LIMIT, buf, sizeof(buf)) == ESP_OK)
{
cJSON_AddNumberToObject(root, "vin_current_limit", atof(buf));
}
if (nconfig_read(MAIN_CURRENT_LIMIT, buf, sizeof(buf)) == ESP_OK)
{
cJSON_AddNumberToObject(root, "main_current_limit", atof(buf));
}
if (nconfig_read(USB_CURRENT_LIMIT, buf, sizeof(buf)) == ESP_OK)
{
cJSON_AddNumberToObject(root, "usb_current_limit", atof(buf));
}
if (wifi_get_current_ap_info(&ap_info) == ESP_OK)
@@ -143,6 +155,9 @@ static esp_err_t setting_post_handler(httpd_req_t* req)
cJSON* net_type_item = cJSON_GetObjectItem(root, "net_type");
cJSON* ssid_item = cJSON_GetObjectItem(root, "ssid");
cJSON* baud_item = cJSON_GetObjectItem(root, "baudrate");
cJSON* vin_climit_item = cJSON_GetObjectItem(root, "vin_current_limit");
cJSON* main_climit_item = cJSON_GetObjectItem(root, "main_current_limit");
cJSON* usb_climit_item = cJSON_GetObjectItem(root, "usb_current_limit");
if (mode_item && cJSON_IsString(mode_item))
{
@@ -253,6 +268,41 @@ static esp_err_t setting_post_handler(httpd_req_t* req)
change_baud_rate(strtol(baudrate, NULL, 10));
httpd_resp_sendstr(req, "{\"status\":\"baudrate_updated\"}");
}
else if (vin_climit_item || main_climit_item || usb_climit_item)
{
char num_buf[10];
if (vin_climit_item && cJSON_IsNumber(vin_climit_item))
{
double val = vin_climit_item->valuedouble;
if (val >= 0.0 && val <= VIN_CURRENT_LIMIT_MAX)
{
snprintf(num_buf, sizeof(num_buf), "%.2f", val);
nconfig_write(VIN_CURRENT_LIMIT, num_buf);
climit_set_vin(val);
}
}
if (main_climit_item && cJSON_IsNumber(main_climit_item))
{
double val = main_climit_item->valuedouble;
if (val >= 0.0 && val <= MAIN_CURRENT_LIMIT_MAX)
{
snprintf(num_buf, sizeof(num_buf), "%.2f", val);
nconfig_write(MAIN_CURRENT_LIMIT, num_buf);
climit_set_main(val);
}
}
if (usb_climit_item && cJSON_IsNumber(usb_climit_item))
{
double val = usb_climit_item->valuedouble;
if (val >= 0.0 && val <= USB_CURRENT_LIMIT_MAX)
{
snprintf(num_buf, sizeof(num_buf), "%.2f", val);
nconfig_write(USB_CURRENT_LIMIT, num_buf);
climit_set_usb(val);
}
}
httpd_resp_sendstr(req, "{\"status\":\"current_limit_updated\"}");
}
else
{
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid payload");

View File

@@ -54,9 +54,8 @@ static void trigger_off_callback(void* arg)
xSemaphoreGive(expander_mutex);
}
void init_sw()
void config_sw()
{
ESP_ERROR_CHECK(pca9557_init_desc(&pca, 0x18, I2C_PORT, GPIO_SDA, GPIO_SCL));
ESP_ERROR_CHECK(pca9557_set_mode(&pca, GPIO_MAIN, PCA9557_MODE_OUTPUT));
ESP_ERROR_CHECK(pca9557_set_mode(&pca, GPIO_USB, PCA9557_MODE_OUTPUT));
ESP_ERROR_CHECK(pca9557_set_mode(&pca, GPIO_PWR, PCA9557_MODE_OUTPUT));
@@ -70,6 +69,13 @@ void init_sw()
load_switch_12v_status = val != 0 ? true : false;
ESP_ERROR_CHECK(pca9557_get_level(&pca, CONFIG_EXPANDER_GPIO_SW_5V, &val));
load_switch_5v_status = val != 0 ? true : false;
}
void init_sw()
{
ESP_ERROR_CHECK(pca9557_init_desc(&pca, 0x18, I2C_PORT, GPIO_SDA, GPIO_SCL));
config_sw();
const esp_timer_create_args_t power_timer_args = {
.callback = &trigger_off_callback, .arg = (void*)GPIO_PWR, .name = "power_trigger_off"};

View File

@@ -7,6 +7,7 @@
#include <stdbool.h>
void init_sw();
void config_sw();
void trig_power();
void trig_reset();
void set_main_load_switch(bool on);

View File

@@ -86,5 +86,6 @@ void start_webserver(void)
register_wifi_endpoint(server);
register_ws_endpoint(server);
register_control_endpoint(server);
register_reboot_endpoint(server);
init_status_monitor();
}