The ScratchPad

2016 August 10
Scratchpad

What is the ScratchPad?

The BrainStem scratchpad is a shared memory on a brainstem module which is accessible from both the host and Reflex code. It serves as a simple interprocess communication channel for separate Reflex routines, as well as a communication channel between the host and reflex code running on the BrainStem module.

The Scratchpad is accessed from the host and from the BrainStem module in two separate ways, this can be slightly more complex to work with at first, but leads to a couple of powerfull access patterns for reflex/host applications. The scratchpad is a volatile memory store, and is not preserved across a reboot or reset of the Brainstem module.

 

Reflexes and the ScratchPad

From the reflex side the scratchpad is accessed through a declaration style syntax. The scratchpad is a memory byte buffer, with no inherent structure. the Reflex pad access syntax allows the developer to overlay simple structures over the contents of the pad and access components as named characters, shorts and integers.  On most brainstem modules, the scratchpad is 300 bytes long.

The pad declaration syntax looks something like this;

pad[0:3] unsigned int timing;

This declaration reserves the first 4 bytes of the pad as an integer literal with the name timing. The figure below shows the relationship of the byte array nature of the scratchpad to the overlay of structure that the named pad variables provide. Be aware that pad declarations can overlap indices, which may cause issues if it is not an intended overlap.

 

 

The developer can then access this value as an integer in a reflex routine. For example;

timing = 500;

or

timeout_in_micro = timing * 1000; 
note: The BrainStem module stores values in little-endian format... if you read out multi-byte value as a series of bytes, keep this in mind.

 

The host and the Scratchpad

The host application interacts with the Scratchpad via a BrainStem entity called a Pointer.

What is a Pointer?

Pointers act like an open file handle into the BrainStem scratchpad. Each pointer starts out pointing at the beginning of the Scratchpad, index 0. The developer can set the pointer offset from the start of the pad, and control the mode of the pointer.

Initially all pointers are by default static. That means that reading or writing a character, short, or int from the pointer position will not result in changing the pointer position. The developer can change this behavior by setting the pointer mode to auto increment, after which a read or write to the pointer will cause the pointer position to advance by either 1, 2 or 4 bytes depending on whether the read/write was of a char, short, or int.

The developer has access of up to 4 pointers within the application, which all initially point to the starting location of the Scratchpad. Accessing data in the pad via a pointer in c++ looks like;

stem.pointer[2].getChar(&val);

Or

stem.pointer[0].setInt(304500);
Note: The pointer position and mode are stored on the BrainStem module in volatile memory. This is important to remember, as destroying and recreating a module object via the host API, will not change set positions and modes on the module. Also if the BrainStem module is reset during the execution of the application, these pointer positions and modes will be reset to initial values.
Tip: The reflex language can use pointers too, to access a Scratchpad on another module connected via the BrainStem network. Reflex pointer use looks similar to the C++ above

reflex mapEnable() {
	char charVar;
	
	netStem.pointer[2].getChar(charVar);
	netStem.pointer[0].setInt(3445);
	...

 

An Example, Setting a bank of digitals on the 40pin USBStem.

The following example shows a reflex file which sets up the BrainStem digital pins to be used in a bank with a set of pad values as state inputs. See the Working with Reflex files section of the brainstem reference for more information about loading and working with Reflex files.

Once the reflex is loaded onto the 40pin module and enabled. A python script can be used to change the state of the digital outputs. The python script is given below, followed by the Reflex code.

the Python script:

 

import brainstem
from time import sleep

# Create a brainstem module, 
# and connect to the first one found.
stem = brainstem.stem.USBStem()
stem.discoverAndConnect(brainstem.link.Spec.USB)

# The 40pin Stem has 15 Digitals, so a Short can be used 
# to set all 15 digitals.
for i in range(0, 10000):
	if (i % 2):
		stem.pointer[0].setShort(0x5555)
	else:
		stem.pointer[0].setShort(0xAAAA)
	sleep(0.1) # sleep for 100 milliseconds

The Reflex file:

#include <a40pinmodule.reflex>

// Create a reference to this module.
a40PinModule stem;

// 10 millisecond update delay.
#define DELAY 10000

// Create a shared memory location for,
// holding the digital state.
pad[0:0] unsigned char bank0;
pad[1:1] unsigned char bank1;

// mapEnable executes when the reflex is enabled.
// we set upd the counter, set the timer mode to
// repeat, and set the timer to expire after delay.

reflex mapEnable() {
    bank0 = 0;
    bank1 = 0;
    stem.digital[0].setConfiguration(digitalConfigurationOutput);
    stem.digital[1].setConfiguration(digitalConfigurationOutput);
    stem.digital[2].setConfiguration(digitalConfigurationOutput);
    stem.digital[3].setConfiguration(digitalConfigurationOutput);
    stem.digital[4].setConfiguration(digitalConfigurationOutput);
    stem.digital[5].setConfiguration(digitalConfigurationOutput);
    stem.digital[6].setConfiguration(digitalConfigurationOutput);
    stem.digital[7].setConfiguration(digitalConfigurationOutput);
    stem.digital[8].setConfiguration(digitalConfigurationOutput);
    stem.digital[9].setConfiguration(digitalConfigurationOutput);
    stem.digital[10].setConfiguration(digitalConfigurationOutput);
    stem.digital[11].setConfiguration(digitalConfigurationOutput);
    stem.digital[12].setConfiguration(digitalConfigurationOutput);
    stem.digital[13].setConfiguration(digitalConfigurationOutput);
    stem.digital[14].setConfiguration(digitalConfigurationOutput);
    // Prime the timer to expire in 50 ms. 
    stem.timer[0].setExpiration(DELAY);
}

reflex timer[0].expiration(char val) {
   
    if (bank0 & 0x01) {
        stem.digital[0].setState(1);
    } else {
        stem.digital[0].setState(0);
    }
    
    if (bank0 & 0x02) {
        stem.digital[1].setState(1);
    } else {
        stem.digital[1].setState(0);
    }
    
    if (bank0 & 0x04) {
        stem.digital[2].setState(1);
    } else {
        stem.digital[2].setState(0);
    }
    
    if (bank0 & 0x08) {
        stem.digital[3].setState(1);
    } else {
        stem.digital[3].setState(0);
    }

    if (bank0 & 0x10) {
    stem.digital[4].setState(1);
    } else {
     stem.digital[4].setState(0);
    }

    if (bank0 & 0x20) {
    stem.digital[5].setState(1);
    } else {
     stem.digital[5].setState(0);
    }

    if (bank0 & 0x40) {
    stem.digital[6].setState(1);
    } else {
     stem.digital[6].setState(0);
    }

    if (bank0 & 0x80) {
    stem.digital[7].setState(1);
    } else {
     stem.digital[7].setState(0);
    }

    if (bank1 & 0x01) {
    stem.digital[8].setState(1);
    } else {
     stem.digital[8].setState(0);
    }

    if (bank1 & 0x02) {
    stem.digital[9].setState(1);
    } else {
     stem.digital[9].setState(0);
    }

    if (bank1 & 0x04) {
    stem.digital[10].setState(1);
    } else {
     stem.digital[10].setState(0);
    }

    if (bank1 & 0x08) {
    stem.digital[11].setState(1);
    } else {
     stem.digital[11].setState(0);
    }

    if (bank1 & 0x10) {
    stem.digital[12].setState(1);
    } else {
     stem.digital[12].setState(0);
    }

    if (bank1 & 0x20) {
    stem.digital[13].setState(1);
    } else {
     stem.digital[13].setState(0);
    }

    if (bank1 & 0x40) {
    stem.digital[14].setState(1);
    } else {
     stem.digital[14].setState(0);
    }

    stem.timer[0].setExpiration(DELAY);
}

reflex mapDisable() {
    stem.timer[0].setExpiration(0);
    stem.digital[0].setState(0);
    stem.digital[1].setState(0);
    stem.digital[2].setState(0);
    stem.digital[3].setState(0);
    stem.digital[4].setState(0);
    stem.digital[5].setState(0);
    stem.digital[6].setState(0);
    stem.digital[7].setState(0);
    stem.digital[8].setState(0);
    stem.digital[9].setState(0);
    stem.digital[10].setState(0);
    stem.digital[11].setState(0);
    stem.digital[12].setState(0);
    stem.digital[13].setState(0);
    stem.digital[14].setState(0);
}