Files
BR_YKC/Core/User/Task/ChargerTask.c

290 lines
8.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "ChargerTask.h"
static struct netconn *datalink_conn; // 数据链路句柄
#define LINK_SERVER_PORT 6001 // 网关UDP服务端口
#define LINK_STAKE_PORT 6001 // 桩通讯端口
/**
* @brief 桩IP地址
* @note 桩IP地址从10.12.19.101开始递增
*/
ip4_addr_t stake_ip_1 = IPADDR4_INIT_BYTES(10, 12, 19, 101); // 桩1IP地址
ip4_addr_t stake_ip_2 = IPADDR4_INIT_BYTES(10, 12, 19, 102); // 桩2IP地址
ip4_addr_t stake_ip_3 = IPADDR4_INIT_BYTES(10, 12, 19, 103); // 桩3IP地址
ip4_addr_t stake_ip_4 = IPADDR4_INIT_BYTES(10, 12, 19, 104); // 桩4IP地址
ip4_addr_t stake_ip_5 = IPADDR4_INIT_BYTES(10, 12, 19, 105); // 桩5IP地址
ip4_addr_t stake_ip_6 = IPADDR4_INIT_BYTES(10, 12, 19, 106); // 桩6IP地址
/**
* @brief UDP发送
* @note 发送数据到指定桩
* @param stake_index 目标桩ID
* @param data 数据指针
* @param len 数据长度
* @return err_t 错误码
*/
err_t udp_send_response(uint8_t stake_index, uint8_t *data, u16_t len)
{
struct netbuf *buf = netbuf_new();
if (!buf)
{
printf("[%s] %d\n", __func__, __LINE__);
return ERR_MEM;
}
ip4_addr_t *dst_ip = NULL;
switch (stake_index)
{
case 1:
dst_ip = &stake_ip_1;
break;
case 2:
dst_ip = &stake_ip_2;
break;
case 3:
dst_ip = &stake_ip_3;
break;
case 4:
dst_ip = &stake_ip_4;
break;
case 5:
dst_ip = &stake_ip_5;
break;
case 6:
dst_ip = &stake_ip_6;
break;
default:
printf("Invalid stake index\r\n");
return;
}
netbuf_ref(buf, data, len);
err_t err = netconn_sendto(datalink_conn, buf, dst_ip, LINK_STAKE_PORT);
netbuf_delete(buf);
return err;
}
void UDP_ParseTask_Function(void const *argument)
{
UdpMsg_t msg;
cJSON *root = NULL, *cmd = NULL, *id = NULL;
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); /* 等待桩通讯协议层完成*/
while (1)
{
if (xQueueReceive(UDP_Message_Queue, &msg, portMAX_DELAY) == pdPASS)
{
root = cJSON_Parse((const char *)msg.data);
if (root == NULL)
{
printf("JSON Parse Failed: %s\r\n", msg.data);
vPortFree(msg.data);
continue;
}
id = cJSON_GetObjectItem(root, "id");
cmd = cJSON_GetObjectItem(root, "cmd");
if (cmd != NULL && id != NULL)
{
const char *cmd_str = cmd->valuestring;
handle_udp_downlink((uint8_t)id->valueint, cmd_str, root);
cJSON_Delete(root);
}
else
{
printf("Missing 'code' field from \r\n");
cJSON_Delete(root);
}
vPortFree(msg.data);
msg.data = NULL;
}
}
}
/**
* @brief UPLinkTask_Function桩通讯任务
*
* @note none
*
* @param taskID : 任务ID
*
* @retval runtime : 任务周期
*/
void UDPTask_Function(void const *argument)
{
err_t recv_err;
struct netbuf *datalink_buf = NULL;
datalink_conn = netconn_new(NETCONN_UDP);
netconn_bind(datalink_conn, IP_ADDR_ANY, LINK_SERVER_PORT);
UDP_Message_Queue_Init(); // 初始化UDP接收队列
/*桩UDP通讯初始化完成 发送云快充任务通知*/
xTaskNotifyGive(YkcTaskHandle);
xTaskNotifyGive(DownLinkTaskHandle);
xTaskNotifyGive(UDP_ParseTaskHandle);
while (1)
{
/*获取任务运行状态*/
TaskRunTimeStat.UPLinkTask.threads_runtime = GetTask_RunTime(UPLinkTaskID);
TaskRunTimeStat.UPLinkTask.threads_counter = GetTask_Beatcnt(UPLinkTaskID);
TaskRunTimeStat.UPLinkTask.threads_freestack = Get_Free_Stack(UPLinkTaskID);
recv_err = netconn_recv(datalink_conn, &datalink_buf);
if (recv_err == ERR_OK && datalink_buf != NULL)
{
uint8_t *playload;
uint16_t playload_len;
netbuf_data(datalink_buf, (void *)&playload, &playload_len);
if (playload_len > 0)
{
UdpMsg_t msg;
ip_addr_copy(msg.src_ip, *netbuf_fromaddr(datalink_buf)); // 获取UDP源IP
msg.src_port = netbuf_fromport(datalink_buf); // 获取UDP源端口
msg.len = playload_len;
msg.data = (char *)pvPortMalloc(playload_len + 1);
if (msg.data != NULL)
{
memcpy(msg.data, playload, playload_len);
msg.data[playload_len] = '\0';
// 队列满,释放数据内存
if (xQueueSend(UDP_Message_Queue, &msg, 0) != pdPASS)
{
vPortFree(msg.data);
}
}
}
netbuf_delete(datalink_buf); // 释放UDP网络缓冲区
}
else
{
if (recv_err != ERR_TIMEOUT && recv_err != ERR_WOULDBLOCK)
{
printf("datalink netconn_recv err: %d\r\n", recv_err);
}
}
}
}
/**
* @brief 解析充电桩上电指令
* @note 设置桩为本地在线状态,发送上电应答
* @param stake_index 桩索引
* @param json_pack json数据包
*/
void local_on_cmd_callback_power_on(uint8_t stake_index, cJSON *json_pack)
{
if (stake_index > 6)
{
return;
}
g_charger_manager.charger_piles[stake_index - 1].is_udp_online = true; // 设置桩为本地在线状态
cJSON *root = NULL;
uint8_t *str = NULL;
root = cJSON_CreateObject();
if (root == NULL)
{
printf("Failed to create JSON object for stake %d\r\n", stake_index);
return;
}
/* 添加一条字符串类型的JSON数据(添加一个链表节点) */
cJSON_AddNumberToObject(root, "id", stake_index);
cJSON_AddStringToObject(root, "cmd", "online");
cJSON_AddStringToObject(root, "type", "response");
str = cJSON_Print(root);
udp_send_response(stake_index, str, strlen(str));
free(str);
cJSON_Delete(root);
printf("南向:对电桩 %d 上电回复成功\r\n", stake_index);
}
/**
* @brief 解析充电桩心跳指令
* @note 回复心跳应答
* @param stake_index 桩索引
* @param json_pack json数据包
*/
void local_on_cmd_callback_heartbeat_response(uint8_t stake_index, cJSON *json_pack)
{
if (stake_index > 6)
{
return;
}
//心跳unpack
cJSON *gun_array = cJSON_GetObjectItem(json_pack, "gun");
// 直接判断 type 字段
if (gun_array == NULL || gun_array->type != cJSON_Array)
{
printf(" └── [error] 缺少 gun 数组\r\n");
return;
}
int gun_count = cJSON_GetArraySize(gun_array);
for (int i = 0; i < gun_count; i++)
{
cJSON *gun = cJSON_GetArrayItem(gun_array, i);
if (!gun) continue;
cJSON *id = cJSON_GetObjectItem(gun, "id");
cJSON *state = cJSON_GetObjectItem(gun, "state");
if (!id || !state) continue;
// if (id->valueint == 1) pile->gun1_state = state->valueint;
// if (id->valueint == 2) pile->gun2_state = state->valueint;
printf(" └── [info] 桩%d 枪%d state=%d\r\n", stake_index, id->valueint, state->valueint);
}
//心跳回复组包
cJSON *root = NULL;
char *str = NULL;
root = cJSON_CreateObject();
if (root == NULL)
{
printf("Failed to create JSON object for stake %d\r\n", stake_index);
return;
}
/* 添加一条字符串类型的JSON数据(添加一个链表节点) */
cJSON_AddNumberToObject(root, "id", stake_index);
cJSON_AddStringToObject(root, "cmd", "heartbeat");
cJSON_AddStringToObject(root, "type", "response");
str = cJSON_Print(root);
udp_send_response(stake_index, str, strlen(str));
free(str);
cJSON_Delete(root);
printf("南向:对电桩 %d 心跳回复成功\r\n", stake_index);
}
void handle_udp_downlink(uint8_t id, const char *cmd, cJSON *json_pack)
{
if (cmd == NULL)
return;
// 处理上电指令
if (strcmp(cmd, "online") == 0)
{
printf("南向:收到电桩 %d 上电指令\r\n", id);
local_on_cmd_callback_power_on(id, json_pack);
}
// 处理心跳指令
else if (strcmp(cmd, "heartbeat") == 0)
{
printf("南向:收到电桩 %d 心跳指令\r\n", id);
local_on_cmd_callback_heartbeat_response(id, json_pack);
}
else
{
printf("Unknown CMD: '%s' from ID %d\r\n", cmd, id);
}
}