BOS offers a powerful remote memory read/write access functionality through specific Messages and APIs. This allows a module to access and modify almost any RAM or Flash memory location in another module in the array. Thus, providing powerful synchronization and granular control.
Typically, you will need a valid memory address to read a variable stored in RAM (e.g., 0x20000100) or Flash (e.g., 0x08000100). In order to simplify the process, BOS defines a set of RAM-based BOS Variables that you can use to easily exchange small amount of data across the array. BOS Variables can be addressed with easy-to-use virtual addresses (1 to N) without the need to know their actual RAM location. For example, you can link a float (or any other datatype) value to BOS Var 1 and access it from any other module in the array. There is a maximum number of bytes that each module reserve for BOS variables. It is defined in MAX_BOS_VARS preprocessor constant. If MAX_BOS_VARS=100, then you can define 100 1-byte variables, or 25 1-word variables and so forth.
The following examples demonstrate how to define BOS variables. Using the keyword volatile in front of a variable definition tells the compiler that this variable might change outside the program (e.g., by a remote module):
// Define local variables: LED state (ON/OFF), intensity and color (global or static if inside a function) volatile bool state = true; volatile uint8_t intensity = 50, color = WHITE; // Link to BOS variables (inside a function) AddBOSvar(FMT_BOOL, (uint32_t) &state); AddBOSvar(FMT_UINT8, (uint32_t) &intensity); AddBOSvar(FMT_UINT8, (uint32_t) &color);
The API AddBOSvar() accepts the following data types:
FMT_UINT8 FMT_INT8 FMT_UINT16 FMT_INT16 FMT_UINT32 FMT_INT32 FMT_FLOAT FMT_BOOL
and returns the BOS variable index (or virtual address) or 0 if memory is full.
Note 1: BOS variables must be defined as global (e.g., outside a function) or static to ensure we are not referencing a temporary variable within a function stack.
Note 2: When using direct Flash and RAM addresses, pay special attention to memory alignment. Cortex-M0 MCUs do not accept non-word aligned memory access, which results in a processor Hardfault.
Use the ReadRemoteVar() and ReadRemoteMemory() APIs to read a remote module BOS variable or memory location. The first one returns a pointer to the remote value as well as a pointer to the remote BOS variable format. The second API only returns a pointer to the remote value. The remote format here should be specified by the local module, since a memory location can contain any datatype. Note that the returned pointers must be cast to the correct datatype before their addressed value can be read correctly. The following examples demonstrate the proper use of these APIs:
volatile float myremotevar = 0; // Reading remote address 0x2000001c from Module 2 with FLOAT format and 1000ms timeout myremotevar = *(float *)ReadRemoteMemory(2, 0x2000001c, FMT_FLOAT, 1000); volatile bool mybool; varFormat_t format1; /* Reading remote BOS variable 1 from Module 2 with 100ms timeout. Remote format is requested and stored in format1. It can be used to cast the variable properly in case we don't know the format beforehand */ mybool = *(bool *)ReadRemoteVar(2, 1, &format1, 100);
Both read APIs will be blocked until the read value is returned, or the timeout is reached (in which case a NULL pointer is returned). If the requested remote BOS variable does not exist, the APIs return BOS_ERR_REMOTE_READ_NO_VAR.
The WriteRemote() API is used to write to a remote memory location or a BOS variable. Setting up the remoteAddress parameter to any value between 1 and MAX_BOS_VARS writes to a BOS variable, while setting it up to a valid RAM or Flash location writes to this memory location. If the BOS variable does not exist, a new one will be created in the remote module. Remote format is always specified by the local module. The following examples demonstrate the API usage:
volatile bool mybool = true; /* Writing the value of mybool to remote BOS variable 1 in Module 2 with a BOOL format and 0 timeout, i.e., skipping confirmation */ WriteRemote(2, (uint32_t) &mybool, 1, FMT_BOOL, 0); volatile uint32_t mynum = 0x12ABCDEF; /* Writing the value of mynum to remote address 0x08016000 in Module 2 with UINT32 format and 100 timeout */ WriteRemote(2, (uint32_t) &mynum, 0x08016000, FMT_UINT32, 100);
A remote write with non-zero timeout will be blocked until a confirmation message is received, or a timeout is reached. A zero timeout disables sending a confirmation. The confirmation Message returns success (BOS_OK=0) or the following error codes:
- BOS_ERR_REMOTE_WRITE_TIMEOUT: Remote module did not respond.
- BOS_ERR_REMOTE_WRITE_MEM_FULL: No memory to create a new BOS variable.
- BOS_ERR_REMOTE_WRITE_INDEX: BOS variable index (address) is out of range.
- BOS_ERR_LOCAL_FORMAT_UPDATED: Remote BOS variable format does not match the requested one and hence was updated to match the request.
- BOS_ERR_REMOTE_WRITE_ADDRESS: Remote address is not a valid Flash or RAM location.
- BOS_ERR_REMOTE_WRITE_FLASH: Writing to a remote Flash location failed because the Flash page has not been erased.
Note: In order to write to an MCU Flash address, the address must contain 0xFFFFFFFF or the entire page (1024 bytes) must be erased beforehand. If you are aware of the consequences of this and still want to force erasing the page if needed, use the WriteRemoteForce() API.