C语言实现J1939长帧组包接口以及模拟DM1数据并生成CANalyst数据文件
利用Dev-Cpp v5.11,通过C语言实现,经过Code::Blocks编译后,会生成exe文件,可以直接用exe文件执行,完成后会在程序目录生成CANalyst工具适用的文件,具体代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/****************************************************************
DEFINE THE DATATYPE
****************************************************************/
typedef unsigned char BOOLEAN;
typedef unsigned char INT8U; /* Unsigned 8 bit quantity */
typedef signed char INT8S; /* Signed 8 bit quantity */
typedef unsigned short INT16U; /* Signed 16 bit quantity */
typedef signed short INT16S; /* Unsigned 32 bit quantity */
typedef unsigned int INT32U; /* Unsigned 32 bit quantity */
typedef unsigned long long INT64U; /* Unsigned 64 bit quantity */
typedef signed int INT32S; /* Signed 32 bit quantity */
typedef float FP32; /* Single precision floating point */
typedef double FP64; /* Double precision floating point */
typedef unsigned long ip_addr;
#ifndef false
#define false 0
#endif
#ifndef true
#define true 1
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define MEMCPY_EX(DET_PTR, DET_LEN, SRC_PTR, SRC_LEN) \
do { \
assert((DET_LEN) >= (SRC_LEN)); \
memcpy(DET_PTR, SRC_PTR, SRC_LEN); \
} while(0)
INT8U HexToChar(INT8U sbyte)
{
sbyte &= 0x0F;
if (sbyte < 0x0A) return (sbyte + '0');
else return (sbyte - 0x0A + 'A');
}
BOOLEAN printf_hex(INT8U *ptr, INT16U len)
{
INT16U i = 0;
INT8U ch;
INT8U s_debugmem[4096] = {0};
if (ptr == 0 || len == 0) {
return false;
}
memset(s_debugmem, 0, sizeof(s_debugmem));
for (i = 0; len > 0; len--) {
ch = *ptr++;
if ((i + 3) > sizeof(s_debugmem)) {
break;
}
s_debugmem[i++] = HexToChar((INT8U)(ch >> 4));
s_debugmem[i++] = HexToChar(ch);
s_debugmem[i++] = ' ';
}
printf("%s\n", s_debugmem);
return true;
}
void printf_bin(int num)
{
int i, j, k;
unsigned char *p = (unsigned char*)&num + 3; //p先指向num后面第3个字节的地址,即num的最高位字节地址
for (i = 0; i < 4; i++) { //依次处理4个字节(32位)
j = *(p - i); //取每个字节的首地址,从高位字节到低位字节,即p p-1 p-2 p-3地址处
for (int k = 7; k >= 0; k--) { //处理每个字节的8个位,注意字节内部的二进制数是按照人的习惯存储!
if (j & (1 << k)) //1左移k位,与单前的字节内容j进行或运算,如k=7时,00000000&10000000=0 ->该字节的最高位为0
printf("1");
else
printf("0");
}
printf(" "); //每8位加个空格,方便查看
}
printf("(%d)", num);
printf("\r\n");
}
#define CANalystXMLFile "./dm1_data.xml"
static FILE *s_xml_fd;
static void save_to_CANalyst_xml_file(INT32U can_id, INT8U *can_data, INT32U len)
{
if (can_data == NULL) {
printf("can data is null\n");
return;
}
if (s_xml_fd) {
char xml_buf[2048] = {0}, temp[128] = {0};
strcat(xml_buf," ");
strcat(xml_buf,"<TaskObj Frames=\"1\" Interval=\"20\" Times=\"1\" IdIncrease=\"0\" DataIncrease=\"0\" ");
sprintf(temp, "ID=\"%d\" ", can_id);
strcat(xml_buf,temp);
strcat(xml_buf,"SendType=\"0\" RemoteFlag=\"0\" ExternFlag=\"1\" DataLen=\"8\" ");
sprintf(temp, "Data=\"%02x %02x %02x %02x %02x %02x %02x %02x\"/>\n",
can_data[0], can_data[1], can_data[2], can_data[3], can_data[4], can_data[5], can_data[6], can_data[7]);
strcat(xml_buf,temp);
strcat(xml_buf,"\0");
fwrite(xml_buf, strlen(xml_buf), 1, s_xml_fd);
}
}
void gen_dm1_can_data(INT16U pgn, INT8U *data, INT16U len)
{
// 广播帧
INT32U bam_id = 0x18ECFF00;
INT8U bam[8] = {0};
bam[0] = 0x20; // 控制字节,固定32
bam[1] = len & 0xff; // 消息字节数,低位在前
bam[2] = (len >> 8) & 0xff; // 消息字节数,高位在后
if ((len % 7) == 0) {
bam[3] = len / 7;
} else {
bam[3] = (len / 7) + 1; // 数据包数
}
bam[4] = 0xff; // 保留,固定ff
bam[5] = pgn & 0xff;
bam[6] = (pgn >> 8) & 0xff;
bam[7] = 00; // 三个字节PGN
printf("\n");
printf("packet num:%d, len:%d, pgn:%d(%04x)\n\n", bam[3], len, pgn, pgn);
printf("TP.CM_BAM can id:%08x(%u), data:", bam_id, bam_id);
printf_hex(bam, sizeof(bam));
printf("\n");
save_to_CANalyst_xml_file(bam_id, bam, sizeof(bam));
// 数据发送帧
INT32U dt_id = 0x18EBFF00;
INT16U i = 0, packet_num = bam[3];
INT8U dt_ptr[packet_num * 8] = {0};
for (i = 0; i < packet_num; i++) {
dt_ptr[i*8] = i + 1;
if (i == packet_num - 1) {
INT8U left_len = len-(7*i);
memset(&dt_ptr[(i*8)+1], 0xff, 7);
memcpy(&dt_ptr[(i*8)+1], &data[i * 7], left_len);
} else {
memcpy(&dt_ptr[(i*8)+1], &data[i * 7], 7);
}
}
for (i = 0; i < packet_num; i++) {
printf("TP.DT_DATA can id:%08x(%d), data:", dt_id, dt_id);
printf_hex(&dt_ptr[8*i], 8);
save_to_CANalyst_xml_file(dt_id, &dt_ptr[8*i], sizeof(dt_ptr));
}
printf("\n");
// printf_hex(dt_ptr, packet_num * 8);
}
void gen_dm1_data(INT8U lamp, INT8U flash, INT32U spn, INT8U fmi, INT8U count, INT8U *des_ptr, INT8U des_len)
{
INT8U dtc[4] = {0};
if ((des_ptr == NULL) || (des_len < 6)) {
printf("des ptr error, len:%d\n", des_len);
return;
}
printf("lamp:%02x, flash:%02x, spn:%d, fmi:%d, count:%d\n", lamp, flash, spn, fmi, count);
dtc[0] = spn;
dtc[1] = spn >> 8;
dtc[2] = fmi & 0x1F;
dtc[2] |= ((spn >> 16) & 0x07) << 5;
dtc[3] = count;
des_ptr[0] = lamp;
des_ptr[1] = flash;
memcpy(&des_ptr[2], dtc, sizeof(dtc));
}
int main(int argc, char const *argv[])
{
// INT8U buf[6] = {0};
// gen_dm1_data(0x11, 0x22, 983, 1, 2, buf, sizeof(buf));
// printf_hex(buf, 6);
// return 0;
remove(CANalystXMLFile);
s_xml_fd = fopen(CANalystXMLFile, "a+");
if (s_xml_fd == NULL) printf("file open error\n");
char xml_buf[1024] = {0};
// 写xml头
sprintf(xml_buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE xml>\n<xml version=\"1.0\">\n");
fwrite(xml_buf, strlen(xml_buf), 1, s_xml_fd);
// DM1长帧数据
INT32U pgn, lamp, flash, spn, fmi, count;
pgn = 0xfeca;
// printf("input pgn(十进制):");
// scanf("%d", &pgn);
printf("input lamp(一个字节十六进制):");
scanf("%x", &lamp);
printf("input flash(一个字节十六进制):");
scanf("%x", &flash);
// DTC 1
INT8U data1[6] = {0};
printf("\n\ninput first DTC data\n");
printf("input spn(十进制):");
scanf("%d", &spn);
printf("input fmi(十进制):");
scanf("%d", &fmi);
printf("input count(十进制):");
scanf("%d", &count);
gen_dm1_data(lamp, flash, spn, fmi, count, data1, sizeof(data1));
// DTC2
INT8U data2[6] = {0};
printf("\n\ninput second DTC data\n");
printf("input spn(十进制):");
scanf("%d", &spn);
printf("input fmi(十进制):");
scanf("%d", &fmi);
printf("input count(十进制):");
scanf("%d", &count);
gen_dm1_data(lamp, flash, spn, fmi, count, data2, sizeof(data2));
// 组成长帧数据体,lamp(1)+flash(1)+DTC1(4)+DTC2(4)+DTCn
INT8U data[10] = {0};
memcpy(data, data1, sizeof(data1));
memcpy(&data[6], &data2[2], sizeof(data2)-2);
gen_dm1_can_data((INT16U)pgn, data, sizeof(data));
// 写xml尾
memset(xml_buf, 0, sizeof(xml_buf));
sprintf(xml_buf, "</xml>\n");
fwrite(xml_buf, strlen(xml_buf), 1, s_xml_fd);
if (s_xml_fd) fclose(s_xml_fd);
printf("save CANalyst XML File to %s\n\n", CANalystXMLFile);
// system("pause>nul"); // 避免可执行程序双击执行后窗口关闭,不提示按任意键继续
system("pause"); // 避免可执行程序双击执行后窗口关闭
return 0;
}