sl_651.h
#ifndef __SL_651_H__
#define __SL_651_H__
#include "stdint.h"
typedef enum {
SOH = 0x7E7E,
STX = 0x02,
SYN = 0x16,
ETX = 0x03,
ETB = 0x17,
ENQ = 0x05,
EOT = 0x04,
ACK = 0x06,
NAK = 0x15,
ESC = 0x1B
} ControlCharacter;
typedef enum {
FUNCTION_CODE_RESERVED_00H_2EH = 0x00,
FUNCTION_CODE_LINK_MAINTENANCE = 0x2F,
FUNCTION_CODE_TEST = 0x30,
FUNCTION_CODE_UNIFORM_TIME_HYDRO_INFO = 0x31,
FUNCTION_CODE_TIMED_REPORT = 0x32,
FUNCTION_CODE_ADDITIONAL_REPORT = 0x33,
FUNCTION_CODE_HOURLY_REPORT = 0x34,
FUNCTION_CODE_MANUAL_SETTING = 0x35,
FUNCTION_CODE_PICTURE_INFO = 0x36,
FUNCTION_CODE_QUERY_REAL_TIME_DATA = 0x37,
FUNCTION_CODE_QUERY_TIME_PERIOD_DATA = 0x38,
FUNCTION_CODE_QUERY_MANUAL_SETTING = 0x39,
FUNCTION_CODE_QUERY_SPECIFIED_ELEMENT_DATA = 0x3A,
FUNCTION_CODE_RESERVED_3B_3FH = 0x3B,
FUNCTION_CODE_MODIFY_STATION_CONFIG = 0x40,
FUNCTION_CODE_READ_STATION_CONFIG = 0x41,
FUNCTION_CODE_MODIFY_RUNNING_PARAM_CONFIG = 0x42,
FUNCTION_CODE_READ_RUNNING_PARAM_CONFIG = 0x43,
FUNCTION_CODE_QUERY_PUMP_MOTOR_DATA = 0x44,
FUNCTION_CODE_QUERY_TERMINAL_VERSION = 0x45,
FUNCTION_CODE_QUERY_STATION_STATUS = 0x46,
FUNCTION_CODE_INITIALIZE_STORAGE = 0x47,
FUNCTION_CODE_RESTORE_FACTORY_SETTINGS = 0x48,
FUNCTION_CODE_MODIFY_PASSWORD = 0x49,
FUNCTION_CODE_SET_STATION_CLOCK = 0x4A,
FUNCTION_CODE_SET_TERMINAL_IC_CARD_STATUS = 0x4B,
FUNCTION_CODE_CONTROL_PUMP_SWITCH = 0x4C,
FUNCTION_CODE_CONTROL_VALVE_SWITCH = 0x4D,
FUNCTION_CODE_CONTROL_GATE_SWITCH = 0x4E,
FUNCTION_CODE_WATER_QUANTITY_CONTROL = 0x4F,
FUNCTION_CODE_QUERY_STATION_EVENT_RECORD = 0x50,
FUNCTION_CODE_QUERY_STATION_CLOCK = 0x51,
FUNCTION_CODE_RESERVED_52H_DFH = 0x52,
FUNCTION_CODE_USER_DEFINED_EXTENSION_START = 0xE0
} FunctionCode;
typedef enum {
OBSERVATION_TIME_GUIDE = 0xF0,
STATION_CODE_GUIDE = 0xF1,
MANUAL_SETTING = 0xF2
} IdentifierGuides;
#pragma pack(1)
typedef struct {
uint8_t dataSize : 5;
uint8_t decimalPlaces : 3;
} DataFormat;
#pragma pack(1)
typedef struct {
uint8_t identifier;
DataFormat data_format;
uint8_t *user_data;
} UserDataGroup;
#define USER_DATA_GROUP_FIX_LEN (1+sizeof(DataFormat))
#pragma pack(1)
typedef struct {
uint16_t isUpload: 1;
uint16_t reserved: 3;
uint16_t length: 12;
} MessageIdentifierAndLength;
#pragma pack(1)
typedef struct {
uint16_t start_frame;
uint8_t centerStationAddress[6];
uint16_t password;
uint8_t functionCode;
MessageIdentifierAndLength messageIdentifierAndLength;
uint8_t user_data_start;
uint16_t serialNumber;
uint8_t reportTime[6];
uint8_t *user_data;
uint8_t end_frame;
uint16_t checksum;
} SL651_Frame_T;
#define SL651_FRAME_FIX_HEAD_LEN (1+6+2+1+sizeof(MessageIdentifierAndLength)+1+2+6)
#define SL651_FRAME_LEN(user_data_length) (SL651_FRAME_FIX_HEAD_LEN+user_data_length+1+2)
#define SL651_DATA_LEN(frame_length) (frame_length-2-1-5-2-1-2-1-1-2)
#endif
sl_651.c
#include "sl_651.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
uint16_t generateSerialNumber() {
static uint16_t currentSerialNumber = 1;
uint16_t serialNumber = currentSerialNumber;
currentSerialNumber++;
if (currentSerialNumber > 65535) {
currentSerialNumber = 1;
}
return serialNumber;
}
static uint16_t SL651_Crc16(uint8_t *buf, int usDataLen)
{
int i;
uint16_t crc_reg, j, check;
crc_reg = 0xFFFF;
for (i = 0; i < usDataLen; i++)
{
crc_reg = (crc_reg >> 8) ^ buf[i];
for (j = 0; j < 8; j++)
{
check = crc_reg & 0x0001;
crc_reg >>= 1;
if (check == 0x0001)
{
crc_reg ^= 0xA001;
}
}
}
return crc_reg;
}
static int dec2bcd(unsigned char data)
{
unsigned char temp;
temp = (((data / 10) << 4) + (data % 10));
return temp;
}
static void sl651_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;
}
}
}
uint16_t SL651_GetUserDataGroup(uint8_t *buffer,uint8_t identifier,DataFormat data_format,uint8_t *user_data,uint16_t user_data_length)
{
if(buffer==0)
return 0;
UserDataGroup *dataGroup = (UserDataGroup *)buffer;
dataGroup->identifier =identifier;
dataGroup->data_format =data_format;
memcpy(dataGroup->user_data ,user_data,user_data_length);
return USER_DATA_GROUP_FIX_LEN+user_data_length;
}
uint16_t SL651_FrameFill(uint8_t *buffer,
uint8_t centerStationAddress[6],
uint16_t password,
uint8_t functionCode,
MessageIdentifierAndLength messageIdentifierAndLength,
uint8_t reportTime[6],
uint8_t *user_data,
uint16_t user_data_length
)
{
SL651_Frame_T *frame = (SL651_Frame_T *)buffer;
frame->start_frame = SOH;
memcpy(frame->centerStationAddress, centerStationAddress, 6);
frame->password = password;
frame->functionCode = functionCode;
frame->messageIdentifierAndLength = messageIdentifierAndLength;
frame->user_data_start = STX;
frame->serialNumber = generateSerialNumber();
memcpy(frame->reportTime, reportTime, 6);
memcpy(frame->user_data ,user_data,user_data_length);
frame = frame+user_data_length;
frame->end_frame = ETX;
uint16_t crc = SL651_Crc16((uint8_t *)buffer, SL651_FRAME_LEN(user_data_length)-2);
frame->checksum = crc;
return SL651_FRAME_LEN(user_data_length);
}
uint8_t SL651_FrameVerification(uint8_t *buffer , uint16_t length)
{
if(buffer == NULL)
return 0;
SL651_Frame_T *frame = (SL651_Frame_T *)buffer;
if(frame->start_frame != SOH || frame->user_data_start!=STX || buffer[length-3] != ETX)
return 0;
if(frame->messageIdentifierAndLength.length != SL651_DATA_LEN(length))
return 0;
uint16_t crc =SL651_Crc16(buffer,length-2);
if(memcmp(crc,buffer[length-2],2)!=0)
return 0;
return 1;
}
uint8_t SL651_FrameHeadParse(uint8_t *buffer, uint8_t *centerStationAddress,
uint8_t *remoteAddress[5], uint16_t *password,
uint8_t *functionCode,
MessageIdentifierAndLength *messageIdentifierAndLength)
{
if (buffer == NULL)
return 0;
SL651_Frame_T *frame = (SL651_Frame_T *)buffer;
uint8_t isUpload = frame->messageIdentifierAndLength.isUpload;
if (isUpload) {
memcpy(centerStationAddress, frame->centerStationAddress, 1);
memcpy(*remoteAddress, frame->centerStationAddress + 1, 5);
} else {
memcpy(*remoteAddress, frame->centerStationAddress, 5);
memcpy(centerStationAddress, frame->centerStationAddress + 5, 1);
}
*password = frame->password;
*functionCode = frame->functionCode;
*messageIdentifierAndLength = frame->messageIdentifierAndLength;
return 1;
}
sl_main.c 列程
#include "sl_651.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
uint8_t* generateTelemetryStationReport(uint8_t centerStationAddress[6], uint16_t password,
uint8_t reportTime[6], uint8_t *observationData,
uint16_t observationDataLength) {
uint16_t totalLength = SL651_FRAME_LEN(observationDataLength);
uint8_t *buffer = (uint8_t *)malloc(totalLength);
if (buffer == NULL) {
printf("内存分配失败!\n");
return NULL;
}
MessageIdentifierAndLength msgIdLen = {
.isUpload = 1,
.reserved = 0,
.length = totalLength - SL651_FRAME_FIX_HEAD_LEN - 1 - 2
};
uint16_t filledLength = SL651_FrameFill(buffer, centerStationAddress, password,
FUNCTION_CODE_UNIFORM_TIME_HYDRO_INFO,
msgIdLen, reportTime,
observationData, observationDataLength);
if (filledLength!= totalLength) {
printf("遥测站自报报文填充失败!\n");
free(buffer);
return NULL;
}
return buffer;
}
void parseTelemetryStationReport(uint8_t *message, uint16_t messageLength) {
if (!SL651_FrameVerification(message, messageLength)) {
printf("报文验证失败,可能损坏或格式不正确!\n");
return;
}
uint8_t centerStationAddress[6];
uint8_t *remoteAddress[5];
uint16_t password;
uint8_t functionCode;
MessageIdentifierAndLength msgIdLen;
if (!SL651_FrameHeadParse(message, centerStationAddress, remoteAddress, &password,
&functionCode, &msgIdLen)) {
printf("报文头解析失败!\n");
return;
}
printf("遥测站自报上行报文解析结果:\n");
printf("帧起始符: 0x%04X\n", ((SL651_Frame_T *)message)->start_frame);
printf("中心站地址: ");
for (int i = 0; i < 6; i++) {
printf("%02X ", centerStationAddress[i]);
}
printf("\n");
printf("遥测站地址: ");
for (int i = 0; i < 5; i++) {
printf("%02X ", (*remoteAddress)[i]);
}
printf("\n");
printf("密码: 0x%04X\n", password);
printf("功能码: 0x%02X\n", functionCode);
printf("是否上行: %s\n", msgIdLen.isUpload? "是" : "否");
printf("报文正文长度: %d\n", msgIdLen.length);
printf("流水号: 0x%04X\n", ((SL651_Frame_T *)message)->serialNumber);
printf("发报时间: ");
for (int i = 0; i < 6; i++) {
printf("%02X ", ((SL651_Frame_T *)message)->reportTime[i]);
}
printf("\n");
printf("用户数据: ");
for (int i = 0; i < messageLength - SL651_FRAME_FIX_HEAD_LEN - 1 - 2; i++) {
printf("%02X ", ((SL651_Frame_T *)message)->user_data[i]);
}
printf("\n");
printf("校验码: 0x%04X\n", ((SL651_Frame_T *)message)->checksum);
}
uint8_t* generateCentralStationQuery(uint8_t centerStationAddress[6], uint16_t password,
FunctionCode functionCode, uint8_t *queryData,
uint16_t queryDataLength) {
uint16_t totalLength = SL651_FRAME_LEN(queryDataLength);
uint8_t *buffer = (uint8_t *)malloc(totalLength);
if (buffer == NULL) {
printf("内存分配失败!\n");
return NULL;
}
MessageIdentifierAndLength msgIdLen = {
.isUpload = 0,
.reserved = 0,
.length = totalLength - SL651_FRAME_FIX_HEAD_LEN - 1 - 2
};
uint16_t filledLength = SL651_FrameFill(buffer, centerStationAddress, password,
functionCode,
msgIdLen, NULL,
queryData, queryDataLength);
if (filledLength!= totalLength) {
printf("中心站查询报文填充失败!\n");
free(buffer);
return NULL;
}
return buffer;
}
void parseCentralStationQuery(uint8_t *message, uint16_t messageLength) {
if (!SL651_FrameVerification(message, messageLength)) {
printf("报文验证失败,可能损坏或格式不正确!\n");
return;
}
uint8_t centerStationAddress[6];
uint8_t *remoteAddress[5];
uint16_t password;
uint8_t functionCode;
MessageIdentifierAndLength msgIdLen;
if (!SL651_FrameHeadParse(message, centerStationAddress, remoteAddress, &password,
&functionCode, &msgIdLen)) {
printf("报文头解析失败!\n");
return;
}
printf("中心站查询下行报文解析结果:\n");
printf("帧起始符: 0x%04X\n", ((SL651_Frame_T *)message)->start_frame);
printf("中心站地址: ");
for (int i = 0; i < 6; i++) {
printf("%02X ", centerStationAddress[i]);
}
printf("\n");
printf("遥测站地址: ");
for (int i = 0; i < 5; i++) {
printf("%02X ", (*remoteAddress)[i]);
}
printf("\n");
printf("密码: 0x%04X\n", password);
printf("功能码: 0x%02X\n", functionCode);
printf("是否上行: %s\n", msgIdLen.isUpload? "是" : "否");
printf("报文正文长度: %d\n", msgIdLen.length);
printf("流水号: 0x%04X\n", ((SL651_Frame_T *)message)->serialNumber);
printf("用户数据: ");
for (int i = 0; i < messageLength - SL651_FRAME_FIX_HEAD_LEN - 1 - 2; i++) {
printf("%02X ", ((SL651_Frame_T *)message)->user_data[i]);
}
printf("\n");
printf("校验码: 0x%04X\n", ((SL651_Frame_T *)message)->checksum);
}
uint8_t* generateCentralStationSetting(uint8_t centerStationAddress[6], uint16_t password,
FunctionCode functionCode, uint8_t *settingData,
uint16_t settingDataLength) {
uint16_t totalLength = SL651_FRAME_LEN(settingDataLength);
uint8_t *buffer = (uint8_t *)malloc(totalLength);
if (buffer == NULL) {
printf("内存分配失败!\n");
return NULL;
}
MessageIdentifierAndLength msgIdLen = {
.isUpload = 0,
.reserved = 0,
.length = totalLength - SL651_FRAME_FIX_HEAD_LEN - 1 - 2
} ;
uint16_t filledLength = SL651_FrameFill(buffer, centerStationAddress, password,
functionCode,
msgIdLen, NULL,
settingData, settingDataLength);
if (filledLength!= totalLength) {
printf("中心站设置报文填充失败!\n");
free(buffer);
return NULL;
}
return buffer;
}
void parseCentralStationSetting(uint8_t *message, uint16_t messageLength) {
if (!SL651_FrameVerification(message, messageLength)) {
printf("报文验证失败,可能损坏或格式不正确!\n");
return;
}
uint8_t centerStationAddress[6];
uint8* remoteAddress[5];
uint16_t password;
uint8_t functionCode;
MessageIdentifierAndLength msgIdLen;
if (!SL651_FrameHeadParse(message, centerStationAddress, remoteAddress, &password,
&functionCode, &msgIdLen)) {
printf("报文头解析失败!\n");
return;
}
printf("中心站设置下行报文解析结果:\n");
printf("帧起始符: 0x%04X\n", ((SL651_Frame_T *)message)->start_frame);
printf("中心站地址: ");
for (int i = 0; i < 6; i++) {
printf("02X ", centerStationAddress[i]);
}
printf("\n");
printf("遥测站地址: ");
for (int i = 0; i < 5; i):
printf("%02X ", (*remoteAddress)[i]);
printf("\n");
printf("密码: 0x%04X\n", password);
printf("功能码: 0x%02X\n", functionCode);
printf("是否上行: %s\n", msgIdLen.isUpload? "是" : "否");
printf("报文正文长度: %d\n", msgIdLen.length);
printf("流水号: 0x%04X\n", ((SL651_Frame_T *)image)->serialNumber);
printf("用户数据: ");
for (int i = 0; i < messageLength - SL651_FRAME_FIX_HEAD_LEN - 1 - 2; i++) {
printf("%02X ", ((SL651_Frame_T *)message)->user_data[i]);
}
printf("\n");
printf("校验码: 0x%04X\n", ((SL651_Frame_T *)message)->checksum);
}
int main() {
uint8_t centerStationAddress[6] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB};
uint16_t password = 0x1234;
uint8_t reportTime[6] = {0x23, 0x08, 0x15, 0x10, 0x00, 0x00};
uint8_t observationData[10] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x10, 0x11};
uint8_t *telemetryStationReport = generateTelemetryStationReport(centerStationAddress, password,
reportTime, observationData,
sizeof(observationData));
if (telemetryStationReport!= NULL) {
printf("生成的遥测站自报上行报文:\n");
for (int i = 0; i < SL651_FRAME_LEN(sizeof(observationData)); i++) {
printf("%02X ", telemetryStationReport[i]);
}
printf("\n");
parseTelemetryStationReport(telemetryStationReport, SL651_FRAME_LEN(sizeof(observationData)));
free(telemetryStationReport);
}
uint8_t queryData[5] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE};
uint8_t *centralStationQuery = generateCentralStationQuery(centerStationAddress, password,
FUNCTION_CODE_QUERY_REAL_TIME_DATA,
queryData, sizeof(queryData));
if (centralStationQuery!= NULL) {
printf("生成的中心站查询下行报文:\n");
for (int i = 0; i < SL651_FRAME_LEN(sizeof(queryData)); i++) {
printf("%02X ", centralStationQuery[i]);
}
printf("\n");
parseCentralStationQuery(centralStationQuery, SL651_FRAME_LEN(sizeof(queryData)));
free(centralStationQuery);
}
uint8_t settingData[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
uint8_t *centralStationSetting = generateCentralStationSetting(centerStationAddress, password,
FUNCTION_CODE_MODIFY_STATION_CONFIG,
settingData, sizeof(settingData));
if (centralStationSetting!= NULL) {
printf("生成的中心站设置下行报文:\n");
for (int i = 0; i < SL651_FRAME_LEN(sizeof(settingData)); i++) {
printf("%02X ", centralStationSetting[i]);
}
printf("\n");
parseCentralStationSetting(centralStationSetting, SL651_FRAME_LEN(sizeof(settingData)));
free(centralStationSetting);
}
return 0;
}