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).
| Section | Item | Setting |
|---|---|---|
| Arbitration field | Baud rate | 500 kbps |
| Sample point | 80% | |
| Payload field | Baud rate | 2 Mbps |
| Sample point | 80% |
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()
- Opening and Initializing the Device
MPXOpen()searches for MicroPeckerX devices and retrieves their serial numbers.- Initializes the device (
MPXSampleInit) and starts monitoring (MPXMonitorStart) forserial.
- 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.DispMonitorand outputs the returned frames.
- Runs
- Generating and Sending CAN Data
- Prepares a 12-byte array (
senddata). - Sends a CAN frame 10,000 times with
MPXDirectSend.- Third argument
iis the CAN ID (incremented each time). - Fourth argument
8is the data length (8 bytes). - Fifth argument
senddatais the payload.
- Third argument
- The first payload byte is incremented for each transmission, and the CAN ID changes on every loop iteration.
- Prepares a 12-byte array (
- Shutdown
- Sets
stop_threads = Trueto terminate the receive thread after transmission. - Stops monitoring and closes the device.
- Sets
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, ¶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;
}
/* 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);
}