The XCP communication protocol for Simulink® external mode simulations is a master-slave communication protocol. By default, the software supports XCP external mode simulations:
On your development computer for code that is generated by using ERT
(ert.tlc
) and GRT (grt.tlc
) system target
files.
If your system target file for custom target hardware is derived from the ERT or GRT system target files, you can use supplied APIs to provide XCP target connectivity. XCP external mode limitations apply.
The external mode target connectivity software comprises:
External mode abstraction layer
XCP slave protocol layer
XCP slave transport layer
XCP platform abstraction layer
To communicate with Simulink during an external mode simulation, your target application must invoke functions from the external mode abstraction layer.
The parent folder for source code files is:
matlabroot\toolbox\coder\xcp\src\target\ext_mode
The layer APIs are declared in include\ext_mode.h
and implemented in
src\xcp_ext_mode.c
.
To communicate with Simulink, the target application uses services exposed by the external mode abstraction layer. This flow chart shows the required target application steps to establish communication with Simulink.
This tables lists the functions that your target application must invoke at each stage.
Stage | Function | Purpose |
---|---|---|
| Extract external mode command-line arguments. | |
| Initialize generated Simulink model code. | |
Initialize external mode target connectivity. | ||
| Wait for a start request from development computer, which is created when you click Run button. | |
|
| Run single step of generated Simulink model code. |
For sample time ID of the model, sample signals generated by model step function and pass packet content to transport layer of communication protocol for transmission to development computer. | ||
Transmit and receive packet from physical communication interface and process packet content in accordance with selected communication protocol. | ||
HOST STOP REQUEST OR SIMULATION
COMPLETE | Check whether a request to stop external mode simulation is received from the model on the development computer. The request is created when you click the Stop button. | |
Check whether execution of generated model code is complete. | ||
RESET |
| Terminate generated Simulink model code. |
Reset the external mode target connectivity to initial state. |
This pseudo-code example shows how you can implement the various flowchart stages in
your target application. During the RUN
stage, the external mode run-time
environment requires at least two threads:
A periodic thread that is responsible for the execution of the generated model code.
A background thread that is responsible for running the external mode communication stack and transmitting and receiving packets.
The pseudo-code simulates multithreading by running
periodicThread
and extmodeBackgroundRun
sequentially
within the same while()
loop.
/*------------- Pseudo-Code Example -------------*/ /* Define periodic thread */ void periodicThread(void) { /* Run model step function */ modelName_step(); /* Notify external mode abstraction layer about periodic event */ extmodeEvent(PERIODIC_EVENT_ID, currentSimulationTime); } /* Main function for target application */ main(int argc, char *argv[]) { /*------------- INITIALIZE -------------*/ /* Parse external mode command line arguments */ extmodeParseArgs(argc, argv); /* Initialize model */ modelName_initialize(); /* Initialize external mode target connectivity */ extmodeInit(extModeInfo, finalSimulationTime); /*------------- HOST START REQUEST -------------*/ /* Wait until a start request is received from development computer */ extmodeWaitForHostRequest(EXTMODE_WAIT_FOREVER); /*------- HOST STOP REQUEST OR SIMULATION COMPLETE -------*/ /* While simulation is not complete and stop request is not received */ while (!extmodeSimulationComplete() && !extmodeStopRequested()) { /*------------- RUN -------------*/ periodicThread(); extmodeBackgroundRun(); } /*------------- RESET -------------*/ /* Terminate model */ modelName_terminate(); /* Reset external mode target connectivity */ extmodeReset(); return 0; }
To see code that invokes the functions, complete the example in External Mode Simulation by Using XCP Communication with System target
file set to ert.tlc
. Then, from the code generation
folder, open ert_main.c
.
The XCP slave protocol layer interprets XCP commands and data according to the Association for Standardisation of Automation and Measuring Systems (ASAM) standard, ASAM MCD-1 XCP.
The source code folder is:
matlabroot\toolbox\coder\xcp\src\target\slave\protocol\src
The XCP slave transport layer transmits and receives messages from the communication medium according to ASAM specifications.
The source folder is:
matlabroot\toolbox\coder\xcp\src\target\slave\transport\src
The XCP platform abstraction layer provides:
An XCP driver for sending and receiving raw data through the physical communication interface.
The implementation of a static memory allocator.
For a customization example, see Create Custom Abstraction Layer.
The XCP driver sends and receives XCP messages through the communication channel. In an external mode simulation, the build process automatically adds the driver files to the build information object.
The XCP driver is based on the rtiostream
API. For example,
host-based external mode simulations use these rtiostream
files:
matlabroot
\toolbox\coder\rtiostream\src\rtiostreamtcpip.c
matlabroot
\toolbox\coder\rtiostream\src\rtiostream_serial.c
For details on implementing and testing an rtiostream
communications channel, see:
For a custom platform abstraction layer, you must add your
rtiostream
files to the build
information object. For an example, see Create Custom Abstraction Layer.
The XCP slave software requires the dynamic allocation of variable-size, contiguous memory blocks to hold internal data structures.
In an external mode simulation, the build process automatically adds memory allocator files to the build information object.
The xcpMemBlockSizes
and xcpMemBlockCounts
preprocessor macros define memory allocation.
The default memory allocator can allocate and deallocate up to 16 different sets of memory blocks. For each set, you can override the default allocations during compilation. You can specify:
The block size through the
XCP_MEM_BLOCK_
preprocessor
macro.N
_SIZE
The number of blocks in each set through the
XCP_MEM_BLOCK_
preprocessor macro.N
_NUMBER
For example, these preprocessor macros create four blocks of 64 bytes and eight blocks of 256 bytes.
#define XCP_MEM_BLOCK_1_SIZE 64 #define XCP_MEM_BLOCK_1_NUMBER 4 #define XCP_MEM_BLOCK_2_SIZE 256 #define XCP_MEM_BLOCK_2_NUMBER 8
Configure the block sizes of the different sets in ascending order:
XCP_MEM_BLOCK_
<
N
_SIZEXCP_MEM_BLOCK_
N
+1_SIZE
The smallest block size, XCP_MEM_BLOCK_1_SIZE
, must be large enough
to hold a pointer.
Configure alignment for the memory allocator through the
XCP_MEM_ALIGNMENT
preprocessor macro. For
example:
#define XCP_MEM_ALIGNMENT 8
This file defines the platform abstraction layer interface:
matlabroot\toolbox\coder\xcp\src\target\slave\platform\include\xcp_platform.h
XCP_CUSTOM_PLATFORM
preprocessor macro to the build information
object. Provide the implementation of the custom functionality in a file named
xcp_platform_custom.h
. If you do not define
XCP_CUSTOM_PLATFORM
, the build process uses default files that
support Linux® and Windows® systems.This table describes the functionality that you must provide for the XCP slave software that you deploy on your target hardware.
Functionality | Details |
---|---|
Mutual exclusion | To access system data structures with mutual exclusion support, the XCP driver depends on basic APIs for definition, initialization, lock, and unlock. To support mutual exclusion for your target hardware, provide a custom implementation. The default implementation for Linux and Windows supports mutual exclusion. #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) ... #define XCP_MUTEX_DEFINE(lock) HANDLE lock #define XCP_MUTEX_INIT(lock) lock = CreateMutex(0, FALSE, 0) #define XCP_MUTEX_LOCK(lock) WaitForSingleObject((lock), INFINITE) #define XCP_MUTEX_UNLOCK(lock) ReleaseMutex(lock) #else ... #include <pthread.h> #define XCP_MUTEX_DEFINE(lock) pthread_mutex_t lock #define XCP_MUTEX_INIT(lock) pthread_mutex_init(&(lock), NULL) #define XCP_MUTEX_LOCK(lock) pthread_mutex_lock(&(lock)) #define XCP_MUTEX_UNLOCK(lock) pthread_mutex_unlock(&(lock)) ... #endif |
Sleep | Provide a sleep API that makes the calling thread sleep until a specified time has elapsed. The default implementation for Linux and Windows systems is: #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) ... #define XCP_SLEEP(seconds,microseconds) Sleep((seconds) * 1000 \ + (((microseconds) + 1000 - 1) / 1000)) #else ... #if _POSIX_C_SOURCE >= 199309L #define XCP_SLEEP(seconds,microseconds) do {struct timespec t;\ t.tv_sec = seconds; t.tv_nsec = microseconds * 1000; nanosleep(&t, NULL);} while(0) #else /* nanosleep is not available. Use select instead. */ #define XCP_SLEEP(seconds,microseconds) do {struct timeval t; t.tv_sec = seconds;\ t.tv_usec = microseconds; select(0, NULL, NULL, NULL, &t);} while(0) #endif /* _POSIX_C_SOURCE >= 199309L */ ... #endif |
Logging | To generate diagnostic messages, the XCP slave software requires a
custom print API that supports logging services provided by the target
hardware. If you do not define the |
Address conversion | The XCP standard expresses the address of a variable in memory as a 32-bit address with an 8-bit extension. The XCP Master extracts the addresses of signals and parameters of the model by parsing the debug information that the build process creates. The debug information is in DWARF or PDB format. The XCP Master requests access to parameters and
signals by sending an XCP command that contains the arguments
When Use the #if defined(__MINGW32__) || defined(__MINGW64__) #define XCP_ADDRESS_GET(addressExtension, address) \ (uint8_T*) ((uintptr_t) address) #else #define XCP_ADDRESS_GET(addressExtension, address) \ (uint8_T*) ((address) + (uint8_T*)&__ImageBase) #endif addressExtension is 0. |
Set and copy memory | You can specify an optimized version of copy memory and set memory operations. If you do not define the #ifndef XCP_MEMCPY #define XCP_MEMCPY memcpy #endif #ifndef XCP_MEMSET #define XCP_MEMSET memset #endif |
Parsing command-line arguments | If your target hardware does not support the parsing of command-line
arguments, define the preprocessor macro
To replace
the set_param(modelName, 'OnTargetWaitForStart', 'on'); -DON_TARGET_WAIT_FOR_START=1 ) to the
compiler. |
For the build process, you can define a post-code generation command that creates a custom platform abstraction layer.
Specify the header file xcp_platform_custom.h
. This
Linux example defines the required
functions.
#ifndef XCP_PLATFORM_CUSTOM_H #define XCP_PLATFORM_CUSTOM_H /* XCP_ADDRESS_GET */ #include <stdint.h> #define XCP_ADDRESS_GET(addressExtension, address) (uint8_T*) ((uintptr_t) address) /* XCP_MUTEX */ #include <pthread.h> #define XCP_MUTEX_DEFINE(lock) pthread_mutex_t lock #define XCP_MUTEX_INIT(lock) pthread_mutex_init(&(lock), NULL) #define XCP_MUTEX_LOCK(lock) pthread_mutex_lock(&(lock)) #define XCP_MUTEX_UNLOCK(lock) pthread_mutex_unlock(&(lock)) /* XCP_SLEEP */ #include <sys/time.h> /* gettimeofday */ #if _POSIX_C_SOURCE >= 199309L #include <time.h> /* for nanosleep */ #else #include <stddef.h> #include <sys/select.h> /* for select */ #endif /* _POSIX_C_SOURCE >= 199309L */ #if _POSIX_C_SOURCE >= 199309L #define XCP_SLEEP(seconds,microseconds) do {struct timespec t;\ t.tv_sec = seconds; t.tv_nsec = microseconds * 1000; nanosleep(&t, NULL);} while(0) #else /* nanosleep is not available. Use select instead. */ #define XCP_SLEEP(seconds,microseconds) do {struct timeval t; t.tv_sec = seconds;\ t.tv_usec = microseconds; select(0, NULL, NULL, NULL, &t);} while(0) #endif /* _POSIX_C_SOURCE >= 199309L */ #endif
Define the post-code generation command.
function myXCPTargetPostCodeGenCommand(buildInfo) buildInfo.addDefines('-DXCP_CUSTOM_PLATFORM', 'OPTS'); % Configure the default memory allocator buildInfo.addDefines('-DXCP_MEM_BLOCK_1_SIZE=64', 'OPTS'); buildInfo.addDefines('-DXCP_MEM_BLOCK_1_NUMBER=46', 'OPTS'); buildInfo.addDefines('-DXCP_MEM_BLOCK_2_SIZE=256', 'OPTS'); buildInfo.addDefines('-DXCP_MEM_BLOCK_2_NUMBER=10', 'OPTS'); % Add my rtiostream buildInfo.addSourceFiles(customRtIOStreamFileName, ... customRtIOStreamSrcPath); % If the target hardware does not support parsing of command % line arguments buildInfo.addDefines('-DEXTMODE_DISABLE_ARGS_PROCESSING', 'OPTS'); end
extmodeBackgroundRun
| extmodeEvent
| extmodeGetFinalSimulationTime
| extmodeInit
| extmodeParseArgs
| extmodeReset
| extmodeSetFinalSimulationTime
| extmodeSimulationComplete
| extmodeStopRequested
| extmodeWaitForHostRequest