Skip to content

TotemModule

Module instance object, providing to send and receive data from module.

Functions list

Result Function Description
TotemModule(number) Create module with number
TotemModule(number, DataReceiver) Create module with number and data receiver
TotemModule(number, serial) Create module with number and serial
TotemModule(number, serial, DataReceiver) Create module with number, serial and data receiver
bool write(command) Send command to module
bool write(command, int) Send command with integer value
bool write(command, string) Send command with string value
bool write(command, array, length) Send command with data
bool write(command, int, int, int, int) Send command with multiple values
bool read(command) Non-blocking read from module
ModuleData readWait(command) Blocking inline read from module
bool readWait(command, ModuleData) Blocking read from module
bool subscribe(command, interval) Subscribe command read
bool unsubscribe(command) Unsubscribe command read
bool attachOnData(DataReceiver) Register data receive function
none setNumber(number) Change number of TotemModule object
none setSerial(serial) Change serial of TotemModule object
int getNumber() Read number of TotemModule object
int getSerial() Read serial of TotemModule object
none ping() Send ping request to module
int hashCmd(command) Encode command to integer
int hashModel(model) Encode robot model (type) to integer

Example

// Define use of Distance sensor [11]
// This can be any module connected to RoboBoard X4 board
TotemModule module(11);
// Arduino setup
void setup() {
  Serial.begin(115200);
  // Initialize RoboBoard X4
  Totem.X4.begin();
}
// Arduino loop
void loop() {
  // Blink on-board led
  module.write("indicate");
  delay(500); // Wait 500ms
  // Read distance
  Serial.println(module.readWait("distance").getInt());
  delay(500); // Wait 500ms
}

API

Constructor

TotemModule object allows to exchange commands with attached module. A number of module and serial (optional) should be passed to specify which module on the network should respond to it. Module number is printed in a white rectangle. Serial number has to be acquired programmatically.
If number 0 is passed - object will communicate with all modules connected to TotemBUS.

TotemModule(number)

Create object by specifying module number.
Parameter:
number - module number [0:255]. 0 - all modules.
TotemModule module(04); // Create object for module 04

TotemModule(number, DataReceiver)

Create object by specifying number and data receiver function.
DataReceiver is a user defined function to get all incoming data from the module.
Format: void onModuleData(ModuleData data). Received data is stored in ModuleData parameter. Also can be registered with function attachOnData().
Parameter:
number - module number [0:255]. 0 - all modules.
DataReceiver - data receiver function name onModuleData.
// Function (DataReceiver) to receive data events from registered module
void onModuleData(ModuleData data) {
  // Received data from module 04
}
// Create object for module 04 and register data receiver
TotemModule module(04, onModuleData);
// Same functionality (adding data receiver) can be achieved with:
void setup() {
  module.attachOnData(onModuleData);
}

TotemModule(number, serial)

Create object by specifying number and serial.
Serial is required when there is two or more modules with the same number.
Parameter:
number - module number [0:255]. 0 - all modules.
serial - module serial [0:32767]. 0 - ignore serial.
// Create object for module 04 with serial number 25485.
// This will send commands only to module with matching serial.
TotemModule module(04, 25485);

TotemModule(number, serial, DataReceiver)

Create object by specifying number, serial and data receiver function.
Parameter:
number - module number [0:255]. 0 - all modules.
serial - module serial [0:32767]. 0 - ignore serial.
DataReceiver - data receiver function name onModuleData.
void onModuleData(ModuleData data) {
  // Received command result from module 04 with serial number 25485
}
// Create object for module 04 with serial 25485 and register data receiver
TotemModule module(04, 25485, onModuleData);

Functions

Calling writeWait(...) will block code execution until response from module received or timeouts. Will return true only if module successfully executed write command request. Used when confirmation of value update is required.
Calling simple write(...) only sends command to network without acknowledgment.
For more information read Wait functions.

write(command)

Call command.
Parameter:
command - module command string or hash.
Returns: command is sent [true:false].
module.write("indicate"); // Blink LED on module

write(command, int)

Write integer to command.
Parameter:
command - module command string or hash.
int - 32bit value [-2147483648:2147483647] or [0:4294967295].
Returns: command is sent [true:false].
module.write("motorA", 50); // Set motor channel A power to 50%

write(command, string)

Write string to command.
Parameter:
command - module command string or hash.
string - any string array.
Returns: command is sent [true:false].
module.write("cfg/robot/name", "My robot"); // Set robot name to "My robot"

write(command, array, length)

Write fixed length array to command.
Parameter:
command - module command string or hash.
array - 8bit data array.
length - size of array.
Returns: command is sent [true:false].
char data[] = {'N', 'a', 'm', 'e'};
module.write("cfg/robot/name", data, sizeof(data)); // Set robot name from data array

write(command, int, int, int, int)

Write four 8bit values to command. These values are merged into one 32bit value and forwarded to write(command, int). Also accepts 3 int parameters.
Parameter:
command - module command string or hash.
int - 8bit value 1.
int - 8bit value 2.
int - 8bit value 3.
int - 8bit value 4.
Returns: command is sent [true:false].
module.write("motorABCD", 50, 0, -60, 20); // Write all 4 motor channels at once
module.write("servoABC", -100, 0, 100); // Write all 3 servo motor channels at once
module.write("rgbA", 255, 0, 255, 0); // Set rgbA led to GREEN color with max brightness
// module.write("rgbA", 0xFF00FF00); // Equivalent to previous command

read(command)

Read command from module. This function sends a read request. It will not block program execution and result of the read will be returned in the function attached with attachOnData().
Parameter:
command - module command string or hash.
Returns: command is sent [true:false].
void onModuleData(ModuleData data) {
  // Check if received data is from 'cfg/robot/name' command
  if (data.is("cfg/robot/name")) {
    Serial.println(data.getString()); // Print name
  }
}
void setup() {
  // Register onModuleData as data receive function
  module.attachOnData(onModuleData);
  // Send read request for 'cfg/robot/name'
  module.read("cfg/robot/name");
}

readWait(command)

Read command from module. This function sends a read request and waits for the result. It will block program execution until result is received or timeouts (100 milliseconds).
This function returns ModuleData to make inline read request.
If read is failed, values will be set to NULL and 0.
Parameter:
command - module command string or hash.
Returns: ModuleData.
// Print robot name
const char *name = module.readWait("cfg/robot/name").getString();
Serial.print("Robot cfg/robot/name: ");
Serial.println(name);
// Get battery voltage
int voltage = module.readWait("battery").getInt();
Serial.print("Robot battery: ");
Serial.println(voltage);

readWait(command, ModuleData)

Read command from module. This function sends a read request and waits for the result. It will block program execution until result is received or timeouts (100 milliseconds).
If returned true - read operation was successful and ModuleData contains received data.
Parameter:
command - module command string or hash.
ModuleData - received data.
Returns: is requested data received [true:false].
// Prepare ModuleData variable
ModuleData data;
// Start read robot name. Will block until result is returned
if (module.readWait("cfg/robot/name", data)) {
  // Print received name
  Serial.print("Received cfg/robot/name: ");
  Serial.println(data.getString());
}
else { // Reading failed. No result returned
  Serial.println("Read cfg/robot/name failed");
}

subscribe(command, interval)

Subscribe to periodical data receive. Result will be returned in DataReceiver function registered with attachOnData().
If no interval provided - event will be sent only when value is changed (eg. button press). Parameter:
command - module command string or hash.
interval - interval in milliseconds. 0 - value change event.
Returns: request is sent [true:false].
void onModuleData(ModuleData data) {
  // Receiving "battery" value
  if (data.is("battery")) {
    Serial.print("Battery level: ");
    Serial.println(data.getInt());
  }
}
void setup() {
  // Register onModuleData as data receive function
  module.attachOnData(onModuleData);
  // Request to receive "battery" on value change
  module.subscribe("battery");
  // Request to receive "battery" command every 1 second
  module.subscribe("battery", 1000);
}

unsubscribe(command)

Unsubscribe from receiving command data.
Parameter:
command - module command string or hash.
Returns: request is sent [true:false].
module.subscribe("battery"); // Request to receive "battery" on value change
module.unsubscribe("battery"); // Stop receiving "battery" on value change

attachOnData(DataReceiver)

Register module data receiver function.
DataReceiver is a user defined function to get all incoming data from the module.
Format: void onModuleData(ModuleData data). Received data is stored in ModuleData parameter.
Note: A command has to be subscribed or read to appear in receiver function.
Parameter:
DataReceiver - data receiver function name onModuleData.
void onModuleData(ModuleData data) {
  // Receiving all data from 'module'
  if (data.is("command")) { /* received "command" */ }
}
void setup() {
  module.attachOnData(onModuleData); // Register data receiver for module
}

setNumber(number)

setSerial(serial)

Change number or serial of defined module.
Parameter:
number - module number [0:255]. 0 - all modules.
serial - module serial [0:32767]. 0 - ignore serial.
TotemModule module(0); // All modules
module.setNumber(04); // Reconfigure to 04 modules only.
module.setSerial(5468); // Reconfigure to module with 5468 serial only.

getNumber()

getSerial()

Get number or serial of defined module.
Returns:
number - module number [0:255].
serial - module serial [0:32767].
TotemModule module(11, 2657); // Distance sensor
int number = module.getNumber(); // Get module number "11"
int serial = module.getSerial(); // Get module serial "2657"

ping()

Sends a request for module to respond. If TotemModule object is initialized with number 0, all modules will receive ping request.
Response will be received in function registered with attachOnModuleConnected().
This can be used to discover modules connected to TotemBUS system or check if they are still connected.
Returns: request is sent [true:false].
TotemModule module(0); // All modules
module.ping(); // Request module to respond

hashCmd(command)

Encode string command to 32bit integer value.
This is done internally when calling any write() function, providing a string command.
Note: This command is static, so requires to be called trough a class name.
Parameter:
command - module command string.
Returns: unsigned 32bit hash [0:0xFFFFFFFF]
// Convert command "indicate" to hash
int commandHash = TotemModule::hashCmd("indicate");
// Call write command with encoded hash
module.write(commandHash);

hashModel(model)

Encode Totem robot model name to 16bit integer value.
Used with cfg/robot/model and getModel().
Note: This command is static, so requires to be called trough a class name.
Parameter:
command - model name string.
Returns: unsigned 16bit hash [0:0xFFFF]
// Convert model name "MiniTrooper" to hash
int modelHash = TotemModule::hashModel("MiniTrooper");
// Set robot model to "MiniTrooper"
module.write("cfg/robot/model", modelHash);

Wait functions

Simple write functions sends data without any acknowledgement and only returns false if command is failed to send. The reasons of failure could be:

  • module object is not connected to any interface to send command over.
  • Module number is larger than 255, or serial is larger than 32767.
  • Internal send queue is full (too much messages are being sent).

This allows to reach high communication speed, but doesn't guarantee that module received a command. To ensure that data was processed by receiving module, use functions with "Wait" suffix. These functions will send a command and block until response is received, indicating successful or failed transmission. Possible reasons of failure:

  • module object is not connected to any interface to send command over.
  • Module number is larger than 255, or serial is larger than 32767.
  • Internal send queue is full (too much messages are being sent).
  • Requested module is not available on TotemBUS or unresponsive.
  • "command" is not available for requested module.
  • Sending invalid data to "command" (e.g. sending int when command expects a string).
  • "command" failed to perform a task it suppose to do.

Same rules applies to subscribe and unsubscribe functions.
Usage examples:

TotemModule module04(04); // Define existing 04 module
TotemModule module03(03); // Define existing 03 module, but not connected
TotemModule module333(333); // Define non-existing (invalid) 333 module

void function() {
// Sending "indicate" to existing 04 module
module04.write("indicate"); // returns true -> module blinks a led
// Sending "indicate" to not connected 03 module
module03.write("indicate"); // returns true -> not expecting for response
// Sending "indicate" to non-existing 333 module
module333.write("indicate"); // returns false -> invalid number

// Sending invalid "indicate" to existing 04 module
module04.write("inDICAte"); // returns true -> module receives a command,
// but does not blink a led, because command spelling is incorrect.
// Sending invalid "indicate" to not connected 03 module
module03.write("inDICAte"); // returns true -> not expecting for response
// Sending invalid "indicate" to non-existing 333 module
module333.write("inDICAte"); // returns false -> invalid number

// Sending "indicate" to existing 04 module
module04.writeWait("indicate"); // returns true -> response received, led blink
// Sending "indicate" to not connected 03 module
module03.writeWait("indicate"); // returns false -> timeout,
// none of the 03 modules responded. Was blocked for 100ms
// Sending "indicate" to non-existing 333 module
module333.writeWait("indicate"); // returns false -> invalid number
// Setting name for existing 04 module
module04.writeWait("cfg/robot/name", 123); // returns false -> failure response,
// received integer while string data expected
}