shibosoftwaredev/f1c100s-linux-nema17-stepper-controller
A four-layer NEMA 17 motor-controller PCB combining an Allwinner F1C100S Linux computer, USB‑PD/buck power system, W5500 Ethernet, STM32 real-time motion control, DRV8825 stepper driver, protection/temperature/current telemetry, USB interfaces, and local LED/buzzer diagnostics.
- Version
- 0.4.56
- License
- unset
- Stars
- 0
firmware/stm32/test_motion.c
#include "motion.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
static const Inputs healthy={true,true,true,15000,25000};
static uint8_t command(Motion *m, uint8_t cmd) {
Request r={cmd,0,0}; return motion_command(m,&r);
}
static void arm(Motion *m) {
/* Mock the independently verified hardware DAC service. */
m->limit_io_ok=true;m->limit_ready=true;
uint8_t one=1; Request r={2,1,&one};
motion_sample(m,&healthy); assert(command(m,1)==0); assert(motion_command(m,&r)==0);
motion_tick(m,m->now+3);
}
int main(void) {
Motion m; motion_init(&m); assert(!m.armed);
uint8_t one=1; Request a={2,1,&one}; assert(motion_command(&m,&a)==5);
arm(&m); motion_tick(&m,249); assert(m.armed);
motion_tick(&m,250); assert(!m.armed && (m.faults&HEARTBEAT_FAULT));
motion_init(&m); arm(&m);
uint8_t wake_bytes[8]={1,0,0,0,200,0,0,0}; Request wake_move={0x10,8,wake_bytes};
m.now=m.armed_at+2; assert(motion_command(&m,&wake_move)==4 && !m.remaining);
m.now=m.armed_at+3; assert(motion_command(&m,&wake_move)==0);
motion_init(&m); arm(&m);
Inputs broken=healthy; broken.pd_good=false; motion_sample(&m,&broken);
assert(!m.armed && (m.faults&POWER_FAULT));
motion_init(&m); arm(&m); broken=healthy; broken.driver_ok=false; motion_sample(&m,&broken);
assert(!m.armed && (m.faults&DRIVER_FAULT));
motion_init(&m); arm(&m); broken=healthy; broken.temperature_mc=71000; motion_sample(&m,&broken);
assert(!m.armed && (m.faults&TEMP_FAULT));
broken.temperature_mc=65000; motion_sample(&m,&broken);
uint8_t zero=0; Request disarm={2,1,&zero}; motion_command(&m,&disarm); assert(m.faults&TEMP_FAULT);
motion_sample(&m,&healthy); motion_command(&m,&disarm); assert(!m.faults);
motion_init(&m); arm(&m); broken=healthy; broken.sensor_ok=false; motion_sample(&m,&broken);
assert(!m.armed && (m.faults&SENSOR_FAULT));
motion_init(&m); arm(&m); motion_fault(&m,PROTOCOL_FAULT); assert(!m.armed);
for(unsigned count=1;count<=1000;count++) {
motion_init(&m); arm(&m);
uint8_t bytes[8]={(uint8_t)count,(uint8_t)(count>>8),0,0,200,0,0,0};
Request move={0x10,8,bytes}; assert(!motion_command(&m,&move));
unsigned rising=0;
for(unsigned tick=0;tick<count*2+20;tick++) {
bool old=m.step_high; motion_step_tick(&m); if(!old && m.step_high)rising++;
}
assert(rising==count && !m.remaining && !m.step_high);
assert(command(&m,0x12)==0 && !m.armed);
}
motion_init(&m); arm(&m);m.remaining=100000;m.rate=1000;m.stopping=true;
for(unsigned now=0;now<1000 && m.armed;now++) {
if(now%50==0)command(&m,1);
motion_tick(&m,now);
}
assert(!m.armed && !m.remaining);
motion_init(&m);arm(&m);
uint8_t reverse_bytes[8]={0xfd,0xff,0xff,0xff,200,0,0,0};
Request reverse_move={0x10,8,reverse_bytes};
assert(!motion_command(&m,&reverse_move) && m.reverse && m.remaining==3);
assert(motion_command(&m,&reverse_move)==4 && m.remaining==3);
for(unsigned i=0;i<6;i++)motion_step_tick(&m);
assert(!m.remaining && !m.step_high);
reverse_bytes[4]=0x21;reverse_bytes[5]=0x4e;
assert(motion_command(&m,&reverse_move)==2 && !m.remaining);
motion_init(&m);m.now=0xfffffff0;arm(&m);motion_tick(&m,0x80);assert(m.armed);
motion_tick(&m,0x100);assert(!m.armed);
motion_init(&m);arm(&m);m.remaining=37;m.rate=200;m.reverse=true;
unsigned char before[sizeof m];memcpy(before,&m,sizeof m);
assert(command(&m,0x21)==0 && memcmp(before,&m,sizeof m)==0);
Request bad_current={0x21,1,&one};
assert(motion_command(&m,&bad_current)==2 && memcmp(before,&m,sizeof m)==0);
motion_tick(&m,249);assert(command(&m,0x21)==0 && m.armed);
motion_tick(&m,250);assert(!m.armed && (m.faults&HEARTBEAT_FAULT));
assert(motion_crc16((const uint8_t*)"123456789",9)==0x29b1);
motion_init(&m);motion_sample(&m,&healthy);m.limit_io_ok=true;
assert(motion_command(&m,&a)==4 && !m.armed);
uint8_t ma[2]={200,0};Request limit={0x22,2,ma};
uint32_t heartbeat=m.last_heartbeat;
assert(motion_command(&m,&limit)==0 && m.limit_ma==200 && !m.limit_ready);
assert(m.last_heartbeat==heartbeat);
arm(&m);assert(motion_command(&m,&limit)==4 && m.limit_ma==200);
motion_fault(&m,CURRENT_LIMIT_FAULT);assert(!m.armed && !m.limit_ready);
ma[0]=0x8d;ma[1]=1;assert(motion_command(&m,&limit)==2 && m.limit_ma==200);
ma[0]=0;ma[1]=0;assert(motion_command(&m,&limit)==0 && m.limit_ma==0);
m.faults=0;m.limit_ready=true;assert(motion_command(&m,&a)==3 && !m.armed);
puts("PASS: startup/arm/wake, heartbeat/wraparound, PD/driver/temperature/sensor faults, controlled stop, reverse/busy/rate validation, read-only current requests cannot refresh heartbeat, CRC vector, 1000 exact pulse counts");
}