バックナンバーはこちら。
https://www.simulationroom999.com/blog/diagnostic-communication-backnumber/
はじめに
ISO-TPのシミュレーションをしよう。のシリーズ。
XLドライバライブラリの受信割り込みと送信完了割り込みの再現方法について。
登場人物
博識フクロウのフクさん
イラストACにて公開の「kino_k」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=iKciwKA9&area=1
エンジニア歴8年の太郎くん
イラストACにて公開の「しのみ」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=uCKphAW2&area=1
XLドライバライブラリの割り込みエミュレーションのソースコード
じゃ、前回の続き。
XLドライバライブラリを割り込みっぽくするんだっけ?
これはとっととコードを出してしまう。
全てのコードを載せるとえらいことになるんで、
スレッド関数の部分だけ。
DWORD WINAPI CCANFunctions::RxThread(LPVOID par)
{
XLstatus xlStatus;
XLcanRxEvent xlEvent;
CCANFunctions *pThis;
TStruct *pth;
bThreadRun = TRUE;
pth = (TStruct*) par;
pThis = (CCANFunctions *)pth->pThis;
while (bThreadRun) {
WaitForSingleObject(pth->hMsgEvent,100);
xlStatus = XL_SUCCESS;
unsigned short flags;
while (!xlStatus) {
xlStatus = xlCanReceive(pth->xlPortHandle, &xlEvent);
if ( xlStatus != XL_ERR_QUEUE_IS_EMPTY ) {
flags = xlEvent.tag;
switch( flags ){
case XL_CAN_EV_TAG_RX_ERROR:
// 受信エラー
if( pThis->err_callback ){
// エラー割り込み
pThis->err_callback( pThis, &xlEvent );
}
break;
case XL_CAN_EV_TAG_TX_ERROR:
// 送信エラー
if( pThis->err_callback ){
// エラー割り込み
pThis->err_callback( pThis, &xlEvent );
}
break;
case XL_CAN_EV_TAG_TX_OK:
// 送信完了
if( pThis->tx_callback ){
// 送信完了割り込み
pThis->tx_callback( pThis, &xlEvent );
}
break;
case XL_CAN_EV_TAG_RX_OK:
// 受信
if( pThis->rx_callback ){
// 受信割り込み
pThis->rx_callback( pThis, &xlEvent );
}
break;
case XL_CAN_EV_TAG_CHIP_STATE:
// BusOFF強制復帰
pThis->CANGoOffBus();
pThis->CANGoOnBus();
break;
default:
break;
}
}
}
}
return NO_ERROR;
}
XLドライバライブラリの割り込みエミュレーション説明
動きがイメージできない・・・。
まぁそうだろうね。
ポイントは以下。
①WaitForSingleObject関数
②xlCanReceive関数
③switch文と各種コールバック
WaitForSingleObject関数
WaitForSingleObject関数はWin32APIの一つ。
イベントオブジェクトがシグナル状態になるか、
指定タイムアウトが過ぎることで戻ってくる関数。
つまりは、基本的にはここで止まっていることの方が多いと言える。
シグナル状態って?
イベントオブジェクトの場合は別スレッドでSetEvent関数で該当イベントオブジェクトを呼び出すことで、シグナル状態になる。
WaitForSingleObjectから戻った段階で非シグナル状態になんで、
SetEvent関数が呼ばれた回数分スレッド内の処理が実施されるイメージだね。
ほう。
ってことは、XLドライバライブラリの内部でCAN受信毎かCAN送信毎にSetEvent関数が呼ばれているんで、
そのタイミングでスレッドが1回動作することになるってことか。
その通り。
xlCanReceive関数
xlCanReceive関数はXLドライバライブラリのAPIの一つでCAN受信用関数。
今回の関数だとxlEvent変数に受信情報が格納される。
1フレームずつ取得するんだけど、
空の場合はXL_ERR_QUEUE_IS_EMPTYが戻り値になる。
WaitForSingleObjectを抜けてきた状態に於いて、
XL_ERR_QUEUE_IS_EMPTYが戻りになることは無いはずなんだけど、
一応、XL_ERR_QUEUE_IS_EMPTYではないことをチェックして次の判定に進んでいる。
まぁ、念のためのチェックは必要だよねー。
実はどっかで読み出されてるってことも有るかもしれないし。
switch文と各種コールバック
で、割り込みエミュレーションを実現している部分が
各種case文とコールバック関数
あーこれこれ。
xlEvent.tagってのにxlCanReceiveから取得したデータの意味が入ってると思って良いのかな?
うん。あってるよ。
xlCanReceiveは受信関数ではあるんだけど、
実際には送信フレームやエラー情報も1つのフレームという体で取得できるんだ。
なるほど。
それで、xlEvent.tagの情報を元にswitchで分岐してそれぞれ該当メソッドを呼び出しているわけか。
今回提示したコード上では載せてないけど、
この先で上位から渡されたコールバック関数を呼ぶような処理をいれると、
割り込み相当の動作になる。
あ、割り込みの実現はスレッドでやっているってことか!
割り込みとスレッドは異なる概念ではあるけれども、
別の処理に切り替えるという特性だけ利用している感じだね。
こうすることで上位のAUTOSAR-CanTpからすると割り込みが来たように見える。
ってわけだ。
あと、XL_CAN_EV_TAG_CHIP_STATEの場合になんかBusOffしてからBusOnするような処理が入ってるけど、これは何?
virtual CAN Busだと気にしなくて良いんだけど、
実際の物理的なCANの場合、ハーネスの抜き差しでCANがBusOFFになって復帰しないことがあるんだよね。
それを強制的に復帰させるためのおまじない。
おまじないって・・・。
ホントはCANのエラーアクティブ、エラーパッシブ、バスオフの状態を意識する必要があるんだけど、ここでは省略だ。
まぁおまじないとしておいた方が安全な気がしてきた。
まとめ
まとめだよ。
- 割り込みエミュレーションのコードを提示。
- WaitForSingleObjectでシグナル待ち。
- xlCanReceiveで受信、送信、エラーの各種情報を取得。
- xlEvent.tagで各種処理に振り分け。
バックナンバーはこちら。
コメント