Compare commits
1 Commits
2.0.6
...
ESP32-IRAM
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b175e9229 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
.development
|
||||
*.zip
|
||||
384
NmraDcc.cpp
384
NmraDcc.cpp
@@ -2,21 +2,11 @@
|
||||
//
|
||||
// Model Railroading with Arduino - NmraDcc.cpp
|
||||
//
|
||||
// Copyright (c) 2008 - 2020 Alex Shepherd
|
||||
// Copyright (c) 2008 - 2017 Alex Shepherd
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
// This source file is subject of the GNU general public license 2,
|
||||
// that is available at the world-wide-web at
|
||||
// http://www.gnu.org/licenses/gpl.txt
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
@@ -37,7 +27,7 @@
|
||||
// Minor fixes to pass NMRA Baseline Conformance Tests.
|
||||
// 2018-12-17 added ESP32 support by Trusty (thierry@lapajaparis.net)
|
||||
// 2019-02-17 added ESP32 specific changes by Hans Tanner
|
||||
// 2020-05-15 changes to pass NMRA Tests ( always search for preamble )
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// purpose: Provide a simplified interface to decode NMRA DCC packets
|
||||
@@ -46,10 +36,12 @@
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#include "NmraDcc.h"
|
||||
#include "EEPROM.h"
|
||||
#ifdef __AVR_MEGA__
|
||||
#include <avr/eeprom.h>
|
||||
#endif
|
||||
|
||||
// Uncomment to print DEBUG messages
|
||||
// #define DEBUG_PRINT
|
||||
//#define DEBUG_PRINT
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// DCC Receive Routine
|
||||
@@ -82,26 +74,19 @@
|
||||
// DCC 1: _________XXXXXXXXX_________XXXXXXXXX_________
|
||||
// |<--------146us------>|
|
||||
// ^-INTx ^-INTx
|
||||
// less than 146us: its a one-Bit
|
||||
// less than 138us: its a one-Bit
|
||||
//
|
||||
//
|
||||
// |<-----------------232us----------->|
|
||||
// DCC 0: _________XXXXXXXXXXXXXXXXXX__________________XXXXXXXX__________
|
||||
// |<--------146us------->|
|
||||
// ^-INTx ^-INTx
|
||||
// greater than 146us: its a zero bit
|
||||
// greater than 138us: its a zero bit
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// if this is commented out, bit synchronisation is only done after a wrong checksum
|
||||
#define SYNC_ALWAYS
|
||||
|
||||
// if this is commented out, Zero-Bit_Stretching is not supported
|
||||
// ( Bits longer than 2* MAX ONEBIT are treated as error )
|
||||
#define SUPPORT_ZERO_BIT_STRETCHING
|
||||
|
||||
#define MAX_ONEBITFULL 146
|
||||
#define MAX_PRAEAMBEL 146
|
||||
@@ -192,7 +177,7 @@
|
||||
#define SET_TP3 GPOS = (1 << D7);
|
||||
#define CLR_TP3 GPOC = (1 << D7);
|
||||
#define MODE_TP4 pinMode( D8,OUTPUT ) ; // GPIO 15
|
||||
#define SET_TP4 GPOS = (1 << D8);
|
||||
#define SET_TP4 GPOC = (1 << D8);
|
||||
#define CLR_TP4 GPOC = (1 << D8);
|
||||
#elif defined(ESP32)
|
||||
#define MODE_TP1 pinMode( 33,OUTPUT ) ; // GPIO 33
|
||||
@@ -205,7 +190,7 @@
|
||||
#define SET_TP3 GPOS = (1 << 26);
|
||||
#define CLR_TP3 GPOC = (1 << 26);
|
||||
#define MODE_TP4 pinMode( 27,OUTPUT ) ; // GPIO 27
|
||||
#define SET_TP4 GPOS = (1 << 27);
|
||||
#define SET_TP4 GPOC = (1 << 27);
|
||||
#define CLR_TP4 GPOC = (1 << 27);
|
||||
|
||||
|
||||
@@ -261,17 +246,12 @@ static byte ISRWatch; // Interrupt Handler Edge Filter
|
||||
static byte ISREdge; // Holder of the Next Edge we're looking for: RISING or FALLING
|
||||
static byte ISRWatch; // Interrupt Handler Edge Filter
|
||||
#endif
|
||||
byte ISRLevel; // expected Level at DCC input during ISR ( to detect glitches )
|
||||
byte ISRChkMask; // Flag if Level must be checked
|
||||
static word bitMax, bitMin;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
WAIT_PREAMBLE = 0,
|
||||
WAIT_START_BIT,
|
||||
#ifndef SYNC_ALWAYS
|
||||
WAIT_START_BIT_FULL,
|
||||
#endif
|
||||
WAIT_DATA,
|
||||
WAIT_END_BIT
|
||||
}
|
||||
@@ -292,7 +272,6 @@ struct DccRx_t
|
||||
uint8_t DataReady ;
|
||||
uint8_t BitCount ;
|
||||
uint8_t TempByte ;
|
||||
uint8_t chkSum;
|
||||
DCC_MSG PacketBuf;
|
||||
DCC_MSG PacketCopy;
|
||||
}
|
||||
@@ -309,8 +288,6 @@ typedef struct
|
||||
DCC_MSG LastMsg ;
|
||||
uint8_t ExtIntNum;
|
||||
uint8_t ExtIntPinNum;
|
||||
volatile uint8_t *ExtIntPort; // use port and bitmask to read input at AVR in ISR
|
||||
uint8_t ExtIntMask; // digitalRead is too slow on AVR
|
||||
int16_t myDccAddress; // Cached value of DCC Address from CVs
|
||||
uint8_t inAccDecDCCAddrNextReceivedMode;
|
||||
uint8_t cv29Value;
|
||||
@@ -334,8 +311,6 @@ void ICACHE_RAM_ATTR ExternalInterruptHandler(void)
|
||||
void ExternalInterruptHandler(void)
|
||||
#endif
|
||||
{
|
||||
SET_TP3;
|
||||
|
||||
#ifdef ESP32
|
||||
// switch (ISRWatch)
|
||||
// {
|
||||
@@ -363,7 +338,7 @@ void ExternalInterruptHandler(void)
|
||||
uint8_t DccBitVal;
|
||||
static int8_t bit1, bit2 ;
|
||||
static unsigned int lastMicros = 0;
|
||||
static byte halfBit, DCC_IrqRunning, preambleBitCount;
|
||||
static byte halfBit, DCC_IrqRunning;
|
||||
unsigned int actMicros, bitMicros;
|
||||
#ifdef ALLOW_NESTED_IRQ
|
||||
if ( DCC_IrqRunning ) {
|
||||
@@ -377,53 +352,17 @@ void ExternalInterruptHandler(void)
|
||||
return; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> abort IRQ
|
||||
}
|
||||
#endif
|
||||
SET_TP3;
|
||||
actMicros = micros();
|
||||
bitMicros = actMicros-lastMicros;
|
||||
|
||||
CLR_TP3; SET_TP3;
|
||||
#ifdef __AVR_MEGA__
|
||||
if ( bitMicros < bitMin || ( DccRx.State != WAIT_START_BIT && (*DccProcState.ExtIntPort & DccProcState.ExtIntMask) != (ISRLevel) ) ) {
|
||||
#else
|
||||
if ( bitMicros < bitMin || ( DccRx.State != WAIT_START_BIT && digitalRead( DccProcState.ExtIntPinNum ) != (ISRLevel) ) ) {
|
||||
#endif
|
||||
// too short - my be false interrupt due to glitch or false protocol or level does not match RISING / FALLING edge -> ignore this IRQ
|
||||
if ( bitMicros < bitMin ) {
|
||||
// too short - my be false interrupt due to glitch or false protocol -> ignore
|
||||
CLR_TP3;
|
||||
SET_TP4; /*delayMicroseconds(1); */ CLR_TP4;
|
||||
SET_TP4; CLR_TP4;
|
||||
return; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> abort IRQ
|
||||
}
|
||||
CLR_TP3; SET_TP3;
|
||||
|
||||
lastMicros = actMicros;
|
||||
#ifndef SUPPORT_ZERO_BIT_STRETCHING
|
||||
//if ( bitMicros > MAX_ZEROBITFULL ) {
|
||||
if ( bitMicros > (bitMax*2) ) {
|
||||
// too long - my be false protocol -> start over
|
||||
DccRx.State = WAIT_PREAMBLE ;
|
||||
DccRx.BitCount = 0 ;
|
||||
preambleBitCount = 0;
|
||||
// SET_TP2; CLR_TP2;
|
||||
bitMax = MAX_PRAEAMBEL;
|
||||
bitMin = MIN_ONEBITFULL;
|
||||
#if defined ( __STM32F1__ )
|
||||
detachInterrupt( DccProcState.ExtIntNum );
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
ISRWatch = ISREdge;
|
||||
#else
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
||||
#endif
|
||||
// enable level-checking
|
||||
ISRChkMask = DccProcState.ExtIntMask;
|
||||
ISRLevel = (ISREdge==RISING)? DccProcState.ExtIntMask : 0 ;
|
||||
CLR_TP3;
|
||||
//CLR_TP3;
|
||||
return; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> abort IRQ
|
||||
}
|
||||
CLR_TP3;
|
||||
SET_TP3;
|
||||
#endif
|
||||
|
||||
DccBitVal = ( bitMicros < bitMax );
|
||||
lastMicros = actMicros;
|
||||
|
||||
#ifdef ALLOW_NESTED_IRQ
|
||||
DCC_IrqRunning = true;
|
||||
@@ -433,37 +372,43 @@ void ExternalInterruptHandler(void)
|
||||
#ifdef DCC_DEBUG
|
||||
DccProcState.TickCount++;
|
||||
#endif
|
||||
|
||||
switch( DccRx.State )
|
||||
{
|
||||
case WAIT_PREAMBLE:
|
||||
// We don't have to do anything special - looking for a preamble condition is done always
|
||||
SET_TP2;
|
||||
break;
|
||||
if( DccBitVal )
|
||||
{
|
||||
SET_TP1;
|
||||
DccRx.BitCount++;
|
||||
if( DccRx.BitCount > 10 ) {
|
||||
DccRx.State = WAIT_START_BIT ;
|
||||
// While waiting for the start bit, detect halfbit lengths. We will detect the correct
|
||||
// sync and detect whether we see a false (e.g. motorola) protocol
|
||||
|
||||
#ifndef SYNC_ALWAYS
|
||||
case WAIT_START_BIT_FULL:
|
||||
// wait for startbit without level checking
|
||||
if ( !DccBitVal ) {
|
||||
// we got the startbit
|
||||
CLR_TP2;CLR_TP1;
|
||||
DccRx.State = WAIT_DATA ;
|
||||
#if defined ( __STM32F1__ )
|
||||
detachInterrupt( DccProcState.ExtIntNum );
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
ISRWatch = CHANGE;
|
||||
#else
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, CHANGE);
|
||||
#endif
|
||||
halfBit = 0;
|
||||
bitMax = MAX_ONEBITHALF;
|
||||
bitMin = MIN_ONEBITHALF;
|
||||
CLR_TP1;
|
||||
// initialize packet buffer
|
||||
DccRx.PacketBuf.Size = 0;
|
||||
/*for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ )
|
||||
DccRx.PacketBuf.Data[i] = 0;*/
|
||||
DccRx.PacketBuf.PreambleBits = preambleBitCount;
|
||||
}
|
||||
} else {
|
||||
SET_TP1;
|
||||
DccRx.BitCount = 0 ;
|
||||
DccRx.chkSum = 0 ;
|
||||
DccRx.TempByte = 0 ;
|
||||
//SET_TP1;
|
||||
CLR_TP1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case WAIT_START_BIT:
|
||||
// we are looking for first half "0" bit after preamble
|
||||
switch ( halfBit ) {
|
||||
case 0:
|
||||
case 0: //SET_TP1;
|
||||
// check first part
|
||||
if ( DccBitVal ) {
|
||||
// is still 1-bit (Preamble)
|
||||
@@ -471,22 +416,24 @@ void ExternalInterruptHandler(void)
|
||||
bit1=bitMicros;
|
||||
} else {
|
||||
// was "0" half bit, maybe the startbit
|
||||
SET_TP1;
|
||||
halfBit = 4;
|
||||
CLR_TP1;
|
||||
}
|
||||
break;
|
||||
case 1: // previous halfbit was '1'
|
||||
case 1: //SET_TP1; // previous halfbit was '1'
|
||||
if ( DccBitVal ) {
|
||||
// its a '1' halfBit -> we are still in the preamble
|
||||
halfBit = 0;
|
||||
bit2=bitMicros;
|
||||
preambleBitCount++;
|
||||
DccRx.BitCount++;
|
||||
if( abs(bit2-bit1) > MAX_BITDIFF ) {
|
||||
// the length of the 2 halfbits differ too much -> wrong protokoll
|
||||
DccRx.State = WAIT_PREAMBLE;
|
||||
bitMax = MAX_PRAEAMBEL;
|
||||
bitMin = MIN_ONEBITFULL;
|
||||
preambleBitCount = 0;
|
||||
// SET_TP2; CLR_TP2;
|
||||
DccRx.BitCount = 0;
|
||||
|
||||
#if defined ( __STM32F1__ )
|
||||
detachInterrupt( DccProcState.ExtIntNum );
|
||||
#endif
|
||||
@@ -494,9 +441,6 @@ void ExternalInterruptHandler(void)
|
||||
ISRWatch = ISREdge;
|
||||
#else
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
||||
// enable level checking ( with direct port reading @ AVR )
|
||||
ISRChkMask = DccProcState.ExtIntMask;
|
||||
ISRLevel = (ISREdge==RISING)? DccProcState.ExtIntMask : 0 ;
|
||||
#endif
|
||||
SET_TP3;
|
||||
CLR_TP4;
|
||||
@@ -509,33 +453,30 @@ void ExternalInterruptHandler(void)
|
||||
SET_TP3;
|
||||
}
|
||||
break;
|
||||
case 3: // previous halfbit was '0' in second halfbit
|
||||
case 3: //SET_TP1; // previous halfbit was '0' in second halfbit
|
||||
if ( DccBitVal ) {
|
||||
// its a '1' halfbit -> we got only a half '0' bit -> cannot be DCC
|
||||
DccRx.State = WAIT_PREAMBLE;
|
||||
bitMax = MAX_PRAEAMBEL;
|
||||
bitMin = MIN_ONEBITFULL;
|
||||
preambleBitCount = 0;
|
||||
// SET_TP2; CLR_TP2;
|
||||
DccRx.BitCount = 0;
|
||||
} else {
|
||||
// we got two '0' halfbits -> it's the startbit
|
||||
// but sync is NOT ok, change IRQ edge.
|
||||
CLR_TP2;CLR_TP1;
|
||||
if ( ISREdge == RISING ) ISREdge = FALLING; else ISREdge = RISING;
|
||||
DccRx.State = WAIT_DATA ;
|
||||
CLR_TP1;
|
||||
bitMax = MAX_ONEBITFULL;
|
||||
bitMin = MIN_ONEBITFULL;
|
||||
DccRx.PacketBuf.Size = 0;
|
||||
/*for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ )
|
||||
DccRx.PacketBuf.Data[i] = 0;*/
|
||||
DccRx.PacketBuf.PreambleBits = preambleBitCount;
|
||||
DccRx.PacketBuf.PreambleBits = 0;
|
||||
for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ )
|
||||
DccRx.PacketBuf.Data[i] = 0;
|
||||
|
||||
DccRx.PacketBuf.PreambleBits = DccRx.BitCount;
|
||||
DccRx.BitCount = 0 ;
|
||||
DccRx.chkSum = 0 ;
|
||||
DccRx.TempByte = 0 ;
|
||||
//SET_TP1;
|
||||
}
|
||||
//SET_TP4;
|
||||
SET_TP4;
|
||||
|
||||
#if defined ( __STM32F1__ )
|
||||
detachInterrupt( DccProcState.ExtIntNum );
|
||||
@@ -545,40 +486,34 @@ void ExternalInterruptHandler(void)
|
||||
#else
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
||||
#endif
|
||||
// enable level-checking
|
||||
ISRChkMask = DccProcState.ExtIntMask;
|
||||
ISRLevel = (ISREdge==RISING)? DccProcState.ExtIntMask : 0 ;
|
||||
//CLR_TP4;
|
||||
CLR_TP1;
|
||||
CLR_TP4;
|
||||
break;
|
||||
case 4: // previous (first) halfbit was 0
|
||||
case 4: SET_TP1; // previous (first) halfbit was 0
|
||||
// if this halfbit is 0 too, we got the startbit
|
||||
if ( DccBitVal ) {
|
||||
// second halfbit is 1 -> unknown protokoll
|
||||
DccRx.State = WAIT_PREAMBLE;
|
||||
bitMax = MAX_PRAEAMBEL;
|
||||
bitMin = MIN_ONEBITFULL;
|
||||
preambleBitCount = 0;
|
||||
CLR_TP2;CLR_TP1;
|
||||
DccRx.BitCount = 0;
|
||||
} else {
|
||||
// we got the startbit
|
||||
CLR_TP2;CLR_TP1;
|
||||
DccRx.State = WAIT_DATA ;
|
||||
CLR_TP1;
|
||||
bitMax = MAX_ONEBITFULL;
|
||||
bitMin = MIN_ONEBITFULL;
|
||||
// initialize packet buffer
|
||||
DccRx.PacketBuf.Size = 0;
|
||||
/*for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ )
|
||||
DccRx.PacketBuf.Data[i] = 0;*/
|
||||
DccRx.PacketBuf.PreambleBits = preambleBitCount;
|
||||
DccRx.PacketBuf.PreambleBits = 0;
|
||||
for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ )
|
||||
DccRx.PacketBuf.Data[i] = 0;
|
||||
|
||||
DccRx.PacketBuf.PreambleBits = DccRx.BitCount;
|
||||
DccRx.BitCount = 0 ;
|
||||
DccRx.chkSum = 0 ;
|
||||
DccRx.TempByte = 0 ;
|
||||
//SET_TP1;
|
||||
}
|
||||
|
||||
//SET_TP4;
|
||||
CLR_TP1;
|
||||
SET_TP4;
|
||||
|
||||
#if defined ( __STM32F1__ )
|
||||
detachInterrupt( DccProcState.ExtIntNum );
|
||||
@@ -588,18 +523,14 @@ void ExternalInterruptHandler(void)
|
||||
#else
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
||||
#endif
|
||||
// enable level-checking
|
||||
ISRChkMask = DccProcState.ExtIntMask;
|
||||
ISRLevel = (ISREdge==RISING)? DccProcState.ExtIntMask : 0 ;
|
||||
|
||||
//CLR_TP4;
|
||||
CLR_TP4;
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case WAIT_DATA:
|
||||
CLR_TP2;
|
||||
DccRx.BitCount++;
|
||||
DccRx.TempByte = ( DccRx.TempByte << 1 ) ;
|
||||
if( DccBitVal )
|
||||
@@ -618,44 +549,30 @@ void ExternalInterruptHandler(void)
|
||||
{
|
||||
DccRx.State = WAIT_END_BIT ;
|
||||
DccRx.PacketBuf.Data[ DccRx.PacketBuf.Size++ ] = DccRx.TempByte ;
|
||||
DccRx.chkSum ^= DccRx.TempByte;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WAIT_END_BIT:
|
||||
SET_TP2;CLR_TP2;
|
||||
DccRx.BitCount++;
|
||||
if( DccBitVal ) { // End of packet?
|
||||
CLR_TP3; SET_TP4;
|
||||
if( DccBitVal ) // End of packet?
|
||||
{
|
||||
CLR_TP3;
|
||||
DccRx.State = WAIT_PREAMBLE ;
|
||||
DccRx.BitCount = 0 ;
|
||||
bitMax = MAX_PRAEAMBEL;
|
||||
bitMin = MIN_ONEBITFULL;
|
||||
SET_TP1;
|
||||
if ( DccRx.chkSum == 0 ) {
|
||||
// Packet is valid
|
||||
#ifdef ESP32
|
||||
#ifdef ESP32
|
||||
portENTER_CRITICAL_ISR(&mux);
|
||||
#endif
|
||||
#endif
|
||||
DccRx.PacketCopy = DccRx.PacketBuf ;
|
||||
DccRx.DataReady = 1 ;
|
||||
#ifdef ESP32
|
||||
#ifdef ESP32
|
||||
portEXIT_CRITICAL_ISR(&mux);
|
||||
#endif
|
||||
// SET_TP2; CLR_TP2;
|
||||
preambleBitCount = 0 ;
|
||||
} else {
|
||||
// Wrong checksum
|
||||
CLR_TP1;
|
||||
#ifdef DCC_DBGVAR
|
||||
DB_PRINT("Cerr");
|
||||
countOf.Err++;
|
||||
#endif
|
||||
#endif
|
||||
SET_TP3;
|
||||
}
|
||||
|
||||
SET_TP3; CLR_TP4;
|
||||
} else { // Get next Byte
|
||||
else // Get next Byte
|
||||
// KGW - Abort immediately if packet is too long.
|
||||
if( DccRx.PacketBuf.Size == MAX_DCC_MESSAGE_LEN ) // Packet is too long - abort
|
||||
{
|
||||
@@ -672,88 +589,31 @@ void ExternalInterruptHandler(void)
|
||||
DccRx.TempByte = 0 ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unless we're already looking for the start bit
|
||||
// we always search for a preamble ( ( 10 or more consecutive 1 bits )
|
||||
// if we found it within a packet, the packet decoding is aborted because
|
||||
// that much one bits cannot be valid in a packet.
|
||||
if ( DccRx.State != WAIT_START_BIT ) {
|
||||
if( DccBitVal )
|
||||
{
|
||||
preambleBitCount++;
|
||||
//SET_TP2;
|
||||
if( preambleBitCount > 10 ) {
|
||||
CLR_TP2;
|
||||
#ifndef SYNC_ALWAYS
|
||||
if ( DccRx.chkSum == 0 ) {
|
||||
// sync must be correct if chksum was ok, no need to check sync
|
||||
DccRx.State = WAIT_START_BIT_FULL;
|
||||
} else {
|
||||
#endif
|
||||
DccRx.State = WAIT_START_BIT ;
|
||||
SET_TP2;
|
||||
// While waiting for the start bit, detect halfbit lengths. We will detect the correct
|
||||
// sync and detect whether we see a false (e.g. motorola) protocol
|
||||
|
||||
#if defined ( __STM32F1__ )
|
||||
detachInterrupt( DccProcState.ExtIntNum );
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
ISRWatch = CHANGE;
|
||||
#else
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, CHANGE);
|
||||
#endif
|
||||
ISRChkMask = 0; // AVR level check is always true with this settings
|
||||
ISRLevel = 0; // ( there cannot be false edge IRQ's with CHANGE )
|
||||
halfBit = 0;
|
||||
bitMax = MAX_ONEBITHALF;
|
||||
bitMin = MIN_ONEBITHALF;
|
||||
//CLR_TP1;
|
||||
#ifndef SYNC_ALWAYS
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
CLR_TP1;
|
||||
preambleBitCount = 0 ;
|
||||
// SET_TP2; CLR_TP2;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ALLOW_NESTED_IRQ
|
||||
DCC_IrqRunning = false;
|
||||
#endif
|
||||
//CLR_TP1;
|
||||
CLR_TP1;
|
||||
CLR_TP3;
|
||||
}
|
||||
|
||||
void ackCV(void)
|
||||
{
|
||||
if( notifyCVAck )
|
||||
{
|
||||
DB_PRINT("ackCV: Send Basic ACK");
|
||||
notifyCVAck() ;
|
||||
}
|
||||
}
|
||||
|
||||
void ackAdvancedCV(void)
|
||||
{
|
||||
if( notifyAdvancedCVAck && (DccProcState.cv29Value & CV29_RAILCOM_ENABLE) )
|
||||
{
|
||||
DB_PRINT("ackAdvancedCV: Send RailCom ACK");
|
||||
if( notifyAdvancedCVAck && (DccProcState.cv29Value & CV29_ADV_ACK) )
|
||||
notifyAdvancedCVAck() ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t readEEPROM( unsigned int CV )
|
||||
{
|
||||
uint8_t readEEPROM( unsigned int CV ) {
|
||||
return EEPROM.read(CV) ;
|
||||
}
|
||||
|
||||
void writeEEPROM( unsigned int CV, uint8_t Value )
|
||||
{
|
||||
void writeEEPROM( unsigned int CV, uint8_t Value ) {
|
||||
EEPROM.write(CV, Value) ;
|
||||
#if defined(ESP8266)
|
||||
EEPROM.commit();
|
||||
@@ -763,17 +623,15 @@ void writeEEPROM( unsigned int CV, uint8_t Value )
|
||||
#endif
|
||||
}
|
||||
|
||||
bool readyEEPROM()
|
||||
{
|
||||
#if defined ARDUINO_ARCH_MEGAAVR
|
||||
return bit_is_clear(NVMCTRL.STATUS,NVMCTRL_EEBUSY_bp);
|
||||
#elif defined __AVR_MEGA__
|
||||
bool readyEEPROM() {
|
||||
#ifdef __AVR_MEGA__
|
||||
return eeprom_is_ready();
|
||||
#else
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
uint8_t validCV( uint16_t CV, uint8_t Writable )
|
||||
{
|
||||
if( notifyCVResetFactoryDefault && (CV == CV_MANUFACTURER_ID ) && Writable )
|
||||
@@ -810,8 +668,6 @@ uint8_t writeCV( unsigned int CV, uint8_t Value)
|
||||
{
|
||||
case CV_29_CONFIG:
|
||||
// copy addressmode Bit to Flags
|
||||
Value = Value & ~CV29_RAILCOM_ENABLE; // Bidi (RailCom) Bit must not be enabled,
|
||||
// because you cannot build a Bidi decoder with this lib.
|
||||
DccProcState.cv29Value = Value;
|
||||
DccProcState.Flags = ( DccProcState.Flags & ~FLAGS_CV29_BITS) | (Value & FLAGS_CV29_BITS);
|
||||
// no break, because myDccAdress must also be reset
|
||||
@@ -863,7 +719,7 @@ uint16_t getMyAddr(void)
|
||||
return DccProcState.myDccAddress ;
|
||||
}
|
||||
|
||||
void processDirectCVOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value, void (*ackFunction)() )
|
||||
void processDirectOpsOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value )
|
||||
{
|
||||
// is it a Byte Operation
|
||||
if( Cmd & 0x04 )
|
||||
@@ -873,9 +729,8 @@ void processDirectCVOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value, void
|
||||
{
|
||||
if( validCV( CVAddr, 1 ) )
|
||||
{
|
||||
DB_PRINT("CV: %d Byte Write: %02X", CVAddr, Value)
|
||||
if( writeCV( CVAddr, Value ) == Value )
|
||||
ackFunction();
|
||||
ackAdvancedCV();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -883,9 +738,8 @@ void processDirectCVOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value, void
|
||||
{
|
||||
if( validCV( CVAddr, 0 ) )
|
||||
{
|
||||
DB_PRINT("CV: %d Byte Read: %02X", CVAddr, Value)
|
||||
if( readCV( CVAddr ) == Value )
|
||||
ackFunction();
|
||||
ackAdvancedCV();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -898,8 +752,6 @@ void processDirectCVOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value, void
|
||||
|
||||
uint8_t tempValue = readCV( CVAddr ) ; // Read the Current CV Value
|
||||
|
||||
DB_PRINT("CV: %d Current Value: %02X Bit-Wise Mode: %s Mask: %02X Value: %02X", CVAddr, tempValue, BitWrite ? "Write":"Read", BitMask, BitValue);
|
||||
|
||||
// Perform the Bit Write Operation
|
||||
if( BitWrite )
|
||||
{
|
||||
@@ -912,7 +764,7 @@ void processDirectCVOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value, void
|
||||
tempValue &= ~BitMask ; // Turn the Bit Off
|
||||
|
||||
if( writeCV( CVAddr, tempValue ) == tempValue )
|
||||
ackFunction() ;
|
||||
ackAdvancedCV() ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -924,12 +776,12 @@ void processDirectCVOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value, void
|
||||
if( BitValue )
|
||||
{
|
||||
if( tempValue & BitMask )
|
||||
ackFunction() ;
|
||||
ackAdvancedCV() ;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !( tempValue & BitMask) )
|
||||
ackFunction() ;
|
||||
ackAdvancedCV() ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -972,8 +824,9 @@ void processMultiFunctionMessage( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t
|
||||
switch( Cmd & 0b00001110 )
|
||||
{
|
||||
case 0b00000000:
|
||||
if( notifyDccReset && ( Cmd & 0b00000001 ) ) // Hard Reset
|
||||
if( notifyDccReset)
|
||||
notifyDccReset( Cmd & 0b00000001 ) ;
|
||||
notifyDccReset( 1 ) ;
|
||||
break ;
|
||||
|
||||
case 0b00000010: // Factory Test
|
||||
@@ -1106,7 +959,7 @@ void processMultiFunctionMessage( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t
|
||||
case 0b11100000: // CV Access
|
||||
CVAddr = ( ( ( Cmd & 0x03 ) << 8 ) | Data1 ) + 1 ;
|
||||
|
||||
processDirectCVOperation( Cmd, CVAddr, Data2, ackAdvancedCV) ;
|
||||
processDirectOpsOperation( Cmd, CVAddr, Data2 ) ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1121,7 +974,7 @@ void processServiceModeOperation( DCC_MSG * pDccMsg )
|
||||
if( pDccMsg->Size == 3) // 3 Byte Packets are for Address Only, Register and Paged Mode
|
||||
{
|
||||
uint8_t RegisterAddr ;
|
||||
DB_PRINT("CV Address, Register & Paged Mode Operation");
|
||||
DB_PRINT("3-BytePkt");
|
||||
RegisterAddr = pDccMsg->Data[0] & 0x07 ;
|
||||
Value = pDccMsg->Data[1] ;
|
||||
|
||||
@@ -1164,11 +1017,11 @@ void processServiceModeOperation( DCC_MSG * pDccMsg )
|
||||
|
||||
else if( pDccMsg->Size == 4) // 4 Byte Packets are for Direct Byte & Bit Mode
|
||||
{
|
||||
DB_PRINT("CV Direct Byte and Bit Mode Mode Operation");
|
||||
DB_PRINT("BB-Mode");
|
||||
CVAddr = ( ( ( pDccMsg->Data[0] & 0x03 ) << 8 ) | pDccMsg->Data[1] ) + 1 ;
|
||||
Value = pDccMsg->Data[2] ;
|
||||
|
||||
processDirectCVOperation( pDccMsg->Data[0] & 0b00001100, CVAddr, Value, ackCV) ;
|
||||
processDirectOpsOperation( pDccMsg->Data[0] & 0b00001100, CVAddr, Value ) ;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1245,13 +1098,12 @@ void execDccProcessor( DCC_MSG * pDccMsg )
|
||||
{
|
||||
resetServiceModeTimer( 1 ) ;
|
||||
|
||||
//Only check the DCC Packet "Size" and "Data" fields and ignore the "PreambleBits" as they can be different to the previous packet
|
||||
if(pDccMsg->Size != DccProcState.LastMsg.Size || memcmp( pDccMsg->Data, &DccProcState.LastMsg.Data, pDccMsg->Size ) != 0 )
|
||||
if( memcmp( pDccMsg, &DccProcState.LastMsg, sizeof( DCC_MSG ) ) )
|
||||
{
|
||||
DccProcState.DuplicateCount = 0 ;
|
||||
memcpy( &DccProcState.LastMsg, pDccMsg, sizeof( DCC_MSG ) ) ;
|
||||
}
|
||||
// Wait until you see 2 identical packets before acting on a Service Mode Packet
|
||||
// Wait until you see 2 identicle packets before acting on a Service Mode Packet
|
||||
else
|
||||
{
|
||||
DccProcState.DuplicateCount++ ;
|
||||
@@ -1522,15 +1374,10 @@ void NmraDcc::pin( uint8_t ExtIntNum, uint8_t ExtIntPinNum, uint8_t EnablePullup
|
||||
DccProcState.ExtIntNum = ExtIntNum;
|
||||
#endif
|
||||
DccProcState.ExtIntPinNum = ExtIntPinNum;
|
||||
#ifdef __AVR_MEGA__
|
||||
// because digitalRead at AVR is slow, we will read the dcc input in the ISR
|
||||
// by direct port access.
|
||||
DccProcState.ExtIntPort = portInputRegister( digitalPinToPort(ExtIntPinNum) );
|
||||
DccProcState.ExtIntMask = digitalPinToBitMask( ExtIntPinNum );
|
||||
#else
|
||||
DccProcState.ExtIntMask = 1;
|
||||
#endif
|
||||
pinMode( ExtIntPinNum, EnablePullup ? INPUT_PULLUP : INPUT );
|
||||
|
||||
pinMode( ExtIntPinNum, INPUT );
|
||||
if( EnablePullup )
|
||||
digitalWrite(ExtIntPinNum, HIGH);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -1564,9 +1411,6 @@ void NmraDcc::init( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, ui
|
||||
DccProcState.inAccDecDCCAddrNextReceivedMode = 0;
|
||||
|
||||
ISREdge = RISING;
|
||||
// level checking to detect false IRQ's fired by glitches
|
||||
ISRLevel = DccProcState.ExtIntMask;
|
||||
ISRChkMask = DccProcState.ExtIntMask;
|
||||
|
||||
#ifdef ESP32
|
||||
ISRWatch = ISREdge;
|
||||
@@ -1677,6 +1521,7 @@ uint8_t NmraDcc::process()
|
||||
if( DccRx.DataReady )
|
||||
{
|
||||
// We need to do this check with interrupts disabled
|
||||
//SET_TP4;
|
||||
#ifdef ESP32
|
||||
portENTER_CRITICAL(&mux);
|
||||
#else
|
||||
@@ -1690,16 +1535,25 @@ uint8_t NmraDcc::process()
|
||||
#else
|
||||
interrupts();
|
||||
#endif
|
||||
// Checking of the XOR-byte is now done in the ISR already
|
||||
#ifdef DCC_DBGVAR
|
||||
countOf.Tel++;
|
||||
#endif
|
||||
// Clear trailing bytes
|
||||
for ( byte i=Msg.Size; i< MAX_DCC_MESSAGE_LEN; i++ ) Msg.Data[i] = 0;
|
||||
|
||||
uint8_t xorValue = 0 ;
|
||||
|
||||
for(uint8_t i = 0; i < DccRx.PacketCopy.Size; i++)
|
||||
xorValue ^= DccRx.PacketCopy.Data[i];
|
||||
if(xorValue) {
|
||||
#ifdef DCC_DBGVAR
|
||||
DB_PRINT("Cerr");
|
||||
countOf.Err++;
|
||||
#endif
|
||||
return 0 ;
|
||||
} else {
|
||||
if( notifyDccMsg ) notifyDccMsg( &Msg );
|
||||
|
||||
execDccProcessor( &Msg );
|
||||
}
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
|
||||
29
NmraDcc.h
29
NmraDcc.h
@@ -2,21 +2,11 @@
|
||||
//
|
||||
// Model Railroading with Arduino - NmraDcc.h
|
||||
//
|
||||
// Copyright (c) 2008 - 2020 Alex Shepherd
|
||||
// Copyright (c) 2008 - 2018 Alex Shepherd
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
// This source file is subject of the GNU general public license 2,
|
||||
// that is available at the world-wide-web at
|
||||
// http://www.gnu.org/licenses/gpl.txt
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
@@ -54,10 +44,12 @@
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include "EEPROM.h"
|
||||
|
||||
#ifndef NMRADCC_IS_IN
|
||||
#define NMRADCC_IS_IN
|
||||
|
||||
#define NMRADCC_VERSION 206 // Version 2.0.6
|
||||
#define NMRADCC_VERSION 201 // Version 2.0.1
|
||||
|
||||
#define MAX_DCC_MESSAGE_LEN 6 // including XOR-Byte
|
||||
|
||||
@@ -126,7 +118,7 @@ typedef enum {
|
||||
CV29_LOCO_DIR = 0b00000001, /** bit 0: Locomotive Direction: "0" = normal, "1" = reversed */
|
||||
CV29_F0_LOCATION = 0b00000010, /** bit 1: F0 location: "0" = bit 4 in Speed and Direction instructions, "1" = bit 4 in function group one instruction */
|
||||
CV29_APS = 0b00000100, /** bit 2: Alternate Power Source (APS) "0" = NMRA Digital only, "1" = Alternate power source set by CV12 */
|
||||
CV29_RAILCOM_ENABLE = 0b00001000, /** bit 3: BiDi ( RailCom ) is active */
|
||||
CV29_ADV_ACK = 0b00001000, /** bit 3: ACK, Advanced Acknowledge mode enabled if 1, disabled if 0 */
|
||||
CV29_SPEED_TABLE_ENABLE = 0b00010000, /** bit 4: STE, Speed Table Enable, "0" = values in CVs 2, 4 and 6, "1" = Custom table selected by CV 25 */
|
||||
CV29_EXT_ADDRESSING = 0b00100000, /** bit 5: "0" = one byte addressing, "1" = two byte addressing */
|
||||
CV29_OUTPUT_ADDRESS_MODE = 0b01000000, /** bit 6: "0" = Decoder Address Mode "1" = Output Address Mode */
|
||||
@@ -712,8 +704,9 @@ extern void notifyCVResetFactoryDefault(void) __attribute__ ((weak));
|
||||
*/
|
||||
extern void notifyCVAck(void) __attribute__ ((weak));
|
||||
/*+
|
||||
* notifyAdvancedCVAck() Called when a CV write must be acknowledged via Advanced Acknowledgement.
|
||||
* This callback must send the Advanced Acknowledgement via RailComm.
|
||||
* notifyAdvancedCVAck() Called when a CV write must be acknowledged.
|
||||
* This callback must increase the current drawn by this
|
||||
* decoder by at least 60mA for 6ms +/- 1ms.
|
||||
*
|
||||
* Inputs:
|
||||
* None
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// DCC Stepper Motor Controller ( A4988 ) Example for Model Railroad Turntable Control
|
||||
//
|
||||
// See: https://www.dccinterface.com/product/arduino-model-railway-dcc-stepper-motor-controller-a4988-assembled/
|
||||
// See: https://www.dccinterface.com/how-to/assemblyguide/
|
||||
//
|
||||
// Author: Alex Shepherd 2020-06-01
|
||||
// Author: Alex Shepherd 2017-12-04
|
||||
//
|
||||
// This example requires two Arduino Libraries:
|
||||
//
|
||||
@@ -22,18 +22,8 @@
|
||||
// The lines below define the pins used to connect to the A4988 driver module
|
||||
#define A4988_STEP_PIN 4
|
||||
#define A4988_DIRECTION_PIN 5
|
||||
#define A4988_ENABLE_PIN 6
|
||||
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
// Uncomment the next line to enable Powering-Off the Stepper when its not running to reduce heating the motor and driver
|
||||
#define DISABLE_OUTPUTS_IDLE
|
||||
#endif
|
||||
|
||||
// By default the stepper motor will move the shortest distance to the desired position.
|
||||
// If you need the turntable to only move in the Positive/Increasing or Negative/Decreasing step numbers to better handle backlash in the mechanism
|
||||
// Then uncomment the appropriate line below
|
||||
//#define ALWAYS_MOVE_POSITIVE
|
||||
//#define ALWAYS_MOVE_NEGATIVE
|
||||
#define A4988_ENABLE_PIN 6
|
||||
|
||||
// The lines below define the stepping speed and acceleration, which you may need to tune for your application
|
||||
#define STEPPER_MAX_SPEED 800 // Sets the maximum permitted speed
|
||||
@@ -102,9 +92,6 @@ TurnoutPosition turnoutPositions[] = {
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// You shouldn't need to edit anything below this line unless you're needing to make big changes... ;)
|
||||
// --------------------------------------------------------------------------------------------
|
||||
#if defined(ALWAYS_MOVE_POSITIVE) && defined(ALWAYS_MOVE_NEGATIVE)
|
||||
#error ONLY uncomment one of ALWAYS_MOVE_POSITIVE or ALWAYS_MOVE_NEGATIVE but NOT both
|
||||
#endif
|
||||
|
||||
#define MAX_TURNOUT_POSITIONS (sizeof(turnoutPositions) / sizeof(TurnoutPosition))
|
||||
|
||||
@@ -117,12 +104,11 @@ NmraDcc Dcc ;
|
||||
// Variables to store the last DCC Turnout message Address and Direction
|
||||
uint16_t lastAddr = 0xFFFF ;
|
||||
uint8_t lastDirection = 0xFF;
|
||||
int lastStep = 0;
|
||||
|
||||
// This function is called whenever a normal DCC Turnout Packet is received
|
||||
void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower )
|
||||
{
|
||||
Serial.print(F("notifyDccAccTurnoutOutput: "));
|
||||
Serial.print("notifyDccAccTurnoutOutput: ") ;
|
||||
Serial.print(Addr,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.print(Direction,DEC) ;
|
||||
@@ -145,50 +131,23 @@ void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t Output
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
stepper1.enableOutputs();
|
||||
#endif
|
||||
|
||||
int newStep;
|
||||
if(Direction)
|
||||
newStep = turnoutPositions[i].positionFront;
|
||||
else
|
||||
newStep = turnoutPositions[i].positionBack;
|
||||
|
||||
Serial.print(newStep, DEC);
|
||||
|
||||
Serial.print(F(" Last Step: "));
|
||||
Serial.print(lastStep, DEC);
|
||||
|
||||
int diffStep = newStep - lastStep;
|
||||
Serial.print(F(" Diff Step: "));
|
||||
Serial.print(diffStep, DEC);
|
||||
|
||||
#if defined ALWAYS_MOVE_POSITIVE
|
||||
Serial.print(F(" Positive"));
|
||||
if(diffStep < 0)
|
||||
diffStep += FULL_TURN_STEPS;
|
||||
|
||||
#elif defined ALWAYS_MOVE_NEGATIVE
|
||||
Serial.print(F(" Negative"));
|
||||
if(diffStep > 0)
|
||||
diffStep -= FULL_TURN_STEPS;
|
||||
#else
|
||||
if(diffStep > HALF_TURN_STEPS)
|
||||
diffStep = diffStep - FULL_TURN_STEPS;
|
||||
|
||||
else if(diffStep < -HALF_TURN_STEPS)
|
||||
diffStep = diffStep + FULL_TURN_STEPS;
|
||||
#endif
|
||||
|
||||
Serial.print(F(" Move: "));
|
||||
Serial.println(diffStep, DEC);
|
||||
stepper1.move(diffStep);
|
||||
|
||||
lastStep = newStep;
|
||||
if (Direction)
|
||||
{
|
||||
Serial.println(turnoutPositions[i].positionFront, DEC);
|
||||
stepper1.moveTo(turnoutPositions[i].positionFront);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(turnoutPositions[i].positionBack, DEC);
|
||||
stepper1.moveTo(turnoutPositions[i].positionBack);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef DISABLE_OUTPUTS_IDLE
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
bool lastIsRunningState ;
|
||||
#endif
|
||||
|
||||
@@ -204,10 +163,6 @@ void setupStepperDriver()
|
||||
stepper1.setSpeed(STEPPER_SPEED); // Sets the desired constant speed for use with runSpeed()
|
||||
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
stepper1.enableOutputs();
|
||||
#endif
|
||||
|
||||
#ifdef DISABLE_OUTPUTS_IDLE
|
||||
lastIsRunningState = stepper1.isRunning();
|
||||
#endif
|
||||
}
|
||||
@@ -218,19 +173,14 @@ bool moveToHomePosition()
|
||||
|
||||
pinMode(HOME_SENSOR_PIN, INPUT_PULLUP);
|
||||
|
||||
#ifdef ALWAYS_MOVE_NEGATIVE
|
||||
stepper1.move(0 - (FULL_TURN_STEPS * 2));
|
||||
#else
|
||||
stepper1.move(FULL_TURN_STEPS * 2);
|
||||
#endif
|
||||
while(digitalRead(HOME_SENSOR_PIN) != HOME_SENSOR_ACTIVE_STATE)
|
||||
stepper1.run();
|
||||
|
||||
if(digitalRead(HOME_SENSOR_PIN) == HOME_SENSOR_ACTIVE_STATE)
|
||||
{
|
||||
stepper1.stop();
|
||||
stepper1.setCurrentPosition(0);
|
||||
Serial.println(F("Found Home Position - Setting Current Position to 0"));
|
||||
stepper1.setCurrentPosition(0);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -260,32 +210,28 @@ void setup()
|
||||
Serial.print(F("Full Rotation Steps: "));
|
||||
Serial.println(FULL_TURN_STEPS);
|
||||
|
||||
Serial.print(F("Movement Strategy: "));
|
||||
#if defined ALWAYS_MOVE_POSITIVE
|
||||
Serial.println(F("Positive Direction Only"));
|
||||
#elif defined ALWAYS_MOVE_NEGATIVE
|
||||
Serial.println(F("Negative Direction Only"));
|
||||
#else
|
||||
Serial.println(F("Shortest Distance"));
|
||||
#endif
|
||||
|
||||
for(uint8_t i = 0; i < MAX_TURNOUT_POSITIONS; i++)
|
||||
{
|
||||
Serial.print(F("DCC Addr: "));
|
||||
Serial.print("DCC Addr: ");
|
||||
Serial.print(turnoutPositions[i].dccAddress);
|
||||
|
||||
Serial.print(F(" Front: "));
|
||||
Serial.print(" Front: ");
|
||||
Serial.print(turnoutPositions[i].positionFront);
|
||||
|
||||
Serial.print(F(" Back: "));
|
||||
Serial.print(" Back: ");
|
||||
Serial.println(turnoutPositions[i].positionBack);
|
||||
}
|
||||
|
||||
setupStepperDriver();
|
||||
|
||||
if(moveToHomePosition());
|
||||
{
|
||||
setupDCCDecoder();
|
||||
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
stepper1.enableOutputs();
|
||||
#endif
|
||||
|
||||
// Fake a DCC Packet to cause the Turntable to move to Position 1
|
||||
notifyDccAccTurnoutOutput(POSITION_01_DCC_ADDRESS, 1, 1);
|
||||
}
|
||||
@@ -299,7 +245,7 @@ void loop()
|
||||
// Process the Stepper Library
|
||||
stepper1.run();
|
||||
|
||||
#ifdef DISABLE_OUTPUTS_IDLE
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
if(stepper1.isRunning() != lastIsRunningState)
|
||||
{
|
||||
lastIsRunningState = stepper1.isRunning();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name=NmraDcc
|
||||
version=2.0.6
|
||||
version=2.0.2
|
||||
author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Müller, Sven (littleyoda), Hans Tanner
|
||||
maintainer=Alex Shepherd <kiwi64ajs@gmail.com>
|
||||
sentence=Enables NMRA DCC Communication
|
||||
|
||||
Reference in New Issue
Block a user