1. 修改apps/chrg/applications/utils/chrg_sink.c: - 调整寄存器数组长度,新增继电器控制相关的初始化配置 - 在放电初始化前先关闭所有功率板继电器 2. 修改apps/chrg/applications/thread/chrg_north.c: - 修复变量类型不匹配问题,将uint8_t改为rt_uint8_t - 新增参数合法性校验逻辑,避免空指针和越界访问 - 新增电压状态标记,仅在电压有效后才将低压视为故障 - 修复无符号整数溢出问题,避免电压差值计算异常 - 优化电流异常时的状态机切换逻辑 - 非工作状态下重置所有状态标记
752 lines
21 KiB
C
752 lines
21 KiB
C
/****************************************************************************
|
||
文件名称 : chrg_north.c
|
||
完成日期 :
|
||
当前版本号 : V1.0
|
||
主要功能 : 实现北向通信交互,包括接收命令解析,发送请求命令,切换通路。以独立线程处理。
|
||
版本历史 : 创建原始版本
|
||
说明 :
|
||
******************************************************************************/
|
||
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <rtthread.h>
|
||
#include "chrg_eload.h"
|
||
#include "chrg_gpio.h"
|
||
#include "chrg_thread.h"
|
||
#include "chrg_north_pkg.h"
|
||
#include "chrg_north.h"
|
||
#include "chrg_roll_nor.h"
|
||
#include "chrg_switch.h"
|
||
#include "chrg_utils.h"
|
||
#include "ulog.h"
|
||
#include "chrg_rel.h"
|
||
//#define LOG_TAG "chrg.nor"
|
||
#define DBG_LEVEL DBG_LOG
|
||
#include <rtdbg.h>
|
||
rt_uint16_t volt;
|
||
uint16_t chrg_compare(rt_int16_t a, rt_int16_t b)
|
||
{
|
||
if(a>b) return a - b;
|
||
else return b - a;
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: chrg_source_stop
|
||
功能描述: 南向功率源停止流程控制函数(分步执行停止操作)
|
||
函数描述: 通过状态机分步执行南向功率停止流程:停止功率输出 -> 关闭北向继电器 -> 清空控制标志并禁用使能
|
||
输入参数:
|
||
frame_data :原始数据帧指针,用于提取当前电压值
|
||
pSW :北向通道控制结构体指针
|
||
idx :通道编号(功率通道/北向通道索引)
|
||
enable :北向通道使能,停止后关掉使能
|
||
返回说明: 无返回值
|
||
*****************************************************************/
|
||
void chrg_source_stop(rt_uint8_t *frame_data,struct chrg_switch_t *pSW,rt_uint8_t idx,rt_uint8_t *enable){
|
||
switch(pSW->source.Stop_step_flag){
|
||
case 0: // 停止工作
|
||
chrg_set_sou_reg((eIDX_SOU_CH)idx, REG_WORK, WORK_STOP);
|
||
rt_thread_mdelay(50);
|
||
rt_uint16_t volt_mv_Now = (frame_data[4] << 8) | frame_data[5];
|
||
volt = volt_mv_Now;
|
||
if(volt_mv_Now < 1000){
|
||
pSW->source.Stop_step_flag = 1;
|
||
}
|
||
break;
|
||
case 1: // 关闭北向继电器
|
||
chrg_nor_sw_rel((eIDX_NOR_CH)idx,0);
|
||
rt_thread_mdelay(50);
|
||
pSW->source.Stop_step_flag = 2;
|
||
break;
|
||
case 2: // 状态2:已执行完停止操作,清空标志位
|
||
pSW->source.Set_CV_Flag = 0;
|
||
*enable = 0;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: chrg_source_standard_output
|
||
功能描述: 南向功率源标准输出控制函数
|
||
函数描述: 根据CV标志位,分别设置电源输出电压或输出电流,实现标准模式下的恒压/恒流输出
|
||
输入参数:
|
||
idx :功率通道编号
|
||
pSW :北向通道控制结构体指针,包含电压/电流设定值、CV控制标志等参数
|
||
输出参数:
|
||
pSW :更新CV控制标志位
|
||
返回说明: 无返回值
|
||
*****************************************************************/
|
||
void chrg_source_standard_output(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||
{
|
||
if(pSW->source.Set_CV_Flag) {
|
||
chrg_set_sou_reg((eIDX_SOU_CH)idx, REG_VOLTAGE_OUT+1, pSW->source.max_vol);
|
||
#if DEBUG_NORTH
|
||
rt_kprintf("Volt_Set%d\r\n",pSW->source.vc.set_voltage);
|
||
#endif
|
||
pSW->source.Set_CV_Flag = 1;
|
||
pSW->change_flag = 0;
|
||
}
|
||
// if(pSW->source.Set_CV_Flag==0){
|
||
// chrg_set_sou_reg((eIDX_SOU_CH)idx, REG_CURRENT_OUT+1, pSW->source.max_vol);
|
||
//#if DEBUG_NORTH
|
||
// rt_kprintf("Curr_set%d\r\n",Curr_mA);
|
||
//#endif
|
||
// pSW->source.Set_CV_Flag = 0;
|
||
// }
|
||
}
|
||
|
||
//电源快充
|
||
void chrg_source_fast_output(rt_uint8_t *frame_data, eIDX_SOU_CH idx,
|
||
struct chrg_switch_t *pSW, struct chrg_north_t *pNOR)
|
||
{
|
||
struct chrg_rollsou_t *pROLL = &chrgrollsou;
|
||
rt_uint16_t volt_mv = (frame_data[8] << 8) | frame_data[9];
|
||
rt_uint16_t Curr_mA = (frame_data[10] << 8) | frame_data[11];
|
||
rt_uint16_t volt_mv_Now = (frame_data[4] << 8) | frame_data[5];
|
||
rt_uint16_t Curr_mA_Now = (frame_data[6] << 8) | frame_data[7];
|
||
rt_uint16_t volt_compare = chrg_compare(volt_mv, volt_mv_Now);
|
||
rt_uint16_t Curr_compare = chrg_compare(Curr_mA, Curr_mA_Now);
|
||
static rt_uint8_t number = 0;
|
||
#if LCD_OPEN
|
||
// rt_kprintf("volt_mv=%d,volt_mv_Now=%d,compare=%d\r\n",volt_mv,volt_mv_Now,volt_compare);
|
||
if(volt_compare<5000){ //比较设定值与实际值差距,小于2V认为达成设定,允许屏幕开始变换
|
||
number++;
|
||
number = number%10;
|
||
if(number == 9)
|
||
{
|
||
pSW->change_flag = 0;
|
||
}
|
||
}else { //没有达成设定,屏幕不允许变换
|
||
pSW->change_flag = 0x01;
|
||
}
|
||
#endif
|
||
// if(volt_mv_Now==0){
|
||
// chrg_set_sou_reg((eIDX_SOU_CH)idx, REG_WORK, WORK_START);
|
||
// }
|
||
// else{
|
||
if (pSW->source.Set_CV_Flag == 0){
|
||
{
|
||
chrg_set_sou_reg((eIDX_SOU_CH)idx, REG_VOLTAGE_OUT+1, volt_mv);
|
||
}
|
||
pSW->source.Set_CV_Flag = 1;
|
||
#if DEBUG_NORTH
|
||
rt_kprintf("Volt_Set%d\r\n",volt_mv);
|
||
#endif
|
||
}
|
||
else if(pSW->source.Set_CV_Flag==1){
|
||
chrg_set_sou_reg((eIDX_SOU_CH)idx, REG_WORK, WORK_START);
|
||
pSW->source.Set_CV_Flag = 0;
|
||
}else{
|
||
pSW->source.Set_CV_Flag=0;
|
||
}
|
||
}
|
||
|
||
//电源设置
|
||
void chrg_source_setting(rt_uint8_t *frame_data, eIDX_SOU_CH idx,
|
||
struct chrg_switch_t *pSW, struct chrg_north_t *pNOR)
|
||
{
|
||
//执行输出调整
|
||
if (pSW->source.On_Flag == 1) {
|
||
if(pSW->source.protocol==0x00){//标准下输出设定值
|
||
chrg_source_standard_output(idx, pSW);
|
||
}
|
||
else{ //快充部分按协商结果输出
|
||
chrg_source_fast_output(frame_data, idx, pSW, pNOR);
|
||
// rt_kprintf("set_end\r\n");
|
||
}
|
||
}else if(pSW->source.On_Flag == 0){
|
||
//chrg_source_stop(frame_data,pSW,idx,&pNOR->enable[idx]);
|
||
pSW->sub = IDX_SET_SOURCE_STOP_STATE;
|
||
}
|
||
}
|
||
////解析负载返回数据
|
||
//void chrg_sink_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx,
|
||
// struct chrg_switch_t *pSW, struct chrg_north_t *pNOR)
|
||
//{
|
||
// rt_uint16_t volt_mv = ((frame_data[4] << 8) | frame_data[5])*10;
|
||
// static uint8_t volt_low[TOTAL_SOU_CHS] = {0};
|
||
// static uint8_t no_curr[TOTAL_SOU_CHS] = {0};
|
||
// pSW->VZ = ((frame_data[14] << 8) | frame_data[15]);
|
||
// pSW->VF = ((frame_data[16] << 8) | frame_data[17]);
|
||
|
||
//#if DEBUG_NORTH
|
||
// LOG_D("Sink[%d] real volt: %d mV", idx, volt_mv);
|
||
//#endif
|
||
//
|
||
// if(pSW->sink.On_work == 1) {
|
||
// if(pSW->sink.test.test_mode == 0){
|
||
// if (volt_mv <= WORK_MIN_VOLT) { // 电压过低,禁止进入工作状态机
|
||
// volt_low[idx]++;
|
||
// //if(volt_low[idx]>=5) pSW->sink.work_mode = SINK_WORK_LOW; // 复位工作状态机
|
||
// }
|
||
// else{ // 电压稳定时执行工作状态机(继电器/工作模式切换)
|
||
// volt_low[idx] = 0;
|
||
// pSW->change_flag = 0;
|
||
// if((pSW->sink.pro_loadv - volt_mv) <= 2000){
|
||
// pSW->sink.work_mode = SINK_WORK_RUNING;
|
||
// if(pSW->Now_current<=200){
|
||
// if(no_curr[idx]++>=5){
|
||
// pSW->sink.work_mode = SINK_WORK_WAIT;
|
||
// no_curr[idx] = 0;
|
||
// }
|
||
// }
|
||
// else no_curr[idx] = 0;
|
||
// }
|
||
// }
|
||
// }
|
||
// }
|
||
// else{
|
||
// volt_low[idx] = 0;
|
||
//// pSW->sink.work_mode = SINK_WORK_STOP;
|
||
// }
|
||
// chrg_sink_work(idx,pSW);
|
||
//}
|
||
|
||
//解析负载返回数据
|
||
void chrg_sink_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx,
|
||
struct chrg_switch_t *pSW, struct chrg_north_t *pNOR)
|
||
{
|
||
rt_uint16_t volt_mv = ((frame_data[4] << 8) | frame_data[5]) * 10;
|
||
static rt_uint8_t volt_low[TOTAL_SOU_CHS] = {0};
|
||
static rt_uint8_t no_curr[TOTAL_SOU_CHS] = {0};
|
||
static rt_uint8_t volt_set_ok[TOTAL_SOU_CHS] = {0};
|
||
|
||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||
return;
|
||
}
|
||
|
||
pSW->VZ = ((frame_data[14] << 8) | frame_data[15]);
|
||
pSW->VF = ((frame_data[16] << 8) | frame_data[17]);
|
||
|
||
#if DEBUG_NORTH
|
||
LOG_D("Sink[%d] real volt: %d mV", idx, volt_mv);
|
||
#endif
|
||
|
||
if(pSW->sink.On_work == 1 && pSW->sink.test.test_mode == 0) {
|
||
if (volt_mv <= WORK_MIN_VOLT) { // 电压过低,禁止进入工作状态机
|
||
// volt_low[idx]++;
|
||
/* Treat low voltage as a fault only after voltage was once valid. */
|
||
if (volt_set_ok[idx] == 1) {
|
||
if (++volt_low[idx] >= 5) {
|
||
volt_set_ok[idx] = 0;
|
||
no_curr[idx] = 0;
|
||
pSW->sink.work_mode = SINK_WORK_LOW;
|
||
}
|
||
}
|
||
// if(volt_low[idx]>=5) pSW->sink.work_on_step = SINK_WORK_LOW; // 复位工作状态机
|
||
}
|
||
else{ // 电压稳定时执行工作状态机(继电器/工作模式切换)
|
||
volt_low[idx] = 0;
|
||
volt_set_ok[idx] = 1;
|
||
pSW->change_flag = 0;
|
||
/* Avoid unsigned underflow when actual voltage is above target. */
|
||
if ((rt_uint32_t)volt_mv + 2000 >= pSW->sink.pro_loadv) {
|
||
pSW->sink.work_mode = SINK_WORK_RUNING;
|
||
/* Voltage is normal but current is still zero: retry from WAIT. */
|
||
if (pSW->Now_current <= 200) {
|
||
if (++no_curr[idx] >= 5) {
|
||
pSW->sink.work_mode = SINK_WORK_WAIT;
|
||
no_curr[idx] = 0;
|
||
}
|
||
}
|
||
else {
|
||
no_curr[idx] = 0;
|
||
}
|
||
} else {
|
||
no_curr[idx] = 0;
|
||
}
|
||
}
|
||
}
|
||
else{
|
||
volt_low[idx] = 0;
|
||
no_curr[idx] = 0;
|
||
volt_set_ok[idx] = 0;
|
||
// pSW->sink.work_on_step = SINK_WORK_STOP; // 复位工作状态机
|
||
}
|
||
chrg_sink_work(idx,pSW);
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: chrg_north_handle_Seting_Volt
|
||
功能描述: 处理设置电压/电流命令,解析命令数据并执行相应操作
|
||
****************************************************/
|
||
rt_uint8_t change_number = 0;
|
||
static void chrg_north_handle_Seting_Volt(rt_uint8_t *frame_data, rt_uint16_t frame_len)
|
||
{
|
||
// 提取电压/电流值
|
||
struct chrg_north_t *pNOR = &chrgnorth;
|
||
rt_uint16_t idx = pNOR->idx;
|
||
struct chrg_switch_t *pSW = &chrgnorth.sw[idx];
|
||
|
||
static uint8_t number = 0;
|
||
//电源部分
|
||
if(pSW->id==ID_SOURCE){
|
||
chrg_source_setting(frame_data,(eIDX_SOU_CH)idx, pSW, pNOR);
|
||
}
|
||
else{
|
||
chrg_sink_parse(frame_data,(eIDX_SOU_CH)idx, pSW, pNOR);
|
||
}
|
||
}
|
||
|
||
struct chrg_north_t chrgnorth = {
|
||
.devname = DEV_NAME_NORTH, // 设备名
|
||
.tty = RT_NULL, // 串口句柄初始为空
|
||
.enable = {1, 0, 0, 0}, // 4个通道使能初始关闭
|
||
.free_flag = 1,
|
||
// 通道1(IDX_NOR_CH1)初始化
|
||
.sw[IDX_NOR_CH1] = {
|
||
.CV_mode = 2,
|
||
.change_flag = 0,
|
||
.show_step = 0,
|
||
.sub = IDX_GET_SINK_VC,
|
||
.id = ID_SINK, // 初始为负载模式
|
||
.source = { // 电源侧参数初始化
|
||
.On_Flag = 0, // 启动标志初始关闭
|
||
.Set_CV_Flag = 1, // 启停控制初始置1
|
||
.Set_Pro_Flag = 1 // 电压/电流切换初始置1
|
||
}, // 关键:补充逗号分隔source和sink
|
||
.sink = {
|
||
.protocol = 0xFE,
|
||
.work_mode= SINK_WORK_WAIT,
|
||
.test.test_mode_old = 0,
|
||
}
|
||
|
||
},
|
||
// 通道2(IDX_NOR_CH2)初始化
|
||
.sw[IDX_NOR_CH2] = {
|
||
.show_step = 0,
|
||
.id = ID_SINK,
|
||
.CV_mode = 2,
|
||
.change_flag = 0,
|
||
.source = {
|
||
.On_Flag = 0,
|
||
.Set_CV_Flag = 1,
|
||
.Set_Pro_Flag = 1
|
||
},
|
||
.sink = {
|
||
.protocol = 0xFE,
|
||
.work_mode= SINK_WORK_WAIT,
|
||
.test.test_mode_old = 0,
|
||
}
|
||
},
|
||
// 通道3(IDX_NOR_CH3)初始化
|
||
.sw[IDX_NOR_CH3] = {
|
||
.show_step = 0,
|
||
.CV_mode = 2,
|
||
.id = ID_SINK,
|
||
.change_flag = 0,
|
||
.source = {
|
||
.On_Flag = 0,
|
||
.Set_CV_Flag = 1,
|
||
.Set_Pro_Flag = 1
|
||
},
|
||
.sink = {
|
||
.protocol = 0xFE,
|
||
.work_mode= SINK_WORK_WAIT,
|
||
.test.test_mode_old = 0,
|
||
}
|
||
},
|
||
// 通道4(IDX_NOR_CH4)初始化
|
||
.sw[IDX_NOR_CH4] = {
|
||
.show_step = 0,
|
||
.CV_mode = 2,
|
||
.id = ID_SINK,
|
||
.change_flag = 0,
|
||
.source = {
|
||
.On_Flag = 0,
|
||
.Set_CV_Flag = 1,
|
||
.Set_Pro_Flag = 1
|
||
},
|
||
.sink = {
|
||
.protocol = 0xFE,
|
||
.work_mode= SINK_WORK_WAIT,
|
||
.test.test_mode_old = 0,
|
||
}
|
||
}
|
||
};
|
||
/*****************************************************************
|
||
函数名称: chrg_north_switch
|
||
函数描述: 北向通道选择
|
||
输入参数: ch: 北向通道
|
||
输出参数: -
|
||
返回说明: <0: 错误
|
||
其它说明: -
|
||
*****************************************************************/
|
||
int chrg_north_switch (eIDX_NOR_CH ch)
|
||
{
|
||
if (ch >= TOTAL_NOR_CHS) {
|
||
return -1;
|
||
}
|
||
|
||
return chrg_switch_ch(chrgios[IDX_GPO_NOR_SW_A].base,
|
||
chrgios[IDX_GPO_NOR_SW_B].base, (eIDX_CH)ch);
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: chrg_north_send
|
||
函数描述: 北向通道数据发送
|
||
输入参数: *data: 数据 length: 数据长度
|
||
输出参数: -
|
||
返回说明: <0: 错误 >0:发送数据长度
|
||
其它说明: -
|
||
*****************************************************************/
|
||
int chrg_north_send (rt_uint8_t *data, rt_size_t length)
|
||
{
|
||
rt_ssize_t ret = -1;
|
||
struct chrg_tty_t *pTTY = chrgnorth.tty;
|
||
|
||
if (RT_NULL != pTTY) {
|
||
#if DEBUG_NORTH //是否打印
|
||
LOG_HEX("sendN", 32, data, length);
|
||
#endif
|
||
ret = chrg_tty_send(pTTY, data, length);
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: chrg_north_frame_head
|
||
函数描述: 北向通道数据帧头提取
|
||
输入参数: *rb: 缓冲区 *head: 帧头 id:编号
|
||
输出参数: -
|
||
返回说明: <0: 错误 >0:帧长度
|
||
其它说明: 提取3字节帧头
|
||
*****************************************************************/
|
||
static int chrg_north_frame_head (struct rt_ringbuffer *rb, rt_uint8_t *head, eIDX_ID id)
|
||
{
|
||
int i = 0;
|
||
rt_uint8_t data = 0, stage = 0;
|
||
rt_size_t ret = 0;
|
||
rt_size_t len_rb = 0; // ring数据长度
|
||
rt_uint8_t len_frame = 0; // 帧长度
|
||
|
||
if (RT_NULL == rb) {
|
||
rt_kprintf("len_rb=NULL%d\r\n",len_rb);
|
||
return -1;
|
||
}
|
||
|
||
len_rb = rt_ringbuffer_data_len(rb);
|
||
|
||
|
||
if (len_rb < LEN_FRAME_HEAD) {
|
||
return 0;
|
||
}
|
||
for (i = 0; i < len_rb - 2; i++) { // 找头三个字节 [帧长, 0x00, id]
|
||
ret = rt_ringbuffer_getchar(rb, &data);
|
||
if (0 == ret) {
|
||
continue;
|
||
}
|
||
|
||
switch (stage) {
|
||
case 0:
|
||
head[0] = data;
|
||
len_frame = data;
|
||
if (data < MIN_FRAME_LENGTH) { // 长度不符
|
||
|
||
stage = 0;
|
||
continue;
|
||
}
|
||
|
||
stage = 1;
|
||
break;
|
||
|
||
case 1:
|
||
head[1] = data;
|
||
if (0x00 != data) {
|
||
stage = 0;
|
||
} else {
|
||
stage = 2;
|
||
}
|
||
break;
|
||
|
||
case 2:
|
||
head[2] = data;
|
||
if ((rt_uint8_t)id != data) {
|
||
stage = 0;
|
||
} else {
|
||
// if (id == ID_SINK) {
|
||
// rt_uint8_t ext1, ext2;
|
||
// // 主动读取并丢弃2字节扩展字段
|
||
// rt_ringbuffer_getchar(rb, &ext1);
|
||
// rt_ringbuffer_getchar(rb, &ext2);
|
||
// rt_kprintf("Sink:%02X %02X\r\n", ext1, ext2);
|
||
// }
|
||
return len_frame;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: chrg_north_pickup_frame
|
||
函数描述: 北向通道数据帧提取
|
||
输入参数: *rb: 缓冲区 *pFrame: 数据帧 idx:通道
|
||
输出参数: -
|
||
返回说明: <0: 错误 >0:帧长度
|
||
其它说明: -
|
||
*****************************************************************/
|
||
int a_number;
|
||
|
||
#define NORTH_FRAME_TIMEOUT_MS 100
|
||
|
||
static void chrg_north_frame_reset(struct pickup_info_t *pFrame, rt_bool_t release)
|
||
{
|
||
if (RT_NULL == pFrame) {
|
||
return;
|
||
}
|
||
|
||
if (release && (RT_NULL != pFrame->pMB)) {
|
||
if (RT_NULL != pFrame->pMB->payload) {
|
||
rt_free(pFrame->pMB->payload);
|
||
}
|
||
rt_free(pFrame->pMB);
|
||
}
|
||
|
||
pFrame->last_tick = 0;
|
||
pFrame->length = 0;
|
||
pFrame->findhead = 0;
|
||
pFrame->len_msg = 0;
|
||
pFrame->pMB = RT_NULL;
|
||
}
|
||
|
||
static int chrg_north_frame_append(struct rt_ringbuffer *rb,
|
||
struct pickup_info_t *pFrame)
|
||
{
|
||
rt_size_t remaining;
|
||
rt_size_t copied;
|
||
|
||
if ((RT_NULL == rb)||(RT_NULL == pFrame)||(RT_NULL == pFrame->pMB)||
|
||
(RT_NULL == pFrame->pMB->payload)||(pFrame->len_msg <= 0)||
|
||
(pFrame->length > (rt_size_t)pFrame->len_msg)) {
|
||
return -1;
|
||
}
|
||
|
||
remaining = (rt_size_t)pFrame->len_msg - pFrame->length;
|
||
if (0 == remaining) {
|
||
return 1;
|
||
}
|
||
|
||
copied = rt_ringbuffer_data_len(rb);
|
||
if (copied > remaining) {
|
||
copied = remaining;
|
||
}
|
||
if (copied > 0) {
|
||
copied = rt_ringbuffer_get(rb,
|
||
&pFrame->pMB->payload[pFrame->length], copied);
|
||
pFrame->length += copied;
|
||
pFrame->last_tick = rt_tick_get();
|
||
}
|
||
|
||
return (pFrame->length == (rt_size_t)pFrame->len_msg) ? 1 : 0;
|
||
}
|
||
|
||
static void chrg_north_frame_dispatch(struct pickup_info_t *pFrame)
|
||
{
|
||
struct mb_msg_t *pMB = pFrame->pMB;
|
||
|
||
if (pMB->length == 21) {
|
||
chrg_north_handle_Seting_Volt(pMB->payload, pMB->length);
|
||
}
|
||
|
||
chrg_north_frame_reset(pFrame, RT_FALSE);
|
||
chrg_thread_mb_send(IDX_THR_NORTH, pMB);
|
||
}
|
||
|
||
static int chrg_north_pickup_frame (struct rt_ringbuffer *rb,
|
||
struct pickup_info_t *pFrame, eIDX_NOR_CH idx)
|
||
{
|
||
int cnt = 0;
|
||
int status = 0;
|
||
rt_size_t len_rb = 0;
|
||
if ((RT_NULL == rb)||(RT_NULL == pFrame)) {
|
||
return -1;
|
||
}
|
||
|
||
struct chrg_switch_t *pSW = &chrgnorth.sw[idx];
|
||
//rt_kprintf("north_idx=%d\r\n",idx);
|
||
do {
|
||
if (0 == pFrame->findhead) {
|
||
//pFrame->len_msg = chrg_north_frame_head(pSW->id,rb, pFrame->head, pSW->id);
|
||
pFrame->len_msg = chrg_north_frame_head(rb, pFrame->head, pSW->id);
|
||
// rt_kprintf("msg=:%d",pFrame->len_msg);
|
||
if (pFrame->len_msg > 0) {
|
||
if ((pFrame->len_msg < LEN_FRAME_HEAD)||
|
||
(pFrame->len_msg >= SIZE_BUF_TTY)) {
|
||
LOG_E("invalid msg length: %d", pFrame->len_msg);
|
||
chrg_north_frame_reset(pFrame, RT_TRUE);
|
||
return -3;
|
||
}
|
||
|
||
pFrame->pMB = (struct mb_msg_t *)rt_malloc(sizeof(struct mb_msg_t));
|
||
if (RT_NULL == pFrame->pMB) {
|
||
LOG_E("malloc mb failed.");
|
||
chrg_north_frame_reset(pFrame, RT_FALSE);
|
||
return -2;
|
||
}
|
||
pFrame->pMB->length = pFrame->len_msg;
|
||
pFrame->pMB->payload = RT_NULL;
|
||
pFrame->pMB->payload = (rt_uint8_t *)rt_malloc(pFrame->len_msg);
|
||
if (RT_NULL == pFrame->pMB->payload) {
|
||
LOG_E("malloc buf failed.");
|
||
chrg_north_frame_reset(pFrame, RT_TRUE);
|
||
return -4;
|
||
}
|
||
rt_memcpy(pFrame->pMB->payload, pFrame->head, LEN_FRAME_HEAD);
|
||
pFrame->length = LEN_FRAME_HEAD;
|
||
pFrame->findhead = 1;
|
||
pFrame->last_tick = rt_tick_get();
|
||
|
||
status = chrg_north_frame_append(rb, pFrame);
|
||
if (status > 0) {
|
||
chrg_north_frame_dispatch(pFrame);
|
||
cnt++;
|
||
} else if (status < 0) {
|
||
chrg_north_frame_reset(pFrame, RT_TRUE);
|
||
return -5;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
status = chrg_north_frame_append(rb, pFrame);
|
||
if (status > 0) {
|
||
chrg_north_frame_dispatch(pFrame);
|
||
cnt++;
|
||
} else if (status < 0) {
|
||
chrg_north_frame_reset(pFrame, RT_TRUE);
|
||
return -5;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
len_rb = rt_ringbuffer_data_len(rb);
|
||
|
||
} while (len_rb >= LEN_FRAME_HEAD);
|
||
|
||
return cnt;
|
||
}
|
||
|
||
/*****************************************************************
|
||
函数名称: chrg_north_thread_entry
|
||
函数描述: 北向通道数据接收线程体
|
||
输入参数: *data: 本线程信息
|
||
输出参数: -
|
||
返回说明: -
|
||
其它说明: -
|
||
*****************************************************************/
|
||
void chrg_north_thread_entry (void *data)
|
||
{
|
||
struct chrg_thread_t *pTHR = (struct chrg_thread_t *)data;
|
||
|
||
if (RT_NULL == pTHR) {
|
||
return ;
|
||
}
|
||
|
||
int len = 0;
|
||
rt_size_t put_len = 0;
|
||
struct chrg_tty_t *pTTY = RT_NULL;
|
||
struct chrg_north_t *pNOR = &chrgnorth;
|
||
//北向协议板线程体通道初始化为CH1,
|
||
chrg_north_switch(IDX_NOR_CH1);
|
||
|
||
pTTY = chrg_tty_create(pNOR->devname, 230400, 0, -1, 1);
|
||
if (RT_NULL == pTTY) {
|
||
LOG_E("tty can't create.");
|
||
return ;
|
||
}
|
||
|
||
chrg_tty_set_recv_tmo(pTTY, 10);
|
||
if (chrg_tty_connect(pTTY) != RT_EOK) {
|
||
chrg_tty_destory(pTTY);
|
||
return ;
|
||
}
|
||
|
||
pNOR->tty = pTTY;
|
||
|
||
pNOR->rb = rt_ringbuffer_create(SIZE_BUF_TTY*2);
|
||
if (RT_NULL == pNOR->rb) {
|
||
LOG_E("create rb '%s' failed.", pNOR->devname);
|
||
return ;
|
||
}
|
||
|
||
while (1) {
|
||
if (pNOR->frame.findhead &&
|
||
((rt_tick_t)(rt_tick_get() - pNOR->frame.last_tick) >=
|
||
rt_tick_from_millisecond(NORTH_FRAME_TIMEOUT_MS))) {
|
||
chrg_north_frame_reset(&pNOR->frame, RT_TRUE);
|
||
LOG_W("partial frame timeout");
|
||
}
|
||
|
||
rt_memset(pNOR->rx_buf, 0, sizeof(pNOR->rx_buf));
|
||
len = chrg_tty_recv(pTTY, pNOR->rx_buf, sizeof(pNOR->rx_buf));
|
||
if (len <= 0) {
|
||
rt_thread_mdelay(1);
|
||
continue;
|
||
}
|
||
|
||
put_len = rt_ringbuffer_put(pNOR->rb, pNOR->rx_buf, len);
|
||
if (put_len != (rt_size_t)len) {
|
||
LOG_E("north ringbuffer overflow: recv=%d put=%d", len, put_len);
|
||
rt_ringbuffer_reset(pNOR->rb);
|
||
chrg_north_frame_reset(&pNOR->frame, RT_TRUE);
|
||
continue;
|
||
}
|
||
#if DEBUG_NORTH
|
||
LOG_HEX("recvN", 32, pNOR->rx_buf, len);
|
||
#endif
|
||
chrg_north_pickup_frame(pNOR->rb, &pNOR->frame, pNOR->idx);
|
||
}
|
||
}
|
||
|
||
|
||
#if 1
|
||
static int north_ch(rt_uint8_t argc, char **argv)
|
||
{
|
||
int ret = 0;
|
||
|
||
if (2 != argc) {
|
||
rt_kprintf("help : %s [0-3]\r\n", argv[0]);
|
||
return -1;
|
||
}
|
||
|
||
ret = chrg_north_switch((eIDX_NOR_CH)atoi(argv[1]));
|
||
|
||
return ret;
|
||
}
|
||
|
||
|
||
MSH_CMD_EXPORT(north_ch, north channel select);
|
||
|
||
static int north_diag(int argc, char **argv)
|
||
{
|
||
rt_uint8_t i;
|
||
struct chrg_north_t *pNOR = &chrgnorth;
|
||
struct chrg_rollnor_t *pROLL = &chrgrollnor;
|
||
|
||
rt_kprintf("roll: run=%d idx=%d ch=%d type=%d sub=%d\r\n",
|
||
pROLL->run, pROLL->idx, pROLL->ch, pROLL->type, pROLL->sub);
|
||
rt_kprintf("rx: rb_len=%d findhead=%d frame_len=%d received=%d\r\n",
|
||
pNOR->rb ? rt_ringbuffer_data_len(pNOR->rb) : 0,
|
||
pNOR->frame.findhead, pNOR->frame.len_msg, pNOR->frame.length);
|
||
for (i = 0; i < TOTAL_NOR_CHS; i++) {
|
||
rt_kprintf("ch%d: enable=%d id=%d sub=%d\r\n", i,
|
||
pNOR->enable[i], pNOR->sw[i].id, pNOR->sw[i].sub);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
MSH_CMD_EXPORT(north_diag, show north polling and frame state);
|
||
|
||
#endif
|
||
|