1、实验目的:
使用CAN卡采集CAN报文,通过mdfSDK记录CAN报文,将记录数据通过CANoe工具导入,在CAoe中对CAN数据进行分析,或导入DBC文件,对CAN数据进行信号量解析。
2、实验方法
模拟CAN报文记录MDF数据文件。
3、mdfSDK的使用
3.1 测试主函数
源码见canlog.c
(1) mdf_open为mdfSDK的API函数,创建一个mdf文件,获取mdfFile的文件
(2) mdf_create_canlog_CG()创建CAN记录文件的MDF文件格式。
(3) write_canData 模拟CAN数据,写到MDF文件中。
(4) mdf_close 为mdfSDK的API函数,关闭mdf文件 。
3.2 创建MDF文件结构
(1) mdf_new_CG(mdfHandle)为SDK API接口,初始化一个CG数据块。
(2) mdf_create_CN为SDK API接口,在上面的CG数据块下依次创建15个CN数据通道,其中msgTime为时间戳通道。
(3) mdf_create_CG为SDK API接口,创建上面的CG数据块。
3.3 写MDF文件
模拟10条CAN报文,CANID依次为1到10,时间间隔为100us 。依次将数据写入到MDF文件中。
4 CANoe加载
使用测试代码 mdf_canlog 生成测试数据 can10.log 。
打开CANoe软件 , 在Trace界面中导入can10.log文件。
#include
#include
#include
#include
#include
#include "mdf.h"
static mdf_handle mdfFile ;
static unsigned long long timebase = 0;
unsigned long long tm_get_systick(void)
{
int ret = -1;
unsigned long long time;
int cnt = 0;
static struct timespec now = {0, 0};
while (ret < 0 && cnt < 3)
{
ret = clock_gettime(CLOCK_MONOTONIC, &now);
cnt++;
}
time = now.tv_sec * 1000 + now.tv_nsec / (1000 * 1000);
return time;
}
unsigned long long tm_get_time(void)
{
return tm_get_systick() - timebase;
}
/****************************************************************************************************************/
static uint8_t u8_canlog = 0;
static pthread_t canlog_tid;
#define CAN_ERROR_FLAG 0x9
#define CAN_GOOD_FLAG 0x0
static mdf_cc_liner can_ts_liner = {
.factor = 0.000001,
.offset = 0
};
#define CANLOG_CN_MAX 15
static mdf_CN_options canlog_info[CANLOG_CN_MAX]=
{
{ "type", 0 , 8, 0 , 0 , CN_TYPE_DATA , MDF_SIGNAL_UNSIGNED ,MDF_CC_NONE , NULL , NULL , NULL},
{ "can" , 8 , 16, 0 , 0 , CN_TYPE_DATA , MDF_SIGNAL_UNSIGNED ,MDF_CC_NONE , NULL , NULL , NULL},
{ "id" , 24 , 32, 0 , 0 , CN_TYPE_DATA , MDF_SIGNAL_UNSIGNED ,MDF_CC_NONE , NULL , NULL , NULL},
{ "dir" , 56 , 8, 0 , 0 , CN_TYPE_DATA , MDF_SIGNAL_UNSIGNED ,MDF_CC_NONE , NULL , NULL , NULL},
{ "rtr" , 64 , 8, 0 , 0 , CN_TYPE_DATA , MDF_SIGNAL_UNSIGNED ,MDF_CC_NONE , NULL , NULL , NULL},
{ "dlc" , 72 , 8, 0 , 0 , CN_TYPE_DATA , MDF_SIGNAL_UNSIGNED ,MDF_CC_NONE , NULL , NULL , NULL},
{ "msg[0]" , 80 , 8, 0 , 0 , CN_TYPE_DATA , MDF_SIGNAL_UNSIGNED ,MDF_CC_NONE , NULL , NULL , NULL},
{ "msg[1]" , 88 , 8, 0 , 0 , CN_TYPE_DATA , MDF_SIGNAL_UNSIGNED ,MDF_CC_NONE , NULL , NULL , NULL},
{ "msg[2]" , 96 , 8, 0 , 0 , CN_TYPE_DATA , MDF_SIGNAL_UNSIGNED ,MDF_CC_NONE , NULL , NULL , NULL},
{ "msg[3]" , 104 , 8, 0 , 0 , CN_TYPE_DATA , MDF_SIGNAL_UNSIGNED ,MDF_CC_NONE , NULL , NULL , NULL},
{ "msg[4]" , 112 , 8, 0 , 0 , CN_TYPE_DATA , MDF_SIGNAL_UNSIGNED ,MDF_CC_NONE , NULL , NULL , NULL},
{ "msg[5]" , 120 , 8, 0 , 0 , CN_TYPE_DATA , MDF_SIGNAL_UNSIGNED ,MDF_CC_NONE , NULL , NULL , NULL},
{ "msg[6]" , 128 , 8, 0 , 0 , CN_TYPE_DATA , MDF_SIGNAL_UNSIGNED ,MDF_CC_NONE , NULL , NULL , NULL},
{ "msg[7]" , 136 , 8, 0 , 0 , CN_TYPE_DATA , MDF_SIGNAL_UNSIGNED ,MDF_CC_NONE , NULL , NULL , NULL},
{ "msgTime", 144 , 32, 0 , 0 , CN_TYPE_TIME , MDF_SIGNAL_UNSIGNED ,MDF_CC_LINEAR , &can_ts_liner , NULL , NULL},
};
int mdf_create_canlog_CG( mdf_handle mdfHandle )
{
int i , ret ;
mdf_CG_handle* canCG = mdf_new_CG(mdfHandle);
if (canCG == NULL )
{
printf("mdf new CG fail!\n");
return MDF_ERR_CG ;
}
for ( i = 0 ; i < CANLOG_CN_MAX ; i++ )
{
if ( (ret = mdf_create_CN( mdfHandle , canCG , &canlog_info[i] ))!= 0 )
{
printf("mdf_add_CN fail , errcode = %d!\n" , ret );
return ret;
}
}
ret = mdf_create_CG(mdfHandle , canCG , "this CG is canlog , it is can import into canoe");
if ( ret < 0 )
{
printf("mdf_add_CG fail , errcode = %d!\n" , ret );
return ret;
}
u8_canlog = (uint8_t) ret;
return 0;
}
typedef struct
{
uint64_t ts;
union
{
uint8_t dlc;
struct
{
uint8_t len : 4;
uint8_t port : 4;
};
};
union
{
uint32_t MsgID; /* CAN Message ID (11-bit or 29-bit) */
struct
{
uint32_t msgid : 31;
uint32_t exten : 1;
};
};
uint8_t Data[8];
} __attribute__ ((packed)) CAN_MSG;
#define CAN_ONEINPUT_MAX 10
#define CAN_TOTAL_MAX 10000
static void *canlog_record(void)
{
int ret ;
uint32_t u32Temp = 0 ;
uint32_t offset ;
uint8_t fileBuf[23*CAN_ONEINPUT_MAX] ;
CAN_MSG canMsg[CAN_ONEINPUT_MAX];
CAN_MSG *pt_can;
int i , cnt = 0;
while(cnt < CAN_TOTAL_MAX)
{
// generate can data
for ( i = 0 ;i < CAN_ONEINPUT_MAX ; i++ )
{
u32Temp++;
canMsg[i].MsgID = 0x100 + i ;
canMsg[i].dlc = 8;
memcpy(canMsg[i].Data , &u32Temp , 4 );
canMsg[i].ts = tm_get_time();
usleep(100);
}
offset = 0;
for ( i = 0 ;i < CAN_ONEINPUT_MAX ; i++ )
{
pt_can = &canMsg[i];
fileBuf[offset++] = u8_canlog ;
fileBuf[offset++] = CAN_GOOD_FLAG ; //type
fileBuf[offset++] = i + 1 ; //can
fileBuf[offset++] = 0; //can
memcpy( &fileBuf[offset] , &pt_can->MsgID , 4 ); //id
offset += 4;
fileBuf[offset++] = 0 ; //dir
fileBuf[offset++] = 0 ; //rtr
fileBuf[offset++] = pt_can->len ; //dlc
memcpy( &fileBuf[offset] , &pt_can->Data , 8);//data
offset += 8;
memcpy( &fileBuf[offset] , &pt_can->ts , 4 );//timestamp
offset += 4;
}
ret = mdf_append_data( mdfFile , u8_canlog , fileBuf , offset , CAN_ONEINPUT_MAX );
if (ret != 0 )
{
printf(" write can log into mdf err %d\n", ret );
break;
}
cnt += CAN_ONEINPUT_MAX ;
usleep(1000);
}
}
static void write_canData()
{
int i ;
uint32_t u32Temp = 0 , offset ;
CAN_MSG canMsg[CAN_ONEINPUT_MAX];
CAN_MSG *pt_can;
uint8_t fileBuf[230] ;
for ( i = 0 ;i < CAN_ONEINPUT_MAX ; i++ )
{
u32Temp++;
canMsg[i].MsgID = i+1 ;
canMsg[i].dlc = 8;
canMsg[i].Data[0] = i + 1;
canMsg[i].Data[1] = 2;
canMsg[i].Data[2] = 3;
canMsg[i].Data[3] = 4;
canMsg[i].Data[4] = 5;
canMsg[i].Data[5] = 6;
canMsg[i].Data[6] = 7;
canMsg[i].Data[7] = 8;
canMsg[i].ts = tm_get_time();
usleep(100);
}
offset = 0;
for ( i = 0 ;i < CAN_ONEINPUT_MAX ; i++ )
{
pt_can = &canMsg[i];
fileBuf[offset++] = u8_canlog ;
fileBuf[offset++] = CAN_GOOD_FLAG ; //type
fileBuf[offset++] = pt_can->port ; //can
fileBuf[offset++] = 0; //can
memcpy( &fileBuf[offset] , &pt_can->MsgID , 4 ); //id
offset += 4;
fileBuf[offset++] = 0 ; //dir
fileBuf[offset++] = 0 ; //rtr
fileBuf[offset++] = pt_can->len ; //dlc
memcpy( &fileBuf[offset] , &pt_can->Data , 8);//data
offset += 8;
memcpy( &fileBuf[offset] , &pt_can->ts , 4 );//timestamp
offset += 4;
}
mdf_append_data( mdfFile , u8_canlog , fileBuf , offset , CAN_ONEINPUT_MAX );
}
int main(int argc, char *argv[])
{
int i ;
int ret ;
mdf_file_options fileOpt;
if ( argc < 2 )
{
printf("Usage: %s file_name", argv[0]);
}
char* fileName = argv[1];
timebase = tm_get_systick();
memset( &fileOpt , 0 ,sizeof(mdf_file_options));
fileOpt.opt_company = "TIZA-Info";
fileOpt.opt_division = "roadtest";
fileOpt.opt_operator = "tboxSN=12345678";
fileOpt.opt_project = "your_project";
fileOpt.opt_subject = "your_subject";
fileOpt.opt_description = "EMS-4G93-CCP-V400";
mdfFile = mdf_open(fileName , &fileOpt );
if (mdfFile == NULL )
{
printf("mdf open fail!\n");
return 0;
}
if ( mdf_create_canlog_CG(mdfFile) != 0 )
{
printf("mdf create canlog CG fail!\n");
goto EXIT;
}
write_canData();
/* ret = pthread_create(&canlog_tid, NULL, (void *)canlog_record , NULL);
if ( ret != 0 )
{
printf(" create pthread for record canlog into mdf fail\n");
}
pthread_join(canlog_tid, NULL) ;
*/
EXIT:
mdf_close(mdfFile);
return 0;
}