mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-12-24 21:21:24 +01:00
Merge branch 'autopower'
This commit is contained in:
commit
65697edb22
40
DCC.cpp
40
DCC.cpp
@ -247,9 +247,14 @@ const ackOp PROGMEM READ_CV_PROG[] = {
|
|||||||
// each bit is validated against 0 and the result inverted in MERGE
|
// each bit is validated against 0 and the result inverted in MERGE
|
||||||
// this is because there tend to be more zeros in cv values than ones.
|
// this is because there tend to be more zeros in cv values than ones.
|
||||||
// There is no need for one validation as entire byte is validated at the end
|
// There is no need for one validation as entire byte is validated at the end
|
||||||
V0, WACK, MERGE, // read and merge bit 0
|
V0, WACK, MERGE, // read and merge first tested bit (7)
|
||||||
V0, WACK, MERGE, // read and merge bit 1 etc
|
ITSKIP, // do small excursion if there was no ack
|
||||||
V0, WACK, MERGE,
|
SETBIT,(ackOp)7,
|
||||||
|
V1, WACK, NAKFAIL, // test if there is an ack on the inverse of this bit (7)
|
||||||
|
SETBIT,(ackOp)6, // and abort whole test if not else continue with bit (6)
|
||||||
|
SKIPTARGET,
|
||||||
|
V0, WACK, MERGE, // read and merge second tested bit (6)
|
||||||
|
V0, WACK, MERGE, // read and merge third tested bit (5) ...
|
||||||
V0, WACK, MERGE,
|
V0, WACK, MERGE,
|
||||||
V0, WACK, MERGE,
|
V0, WACK, MERGE,
|
||||||
V0, WACK, MERGE,
|
V0, WACK, MERGE,
|
||||||
@ -494,13 +499,13 @@ void DCC::ackManagerSetup(int cv, byte byteValueOrBitnum, ackOp const program[]
|
|||||||
const byte RESET_MIN=8; // tuning of reset counter before sending message
|
const byte RESET_MIN=8; // tuning of reset counter before sending message
|
||||||
|
|
||||||
// checkRessets return true if the caller should yield back to loop and try later.
|
// checkRessets return true if the caller should yield back to loop and try later.
|
||||||
bool DCC::checkResets(bool blocking) {
|
bool DCC::checkResets(bool blocking, uint8_t numResets) {
|
||||||
if (blocking) {
|
if (blocking) {
|
||||||
// must block waiting for restest to be issued
|
// must block waiting for restest to be issued
|
||||||
while(DCCWaveform::progTrack.sentResetsSincePacket < RESET_MIN);
|
while(DCCWaveform::progTrack.sentResetsSincePacket < numResets);
|
||||||
return false; // caller need not yield
|
return false; // caller need not yield
|
||||||
}
|
}
|
||||||
return DCCWaveform::progTrack.sentResetsSincePacket < RESET_MIN;
|
return DCCWaveform::progTrack.sentResetsSincePacket < numResets;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DCC::ackManagerLoop(bool blocking) {
|
void DCC::ackManagerLoop(bool blocking) {
|
||||||
@ -513,13 +518,19 @@ void DCC::ackManagerLoop(bool blocking) {
|
|||||||
// if blocking then we must ONLY return AFTER callback issued
|
// if blocking then we must ONLY return AFTER callback issued
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case BASELINE:
|
case BASELINE:
|
||||||
if (checkResets(blocking)) return;
|
if (DCCWaveform::progTrack.getPowerMode() == POWERMODE::OFF) {
|
||||||
|
DCCWaveform::progTrack.setPowerMode(POWERMODE::ON);
|
||||||
|
DCCWaveform::progTrack.sentResetsSincePacket = 0;
|
||||||
|
DCCWaveform::progTrack.autoPowerOff=true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (checkResets(blocking, DCCWaveform::progTrack.autoPowerOff ? 20 : 3)) return;
|
||||||
DCCWaveform::progTrack.setAckBaseline(debugMode);
|
DCCWaveform::progTrack.setAckBaseline(debugMode);
|
||||||
break;
|
break;
|
||||||
case W0: // write 0 bit
|
case W0: // write 0 bit
|
||||||
case W1: // write 1 bit
|
case W1: // write 1 bit
|
||||||
{
|
{
|
||||||
if (checkResets(blocking)) return;
|
if (checkResets(blocking, RESET_MIN)) return;
|
||||||
if (debugMode) DIAG(F("\nW%d cv=%d bit=%d"),opcode==W1, ackManagerCv,ackManagerBitNum);
|
if (debugMode) DIAG(F("\nW%d cv=%d bit=%d"),opcode==W1, ackManagerCv,ackManagerBitNum);
|
||||||
byte instruction = WRITE_BIT | (opcode==W1 ? BIT_ON : BIT_OFF) | ackManagerBitNum;
|
byte instruction = WRITE_BIT | (opcode==W1 ? BIT_ON : BIT_OFF) | ackManagerBitNum;
|
||||||
byte message[] = {cv1(BIT_MANIPULATE, ackManagerCv), cv2(ackManagerCv), instruction };
|
byte message[] = {cv1(BIT_MANIPULATE, ackManagerCv), cv2(ackManagerCv), instruction };
|
||||||
@ -530,7 +541,7 @@ void DCC::ackManagerLoop(bool blocking) {
|
|||||||
|
|
||||||
case WB: // write byte
|
case WB: // write byte
|
||||||
{
|
{
|
||||||
if (checkResets(blocking)) return;
|
if (checkResets(blocking, RESET_MIN)) return;
|
||||||
if (debugMode) DIAG(F("\nWB cv=%d value=%d"),ackManagerCv,ackManagerByte);
|
if (debugMode) DIAG(F("\nWB cv=%d value=%d"),ackManagerCv,ackManagerByte);
|
||||||
byte message[] = {cv1(WRITE_BYTE, ackManagerCv), cv2(ackManagerCv), ackManagerByte};
|
byte message[] = {cv1(WRITE_BYTE, ackManagerCv), cv2(ackManagerCv), ackManagerByte};
|
||||||
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS);
|
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS);
|
||||||
@ -540,7 +551,7 @@ void DCC::ackManagerLoop(bool blocking) {
|
|||||||
|
|
||||||
case VB: // Issue validate Byte packet
|
case VB: // Issue validate Byte packet
|
||||||
{
|
{
|
||||||
if (checkResets(blocking)) return;
|
if (checkResets(blocking, RESET_MIN)) return;
|
||||||
if (debugMode) DIAG(F("\nVB cv=%d value=%d"),ackManagerCv,ackManagerByte);
|
if (debugMode) DIAG(F("\nVB cv=%d value=%d"),ackManagerCv,ackManagerByte);
|
||||||
byte message[] = { cv1(VERIFY_BYTE, ackManagerCv), cv2(ackManagerCv), ackManagerByte};
|
byte message[] = { cv1(VERIFY_BYTE, ackManagerCv), cv2(ackManagerCv), ackManagerByte};
|
||||||
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS);
|
DCCWaveform::progTrack.schedulePacket(message, sizeof(message), PROG_REPEATS);
|
||||||
@ -551,7 +562,7 @@ void DCC::ackManagerLoop(bool blocking) {
|
|||||||
case V0:
|
case V0:
|
||||||
case V1: // Issue validate bit=0 or bit=1 packet
|
case V1: // Issue validate bit=0 or bit=1 packet
|
||||||
{
|
{
|
||||||
if (checkResets(blocking)) return;
|
if (checkResets(blocking, RESET_MIN)) return;
|
||||||
if (debugMode) DIAG(F("\nV%d cv=%d bit=%d"),opcode==V1, ackManagerCv,ackManagerBitNum);
|
if (debugMode) DIAG(F("\nV%d cv=%d bit=%d"),opcode==V1, ackManagerCv,ackManagerBitNum);
|
||||||
byte instruction = VERIFY_BIT | (opcode==V0?BIT_OFF:BIT_ON) | ackManagerBitNum;
|
byte instruction = VERIFY_BIT | (opcode==V0?BIT_OFF:BIT_ON) | ackManagerBitNum;
|
||||||
byte message[] = {cv1(BIT_MANIPULATE, ackManagerCv), cv2(ackManagerCv), instruction };
|
byte message[] = {cv1(BIT_MANIPULATE, ackManagerCv), cv2(ackManagerCv), instruction };
|
||||||
@ -577,6 +588,7 @@ void DCC::ackManagerLoop(bool blocking) {
|
|||||||
case ITC1: // If True Callback(0 or 1) (if prevous WACK got an ACK)
|
case ITC1: // If True Callback(0 or 1) (if prevous WACK got an ACK)
|
||||||
if (ackReceived) {
|
if (ackReceived) {
|
||||||
ackManagerProg = NULL; // all done now
|
ackManagerProg = NULL; // all done now
|
||||||
|
DCCWaveform::progTrack.doAutoPowerOff();
|
||||||
callback(opcode==ITC0?0:1);
|
callback(opcode==ITC0?0:1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -585,6 +597,7 @@ void DCC::ackManagerLoop(bool blocking) {
|
|||||||
case ITCB: // If True callback(byte)
|
case ITCB: // If True callback(byte)
|
||||||
if (ackReceived) {
|
if (ackReceived) {
|
||||||
ackManagerProg = NULL; // all done now
|
ackManagerProg = NULL; // all done now
|
||||||
|
DCCWaveform::progTrack.doAutoPowerOff();
|
||||||
callback(ackManagerByte);
|
callback(ackManagerByte);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -593,6 +606,7 @@ void DCC::ackManagerLoop(bool blocking) {
|
|||||||
case NAKFAIL: // If nack callback(-1)
|
case NAKFAIL: // If nack callback(-1)
|
||||||
if (!ackReceived) {
|
if (!ackReceived) {
|
||||||
ackManagerProg = NULL; // all done now
|
ackManagerProg = NULL; // all done now
|
||||||
|
DCCWaveform::progTrack.doAutoPowerOff();
|
||||||
callback(-1);
|
callback(-1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -600,7 +614,8 @@ void DCC::ackManagerLoop(bool blocking) {
|
|||||||
|
|
||||||
case FAIL: // callback(-1)
|
case FAIL: // callback(-1)
|
||||||
ackManagerProg = NULL;
|
ackManagerProg = NULL;
|
||||||
callback(-1);
|
DCCWaveform::progTrack.doAutoPowerOff();
|
||||||
|
callback(-1);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case STARTMERGE:
|
case STARTMERGE:
|
||||||
@ -632,6 +647,7 @@ void DCC::ackManagerLoop(bool blocking) {
|
|||||||
case COMBINELOCOID:
|
case COMBINELOCOID:
|
||||||
// ackManagerStash is cv17, ackManagerByte is CV 18
|
// ackManagerStash is cv17, ackManagerByte is CV 18
|
||||||
ackManagerProg=NULL;
|
ackManagerProg=NULL;
|
||||||
|
DCCWaveform::progTrack.doAutoPowerOff();
|
||||||
callback( ackManagerByte + ((ackManagerStash - 192) << 8));
|
callback( ackManagerByte + ((ackManagerStash - 192) << 8));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
2
DCC.h
2
DCC.h
@ -120,7 +120,7 @@ private:
|
|||||||
static ACK_CALLBACK ackManagerCallback;
|
static ACK_CALLBACK ackManagerCallback;
|
||||||
static void ackManagerSetup(int cv, byte bitNumOrbyteValue, ackOp const program[], ACK_CALLBACK callback, bool blocking);
|
static void ackManagerSetup(int cv, byte bitNumOrbyteValue, ackOp const program[], ACK_CALLBACK callback, bool blocking);
|
||||||
static void ackManagerLoop(bool blocking);
|
static void ackManagerLoop(bool blocking);
|
||||||
static bool checkResets(bool blocking);
|
static bool checkResets(bool blocking, uint8_t numResets);
|
||||||
static const int PROG_REPEATS=8; // repeats of programming commands (some decoders need at least 8 to be reliable)
|
static const int PROG_REPEATS=8; // repeats of programming commands (some decoders need at least 8 to be reliable)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* © 2020, Chris Harlow. All rights reserved.
|
* © 2020, Chris Harlow. All rights reserved.
|
||||||
|
* © 2020, Harald Barth.
|
||||||
*
|
*
|
||||||
* This file is part of Asbelos DCC API
|
* This file is part of Asbelos DCC API
|
||||||
*
|
*
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* © 2020, Chris Harlow. All rights reserved.
|
* © 2020, Chris Harlow. All rights reserved.
|
||||||
|
* © 2020, Harald Barth.
|
||||||
*
|
*
|
||||||
* This file is part of Asbelos DCC API
|
* This file is part of Asbelos DCC API
|
||||||
*
|
*
|
||||||
@ -60,10 +61,17 @@ class DCCWaveform {
|
|||||||
void schedulePacket(const byte buffer[], byte byteCount, byte repeats);
|
void schedulePacket(const byte buffer[], byte byteCount, byte repeats);
|
||||||
volatile bool packetPending;
|
volatile bool packetPending;
|
||||||
volatile byte sentResetsSincePacket;
|
volatile byte sentResetsSincePacket;
|
||||||
|
volatile bool autoPowerOff=false;
|
||||||
void setAckBaseline(bool debug); //prog track only
|
void setAckBaseline(bool debug); //prog track only
|
||||||
void setAckPending(bool debug); //prog track only
|
void setAckPending(bool debug); //prog track only
|
||||||
byte getAck(bool debug); //prog track only 0=NACK, 1=ACK 2=keep waiting
|
byte getAck(bool debug); //prog track only 0=NACK, 1=ACK 2=keep waiting
|
||||||
static bool progTrackSyncMain; // true when prog track is a siding switched to main
|
static bool progTrackSyncMain; // true when prog track is a siding switched to main
|
||||||
|
inline void doAutoPowerOff() {
|
||||||
|
if (autoPowerOff) {
|
||||||
|
setPowerMode(POWERMODE::OFF);
|
||||||
|
autoPowerOff=false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static VirtualTimer * interruptTimer;
|
static VirtualTimer * interruptTimer;
|
||||||
|
Loading…
Reference in New Issue
Block a user