From dc7860f743ee34c1009c0b88feff1a7b42ce204d Mon Sep 17 00:00:00 2001 From: Andrey Baboshin Date: Thu, 28 Dec 2023 00:07:17 +0100 Subject: [PATCH] feat: a servo turnout directly connected to a gpio pin --- PinServoTurnout.cpp | 133 ++++++++++++++++++++++++++++++++++++++++++++ PinServoTurnout.h | 59 ++++++++++++++++++++ Turnouts.h | 46 +++++++-------- 3 files changed, 216 insertions(+), 22 deletions(-) create mode 100644 PinServoTurnout.cpp create mode 100644 PinServoTurnout.h diff --git a/PinServoTurnout.cpp b/PinServoTurnout.cpp new file mode 100644 index 0000000..f1f17da --- /dev/null +++ b/PinServoTurnout.cpp @@ -0,0 +1,133 @@ +/* + * © 2023 Andrey Baboshin + * All rights reserved. + * + * This file is part of CommandStation-EX + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * It is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CommandStation. If not, see . + */ + +#include "defines.h" // includes config.h +#ifndef DISABLE_EEPROM +#include "EEStore.h" +#endif + +#include "PinServoTurnout.h" + +/************************************************************************************* + * PinServoTurnout - Turnout controlled by servo device connected to a processor pin. + * + *************************************************************************************/ + +// Private Constructor +PinServoTurnout::PinServoTurnout(uint16_t id, VPIN vpin, uint16_t thrownPosition, uint16_t closedPosition, uint8_t profile, bool closed) : Turnout(id, TURNOUT_SERVO, closed) +{ + _servoTurnoutData.vpin = vpin; + _servoTurnoutData.thrownPosition = thrownPosition; + _servoTurnoutData.closedPosition = closedPosition; + _servoTurnoutData.profile = profile; +} + +// Create function +/* static */ Turnout *PinServoTurnout::create(uint16_t id, VPIN vpin, uint16_t thrownPosition, uint16_t closedPosition, uint8_t profile, bool closed) +{ +#ifndef IO_NO_HAL + Turnout *tt = get(id); + if (tt) + { + // Object already exists, check if it is usable + if (tt->isType(TURNOUT_PIN)) + { + // Yes, so set parameters + PinServoTurnout *st = (PinServoTurnout *)tt; + st->_servoTurnoutData.vpin = vpin; + st->_servoTurnoutData.thrownPosition = thrownPosition; + st->_servoTurnoutData.closedPosition = closedPosition; + st->_servoTurnoutData.profile = profile; + // Don't touch the _closed parameter, retain the original value. + + st->servo.attach(vpin); + st->servo.write(closed ? closedPosition : thrownPosition); + + return tt; + } + else + { + // Incompatible object, delete and recreate + remove(id); + } + } + PinServoTurnout* ttnew = new PinServoTurnout(id, vpin, thrownPosition, closedPosition, profile, closed); + DIAG(F("PinServoTurnout 0x%x size %d size %d"), tt, sizeof(Turnout), sizeof(struct TurnoutData)); + + ttnew->servo.attach(vpin); + ttnew->servo.write(closed ? closedPosition : thrownPosition); + return (Turnout *)ttnew; +#else + (void)id; + (void)vpin; + (void)thrownPosition; + (void)closedPosition; + (void)profile; + (void)closed; // avoid compiler warnings. + return NULL; +#endif +} + +// Load a Pin Servo turnout definition from EEPROM. The common Turnout data has already been read at this point. +Turnout *PinServoTurnout::load(struct TurnoutData *turnoutData) +{ +#ifndef DISABLE_EEPROM + PinServoTurnoutData servoTurnoutData; + // Read class-specific data from EEPROM + EEPROM.get(EEStore::pointer(), servoTurnoutData); + EEStore::advance(sizeof(servoTurnoutData)); + + // Create new object + Turnout *tt = PinServoTurnout::create(turnoutData->id, servoTurnoutData.vpin, servoTurnoutData.thrownPosition, + servoTurnoutData.closedPosition, servoTurnoutData.profile, turnoutData->closed); + return tt; +#else + (void)turnoutData; + return NULL; +#endif +} + +// For DCC++ classic compatibility, state reported to JMRI is 1 for thrown and 0 for closed +void PinServoTurnout::print(Print *stream) +{ + StringFormatter::send(stream, F("\n"), _turnoutData.id, _servoTurnoutData.vpin, + _servoTurnoutData.thrownPosition, _servoTurnoutData.closedPosition, _servoTurnoutData.profile, + !_turnoutData.closed); +} + +// ServoTurnout-specific code for throwing or closing a servo turnout. +bool PinServoTurnout::setClosedInternal(bool close) +{ + servo.write(close ? _servoTurnoutData.closedPosition : _servoTurnoutData.thrownPosition); + return true; +} + +void PinServoTurnout::save() +{ +#ifndef DISABLE_EEPROM + // Write turnout definition and current position to EEPROM + // First write common servo data, then + // write the servo-specific data + EEPROM.put(EEStore::pointer(), _turnoutData); + EEStore::advance(sizeof(_turnoutData)); + EEPROM.put(EEStore::pointer(), _servoTurnoutData); + EEStore::advance(sizeof(_servoTurnoutData)); +#endif +} diff --git a/PinServoTurnout.h b/PinServoTurnout.h new file mode 100644 index 0000000..b2dc443 --- /dev/null +++ b/PinServoTurnout.h @@ -0,0 +1,59 @@ +/* + * © 2023 Andrey Baboshin + * All rights reserved. + * + * This file is part of CommandStation-EX + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * It is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CommandStation. If not, see . + */ + +#ifndef IO_PINSERVO_H +#define IO_PINSERVO_H + +#include "Turnouts.h" +#include + +class PinServoTurnout : public Turnout +{ +private: + // PinServoTurnoutData contains data specific to this subclass that is + // written to EEPROM when the turnout is saved. + struct PinServoTurnoutData + { + VPIN vpin; + uint16_t closedPosition; + uint16_t thrownPosition; + uint8_t profile; + } _servoTurnoutData; // 6 bytes + + Servo servo; + + // Constructor + PinServoTurnout(uint16_t id, VPIN vpin, uint16_t thrownPosition, uint16_t closedPosition, uint8_t profile, bool closed); + +public: + // Create function + static Turnout *create(uint16_t id, VPIN vpin, uint16_t thrownPosition, uint16_t closedPosition, uint8_t profile, bool closed = true); + + // Load a Servo turnout definition from EEPROM. The common Turnout data has already been read at this point. + static Turnout *load(struct TurnoutData *turnoutData); + void print(Print *stream) override; + +protected: + // PinServoTurnout-specific code for throwing or closing a servo turnout. + bool setClosedInternal(bool close) override; + void save() override; +}; + +#endif // IO_PINSERVO_H diff --git a/Turnouts.h b/Turnouts.h index 56b7f82..31a8d95 100644 --- a/Turnouts.h +++ b/Turnouts.h @@ -1,4 +1,5 @@ /* + * © 2023 Andrey Baboshin * © 2021 Neil McKechnie * © 2021 M Steve Todd * © 2021 Fred Decker @@ -6,7 +7,7 @@ * © 2020-2022 Chris Harlow * © 2013-2016 Gregg E. Berman * All rights reserved. - * + * * This file is part of CommandStation-EX * * This is free software: you can redistribute it and/or modify @@ -26,7 +27,7 @@ #ifndef TURNOUTS_H #define TURNOUTS_H -//#define EESTOREDEBUG +//#define EESTOREDEBUG #include "Arduino.h" #include "IODevice.h" #include "StringFormatter.h" @@ -37,20 +38,21 @@ enum { TURNOUT_SERVO = 2, TURNOUT_VPIN = 3, TURNOUT_LCN = 4, + TURNOUT_PIN = 5 }; /************************************************************************************* * Turnout - Base class for turnouts. - * + * *************************************************************************************/ class Turnout { protected: - /* + /* * Object data */ - // The TurnoutData struct contains data common to all turnout types, that + // The TurnoutData struct contains data common to all turnout types, that // is written to EEPROM when the turnout is saved. // The first byte of this struct contains the 'closed' flag which is // updated whenever the turnout changes from thrown to closed and @@ -71,7 +73,7 @@ protected: #ifndef DISABLE_EEPROM // Address in eeprom of first byte of the _turnoutData struct (containing the closed flag). - // Set to zero if the object has not been saved in EEPROM, e.g. for newly created Turnouts, and + // Set to zero if the object has not been saved in EEPROM, e.g. for newly created Turnouts, and // for all LCN turnouts. uint16_t _eepromAddress = 0; #endif @@ -90,35 +92,35 @@ protected: add(this); } - /* + /* * Static data - */ + */ static Turnout *_firstTurnout; static int _turnoutlistHash; - /* + /* * Virtual functions */ virtual bool setClosedInternal(bool close) = 0; // Mandatory in subclass virtual void save() {} - + /* * Static functions */ static void add(Turnout *tt); - + public: static Turnout *get(uint16_t id); - /* + /* * Static data */ static int turnoutlistHash; static const bool useClassicTurnoutCommands; - + /* * Public base class functions */ @@ -130,7 +132,7 @@ public: inline uint16_t getId() { return _turnoutData.id; } inline Turnout *next() { return _nextTurnout; } void printState(Print *stream); - /* + /* * Virtual functions */ virtual void print(Print *stream) { @@ -189,11 +191,11 @@ public: /************************************************************************************* * ServoTurnout - Turnout controlled by servo device. - * + * *************************************************************************************/ class ServoTurnout : public Turnout { private: - // ServoTurnoutData contains data specific to this subclass that is + // ServoTurnoutData contains data specific to this subclass that is // written to EEPROM when the turnout is saved. struct ServoTurnoutData { VPIN vpin; @@ -222,11 +224,11 @@ protected: /************************************************************************************* * DCCTurnout - Turnout controlled by DCC Accessory Controller. - * + * *************************************************************************************/ class DCCTurnout : public Turnout { private: - // DCCTurnoutData contains data specific to this subclass that is + // DCCTurnoutData contains data specific to this subclass that is // written to EEPROM when the turnout is saved. struct DCCTurnoutData { // DCC address (Address in bits 15-2, subaddress in bits 1-0) @@ -257,11 +259,11 @@ protected: /************************************************************************************* * VpinTurnout - Turnout controlled through a HAL vpin. - * + * *************************************************************************************/ class VpinTurnout : public Turnout { private: - // VpinTurnoutData contains data specific to this subclass that is + // VpinTurnoutData contains data specific to this subclass that is // written to EEPROM when the turnout is saved. struct VpinTurnoutData { VPIN vpin; @@ -287,7 +289,7 @@ protected: /************************************************************************************* * LCNTurnout - Turnout controlled by Loconet - * + * *************************************************************************************/ class LCNTurnout : public Turnout { private: @@ -295,7 +297,7 @@ private: // struct LCNTurnoutData { // } _lcnTurnoutData; // 0 bytes - // Constructor + // Constructor LCNTurnout(uint16_t id, bool closed); public: