メインコンテンツまでスキップ

概要

送信、受信、スロット送信等、MicroPeckerX CAN FDアプリケーション開発ライブラリで利用できる機能を確認できるサンプルプログラムをご用意しています。

サンプルプログラム環境構築

02_sampleディレクトリに、お使いのCPU/OS対応する静的ライブラリをコピーして make してください。
若しくは、動的ライブラリをOSライブラリがロード可能なパスにコピーして実行して下さい。

通信設定

サンプルプログラムの通信設定(ボーレート、サンプルポイント)は以下の通りです。

大項目小項目設定値
アービトレーション部ボーレート500kbps
サンプルポイント80%
ペイロード部ボーレート2Mbps
サンプルポイント80%

Python版サンプルプログラム

送信、受信が利用できるPython3ラッパとPythonアプリケーションサンプルです。
カスタムPythonラッパやMPX向けPythonアプリケーション開発にお役立て下さい。

実行方法

ユーザ書き込み許可設定まで実施した後に、以下の順で、Pythonラッパサンプルのビルドとインストールを行って下さい。

python setup.py build
sudo python setup.py install

インストール後に、「mpx_adl_sample.py」を実行するとサンプルが動作します。

確認できる機能

  • モニタ機能
  • 送信(シミュレーション)機能

サンプルの動作

  • CH1
    CAN-IDとペイロードの1バイト目をインクリメントしつつ10,000メッセージ送信します。
    CH1に流れるメッセージをコンソールに表示します。
  • CH2
    未使用

サンプルソースコード

import MPX_ADL_WR
import threading

#read thread
def read_exec():
while True:
ret = MPX_ADL_WR.DispMonitor(serial,1)
if not ret is None:
for i in range(ret[0]):
print('time:' +
str(ret[1 + i][0]) +'[ms] , ' +
str(ret[1 + i][1]) +'[us] , CAN-ID:' +
hex(ret[1 + i][2]) +
' DL:' + str(ret[1 + i][3]) +
' DIR:' + ret[1 + i][4] +
' DATA:' + str(ret[1 + i][5]))
global stop_threads
if stop_threads:
break

ret=MPX_ADL_WR.MPXOpen()
if ret[0] != 0:
print('MPXOpen Error:' + str(ret[0]))

print('Serial No.')
for i in range(ret[1]):
print(' ' + str(ret[2][i]))

serial = ret[2][0]

print('MPX INIT.')
ret=MPX_ADL_WR.MPXSampleInit(serial)
if ret != 0:
print('INIT error:' + str(ret))

print('MPX MonitorStart.')
ret=MPX_ADL_WR.MPXMonitorStart(serial)

print('Start ReadThread...')
stop_threads = False
read_thread = threading.Thread(target=read_exec)
read_thread.start()

print('CAN_SEND...')
senddata=bytearray(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B')
for i in range(10000):
ret=MPX_ADL_WR.MPXDirectSend(serial,1,i,8,senddata)
senddata[0] = (senddata[0] + 1) % 256
if ret != 0:
print('SendError:' + str(ret))

stop_threads = True
read_thread.join()

ret=MPX_ADL_WR.MPXMonitorStop(serial)
if ret[0] != 0:
print('MonitorStop :Error' + str(ret[0]))
else:
print('MonitorStop :Time'+str(ret[1])+'[ms]'+ str(ret[2])+'[ns]')

ret=MPX_ADL_WR.MPXClose()
  1. デバイスオープンと初期化
  • MPXOpen() でMicroPeckerXデバイスを検索し、シリアル番号を取得。
  • (serial)を初期化(MPXSampleInit)&モニタリング開始(MPXMonitorStart)。
  1. モニタ用スレッドの起動
  • read_exec()関数を別スレッドで動作。
    • 常時CANの受信を監視し、受信データをリアルタイムで表示する処理。
    • MPX_ADL_WR.DispMonitorを呼び出し、返り値(受信フレーム群)を出力。
  1. CAN送信データ生成と送信
  • 12バイトのバイト列 (senddata) を初期値として用意。
  • ループで1万回、MPXDirectSendでCANフレーム送信。  
    • 第3引数iはCAN ID(毎回カウントアップ)。
    • 第4引数8はデータ長(8バイト)。
    • 第5引数senddataは送信ペイロード。

送信するペイロード(データフィールド)の最初の1バイトをインクリメントしています。
CAN IDはループ変数iで、毎回違うIDで送信しています。

  1. 終了処理
  • 送信後、stop_threads = Trueで受信スレッド終了。
  • モニタストップ&デバイスクローズ。

C++版サンプルプログラム

確認できる機能

  • モニタ機能
  • 送信(シミュレーション)機能
  • スロット送信機能
  • ボーレート機能
  • 終端抵抗有無切り替え機能

サンプルの動作

  • CH1
    モニタモードで動作します。CH1に流れるメッセージをコンソールに表示します。
  • CH2
    スロット送信機能でID:300 ID:400 を送信します。
    また、ダイレクト送信機能でID:350を送信します。
スロット送信機能とダイレクト送信機能
  • スロット送信機能は、MicroPeckerXに送信設定を行い、MicroPeckerXが主体となり送信する機能です。
    実車両で要求されるような厳密な周期で送信が可能です。
  • ダイレクト送信機能は、PCが主体となり都度送信する機能です。
    PC上でデータを変更しつつ送信する場合などに有効です。

サンプルソースコード

#include "MPXCANFDCtrlLinuxFree.h"
#include "stdio.h"
#include "unistd.h"
#include <deque>
#include <pthread.h>
#include <sstream>
#include <string.h>
#include <iostream>
#include <stdint.h>

//グローバル
unsigned int serial;
StMPXCANSlot MPXCANSlot[2];

//表示文字列
std::deque<std::string> print_que;

void DispMonitor(void);

pthread_mutex_t que_mutex;
std::string strbuf;

void * thread_routine(void *data) {
while (1) {
usleep(1000 * 5); //wait1ms
pthread_mutex_lock(&que_mutex);
if(!print_que.empty()) {
strbuf = print_que.front();
print_que.pop_front(); // 先頭要素を削除
std::cout << strbuf; //バッファを表示
}
pthread_mutex_unlock(&que_mutex);
pthread_testcancel();
}
return 0;
}


int main() {
ER ret;
unsigned int MSec;
unsigned short USec;

pthread_t print_thread;

printf("Sample Start\n");
/* MicroPeckerXオープン */
StMPXDeviceInfo devices[4];
unsigned char count;

ret = MPXOpen(devices, &count);
if (ret != E_OK)
{
printf("MPXOpen : error");
return 1;
}
else if (count == 0)
{
printf("MPXOpen : no devices");
return 1;
}
else
{
/* シリアル番号 */
serial = devices[0].Serial;
/* LED消灯 */
MPXSetLED(serial, MPX_LED_OFF, MPX_LED_OFF, MPX_LED_OFF, MPX_LED_OFF, MPX_LED_OFF);
}

for (int i = 0; i < count; i++) {
printf("Serial : [%d]\n" , devices[0].Serial );
}


/* APIバージョン情報 */
StMPXAPIVersion version;
MPXGetAPIVersion(&version);
printf("API Version : [%s]\n" , version.APIVersion );

/* CAN FD通信パラメータ設定 */
StMPXCANParam param1, param2;
param1.Mode = MPX_MODE_MONITOR;
param1.ArbitrationBaudrate = MPX_CAN_PARAM_ABR_500K;
param1.ArbitrationSamplepoint = MPX_CAN_PARAM_SP_80P;
param1.DataBaudrate = MPX_CAN_PARAM_DBR_2M;
param1.DataSamplepoint = MPX_CAN_PARAM_SP_80P;
param1.EnableTerminate = MPX_CAN_TERMINATE_ENABLE; //終端有効

param2 = param1;
param2.Mode = MPX_MODE_CAN_SIM; /* Ch2はシミュレータ(送信有) */

ret = MPXSetCANParam(serial, 1, &param1);
if (ret != E_OK)
{
printf("\n MPXSetCANParam 1 : error\n");
return -1;
}
ret = MPXSetCANParam(serial, 2, &param2);
if (ret != E_OK)
{
printf("\n MPXSetCANParam 2 : error\n");
return -1;
}


/* シミュレーションデータ設定(スロット送信機能) */
for (int i = 0; i < 2; i++)
{
MPXCANSlot[i].SlotNo = i;
MPXCANSlot[i].FrameType.Enabled = MPX_CAN_SLOT_ENABLE; /* スロットの有効化 */
MPXCANSlot[i].FrameType.Option.Protocol = MPX_CAN_PROTOCOL_CANFD;
MPXCANSlot[i].FrameType.Option.BRS = MPX_CAN_BRS_ENABLE;
MPXCANSlot[i].Frame.ID.IDE = MPX_CAN_IDE_STD;
MPXCANSlot[i].Frame.ID.RTR = MPX_CAN_RTR_DATA;
MPXCANSlot[i].msSendCycle = 35U;
MPXCANSlot[i].SendCounter = 0; /* 0は無制限を示す */
MPXCANSlot[i].Frame.DL = 20;
for (int j = 0; j < 20; j++)
{
MPXCANSlot[i].Frame.Data[j] = (i + 1) * 0x10 + j;
MPXCANSlot[i].Increment[j] = MPX_CAN_SIM_INC_TRUE;
}
}
/* フレーム個別設定 */
MPXCANSlot[0].Frame.ID.ID = 0x300U;
MPXCANSlot[1].Frame.ID.ID = 0x400U;
MPXCANSlot[1].msSendCycle = 2U;
MPXCANSlot[0].FrameType.FrameType = MPX_CAN_FRAME_TYPE_PERIODIC;
MPXCANSlot[1].FrameType.FrameType = MPX_CAN_FRAME_TYPE_PERIODIC;

/* スロット設定(2CH) */
ret = MPXSetSlot(serial, 2, &MPXCANSlot[0], 2);
if (ret != E_OK)
{
printf("\n MPXSetSlot 2 : error[%d]\n",ret);
return -1;
}

/* ログ取得モードの設定 Ch1 */
MPXSetGetLogMode(serial, 1, MPX_GETLOGMODE_GETLOGAPI);

/* ログ取得モードの設定 Ch1 */
MPXSetGetLogMode(serial, 2, MPX_GETLOGMODE_GETLOGAPI);

printf("\n Monitor Start ...\n");
/* モニタリング開始 */
ret = MPXMonitorStart(serial, MPX_SYNC_MASTER);
if (ret != E_OK)
{
printf("\n Monitor Start : error");
return -1;
}

int pth_arg;
//表示スレッド起動
pthread_mutex_init(&que_mutex, NULL);
if (pthread_create(&print_thread, NULL, thread_routine, (void *)&pth_arg) != 0) {
perror("pthread_create");
return 1;
}

/* モニタリング */
for(int i = 0; i < 10000 ;i++){
/* usleep (コメントアウト中):
ソフトウェア制御では周期送信間隔を正確に維持できない
(スケジューリングにより設定したSleep時間より多くの時間を待たされる) */
//usleep(50)
/* ダイレクト送信機能 */
StMPXCANDirect directFrame;
/* 送信データ設定(CAN-FDデータ) */
directFrame.FrameType.Option.Protocol = MPX_CAN_PROTOCOL_CANFD;
directFrame.FrameType.Option.BRS = MPX_CAN_BRS_ENABLE;

directFrame.Frame.ID.IDE = MPX_CAN_IDE_STD;
directFrame.Frame.ID.RTR = MPX_CAN_RTR_DATA;
directFrame.Frame.ID.ID = 0x350;
directFrame.Frame.DL = 64;
/* 先頭4byteにカウンタ値を代入(CPUエンディアン依存) */
memcpy(&directFrame.Frame.Data[0], &i, 4);
for (int i = 4; i < 64; i++)
{
directFrame.Frame.Data[i] = 0x30;
}

MPXDirectSend(serial,2,&directFrame);
DispMonitor();
}

ret = MPXMonitorStop(serial, &MSec, &USec);
if (ret != E_OK)
{
printf("MPXMonitorStop : error");
return -1;
}
pthread_mutex_lock(&que_mutex);
print_que.clear();
pthread_mutex_unlock(&que_mutex);


usleep(100 * 1000); //wait100ms

pthread_cancel(print_thread);
pthread_join(print_thread, NULL);

//表示用キューを削除
if(!print_que.empty())
print_que.clear();

MPXClose();
return 0;
}

void DispMonitor(void)
{
/*モニタログ取得*/
uint16_t Count;
uint8_t BufferOver;

ER ret;
StMPXCANLog *CANLog;
std::stringstream dispTmp;

//CH2のログは捨てる
ret = MPXGetLog(serial, 2, &CANLog, &Count, &BufferOver);
ret = MPXGetLog(serial, 1, &CANLog, &Count, &BufferOver);

if (ret != E_OK)
{
printf("MPXGetLog: error\n");
return;
}
/* ログ表示 */
for (int i = 0; i < (int)Count; i++)
{


//空ログ無視
if(CANLog[i].Protocol == MPX_LOG_TYPE_EMPTY){
continue;
}
/* エラーチェック */
if (CANLog[i].Error == CAN_ERRFLG_FALSE)
{
/* 時間 */
dispTmp << "time : " << std::dec << (int)CANLog[i].mSec << "[ms]," << (int)CANLog[i].uSec << "[us] ,";

/* IDフォーマット */
if (CANLog[i].IDE == MPX_CAN_IDE_STD)
{
//printf("Std ,");
dispTmp << "Std ,";
}
else
{
dispTmp << "Ext ,";
}

/* ID */
dispTmp << "CAN-ID:" << std::hex << (int)CANLog[i].ID << " ,";

dispTmp << "DL:" << std::dec <<(int)CANLog[i].DL << " ,";

/* 方向 */
dispTmp << "DIR : ";
if (CANLog[i].Dir == MPX_LOG_DIR_RX)
{
dispTmp << "Rx ,";
}
else
{
dispTmp << "Tx ,";
}

dispTmp << "DATA : ";
/* Data */
for (int j = 0; j < CANLog[i].DL; j++)
{
dispTmp << std::hex << (int)CANLog[i].Data[j] << " ";
}
dispTmp << "\n";
}
else
{
if (CANLog[i].ErrorInfo & CAN_ERR_ACK)
{
dispTmp << "ERROR : Ack E.\n";
}
else if (CANLog[i].ErrorInfo == CAN_ERR_OVERLOAD)
{
dispTmp << "ERROR : OLF E.\n";
}
}
}
pthread_mutex_lock(&que_mutex);
print_que.push_back(dispTmp.str());
pthread_mutex_unlock(&que_mutex);

}