666 lines
19 KiB
Arduino
666 lines
19 KiB
Arduino
//
|
|
// Auto_Seat
|
|
// Automatic seat controller with EEPROM settings and optional serial tools.
|
|
//
|
|
#include <EEPROM.h>
|
|
|
|
#define seatRelayD8 8 // HIGH = OFF, LOW = ON (up relay)
|
|
#define seatRelayD9 9 // HIGH = OFF, LOW = ON (down relay)
|
|
|
|
#define parkingPin A0 // PARKING raw analog value, 0~1023
|
|
#define ignitionPin 7 // HIGH = IG1 ON, LOW = IG1 OFF
|
|
|
|
// ============================================================
|
|
// !!! SAFETY LIMIT !!!
|
|
//
|
|
// Physical maximum travel time from bottom to the highest allowed point.
|
|
// User settings saved in EEPROM must stay inside 0..6000ms.
|
|
// ============================================================
|
|
const uint16_t SEAT_HARD_LIMIT_UP_MS = 6000;
|
|
|
|
// Parking raw threshold hysteresis.
|
|
// P turns ON at 950 or higher, and turns OFF at 940 or lower.
|
|
const int PARKING_ON_THRESHOLD = 950;
|
|
const int PARKING_OFF_THRESHOLD = 940;
|
|
|
|
// Down movement is estimated as 1.1x faster than up movement.
|
|
const int DOWN_SPEED_NUM = 11;
|
|
const int DOWN_SPEED_DEN = 10;
|
|
|
|
// Input and relay protection.
|
|
const unsigned long IGNITION_STABILIZE_MS = 1000UL;
|
|
const unsigned long DRIVE_CONFIRM_MS = 80UL;
|
|
const unsigned long PARK_CONFIRM_MS = 250UL;
|
|
const unsigned long RELAY_DEADTIME_MS = 120UL;
|
|
const unsigned long DOWN_EDGE_MARGIN_MS = 300UL;
|
|
|
|
// After 10 ignition OFF events, wait 5 minutes while ignition is OFF,
|
|
// then auto-calibrate: up 7 seconds -> down 6 seconds -> set position to bottom.
|
|
const byte USES_BEFORE_AUTO_CALIBRATION = 10;
|
|
const unsigned long AUTO_CALIBRATION_DELAY_MS = 300000UL;
|
|
const unsigned long AUTO_CALIBRATION_UP_MS = 7000UL;
|
|
const unsigned long AUTO_CALIBRATION_DOWN_MS = 6000UL;
|
|
|
|
// Serial debug output.
|
|
const unsigned long DEBUG_INTERVAL_MS = 1000UL;
|
|
const long MANUAL_STEP_MS = 500;
|
|
|
|
// EEPROM map.
|
|
const int EEPROM_MAGIC_ADDR = 0;
|
|
const byte EEPROM_MAGIC_VALUE = 0x64;
|
|
const int EEPROM_USE_COUNT_ADDR = 1;
|
|
const int EEPROM_SEAT_POSITION_ADDR = 2; // uint16_t, low byte first
|
|
|
|
const byte CALIBRATION_IDLE = 0;
|
|
const byte CALIBRATION_UP = 1;
|
|
const byte CALIBRATION_DOWN = 2;
|
|
|
|
boolean ignitionState = LOW;
|
|
boolean parkingState = LOW;
|
|
boolean prevIgnitionState = LOW;
|
|
boolean isStabilizing = false;
|
|
boolean confirmedDriveMode = LOW;
|
|
boolean pendingDriveMode = LOW;
|
|
|
|
byte useCount = 0;
|
|
byte autoCalibrationState = CALIBRATION_IDLE;
|
|
bool autoCalibrationPending = false;
|
|
bool forceCalibration = false;
|
|
bool manualMode = false;
|
|
|
|
int parkingRawValue = 0;
|
|
uint16_t storedSeatPositionMs = 0;
|
|
long currentPosMs = 0;
|
|
long targetPosMs = 0;
|
|
long downSpeedRemainder = 0;
|
|
unsigned long downEdgeMarginTime = DOWN_EDGE_MARGIN_MS;
|
|
bool downEdgeMarginActive = false;
|
|
|
|
unsigned long lastTime = 0;
|
|
unsigned long stabilizeStartTime = 0;
|
|
unsigned long ignitionOffStartTime = 0;
|
|
unsigned long calibrationPhaseStartTime = 0;
|
|
unsigned long pendingDriveModeStartTime = 0;
|
|
unsigned long relayDeadtimeStartTime = 0;
|
|
unsigned long lastDebugPrintTime = 0;
|
|
|
|
int currentSeatAction = 0;
|
|
int requestedSeatAction = 0;
|
|
int lastStoppedSeatAction = 0;
|
|
|
|
bool serialIntroPrinted = false;
|
|
bool debugEnabled = false;
|
|
bool manualStepStatusPending = false;
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
Serial.setTimeout(25);
|
|
|
|
pinMode(parkingPin, INPUT);
|
|
pinMode(ignitionPin, INPUT);
|
|
pinMode(seatRelayD8, OUTPUT);
|
|
pinMode(seatRelayD9, OUTPUT);
|
|
|
|
applySeatAction(0);
|
|
seat(0);
|
|
loadSettings();
|
|
|
|
measurement();
|
|
confirmedDriveMode = getRawDriveMode();
|
|
pendingDriveMode = confirmedDriveMode;
|
|
targetPosMs = getTargetForConfirmedMode();
|
|
if (ignitionState == LOW) {
|
|
ignitionOffStartTime = millis();
|
|
}
|
|
|
|
lastTime = millis();
|
|
}
|
|
|
|
void loop() {
|
|
measurement();
|
|
handleSerial();
|
|
|
|
unsigned long currentTime = millis();
|
|
unsigned long deltaTime = currentTime - lastTime;
|
|
lastTime = currentTime;
|
|
|
|
if (prevIgnitionState == LOW && ignitionState == HIGH) {
|
|
isStabilizing = true;
|
|
stabilizeStartTime = currentTime;
|
|
} else if (prevIgnitionState == HIGH && ignitionState == LOW) {
|
|
registerIgnitionOffUse(currentTime);
|
|
}
|
|
prevIgnitionState = ignitionState;
|
|
|
|
if (autoCalibrationState != CALIBRATION_IDLE) {
|
|
updateAutoCalibration(currentTime);
|
|
updateRelayOutput(currentTime);
|
|
updateDebugOutput(currentTime);
|
|
return;
|
|
}
|
|
|
|
if (autoCalibrationPending && ignitionState == LOW &&
|
|
currentTime - ignitionOffStartTime >= AUTO_CALIBRATION_DELAY_MS) {
|
|
startAutoCalibration(currentTime);
|
|
updateRelayOutput(currentTime);
|
|
updateDebugOutput(currentTime);
|
|
return;
|
|
}
|
|
|
|
if (isStabilizing) {
|
|
if (currentTime - stabilizeStartTime < IGNITION_STABILIZE_MS) {
|
|
seat(0);
|
|
updateRelayOutput(currentTime);
|
|
updateDebugOutput(currentTime);
|
|
return;
|
|
}
|
|
isStabilizing = false;
|
|
}
|
|
|
|
updateConfirmedDriveMode(currentTime);
|
|
if (!manualMode) {
|
|
targetPosMs = getTargetForConfirmedMode();
|
|
}
|
|
normalizeMotionState();
|
|
updateMovement(deltaTime);
|
|
normalizeMotionState();
|
|
updateRelayOutput(currentTime);
|
|
updateManualStepStatus();
|
|
updateDebugOutput(currentTime);
|
|
}
|
|
|
|
void measurement() {
|
|
ignitionState = digitalRead(ignitionPin);
|
|
|
|
parkingRawValue = analogRead(parkingPin);
|
|
if (parkingState == LOW && parkingRawValue >= PARKING_ON_THRESHOLD) {
|
|
parkingState = HIGH;
|
|
} else if (parkingState == HIGH && parkingRawValue <= PARKING_OFF_THRESHOLD) {
|
|
parkingState = LOW;
|
|
}
|
|
}
|
|
|
|
boolean getRawDriveMode() {
|
|
if (ignitionState == HIGH && parkingState == LOW) {
|
|
return HIGH;
|
|
}
|
|
return LOW;
|
|
}
|
|
|
|
long getTargetForConfirmedMode() {
|
|
if (confirmedDriveMode == HIGH) {
|
|
return storedSeatPositionMs;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void updateConfirmedDriveMode(unsigned long currentTime) {
|
|
boolean rawDriveMode = getRawDriveMode();
|
|
|
|
if (rawDriveMode != pendingDriveMode) {
|
|
pendingDriveMode = rawDriveMode;
|
|
pendingDriveModeStartTime = currentTime;
|
|
}
|
|
|
|
unsigned long confirmMs = pendingDriveMode == HIGH ? DRIVE_CONFIRM_MS : PARK_CONFIRM_MS;
|
|
if (pendingDriveMode != confirmedDriveMode &&
|
|
currentTime - pendingDriveModeStartTime >= confirmMs) {
|
|
confirmedDriveMode = pendingDriveMode;
|
|
manualMode = false;
|
|
manualStepStatusPending = false;
|
|
}
|
|
}
|
|
|
|
void updateMovement(unsigned long deltaTime) {
|
|
if (downEdgeMarginActive) {
|
|
if (currentPosMs == 0 && targetPosMs == 0) {
|
|
seat(-1);
|
|
downEdgeMarginTime += deltaTime;
|
|
if (downEdgeMarginTime >= DOWN_EDGE_MARGIN_MS) {
|
|
downEdgeMarginTime = DOWN_EDGE_MARGIN_MS;
|
|
downEdgeMarginActive = false;
|
|
seat(0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
downEdgeMarginActive = false;
|
|
downEdgeMarginTime = DOWN_EDGE_MARGIN_MS;
|
|
}
|
|
|
|
if (currentPosMs < targetPosMs) {
|
|
seat(1);
|
|
currentPosMs += deltaTime;
|
|
if (currentPosMs >= targetPosMs) {
|
|
currentPosMs = targetPosMs;
|
|
seat(0);
|
|
}
|
|
} else if (currentPosMs > targetPosMs) {
|
|
seat(-1);
|
|
long downMoveScaled = deltaTime * DOWN_SPEED_NUM + downSpeedRemainder;
|
|
currentPosMs -= downMoveScaled / DOWN_SPEED_DEN;
|
|
downSpeedRemainder = downMoveScaled % DOWN_SPEED_DEN;
|
|
if (currentPosMs <= targetPosMs) {
|
|
currentPosMs = targetPosMs;
|
|
downSpeedRemainder = 0;
|
|
if (targetPosMs == 0) {
|
|
startDownEdgeMargin();
|
|
} else {
|
|
seat(0);
|
|
}
|
|
}
|
|
} else {
|
|
seat(0);
|
|
}
|
|
}
|
|
|
|
void startDownEdgeMargin() {
|
|
downEdgeMarginActive = true;
|
|
downEdgeMarginTime = 0;
|
|
seat(-1);
|
|
}
|
|
|
|
void registerIgnitionOffUse(unsigned long currentTime) {
|
|
ignitionOffStartTime = currentTime;
|
|
|
|
if (useCount < USES_BEFORE_AUTO_CALIBRATION) {
|
|
useCount++;
|
|
EEPROM.update(EEPROM_USE_COUNT_ADDR, useCount);
|
|
}
|
|
|
|
if (useCount >= USES_BEFORE_AUTO_CALIBRATION) {
|
|
autoCalibrationPending = true;
|
|
}
|
|
}
|
|
|
|
void startAutoCalibration(unsigned long currentTime) {
|
|
manualMode = false;
|
|
manualStepStatusPending = false;
|
|
downSpeedRemainder = 0;
|
|
downEdgeMarginActive = false;
|
|
downEdgeMarginTime = DOWN_EDGE_MARGIN_MS;
|
|
autoCalibrationState = CALIBRATION_UP;
|
|
calibrationPhaseStartTime = currentTime;
|
|
seat(1);
|
|
}
|
|
|
|
void updateAutoCalibration(unsigned long currentTime) {
|
|
if (ignitionState == HIGH && !forceCalibration) {
|
|
seat(0);
|
|
autoCalibrationState = CALIBRATION_IDLE;
|
|
manualStepStatusPending = false;
|
|
downSpeedRemainder = 0;
|
|
downEdgeMarginActive = false;
|
|
downEdgeMarginTime = DOWN_EDGE_MARGIN_MS;
|
|
ignitionOffStartTime = currentTime;
|
|
return;
|
|
}
|
|
|
|
if (autoCalibrationState == CALIBRATION_UP) {
|
|
if (currentTime - calibrationPhaseStartTime >= AUTO_CALIBRATION_UP_MS) {
|
|
autoCalibrationState = CALIBRATION_DOWN;
|
|
calibrationPhaseStartTime = currentTime;
|
|
seat(-1);
|
|
} else {
|
|
seat(1);
|
|
}
|
|
} else if (autoCalibrationState == CALIBRATION_DOWN) {
|
|
if (currentTime - calibrationPhaseStartTime >= AUTO_CALIBRATION_DOWN_MS) {
|
|
seat(0);
|
|
autoCalibrationState = CALIBRATION_IDLE;
|
|
autoCalibrationPending = false;
|
|
forceCalibration = false;
|
|
useCount = 0;
|
|
EEPROM.update(EEPROM_USE_COUNT_ADDR, useCount);
|
|
currentPosMs = 0;
|
|
targetPosMs = 0;
|
|
downSpeedRemainder = 0;
|
|
downEdgeMarginActive = false;
|
|
downEdgeMarginTime = DOWN_EDGE_MARGIN_MS;
|
|
} else {
|
|
seat(-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void handleSerial() {
|
|
if (!Serial.available()) {
|
|
return;
|
|
}
|
|
|
|
String command = Serial.readStringUntil('\n');
|
|
command.trim();
|
|
|
|
if (debugEnabled) {
|
|
command.toLowerCase();
|
|
if (command == "x") {
|
|
debugEnabled = false;
|
|
Serial.println(F("DEBUG_STOPPED"));
|
|
printStatus(F("STATUS"));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!serialIntroPrinted) {
|
|
if (command.length() == 0) {
|
|
printIntro();
|
|
serialIntroPrinted = true;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (command.length() == 0) {
|
|
return;
|
|
}
|
|
|
|
processSerialCommand(command);
|
|
}
|
|
|
|
bool isSeatCommandBusy() {
|
|
return manualStepStatusPending ||
|
|
autoCalibrationState != CALIBRATION_IDLE ||
|
|
downEdgeMarginActive ||
|
|
currentPosMs != targetPosMs ||
|
|
requestedSeatAction != 0 ||
|
|
currentSeatAction != 0;
|
|
}
|
|
|
|
void processSerialCommand(String command) {
|
|
command.trim();
|
|
command.toLowerCase();
|
|
if (command.length() == 0) {
|
|
printStatus(F("EMPTY_INPUT_STATUS"));
|
|
return;
|
|
}
|
|
|
|
if (command.length() != 1) {
|
|
Serial.println(F("ERR: one-character command only. Send h for help."));
|
|
printStatus(F("ACK"));
|
|
return;
|
|
}
|
|
|
|
char name = command.charAt(0);
|
|
|
|
if (requiresParkingForCommand(name) && parkingState != HIGH) {
|
|
Serial.println(F("ERR: check gear state. Command requires P."));
|
|
printStatus(F("GEAR_CHECK_FAILED"));
|
|
return;
|
|
}
|
|
|
|
if (isSeatCommandBusy()) {
|
|
Serial.println(F("ERR: busy. Wait until seat movement is done."));
|
|
printStatus(F("BUSY"));
|
|
return;
|
|
}
|
|
|
|
if (name == 'h') {
|
|
printIntro();
|
|
} else if (name == 's') {
|
|
printStatus(F("STATUS"));
|
|
} else if (name == 'p') {
|
|
saveCurrentPositionCommand();
|
|
} else if (name == 'u') {
|
|
handleRelativeStep(1);
|
|
} else if (name == 'd') {
|
|
handleRelativeStep(-1);
|
|
} else if (name == 'g') {
|
|
debugEnabled = true;
|
|
lastDebugPrintTime = 0;
|
|
printStatus(F("DEBUG_STARTED_X_TO_STOP"));
|
|
} else if (name == 'a') {
|
|
manualStepStatusPending = false;
|
|
manualMode = false;
|
|
targetPosMs = getTargetForConfirmedMode();
|
|
printStatus(F("AUTO_MODE_RESTORED"));
|
|
} else if (name == 'c') {
|
|
manualStepStatusPending = false;
|
|
forceCalibration = true;
|
|
autoCalibrationPending = false;
|
|
startAutoCalibration(millis());
|
|
printStatus(F("CALIBRATION_STARTED_UP7_DOWN6"));
|
|
} else if (name == 'r') {
|
|
useCount = 0;
|
|
autoCalibrationPending = false;
|
|
EEPROM.update(EEPROM_USE_COUNT_ADDR, useCount);
|
|
printStatus(F("USE_COUNT_RESET"));
|
|
} else {
|
|
Serial.println(F("Unknown command. Send h for help."));
|
|
printStatus(F("ACK"));
|
|
}
|
|
}
|
|
|
|
bool requiresParkingForCommand(char name) {
|
|
return name == 'p' ||
|
|
name == 'u' ||
|
|
name == 'd' ||
|
|
name == 'a' ||
|
|
name == 'c' ||
|
|
name == 'r';
|
|
}
|
|
|
|
void saveCurrentPositionCommand() {
|
|
currentPosMs = clampPosition(currentPosMs);
|
|
targetPosMs = currentPosMs;
|
|
|
|
storedSeatPositionMs = (uint16_t)currentPosMs;
|
|
writeUint16(EEPROM_SEAT_POSITION_ADDR, storedSeatPositionMs);
|
|
manualMode = true;
|
|
targetPosMs = currentPosMs;
|
|
printStatus(F("CURRENT_POSITION_SAVED"));
|
|
}
|
|
|
|
void handleRelativeStep(int direction) {
|
|
long nextTarget = currentPosMs + (direction * MANUAL_STEP_MS);
|
|
if (nextTarget < 0 || nextTarget > SEAT_HARD_LIMIT_UP_MS) {
|
|
Serial.print(F("WARN: ignored. Requested target "));
|
|
Serial.print(nextTarget);
|
|
Serial.print(F("ms is outside 0.."));
|
|
Serial.print(SEAT_HARD_LIMIT_UP_MS);
|
|
Serial.println(F("ms."));
|
|
printStatus(F("ACK"));
|
|
return;
|
|
}
|
|
|
|
manualMode = true;
|
|
targetPosMs = nextTarget;
|
|
manualStepStatusPending = true;
|
|
}
|
|
|
|
void updateManualStepStatus() {
|
|
if (!manualStepStatusPending) {
|
|
return;
|
|
}
|
|
|
|
if (currentPosMs == targetPosMs && requestedSeatAction == 0 && currentSeatAction == 0) {
|
|
manualStepStatusPending = false;
|
|
printStatus(F("MANUAL_STEP_DONE"));
|
|
}
|
|
}
|
|
|
|
long clampPosition(long value) {
|
|
if (value < 0) {
|
|
return 0;
|
|
}
|
|
if (value > SEAT_HARD_LIMIT_UP_MS) {
|
|
return SEAT_HARD_LIMIT_UP_MS;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
void normalizeMotionState() {
|
|
currentPosMs = clampPosition(currentPosMs);
|
|
targetPosMs = clampPosition(targetPosMs);
|
|
|
|
if (storedSeatPositionMs > SEAT_HARD_LIMIT_UP_MS) {
|
|
storedSeatPositionMs = SEAT_HARD_LIMIT_UP_MS;
|
|
}
|
|
|
|
if (targetPosMs != 0 && downEdgeMarginActive) {
|
|
downEdgeMarginActive = false;
|
|
downEdgeMarginTime = DOWN_EDGE_MARGIN_MS;
|
|
}
|
|
|
|
if (currentPosMs <= targetPosMs) {
|
|
downSpeedRemainder = 0;
|
|
}
|
|
}
|
|
|
|
void updateDebugOutput(unsigned long currentTime) {
|
|
if (!debugEnabled) {
|
|
return;
|
|
}
|
|
|
|
if (lastDebugPrintTime == 0 || currentTime - lastDebugPrintTime >= DEBUG_INTERVAL_MS) {
|
|
lastDebugPrintTime = currentTime;
|
|
printStatus(F("DEBUG"));
|
|
}
|
|
}
|
|
|
|
void loadSettings() {
|
|
if (EEPROM.read(EEPROM_MAGIC_ADDR) != EEPROM_MAGIC_VALUE) {
|
|
EEPROM.update(EEPROM_MAGIC_ADDR, EEPROM_MAGIC_VALUE);
|
|
EEPROM.update(EEPROM_USE_COUNT_ADDR, 0);
|
|
writeUint16(EEPROM_SEAT_POSITION_ADDR, SEAT_HARD_LIMIT_UP_MS);
|
|
}
|
|
|
|
useCount = EEPROM.read(EEPROM_USE_COUNT_ADDR);
|
|
if (useCount > USES_BEFORE_AUTO_CALIBRATION) {
|
|
useCount = 0;
|
|
EEPROM.update(EEPROM_USE_COUNT_ADDR, useCount);
|
|
}
|
|
autoCalibrationPending = (useCount >= USES_BEFORE_AUTO_CALIBRATION);
|
|
|
|
storedSeatPositionMs = readUint16(EEPROM_SEAT_POSITION_ADDR);
|
|
if (storedSeatPositionMs > SEAT_HARD_LIMIT_UP_MS) {
|
|
storedSeatPositionMs = SEAT_HARD_LIMIT_UP_MS;
|
|
writeUint16(EEPROM_SEAT_POSITION_ADDR, storedSeatPositionMs);
|
|
}
|
|
}
|
|
|
|
uint16_t readUint16(int addr) {
|
|
byte lowByte = EEPROM.read(addr);
|
|
byte highByte = EEPROM.read(addr + 1);
|
|
return (uint16_t)lowByte | ((uint16_t)highByte << 8);
|
|
}
|
|
|
|
void writeUint16(int addr, uint16_t value) {
|
|
EEPROM.update(addr, value & 0xFF);
|
|
EEPROM.update(addr + 1, (value >> 8) & 0xFF);
|
|
}
|
|
|
|
void printIntro() {
|
|
Serial.println();
|
|
Serial.println(F("+--------------------------------------------------+"));
|
|
Serial.println(F("| Auto Seat Serial Console |"));
|
|
Serial.println(F("+--------------------------------------------------+"));
|
|
Serial.println(F("| Units: milliseconds. 0 = bottom. 6000 = top cap. |"));
|
|
Serial.println(F("| Normal auto move target is saved in EEPROM. |"));
|
|
Serial.println(F("| Action commands require gear P for safety. |"));
|
|
Serial.println(F("| Serial output is quiet unless a command is used. |"));
|
|
Serial.println(F("+--------------------------------------------------+"));
|
|
Serial.println(F("Commands:"));
|
|
Serial.println(F(" s Print current state once"));
|
|
Serial.println(F(" p Save current position to EEPROM"));
|
|
Serial.println(F(" u Manual up +500ms if inside 0..6000"));
|
|
Serial.println(F(" d Manual down -500ms if inside 0..6000"));
|
|
Serial.println(F(" g Debug every 1s; only x works in debug"));
|
|
Serial.println(F(" x Stop debug mode only"));
|
|
Serial.println(F(" d=down, g=debug to avoid command overlap"));
|
|
Serial.println(F(" a Return to gear-based automatic target"));
|
|
Serial.println(F(" c Run calibration now: up 7s, down 6s, set 0"));
|
|
Serial.println(F(" r Clear 10-use auto calibration counter"));
|
|
Serial.println(F(" h Print this help"));
|
|
Serial.println(F("+--------------------------------------------------+"));
|
|
printStatus(F("CURRENT_SETTINGS"));
|
|
}
|
|
|
|
void printStatus(const __FlashStringHelper *tag) {
|
|
Serial.println();
|
|
Serial.print(F("["));
|
|
Serial.print(tag);
|
|
Serial.println(F("]"));
|
|
Serial.print(F("raw="));
|
|
Serial.print(parkingRawValue);
|
|
Serial.print(F(" ig="));
|
|
Serial.print(ignitionState == HIGH ? 1 : 0);
|
|
Serial.print(F(" p="));
|
|
Serial.print(parkingState == HIGH ? 1 : 0);
|
|
Serial.print(F(" rawDrive="));
|
|
Serial.print(getRawDriveMode() == HIGH ? 1 : 0);
|
|
Serial.print(F(" confirmedDrive="));
|
|
Serial.println(confirmedDriveMode == HIGH ? 1 : 0);
|
|
|
|
Serial.print(F("currentMs="));
|
|
Serial.print(currentPosMs);
|
|
Serial.print(F(" targetMs="));
|
|
Serial.print(targetPosMs);
|
|
Serial.print(F(" savedPositionMs="));
|
|
Serial.print(storedSeatPositionMs);
|
|
Serial.print(F(" hardLimitMs="));
|
|
Serial.println(SEAT_HARD_LIMIT_UP_MS);
|
|
|
|
Serial.print(F("requestedRelay="));
|
|
Serial.print(requestedSeatAction);
|
|
Serial.print(F(" actualRelay="));
|
|
Serial.print(currentSeatAction);
|
|
Serial.print(F(" manualMode="));
|
|
Serial.print(manualMode ? 1 : 0);
|
|
Serial.print(F(" stabilizing="));
|
|
Serial.println(isStabilizing ? 1 : 0);
|
|
|
|
Serial.print(F("useCount="));
|
|
Serial.print(useCount);
|
|
Serial.print(F("/"));
|
|
Serial.print(USES_BEFORE_AUTO_CALIBRATION);
|
|
Serial.print(F(" autoPending="));
|
|
Serial.print(autoCalibrationPending ? 1 : 0);
|
|
Serial.print(F(" forceCal="));
|
|
Serial.print(forceCalibration ? 1 : 0);
|
|
Serial.print(F(" autoCalState="));
|
|
Serial.println(autoCalibrationState);
|
|
}
|
|
|
|
void setRelay(int relayPin, boolean state) {
|
|
digitalWrite(relayPin, state ? LOW : HIGH);
|
|
}
|
|
|
|
void seat(int action) {
|
|
requestedSeatAction = action;
|
|
}
|
|
|
|
void updateRelayOutput(unsigned long currentTime) {
|
|
if (requestedSeatAction == currentSeatAction) {
|
|
applySeatAction(currentSeatAction);
|
|
return;
|
|
}
|
|
|
|
if (currentSeatAction != 0) {
|
|
lastStoppedSeatAction = currentSeatAction;
|
|
currentSeatAction = 0;
|
|
relayDeadtimeStartTime = currentTime;
|
|
applySeatAction(0);
|
|
return;
|
|
}
|
|
|
|
bool sameDirectionResume = requestedSeatAction != 0 && requestedSeatAction == lastStoppedSeatAction;
|
|
bool deadtimeDone = currentTime - relayDeadtimeStartTime >= RELAY_DEADTIME_MS;
|
|
if (sameDirectionResume || deadtimeDone) {
|
|
currentSeatAction = requestedSeatAction;
|
|
}
|
|
|
|
applySeatAction(currentSeatAction);
|
|
}
|
|
|
|
void applySeatAction(int action) {
|
|
if (action == 1) {
|
|
setRelay(seatRelayD8, 1);
|
|
setRelay(seatRelayD9, 0);
|
|
} else if (action == -1) {
|
|
setRelay(seatRelayD8, 0);
|
|
setRelay(seatRelayD9, 1);
|
|
} else {
|
|
setRelay(seatRelayD8, 0);
|
|
setRelay(seatRelayD9, 0);
|
|
}
|
|
}
|