Skip to main content

Overview

Sample programs are provided so you can try out the features available in the MicroPeckerX CAN FD Application Development Library, such as transmission, reception, and slot-based transmission.

Preparing the Sample Program Environment

Copy the static library for your CPU/OS into the 02_sample directory and run make.
Alternatively, copy the dynamic library to a path that the OS can load and then run the sample.

Communication Settings

The sample programs use the following communication settings (baud rate and sample point).

SectionItemSetting
Arbitration fieldBaud rate500 kbps
Sample point80%
Payload fieldBaud rate2 Mbps
Sample point80%

Python Sample Program

This is a Python 3 wrapper and sample application that supports transmission and reception.
Use it as a reference when creating custom Python wrappers or developing Python applications for MicroPeckerX.

How to Run

After completing the user write-permission setup, build and install the Python wrapper sample as follows.

python setup.py build
sudo python setup.py install

After installation, run mpx_adl_sample.py to launch the sample.

Features Demonstrated

  • Monitoring
  • Transmission (simulation)

Sample Behavior

  • CH1
    Transmits 10,000 messages while incrementing the CAN ID and the first byte of the payload, and prints the frames flowing on CH1 to the console.
  • CH2
    Not used.

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()
  1. Opening and Initializing the Device
    • MPXOpen() searches for MicroPeckerX devices and retrieves their serial numbers.
    • Initializes the device (MPXSampleInit) and starts monitoring (MPXMonitorStart) for serial.
  2. Starting the Monitoring Thread
    • Runs read_exec() in a separate thread.
      • Continuously monitors CAN reception and prints received data in real time.
      • Calls MPX_ADL_WR.DispMonitor and outputs the returned frames.
  3. Generating and Sending CAN Data
    • Prepares a 12-byte array (senddata).
    • Sends a CAN frame 10,000 times with MPXDirectSend.
      • Third argument i is the CAN ID (incremented each time).
      • Fourth argument 8 is the data length (8 bytes).
      • Fifth argument senddata is the payload.
    • The first payload byte is incremented for each transmission, and the CAN ID changes on every loop iteration.
  4. Shutdown
    • Sets stop_threads = True to terminate the receive thread after transmission.
    • Stops monitoring and closes the device.

C++ Sample Program

Features Demonstrated

  • Monitoring
  • Transmission (simulation)
  • Slot-based transmission
  • Baud-rate configuration
  • Toggling the termination resistor

Sample Behavior

  • CH1
    Runs in monitor mode and prints the messages flowing on CH1 to the console.
  • CH2
    Transmits frames with IDs 0x300 and 0x400 via slot transmission, and transmits ID 0x350 via direct transmission.
Slot Transmission vs. Direct Transmission
  • Slot transmission configures the MicroPeckerX unit to perform transmission autonomously. It can transmit with accurate periods suitable for real vehicle requirements.
  • Direct transmission lets the PC send frames on demand, which is useful when you want to modify data 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 values
unsigned int serial;
StMPXCANSlot MPXCANSlot[2];

// Output queue
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); // wait 1 ms
pthread_mutex_lock(&que_mutex);
if (!print_que.empty()) {
strbuf = print_que.front();
print_que.pop_front(); // remove the oldest element
std::cout << strbuf; // print 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 );

/* Configure CAN FD communication parameters */
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; // enable termination

param2 = param1;
param2.Mode = MPX_MODE_CAN_SIM; /* CH2 operates as a simulator (transmit enabled) */

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;
}

/* Configure simulation data (slot transmission) */
for (int i = 0; i < 2; i++)
{
MPXCANSlot[i].SlotNo = i;
MPXCANSlot[i].FrameType.Enabled = MPX_CAN_SLOT_ENABLE; /* Enable the 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 configuration */
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;

/* Configure slots (both channels) */
ret = MPXSetSlot(serial, 2, &MPXCANSlot[0], 2);
if (ret != E_OK)
{
printf("\n MPXSetSlot 2 : error[%d]\n", ret);
return -1;
}

/* Configure log acquisition mode (CH1) */
MPXSetGetLogMode(serial, 1, MPX_GETLOGMODE_GETLOGAPI);

/* Configure log acquisition mode (CH2) */
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 loop */
for (int i = 0; i < 10000; i++) {
/* usleep (commented out): software cannot strictly maintain the requested period
because scheduling may delay execution beyond the specified sleep time. */
// usleep(50)
/* Direct transmission */
StMPXCANDirect directFrame;
/* Configure transmission data (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;
/* Store the counter in the 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); // wait 100 ms

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

// Clear the display queue
if (!print_que.empty())
print_que.clear();

MPXClose();
return 0;
}

void DispMonitor(void)
{
/* Retrieve 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++)
{
// Skip empty logs
if (CANLog[i].Protocol == MPX_LOG_TYPE_EMPTY) {
continue;
}
/* Error check */
if (CANLog[i].Error == CAN_ERRFLG_FALSE)
{
/* Timestamp */
dispTmp << "time : " << std::dec << (int)CANLog[i].mSec << "[ms]," << (int)CANLog[i].uSec << "[us] ,";

/* ID format */
if (CANLog[i].IDE == MPX_CAN_IDE_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);

}