388 lines
13 KiB
C
388 lines
13 KiB
C
/*
|
||
* @Author:
|
||
* @Date: 2023-03-20 19:27:47
|
||
* @LastEditors: wangxujie-laptop 390834610@qq.com
|
||
* @LastEditTime: 2024-09-11 10:51:36
|
||
* @FilePath: \hart\hart\hart_frame.c
|
||
* @Description:
|
||
* email:
|
||
* Copyright (c) 2023 by xxx, All Rights Reserved.
|
||
*/
|
||
|
||
#include "./inc/hart_frame.h"
|
||
#include "../slave/inc/hart_slave_frame.h"
|
||
static uint8_t *hart_frame_data_length_p; // 帧数据长度位置
|
||
static uint8_t *hart_frame_response_code_p; // 帧响应码位置
|
||
|
||
/**
|
||
* @brief 在处理请求开始时记录帧响应码起始位置
|
||
* @param {uint8_t} *
|
||
* @return {*}
|
||
*/
|
||
void hart_frame_response_code_start(uint8_t **data_p)
|
||
{
|
||
hart_frame_response_code_p = *data_p;
|
||
}
|
||
|
||
/**
|
||
* @brief 响应码第一个字节为通信有关的信息
|
||
* @param {uint8_t} code
|
||
* @return {*}
|
||
* 1. 第7位如果是1,则剩余的位包含了有关通信错误的信息 response_error_communication_code_e
|
||
* 2. 第7位如果是0,则剩余的位包含了有关通信正常的信息 response_communication_code_e
|
||
*/
|
||
void hart_frame_response_communication_code(uint8_t code)
|
||
{
|
||
*hart_frame_response_code_p = code;
|
||
}
|
||
|
||
/**
|
||
* @brief 响应码第二个字节为设备的操作状态有关的信息
|
||
* 如在第一个字节中最高位置1,则该字节无意义
|
||
* @param {uint8_t} code
|
||
* @return {*}
|
||
*/
|
||
void hart_frame_slave_response_operate_code(hart_device_attribute_t *hart_device_attribute)
|
||
{
|
||
/**
|
||
* 判断当前设备状态的crc和device_status_crc是否一致
|
||
* Note:
|
||
Masters will issue this command whenever More Status Available (Bit 4 of the device status byte) issetAs a result, the Field Device must carefully define and contro the events and status information inthis command that affect these two device status bits. f the More Status Available bit is alwaysasserted. then communication bandwidth is effectively cut in half.
|
||
*/
|
||
// uint16_t crc = crc16_compute((uint8_t *)&hart_device_attribute->device_status.additional_device_status, sizeof(additional_device_status_t));
|
||
// if (hart_device_attribute->device_status.additional_device_status_crc != crc)
|
||
// {
|
||
// hart_device_status_set_operational_state(DEVICE_OPERATIONAL_STATE_5);
|
||
// }
|
||
// else
|
||
// {
|
||
// hart_device_status_clr_operational_state(DEVICE_OPERATIONAL_STATE_5);
|
||
// }
|
||
|
||
*(hart_frame_response_code_p + 1) = hart_device_attribute->device_status.operational_state;
|
||
}
|
||
|
||
/**
|
||
* @brief 响应码第二个字节为设备的操作状态有关的信息,主机默认回复0x00
|
||
* @return {*}
|
||
*/
|
||
void hart_frame_master_response_operate_code(void)
|
||
{
|
||
*(hart_frame_response_code_p + 1) = 0x00;
|
||
}
|
||
|
||
/**
|
||
* @brief在处理请求开始时记录帧数据域长度起始位置
|
||
* @param {uint8_t} *data_p
|
||
* @return {*}
|
||
*/
|
||
void hart_frame_data_length_start(uint8_t **data_p)
|
||
{
|
||
DBG_ASSERT(data_p != NULL __DBG_LINE);
|
||
DBG_ASSERT(*data_p != NULL __DBG_LINE);
|
||
|
||
hart_frame_data_length_p = *data_p;
|
||
}
|
||
/**
|
||
* @brief在处理请求结束时记录帧数据长度位置
|
||
* @param {uint8_t} *data_p
|
||
* @return {*}
|
||
*/
|
||
void hart_frame_data_length_end(uint8_t *data_p)
|
||
{
|
||
*hart_frame_data_length_p = data_p - hart_frame_data_length_p - 1; // 计算数据个数
|
||
// LOG_PRINT("%d", *hart_frame_data_length_p);
|
||
}
|
||
|
||
// 判断指令是否是写
|
||
BOOL hart_is_write_command(uint16_t command)
|
||
{
|
||
// 先判断是否在用户自定义的指令中
|
||
uint16_t user_version[] = {HART_COMMAND_130, HART_COMMAND_131, HART_COMMAND_135, HART_COMMAND_143, HART_COMMAND_149, HART_COMMAND_154,
|
||
HART_COMMAND_162, HART_COMMAND_165, HART_COMMAND_167};
|
||
if (is_in_array(user_version, ARRAY_LEN(user_version), command))
|
||
{
|
||
return TRUE;
|
||
}
|
||
|
||
uint16_t cmd[] = {HART_COMMAND_6, HART_COMMAND_17, HART_COMMAND_18, HART_COMMAND_19, HART_COMMAND_22,/* HART_COMMAND_38,//ZKBW*/
|
||
HART_COMMAND_34, HART_COMMAND_35, HART_COMMAND_36, HART_COMMAND_37, HART_COMMAND_39, HART_COMMAND_40, HART_COMMAND_43,
|
||
HART_COMMAND_44, HART_COMMAND_45, HART_COMMAND_46, HART_COMMAND_47, HART_COMMAND_49, HART_COMMAND_51, HART_COMMAND_52,
|
||
HART_COMMAND_53, HART_COMMAND_55, HART_COMMAND_56, HART_COMMAND_58, HART_COMMAND_59, HART_COMMAND_64, HART_COMMAND_65,
|
||
HART_COMMAND_66, HART_COMMAND_67, HART_COMMAND_68, HART_COMMAND_69, HART_COMMAND_79, HART_COMMAND_82, HART_COMMAND_83,
|
||
HART_COMMAND_87, HART_COMMAND_88, HART_COMMAND_92, HART_COMMAND_97, HART_COMMAND_99, HART_COMMAND_100, HART_COMMAND_102,
|
||
HART_COMMAND_103, HART_COMMAND_104, HART_COMMAND_107, HART_COMMAND_108, HART_COMMAND_109, HART_COMMAND_112,
|
||
HART_COMMAND_116, HART_COMMAND_117, HART_COMMAND_118, HART_COMMAND_513, HART_COMMAND_517, HART_COMMAND_519,
|
||
HART_COMMAND_521, HART_COMMAND_522, HART_COMMAND_524, HART_COMMAND_525, HART_COMMAND_526, HART_COMMAND_535,
|
||
HART_COMMAND_539, HART_COMMAND_540};
|
||
return is_in_array(cmd, ARRAY_LEN(cmd), command);
|
||
}
|
||
|
||
// 判断版本是否支持当前指令
|
||
BOOL hart_is_support_command(uint16_t command)
|
||
{
|
||
if (HART_PROTOCOL_VERSION_SUPPORT_COMMAND == 0)
|
||
{
|
||
return TRUE;
|
||
}
|
||
|
||
// 先判断是否在用户自定义的指令中
|
||
uint16_t user_version[] = {/*HART_COMMAND_31, HART_COMMAND_109, */ HART_COMMAND_129, HART_COMMAND_130, HART_COMMAND_131, HART_COMMAND_132,
|
||
HART_COMMAND_133, HART_COMMAND_134, HART_COMMAND_135, HART_COMMAND_136, HART_COMMAND_138, HART_COMMAND_140,
|
||
HART_COMMAND_141, HART_COMMAND_142, HART_COMMAND_143, HART_COMMAND_144,
|
||
HART_COMMAND_145, HART_COMMAND_146, HART_COMMAND_147, HART_COMMAND_149, HART_COMMAND_150, HART_COMMAND_151, HART_COMMAND_153,
|
||
HART_COMMAND_154, HART_COMMAND_155, HART_COMMAND_156, HART_COMMAND_157, HART_COMMAND_158, HART_COMMAND_162, HART_COMMAND_164, HART_COMMAND_165,
|
||
HART_COMMAND_167, HART_COMMAND_168, HART_COMMAND_170, HART_COMMAND_187, HART_COMMAND_200};
|
||
if (is_in_array(user_version, ARRAY_LEN(user_version), command))
|
||
{
|
||
return TRUE;
|
||
}
|
||
|
||
if (hart_get_current_protocol_version() == HART_PROTOCOL_VERSION_5)
|
||
{
|
||
uint16_t version[] = {HART_COMMAND_0, HART_COMMAND_1, HART_COMMAND_2, HART_COMMAND_6, HART_COMMAND_11, HART_COMMAND_12,
|
||
HART_COMMAND_13, HART_COMMAND_14, HART_COMMAND_15, HART_COMMAND_16, HART_COMMAND_17, HART_COMMAND_18, HART_COMMAND_19,
|
||
HART_COMMAND_33, HART_COMMAND_34, HART_COMMAND_35, HART_COMMAND_36, HART_COMMAND_37, HART_COMMAND_38, HART_COMMAND_39,
|
||
HART_COMMAND_40, HART_COMMAND_41, HART_COMMAND_42, HART_COMMAND_43, HART_COMMAND_44, HART_COMMAND_45, HART_COMMAND_46,
|
||
HART_COMMAND_47, HART_COMMAND_48, HART_COMMAND_49, HART_COMMAND_50, HART_COMMAND_51, HART_COMMAND_52, HART_COMMAND_53,
|
||
HART_COMMAND_54, HART_COMMAND_55, HART_COMMAND_56, HART_COMMAND_57, HART_COMMAND_58, HART_COMMAND_59, HART_COMMAND_60,
|
||
HART_COMMAND_61, HART_COMMAND_62, HART_COMMAND_63, HART_COMMAND_64, HART_COMMAND_65, HART_COMMAND_66, HART_COMMAND_67,
|
||
HART_COMMAND_68, HART_COMMAND_69, HART_COMMAND_70, HART_COMMAND_107, HART_COMMAND_109, HART_COMMAND_110};
|
||
if (is_in_array(version, ARRAY_LEN(version), command))
|
||
{
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
if (hart_get_current_protocol_version() == HART_PROTOCOL_VERSION_7)
|
||
{
|
||
uint16_t version[] = {/*Universal Command */ HART_COMMAND_0, HART_COMMAND_1, HART_COMMAND_2, HART_COMMAND_3, HART_COMMAND_6, HART_COMMAND_7,
|
||
HART_COMMAND_8, HART_COMMAND_9, HART_COMMAND_11, HART_COMMAND_12, HART_COMMAND_13, HART_COMMAND_14, HART_COMMAND_15,
|
||
HART_COMMAND_16, HART_COMMAND_17, HART_COMMAND_18, HART_COMMAND_19, HART_COMMAND_20, HART_COMMAND_21, HART_COMMAND_22,
|
||
HART_COMMAND_38, HART_COMMAND_48, /*Common Command */ HART_COMMAND_33, HART_COMMAND_35, HART_COMMAND_44, HART_COMMAND_50,
|
||
HART_COMMAND_51, HART_COMMAND_52, HART_COMMAND_53, HART_COMMAND_54, HART_COMMAND_59};
|
||
if (is_in_array(version, ARRAY_LEN(version), command))
|
||
{
|
||
return TRUE;
|
||
}
|
||
}
|
||
LOG_ERR("command %d is not support", command);
|
||
return FALSE;
|
||
}
|
||
|
||
/**
|
||
* @brief 检查数据长度是否符合规定
|
||
* @param {uint8_t} data_length
|
||
* @param {uint8_t} data_structure_length 原始的数据结构长度
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
BOOL hart_frame_data_length_check(uint8_t data_length, uint8_t data_structure_length, uint8_t *resp_code)
|
||
{
|
||
if (data_length != data_structure_length)
|
||
{
|
||
if (data_length < data_structure_length)
|
||
{
|
||
*resp_code = RESPONSE_COMMUNICATION_CODE_5;
|
||
return FALSE;
|
||
}
|
||
else
|
||
{
|
||
*resp_code = RESPONSE_COMMUNICATION_CODE_3;
|
||
return FALSE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
// 日期检测,年月日
|
||
BOOL check_date(rtc_date_t *date)
|
||
{
|
||
if (date->year > 99)
|
||
{
|
||
return FALSE;
|
||
}
|
||
if (date->month < 1 || date->month > 12)
|
||
{
|
||
return FALSE;
|
||
}
|
||
if (date->day < 1 || date->day > 31)
|
||
{
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
// 判断是否是广播地址
|
||
BOOL is_broadcast_address(uint8_t *address, uint8_t len)
|
||
{
|
||
for (uint8_t i = 0; i < len; i++)
|
||
{
|
||
if (*(address + i) != 0x00)
|
||
{
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
// uint32转小时:分钟:秒:毫秒
|
||
void timestamp_to_hmsms(uint32_t timestamp, uint8_t *hmsms)
|
||
{
|
||
uint32_t ms = timestamp % 1000;
|
||
uint32_t s = timestamp / 1000;
|
||
uint32_t m = s / 60;
|
||
uint32_t h = m / 60;
|
||
hmsms[0] = h;
|
||
hmsms[1] = m % 60;
|
||
hmsms[2] = s % 60;
|
||
hmsms[3] = ms;
|
||
}
|
||
|
||
// assic转十六进制(assic-6)
|
||
void encode_ascii_6(const uint8_t *input, uint16_t input_length, uint8_t *output)
|
||
{
|
||
uint8_t adjusted_input[input_length];
|
||
uint16_t i = 0;
|
||
|
||
osel_memset(adjusted_input, 0, input_length);
|
||
|
||
for (i = 0; i < input_length; i++)
|
||
{
|
||
if (input[i] == 0x00)
|
||
{
|
||
adjusted_input[i] = 0x20;
|
||
continue;
|
||
}
|
||
|
||
adjusted_input[i] = input[i] >= 0x40 ? input[i] - 0x40 : input[i];
|
||
}
|
||
|
||
uint16_t acs8_len = i + 1;
|
||
uint16_t acs6_len = acs8_len * 6 / 8;
|
||
for (i = 0; i < acs6_len; i++)
|
||
{
|
||
uint8_t pos = i * 8 / 6;
|
||
uint8_t val = adjusted_input[pos] & 0x3f;
|
||
uint8_t valNext = pos + 1 < acs8_len ? (adjusted_input[pos + 1] & 0x3f) : 0x20;
|
||
uint8_t newVal = 0;
|
||
switch (i % 3)
|
||
{
|
||
case 0:
|
||
newVal = val << 2;
|
||
newVal += valNext >> 4;
|
||
break;
|
||
case 1:
|
||
newVal = val << 4;
|
||
newVal += valNext >> 2;
|
||
break;
|
||
case 2:
|
||
newVal = val << 6;
|
||
newVal += valNext;
|
||
break;
|
||
}
|
||
output[i] = newVal;
|
||
}
|
||
}
|
||
|
||
// assic-6 转 assic的十六进制
|
||
void decode_ascii_6(const uint8_t *input, uint16_t input_length, uint8_t *output)
|
||
{
|
||
uint16_t acs8_len = input_length * 8 / 6;
|
||
|
||
for (uint16_t i = 0; i < acs8_len; i++)
|
||
{
|
||
uint8_t pos = i * 6 / 8;
|
||
uint8_t val = input[pos];
|
||
uint8_t valNext = pos + 1 < input_length ? input[pos + 1] : 0;
|
||
uint8_t newVal = 0;
|
||
switch (i % 4)
|
||
{
|
||
case 0:
|
||
newVal = (val & 0xfc) >> 2;
|
||
break;
|
||
case 1:
|
||
newVal = (val & 3) << 4;
|
||
newVal += (valNext & 240) >> 4;
|
||
break;
|
||
case 2:
|
||
newVal = (val & 15) << 2;
|
||
newVal += (valNext & 192) >> 6;
|
||
break;
|
||
case 3:
|
||
newVal = val & 0x3f;
|
||
break;
|
||
}
|
||
if (newVal < 0x20)
|
||
newVal += 64;
|
||
if (newVal == 0x20)
|
||
newVal = 0;
|
||
output[i] = newVal;
|
||
}
|
||
}
|
||
|
||
// Time由一个无符号的32位二进制整数组成,最低有效位表示1/32毫秒(即0.03125毫秒)。
|
||
void convert_time(uint32_t t, uint8_t *h, uint8_t *m, uint8_t *s)
|
||
{
|
||
t = (t / 32);
|
||
t = t / 1000;
|
||
*h = t / 3600;
|
||
*m = (t - (*h) * 3600) / 60;
|
||
*s = t - (*h) * 3600 - (*m) * 60;
|
||
}
|
||
|
||
// Time由一个无符号的32位二进制整数组成,最低有效位表示1/32毫秒(即0.03125毫秒)。
|
||
void convert_timestrap(uint32_t *t, uint8_t h, uint8_t m, uint8_t s, uint16_t ms)
|
||
{
|
||
*t = (h * 3600 + m * 60 + s) * 1000 + ms;
|
||
*t = (*t) * 32;
|
||
}
|
||
|
||
// 年份转换,HART的年份是从1900年开始的,如果要转换到标准的年份,需要加上1900。另外,HART的年份是一个字节,所以最大只能表示到2155年。
|
||
void covert_year_rtc(uint8_t *year)
|
||
{
|
||
uint8_t y = *year;
|
||
*year = y - 100;
|
||
}
|
||
|
||
// 将RTC的年份转换为HART的年份
|
||
void covert_rtc_year(uint8_t *year)
|
||
{
|
||
uint8_t y = *year;
|
||
*year = y + 100;
|
||
}
|
||
|
||
// 将RTC的年份转换成标准的年份
|
||
void covert_rtc_year_to_standard(uint16_t *year)
|
||
{
|
||
uint16_t y = *year;
|
||
*year = y + 2000;
|
||
}
|
||
|
||
float32 covert_float(user_param_type_e data_type, void *data_p)
|
||
{
|
||
float32 f = 0;
|
||
switch (data_type)
|
||
{
|
||
case USER_BYTE:
|
||
f = *(uint8_t *)data_p;
|
||
break;
|
||
case USER_WORD:
|
||
f = *(uint16_t *)data_p;
|
||
break;
|
||
case USER_UINT32:
|
||
f = *(uint32_t *)data_p;
|
||
break;
|
||
case USER_FLOAT:
|
||
f = *(float32 *)data_p;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return f;
|
||
}
|