RM新时代网站-首页

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

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

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

CAPL腳本使用介紹

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

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

然而里面還有一項最重要的,也是平時使用過程中,提效很明顯的CAPL腳本的使用,覆蓋整車各節(jié)點的模擬、軟件刷寫、診斷測試等等,今天就來理一理CAPL腳本。 首先理一理基本語法和常用語句。在打開CAPl編輯界面時,下默認組成部分有: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é))

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

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

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

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

1、定時器

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

msTimer myTimer1;//聲明了一個ms定時器,定時單位是毫秒
timermyTimer2;//聲明了一個以秒為單位的定時器;

設置定時器:

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

設置定時器定時事件,即當定時器計時時間到時將要執(zhí)行的操作:

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

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

//CAN消息發(fā)送:
message0x7ffMsg;//聲明一個message,ID=0x7ff
Msg.dlc=8;//設置其DLC=8;
Msg.id=0x100;//更改其ID=0x100;
Msg.byte(0)=55;//設置數(shù)據(jù)場的第一個字節(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é)點上下線操作

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

節(jié)點上線:

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

節(jié)點下線:

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

4、檢查錯誤幀

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

下面是一個小的例子

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

5、添加事件信號

這種事件信號相當于信號量機制,一般使用在需要等待某個或者是多個條件滿足時進行下一步操作。

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

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

以下是一個例子:

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、回調函數(shù)

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

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

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

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

8、關于獲取關鍵時間點

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

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

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

float TestGetLastWaitElapsedTimeNS();

(3)獲取當前的仿真時間點:

float timeNowFloat();

(4)等待指定報文:

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

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

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

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

9、多總線測試

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

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

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

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

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

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

11、

將診斷請求 / 響應寫入報告

TestReportWriteDiagObject (diagRequest req);


TestReportWriteDiagObject (diagResponse resp);


TestReportWriteDiagResponse (diagRequest req);

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

long diagGetPrimitiveByte( diagRequest request, DWORD bytePos);


long diagGetPrimitiveByte( diagResponse response, DWORD bytePos);

13、獲取診斷請求 / 響應的參數(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腳本的一些注意點以及一個示例

第一CAPL 的局部變量是靜態(tài)局部變量。經(jīng)過使用發(fā)現(xiàn),在 variables{ }之外,事件或者函數(shù)內(nèi)部定義的局部變量是靜態(tài)局部變量,其值不會因為退出本事件或者函數(shù),而變?yōu)槌跏贾?。所以如果真的需要一個局部變量,在每次退出之前,重新使用賦值語句賦為初始值。

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

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

第三個就是以太網(wǎng)轉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)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • C語言
    +關注

    關注

    180

    文章

    7604

    瀏覽量

    136685
  • 函數(shù)
    +關注

    關注

    3

    文章

    4327

    瀏覽量

    62569
  • 腳本
    +關注

    關注

    1

    文章

    389

    瀏覽量

    14858

原文標題:CAPL腳本使用介紹

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

收藏 人收藏

    評論

    相關推薦

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

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

    CANoe編寫CAPL測試腳本的幾點思考

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

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

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

    CAPL編程語言 官方英文原版

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

    Lua腳本簡單介紹

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

    Lua腳本簡單介紹

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

    如何用CAPL通過RS232遠程控制ALR3220

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

    什么是腳本

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

    什么是腳本?腳本程序學習

    腳本中編寫VB腳本代碼??梢韵笫褂孟到y(tǒng)函數(shù)一樣使用項目中完成的腳本。創(chuàng)建腳本時,確定其型號并定義傳送參數(shù)?!癋unction”類型的腳本
    的頭像 發(fā)表于 05-11 10:39 ?6757次閱讀
    什么是<b class='flag-5'>腳本</b>?<b class='flag-5'>腳本</b>程序學習

    CAPL通過RS232遠程控制ALR3220程控電源

    CAPL通過RS232遠程控制ALR3220程控電源
    發(fā)表于 01-05 15:10 ?20次下載
    用<b class='flag-5'>CAPL</b>通過RS232遠程控制ALR3220程控電源

    什么是CAPL編程?

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

    CAPL編程語言快速入門

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

    Linux主機排查腳本介紹

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

    ?CAPL在診斷中的應用,你值得了解!

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

    Shell腳本檢查工具ShellCheck介紹

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