Using new software for X4

Extended previous example with data sending from X4 → ESP32

Important: A bit of “hack” is required to access some internal RoboBoard functionality. Will implement a proper way to do it later (with furter software releases).
For now, update this file path to match your file system. It should point to this file inside “TotemLibrary”:

#include "C:\Users\NAME\Documents\Arduino\libraries\TotemArduino\src\core\TotemBUS.h"

Example demonstrates sending 32bit integer, string or data array.

RoboBoard X4 Arduino sketch:

void appEvent(int evt, int value) {
  // If disconnected from RoboBoard - stop all motors
  if (evt == TotemApp.evtDisconnect) {
    DC.brake();
    return;
  }
  // Accept only "functionA"
  if (evt != TotemApp.evtFunctionA) return;
  // Unpack data from 32-bit "value" variable
  int cmd = value & 0xFF;         // Function type to call
  int port = (value >> 8) & 0xFF; // Motor port (A,B,C,D)
  value = value >> 16;            // Value sent to the function (16-bit)
  // Execute selected command
  switch (cmd) {
    case 0: DC[port].brake(value); break;
    case 1: DC[port].spin(value); break;
    case 2: DC[port].tone(value); break;
    case 3: DC[port].setAccelerationTime(value); break;
    case 4: DC[port].setDecelerationTime(value); break;
  }
}
// Update path to match your local file system
#include "C:\Users\USER\Documents\Arduino\libraries\TotemArduino\src\core\TotemBUS.h"
int BleServerService_sendFrame(TotemBUS::Frame frame, uint16_t number, uint16_t serial);
// Functions to send data back to ESP32
int sendValue(int command, int value) {
  return BleServerService_sendFrame(TotemBUS::respond(command, value), 4, 0);
}
int sendData(int command, uint8_t *data, uint32_t len) {
  return BleServerService_sendFrame(TotemBUS::respond(command, {(const char*)data, len}), 4, 0);
}
int sendString(int command, const char *str) {
  return BleServerService_sendFrame(TotemBUS::respond(command, {str, strlen(str)}), 4, 0);
}

IOButton button(BUTTON_BUILTIN);
void buttonEvent(int evt) {
  // Send X4 button state to ESP32
  if (evt == Button.evtPress) { sendValue(11, 1); }
  else if (evt == Button.evtRelease) { sendValue(11, 0); }
}
void setup() {
  TotemApp.addEvent(appEvent); // Register events from Totem.BLE
  button.addEvent(buttonEvent); // Regiser button event
}
void loop() {
  // Send value (integer) to ESP32
  sendValue(55, 1000);
  printf("send command:55 value:1000 to ESP32\n");
  delay(1000);
  // Send string to ESP32
  sendString(66, "This is a text");
  printf("send command:66 string:'This is a text' to ESP32\n");
  delay(1000);
  // Send byte array to ESP32
  uint8_t arr[] = {1, 2, 3, 4, 5, 0};
  sendData(77, arr, sizeof(arr));
  printf("send command:77 bytes: 1,2,3,4,5,0 to ESP32\n");
  delay(1000);
}

Remote ESP32 Arduino sketch:

#include <Totem.h>
// Define object that will be used to access X4 board.
// It will become active when BLE connection is established.
TotemModule rb_x4(04);
// Function wrapper to send custom commands to X4
class RoboBoardX4 {
  void write(int cmd, int port, int value) {
    // Pack parameters to 32-bit "value"
    value <<= 16;
    value |= (port & 0xFF) << 8;
    value |= (cmd & 0xFF);
    rb_x4.write("functionA", value); // Send to X4
  }
public:
  // port: 0-A, 1-B, 2-C, 3-D
  void brake(int port, int value = 100) { write(0, port, value); }
  void spin(int port, int value) { write(1, port, value); }
  void tone(int port, int value) { write(2, port, value); }
  void setAccelerationTime(int port, int value) { write(3, port, value); }
  void setDecelerationTime(int port, int value) { write(4, port, value); }
} X4;
// Receive data from RoboBoard X4
void onSendFromX4(ModuleData data) {
  if (data.getHashCmd() == 11) { // Buton was pressed on RoboBoard X4
    printf("==>> BUTTON: %d\n", data.getInt());
  }
  else if (data.isInt()) { // Used "sendValue"
    // Get command and value
    int command = data.getHashCmd();
    int value = data.getInt();
    // Print command and value
    printf("==>> Got command: %d value: %d\n", command, value);
  }
  else if (data.isString()) { // Used "sendData" or "sendString"
    // Get command and string
    int command = data.getHashCmd();
    const char *str = data.getString();
    // Get data array
    uint8_t *dataPtr; int dataLen;
    data.getData(dataPtr, dataLen);
    // Print string & data array (choose the one you need)
    printf("==>> Got command: %d string: %s\nBytes(%d): ", command, str, dataLen);
    for (int i=0; i<dataLen; i++) {
      printf(" %d", dataPtr[i]);
    }
    printf("\n");
  }
}

// Arduino setup function.
void setup() {
    // put your setup code here, to run once:
    Serial.begin(115200);
    Totem.BLE.begin(); // Start Bluetooth Low Energy interface
    Serial.println("Searching for Totem board...");
    // Start scanning for Totem board. It's representing a Totem robot.
    TotemRobot robot = Totem.BLE.findRobot(); // Wait until connected to first found Totem robot
    // Print connected robot name
    Serial.print("Connected to: ");
    Serial.println(robot.getName());
    // Register data receiver from RoboBoard X4
    rb_x4.attachOnData(onSendFromX4);
    // Proceed to loop    
}
// Arduino loop function
void loop() {
    X4.spin(0, 50); // Send to X4
    Serial.println("Spin DC A 50%");
    delay(1000);
    X4.brake(0); // Send to X4
    Serial.println("Stop DC A");
    delay(1000);
}