可用的文件,全部

This commit is contained in:
2026-03-21 01:49:41 +08:00
commit da4f00f652
56 changed files with 9299 additions and 0 deletions

255
Core/Bsp/bsp_cmd.c Normal file
View File

@@ -0,0 +1,255 @@
/**
* @file bsp_cmd.c
* @brief JSON command parser - receives JSON, executes command, returns JSON via UART1
*/
#include "bsp_cmd.h"
#include "bsp_relay.h"
#include "bsp_uart.h"
#include "bsp_flash.h"
#include "cJSON.h"
#include <string.h>
#include <stdio.h>
/**
* @brief Send JSON response via UART1
*/
static void send_response(cJSON *root)
{
char *json_str = cJSON_PrintUnformatted(root);
if (json_str != NULL)
{
BSP_UART1_SendString(json_str);
BSP_UART1_SendString("\r\n");
cJSON_free(json_str);
}
cJSON_Delete(root);
}
/**
* @brief Make a simple {"status":"ok","msg":"xxx"} response
*/
static void respond_ok(const char *msg)
{
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "status", "ok");
cJSON_AddStringToObject(root, "msg", msg);
send_response(root);
}
/**
* @brief Make a {"status":"error","msg":"xxx"} response
*/
static void respond_error(const char *msg)
{
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "status", "error");
cJSON_AddStringToObject(root, "msg", msg);
send_response(root);
}
/**
* @brief Process JSON command
*
* Supported commands:
* {"cmd":"status"}
* {"cmd":"fan_mode","value":"auto"} or "manual"
* {"cmd":"fan_threshold","value":30.0}
* {"cmd":"fan","value":"on"} or "off"
* {"cmd":"light","value":"on"} or "off"
* {"cmd":"reset"}
*/
void BSP_Cmd_ProcessJSON(const uint8_t *buf, uint16_t len)
{
cJSON *root = NULL;
cJSON *cmd_item = NULL;
cJSON *val_item = NULL;
if (buf == NULL || len == 0)
{
respond_error("empty input");
return;
}
/* Ensure null termination and strip non-JSON prefix/suffix */
char tmp[256];
if (len >= sizeof(tmp))
len = sizeof(tmp) - 1;
memcpy(tmp, buf, len);
tmp[len] = '\0';
/* Find the first '{' to skip any MQTT topic prefix */
char *json_start = strchr(tmp, '{');
if (json_start == NULL)
{
respond_error("no json found");
return;
}
/* Find matching '}' to trim trailing garbage */
char *json_end = json_start;
int depth = 0;
while (*json_end != '\0')
{
if (*json_end == '{') depth++;
else if (*json_end == '}') depth--;
if (depth == 0) { json_end++; break; }
json_end++;
}
*json_end = '\0';
/* Parse JSON */
root = cJSON_Parse(json_start);
if (root == NULL)
{
respond_error("invalid json");
return;
}
/* Get "cmd" field */
cmd_item = cJSON_GetObjectItemCaseSensitive(root, "cmd");
if (cmd_item == NULL || !cJSON_IsString(cmd_item))
{
respond_error("missing cmd field");
cJSON_Delete(root);
return;
}
const char *cmd = cmd_item->valuestring;
/* Get "value" field (optional) */
val_item = cJSON_GetObjectItemCaseSensitive(root, "value");
/* --- STATUS --- */
if (strcasecmp(cmd, "status") == 0)
{
system_state_t state;
BSP_System_GetState(&state);
cJSON *resp = cJSON_CreateObject();
cJSON_AddStringToObject(resp, "status", "ok");
cJSON *data = cJSON_CreateObject();
cJSON_AddStringToObject(data, "fan_mode", state.fan_mode == FAN_MODE_AUTO ? "auto" : "manual");
cJSON_AddNumberToObject(data, "fan_threshold", state.fan_threshold);
cJSON_AddStringToObject(data, "fan", state.fan_state ? "on" : "off");
cJSON_AddStringToObject(data, "light", state.light_state ? "on" : "off");
cJSON_AddItemToObject(resp, "data", data);
send_response(resp);
}
/* --- FAN MODE --- */
else if (strcasecmp(cmd, "fan_mode") == 0)
{
if (val_item == NULL || !cJSON_IsString(val_item))
{
respond_error("missing value");
}
else
{
const char *val = val_item->valuestring;
if (strcasecmp(val, "auto") == 0)
{
BSP_FAN_SetMode(FAN_MODE_AUTO);
respond_ok("fan mode set to auto");
}
else if (strcasecmp(val, "manual") == 0)
{
BSP_FAN_SetMode(FAN_MODE_MANUAL);
respond_ok("fan mode set to manual");
}
else
{
respond_error("invalid fan_mode value");
}
}
}
/* --- FAN THRESHOLD --- */
else if (strcasecmp(cmd, "fan_threshold") == 0)
{
if (val_item == NULL || !cJSON_IsNumber(val_item))
{
respond_error("missing or invalid value");
}
else
{
float thresh = (float)val_item->valuedouble;
if (thresh > 0 && thresh < 100)
{
BSP_FAN_SetThreshold(thresh);
respond_ok("fan threshold updated");
}
else
{
respond_error("threshold out of range");
}
}
}
/* --- FAN ON/OFF --- */
else if (strcasecmp(cmd, "fan") == 0)
{
if (val_item == NULL || !cJSON_IsString(val_item))
{
respond_error("missing value");
}
else
{
const char *val = val_item->valuestring;
if (strcasecmp(val, "on") == 0)
{
BSP_FAN_SetMode(FAN_MODE_MANUAL);
BSP_FAN_On();
respond_ok("fan on");
}
else if (strcasecmp(val, "off") == 0)
{
BSP_FAN_SetMode(FAN_MODE_MANUAL);
BSP_FAN_Off();
respond_ok("fan off");
}
else
{
respond_error("invalid fan value");
}
}
}
/* --- LIGHT ON/OFF --- */
else if (strcasecmp(cmd, "light") == 0)
{
if (val_item == NULL || !cJSON_IsString(val_item))
{
respond_error("missing value");
}
else
{
const char *val = val_item->valuestring;
if (strcasecmp(val, "on") == 0)
{
BSP_LIGHT_On();
respond_ok("light on");
}
else if (strcasecmp(val, "off") == 0)
{
BSP_LIGHT_Off();
respond_ok("light off");
}
else
{
respond_error("invalid light value");
}
}
}
/* --- RESET --- */
else if (strcasecmp(cmd, "reset") == 0)
{
BSP_Flash_ResetSettings();
respond_ok("settings reset to default");
}
/* --- UNKNOWN --- */
else
{
respond_error("unknown command");
}
cJSON_Delete(root);
}