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)
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;
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, SET_TERMINAL_IC_CARD_FUNCTION_DISABLE = 0x31, 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;
#pragma pack(1)
typedef struct {uint8_t key_algorithm : 4; uint16_t key:12;
} Password;
#pragma pack(1)
typedef struct {uint32_t start_frame_send_time; uint8_t allow_send_transfer_delay_time;
} TimeTag;
#pragma pack(1)
typedef struct {uint8_t start_frame; uint8_t length; uint8_t start_frame2; ControlField control; uint8_t address[5]; uint8_t AFN; uint8_t* user_data; Password password; TimeTag time_tag; uint8_t checksum; uint8_t end_char;
} SZY206_Frame_T;#define SZY206_FIX_HEAD_LEN (3)
#define SZY206_USER_DATA_OFFSET (SZY206_FIX_HEAD_LEN+sizeof(ControlField)+5+1)
#define SZY206_MIN_FRAME_LEN (SZY206_USER_DATA_OFFSET+2) 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>
static int dec2bcd(unsigned char data)
{unsigned char temp;temp = (((data / 10) << 4) + (data % 10));return temp;
}
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;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;}}
}
#define POLYNOMIAL 0x31
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;
}
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; }
}
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) {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;length = sizeof(ControlField)+5+1+user_data_length;if(isAux) length = length +sizeof(Password)+sizeof(TimeTag);frame->length = length; memcpy(frame->user_data,user_data,user_data_length);frame = frame+user_data_length;isAux = SZY206_IsAux(AFN);if(isAux) {frame->password = password;frame->time_tag = time_tag;} else {frame =frame-sizeof(Password)+sizeof(TimeTag);}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;
}
uint8_t SZY206_FrameVerification(uint8_t *buffer , uint16_t length)
{if(buffer ==NULL)return 0;if (length < SZY206_MIN_FRAME_LEN) return 0; 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;
}
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; 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; uint8_t address[5] = {0x01, 0x02, 0x03, 0x04, 0x05};uint8_t AFN = SET_TERMINAL_WORK_MODE;Password password;password.key_algorithm = 1;password.key = 123;TimeTag time_tag;time_tag.start_frame_send_time = (10 << 24) | (10 << 16) | (10 << 8) | 10; time_tag.allow_send_transfer_delay_time = 10;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) {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; 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}; uint8_t user_data[3];SZY206_Dec2bcd(user_data, 10.5, 3, 1); 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) {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");}
}