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");
}
}