Main Content

Customize XCP Slave Software

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.

  • For some support packages.

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

External Mode 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.

StageFunctionPurpose

INITIALIZE

extmodeParseArgs

Extract external mode command-line arguments.

modelName_initialize

Initialize generated Simulink model code.

extmodeInit

Initialize external mode target connectivity.

HOST START REQUEST

extmodeWaitForHostRequest

Wait for a start request from development computer, which is created when you click Run button.

RUN

modelName_step

Run single step of generated Simulink model code.

extmodeEvent

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.

extmodeBackgroundRun

Transmit and receive packet from physical communication interface and process packet content in accordance with selected communication protocol.

HOST STOP REQUEST OR SIMULATION COMPLETE

extmodeStopRequested

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.

extmodeSimulationComplete

Check whether execution of generated model code is complete.
RESET

modelName_terminate

Terminate generated Simulink model code.

extmodeReset

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.

XCP Slave Protocol Layer

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
In an external mode simulation, the build process automatically adds the required files to the build information object.

XCP Slave Transport Layer

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
In an external mode simulation, the build process automatically adds the required files to the build information object.

XCP Platform Abstraction Layer

The XCP platform abstraction layer provides:

For a customization example, see Create Custom Abstraction Layer.

XCP Driver

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.

Memory Allocator

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_N_SIZE preprocessor macro.

  • The number of blocks in each set through the XCP_MEM_BLOCK_N_NUMBER preprocessor macro.

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_SIZE < XCP_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

Other Platform Abstraction Layer Functionality

This file defines the platform abstraction layer interface:

matlabroot\toolbox\coder\xcp\src\target\slave\platform\include\xcp_platform.h
To implement custom platform abstraction layer functionality, add the 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.

FunctionalityDetails

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 XCP_PRINTF preprocessor macro, the default implementation is empty.

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 addressExtension and address.

When addressExtension and address information is received by the target hardware, the XCP Slave must convert the address to the location of the variable in the target hardware memory. The variable location is assigned by the loader and is target-specific.

Use the XCP_ADDRESS_GET() macro to specify the conversion logic. The default implementation for Linux and Windows systems is:

#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
Currently, only 32-bit hardware architectures are supported, so 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 XCP_MEMCPY and XCP_MEMSET preprocessor macros, the default implementation specifies the standard C functions, memcpy and memset.

#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 EXTMODE_DISABLE_ARGS_PROCESSING.

To replace the -w option, you can use this command to specify that the target application enters and stays in a wait state until it receives a Connect message from Simulink:

set_param(modelName, 'OnTargetWaitForStart', 'on');
The build process provides the required option (-DON_TARGET_WAIT_FOR_START=1) to the compiler.

Create Custom Abstraction Layer

For the build process, you can define a post-code generation command that creates a custom platform abstraction layer.

  1. 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
    

  2. 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

See Also

| | | | | | | | |

Related Topics

External Websites