/************************************************* Copyright (c) 2019 All rights reserved. File name: dlt645_data.c Description: DLT645 数据处理源文件 History: 1. Version: Date: 2019-09-20 Author: wangjunjie Modify: *************************************************/ #include "dlt645_private.h" #include #include "data_task.h" //字节位置枚举类型 typedef enum { BYTE_RESET = 0, //重置 BYTE_LOW_ADDRESS, //低位 BYTE_HIGH_ADDRESS //高位 } byte_part; /** * Name: _crc * Brief: crc和校验 * Input: * @msg: 校验数据包 * @len: 数据包长度 * Output: 校验值 */ int _crc(uint8_t *msg, int len) { uint8_t crc = 0; while (len--) { crc += *msg++; } return crc; } /** * Name: dlt645_common_check * Brief: 645协议接收数据公共部分校验 * Input: * @msg: 校验数据包 * @len: 数据包长度 * @addr: 从站地址 * Output: 校验成功:0,校验失败:-1 */ int dlt645_common_check(uint8_t *msg, int len, uint8_t *addr) { //数据包长度校验 if (len < 7) { return -1; } //数据帧标志校验 if (msg[0] != DL645_START_CODE || msg[DL645_ADDR_LEN + 1] != DL645_START_CODE || msg[len - 1] != DL645_STOP_CODE) { DLT645_LOG("check code error!\n"); return -1; } //CRC校验 uint8_t crc = _crc(msg, len - 2); if (crc != msg[len - 2]) { DLT645_LOG("check crc error!\n"); return -1; } //控制码主从校验 if ((msg[DL645_CONTROL_POS] & C_TD_MASK) == (C_TD_MASTER << C_TD_POS)) { DLT645_LOG("check control direction error!\n"); return -1; } //控制码应答校验 if ((msg[DL645_CONTROL_POS] & C_ACK_MASK) == (C_ACK_ERR << C_ACK_POS)) { DLT645_LOG("check ACK error!\n"); return msg[len - 3]; } //从站地址校验 if (memcmp(msg + 1, addr, 6) != 0) { return -1; } return 0; } /** * Name: dec2bcd * Brief: 十进制转BCD码(目前支持32位数字大小) * Input: * @val: 十进制值 * Output: BCD码值 */ uint32_t dec_to_bcd(uint32_t val) { uint32_t data = 0; if (val < 100) { uint8_t byte0 = val % 10; uint8_t byte1 = val / 10; data = (byte1 << 4) + byte0; } else if (val < 10000) { uint8_t byte0 = val % 10; uint8_t byte1 = (val / 10) % 10; uint8_t byte2 = (val / 100) % 10; uint8_t byte3 = (val / 1000) % 10; data = (byte3 << 12) + (byte2 << 8) + (byte1 << 4) + byte0; } else if (val < 1000000) { uint8_t byte0 = val % 10; uint8_t byte1 = (val / 10) % 10; uint8_t byte2 = (val / 100) % 10; uint8_t byte3 = (val / 1000) % 10; uint8_t byte4 = (val / 10000) % 10; uint8_t byte5 = (val / 100000) % 10; data = (byte5 << 20) + (byte4 << 16) + (byte3 << 12) + (byte2 << 8) + (byte1 << 4) + byte0; } else if (val < 100000000) { uint8_t byte0 = val % 10; uint8_t byte1 = (val / 10) % 10; uint8_t byte2 = (val / 100) % 10; uint8_t byte3 = (val / 1000) % 10; uint8_t byte4 = (val / 10000) % 10; uint8_t byte5 = (val / 100000) % 10; uint8_t byte6 = (val / 1000000) % 10; uint8_t byte7 = (val / 10000000) % 10; data = (byte7 << 28) + (byte6 << 24) + (byte5 << 20) + (byte4 << 16) + (byte3 << 12) + (byte2 << 8) + (byte1 << 4) + byte0; } return data; } /** * Name: str_to_bcd * Brief: 字符串转BCD形式 * Input: * @str: 要转换的字符串 * @bcd_store_address: 转换后的存储地址 * @bcd_len: BCD码总长度 * Output: 成功0,失败-1 */ int str_to_bcd(char *str, uint8_t *bcd_store_address, uint16_t bcd_len) { //字符串偏移 int str_pos = bcd_len * 2 - strlen(str); //字符串比BCD码长度长 if (str_pos < 0) { return -1; } memset(bcd_store_address, 0, bcd_len); for (int i = 0; i < strlen(str); i++) { if (str[i] >= '0' && str[i] <= '9') { bcd_store_address[(i + str_pos) / 2] |= (str[i] - '0') << (4 * ((i + 1 + (strlen(str) % 2)) % 2)); } else { //当前字符不为数字,返回错误 return -1; } } return 0; } /** * Name: data_package_translate_to_int * Brief: 将接收到的dlt645数据包中的数据转化为整数 * Input: * @read_data: 数据首地址 * @len: 数据长度 * Output: 转化后的整数 */ int data_package_translate_to_int(uint8_t *read_data, uint16_t len) { //权值 uint8_t number_weight = 0; //当前数组下标索引 uint8_t current_index = 0; //当前解析字节位 uint8_t current_byte_part = BYTE_RESET; //当前整数值 int i_value = 0; while (len--) { current_byte_part = BYTE_LOW_ADDRESS; do { switch (current_byte_part) { //当前处理字节低位 case BYTE_LOW_ADDRESS: i_value += ((read_data[current_index] - 0x33) & 0x0f) * my_pow(10,number_weight); number_weight++; current_byte_part = BYTE_HIGH_ADDRESS; break; //当前处理字节高位 case BYTE_HIGH_ADDRESS: i_value += ((read_data[current_index] - 0x33) >> 4) * my_pow(10,number_weight); number_weight++; current_byte_part = BYTE_RESET; break; } } while (current_byte_part != BYTE_RESET); current_index++; } return i_value; } /** * Name: dlt645_data_parse_by_format_to_float * Brief: 根据数据格式将645协议读取的数据转换为真实数据并存储 * !真实数据为浮点数据,需要注意的是无论读取数据长度是多少,存储数据长度都应是4字节 * Input: * @read_data: 645协议读取的数据 * @read_len: 读取数据的长度 * @data_format: 转换的数据格式,如 XX.XX,XX.XXX * Output: 转换成功返回0,失败返回-1 */ int dlt645_data_parse_by_format_to_float(uint8_t *read_data, uint16_t read_len, const char *data_format, uint8_t *store_address) { //权值 int num_weight = 0; int ival = data_package_translate_to_int(read_data, read_len); for (int i = 0; i < strlen(data_format); i++) { if (*(data_format + i) == '.') { num_weight = strlen(data_format) - i - 1; if (num_weight < 0) { return -1; } break; } } float fval = ival / my_pow(10,num_weight); memcpy(store_address, &fval, 4); return 0; } int dlt645_data_parse_by_format_to_float_and_DATE(uint8_t *read_data, uint16_t read_len, const char *data_format, uint8_t *store_address) { int num_weight = 0; int ival = data_package_translate_to_int(read_data, read_len); for (int i = 0; i < strlen(data_format); i++) { if (*(data_format + i) == '.') { num_weight = strlen(data_format) - i - 1; if (num_weight < 0) { return -1; } break; } } float fval = ival / my_pow(10,num_weight); memcpy(store_address, &fval, 4); return 0; }