Skip to content

Intercore Messaging

Dave Glover edited this page Sep 15, 2021 · 3 revisions

Intercore Messaging

Examples

The following code example includes a high-level application that communicates with two real-time applications. The high-level application demonstrates both the asynchronous and synchronous message patterns with the real-time core applications.

Code example, inter-core messaging


Functions

bool dx_intercoreConnect(DX_INTERCORE_BINDING *intercore_binding);
bool dx_intercorePublish(DX_INTERCORE_BINDING* intercore_binding, void* control_block, size_t message_length);
bool dx_intercorePublishThenReadTimeout(DX_INTERCORE_BINDING *intercore_binding, suseconds_t timeoutInMicroseconds);
ssize_t dx_intercorePublishThenRead(DX_INTERCORE_BINDING *intercore_binding, void *control_block, size_t message_length);

Structures

GPIO context structure.

typedef struct {
    char* rtAppComponentId;
    int sockFd;
    bool initialized;
    bool nonblocking_io;
    void (*interCoreCallback)(void*, ssize_t message_size);
    void* intercore_recv_block;
    size_t intercore_recv_block_length;
} DX_INTERCORE_BINDING;

Asynchronous and Synchronous inter-core communications

The AzureSphereDevX library supports two inter-core communications patterns.

  1. Asynchronous Pattern: Declare an DX_INTERCORE_BINDING and specify a interCoreCallback function handler. The inter-core callback handler will be called when a message is received from a real-time core.
  2. Synchronous Pattern: Declare an DX_INTERCORE_BINDING and specify a interCoreCallback NULL handler. This supports the PublishThenRead Inter-core high-level API. The high-level application publishes a message to a real-time core, and then sits on a read until the the real-time core responses, or the read times out.

Which inter-core messaging pattern should you use?

  • Use the asynchronous messaging pattern when the response from the real-time core is not critical to the flow of your application. This is the preferred event driven pattern for high-level applications. For example, the real-time core updates high-level application with the current temperature.
  • Use the synchronous pattern for request/response style messaging when the flow of your high-level application is dependent on the response from the real-core. The synchronous pattern can help simplify your application logic. The high-level application will block waiting for a message from the real-time core or until the request times out. For this pattern, the typical response time from your real-core application should be measured in hundreds of microseconds.

Intercore example

Declare intercore message structure.

INTER_CORE_BLOCK ic_block_asynchronous = {.cmd = IC_UNKNOWN, .msgId = 0, .message = {0}};
INTER_CORE_BLOCK ic_block_synchronous = {.cmd = IC_UNKNOWN, .msgId = 0, .message = {0}};

Declare an asynchronous intercore binding

DX_INTERCORE_BINDING intercore_app_asynchronous = {
                            .nonblocking_io = true,
                            .rtAppComponentId = REAL_TIME_COMPONENT_ID_ASYNCHRONOUS,
                            .interCoreCallback = IntercoreResponseHandler,
                            .intercore_recv_block = &ic_block_asynchronous,
                            .intercore_recv_block_length = sizeof(ic_block_asynchronous)};

Declare intercore callback.

/// <summary>
/// Callback handler for Asynchronous Inter-Core Messaging Pattern
/// </summary>
static void IntercoreResponseHandler(void *data_block, ssize_t message_length)
{
    INTER_CORE_BLOCK *ic_message_block = (INTER_CORE_BLOCK *)data_block;

    switch (ic_message_block->cmd) {
    case IC_ECHO:
        Log_Debug("Echoed message number %d from realtime core id: %s\n", ic_message_block->msgId, ic_message_block->message);
        break;
    default:
        break;
    }
}

Declare a synchronous intercore binding

Note, for a synchronous intercore binding, the interCoreCallback function must be NULL.

DX_INTERCORE_BINDING intercore_app_synchronous = {
                            .nonblocking_io = true,
                            .rtAppComponentId = REAL_TIME_COMPONENT_ID_SYNCHRONOUS,
                            .interCoreCallback = NULL,
                            .intercore_recv_block = &ic_block_synchronous,
                            .intercore_recv_block_length = sizeof(ic_block_synchronous)};

Initializing inter-core bindings

Initialize an inter-core binding in the InitPeripheralAndHandlers function by calling the dx_intercoreConnect function.

// Initialize asynchronous inter-core messaging
dx_intercoreConnect(&intercore_app_asynchronous);

For the synchronous messaging pattern, you should set a Read request timeout.

// Initialize synchronous inter-core messaging
dx_intercoreConnect(&intercore_app_synchronous);
// set intercore read timeout to 1000 microseconds
dx_intercorePublishThenReadTimeout(&intercore_app_synchronous, 1000);
Clone this wiki locally