可用的文件,全部
This commit is contained in:
255
Core/Bsp/bsp_cmd.c
Normal file
255
Core/Bsp/bsp_cmd.c
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user