refactor: structure pico project

This commit is contained in:
2025-09-04 23:00:48 +02:00
parent db44b15717
commit 0a376487df
8 changed files with 117 additions and 463 deletions

View File

@@ -1,15 +0,0 @@
#pragma once
// ...existing code...
class Stepper {
protected:
int steps_per_rev;
public:
virtual void step(int steps, bool direction) = 0;
void step_rev(int revs, bool direction){
step(steps_per_rev*revs, direction);
}
int get_steps_per_rev(){
return steps_per_rev;
}
virtual ~Stepper() {}
};

View File

@@ -1,39 +0,0 @@
#pragma once
#include <Arduino.h>
#include "Stepper.h"
#include <array>
class ULN2003Stepper : public Stepper {
private:
std::array<uint8_t, 4> pins;
static constexpr int steps_per_seq = 8;
const uint8_t sequence[8][4] = {
{1, 0, 0, 0},
{1, 1, 0, 0},
{0, 1, 0, 0},
{0, 1, 1, 0},
{0, 0, 1, 0},
{0, 0, 1, 1},
{0, 0, 0, 1},
{1, 0, 0, 1}
};
int step_delay_us = 5000;
public:
ULN2003Stepper(std::array<uint8_t, 4> pins, int rev_steps) : pins(pins) {
steps_per_rev = rev_steps;
for (auto pin : pins) {
pinMode(pin, OUTPUT);
}
}
void step(int steps, bool direction) override {
for (int i = 0; i < steps; ++i) {
int seq_idx = direction ? (i % steps_per_seq) : (steps_per_seq - 1 - (i % steps_per_seq));
for (int j = 0; j < 4; ++j) {
digitalWrite(pins[j], sequence[seq_idx][j]);
}
delayMicroseconds(step_delay_us);
}
}
void setSpeed(int delay_us) {
step_delay_us = delay_us;
}
};

View File

@@ -1,6 +1,6 @@
#include <Arduino.h>
#include "Stepper.h"
#include "ULN2003Stepper.h"
#include <Stepper.h>
#include <ULN2003Stepper.h>
#ifndef LED_BUILTIN
#define LED_BUILTIN 25
@@ -16,12 +16,10 @@ public:
Serial.begin(baud);
int revSteps = driver1.get_steps_per_rev();
Serial.print("EVENT:START STEPS_PER_REV ");
Serial.println(revSteps);
waitForHost(1500);
logStartup();
// Startup indication
for(int i=0;i<3;i++) blink(60,100);
}
void loop() {
@@ -31,7 +29,11 @@ public:
private:
String inputBuffer;
enum class CmdType { PING, STEP, SPEED, UNKNOWN };
struct CommandHandler {
const char* name;
void (SchafkopfSerialApp::*fn)(const String &args);
};
static const CommandHandler commandTable[]; // defined after class
void waitForHost(unsigned long timeoutMs){
unsigned long start = millis();
@@ -45,15 +47,10 @@ private:
if(offMs) delay(offMs);
}
void logStartup(){
Serial.println(F("HELLO START"));
for(int i=0;i<3;i++) blink(60,100);
}
void pollSerial(){
while(Serial.available()){
char c = Serial.read();
if(c=='\r') continue; // ignore CR
if(c=='\r') continue;
if(c=='\n') {
processLine(inputBuffer);
inputBuffer = "";
@@ -66,17 +63,21 @@ private:
void processLine(const String &raw){
String line = raw;
line.trim();
if(!line.length()) return;
String cmdToken = firstToken(line);
String rest = remainingAfterFirst(line);
CmdType type = classify(cmdToken);
handleCommand(type, cmdToken, rest);
cmdToken.toUpperCase();
dispatchCommand(cmdToken, rest);
}
static String firstToken(const String &line){
int sp = line.indexOf(' ');
return (sp==-1)? line : line.substring(0, sp);
}
static String remainingAfterFirst(const String &line){
int sp = line.indexOf(' ');
if (sp==-1) return String("");
@@ -85,67 +86,68 @@ private:
return r;
}
CmdType classify(String token){
token.toUpperCase();
if(token==F("PING")) return CmdType::PING;
if(token==F("STEP")) return CmdType::STEP;
if(token==F("SPEED")) return CmdType::SPEED;
return CmdType::UNKNOWN;
void dispatchCommand(const String &uppercaseToken, const String &args){
for(size_t i=0; commandTable[i].name != nullptr; ++i){
if(uppercaseToken.equals(commandTable[i].name)){
(this->*commandTable[i].fn)(args);
return;
}
}
Serial.print(F("ERR:UNKNOWN COMMAND '")); Serial.print(uppercaseToken); Serial.println("'");
blink(20);
}
void handleCommand(CmdType type, const String &token, const String &args){
switch(type){
case CmdType::PING: {
Serial.println(F("PONG"));
blink();
break; }
case CmdType::STEP: {
// Expected: STEP <steps> <dir>
int steps = -1; int dir = -1;
if(parseStepArgs(args, steps, dir)) {
Serial.print(F("STEP: moving ")); Serial.print(steps); Serial.print(F(" dir=")); Serial.println(dir);
driver1.step(steps, dir!=0);
blink(60);
} else {
Serial.println(F("ERR:STEP usage STEP <steps> <0|1>"));
blink(20);
}
break; }
case CmdType::SPEED: {
int delayUs = args.toInt();
if(delayUs > 0) {
driver1.setSpeed(delayUs);
Serial.print(F("SPEED: set delay_us=")); Serial.println(delayUs);
blink();
} else {
Serial.println(F("ERR:SPEED usage SPEED <positive_delay_us>"));
blink(20);
}
break; }
case CmdType::UNKNOWN: {
Serial.print(F("ERR:UNKNOWN COMMAND '")); Serial.print(token); Serial.println("'");
blink(20);
break; }
default: {
Serial.println(F("ERR:UNHANDLED"));
blink(20);
break; }
// ---- COMMANDS ----
void cmdHealthcheck(const String &){
Serial.println(F("OK"));
blink();
}
void cmdStep(const String &args){
double steps = -1; int dir = -1;
if(parseStepArgs(args, steps, dir)) {
Serial.print(F("STEP: moving ")); Serial.print(steps); Serial.print(F(" dir=")); Serial.println(dir);
driver1.step_rev(steps, dir!=0);
blink(60);
} else {
Serial.println(F("ERR:STEP usage STEP <revs> <0|1>"));
blink(20);
}
}
// Helpers for parsing arguments
bool parseStepArgs(const String &args, int &steps, int &dir){
void cmdSpeed(const String &args){
int delayUs = args.toInt();
if(delayUs > 0) {
driver1.setStepDelay(delayUs);
Serial.print(F("SPEED: set delay_us=")); Serial.println(delayUs);
blink();
} else {
Serial.println(F("ERR:SPEED usage SPEED <positive_delay_us>"));
blink(20);
}
}
bool parseStepArgs(const String &args, double &steps, int &dir){
int sp = args.indexOf(' ');
if(sp == -1) return false;
String a = args.substring(0, sp); a.trim();
String b = args.substring(sp+1); b.trim();
if(!a.length() || !b.length()) return false;
steps = a.toInt(); dir = b.toInt();
steps = a.toDouble(); dir = b.toInt();
if(steps <= 0) return false;
if(!(dir==0 || dir==1)) return false;
return true;
}
};
// ---- COMMAND TABLE ----
const SchafkopfSerialApp::CommandHandler SchafkopfSerialApp::commandTable[] = {
{"HEALTHCHECK", &SchafkopfSerialApp::cmdHealthcheck},
{"STEP", &SchafkopfSerialApp::cmdStep},
{"SPEED", &SchafkopfSerialApp::cmdSpeed},
{nullptr, nullptr}
};
SchafkopfSerialApp app;
void setup(){ app.begin(); }