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 ->该字节的最高位为0printf("1");elseprintf("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; // 控制字节,固定32bam[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; // 保留,固定ffbam[5] = pgn & 0xff;bam[6] = (pgn >> 8) & 0xff;bam[7] = 00; // 三个字节PGNprintf("\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 1INT8U 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));// DTC2INT8U 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)+DTCnINT8U 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;
}