Device wake up via BLE and duration getting SOS Hard fault

Hi all,

This is my setup:

  • Argon1 acting as BLE central, not connected to the cloud (don’t care for now). DeviceOS 5.1.0
  • Argon2 acting as BLE peripheral, not connected to the cloud (will never connect since there is no need in my scenario), sleeping in ULTRA_LOW_POWER mode. Tested DeviceOS 5.1.0 and 4.0.0.

Argon2 boots and waits for a BLE connection then goes to sleep for some time or can wake up via BLE (Argon1 will wake it up).

This is my problem:
when I use sleep config duration(x) and ble() at the same time, right before going to sleep, Argon2 crashes with SOS code 1: Hard fault.
Argon2 will go to sleep after it receives a BLE command from Argon1 to go to sleep.

My sleep config:

 sleepConfig.mode(SystemSleepMode::ULTRA_LOW_POWER)
      .ble()
      .duration(120000);

If I only use one, either ble() or duration(x), all is good.

Argon 2 serial log:

Serial monitor opened successfully:
0000001912 [app] INFO: BLE Peripheral started
0000001912 [app] INFO: Waiting for incoming connections
0000001913 [app] INFO: Hint: you can now power on (or power cycle) the other device)
0000017908 [wiring.ble] TRACE: Connected by Central device.
0000017908 [app] INFO: ******** Connected to central device
0000017914 [system.ctrl.ble] TRACE: Connected
0000020879 [app] INFO: ====>>>> Received SLEEP command
0000020880 [app] INFO: About to go to sleep in 1 second
0000022014 [app] INFO: Going to sleep in 1 second
0000023015 [system.sleep] TRACE: Entering system_sleep_ext()
0000023015 [system.sleep] TRACE: Interface 4 is off already

<<--  DEVICE CRASHED HERE  -->>
Serial connection closed.  Attempting to reconnect...

Where are things going wrong?
Thanks!


Argon1 code:

SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);

SerialLogHandler logHandler(LOG_LEVEL_WARN, {
                                                {"app", LOG_LEVEL_ALL},
                                                {"system.ctrl.ble", LOG_LEVEL_ALL},
                                                {"wiring.ble", LOG_LEVEL_ALL},
                                            });

const BleUuid serviceUuid("a1d1daf4-aaa2-4d9d-9214-9df347db4287");
const BleUuid txUuid("a1d1daf4-aaa2-4d9d-9214-9df347db4288");
const BleUuid rxUuid("a1d1daf4-aaa2-4d9d-9214-9df347db4289");

#define BLE_SLEEP "sleep"

const BleScanResult *bleScanResult;

BleCharacteristic rxCharacteristic;
BleCharacteristic txCharacteristic;
BlePeerDevice peripheral;

void setup()
{
  BLE.on();
  BLE.setScanPhy(BlePhy::BLE_PHYS_1MBPS);

  waitFor(Serial.isConnected, 15000);
  delay(1000);

  scan();
  bleSend(BLE_SLEEP);
}

void loop()
{
}

bool bleSend(const char *message)
{
  if (peripheral.connected())
  {
    Log.info("====>>>> Sending to peripheral: %s", message);
    txCharacteristic.setValue(message);
    return true;
  }
  else
  {
    Log.info("====>>>> Not sending to peripheral: %s", message);
    return false;
  }
}

void scan()
{

  BleScanFilter filter;
  filter.serviceUUID(serviceUuid);
  Vector<BleScanResult> scanResults = BLE.scanWithFilter(filter);

  Log.info("Found %u %s", scanResults.size(), scanResults.size() == 1 ? "device" : "devices");

  // if there are more than 1 devices, connect to the one with the strongest signal
  if (scanResults.size() > 1)
  {
    // find the scan result for the peripheral with the highest RSSI
    int maxRSSI = -1000;
    for (int i = 0; i < scanResults.size(); i++)
    {
      if (scanResults[i].rssi() > maxRSSI)
      {
        maxRSSI = scanResults[i].rssi();
        bleScanResult = &scanResults[i];
      }
    }
  }
  else if (scanResults.size() == 1)
  {
    bleScanResult = &scanResults[0];
  }
  else
  {
    return;
  }

  peripheral = BLE.connect(bleScanResult->address());
  if (peripheral.connected())
  {
    Log.info("Peripheral connected");
    peripheral.getCharacteristicByUUID(rxCharacteristic, rxUuid);
    peripheral.getCharacteristicByUUID(txCharacteristic, txUuid);
  }
  else
  {
    Log.info("Failed to connect to peripheral");
  }
}


Argon2 code:

// system modes tested: MANUAL and AUTO (no difference)
SYSTEM_MODE(MANUAL);
// system thread enabled/disabled: no difference
SYSTEM_THREAD(ENABLED);

SerialLogHandler logHandler(LOG_LEVEL_TRACE, {
                                                 {"app", LOG_LEVEL_ALL},
                                                 {"system.ctrl.ble", LOG_LEVEL_ALL},
                                                 {"wiring.ble", LOG_LEVEL_ALL},
                                             });

const char *serviceUuid = "a1d1daf4-aaa2-4d9d-9214-9df347db4287";
const char *rxUuid = "a1d1daf4-aaa2-4d9d-9214-9df347db4288";
const char *txUuid = "a1d1daf4-aaa2-4d9d-9214-9df347db4289";

BleCharacteristic txCharacteristic("tx", BleCharacteristicProperty::INDICATE, txUuid, serviceUuid);
BleCharacteristic rxCharacteristic("rx", BleCharacteristicProperty::WRITE, rxUuid, serviceUuid, onDataReceived, NULL);

bool goToSleepFlag = false;

SystemSleepConfiguration sleepConfig;

void setup()
{

  sleepConfig.mode(SystemSleepMode::ULTRA_LOW_POWER)
      .ble()
      .duration(120000);

  waitFor(Serial.isConnected, 15000);
  delay(1000);

  // we only need to do this in MANUAL mode
  BLE.on();

  BLE.setAdvertisingPhy(BlePhy::BLE_PHYS_1MBPS);
  BLE.addCharacteristic(txCharacteristic);
  BLE.addCharacteristic(rxCharacteristic);

  BLE.onConnected(connectedCallback, NULL);

  BleAdvertisingData data;
  data.appendServiceUUID(serviceUuid);
  BLE.advertise(&data);

  Log.info("BLE Peripheral started");
  Log.info("Waiting for incoming connections");
  Log.info("Hint: you can now power on (or power cycle) the other device)");
}

void loop()
{
  if (goToSleepFlag)
  {
    goToSleep();
    goToSleepFlag = false;
  }
}

void onDataReceived(const uint8_t *data, size_t len, const BlePeerDevice &peer, void *context)
{
  if (strcmp((const char *)data, "sleep") == 0)
  {
    Log.info("====>>>> Received SLEEP command");

    goToSleepFlag = true;
  }
}

void goToSleep()
{
  Log.info("About to go to sleep in 1 second");
  BLE.disconnect();
  // BLE.stopAdvertising();
  // BLE.off();
  delay(1000);

  Log.info("Going to sleep in 1 second");
  delay(1000);

  System.sleep(sleepConfig);

  waitFor(Serial.isConnected, 15000);
  delay(1000);
  Log.info("Back from sleep");
}

void connectedCallback(const BlePeerDevice &peer, void *context)
{
  Log.info("******** Connected to central device");
}

Edit: seems to be similar to the issue reported here.

I have run into the same issue except on 3.1.0-3.2.0
interested if anyone has a fix / workaround

My current solution is just to have the central wake the device at the correct time

same here.
It seems like those two settings to wake up are mutually exclusive:

      .ble()
      .duration(120000);