当前位置: 首页 > article >正文

SZY206-2016水资源监测数据传输规约 基础架构

szy_206.h
#ifndef __SZY_206_H__
#define __SZY_206_H__


#include "stdint.h"
#include "stdio.h"
#include "string.h"

#define FRAME_START     (0x68)
#define FRAME_END       (0x16)

// 定义下行帧传输方向的枚举类型(DIR=0)
typedef enum {
    DOWN_SEND_CONFIRM_COMMAND = 0,  // 发送∕确认 命令
    DOWN_QUERY_RESPONSE_RAINFALL = 1,  // 查询∕响应帧 雨量参数
    DOWN_QUERY_RESPONSE_WATER_LEVEL = 2,  // 查询∕响应帧 水位参数
    DOWN_QUERY_RESPONSE_FLOW = 3,  // 查询∕响应帧 流量(水量)参数
    DOWN_QUERY_RESPONSE_FLOW_VELOCITY = 4,  // 查询∕响应帧 流速参数
    DOWN_QUERY_RESPONSE_GATE_POSITION = 5,  // 查询∕响应帧 闸位参数
    DOWN_QUERY_RESPONSE_POWER = 6,  // 查询∕响应帧 功率参数
    DOWN_QUERY_RESPONSE_AIR_PRESSURE = 7,  // 查询∕响应帧 气压参数
    DOWN_QUERY_RESPONSE_WIND_SPEED = 8,  // 查询∕响应帧 风速参数
    DOWN_QUERY_RESPONSE_WATER_TEMPERATURE = 9,  // 查询∕响应帧 水温参数
    DOWN_QUERY_RESPONSE_WATER_QUALITY = 10,  // 查询∕响应帧 水质参数
    DOWN_QUERY_RESPONSE_SOIL_MOISTURE = 11,  // 查询∕响应帧 土壤含水率参数
    DOWN_QUERY_RESPONSE_EVAPORATION = 12,  // 查询∕响应帧 蒸发量参数
    DOWN_QUERY_RESPONSE_ALARM_STATUS = 13,  // 查询∕响应帧 报警或状态参数
    DOWN_QUERY_RESPONSE_INTEGRATED = 14,  // 查询∕响应帧 综合参数
    DOWN_QUERY_RESPONSE_WATER_PRESSURE = 15  // 查询∕响应帧 水压参数
} control_funcode_down_e;

// 定义上行帧传输方向的枚举类型(DIR=1)
typedef enum {
    UP_CONFIRM_APPROVAL = 0,  // 确认 认可
    UP_SELF_REPORT_RAINFALL = 1,  // 自报帧 雨量参数
    UP_SELF_REPORT_WATER_LEVEL = 2,  // 自报帧 水位参数
    UP_SELF_REPORT_FLOW = 3,  // 自报帧 流量(水量)参数
    UP_SELF_REPORT_FLOW_VELOCITY = 4,  // 自报帧 流速参数
    UP_SELF_REPORT_GATE_POSITION = 5,  // 自报帧 闸位参数
    UP_SELF_REPORT_POWER = 6,  // 自报帧 功率参数
    UP_SELF_REPORT_AIR_PRESSURE = 7,  // 自报帧 气压参数
    UP_SELF_REPORT_WIND_SPEED = 8,  // 自报帧 风速参数
    UP_SELF_REPORT_WATER_TEMPERATURE = 9,  // 自报帧 水温参数
    UP_SELF_REPORT_WATER_QUALITY = 10,  // 自报帧 水质参数
    UP_SELF_REPORT_SOIL_MOISTURE = 11,  // 自报帧 土壤含水率参数
    UP_SELF_REPORT_EVAPORATION = 12,  // 自报帧 蒸发量参数
    UP_SELF_REPORT_ALARM_STATUS = 13,  // 自报帧 报警或状态参数
    UP_SELF_REPORT_STATISTICAL_RAINFALL = 14,  // 自报帧 统计雨量
    UP_SELF_REPORT_WATER_PRESSURE = 15  // 自报帧 水压参数
} control_funcode_up_e;


typedef enum {
    LINK_DETECTION = 0x02,  // 链路检测
    SET_TERMINAL_ADDRESS = 0x10,  // 设置遥测终端、中继站地址
    SET_TERMINAL_CLOCK = 0x11,  // 设置遥测终端、中继站时钟
    SET_TERMINAL_WORK_MODE = 0x12,  // 设置遥测终端工作模式
    SET_TERMINAL_CURRENT_RECHARGE_AMOUNT = 0x15,  // 设置遥测终端本次充值量
    SET_TERMINAL_REMAINING_WATER_ALARM_VALUE = 0x16,  // 设置遥测终端剩余水量报警值
    SET_TERMINAL_WATER_LEVEL_BASE_AND_LIMITS = 0x17,  // 设置遥测终端的水位基值、水位上下限
    SET_TERMINAL_WATER_PRESSURE_LIMITS = 0x18,  // 设置遥测终端水压上、下限
    SET_TERMINAL_WATER_QUALITY_PARAMETER_UPPER_LIMIT = 0x19,  // 设置遥测终端水质参数种类、上限值
    SET_TERMINAL_WATER_QUALITY_PARAMETER_LOWER_LIMIT = 0x1A,  // 设置遥测终端水质参数种类、下限值
    SET_TERMINAL_INITIAL_WATER_AMOUNT = 0x1B,  // 设置终端站水量的表底(初始)值
    SET_TERMINAL_FORWARD_RELAY_LEADING_CODE_LENGTH = 0x1C,  // 设置遥测终端转发中继引导码长
    SET_RELAY_FORWARD_TERMINAL_ADDRESS = 0x1D,  // 设置中继站转发终端地址
    SET_RELAY_WORK_MACHINE_AUTO_SWITCH_AND_SELF_REPORT_STATUS = 0x1E,  // 设置中继站工作机自动切换,自报状态
    SET_TERMINAL_FLOW_PARAMETER_UPPER_LIMIT = 0x1F,  // 设置遥测终端流量参数上限值
    SET_TERMINAL_DETECTION_PARAMETER_TRIGGER_THRESHOLD_AND_STORAGE_INTERVAL = 0x20,  // 设置遥测终端检测参数启报阈值及固态存储时间段间隔
    SET_TERMINAL_IC_CARD_FUNCTION_ENABLE = 0x30,  // 置遥测终端IC卡功能有效
    SET_TERMINAL_IC_CARD_FUNCTION_DISABLE = 0x31,  // 取消遥测终端IC卡功能
    FIXED_VALUE_CONTROL_ENGAGE = 0x32,  // 定值控制投入
    FIXED_VALUE_CONTROL_DISENGAGE = 0x33,  // 定值控制退出
    FIXED_VALUE_SETTING = 0x34,  // 定值量设定
    QUERY_TERMINAL_ADDRESS = 0x50,  // 查询遥测终端、中继站地址
    QUERY_TERMINAL_CLOCK = 0x51,  // 查询遥测终端、中继站时钟
    QUERY_TERMINAL_WORK_MODE = 0x52,  // 查询遥测终端工作模式
    QUERY_TERMINAL_SELF_REPORT_DATA_TYPE_AND_INTERVAL = 0x53,  // 查询遥测终端的数据自报种类及时间间隔
    QUERY_TERMINAL_REAL_TIME_DATA_TYPE_TO_QUERY = 0x54,  // 查询遥测终端需查询的实时数据种类
    QUERY_TERMINAL_LATEST_RECHARGE_AMOUNT_AND_CURRENT_REMAINING_WATER = 0x55,  // 查询遥测终端最近成功充值量和现有剩余水量
    QUERY_TERMINAL_REMAINING_WATER_AND_ALARM_VALUE = 0x56,  // 查询遥测终端剩余水量和报警值
    QUERY_TERMINAL_WATER_LEVEL_BASE_AND_LIMITS = 0x57,  // 查询遥测终端水位基值、水位上下限
    QUERY_TERMINAL_WATER_PRESSURE_LIMITS = 0x58,  // 查询遥测终端水压上、下限
    QUERY_TERMINAL_WATER_QUALITY_PARAMETER_UPPER_LIMIT = 0x59,  // 查询遥测终端水质参数种类、上限值
    QUERY_TERMINAL_WATER_QUALITY_PARAMETER_LOWER_LIMIT = 0x5A,  // 查询遥测终端水质参数种类、下限值
    QUERY_TERMINAL_EVENT_RECORDS = 0x5D,  // 查询遥测终端的事件记录
    QUERY_TERMINAL_STATUS_AND_ALARM_STATUS = 0x5E,  // 查询遥测终端状态和报警状态
    QUERY_PUMP_MOTOR_REAL_TIME_WORK_DATA = 0x5F,  // 查询水泵电机实时工作数据
    QUERY_TERMINAL_FORWARD_RELAY_LEADING_CODE_LENGTH = 0x60,  // 查询遥测终端转发中继引导码长
    QUERY_TERMINAL_IMAGE_RECORDS = 0x61,  // 查询遥测终端图像记录
    QUERY_RELAY_FORWARD_TERMINAL_ADDRESS = 0x62,  // 查询中继站转发终端地址
    QUERY_RELAY_WORK_MACHINE_STATUS_AND_SWITCH_RECORDS = 0x63,  // 查询中继站工作机状态和切换记录
    QUERY_TERMINAL_FLOW_PARAMETER_UPPER_LIMIT = 0x64,  // 查询遥测终端流量参数上限值
    RANDOM_SELF_REPORT_ALARM_DATA = 0x81,  // 随机自报报警数据
    MANUAL_SET_NUMBER = 0x82,  // 人工置数
    RESET_TERMINAL_PARAMETERS_AND_STATUS = 0x90,  // 复位遥测终端参数和状态
    CLEAR_TERMINAL_HISTORICAL_DATA_UNIT = 0x91,  // 清空遥测终端历史数据单元
    REMOTE_CONTROL_START_PUMP_OR_VALVE = 0x92,  // 遥控启动水泵或阀门/闸门
    REMOTE_CONTROL_CLOSE_PUMP_OR_VALVE = 0x93,  // 遥控关闭水泵或阀门/闸门
    REMOTE_CONTROL_TERMINAL_OR_RELAY_COMMUNICATION_MACHINE_SWITCH = 0x94,  // 遥控终端或中继站通信机切换
    REMOTE_CONTROL_RELAY_WORK_MACHINE_SWITCH = 0x95,  // 遥控中继站工作机切换
    MODIFY_TERMINAL_PASSWORD = 0x96,  // 修改遥测终端密码
    SET_TERMINAL_REAL_TIME_DATA_TYPE_TO_QUERY = 0xA0,  // 设置遥测站需查询的实时数据种类
    SET_TERMINAL_SELF_REPORT_DATA_TYPE_AND_INTERVAL = 0xA1,  // 设置遥测终端的数据自报种类及时间间隔
    QUERY_TERMINAL_REAL_TIME_VALUE = 0xB0,  // 查询遥测终端实时值
    QUERY_TERMINAL_SOLID_STATE_STORAGE_DATA = 0xB1,  // 查询遥测终端固态存储数据
    QUERY_TERMINAL_MEMORY_SELF_REPORT_DATA = 0xB2,  // 查询遥测终端内存自报数据
    TERMINAL_SELF_REPORT_REAL_TIME_DATA = 0xC0  // 遥测终端自报实时数据
} user_func_e;


// 控制域结构体
#pragma pack(1)
typedef struct {
    uint8_t DIR : 1;      // 传输方向位
    uint8_t DIV : 1;      // 拆分标志位
    uint8_t FCB : 2;      // 帧计数位
    uint8_t function_code : 4;   // 功能码
} ControlField;

// 密码PW结构体
#pragma pack(1)
typedef struct {
    uint8_t key_algorithm : 4;   // 密钥算法,采用BCD编码,取值范围0 - 9
    uint16_t key:12;            // 密钥,采用BCD编码,取值范围0 - 999
} Password;

// 时间标签Tp结构体
#pragma pack(1)
typedef struct {
    uint32_t start_frame_send_time;   // 启动帧发送时标,数据格式为BCD码,依次为秒、分、时、日
    uint8_t allow_send_transfer_delay_time;   // 允许发送传输延时时间,BIN编码,单位为min
} TimeTag;


// 统一数据结构体
#pragma pack(1)
typedef struct {
    uint8_t start_frame;   // 起始字符(68H)
    uint8_t length;       // 长度L 控制域、地址域、用户数据域(应用层)的字节总数
    uint8_t start_frame2;  // 起始字符(68H)
    ControlField control;   // 控制域
    uint8_t address[5];   // 地址域A
    uint8_t AFN;          // 应用层功能码AFN
    uint8_t* user_data;    // 数据域指针,用户根据具体功能码分配和填充数据
    Password password;      // 密码PW
    TimeTag time_tag;      // 时间标签Tp
    uint8_t checksum;     // 校验CS   用户数据区的 CRC 校验  控制域+地址域+用户数据
    uint8_t end_char;     // 结束字符(16H)
} SZY206_Frame_T;

         
#define SZY206_FIX_HEAD_LEN         (3)  //起始字符+长度L+起始字符+控制域+地址域A+应用层功能码AFN
#define SZY206_USER_DATA_OFFSET     (SZY206_FIX_HEAD_LEN+sizeof(ControlField)+5+1)//到user_data的偏移地址
#define SZY206_MIN_FRAME_LEN        (SZY206_USER_DATA_OFFSET+2)  //起始字符+长度L+起始字符+控制域+地址域A+应用层功能码AFN+校验CS+结束字符(16H)






static void SZY206_Dec2bcd(uint8_t* bufIn, double dval, uint16_t nb_byte, int nb_dec);
uint8_t calculateCRC8(uint8_t *data, uint16_t length) ;
uint8_t SZY206_IsAux(uint8_t AFN) ;

uint8_t SZY206_FrameFill(uint8_t *buffer, ControlField control, uint8_t *address, uint8_t AFN,
                         Password password, TimeTag time_tag, uint8_t *user_data, uint16_t user_data_length);

uint8_t SZY206_FrameVerification(uint8_t *buffer , uint16_t length);

uint8_t SZY206_Parse(uint8_t *buffer , uint16_t length ,ControlField  *control , uint8_t *AFN,
                    Password *password ,TimeTag *time_tag,uint8_t *user_data);


#endif
szy_206.c
#include "szy_206.h"
#include <stdio.h>


/// @brief 十进制转BCD
/// @param data 
/// @return 
static int dec2bcd(unsigned char data)
{
	unsigned char temp;
	temp = (((data / 10) << 4) + (data % 10));
	return temp;
}
/// @brief double 转换成BCD
/// @param bufIn 
/// @param dval 数据
/// @param nb_byte 总长度
/// @param nb_dec 小数点后位数
static void SZY206_Dec2bcd(uint8_t* bufIn, double dval, uint16_t nb_byte, int nb_dec)
{
	int val = 0;
	int data_len = 0;

	val = (int)(dval * pow(10, nb_dec));
	char tmp[32];
	memset(tmp, 0, 32);
	sprintf_s(tmp, "%d", val);

	data_len = strlen(tmp);

	memset(tmp, 0, 32);

	for (int i = 0; i < data_len; i++)
	{
		if (data_len % 2)
		{
			tmp[0] = 0;
			tmp[i + 1] = (int)(val / pow(10, data_len - i - 1)) % 10;
		}
		else
		{
			tmp[i] = (int)(val / pow(10, data_len - i - 1)) % 10;
		}
	}
	int index_tmp = 0;
	data_len = data_len % 2 == 0 ? data_len / 2 : data_len / 2 + 1;
	// printf("nb_byte:%d  nb_dec:%d val:%d data len:%d \n", nb_byte, nb_dec, val, data_len);

	//数据
	for (int i = nb_byte; i > 0; i--)
	{
		if ((i - data_len) > 0)
		{
			bufIn[nb_byte - i] = 0;
		}
		else
		{
			bufIn[nb_byte - i] = dec2bcd(tmp[0 + index_tmp * 2] * 10 + tmp[1 + index_tmp * 2]);
			index_tmp += 1;
		}
	}
}


// CRC8 多项式,这里使用常见的0x31(x^8 + x^5 + x^4 + 1)
#define POLYNOMIAL 0x31

// 计算CRC8校验值
uint8_t calculateCRC8(uint8_t *data, uint16_t length) 
{
    uint8_t crc = 0;
    for (size_t i = 0; i < length; i++) {
        crc ^= data[i];
        for (int j = 0; j < 8; j++) {
            if (crc & 0x80) {
                crc = (crc << 1) ^ POLYNOMIAL;
            } else {
                crc <<= 1;
            }
        }
    }
    return crc;
}

/// @brief 判断是否有扩展域(即是否存在Password TimeTag)
/// @param AFN 
/// @return 存在返回1
uint8_t SZY206_IsAux(uint8_t AFN) 
{
    // 以下功能码对应的帧包含密码和时间标签扩展域
    switch (AFN) {
    case SET_TERMINAL_ADDRESS:
    case SET_TERMINAL_CLOCK:
    case SET_TERMINAL_WORK_MODE:
    case SET_TERMINAL_CURRENT_RECHARGE_AMOUNT:
    case SET_TERMINAL_REMAINING_WATER_ALARM_VALUE:
    case SET_TERMINAL_WATER_LEVEL_BASE_AND_LIMITS:
    case SET_TERMINAL_WATER_PRESSURE_LIMITS:
    case SET_TERMINAL_WATER_QUALITY_PARAMETER_UPPER_LIMIT:
    case SET_TERMINAL_WATER_QUALITY_PARAMETER_LOWER_LIMIT:
    case SET_TERMINAL_INITIAL_WATER_AMOUNT:
    case SET_TERMINAL_FORWARD_RELAY_LEADING_CODE_LENGTH:
    case SET_RELAY_FORWARD_TERMINAL_ADDRESS:
    case SET_RELAY_WORK_MACHINE_AUTO_SWITCH_AND_SELF_REPORT_STATUS:
    case SET_TERMINAL_FLOW_PARAMETER_UPPER_LIMIT:
    case SET_TERMINAL_DETECTION_PARAMETER_TRIGGER_THRESHOLD_AND_STORAGE_INTERVAL:
    case SET_TERMINAL_IC_CARD_FUNCTION_ENABLE:
    case SET_TERMINAL_IC_CARD_FUNCTION_DISABLE:
    case FIXED_VALUE_CONTROL_ENGAGE:
    case FIXED_VALUE_CONTROL_DISENGAGE:
    case FIXED_VALUE_SETTING:
    case MODIFY_TERMINAL_PASSWORD:
    case SET_TERMINAL_REAL_TIME_DATA_TYPE_TO_QUERY:
    case SET_TERMINAL_SELF_REPORT_DATA_TYPE_AND_INTERVAL:
        return 1;  // 存在扩展域
    default:
        return 0;  // 不存在扩展域
    }
}


/// @brief 填充数据
/// @param buffer 缓存
/// @param control 控制域
/// @param address 地址域
/// @param AFN 功能码
/// @param password 密码
/// @param time_tag 时间
/// @param user_data 用户数据
/// @param user_data_length 用户数据长度
/// @return  帧总长度
uint8_t SZY206_FrameFill(uint8_t *buffer, ControlField control, uint8_t *address, uint8_t AFN,
                         Password password, TimeTag time_tag, uint8_t *user_data, uint16_t user_data_length) {
    // 将buffer转换为SZY206_Frame_T指针
    SZY206_Frame_T *frame = (SZY206_Frame_T *)buffer;
    uint8_t *data_for_crc = &frame->control;
    uint16_t length=0;
    uint8_t isAux;
    uint16_t frame_length=0;
    // 起始字符
    frame->start_frame = FRAME_START;
    frame->start_frame2 = FRAME_START;
    // 控制域
    frame->control = control;
    // 地址域
    memcpy(frame->address ,address,5);
    // 应用层功能码
    frame->AFN = AFN;

    // 计算长度L(控制域、地址域、用户数据域、密码、时间标签的字节总数)
    length =  sizeof(ControlField)+5+1+user_data_length;
    if(isAux) 
        length = length +sizeof(Password)+sizeof(TimeTag);
    frame->length = length; 
    // 用户数据域
    // 拷贝用户数据到buffer
    memcpy(frame->user_data,user_data,user_data_length);
    //偏移指针
    frame = frame+user_data_length;
    isAux = SZY206_IsAux(AFN);
    if(isAux) {
        // 密码PW
        frame->password = password;
        // 时间标签Tp
        frame->time_tag = time_tag;
    } else {
        frame =frame-sizeof(Password)+sizeof(TimeTag);
    }

    // 计算校验和CS(CRC8校验)
    uint8_t crc = calculateCRC8(data_for_crc, length);
    frame->checksum = crc;
    // 结束字符
    frame->end_char = FRAME_END;
    frame_length=SZY206_FIX_HEAD_LEN+length+2;  // 返回填充后的帧长度(包括起始字符和结束字符)
    return frame_length;
}

/// @brief 检验帧的正确性
/// @param buffer 缓存
/// @param length 缓存长度
/// @return 
uint8_t SZY206_FrameVerification(uint8_t *buffer , uint16_t length)
{
    if(buffer ==NULL)
        return 0;
    // 最小帧长度为(两个起始字符、控制域、地址域、应用层功能码、校验码和结束字符)
    if (length < SZY206_MIN_FRAME_LEN) 
        return 0;  // 帧长度过短,错误
    // 将buffer转换为SZY206_Frame_T指针
    uint8_t crc=0;
    SZY206_Frame_T *frame = (SZY206_Frame_T *)buffer;
    if(frame->start_frame!=FRAME_START || frame->start_frame2!=FRAME_START)
        return 0;
    crc = calculateCRC8(&frame->control,frame->length);
    if(frame->length > SZY206_USER_DATA_OFFSET-SZY206_FIX_HEAD_LEN)  //是否存在用户数据
        frame = frame+frame->length;
    if(!SZY206_IsAux(frame->AFN)){
        frame = frame-sizeof(Password)+sizeof(TimeTag);
    }
    if(crc != frame->checksum)
        return 0;
    if(frame->end_char != FRAME_END)
        return 0;
    return 1;
}

/// @brief 解析帧
/// @param buffer 
/// @param length 
/// @param control 控制域
/// @param AFN 功能吗
/// @param user_data 用户数据
/// @return 
uint8_t SZY206_Parse(uint8_t *buffer , uint16_t length ,ControlField  *control , uint8_t *AFN,
                    Password *password ,TimeTag *time_tag,uint8_t *user_data)
{
    if(buffer ==NULL)
        return 0;
    SZY206_Frame_T *frame = (SZY206_Frame_T *)buffer;
    *control = frame->control;
    *AFN = frame->AFN;
    *user_data = frame->user_data;
    if(SZY206_IsAux(frame->AFN) && frame->length > SZY206_USER_DATA_OFFSET-SZY206_FIX_HEAD_LEN) {
        frame = frame+frame->length;
        *password = frame->password;
        *time_tag = frame->time_tag;
    }
    return 1;
}


szy_main.c 列程


#include "szy_206.h"
// 示例:查询遥测终端实时值(下行)
void queryTerminalRealTimeValueDown() {
    // 控制域设置
    ControlField control;
    control.DIR = 0;   // 下行帧
    control.DIV = 0;   // 单帧
    control.FCB = 0;   // 初始帧计数位
    control.function_code = DOWN_QUERY_RESPONSE_INTEGRATED;   // 查询综合参数实时值

    // 地址域设置(假设地址为0102030405)
    uint8_t address[5] = {0x01, 0x02, 0x03, 0x04, 0x05};

    // 应用层功能码
    uint8_t AFN = QUERY_TERMINAL_REAL_TIME_VALUE;

    // 其他参数(密码、时间标签等,此处假设为默认值)
    Password password = {0};   // 密码部分根据实际情况填充或保持默认
    TimeTag time_tag = {0};   // 时间标签部分根据实际情况填充或保持默认

    // 用户数据(根据查询类型确定,这里查询综合参数实时值,示例数据为雨量、水位有值,其他参数无值)
    uint8_t user_data[1] = {0b00000011};   // 表示雨量、水位参数存在

    // 计算帧长度并填充帧
    uint16_t user_data_length = sizeof(user_data);
    uint8_t buffer[SZY206_MIN_FRAME_LEN + user_data_length];   // 根据预计最大长度分配缓冲区
    uint8_t frame_length = SZY206_FrameFill(buffer, control, address, AFN, password, time_tag, user_data, user_data_length);

    // 发送帧(这里假设通过串口发送,实际根据通信方式实现)
    sendFrame(buffer, frame_length);   // 发送帧的函数需根据实际通信方式实现
}

// 示例:解析查询遥测终端实时值的上行帧
void parseQueryTerminalRealTimeValueUp(uint8_t *received_buffer, uint16_t received_length) {
    // 验证帧的正确性
    if (SZY206_FrameVerification(received_buffer, received_length)) {
        // 解析帧
        ControlField control;
        uint8_t AFN;
        Password password;
        TimeTag time_tag;
        uint8_t *user_data;
        if (SZY206_Parse(received_buffer, received_length, &control, &AFN, &password, &time_tag, &user_data)) {
            if (control.DIR == 1 && AFN == QUERY_TERMINAL_REAL_TIME_VALUE) {
                // 根据数据域格式解析数据(这里仅为示例,实际根据文档详细格式解析)
                // 假设解析雨量、水位、流量等参数
                uint8_t rainfall[3];
                uint8_t water_level[4];
                uint8_t flow[5];
                memcpy(rainfall, user_data, 3);
                memcpy(water_level, user_data + 3, 4);
                memcpy(flow, user_data + 7, 5);
                // 处理解析后的数据(打印或存储等操作)
                printf("Rainfall: %.1f mm\n", (float)(rainfall[0] + (rainfall[1] << 8) + (rainfall[2] << 16)) / 10);
                printf("Water Level: %.3f m\n", (float)(water_level[0] + (water_level[1] << 8) + (water_level[2] << 16) + (water_level[3] << 24)) / 1000);
                printf("Flow: %.3f m³/s\n", (float)(flow[0] + (flow[1] << 8) + (flow[2] << 16) + (flow[3] << 24) + (flow[4] << 32)) / 1000);
            }
        }
    } else {
        printf("Received frame is incorrect.\n");
    }
}



// 示例:设置遥测终端工作模式(下行)
void setTerminalWorkModeDown() {
    // 控制域设置
    ControlField control;
    control.DIR = 0;   // 下行帧
    control.DIV = 0;   // 单帧
    control.FCB = 0;   // 初始帧计数位
    control.function_code = DOWN_SEND_CONFIRM_COMMAND;   // 发送/确认命令

    // 地址域设置(假设地址为0102030405)
    uint8_t address[5] = {0x01, 0x02, 0x03, 0x04, 0x05};

    // 应用层功能码
    uint8_t AFN = SET_TERMINAL_WORK_MODE;

    // 密码(假设密码算法为1,密钥为123)
    Password password;
    password.key_algorithm = 1;
    password.key = 123;

    // 时间标签(假设当前时间为2023年10月10日10时10分10秒,允许延时10分钟)
    TimeTag time_tag;
    time_tag.start_frame_send_time = (10 << 24) | (10 << 16) | (10 << 8) | 10;   // 秒、分、时、日的BCD码组合
    time_tag.allow_send_transfer_delay_time = 10;

    // 用户数据(设置工作模式为自报工作状态,01H)
    uint8_t user_data[1] = {0x01};

    // 计算帧长度并填充帧
    uint16_t user_data_length = sizeof(user_data);
    uint8_t buffer[SZY206_MIN_FRAME_LEN + user_data_length];   // 根据预计最大长度分配缓冲区
    uint8_t frame_length = SZY206_FrameFill(buffer, control, address, AFN, password, time_tag, user_data, user_data_length);

    // 发送帧(这里假设通过串口发送,实际根据通信方式实现)
    sendFrame(buffer, frame_length);   // 发送帧的函数需根据实际通信方式实现
}


// 示例:解析设置遥测终端工作模式的上行确认帧
void parseSetTerminalWorkModeUp(uint8_t *received_buffer, uint16_t received_length) {
    // 验证帧的正确性
    if (SZY206_FrameVerification(received_buffer, received_length)) {
        // 解析帧
        ControlField control;
        uint8_t AFN;
        Password password;
        TimeTag time_tag;
        uint8_t *user_data;
        if (SZY206_Parse(received_buffer, received_length, &control, &AFN, &password, &time_tag, &user_data)) {
            if (control.DIR == 1 && AFN == SET_TERMINAL_WORK_MODE) {
                // 根据确认帧数据域格式解析数据(这里假设数据域为1字节,表示终端工作模式确认)
                uint8_t work_mode_confirmation = *user_data;
                if (work_mode_confirmation == 0x01) {
                    printf("Terminal work mode set to self-report successfully.\n");
                } else {
                    printf("Terminal work mode set failed.\n");
                }
            }
        }
    } else {
        printf("Received frame is incorrect.\n");
    }
}


// 示例:遥测终端自报实时数据(上行)
void terminalSelfReportRealTimeDataUp() {
    // 控制域设置
    ControlField control;
    control.DIR = 1;   // 上行帧
    control.DIV = 0;   // 单帧
    control.FCB = 0;   // 初始帧计数位
    control.function_code = UP_SELF_REPORT_RAINFALL;   // 自报雨量数据

    // 地址域设置(假设地址为0102030405)
    uint8_t address[5] = {0x01, 0x02, 0x03, 0x04, 0x05};

    // 应用层功能码
    uint8_t AFN = TERMINAL_SELF_REPORT_REAL_TIME_DATA;

    // 其他参数(密码、时间标签等,此处假设为默认值)
    Password password = {0};   // 密码部分根据实际情况填充或保持默认
    TimeTag time_tag = {0};   // 时间标签部分根据实际情况填充或保持默认

    // 用户数据(假设雨量值为10.5mm,根据数据格式转换为BCD码)
    uint8_t user_data[3];
    SZY206_Dec2bcd(user_data, 10.5, 3, 1);   // 将雨量值转换为BCD码格式

    // 计算帧长度并填充帧
    uint16_t user_data_length = sizeof(user_data);
    uint8_t buffer[SZY206_MIN_FRAME_LEN + user_data_length];   // 根据预计最大长度分配缓冲区
    uint8_t frame_length = SZY206_FrameFill(buffer, control, address, AFN, password, time_tag, user_data, user_data_length);

    // 发送帧(这里假设通过无线通信模块发送,实际根据通信方式实现)
    sendFrame(buffer, frame_length);   // 发送帧的函数需根据实际通信方式实现
}


// 示例:解析遥测终端自报实时数据的下行确认帧
void parseTerminalSelfReportRealTimeDataDown(uint8_t *received_buffer, uint16_t received_length) {
    // 验证帧的正确性
    if (SZY206_FrameVerification(received_buffer, received_length)) {
        // 解析帧
        ControlField control;
        uint8_t AFN;
        Password password;
        TimeTag time_tag;
        uint8_t *user_data;
        if (SZY206_Parse(received_buffer, received_length, &control, &AFN, &password, &time_tag, &user_data)) {
            if (control.DIR == 0 && AFN == TERMINAL_SELF_REPORT_REAL_TIME_DATA) {
                // 根据确认帧数据域格式解析数据(这里假设数据域为1字节,表示终端工作模式确认)
                uint8_t work_mode_confirmation = *user_data;
                if (work_mode_confirmation == 0x01) {
                    printf("Terminal is in self-report work mode.\n");
                } else if (work_mode_confirmation == 0x02) {
                    printf("Terminal is in query/response work mode.\n");
                } else {
                    printf("Terminal work mode confirmation error.\n");
                }
            }
        }
    } else {
        printf("Received frame is incorrect.\n");
    }
}

http://www.kler.cn/a/467972.html

相关文章:

  • QPainter,QPen,QBrush详解
  • 【读书与思考】历史是一个好东西
  • 3.final关键字
  • 【Redis经典面试题七】Redis的事务机制是怎样的?
  • JavaScript语言的编程范式
  • Which CAM is Better for Extracting Geographic Objects? A Perspective From参考文献
  • 深入解析 Redisson 分布式限流器 RRateLimiter 的原理与实现
  • python识别outlook邮件并且将pdf文件作为附件发送邮件
  • 矩阵运算提速——玩转opencv::Mat
  • 电脑键盘打不了字是何原因,如何解决呢
  • 软件需求规格是什么
  • CSS——4. 行内样式和内部样式(即CSS引入方式)
  • 连接Milvus
  • Apache PDFBox添加maven依赖,pdf转成图片
  • 人工智能(AI)简史:推动新时代的科技力量
  • 详解MySQL SQL删除(超详,7K,含实例与分析)
  • PaperAssistant:使用Microsoft.Extensions.AI实现
  • Uniapp中使用`wxml-to-canvas`开发DOM生成图片功能
  • Traceroute 网络诊断工具实战详解
  • 中高级运维工程师运维面试题(九)之 Apache Pulsar
  • MySQL优化器估算SQL语句访问行数的深入分析
  • MIPI_DPU 综合(DPU+MIPI+Demosaic+VDMA 通路)
  • Django Admin中实现字段自动提交功能
  • 文献分享:跨模态的最邻近查询RoarGraph
  • BGP的基本配置
  • OC中isa指针