gen_YDN23_protocol_send_cmd fixed YDN23(电总)协议发包INFO带数据的拼包方法
前言这几天去现场,给一台艾默生ExmUPS写采集数据的插件。发现有的包回的数据是0. 看协议,发包时,要指定模块号才行, 这样就要LENGTH不为0, INFO中放数据。INFO中带1个字节数据,LENGTH= 1 * 2;INFO中带2个字节数据,LENGTH = 2 * 2;INFO中带3个字节数据,LENGTH = 3 * 2;以前自己写了一个电总发包的拼包程序,整错了. INFO带了数据,
前言
这几天去现场,给一台艾默生ExmUPS写采集数据的插件。
发现有的包回的数据是0. 看协议,发包时,要指定模块号才行, 这样就要LENGTH不为0, INFO中放数据。
INFO中带1个字节数据,LENGTH= 1 * 2;
INFO中带2个字节数据,LENGTH = 2 * 2;
INFO中带3个字节数据,LENGTH = 3 * 2;
以前自己写了一个电总发包的拼包程序,整错了. INFO带了数据,拼出的包不对,修正了一下。
具体的电总协议,可以看 <<YD-T_1363.3-2005_通信局(站)电源、空调及环境集中监控管理系统第3部分:前端智能设备协议.pdf>>,拼包,回包分析都讲的很清楚。 csdn的ailun1982同学上传过一份YD-T_1363.3-2005_通信局(站)电源、空调及环境集中监控管理系统第3部分:前端智能设备协议.pd。
其实自己想用QT写一个电总协议测试程序(其实想写一个串口助手带协议插件,插件中包含发包的拼包和回包的分析,电总协议只是其中一个插件),虽然网上有同学已经写了类似的程序,不过自己还想写一个(可以将自己想用的功能加上,最能满足自己需求,维护也方便)。不过忙的跟狗一样,只能先在心里想一下:)
电总协议如果手工拼包基本不可能,如果没有顺手的工具,也要整一个简陋的测试工程给自己用。虽然不通用,不过遇到新协议,改起来也容易。
修正过的测试程序<<gen_YDN23_protocol_send_cmd>>如下:
编译环境 vs2017 vc++ console
// @file gen_YDN23_protocol_send_cmd.cpp
// @brief gen YDN23 protocol(电总协议) send cmd
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <tchar.h>
#include <math.h>
const unsigned char SOI = 0x7E; // 开始字符是固定的0x7E => ~
const unsigned char EOI = 0x0D; // 结束字符是固定的0x0D
void calc_and_print_YND23_cmd(const char* psz_tip, unsigned char VER, unsigned char ADR, unsigned char CID1, unsigned char CID2, unsigned char* INFO, unsigned short int LENGTH, unsigned char* YND23_cmd);
int gen_YND23_cmd(unsigned char VER, unsigned char ADR, unsigned char CID1, unsigned char CID2, unsigned short int LENGTH, unsigned char* INFO, unsigned char* YND23_cmd);
void uint8_to_2ascii_char(unsigned char uc_in, char& c1, char& c2);
void uint16_to_4ascii_char(unsigned int ui_in, char& c1, char& c2, char& c3, char& c4);
char fn_4bits_to_char(unsigned char uc);
unsigned short int LENGTH_add_LCHKSUM(unsigned short int LENGTH);
unsigned short int calc_YDN23_CHKSUM(unsigned char* YND23_cmd, int index_begin, int index_end);
void print_ary_as_hex(unsigned char* ary, int len);
int main(int argc, char** argv)
{
int i = 0;
unsigned char VER = 0;
unsigned char ADR = 0;
unsigned char CID1 = 0;
unsigned char CID2 = 0;
unsigned short int LENGTH = 0;
const char* psz_tip = NULL;
unsigned char VER_real = 0x20;
// LENGTH中的低12位 所能带的INFO数据个数为 2^12 = 4096;
// INFO中的数据为WORD, WORD的最大数量为 4096/2 = 2048;
unsigned char INFO[4096] = {'\0'}; // 如果LENGTH中的低12位是0, INFO域没内容, 不出现在产生的命令序列中
// unsigned short int CHKSUM = 0;
// 最终拼好的命令序列最大长度 = SOI(1bytes) + VER(2bytes) + ADR(2bytes) + CID1(2bytes) + CID2(2bytes) + LENGTH(4bytes) + INFO(4096 max bytes) + CHKSUM(4bytes) + EOI(1byte) = 4906 + 18
unsigned char YND23_cmd[4906 + 18] = {'\0'}; // 根据参数, 防止最终拼好的命令序列
do {
setlocale(LC_ALL, ".936"); ///< 设置中文代码页, 用来显示中文字符
// 不传参数进来了, 将参数写死,运行一次产生一个发送的命令序列
// 如果要产生不同的命令, 重新写参数, 然后编译运行一次后, 产生一个新命令
// 电总协议, 要给定以下6个参数(VER/ADR/CID1/CID2/LENGTH_for_INFO/INFO)
// -----------------------------------------------------------------------------
// 产生YDN23协议的发送命令
// -----------------------------------------------------------------------------
//psz_tip = "这条指令只是验证计算和拼包, 用已知的正确包参数构造一个新包, 能还原原始包,说明拼包算法正确";
//VER = 0x20; // 对于同一种设备, 通讯协议版本是固定的, 只要发一条命令取一下就行
//ADR = 0x01; // 设备地址在设备仪表上有显示
//CID1 = 0x42; // CID1/CID2的组合说明该命令具体任务
//CID2 = 0x44;
//LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
//memset(INFO, 0, sizeof(INFO));
//calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
printf("Exm电总后台通讯协议_V120.pdf\n");
//1 获取系统模拟量量化数据(浮点数) 2AH 41H
psz_tip = "1 获取系统模拟量量化数据(浮点数) 2AH 41H";
VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
ADR = 0x01; // 地址要正确
CID1 = 0x2A;
CID2 = 0x41;
LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
memset(INFO, 0, sizeof(INFO));
calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//2 获取开关输入状态 2AH 43H
psz_tip = "2 获取开关输入状态 2AH 43H";
VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
ADR = 0x01; // 地址要正确
CID1 = 0x2A;
CID2 = 0x43;
LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
memset(INFO, 0, sizeof(INFO));
calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//3 获取告警状态 2AH 44H
psz_tip = "3 获取告警状态 2AH 44H";
VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
ADR = 0x01; // 地址要正确
CID1 = 0x2A;
CID2 = 0x44;
LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
memset(INFO, 0, sizeof(INFO));
calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//4 获取协议版本号 2AH 4FH
psz_tip = "4 获取协议版本号 2AH 4FH";
VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
ADR = 0x01; // 地址要正确
CID1 = 0x2A;
CID2 = 0x4F;
LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
memset(INFO, 0, sizeof(INFO));
calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//5 获取设备地址 2AH 50H
psz_tip = "5 获取设备地址 2AH 50H";
VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
ADR = 0x01; // 地址要正确
CID1 = 0x2A;
CID2 = 0x50;
LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
memset(INFO, 0, sizeof(INFO));
calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//6 获取设备厂家信息 2AH 51H
psz_tip = "6 获取设备厂家信息 2AH 51H";
VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
ADR = 0x01; // 地址要正确
CID1 = 0x2A;
CID2 = 0x51;
LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
memset(INFO, 0, sizeof(INFO));
calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//7 获取自定义模拟量量化数据1(浮点数) 2AH E1H
psz_tip = "7 获取自定义模拟量量化数据1(浮点数) 2AH E1H";
VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
ADR = 0x01; // 地址要正确
CID1 = 0x2A;
CID2 = 0xE1;
LENGTH = 1; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
memset(INFO, 0, sizeof(INFO));
INFO[0] = 0x00;
calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//8 获取自定义模拟量量化数据2(浮点数) 2AH E2H
psz_tip = "8 获取自定义模拟量量化数据2(浮点数) 2AH E2H";
VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
ADR = 0x01; // 地址要正确
CID1 = 0x2A;
CID2 = 0xE2;
LENGTH = 1; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
memset(INFO, 0, sizeof(INFO));
INFO[0] = 0x00;
calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//9 获取自定义模拟量量化数据3(浮点数) 2AH E3H
psz_tip = "9 获取自定义模拟量量化数据3(浮点数) 2AH E3H";
VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
ADR = 0x01; // 地址要正确
CID1 = 0x2A;
CID2 = 0xE3;
LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
memset(INFO, 0, sizeof(INFO));
calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//10 获取自定义模拟量量化数据4(浮点数) 2AH E7H
psz_tip = "10 获取自定义模拟量量化数据4(浮点数) 2AH E7H 电池组1";
VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
ADR = 0x01; // 地址要正确
CID1 = 0x2A;
CID2 = 0xE7;
LENGTH = 2; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
memset(INFO, 0, sizeof(INFO));
INFO[0] = 1;
INFO[1] = 0;
calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//10 获取自定义模拟量量化数据4(浮点数) 2AH E7H
psz_tip = "10 获取自定义模拟量量化数据4(浮点数) 2AH E7H 电池组2";
VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
ADR = 0x01; // 地址要正确
CID1 = 0x2A;
CID2 = 0xE7;
LENGTH = 2; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
memset(INFO, 0, sizeof(INFO));
INFO[0] = 2;
INFO[1] = 0;
calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//// -----------------------------------------------------------------------------
//// 产生YDN23协议的发送命令
//// -----------------------------------------------------------------------------
//// 获取通信协议版本号 2AH 4FH
//psz_tip = "获取通信协议版本号";
//VER = 0x00; // 因为是取通讯协议版本, 所以这里的版本可以随便填
//ADR = 0x01; // 地址要正确
//CID1 = 0x2A; // CID1 = 0x2A, CID2 = 0x4F
//CID2 = 0x4F;
//LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
//memset(INFO, 0, sizeof(INFO));
//calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//// 回包
//// 7E 32 36 30 31 32 41 30 30 30 30 30 30 46 44 41 34 0D
//// 回包分析
//// 7E // SOI
//// 32 36 // VER = "26" = 2.6
//// printf("%c%c\n", 0x32, 0x36);
//// 30 31 // ADR
//// 32 41 // CID1
//// 30 30 // RTN = 0x00(正常)
//// 30 30 30 30 // LENGTH = 0(NO INFO)
//// 46 44 41 34 // CHKSUM
//// 0D // EOI
//VER_real = 0x26; // @todo 从回包中取到实际的VER
//// -----------------------------------------------------------------------------
//// 产生YDN23协议的发送命令
//// -----------------------------------------------------------------------------
//// 拿上面取到的协议版本号填入VER, 再执行其他命令, 因为其他命令都和实际的VER有关
//// 获取设备厂家信息 2AH 51H
//psz_tip = "获取设备厂家信息";
//VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
//ADR = 0x01; // 地址要正确
//CID1 = 0x2A;
//CID2 = 0x51;
//LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
//memset(INFO, 0, sizeof(INFO));
//calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//// 产生的发包 : 7E 32 36 30 31 32 41 35 31 30 30 30 30 46 44 39 45 0D
//// -----------------------------------------------------------------------------
//// 产生YDN23协议的发送命令
//// -----------------------------------------------------------------------------
//// 拿上面取到的协议版本号填入VER, 再执行其他命令, 因为其他命令都和实际的VER有关
//// 获取告警状态 2AH 44H
//psz_tip = "获取告警状态";
//VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
//ADR = 0x01; // 地址要正确
//CID1 = 0x2A;
//CID2 = 0x44;
//LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
//memset(INFO, 0, sizeof(INFO));
//calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//// -----------------------------------------------------------------------------
//// 产生YDN23协议的发送命令
//// -----------------------------------------------------------------------------
//// 拿上面取到的协议版本号填入VER, 再执行其他命令, 因为其他命令都和实际的VER有关
//// 获取开关输入状态 2AH 43H
//psz_tip = "获取开关输入状态";
//VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
//ADR = 0x01; // 地址要正确
//CID1 = 0x2A;
//CID2 = 0x43;
//LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
//memset(INFO, 0, sizeof(INFO));
//calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//// -----------------------------------------------------------------------------
//// 产生YDN23协议的发送命令
//// -----------------------------------------------------------------------------
//// 拿上面取到的协议版本号填入VER, 再执行其他命令, 因为其他命令都和实际的VER有关
//// 获取自定义模拟量量化数据3 2AH E3H
//psz_tip = "获取自定义模拟量量化数据3";
//VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
//ADR = 0x01; // 地址要正确
//CID1 = 0x2A;
//CID2 = 0xE3;
//LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
//memset(INFO, 0, sizeof(INFO));
//calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//// -----------------------------------------------------------------------------
//// 产生YDN23协议的发送命令
//// -----------------------------------------------------------------------------
//// 拿上面取到的协议版本号填入VER, 再执行其他命令, 因为其他命令都和实际的VER有关
//// 获取自定义模拟量量化数据2 2AH E2H
//psz_tip = "获取自定义模拟量量化数据2";
//VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
//ADR = 0x01; // 地址要正确
//CID1 = 0x2A;
//CID2 = 0xE2;
//LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
//memset(INFO, 0, sizeof(INFO));
//calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//// -----------------------------------------------------------------------------
//// 产生YDN23协议的发送命令
//// -----------------------------------------------------------------------------
//// 拿上面取到的协议版本号填入VER, 再执行其他命令, 因为其他命令都和实际的VER有关
//// 获取自定义模拟量量化数据1 2AH E1H
//psz_tip = "获取自定义模拟量量化数据1";
//VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
//ADR = 0x01; // 地址要正确
//CID1 = 0x2A;
//CID2 = 0xE1;
//LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
//memset(INFO, 0, sizeof(INFO));
//calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
//// -----------------------------------------------------------------------------
//// 产生YDN23协议的发送命令
//// -----------------------------------------------------------------------------
//// 拿上面取到的协议版本号填入VER, 再执行其他命令, 因为其他命令都和实际的VER有关
//// 获取系统模拟量量化数据 2AH 41H
//psz_tip = "获取系统模拟量量化数据";
//VER = VER_real; // 因为是取通讯协议版本, 所以这里的版本可以随便填
//ADR = 0x01; // 地址要正确
//CID1 = 0x2A;
//CID2 = 0x41;
//LENGTH = 0x0000; // 低12位标识后面的INFO域有多少个字节(最多4096个), 高4位是低12位的校验和
//memset(INFO, 0, sizeof(INFO));
//calc_and_print_YND23_cmd(psz_tip, VER, ADR, CID1, CID2, INFO, LENGTH, YND23_cmd);
} while (0);
return EXIT_SUCCESS;
}
void calc_and_print_YND23_cmd(const char* psz_tip, unsigned char VER, unsigned char ADR, unsigned char CID1, unsigned char CID2, unsigned char* INFO, unsigned short int LENGTH, unsigned char* YND23_cmd)
{
// 一个有效的电总协议发送命令
// 7E 32 30 30 31 34 32 34 34 30 30 30 30 46 44 41 46 0D // 命令序列最小为18个字节
// 分析
// 7E // SOI = 0x7E
// 32 30 // VER = 0x20
// 30 31 // ADR = 0x01
// 34 32 // CID1 = 0x42
// 34 34 // CID2 = 0x44
// 30 30 30 30 // LENGTH = 0
// INFO(no data)
// 46 44 41 46 // CHKSUM = "FDAF" = 0xFDAF
// 0D // EOI = 0x0D
// CHKSUM = 0x0000; // 除了SOI/CHKSUM/EOI之外字节的累加和(4个字节一组进行累加)
int len_YND23_cmd = 0; // 最终拼好的命令有多少个字节?
memset(YND23_cmd, 0, sizeof(YND23_cmd)); // 除了SOI/EOI是16进制字节,其他的位置都要将16进制字节表示成2个ASCII字符标识的16进制数(e.g. 0x01 => "01" => 0x30 0x31)
// 看看给定的参数,是否能还原上面的命令序列
// 产生出的命令为YND23_cmd,字节长度为len_YND23_cmd
len_YND23_cmd = gen_YND23_cmd(VER, ADR, CID1, CID2, LENGTH, INFO, YND23_cmd);
// 打印出YND23_cmd的内容供贴到串口助手做测试
printf("%s:\n", psz_tip);
print_ary_as_hex(YND23_cmd, len_YND23_cmd);
printf("请将回包贴在下面一行:\n");
printf("\n\n");
// 7E 32 30 30 31 34 32 34 34 30 30 30 30 46 44 41 46 0D // run result
// 7E 32 30 30 31 34 32 34 34 30 30 30 30 46 44 41 46 0D // original cmd, CHKSUM = "FDAF" = 0xFDAF
// ok :)
}
void print_ary_as_hex(unsigned char* ary, int len)
{
int i = 0;
for (i = 0; i < len; i++) {
printf("%2.2X", ary[i]); // 为了贴到串口助手中直接用,不要换行
if ((i + 1) != len) {
printf(" ");
}
else {
printf("\n");
}
}
}
int gen_YND23_cmd(unsigned char VER, unsigned char ADR, unsigned char CID1, unsigned char CID2, unsigned short int LENGTH, unsigned char* INFO, unsigned char* YND23_cmd)
{
int len = 0;
int ipos = 0;
char c1 = '\0';
char c2 = '\0';
char c3 = '\0';
char c4 = '\0';
unsigned short int LENGTH_have_ehck_sum = 0;
unsigned short int YDN23_CHKSUM = 0;
int i = 0;
do {
// @todo 不检查入参了
// 7E // SOI = 0x7E
// 32 30 // VER = 0x20
// 30 31 // ADR = 0x01
// 34 32 // CID1 = 0x42
// 34 34 // CID2 = 0x44
// 30 30 30 30 // LENGTH = 0
// INFO(no data)
// 46 44 41 46 // CHKSUM = "FDAF" = 0xFDAF
// 0D // EOI = 0x0D
// SOI
YND23_cmd[ipos++] = SOI;
// VER
uint8_to_2ascii_char(VER, c1, c2);
YND23_cmd[ipos++] = c1;
YND23_cmd[ipos++] = c2;
// ADR
uint8_to_2ascii_char(ADR, c1, c2);
YND23_cmd[ipos++] = c1;
YND23_cmd[ipos++] = c2;
// CID1
uint8_to_2ascii_char(CID1, c1, c2);
YND23_cmd[ipos++] = c1;
YND23_cmd[ipos++] = c2;
// CID2
uint8_to_2ascii_char(CID2, c1, c2);
YND23_cmd[ipos++] = c1;
YND23_cmd[ipos++] = c2;
// LENGTH
LENGTH = LENGTH & (~(1 >> 12)); // 只取低12位, 最多4096(2^12)个数据
LENGTH_have_ehck_sum = LENGTH_add_LCHKSUM(LENGTH);
uint16_to_4ascii_char(LENGTH_have_ehck_sum, c1, c2, c3, c4);
YND23_cmd[ipos++] = c1;
YND23_cmd[ipos++] = c2;
YND23_cmd[ipos++] = c3;
YND23_cmd[ipos++] = c4;
// INFO
for (i = 0; i < LENGTH; i++) {
uint8_to_2ascii_char(INFO[i], c1, c2);
YND23_cmd[ipos++] = c1;
YND23_cmd[ipos++] = c2;
}
// CHKSUM
// test calc_YDN23_CHKSUM
//ipos = 0;
//YND23_cmd[ipos++] = SOI;
//YND23_cmd[ipos++] = '1';
//YND23_cmd[ipos++] = '2';
//YND23_cmd[ipos++] = '0';
//YND23_cmd[ipos++] = '3';
//YND23_cmd[ipos++] = '4';
//YND23_cmd[ipos++] = '0';
//YND23_cmd[ipos++] = '0';
//YND23_cmd[ipos++] = '4';
//YND23_cmd[ipos++] = '5';
//YND23_cmd[ipos++] = '6';
//YND23_cmd[ipos++] = 'A';
//YND23_cmd[ipos++] = 'B';
//YND23_cmd[ipos++] = 'C';
//YND23_cmd[ipos++] = 'D';
//YND23_cmd[ipos++] = 'F';
//YND23_cmd[ipos++] = 'E';
//// 1203400456ABCDFE
//ipos = 16 + 1;
//YDN23_CHKSUM = calc_YDN23_CHKSUM(YND23_cmd, 1 /*不要算SOI*/, ipos - 1 /*不算累加和本身和EOI*/);
YDN23_CHKSUM = calc_YDN23_CHKSUM(YND23_cmd, 1 /*不要算SOI*/, ipos - 1 /*不算累加和本身和EOI*/);
uint16_to_4ascii_char(YDN23_CHKSUM, c1, c2, c3, c4);
YND23_cmd[ipos++] = c1;
YND23_cmd[ipos++] = c2;
YND23_cmd[ipos++] = c3;
YND23_cmd[ipos++] = c4;
// EOI
YND23_cmd[ipos++] = EOI;
len = ipos;
} while (0);
return len;
}
char fn_4bits_to_char(unsigned char uc)
{
char c_out = '0';
// 0 => '0'
// 1 => '1'
// 10 => 'A'
// 11 => 'B'
// 12 => 'C'
// 13 => 'D'
// 14 => 'E'
// 15 => 'F'
if ((uc >= 0x00) && (uc < 0x0A)) {
c_out = uc - 0 + '0';
} else if ((uc >= 0x0A) && (uc <= 0x0F)) {
c_out = uc - 0x0A + 'A';
}
return c_out;
}
void uint8_to_2ascii_char(unsigned char uc_in, char& c1, char& c2)
{
// 0x12 => '1' '2'
unsigned char uc1 = (uc_in >> 4) & 0x0f;
unsigned char uc2 = (uc_in >> 0) & 0x0f;
c1 = fn_4bits_to_char(uc1);
c2 = fn_4bits_to_char(uc2);
}
void uint16_to_4ascii_char(unsigned int ui_in, char& c1, char& c2, char& c3, char& c4)
{
// 0x1234 => '1' '2' '3' '4'
unsigned char uc1 = (unsigned char)((ui_in >> 12) & 0x0f);
unsigned char uc2 = (unsigned char)((ui_in >> 8) & 0x0f);
unsigned char uc3 = (unsigned char)((ui_in >> 4) & 0x0f);
unsigned char uc4 = (unsigned char)((ui_in >> 0) & 0x0f);
c1 = fn_4bits_to_char(uc1);
c2 = fn_4bits_to_char(uc2);
c3 = fn_4bits_to_char(uc3);
c4 = fn_4bits_to_char(uc4);
}
unsigned short int LENGTH_add_LCHKSUM(unsigned short int LENGTH)
{
if (LENGTH > 0) {
LENGTH = LENGTH;
}
LENGTH *= 2; // 给定的长度是指的字节长度,在电总协议里面表示的是拆分后的字节长度,1个字变成了2个字节。
unsigned short int ui_out = 0;
unsigned short int ui_shift = 0;
unsigned char uc1 = (LENGTH >> 8) & 0x0f;
unsigned char uc2 = (LENGTH >> 4) & 0x0f;
unsigned char uc3 = (LENGTH >> 0) & 0x0f;
unsigned short int uc_LCHKSUM = '\0'; // 高4位的电总校验和
uc_LCHKSUM = uc1 + uc2 + uc3; // 低12位分为3个4位,进行累加
uc_LCHKSUM %= 0x10; // 模16取余数
uc_LCHKSUM = ~uc_LCHKSUM; // 取反
uc_LCHKSUM += 1; // 加1
ui_out = (uc_LCHKSUM << 12);
ui_shift = (0x0F << 12);
ui_out = ui_out & ui_shift; // 将算出的累加和放到高4位
ui_out |= (LENGTH & 0xFFF); // 将LENGTH的低12位放到返回值的低12位
return ui_out;
}
unsigned short int calc_YDN23_CHKSUM(unsigned char* YND23_cmd, int index_begin, int index_end)
{
// CHKSUM的计算是除SOI、 EOI和CHKSUM外,其他字符ASCII码值累加求和
// 结果模65535取余数
// 取反加1
// YND23_cmd送进来时, 已经刨掉了SOI, CHKSUM, EOI
int i = 0;
unsigned int ui_chksum = 0;
unsigned short int ui_chksum_rc = 0;
for (i = index_begin; i <= index_end; i++) {
ui_chksum += YND23_cmd[i];
}
ui_chksum %= 0xFFFF;
ui_chksum = ~ui_chksum;
ui_chksum += 1;
ui_chksum_rc = ui_chksum & 0xffff;
return ui_chksum_rc;
}

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)