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_target_power.cpp

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

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

static void advance(unsigned ms) { fakeNow+=ms; loop(); }
static void expectSafe() {
  for (auto p : {PD1180_PIN_MCU_RUN, PD1180_PIN_POWER_PERMIT, PD1180_PIN_SD_MODE})
    assert(fakeLevels[pin(p)]==LOW);
  for (auto p : {PD1180_PIN_TMC_CS_N, PD1180_PIN_ENC_CS_N, PD1180_PIN_FLASH_CS_N}) {
    assert(fakeModes[pin(p)]==OUTPUT_OPEN_DRAIN);
    assert(fakeLevels[pin(p)]==HIGH);
  }
}
int main() {
  uint8_t identity[8] = {'P','D','1','1','8','0','4','1'};
  assert(pdConfigurationMatches(identity));
  for (unsigned i=0;i<sizeof(identity);i++) {identity[i]^=1; assert(!pdConfigurationMatches(identity)); identity[i]^=1;}
  memset(identity,0,sizeof(identity)); assert(!pdConfigurationMatches(identity));
  assert(!pdImageVerified && !motionQualified);
  // Exercise the actual mux scan and target call site: bus=200 ms, return=240
  // ms. Q16 goes low after the bus reading; the next scan recovers at 300 ms.
  pdBus.adcPresent=true;
  control.power_permit=true;
  for(unsigned t=10;t<=180;t+=10) {
    fakeNow=t; pollBusAdc(t);
    if(t%60==0) pollPower();
  }
  assert(brakePreflight.ready);
  control.mcu_run=true;
  for(unsigned t=190;t<=300;t+=10) {
    fakeNow=t;
    pdBus.adcRaw[2]=(t>200 && t<=240) ? 0 : 19762;
    pollBusAdc(t);
    if(t==240) {
      assert(adcSampleAt[0]==200 && adcSampleAt[2]==240);
      pollPower(); assert(inputs.brake_preflight_ok && !brakePreflight.faulted);
    }
    if(t==250 || t==300) {
      pollPower(); assert(inputs.brake_preflight_ok && !brakePreflight.faulted);
    }
  }
  assert(!brakePreflight.mismatch_pending);
  invalidateTelemetry(); fakeNow=lastAdcPoll=0; pdBus.adcChannels.clear();
  pdBus.adcPresent=true;
  for (unsigned n=1;n<=6;n++) pollBusAdc(n*10u);
  assert((pdBus.adcChannels==std::vector<unsigned>{0,1,2}));
  assert(adcValid[0] && adcValid[1] && adcValid[2]);
  assert(adcMv[2]==2470 && adcSampleAt[2]==60);
  pdBus.adcFail=true; pollBusAdc(70);
  assert(!adcValid[0] && !adcValid[1] && !adcValid[2]);
  pdBus.adcPresent=false; pdBus.adcFail=false; pdBus.transactions=0;
  invalidateTelemetry(); lastAdcPoll=0;
  fakeAdc[pin(PD1180_PIN_USB_VBUS_SENSE)]=279; // Approximately 5 V DATA supply.
  setup(); advance(1);
  assert(usbStarted && !peripheralsStarted && !pdBus.started);
  assert(pdBus.transactions==0);
  expectSafe();
  SerialUSB.input="ARM\n";advance(1);advance(1);
  assert(SerialUSB.output.find("BLOCKED")!=std::string::npos);
  expectSafe();

  fakeAdc[pin(PD1180_PIN_BOARD_POWER_SENSE)]=2048;
  advance(1);assert(!peripheralsStarted);
  advance(19);assert(!peripheralsStarted);
  advance(1);assert(peripheralsStarted && pdBus.started);
  assert(!spiStarted && motorSpi.transactions==0);
  inputs.motor_power_good=inputs.vmotor_in_range=true;
  pollDriver(fakeNow+20);
  assert(spiStarted && !tmcStatus.valid && !inputs.driver_ready);
  inputs.motor_power_good=false; pollDriver(fakeNow+21);
  assert(!spiStarted && fakeModes[pin(PD1180_PIN_SPI_MOSI)]==INPUT_ANALOG);
  adcValid[0]=adcValid[2]=phaseValid=inputs.temperature_valid=true;
  brakePreflight.ready=inputs.brake_preflight_ok=true;
  fakeAdc[pin(PD1180_PIN_BOARD_POWER_SENSE)]=0;
  advance(1);
  assert(!peripheralsStarted && !pdBus.started && !adcValid[0] && !adcValid[2] && !brakePreflight.ready && !inputs.brake_preflight_ok && !phaseValid && !inputs.temperature_valid);
  assert(fakeModes[pin(PD1180_PIN_PD_SCL)]==INPUT_ANALOG);
  expectSafe();

  fakeAdc[pin(PD1180_PIN_BOARD_POWER_SENSE)]=2048;
  advance(1);advance(20);assert(peripheralsStarted);
  commandLength=3; responseLength=10;
  const auto reads=pdBus.transactions, reloads=IWatchdog.reloads;
  suspended=true;advance(1);
  assert(sleeps==1 && IWatchdog.reloads==reloads+1);
  assert(pdBus.transactions==reads && !pdBus.started && !peripheralsStarted);
  assert(commandLength==0 && responseLength==0 && fakeLevels[pin(PD1180_PIN_STATUS_GPIO)]==LOW);
  expectSafe();
  suspended=false;advance(1);assert(!peripheralsStarted);
  advance(20);assert(peripheralsStarted);
  expectSafe();

  suspended=true;advance(1);
  fakeAdc[pin(PD1180_PIN_USB_VBUS_SENSE)]=0;advance(1);
  assert(!usbStarted && !SerialUSB.started);
  expectSafe();
  puts("PASS: target USB-only startup, power loss/recovery, suspend/resume, detach and ARM lock");
}