mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-27 10:06:13 +01:00
Delay Turnout <H> response following movement.
This commit is contained in:
parent
0e78cf6e55
commit
8e6c232d05
|
@ -129,6 +129,7 @@ void DCCEXParser::loop(Stream &stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Sensor::checkAll(&stream); // Update and print changes
|
Sensor::checkAll(&stream); // Update and print changes
|
||||||
|
Turnout::loop(); // Check for outstanding turnout responses
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t DCCEXParser::splitValues(int16_t result[MAX_COMMAND_PARAMS], const byte *cmd)
|
int16_t DCCEXParser::splitValues(int16_t result[MAX_COMMAND_PARAMS], const byte *cmd)
|
||||||
|
|
92
Turnouts.cpp
92
Turnouts.cpp
|
@ -43,6 +43,8 @@
|
||||||
*/
|
*/
|
||||||
/* static */ int Turnout::turnoutlistHash = 0;
|
/* static */ int Turnout::turnoutlistHash = 0;
|
||||||
|
|
||||||
|
/* static */ unsigned long Turnout::_lastLoopEntry = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Protected static functions
|
* Protected static functions
|
||||||
*/
|
*/
|
||||||
|
@ -68,6 +70,48 @@
|
||||||
turnoutlistHash++;
|
turnoutlistHash++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ void Turnout::loop() {
|
||||||
|
// Here, we check whether the turnout state needs updating.
|
||||||
|
// For Servo and VPIN turnouts, we need to check the isBusy() status of the device
|
||||||
|
// and when it goes to 0 we can send out a turnout notification.
|
||||||
|
// We allow a small delay before we start checking isBusy(), to allow the
|
||||||
|
// operation time to start.
|
||||||
|
unsigned long currentMillis = millis();
|
||||||
|
// Check for updates once every 100ms.
|
||||||
|
if (currentMillis - _lastLoopEntry > 100) {
|
||||||
|
_lastLoopEntry = currentMillis;
|
||||||
|
|
||||||
|
Turnout *tt = _firstTurnout;
|
||||||
|
for ( ; tt != 0; tt=tt->_nextTurnout) {
|
||||||
|
if (tt->_delayResponse > 1) {
|
||||||
|
tt->_delayResponse--;
|
||||||
|
} else if (tt->_delayResponse == 1) {
|
||||||
|
// Pointer has been triggered and grace time has elapsed, so check if completed
|
||||||
|
if (!tt->isPending()) {
|
||||||
|
tt->sendResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function called when the turnout has changed.
|
||||||
|
void Turnout::sendResponse() {
|
||||||
|
turnoutlistHash++; // let withrottle know something changed
|
||||||
|
|
||||||
|
#if defined(RMFT_ACTIVE)
|
||||||
|
RMFT2::turnoutEvent(_turnoutData.id, _turnoutData.closed);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Send message to JMRI etc. over Serial USB. This is done here
|
||||||
|
// to ensure that the message is sent when the turnout operation
|
||||||
|
// is not initiated by a Serial command.
|
||||||
|
printState(&Serial);
|
||||||
|
|
||||||
|
// Clear flag pending operation
|
||||||
|
_delayResponse = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// For DCC++ classic compatibility, state reported to JMRI is 1 for thrown and 0 for closed;
|
// For DCC++ classic compatibility, state reported to JMRI is 1 for thrown and 0 for closed;
|
||||||
void Turnout::printState(Print *stream) {
|
void Turnout::printState(Print *stream) {
|
||||||
StringFormatter::send(stream, F("<H %d %d>\n"),
|
StringFormatter::send(stream, F("<H %d %d>\n"),
|
||||||
|
@ -139,24 +183,22 @@
|
||||||
if (!tt) return false;
|
if (!tt) return false;
|
||||||
bool ok = tt->setClosedInternal(closeFlag);
|
bool ok = tt->setClosedInternal(closeFlag);
|
||||||
|
|
||||||
|
// Check return value to see if this type of turnout is immediate
|
||||||
|
// or if we need to check for completion.
|
||||||
if (ok) {
|
if (ok) {
|
||||||
turnoutlistHash++; // let withrottle know something changed
|
tt->sendResponse();
|
||||||
|
} else {
|
||||||
// Write byte containing new closed/thrown state to EEPROM if required. Note that eepromAddress
|
// Set flag indicating that the operation is pending and needs to be checked for completion
|
||||||
// is always zero for LCN turnouts.
|
// starting in 4 loop counts (starts checking at 1).
|
||||||
if (EEStore::eeStore->data.nTurnouts > 0 && tt->_eepromAddress > 0)
|
tt->_delayResponse = 5;
|
||||||
EEPROM.put(tt->_eepromAddress, tt->_turnoutData.flags);
|
|
||||||
|
|
||||||
#if defined(RMFT_ACTIVE)
|
|
||||||
RMFT2::turnoutEvent(id, closeFlag);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Send message to JMRI etc. over Serial USB. This is done here
|
|
||||||
// to ensure that the message is sent when the turnout operation
|
|
||||||
// is not initiated by a Serial command.
|
|
||||||
tt->printState(&Serial);
|
|
||||||
}
|
}
|
||||||
return ok;
|
|
||||||
|
// Write byte containing new closed/thrown state to EEPROM if required. Note that eepromAddress
|
||||||
|
// is always zero for LCN turnouts.
|
||||||
|
if (EEStore::eeStore->data.nTurnouts > 0 && tt->_eepromAddress > 0)
|
||||||
|
EEPROM.put(tt->_eepromAddress, tt->_turnoutData.flags);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load all turnout objects
|
// Load all turnout objects
|
||||||
|
@ -301,10 +343,16 @@
|
||||||
IODevice::writeAnalogue(_servoTurnoutData.vpin,
|
IODevice::writeAnalogue(_servoTurnoutData.vpin,
|
||||||
close ? _servoTurnoutData.closedPosition : _servoTurnoutData.thrownPosition, _servoTurnoutData.profile);
|
close ? _servoTurnoutData.closedPosition : _servoTurnoutData.thrownPosition, _servoTurnoutData.profile);
|
||||||
_turnoutData.closed = close;
|
_turnoutData.closed = close;
|
||||||
|
return false; // Don't send update messages yet.
|
||||||
#else
|
#else
|
||||||
(void)close; // avoid compiler warnings
|
(void)close; // avoid compiler warnings
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if the turnout is moving into its new state.
|
||||||
|
bool ServoTurnout::isPending() {
|
||||||
|
return IODevice::isBusy(_servoTurnoutData.vpin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServoTurnout::save() {
|
void ServoTurnout::save() {
|
||||||
|
@ -458,12 +506,22 @@
|
||||||
!_turnoutData.closed);
|
!_turnoutData.closed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setClosedInternal is called from the base class's setClosed() method. It returns true if the
|
||||||
|
// operation is considered to be completed, and false if it is started but not completed.
|
||||||
|
// For VPINs which are attached to servos, we ought to return false so that the confirmation
|
||||||
|
// message to JMRI is deferred until the servo movement is completed. However, if we do this
|
||||||
|
// it will also affect VPINs that are GPIO pins; when it polls the pin it will put the pin into
|
||||||
|
// input mode, which is not desirable. Hence, we return true here so that no polling takes place.
|
||||||
bool VpinTurnout::setClosedInternal(bool close) {
|
bool VpinTurnout::setClosedInternal(bool close) {
|
||||||
IODevice::write(_vpinTurnoutData.vpin, close);
|
IODevice::write(_vpinTurnoutData.vpin, close);
|
||||||
_turnoutData.closed = close;
|
_turnoutData.closed = close;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VpinTurnout::isPending() {
|
||||||
|
return IODevice::isBusy(_vpinTurnoutData.vpin);
|
||||||
|
}
|
||||||
|
|
||||||
void VpinTurnout::save() {
|
void VpinTurnout::save() {
|
||||||
// Write turnout definition and current position to EEPROM
|
// Write turnout definition and current position to EEPROM
|
||||||
// First write common servo data, then
|
// First write common servo data, then
|
||||||
|
|
14
Turnouts.h
14
Turnouts.h
|
@ -72,6 +72,9 @@ protected:
|
||||||
// Pointer to next turnout on linked list.
|
// Pointer to next turnout on linked list.
|
||||||
Turnout *_nextTurnout = 0;
|
Turnout *_nextTurnout = 0;
|
||||||
|
|
||||||
|
// Delay counter for responses. If non-zero, there is a pending response to be sent.
|
||||||
|
uint8_t _delayResponse = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
|
@ -88,6 +91,7 @@ protected:
|
||||||
|
|
||||||
static Turnout *_firstTurnout;
|
static Turnout *_firstTurnout;
|
||||||
static int _turnoutlistHash;
|
static int _turnoutlistHash;
|
||||||
|
static unsigned long _lastLoopEntry;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Virtual functions
|
* Virtual functions
|
||||||
|
@ -95,6 +99,7 @@ protected:
|
||||||
|
|
||||||
virtual bool setClosedInternal(bool close) = 0; // Mandatory in subclass
|
virtual bool setClosedInternal(bool close) = 0; // Mandatory in subclass
|
||||||
virtual void save() {}
|
virtual void save() {}
|
||||||
|
virtual bool isPending() { return false; };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Static functions
|
* Static functions
|
||||||
|
@ -104,6 +109,11 @@ protected:
|
||||||
|
|
||||||
static void add(Turnout *tt);
|
static void add(Turnout *tt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Other functions
|
||||||
|
*/
|
||||||
|
void sendResponse();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*
|
/*
|
||||||
* Static data
|
* Static data
|
||||||
|
@ -155,6 +165,8 @@ public:
|
||||||
|
|
||||||
inline static Turnout *first() { return _firstTurnout; }
|
inline static Turnout *first() { return _firstTurnout; }
|
||||||
|
|
||||||
|
static void loop();
|
||||||
|
|
||||||
// Load all turnout definitions.
|
// Load all turnout definitions.
|
||||||
static void load();
|
static void load();
|
||||||
// Load one turnout definition
|
// Load one turnout definition
|
||||||
|
@ -201,6 +213,7 @@ protected:
|
||||||
// ServoTurnout-specific code for throwing or closing a servo turnout.
|
// ServoTurnout-specific code for throwing or closing a servo turnout.
|
||||||
bool setClosedInternal(bool close) override;
|
bool setClosedInternal(bool close) override;
|
||||||
void save() override;
|
void save() override;
|
||||||
|
bool isPending() override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -265,6 +278,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
bool setClosedInternal(bool close) override;
|
bool setClosedInternal(bool close) override;
|
||||||
void save() override;
|
void save() override;
|
||||||
|
bool isPending() override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user