techmannih/nema34-mounted-stepper-controller

A 48 V USB‑C PD 3.1 EPR NEMA‑34 stepper controller PCB combining STM32/TMC5160 control, external MOSFET motor bridges, protected power and regenerative braking, USB data, telemetry, diagnostics, status LEDs, and buzzer alarms.

Version
0.3.92
License
unset
Stars
1

firmware/tests/test_indicators.cpp

#include <cassert>
#include "../target/main.cpp"

static bool suspended;
void initializeSuspendTimer() {}
bool usbIsSuspended() { return suspended; }
void sleepWhileUsbSuspended() {}

static void start(unsigned now) {
  fakeNow=now;
  startPeripherals();
  assert(fakeLevels[pin(PD1180_PIN_STATUS_GPIO)]==HIGH);
}
static void expectReset() {
  assert(fakeLevels[pin(PD1180_PIN_STATUS_GPIO)]==LOW);
  assert(!indicatorsReady && !indicatorResetReleased);
}
int main() {
  setup(); expectReset();
  pdBus.indicatorPresent=true;
  start(100);
  pollIndicators(100); assert(pdBus.indicatorWrites==0); // Reset release settle time.
  pollIndicators(101); assert(indicatorsReady);
  assert((pdBus.indicatorLog[0]==std::array<uint8_t,2>{1,0x07})); // Latch off first.
  assert((pdBus.indicatorLog[1]==std::array<uint8_t,2>{2,0x00}));
  assert((pdBus.indicatorLog[2]==std::array<uint8_t,2>{3,0xF0})); // Only P0..3 outputs.
  assert(pdBus.indicatorRegisters[1]==0x03); // Blue commissioning indication.
  assert(!control.mcu_run && !control.power_permit);

  control.fault_latched=true;
  pollIndicators(2001); assert(pdBus.indicatorRegisters[1]==0x0E); // Red + alarm.
  pollIndicators(2251); assert(pdBus.indicatorRegisters[1]==0x06); // Alarm bounded to 200 ms.
  control.fault_latched=false;
  pollIndicators(2301); assert(pdBus.indicatorRegisters[1]==0x03);

  // An expander brownout must trigger a reset, then replay the safe latch/config sequence.
  pdBus.indicatorRegisters[3]=0xFF;
  pollIndicators(2351); expectReset();
  pollIndicators(3350); expectReset();
  pollIndicators(3351); assert(indicatorResetReleased && !indicatorsReady);
  pollIndicators(3401); assert(indicatorsReady && pdBus.indicatorRegisters[3]==0xF0);

  control.fault_latched=true; pollIndicators(4001);
  assert(pdBus.indicatorRegisters[1]&8);
  const auto count=pdBus.transactions;
  stopPeripherals(); expectReset();
  assert(pdBus.transactions==count); // Power loss/suspend silence requires no functioning bus.
  pollIndicators(4500); assert(pdBus.transactions==count);

  // A failure at any initialization write leaves outputs reset, never partly enabled.
  for (unsigned failed=1;failed<=3;++failed) {
    pdBus.indicatorWrites=0; pdBus.failIndicatorWrite=failed;
    start(5000+failed*2000);
    pollIndicators(fakeNow+1); expectReset();
  }
  pdBus.failIndicatorWrite=0;
  start(12000); pollIndicators(12001); assert(indicatorsReady);
  pdBus.indicatorPresent=false;
  pollIndicators(12051); expectReset();
  suspended=usbStarted=true;
  const auto suspendedCount=pdBus.transactions;
  pollIndicators(14000); // Suspend holds RESET low and permits no I2C.
  pollIndicators(14051); expectReset();
  assert(pdBus.transactions==suspendedCount);
  puts("PASS: indicator polarity, safe initialization, reset, bounded alarm, brownout and bus faults");
}