Overview
This product provides sample programs that let you verify features available in the MicroPeckerX CAN FD application development library, such as transmit, receive, and slot transmission.
Sample Program Environment Setup
Copy the static library for your CPU/OS into the 02_sample directory and run make.
Alternatively, copy the dynamic library to a path where your OS can load libraries and run the program.
Communication Settings
The communication settings (baud rate and sample point) for the sample programs are as follows.
| Category | Item | Setting Value |
|---|---|---|
| Arbitration Section | Baud Rate | 500kbps |
| Sample Point | 80% | |
| Payload Section | Baud Rate | 2Mbps |
| Sample Point | 80% |
Python Sample Program
This is a Python 3 wrapper and sample Python application that supports transmit and receive operations.
Use it for developing custom Python wrappers and Python applications for MPX.
How to Run
After completing the user write-permission setup, build and install the Python wrapper sample in the following order.
python setup.py build
sudo python setup.py install
After installation, run mpx_adl_sample.py to execute the sample.
Features You Can Verify
- Monitoring function
- Transmission (simulation) function
Sample Behavior
- CH1
Transmits 10,000 messages while incrementing the CAN ID and the first byte of the payload.
Displays messages on CH1 in the console. - CH2
Unused
Sample Source Code
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()
- Open and initialize device
- MPXOpen() Searches for MicroPeckerX devices and obtains the serial number.
- Initializes
serial(MPXSampleInit) and starts monitoring (MPXMonitorStart).
- Start monitoring thread
- Runs
read_exec()in a separate thread.- Continuously monitors CAN reception and displays received data in real time.
- Calls
MPX_ADL_WR.DispMonitorand outputs returned values (received frame list).
- Generate and transmit CAN data
- Prepares a 12-byte array (
senddata) as initial data. - Transmits CAN frames 10,000 times in a loop using
MPXDirectSend.- The third argument
iis the CAN ID (incremented each loop). - The fourth argument
8is the data length (8 bytes). - The fifth argument
senddatais the payload to transmit.
- The third argument
The first byte of the transmitted payload (data field) is incremented each time.
The CAN ID uses loop variable i, so each transmission uses a different ID.
- Shutdown processing
- After transmission, sets
stop_threads = Trueto stop the receive thread. - Stops monitoring and closes the device.
C++ Sample Program
Features You Can Verify
- Monitoring function
- Transmission (simulation) function
- Slot transmission function
- Baud rate function
- Termination resistor on/off switching function
Sample Behavior
- CH1
Operates in monitor mode and displays messages on CH1 in the console. - CH2
Transmits ID:300 and ID:400 using slot transmission.
Also transmits ID:350 using direct transmission.
Slot Transmission and Direct Transmission
- Slot transmission configures transmission on MicroPeckerX and lets MicroPeckerX transmit autonomously.
It supports strict transmission cycles, as required in actual vehicles. - Direct transmission sends frames each time under PC control.
It is useful when changing data dynamically on the PC while transmitting.
Sample Source Code
#include "MPXCANFDCtrlLinuxFree.h"
#include "stdio.h"
#include "unistd.h"
#include <deque>
#include <pthread.h>
#include <sstream>
#include <string.h>
#include <iostream>
#include <stdint.h>
// global
unsigned int serial;
StMPXCANSlot MPXCANSlot[2];
// display string
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(); // remove first element
std::cout << strbuf; // display buffer
}
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");
/* Open 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 number */
serial = devices[0].Serial;
/* Turn off LEDs */
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 version information */
StMPXAPIVersion version;
MPXGetAPIVersion(&version);
printf("API Version : [%s]\n" , version.APIVersion );
/* CAN FD communication parameter settings */
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; // termination enabled
param2 = param1;
param2.Mode = MPX_MODE_CAN_SIM; /* CH2: simulator (with transmission) */
ret = MPXSetCANParam(serial, 1, ¶m1);
if (ret != E_OK)
{
printf("\n MPXSetCANParam 1 : error\n");
return -1;
}
ret = MPXSetCANParam(serial, 2, ¶m2);
if (ret != E_OK)
{
printf("\n MPXSetCANParam 2 : error\n");
return -1;
}
/* Simulation data settings (slot transmission function) */
for (int i = 0; i < 2; i++)
{
MPXCANSlot[i].SlotNo = i;
MPXCANSlot[i].FrameType.Enabled = MPX_CAN_SLOT_ENABLE; /* Enable slot */
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 means unlimited */
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;
}
}
/* Per-frame settings */
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;
/* Slot settings (2CH) */
ret = MPXSetSlot(serial, 2, &MPXCANSlot[0], 2);
if (ret != E_OK)
{
printf("\n MPXSetSlot 2 : error[%d]\n",ret);
return -1;
}
/* Set log acquisition mode Ch1 */
MPXSetGetLogMode(serial, 1, MPX_GETLOGMODE_GETLOGAPI);
/* Set log acquisition mode Ch1 */
MPXSetGetLogMode(serial, 2, MPX_GETLOGMODE_GETLOGAPI);
printf("\n Monitor Start ...\n");
/* Start monitoring */
ret = MPXMonitorStart(serial, MPX_SYNC_MASTER);
if (ret != E_OK)
{
printf("\n Monitor Start : error");
return -1;
}
int pth_arg;
// start display thread
pthread_mutex_init(&que_mutex, NULL);
if (pthread_create(&print_thread, NULL, thread_routine, (void *)&pth_arg) != 0) {
perror("pthread_create");
return 1;
}
/* Monitoring */
for(int i = 0; i < 10000 ;i++){
/* usleep (commented out):
software control cannot maintain periodic transmission intervals accurately
((scheduling may wait longer than the configured sleep time)) */
//usleep(50)
/* Direct transmission function */
StMPXCANDirect directFrame;
/* Transmission data settings (CAN-FD data) */
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;
/* Assign counter value to first 4 bytes (CPU-endian dependent) */
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);
// clear display queue
if(!print_que.empty())
print_que.clear();
MPXClose();
return 0;
}
void DispMonitor(void)
{
/* Acquire monitor logs */
uint16_t Count;
uint8_t BufferOver;
ER ret;
StMPXCANLog *CANLog;
std::stringstream dispTmp;
// discard CH2 logs
ret = MPXGetLog(serial, 2, &CANLog, &Count, &BufferOver);
ret = MPXGetLog(serial, 1, &CANLog, &Count, &BufferOver);
if (ret != E_OK)
{
printf("MPXGetLog: error\n");
return;
}
/* Display logs */
for (int i = 0; i < (int)Count; i++)
{
// ignore empty logs
if(CANLog[i].Protocol == MPX_LOG_TYPE_EMPTY){
continue;
}
/* Error check */
if (CANLog[i].Error == CAN_ERRFLG_FALSE)
{
/* Time */
dispTmp << "time : " << std::dec << (int)CANLog[i].mSec << "[ms]," << (int)CANLog[i].uSec << "[us] ,";
/* ID format */
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 << " ,";
/* Direction */
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);
}