0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

CAPL腳本使用介紹

汽車ECU開發(fā) ? 來源:汽車ECU開發(fā) ? 2024-04-01 11:23 ? 次閱讀

之前斷斷續(xù)續(xù)分享過一些Vector工具的使用總結(jié),如下所示,包括CANape、CANoe、CANalyzer。

然而里面還有一項(xiàng)最重要的,也是平時(shí)使用過程中,提效很明顯的CAPL腳本的使用,覆蓋整車各節(jié)點(diǎn)的模擬、軟件刷寫、診斷測試等等,今天就來理一理CAPL腳本。 首先理一理基本語法和常用語句。在打開CAPl編輯界面時(shí),下默認(rèn)組成部分有:Include、Variable、System、Value Objects,其中Include為需要包含的已存在的頭文件,一般不配置;Variable為申明與定義全局變量,需要定義的變量包括需要發(fā)送的信號以及其數(shù)據(jù)類型。CAPL中的數(shù)據(jù)類型有: 無符號整型:byte(1字節(jié)),word(2字節(jié)),dword(4字節(jié))

有符號整型:int(2字節(jié)),long(4字節(jié))

浮點(diǎn)數(shù):float(8字節(jié)),double(16字節(jié))

CAN消息類型:Message;定時(shí)器類型:timer(單位為s),msTimer(單位為ms);

單個(gè)字符:char(1字節(jié))。

除了界面基礎(chǔ)的信息外,在CAPL腳本中,我們大量使用官方定的的一些接口,這些接口通常需要查看help文檔或者是CAPL的手冊,下面是梳理的一些常用接口。

1、定時(shí)器

CAPL中的定時(shí)器的使用相當(dāng)頻繁,比如測試時(shí)需要向定時(shí)發(fā)送某條CAN報(bào)文時(shí)就需要用定時(shí)器;定時(shí)器的聲明:

msTimer myTimer1;//聲明了一個(gè)ms定時(shí)器,定時(shí)單位是毫秒
timermyTimer2;//聲明了一個(gè)以秒為單位的定時(shí)器;

設(shè)置定時(shí)器:

setTimer(myTimer1,400);//設(shè)置定時(shí)器myTimer1為一個(gè)400ms定時(shí)器;
setTimerCyclic(myTimer2,2);//設(shè)置定時(shí)器myTimer2為一個(gè)2s為周期的循環(huán)定時(shí)器;

設(shè)置定時(shí)器定時(shí)事件,即當(dāng)定時(shí)器計(jì)時(shí)時(shí)間到時(shí)將要執(zhí)行的操作:

on timer myTimer1
{
.......
}

2、信息的操作和發(fā)送

//CAN消息發(fā)送:
message0x7ffMsg;//聲明一個(gè)message,ID=0x7ff
Msg.dlc=8;//設(shè)置其DLC=8;
Msg.id=0x100;//更改其ID=0x100;
Msg.byte(0)=55;//設(shè)置數(shù)據(jù)場的第一個(gè)字節(jié)為55
output(Msg);//發(fā)送Msg


//CANFD消息發(fā)送:
  msg1.FDF=1;
  msg1.BRS=1;
  msg1.dlc=8;
Msg.id=0x100;//更改其ID=0x100;
  msg1.byte(0)=0x44;
  msg1.byte(10)=0x10;
  msg1.byte(11)=0x11;
  output(Msg);//發(fā)送Msg

3、節(jié)點(diǎn)上下線操作

節(jié)點(diǎn)是在dbc中定義的,如VCU,BMS,MCU等,有時(shí)需要將它們離線,離線后不再向總線上發(fā)送報(bào)文,在線時(shí)可以向總線上發(fā)送報(bào)文。

節(jié)點(diǎn)上線:

voidtestSetEcuOnline(dbNodeaNode);
void testSetEcuOnline(char aNodeName[]);

節(jié)點(diǎn)下線:

voidtestSetEcuOffline(dbNodeaNode);
void testSetEcuOffline(char aNodeName[]);

4、檢查錯(cuò)誤幀

進(jìn)行CAN通訊的測試時(shí),檢查錯(cuò)誤幀是很常見的,要用CAPL腳本實(shí)現(xiàn)自動(dòng)檢測錯(cuò)誤幀也不困難,它的核心就是調(diào)用錯(cuò)誤檢查函數(shù)ChkStart_ErrorFrameOccured(),該函數(shù)一旦被調(diào)用,CANoe就會(huì)從此函數(shù)被調(diào)用時(shí)開始持續(xù)檢測總線上有沒有出現(xiàn)錯(cuò)誤幀。

下面是一個(gè)小的例子

dword chechId;
dword numCheckEvents;
checkId=ChkStart_ErrorFrameOccured();//開始檢測錯(cuò)誤幀
TestAddCondition(checkId);//添加檢測條件,如果出現(xiàn)了錯(cuò)誤幀,則輸出報(bào)告中會(huì)記錄下來
TestWaitForTimeout(5000);//持續(xù)檢測5s
checkControl_Stop(checkId);//停止檢測錯(cuò)誤幀
numCheckEvents=ChkQuery_NumEvents(checkId);//對5s內(nèi)的檢測情況進(jìn)行獲取,若函數(shù)返回0則沒有出現(xiàn)錯(cuò)誤幀
if(numCheckEvents>0)
     TestStepFail("Error Frames Occured");

5、添加事件信號

這種事件信號相當(dāng)于信號量機(jī)制,一般使用在需要等待某個(gè)或者是多個(gè)條件滿足時(shí)進(jìn)行下一步操作。

具體做法是:在一個(gè)位置添加需要等待的事件,程序中的其他地方,如果某個(gè)事件發(fā)生了(如周期超界等),提供該事件的供應(yīng),則等待的程序段獲得了該事件,繼續(xù)執(zhí)行下面的操作。主要使用的函數(shù)有以下幾個(gè):

//供應(yīng)text事件
long TestSupplyTextEvent( char aText[] );
//添加text事件
long TestJoinTextEvent(char[]aText);
//等待text事件,有一個(gè)出現(xiàn)則程序執(zhí)行下一步
long TestWaitForAnyJoinedEvent(dword aTimeout);
//等待text事件,所有等待事件都出現(xiàn)則程序執(zhí)行下一步
long TestWaitForAllJoinedEvents(dword aTimeout);

以下是一個(gè)例子:

TestJoinTextEvent("Test finished");
TestJoinTextEvent("Error Frame Occured");
TestWaitForAnyJoinedEvents(20000);
或者:
TestWaitForAllJoinedEvents(20000);
在系統(tǒng)事件on errorFrame中:
on errorFrame
{
   TestSupplyTextEvent("Error Frame occured");
}
在系統(tǒng)的on message 中:
on message 0x400
{
   TestSupplyTextEvent("Test Finished")
}

6、回調(diào)函數(shù)

CAPL中也有類似于C語言中的回調(diào)函數(shù)的機(jī)制,如檢測報(bào)文周期和錯(cuò)誤幀的函數(shù)中就可以使用,當(dāng)周期超界或者總線出現(xiàn)錯(cuò)誤幀就會(huì)自動(dòng)調(diào)用回調(diào)函數(shù)執(zhí)行一些操作;如:

ErrChkId=ChkStart_ErrorFramesOccured("Callback_ErrorFrameOccured");//檢查錯(cuò)誤幀,如果發(fā)現(xiàn)錯(cuò)誤幀就調(diào)用回調(diào)函數(shù)
回調(diào)函數(shù)設(shè)計(jì)如下:
void Callback_errorFrameOccured(dword chk_id)
{
  float t;
  t=timeNow()/100000.0;//記錄出現(xiàn)錯(cuò)誤幀的時(shí)間
  testStep("ErrorFrameTimeStamp","%.6f s",t);//打印該事件戳
  TestSupplyTextEvent("ErrorFrameOccured");//供應(yīng)Text事件
}

7、監(jiān)視總線的情況,這一般會(huì)用在查看一段時(shí)間內(nèi),總線上有沒有出現(xiàn)通訊異常的情況。需要使用函數(shù)ChkStart_NodeBabbling( ). 如,檢測一段時(shí)間內(nèi)總線有沒有出現(xiàn)停止通訊的情況:

CheckId=ChkStart_NodeBabbling(CAN::PT_MCU,0);//立即開始檢查總線狀態(tài)
testWaitForTimeout(2000);//延時(shí)2s
ChkControl_Stop(CheckId);//停止檢測
QueryNumberEvents=ChkQuery_NumEvents(CheckId);//如果在2s內(nèi)總線停止通訊,則QueryNumberEvents!=0

8、關(guān)于獲取關(guān)鍵時(shí)間點(diǎn)

(1)CANoe中獲取定時(shí)器當(dāng)前計(jì)時(shí)值的函數(shù)為:timerToElapse();該函數(shù)原型如下:

long timerToElapse(timer);
long timerToElpase(msTimer);                

(2)獲取等待某個(gè)事件的時(shí)間,需要使用函數(shù)TestGetLastWaitElapsedTimeNS(),其原型如下:

float TestGetLastWaitElapsedTimeNS();

(3)獲取當(dāng)前的仿真時(shí)間點(diǎn):

float timeNowFloat();

(4)等待指定報(bào)文:

long TestWaitForMessage(dbMessage aMessage,dword aTimeout);
long TestWaitForMessage(dword aMessageId,dword aTimeout);

若在aTimeout時(shí)間內(nèi)等到了指定ID的報(bào)文,函數(shù)返回1,否則返回0;

(5)獲取報(bào)文的數(shù)據(jù),等到了報(bào)文之后,如果想知道報(bào)文的具體內(nèi)容可以使用函數(shù):

message msg;
long result;
result=TestGetWaitEventMsgData(msg);
.....處理msg.....

9、多總線測試

設(shè)置總線背景,一般都總線測試都會(huì)有兩路及以上的CAN,這時(shí)若要通過CAPL腳本獲取某個(gè)CAN通道上的報(bào)文時(shí),就需要先設(shè)置好總線背景,即將總線設(shè)置為值監(jiān)聽某一路的CAN通道。下面是一個(gè)例子:

void BusContextConfiguration(char yBus[])
{
   yBusContext=GetBusNameContext(yBus);//這里的yBusContext為全局變量
   SetBusContext(yBusContext);
}
//使用:
BusContextConfiguration("CAN1");//將總線監(jiān)聽設(shè)為CAN1

此時(shí)等待某一路的CAN報(bào)文可是這樣實(shí)現(xiàn):

res=testWaitForMessage(CAN1::NM_IPU,600);//等待CAN1上的名稱為NM_IPU的報(bào)文,等待事件為600ms

10、診斷報(bào)文的發(fā)送和接收

request_A.SendRequest();//診斷請求
TestWaitForDiagResponse(request_A,5000);//診斷接收

11、

將診斷請求 / 響應(yīng)寫入報(bào)告

TestReportWriteDiagObject (diagRequest req);


TestReportWriteDiagObject (diagResponse resp);


TestReportWriteDiagResponse (diagRequest req);

12、獲取診斷請求 / 響應(yīng)的原始數(shù)據(jù)

long diagGetPrimitiveByte( diagRequest request, DWORD bytePos);


long diagGetPrimitiveByte( diagResponse response, DWORD bytePos);

13、獲取診斷請求 / 響應(yīng)的參數(shù)

long diagGetParameter (diagResponse obj, char parameterName[], double output[1])


long diagGetParameter (diagRequest obj, char parameterName[], double output [1])


double diagGetParameter (diagResponse obj, char parameterName[])


double DiagGetParameter (diagRequest obj, char parameterName[])


long diagGetParameter (diagResponse obj, long mode, char parameterName[], double output[1])


long DiagGetParameter (diagRequest obj, long mode, char parameterName[], double output [1])


double diagGetParameter (diagResponse obj, long mode, char parameterName[])


double diagGetParameter (diagRequest obj, long mode, char parameterName[])

最后分享最近剛使用CAPL腳本的一些注意點(diǎn)以及一個(gè)示例

第一CAPL 的局部變量是靜態(tài)局部變量。經(jīng)過使用發(fā)現(xiàn),在 variables{ }之外,事件或者函數(shù)內(nèi)部定義的局部變量是靜態(tài)局部變量,其值不會(huì)因?yàn)橥顺霰臼录蛘吆瘮?shù),而變?yōu)槌跏贾怠K匀绻娴男枰粋€(gè)局部變量,在每次退出之前,重新使用賦值語句賦為初始值。

第二建議使用系統(tǒng)變量或者環(huán)境變量,這樣可以跨不同的capl腳本操作,比如檢測某個(gè)環(huán)境變量或者系統(tǒng)變量的變化,來執(zhí)行一些動(dòng)作。

on sysvar sysvar::EngineStateSwitch
{
  $EngineState::OnOff = @this;
if(@this)
  $EngineState::EngineSpeed = @sysvar::Engine::EngineSpeedEntry;
else
  $EngineState::EngineSpeed = 0;
}

第三個(gè)就是以太網(wǎng)轉(zhuǎn)CAN的capl腳本示例:

/*@!Encoding:1252*/


variables
{
  //
  // Constants
  //
  
  const WORD kPort         = 23; // UDP port number for instance
  const WORD kRxBufferSize = 1500;
  const WORD kTxBufferSize = 1500;
  
  //
  // Structure of UDP payload
  //
  
  _align(1) struct CANData
  {
    BYTE  dlc;
    BYTE  flags; // Bit 7 - Frame type (0 = standard, 1 = extended)
                 // Bit 6 - RTR bit ('1' = RTR bit is set)
    DWORD canId;
    BYTE  canData[8];
  };
  
  //
  // Global variables
  //
  
  UdpSocket gSocket;
  CHAR      gRxBuffer[kRxBufferSize];
  CHAR      gTxBuffer[kTxBufferSize];
  DWORD     gOwnAddress;
  DWORD     gModuleAddress= 0xFFFFFFFF; // default is the broadcast address 255.255.255.255  and the TCP/IP stack will build the Network broadcast address
}


//
// Measurement start handler
//


on start
{
  DWORD addresses[1];
  
  // get own IP address of the Windows TCP/IP stack
  IpGetAdapterAddress( 1, addresses, elcount(addresses) );
  gOwnAddress = addresses[0];
  
  // open UDP socket
  gSocket = UdpSocket::Open( 0, kPort ); 
  
  if (gSocket.GetLastSocketError() != 0)
  {
    write( "<%BASE_FILE_NAME%> Open UDP socket failed, result %d. Measurement stopped!", gSocket.GetLastSocketError() );
    stop();
    return;
  }


  if (gSocket.ReceiveFrom( gRxBuffer, elcount(gRxBuffer) ) != 0)
  {
    if (gSocket.GetLastSocketError() != 997) // ignore pending IO operation
    {
      write( "<%BASE_FILE_NAME%> UDPReceive failed, result %d. Measurement stopped!", gSocket.GetLastSocketError() );
      stop();
      return;
    }
  }


}
//
// On receive UDP data handler using CAPL Callback 
//
void OnUdpReceiveFrom( dword socket, long result, dword address, dword port, char buffer[], dword size)
{
  DWORD          dataOffset;
  struct CANData canData;
  message *      canMsg;
  
if(address==gOwnAddress)return;//ignoreownbroadcasts
  //
  // Store IP address of module to reach
  //
  
  if (gModuleAddress == 0)
  {
    gModuleAddress = address;
  }
  
  //
  // Handle received data
  //
  
  dataOffset = 0;
  while (dataOffset + __size_of(struct CANData) <= size)
  {
    memcpy( canData, buffer, dataOffset );
    
    canMsg.id      = (canData.canId & 0x1FFFFFFF) | ((canData.flags & 0x80) ? 0x80000000 : 0);
    canMsg.dlc     = canData.dlc & 0x0f;
    canMsg.rtr     = ((canData.flags & 0x40) ? 1 : 0);
    canMsg.byte(0) = canData.canData[0];
    canMsg.byte(1) = canData.canData[1];
    canMsg.byte(2) = canData.canData[2];
    canMsg.byte(3) = canData.canData[3];
    canMsg.byte(4) = canData.canData[4];
    canMsg.byte(5) = canData.canData[5];
    canMsg.byte(6) = canData.canData[6];
    canMsg.byte(7) = canData.canData[7];
    
    output( canMsg );
   
    dataOffset += __size_of(struct CANData);
  }
  


  //
  // Receive more data
  //
  if (gSocket.ReceiveFrom( gRxBuffer, elcount(gRxBuffer) ) != 0)
  {
    if (gSocket.GetLastSocketError() != 997) // ignore pending IO operation
    {
      write( "<%BASE_FILE_NAME%> UDPReceive failed, result %d. Measurement stopped!", gSocket.GetLastSocketError() );
      stop();
      return;
    }
  }
}


//
// Handler for CAN messages
//


on message *
{
  int i;
  struct CANData canData;
  
  if ((this.dir == RX) && (gModuleAddress != 0))
  {
    canData.canId = this.id & 0x1FFFFFFF;
    canData.flags = ((this.id & 0x80000000) ? 0x80 : 0x00) | ((this.rtr == 1) ? 0x40 : 0x00);
    canData.dlc   = this.dlc;
    
    for( i = 0; i < 8; i++ )
    {
      canData.canData[i] = (i < this.dlc) ? this.byte(i) : 0;
    }
    
    memcpy( gTxBuffer, canData );
    
    gSocket.SendTo( gModuleAddress, kPort, gTxBuffer, __size_of(struct CANData) );
  }
  else if (gModuleAddress == 0)
  {
    write( "<%BASE_FILE_NAME%> Tx not possible. Module to reach must send packets first." ); //Server simulation
  }
}
審核編輯:黃飛

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7581

    瀏覽量

    135575
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4260

    瀏覽量

    62228
  • 腳本
    +關(guān)注

    關(guān)注

    1

    文章

    384

    瀏覽量

    14793

原文標(biāo)題:CAPL腳本使用介紹

文章出處:【微信號:eng2mot,微信公眾號:汽車ECU開發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    ProF腳本指令介紹及解決方案

    INCA是車輛控制器標(biāo)定的首選軟件之一,主要包含功能模型標(biāo)定、測量數(shù)據(jù)分析(MDA)、標(biāo)定數(shù)據(jù)管理(CDM)、控制器刷新(ProF)功能等。而本文將介紹常用卻又陌生的ProF腳本的擴(kuò)展用法,通過編寫
    的頭像 發(fā)表于 10-08 11:13 ?4454次閱讀

    CANoe編寫CAPL測試腳本的幾點(diǎn)思考

    測試腳本的開發(fā)人員,需要考慮到測試執(zhí)行者測試不同控制器時(shí)的參數(shù)配置。比如不同的網(wǎng)絡(luò)喚醒條件、不同的網(wǎng)絡(luò)管理消息、不同的時(shí)間參數(shù)等等。
    的頭像 發(fā)表于 01-02 10:42 ?1798次閱讀
    CANoe編寫<b class='flag-5'>CAPL</b>測試<b class='flag-5'>腳本</b>的幾點(diǎn)思考

    CAPL介紹-腳本編輯和常用基本事件#CANoe#CAPL#腳本

    編程語言
    北匯信息POLELINK
    發(fā)布于 :2023年01月06日 09:06:50

    CAPL編程語言 官方英文原版

    之前看過的一份CAPL編程語言資料,英文原版,分享給需要的小伙伴?。?!
    發(fā)表于 01-14 18:19

    Lua腳本簡單介紹

    Lua簡單介紹Lua[1]是一個(gè)小巧的腳本語言。作者是巴西人。該語言的設(shè)計(jì)目的是為了嵌入應(yīng)用程序中,從而為應(yīng)用程序提供靈活的擴(kuò)展和定制功能。Lua腳本能夠非常easy的被C/C++ 代碼調(diào)用,也能夠
    發(fā)表于 08-20 06:37

    Lua腳本簡單介紹

    Lua簡單介紹Lua[1]是一個(gè)小巧的腳本語言。作者是巴西人。該語言的設(shè)計(jì)目的是為了嵌入應(yīng)用程序中,從而為應(yīng)用程序提供靈活的擴(kuò)展和定制功能。Lua腳本能夠非常easy的被C/C++ 代碼調(diào)用,也能夠
    發(fā)表于 08-20 08:06

    如何用CAPL通過RS232遠(yuǎn)程控制ALR3220

    CAPL通過RS232遠(yuǎn)程控制ALR3220程控電源
    發(fā)表于 12-28 06:37

    什么是腳本

    什么是腳本,腳本是什么意思,腳本錯(cuò)誤是什么意思電子發(fā)燒友深入為大家講解了腳本相關(guān)知識
    發(fā)表于 12-07 10:36 ?2787次閱讀

    什么是腳本?腳本程序?qū)W習(xí)

    腳本中編寫VB腳本代碼。可以象使用系統(tǒng)函數(shù)一樣使用項(xiàng)目中完成的腳本。創(chuàng)建腳本時(shí),確定其型號并定義傳送參數(shù)?!癋unction”類型的腳本
    的頭像 發(fā)表于 05-11 10:39 ?6641次閱讀
    什么是<b class='flag-5'>腳本</b>?<b class='flag-5'>腳本</b>程序?qū)W習(xí)

    詳細(xì)介紹下如何解析ODX數(shù)據(jù)庫

    針對涉及診斷功能類(如DTC等)測試的項(xiàng)目,實(shí)現(xiàn)過程大致為兩步:先通過CANoe-CAPL完成通用的診斷功能測試腳本的開發(fā);
    的頭像 發(fā)表于 02-17 10:27 ?1091次閱讀

    什么是CAPL編程?

    與Vspy的"C Code Interface"一樣;在CANoe的使用中,一樣提供了我們進(jìn)行二次編程開發(fā)的工具——”CAPL Browser”。
    的頭像 發(fā)表于 06-18 10:13 ?2568次閱讀
    什么是<b class='flag-5'>CAPL</b>編程?

    CAPL編程語言快速入門

    CAPL是由Vector公司開發(fā)的類似于C語言的面向過程編程語言,是CANoe和CANalyzer中可用的編程語言。CAPL中程序塊的執(zhí)行由事件控制,在專用的編譯器中開發(fā)和編譯,這樣可以訪問數(shù)據(jù)庫中
    的頭像 發(fā)表于 09-17 16:11 ?2511次閱讀
    <b class='flag-5'>CAPL</b>編程語言快速入門

    Linux主機(jī)排查腳本介紹

    介紹 HScan,本腳本旨在為安全應(yīng)急響應(yīng)人員對Linux主機(jī)排查,日志分析等提供便利,定制化在主機(jī)中執(zhí)行命令 獲取腳本 git clone?https://github.com/HZzz2
    的頭像 發(fā)表于 06-28 09:44 ?500次閱讀
    Linux主機(jī)排查<b class='flag-5'>腳本</b><b class='flag-5'>介紹</b>

    ?CAPL在診斷中的應(yīng)用,你值得了解!

    的過程中相信每位工程師都或多或少的要和“CAPL”打交道。學(xué)好CAPL的用法可以讓我們更加高效、便捷地使用CANoe。本文就CANoe中關(guān)于診斷的CAPL函數(shù)進(jìn)行介紹
    的頭像 發(fā)表于 09-07 08:27 ?911次閱讀
    ?<b class='flag-5'>CAPL</b>在診斷中的應(yīng)用,你值得了解!

    Shell腳本檢查工具ShellCheck介紹

    ShellCheck是一個(gè)用于bash/sh shell腳本的靜態(tài)分析工具,可以輔助檢查腳本語法錯(cuò)誤,給出建議增強(qiáng)腳本健壯性。
    的頭像 發(fā)表于 12-27 13:43 ?1818次閱讀
    Shell<b class='flag-5'>腳本</b>檢查工具ShellCheck<b class='flag-5'>介紹</b>