Compare commits
25 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
159a4bc5bf | ||
|
5b681f49de | ||
|
02be948ed2 | ||
|
24d6689b24 | ||
|
f1f214af3a | ||
|
e1080f28fd | ||
|
54c56b7cda | ||
|
2e1f9098ad | ||
|
37b66af743 | ||
|
4cf529e8c5 | ||
|
cea2913e8a | ||
|
ae9afe9c24 | ||
|
afe488d792 | ||
|
61a730bf82 | ||
|
b0b27ce0cc | ||
|
c3dc28479a | ||
|
a05c12ce95 | ||
|
0a72fc610b | ||
|
ad5ce96253 | ||
|
1e81b95044 | ||
|
84fdf45dce | ||
|
037070b899 | ||
|
eb15c25491 | ||
|
681b362811 | ||
|
f5d7e9b8c3 |
55
.astylerc
Normal file
55
.astylerc
Normal file
@@ -0,0 +1,55 @@
|
||||
# http://astyle.sourceforge.net/astyle.html#_style=allman
|
||||
# use the allman style for braces
|
||||
--style=allman
|
||||
|
||||
# http://astyle.sourceforge.net/astyle.html#_lineend
|
||||
# newlines for all line endings
|
||||
--lineend=linux
|
||||
|
||||
# http://astyle.sourceforge.net/astyle.html#_indent=spaces
|
||||
# 4 space indents
|
||||
--indent=spaces=4
|
||||
|
||||
# http://astyle.sourceforge.net/astyle.html#_add-braces
|
||||
# don't leave any unbraced one-line blocks by changing:
|
||||
# if (thing)
|
||||
# statement;
|
||||
#
|
||||
# to
|
||||
# if (thing)
|
||||
# {
|
||||
# statement;
|
||||
# }
|
||||
#
|
||||
# --add-braces
|
||||
|
||||
# http://astyle.sourceforge.net/astyle.html#_indent-preproc-cond
|
||||
# line up #if/#endif with the code
|
||||
#
|
||||
# statement;
|
||||
# #if SOMETHING
|
||||
# statement;
|
||||
# #endif
|
||||
#
|
||||
--indent-preproc-cond
|
||||
|
||||
# http://astyle.sourceforge.net/astyle.html#_indent-preproc-block
|
||||
# indent top level preprocessor block contents
|
||||
#
|
||||
# #ifdef __ARDUINO__
|
||||
# #include "Arduino.h"
|
||||
# #endif
|
||||
#
|
||||
--indent-preproc-block
|
||||
|
||||
# normalize spacing around parenthese
|
||||
# http://astyle.sourceforge.net/astyle.html#_unpad-paren
|
||||
# first, remove all whitespace on either side of a paren
|
||||
--unpad-paren
|
||||
# http://astyle.sourceforge.net/astyle.html#_pad-paren-out
|
||||
# then add a space on the "outer" side of a paren
|
||||
--pad-paren-out
|
||||
|
||||
# http://astyle.sourceforge.net/astyle.html#_max-code-length
|
||||
# we've got big monitors these days....
|
||||
--max-code-length=180
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
.development
|
||||
*.zip
|
||||
*.orig
|
||||
*~
|
||||
|
2268
NmraDcc.cpp
2268
NmraDcc.cpp
File diff suppressed because it is too large
Load Diff
459
NmraDcc.h
459
NmraDcc.h
@@ -49,9 +49,9 @@
|
||||
//#define NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#ifndef NMRADCC_IS_IN
|
||||
@@ -65,9 +65,9 @@
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t Size ;
|
||||
uint8_t PreambleBits ;
|
||||
uint8_t Data[MAX_DCC_MESSAGE_LEN] ;
|
||||
uint8_t Size ;
|
||||
uint8_t PreambleBits ;
|
||||
uint8_t Data[MAX_DCC_MESSAGE_LEN] ;
|
||||
} DCC_MSG ;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -94,6 +94,10 @@ typedef struct
|
||||
|
||||
// Product/Version Id Codes allocated under: MAN_ID_DIY
|
||||
|
||||
#define DEFAULT_MULTIFUNCTION_DECODER_ADDRESS 3
|
||||
#define DEFAULT_ACCESSORY_DECODER_ADDRESS 1
|
||||
|
||||
|
||||
// Standard CV Addresses
|
||||
#define CV_ACCESSORY_DECODER_ADDRESS_LSB 1
|
||||
#define CV_ACCESSORY_DECODER_ADDRESS_MSB 9
|
||||
@@ -102,65 +106,78 @@ typedef struct
|
||||
#define CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB 17
|
||||
#define CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB 18
|
||||
|
||||
#define CALC_MULTIFUNCTION_EXTENDED_ADDRESS_LSB(x) (x & 0xFF)
|
||||
#define CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB(x) (((x>>8) & 0x7F) + 192)
|
||||
|
||||
#define CV_VERSION_ID 7
|
||||
#define CV_MANUFACTURER_ID 8
|
||||
#define CV_29_CONFIG 29
|
||||
#define CV_MANUFACTURER_START 33
|
||||
|
||||
#if defined(ESP32)
|
||||
#include <esp_spi_flash.h>
|
||||
#define MAXCV SPI_FLASH_SEC_SIZE
|
||||
#include <esp_spi_flash.h>
|
||||
#define MAXCV SPI_FLASH_SEC_SIZE
|
||||
#elif defined(ESP8266)
|
||||
#include <spi_flash.h>
|
||||
#define MAXCV SPI_FLASH_SEC_SIZE
|
||||
#include <spi_flash.h>
|
||||
#define MAXCV SPI_FLASH_SEC_SIZE
|
||||
#elif defined( __STM32F1__)
|
||||
#define MAXCV (EEPROM_PAGE_SIZE/4 - 1) // number of storage places (CV address could be larger
|
||||
// because STM32 uses virtual adresses)
|
||||
#define MAXCV (EEPROM_PAGE_SIZE/4 - 1) // number of storage places (CV address could be larger
|
||||
// because STM32 uses virtual adresses)
|
||||
#undef ALLOW_NESTED_IRQ // This is done with NVIC on STM32
|
||||
#define PRIO_DCC_IRQ 9
|
||||
#define PRIO_SYSTIC 8 // MUST be higher priority than DCC Irq
|
||||
#elif defined(ARDUINO_ARCH_RP2040)
|
||||
#define MAXCV 256 // todo: maybe somebody knows a good define for it
|
||||
#elif defined(ARDUINO_SAMD_ZERO)
|
||||
#define MAXCV EEPROM_EMULATION_SIZE
|
||||
#else
|
||||
#define MAXCV E2END // the upper limit of the CV value currently defined to max memory.
|
||||
#define MAXCV E2END // the upper limit of the CV value currently defined to max memory.
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
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_RAILCOM_ENABLE = 0b00001000, /** bit 3: BiDi ( RailCom ) is active */
|
||||
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 */
|
||||
CV29_ACCESSORY_DECODER = 0b10000000, /** bit 7: "0" = Multi-Function Decoder Mode "1" = Accessory Decoder Mode */
|
||||
} CV_29_BITS;
|
||||
|
||||
typedef enum {
|
||||
#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
|
||||
typedef enum
|
||||
{
|
||||
#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
|
||||
SPEED_STEP_14 = 15, /**< ESTOP=0, 1 to 15 */
|
||||
#endif
|
||||
#endif
|
||||
SPEED_STEP_28 = 29, /**< ESTOP=0, 1 to 29 */
|
||||
SPEED_STEP_128 = 127 /**< ESTOP=0, 1 to 127 */
|
||||
} DCC_SPEED_STEPS;
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
DCC_DIR_REV = 0, /** The locomotive to go in the reverse direction */
|
||||
DCC_DIR_FWD = 1, /** The locomotive should move in the forward direction */
|
||||
} DCC_DIRECTION;
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
DCC_ADDR_SHORT, /** Short address is used. The range is 0 to 127. */
|
||||
DCC_ADDR_LONG, /** Long Address is used. The range is 1 to 10239 */
|
||||
} DCC_ADDR_TYPE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FN_0_4 = 1,
|
||||
FN_5_8,
|
||||
FN_9_12,
|
||||
FN_13_20,
|
||||
FN_21_28,
|
||||
#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
|
||||
FN_0 /** function light is controlled by base line package (14 speed steps) */
|
||||
#endif
|
||||
FN_0_4 = 1,
|
||||
FN_5_8,
|
||||
FN_9_12,
|
||||
FN_13_20,
|
||||
FN_21_28,
|
||||
#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
|
||||
FN_0, /** function light is controlled by base line package (14 speed steps) */
|
||||
#endif
|
||||
FN_LAST
|
||||
} FN_GROUP;
|
||||
|
||||
#define FN_BIT_00 0x10
|
||||
@@ -199,20 +216,21 @@ typedef enum
|
||||
|
||||
//#define DCC_DBGVAR
|
||||
#ifdef DCC_DBGVAR
|
||||
typedef struct countOf_t {
|
||||
typedef struct countOf_t
|
||||
{
|
||||
unsigned long Tel;
|
||||
unsigned long Err;
|
||||
}countOf_t ;
|
||||
} countOf_t ;
|
||||
|
||||
extern struct countOf_t countOf;
|
||||
#endif
|
||||
|
||||
class NmraDcc
|
||||
{
|
||||
private:
|
||||
private:
|
||||
DCC_MSG Msg ;
|
||||
|
||||
public:
|
||||
public:
|
||||
NmraDcc();
|
||||
|
||||
// Flag values to be logically ORed together and passed into the init() method
|
||||
@@ -226,180 +244,180 @@ class NmraDcc
|
||||
#define FLAGS_CV29_BITS (FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER)
|
||||
|
||||
|
||||
/*+
|
||||
* pin() is called from setup() and sets up the pin used to receive DCC packets.
|
||||
*
|
||||
* Inputs:
|
||||
* ExtIntNum - Interrupt number of the pin. Use digitalPinToInterrupt(ExtIntPinNum).
|
||||
* ExtIntPinNum - Input pin number.
|
||||
* EnablePullup - Set true to enable the pins pullup resistor.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*/
|
||||
void pin( uint8_t ExtIntNum, uint8_t ExtIntPinNum, uint8_t EnablePullup);
|
||||
/*+
|
||||
* pin() is called from setup() and sets up the pin used to receive DCC packets.
|
||||
*
|
||||
* Inputs:
|
||||
* ExtIntNum - Interrupt number of the pin. Use digitalPinToInterrupt(ExtIntPinNum).
|
||||
* ExtIntPinNum - Input pin number.
|
||||
* EnablePullup - Set true to enable the pins pullup resistor.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*/
|
||||
void pin (uint8_t ExtIntNum, uint8_t ExtIntPinNum, uint8_t EnablePullup);
|
||||
|
||||
/*+
|
||||
* pin() is called from setup() and sets up the pin used to receive DCC packets.
|
||||
* This relies on the internal function: digitalPinToInterrupt() to map the input pin number to the right interrupt
|
||||
*
|
||||
* Inputs:
|
||||
* ExtIntPinNum - Input pin number.
|
||||
* EnablePullup - Set true to enable the pins pullup resistor.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*/
|
||||
#ifdef digitalPinToInterrupt
|
||||
void pin( uint8_t ExtIntPinNum, uint8_t EnablePullup);
|
||||
#endif
|
||||
/*+
|
||||
* pin() is called from setup() and sets up the pin used to receive DCC packets.
|
||||
* This relies on the internal function: digitalPinToInterrupt() to map the input pin number to the right interrupt
|
||||
*
|
||||
* Inputs:
|
||||
* ExtIntPinNum - Input pin number.
|
||||
* EnablePullup - Set true to enable the pins pullup resistor.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*/
|
||||
#ifdef digitalPinToInterrupt
|
||||
void pin (uint8_t ExtIntPinNum, uint8_t EnablePullup);
|
||||
#endif
|
||||
|
||||
/*+
|
||||
* init() is called from setup() after the pin() command is called.
|
||||
* It initializes the NmDcc object and makes it ready to process packets.
|
||||
*
|
||||
* Inputs:
|
||||
* ManufacturerId - Manufacturer ID returned in CV 8.
|
||||
* Commonly MAN_ID_DIY.
|
||||
* VersionId - Version ID returned in CV 7.
|
||||
* Flags - ORed flags beginning with FLAGS_...
|
||||
* FLAGS_MY_ADDRESS_ONLY - Only process packets with My Address.
|
||||
* FLAGS_DCC_ACCESSORY_DECODER - Decoder is an accessory decoder.
|
||||
* FLAGS_OUTPUT_ADDRESS_MODE - This flag applies to accessory decoders only.
|
||||
* Accessory decoders normally have 4 paired outputs
|
||||
* and a single address refers to all 4 outputs.
|
||||
* Setting FLAGS_OUTPUT_ADDRESS_MODE causes each
|
||||
* address to refer to a single output.
|
||||
* OpsModeAddressBaseCV - Ops Mode base address. Set it to 0?
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*/
|
||||
void init( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV );
|
||||
/*+
|
||||
* init() is called from setup() after the pin() command is called.
|
||||
* It initializes the NmDcc object and makes it ready to process packets.
|
||||
*
|
||||
* Inputs:
|
||||
* ManufacturerId - Manufacturer ID returned in CV 8.
|
||||
* Commonly MAN_ID_DIY.
|
||||
* VersionId - Version ID returned in CV 7.
|
||||
* Flags - ORed flags beginning with FLAGS_...
|
||||
* FLAGS_MY_ADDRESS_ONLY - Only process packets with My Address.
|
||||
* FLAGS_DCC_ACCESSORY_DECODER - Decoder is an accessory decoder.
|
||||
* FLAGS_OUTPUT_ADDRESS_MODE - This flag applies to accessory decoders only.
|
||||
* Accessory decoders normally have 4 paired outputs
|
||||
* and a single address refers to all 4 outputs.
|
||||
* Setting FLAGS_OUTPUT_ADDRESS_MODE causes each
|
||||
* address to refer to a single output.
|
||||
* OpsModeAddressBaseCV - Ops Mode base address. Set it to 0?
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*/
|
||||
void init (uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV);
|
||||
|
||||
/*+
|
||||
* initAccessoryDecoder() is called from setup() for accessory decoders.
|
||||
* It calls init() with FLAGS_DCC_ACCESSORY_DECODER ORed into Flags.
|
||||
*
|
||||
* Inputs:
|
||||
* ManufacturerId - Manufacturer ID returned in CV 8.
|
||||
* Commonly MAN_ID_DIY.
|
||||
* VersionId - Version ID returned in CV 7.
|
||||
* Flags - ORed flags beginning with FLAGS_...
|
||||
* FLAGS_DCC_ACCESSORY_DECODER will be set for init() call.
|
||||
* OpsModeAddressBaseCV - Ops Mode base address. Set it to 0?
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*/
|
||||
void initAccessoryDecoder( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV );
|
||||
/*+
|
||||
* initAccessoryDecoder() is called from setup() for accessory decoders.
|
||||
* It calls init() with FLAGS_DCC_ACCESSORY_DECODER ORed into Flags.
|
||||
*
|
||||
* Inputs:
|
||||
* ManufacturerId - Manufacturer ID returned in CV 8.
|
||||
* Commonly MAN_ID_DIY.
|
||||
* VersionId - Version ID returned in CV 7.
|
||||
* Flags - ORed flags beginning with FLAGS_...
|
||||
* FLAGS_DCC_ACCESSORY_DECODER will be set for init() call.
|
||||
* OpsModeAddressBaseCV - Ops Mode base address. Set it to 0?
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*/
|
||||
void initAccessoryDecoder (uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV);
|
||||
|
||||
/*+
|
||||
* process() is called from loop() to process DCC packets.
|
||||
* It must be called very frequently to keep up with the packets.
|
||||
*
|
||||
* Inputs:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* 1 - Packet succesfully parsed on this call to process().
|
||||
* 0 - Packet not ready or received packet had an error.
|
||||
*/
|
||||
uint8_t process();
|
||||
/*+
|
||||
* process() is called from loop() to process DCC packets.
|
||||
* It must be called very frequently to keep up with the packets.
|
||||
*
|
||||
* Inputs:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* 1 - Packet succesfully parsed on this call to process().
|
||||
* 0 - Packet not ready or received packet had an error.
|
||||
*/
|
||||
uint8_t process();
|
||||
|
||||
/*+
|
||||
* getCV() returns the selected CV value.
|
||||
*
|
||||
* Inputs:
|
||||
* CV - CV number. It must point to a valid CV.
|
||||
*
|
||||
* Returns:
|
||||
* Value - CV value. Invalid CV numbers will return an undefined result
|
||||
* since nothing will have been set in that EEPROM position.
|
||||
* Calls notifyCVRead() if it is defined.
|
||||
*/
|
||||
uint8_t getCV( uint16_t CV );
|
||||
/*+
|
||||
* getCV() returns the selected CV value.
|
||||
*
|
||||
* Inputs:
|
||||
* CV - CV number. It must point to a valid CV.
|
||||
*
|
||||
* Returns:
|
||||
* Value - CV value. Invalid CV numbers will return an undefined result
|
||||
* since nothing will have been set in that EEPROM position.
|
||||
* Calls notifyCVRead() if it is defined.
|
||||
*/
|
||||
uint8_t getCV (uint16_t CV);
|
||||
|
||||
/*+
|
||||
* setCV() sets the value of a CV.
|
||||
*
|
||||
* Inputs:
|
||||
* CV - CV number. It must point to a valid CV.
|
||||
* Value - CV value.
|
||||
*
|
||||
* Returns:
|
||||
* Value - CV value set by this call.
|
||||
* since nothing will have been set in that EEPROM position.
|
||||
* Calls notifyCVWrite() if it is defined.
|
||||
* Calls notifyCVChange() if the value is changed by this call.
|
||||
*/
|
||||
uint8_t setCV( uint16_t CV, uint8_t Value);
|
||||
/*+
|
||||
* setCV() sets the value of a CV.
|
||||
*
|
||||
* Inputs:
|
||||
* CV - CV number. It must point to a valid CV.
|
||||
* Value - CV value.
|
||||
*
|
||||
* Returns:
|
||||
* Value - CV value set by this call.
|
||||
* since nothing will have been set in that EEPROM position.
|
||||
* Calls notifyCVWrite() if it is defined.
|
||||
* Calls notifyCVChange() if the value is changed by this call.
|
||||
*/
|
||||
uint8_t setCV (uint16_t CV, uint8_t Value);
|
||||
|
||||
/*+
|
||||
* setAccDecDCCAddrNextReceived() enables/disables the setting of the board address from the next received turnout command
|
||||
*
|
||||
* Inputs:
|
||||
* enable- boolean to enable or disable the mode
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
void setAccDecDCCAddrNextReceived(uint8_t enable);
|
||||
/*+
|
||||
* setAccDecDCCAddrNextReceived() enables/disables the setting of the board address from the next received turnout command
|
||||
*
|
||||
* Inputs:
|
||||
* enable- boolean to enable or disable the mode
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
void setAccDecDCCAddrNextReceived (uint8_t enable);
|
||||
|
||||
/*+
|
||||
* isSetCVReady() returns 1 if EEPROM is ready to write.
|
||||
*
|
||||
* Inputs:
|
||||
* CV - CV number. It must point to a valid CV.
|
||||
* Value - CV value.
|
||||
*
|
||||
* Returns:
|
||||
* ready - 1 if ready to write, 0 otherwise. AVR processor will block
|
||||
* for several ms. for each write cycle so you should check this to avoid blocks.
|
||||
* Note: It returns the value returned by notifyIsSetCVReady() if it is defined.
|
||||
* Calls notifyIsSetCVReady() if it is defined.
|
||||
*/
|
||||
uint8_t isSetCVReady( void );
|
||||
/*+
|
||||
* isSetCVReady() returns 1 if EEPROM is ready to write.
|
||||
*
|
||||
* Inputs:
|
||||
* CV - CV number. It must point to a valid CV.
|
||||
* Value - CV value.
|
||||
*
|
||||
* Returns:
|
||||
* ready - 1 if ready to write, 0 otherwise. AVR processor will block
|
||||
* for several ms. for each write cycle so you should check this to avoid blocks.
|
||||
* Note: It returns the value returned by notifyIsSetCVReady() if it is defined.
|
||||
* Calls notifyIsSetCVReady() if it is defined.
|
||||
*/
|
||||
uint8_t isSetCVReady (void);
|
||||
|
||||
/*+
|
||||
* getAddr() return the currently active decoder address.
|
||||
* based on decoder type and current address size.
|
||||
*
|
||||
* Inputs:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Adr - The current decoder address based on decoder type(Multifunction, Accessory)
|
||||
* and short or long address selection for Multifunction decoders.
|
||||
*/
|
||||
uint16_t getAddr(void);
|
||||
/*+
|
||||
* getAddr() return the currently active decoder address.
|
||||
* based on decoder type and current address size.
|
||||
*
|
||||
* Inputs:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Adr - The current decoder address based on decoder type(Multifunction, Accessory)
|
||||
* and short or long address selection for Multifunction decoders.
|
||||
*/
|
||||
uint16_t getAddr (void);
|
||||
|
||||
/*+
|
||||
* getX() return debugging data if DCC_DEBUG is defined.
|
||||
* You would really need to be modifying the library to need them.
|
||||
*
|
||||
* Inputs:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* getIntCount - Init to 0 and apparently never incremented?
|
||||
* getTickCount - Init to 0 and incremented each time interrupt handler
|
||||
* completes without an error.
|
||||
* getBitCount - Bit count of valid packet, 0 otherwise. Only valid until
|
||||
* start of the next packet.
|
||||
* getState - Current WAIT_... state as defined by DccRxWaitState in NmraDcc.cpp.
|
||||
* getNestedIrqCount - Init to 0 and incremented each time the interrupt handler
|
||||
* is called before the previous interrupt was complete.
|
||||
* This is an error indication and may indicate the system
|
||||
* is not handling packets fast enough or some other error is occurring.
|
||||
*/
|
||||
/*+
|
||||
* getX() return debugging data if DCC_DEBUG is defined.
|
||||
* You would really need to be modifying the library to need them.
|
||||
*
|
||||
* Inputs:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* getIntCount - Init to 0 and apparently never incremented?
|
||||
* getTickCount - Init to 0 and incremented each time interrupt handler
|
||||
* completes without an error.
|
||||
* getBitCount - Bit count of valid packet, 0 otherwise. Only valid until
|
||||
* start of the next packet.
|
||||
* getState - Current WAIT_... state as defined by DccRxWaitState in NmraDcc.cpp.
|
||||
* getNestedIrqCount - Init to 0 and incremented each time the interrupt handler
|
||||
* is called before the previous interrupt was complete.
|
||||
* This is an error indication and may indicate the system
|
||||
* is not handling packets fast enough or some other error is occurring.
|
||||
*/
|
||||
// #define DCC_DEBUG
|
||||
#ifdef DCC_DEBUG
|
||||
uint8_t getIntCount(void);
|
||||
uint8_t getTickCount(void);
|
||||
uint8_t getBitCount(void);
|
||||
uint8_t getState(void);
|
||||
uint8_t getNestedIrqCount(void);
|
||||
#endif
|
||||
#ifdef DCC_DEBUG
|
||||
uint8_t getIntCount (void);
|
||||
uint8_t getTickCount (void);
|
||||
uint8_t getBitCount (void);
|
||||
uint8_t getState (void);
|
||||
uint8_t getNestedIrqCount (void);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
@@ -408,7 +426,7 @@ void pin( uint8_t ExtIntPinNum, uint8_t EnablePullup);
|
||||
************************************************************************************/
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*+
|
||||
@@ -421,7 +439,7 @@ void pin( uint8_t ExtIntPinNum, uint8_t EnablePullup);
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccReset(uint8_t hardReset ) __attribute__ ((weak));
|
||||
extern void notifyDccReset (uint8_t hardReset) __attribute__ ( (weak));
|
||||
|
||||
/*+
|
||||
* notifyDccIdle() Callback for a DCC idle command.
|
||||
@@ -432,7 +450,7 @@ extern void notifyDccReset(uint8_t hardReset ) __attribute__ ((weak));
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccIdle(void) __attribute__ ((weak));
|
||||
extern void notifyDccIdle (void) __attribute__ ( (weak));
|
||||
|
||||
|
||||
/*+
|
||||
@@ -453,7 +471,7 @@ extern void notifyDccIdle(void) __attribute__ ((weak));
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps ) __attribute__ ((weak));
|
||||
extern void notifyDccSpeed (uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps) __attribute__ ( (weak));
|
||||
|
||||
/*+
|
||||
* notifyDccSpeedRaw() Callback for a multifunction decoder speed command.
|
||||
@@ -467,7 +485,7 @@ extern void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Sp
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccSpeedRaw( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Raw) __attribute__ ((weak));
|
||||
extern void notifyDccSpeedRaw (uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Raw) __attribute__ ( (weak));
|
||||
|
||||
/*+
|
||||
* notifyDccFunc() Callback for a multifunction decoder function command.
|
||||
@@ -489,11 +507,11 @@ extern void notifyDccSpeedRaw( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) __attribute__ ((weak));
|
||||
extern void notifyDccFunc (uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) __attribute__ ( (weak));
|
||||
|
||||
/*+
|
||||
* notifyDccAccTurnoutBoard() Board oriented callback for a turnout accessory decoder.
|
||||
* Most useful when CV29_OUTPUT_ADDRESS_MODE is not set.
|
||||
* Most useful when CV29_OUTPUT_ADDRESS_MODE is NOT set.
|
||||
* Decoders of this type have 4 paired turnout outputs per board.
|
||||
* OutputPower is 1 if the power is on, and 0 otherwise.
|
||||
*
|
||||
@@ -511,11 +529,10 @@ extern void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP Fu
|
||||
* None
|
||||
*/
|
||||
|
||||
extern void notifyDccAccTurnoutBoard( uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower ) __attribute__ ((weak));
|
||||
extern void notifyDccAccTurnoutBoard (uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower) __attribute__ ( (weak));
|
||||
/*+
|
||||
* notifyDccAccTurnoutOutput() Output oriented callback for a turnout accessory decoder.
|
||||
* Most useful when CV29_OUTPUT_ADDRESS_MODE is not set.
|
||||
* Decoders of this type have 4 paired turnout outputs per board.
|
||||
* Most useful when CV29_OUTPUT_ADDRESS_MODE IS set.
|
||||
* OutputPower is 1 if the power is on, and 0 otherwise.
|
||||
*
|
||||
* Inputs:
|
||||
@@ -530,7 +547,7 @@ extern void notifyDccAccTurnoutBoard( uint16_t BoardAddr, uint8_t OutputPair,
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower ) __attribute__ ((weak));
|
||||
extern void notifyDccAccTurnoutOutput (uint16_t Addr, uint8_t Direction, uint8_t OutputPower) __attribute__ ( (weak));
|
||||
|
||||
/*+
|
||||
* notifyDccAccBoardAddrSet() Board oriented callback for a turnout accessory decoder.
|
||||
@@ -546,7 +563,7 @@ extern void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccAccBoardAddrSet( uint16_t BoardAddr) __attribute__ ((weak));
|
||||
extern void notifyDccAccBoardAddrSet (uint16_t BoardAddr) __attribute__ ( (weak));
|
||||
|
||||
/*+
|
||||
* notifyDccAccOutputAddrSet() Output oriented callback for a turnout accessory decoder.
|
||||
@@ -562,7 +579,7 @@ extern void notifyDccAccBoardAddrSet( uint16_t BoardAddr) __attribute__ ((wea
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccAccOutputAddrSet( uint16_t Addr) __attribute__ ((weak));
|
||||
extern void notifyDccAccOutputAddrSet (uint16_t Addr) __attribute__ ( (weak));
|
||||
|
||||
/*+
|
||||
* notifyDccSigOutputState() Callback for a signal aspect accessory decoder.
|
||||
@@ -575,7 +592,7 @@ extern void notifyDccAccOutputAddrSet( uint16_t Addr) __attribute__ ((weak));
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccSigOutputState( uint16_t Addr, uint8_t State) __attribute__ ((weak));
|
||||
extern void notifyDccSigOutputState (uint16_t Addr, uint8_t State) __attribute__ ( (weak));
|
||||
|
||||
/*+
|
||||
* notifyDccMsg() Raw DCC packet callback.
|
||||
@@ -590,7 +607,7 @@ extern void notifyDccSigOutputState( uint16_t Addr, uint8_t State) __attribut
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccMsg( DCC_MSG * Msg ) __attribute__ ((weak));
|
||||
extern void notifyDccMsg (DCC_MSG * Msg) __attribute__ ( (weak));
|
||||
|
||||
/*+
|
||||
* notifyCVValid() Callback to determine if a given CV is valid.
|
||||
@@ -608,7 +625,7 @@ extern void notifyDccMsg( DCC_MSG * Msg ) __attribute__ ((weak));
|
||||
* 1 - CV is valid.
|
||||
* 0 - CV is not valid.
|
||||
*/
|
||||
extern uint8_t notifyCVValid( uint16_t CV, uint8_t Writable ) __attribute__ ((weak));
|
||||
extern uint8_t notifyCVValid (uint16_t CV, uint8_t Writable) __attribute__ ( (weak));
|
||||
|
||||
/*+
|
||||
* notifyCVRead() Callback to read a CV.
|
||||
@@ -624,7 +641,7 @@ extern uint8_t notifyCVValid( uint16_t CV, uint8_t Writable ) __attribute__ ((we
|
||||
* Returns:
|
||||
* Value - Value of the CV.
|
||||
*/
|
||||
extern uint8_t notifyCVRead( uint16_t CV) __attribute__ ((weak));
|
||||
extern uint8_t notifyCVRead (uint16_t CV) __attribute__ ( (weak));
|
||||
|
||||
/*+
|
||||
* notifyCVWrite() Callback to write a value to a CV.
|
||||
@@ -641,7 +658,7 @@ extern uint8_t notifyCVRead( uint16_t CV) __attribute__ ((weak));
|
||||
* Returns:
|
||||
* Value - Value of the CV.
|
||||
*/
|
||||
extern uint8_t notifyCVWrite( uint16_t CV, uint8_t Value) __attribute__ ((weak));
|
||||
extern uint8_t notifyCVWrite (uint16_t CV, uint8_t Value) __attribute__ ( (weak));
|
||||
|
||||
/*+
|
||||
* notifyIsSetCVReady() Callback to to determine if CVs can be written.
|
||||
@@ -661,7 +678,7 @@ extern uint8_t notifyCVWrite( uint16_t CV, uint8_t Value) __attribute__ ((weak))
|
||||
* 1 - CV is ready to be written.
|
||||
* 0 - CV is not ready to be written.
|
||||
*/
|
||||
extern uint8_t notifyIsSetCVReady(void) __attribute__ ((weak));
|
||||
extern uint8_t notifyIsSetCVReady (void) __attribute__ ( (weak));
|
||||
|
||||
/*+
|
||||
* notifyCVChange() Called when a CV value is changed.
|
||||
@@ -679,8 +696,8 @@ extern uint8_t notifyIsSetCVReady(void) __attribute__ ((weak));
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyCVChange( uint16_t CV, uint8_t Value) __attribute__ ((weak));
|
||||
extern void notifyDccCVChange( uint16_t CV, uint8_t Value) __attribute__ ((weak));
|
||||
extern void notifyCVChange (uint16_t CV, uint8_t Value) __attribute__ ( (weak));
|
||||
extern void notifyDccCVChange (uint16_t CV, uint8_t Value) __attribute__ ( (weak));
|
||||
|
||||
/*+
|
||||
* notifyCVResetFactoryDefault() Called when CVs must be reset.
|
||||
@@ -697,7 +714,7 @@ extern void notifyDccCVChange( uint16_t CV, uint8_t Value) __attribute__ ((we
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyCVResetFactoryDefault(void) __attribute__ ((weak));
|
||||
extern void notifyCVResetFactoryDefault (void) __attribute__ ( (weak));
|
||||
|
||||
/*+
|
||||
* notifyCVAck() Called when a CV write must be acknowledged.
|
||||
@@ -710,7 +727,7 @@ extern void notifyCVResetFactoryDefault(void) __attribute__ ((weak));
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyCVAck(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.
|
||||
@@ -721,7 +738,7 @@ extern void notifyCVAck(void) __attribute__ ((weak));
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyAdvancedCVAck(void) __attribute__ ((weak));
|
||||
extern void notifyAdvancedCVAck (void) __attribute__ ( (weak));
|
||||
/*+
|
||||
* notifyServiceMode(bool) Called when state of 'inServiceMode' changes
|
||||
*
|
||||
@@ -731,12 +748,12 @@ extern void notifyAdvancedCVAck(void) __attribute__ ((weak));
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyServiceMode(bool) __attribute__ ((weak));
|
||||
extern void notifyServiceMode (bool) __attribute__ ( (weak));
|
||||
|
||||
// Deprecated, only for backward compatibility with version 1.4.2.
|
||||
// Don't use in new designs. These functions may be dropped in future versions
|
||||
extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State ) __attribute__ ((weak));
|
||||
extern void notifyDccSigState( uint16_t Addr, uint8_t OutputIndex, uint8_t State) __attribute__ ((weak));
|
||||
extern void notifyDccAccState (uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) __attribute__ ( (weak));
|
||||
extern void notifyDccSigState (uint16_t Addr, uint8_t OutputIndex, uint8_t State) __attribute__ ( (weak));
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
|
11
README.md
11
README.md
@@ -10,3 +10,14 @@ The library currently supports the AVR ATTiny84/85 & ATMega88/168/328/32u4 and T
|
||||
extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State )
|
||||
extern void notifyDccSigState( uint16_t Addr, uint8_t OutputIndex, uint8_t State)
|
||||
|
||||
|
||||
|
||||
Developers:
|
||||
Use of the supplied git pre-commit hook is encouraged. This will require installation of the 'astyle' package for formatting source file.
|
||||
See http://astyle.sourceforge.net for details on this package.
|
||||
|
||||
On Linux or Mac development machines, run the following command after you clone the repository:
|
||||
|
||||
ln -s support/pre-commit .git/hooks/pre-commit
|
||||
|
||||
Reformatting the source code to the preferred style is easy using astyle. Just run 'astyle --options=.astylerc NmraDcc.h NmraDcc.cpp'
|
||||
|
@@ -19,6 +19,9 @@
|
||||
#include <AccelStepper.h>
|
||||
#include <NmraDcc.h>
|
||||
|
||||
// Define the Arduino input Pin number for the DCC Signal
|
||||
#define DCC_PIN 2
|
||||
|
||||
// The lines below define the pins used to connect to the A4988 driver module
|
||||
#define A4988_STEP_PIN 4
|
||||
#define A4988_DIRECTION_PIN 5
|
||||
@@ -29,6 +32,9 @@
|
||||
#define DISABLE_OUTPUTS_IDLE
|
||||
#endif
|
||||
|
||||
// Uncomment the following line to enable Debug Print of DCC Messages
|
||||
//#define NOTIFY_DCC_MSG
|
||||
|
||||
// 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
|
||||
@@ -119,15 +125,10 @@ 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 )
|
||||
|
||||
void processTurnoutCommand(uint16_t Addr, uint8_t Direction, uint8_t OutputPower)
|
||||
{
|
||||
Serial.print(F("notifyDccAccTurnoutOutput: "));
|
||||
Serial.print(Addr,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.print(Direction,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.println(OutputPower, HEX) ;
|
||||
Serial.print(F("processTurnoutCommand: "));
|
||||
|
||||
for (int i = 0; i < MAX_TURNOUT_POSITIONS ; i++)
|
||||
{
|
||||
@@ -186,6 +187,22 @@ void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t Output
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This function is called from the Library whenever a normal DCC Turnout Packet is received
|
||||
void notifyDccAccTurnoutBoard (uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower)
|
||||
{
|
||||
uint16_t Addr = ((BoardAddr - 1) * 4) + OutputPair + 1;
|
||||
|
||||
Serial.print(F("notifyDccAccTurnoutBoard: "));
|
||||
Serial.print(Addr,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.print(Direction,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.println(OutputPower, HEX) ;
|
||||
|
||||
processTurnoutCommand(Addr, Direction, OutputPower);
|
||||
};
|
||||
|
||||
#ifdef DISABLE_OUTPUTS_IDLE
|
||||
@@ -244,16 +261,24 @@ void setupDCCDecoder()
|
||||
Serial.println(F("Setting up DCC Decorder..."));
|
||||
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
Dcc.pin(0, 2, 1);
|
||||
// Many Arduino Cores now support the digitalPinToInterrupt() function that makes it easier to figure out the
|
||||
// Interrupt Number for the Arduino Pin number, which reduces confusion.
|
||||
#ifdef digitalPinToInterrupt
|
||||
Dcc.pin(DCC_PIN, 0);
|
||||
#else
|
||||
Dcc.pin(0, DCC_PIN, 1);
|
||||
#endif
|
||||
|
||||
// Call the main DCC Init function to enable the DCC Receiver
|
||||
Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 );
|
||||
Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER, 0 );
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while(!Serial); // Wait for the USB Device to Enumerate
|
||||
uint8_t maxWaitLoops = 255;
|
||||
while(!Serial && maxWaitLoops--) // Wait for the USB Device to Enumerate
|
||||
delay(20);
|
||||
|
||||
Serial.println(F("\nExample Stepper Motor Driver for DCC Turntable Control"));
|
||||
|
||||
@@ -287,7 +312,7 @@ void setup()
|
||||
setupDCCDecoder();
|
||||
|
||||
// Fake a DCC Packet to cause the Turntable to move to Position 1
|
||||
notifyDccAccTurnoutOutput(POSITION_01_DCC_ADDRESS, 1, 1);
|
||||
processTurnoutCommand(POSITION_01_DCC_ADDRESS, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,3 +336,16 @@ void loop()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef NOTIFY_DCC_MSG
|
||||
void notifyDccMsg( DCC_MSG * Msg)
|
||||
{
|
||||
Serial.print("notifyDccMsg: ") ;
|
||||
for(uint8_t i = 0; i < Msg->Size; i++)
|
||||
{
|
||||
Serial.print(Msg->Data[i], HEX);
|
||||
Serial.write(' ');
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
#endif
|
||||
|
487
examples/Fahrstuhl/Fahrstuhl.ino
Normal file
487
examples/Fahrstuhl/Fahrstuhl.ino
Normal file
@@ -0,0 +1,487 @@
|
||||
#include <AccelStepper.h> // Requires AccelStepper Library - http://www.airspayce.com/mikem/arduino/AccelStepper/
|
||||
#include <EncButton2.h> // Requires EncButton library - https://github.com/GyverLibs/EncButton
|
||||
#include <elapsedMillis.h> // Requires elapsedMillis library - https://github.com/pfeerick/elapsedMillis
|
||||
|
||||
#define OPTIMIZE_I2C 1
|
||||
|
||||
#include <Wire.h>
|
||||
#include <SSD1306Ascii.h>
|
||||
#include <SSD1306AsciiWire.h>
|
||||
#include <EEPROM.h>
|
||||
#include <NmraDcc.h>
|
||||
|
||||
// You can print every DCC packet by un-commenting the line below
|
||||
//#define NOTIFY_DCC_MSG
|
||||
|
||||
// Define the Arduino Pin to connect to the DCC input signal
|
||||
#define DCC_PIN 2
|
||||
|
||||
// Define the DCC Turnout Address to select the first level = 1
|
||||
#define DCC_ACCESSORY_DECODER_BASE_ADDRESS 200
|
||||
|
||||
// Define the manimus numbr of Levels
|
||||
#define NUM_LIFT_LEVELS 8
|
||||
|
||||
#define PROGRAM_NAME "Fahrstuhl"
|
||||
#define PROGRAM_VERSION "1.1"
|
||||
|
||||
// Locate the Persistant State storage EEPROM space well above the DCC Accessory Decoder CV Storage
|
||||
#define EEPROM_BASE_ADDR 100
|
||||
#define EEPROM_VALID_DATA_SIGNATURE 0xA5A5
|
||||
// Uncomment the line below to force the EEPROM values to be reset to defaults
|
||||
//#define EEPROM_FORCE_RELOAD_DEFAULT_VALUES
|
||||
|
||||
#define BUTTON_LONG_PRESS_DELAY 2000
|
||||
|
||||
// Uncomment ONE of the next 2 lines to enable AJS or UWE Board Settings
|
||||
//#define AJS_BOARD_SETTINGS
|
||||
#define UWE_BOARD_SETTINGS
|
||||
|
||||
#if defined(AJS_BOARD_SETTINGS) // Setting for AJS Dev System
|
||||
|
||||
// Uncomment the next line to reverse the direction of the stepper movement
|
||||
#define REVERSE_STEPPER_DIRECTION
|
||||
|
||||
#define HOME_SENSOR_PIN 10
|
||||
|
||||
#define STEPPER_PULSE_PIN 11
|
||||
#define STEPPER_ENABLE_PIN 12
|
||||
#define STEPPER_DIR_PIN 13
|
||||
|
||||
#define STEPPER_MAX_SPEED 2100
|
||||
#define STEPPER_NORMAL_ACCELERATION 5000
|
||||
#define STEPPER_MAX_POSITION 300000U // Maximum Steps to allow the stepper to drive Up Saftey mechanism
|
||||
|
||||
#define BUTTON_MANUAL A3
|
||||
#define BUTTON_DOWN A2
|
||||
#define BUTTON_UP A1
|
||||
#define BUTTON_STOP_HOME A0
|
||||
|
||||
long defaultPositions[NUM_LIFT_LEVELS] = {1000, 4000, 7000, 10000, 13000, 16000, 19000, 22000}; // Default positions
|
||||
|
||||
#define STEPPER_INC_SPEED (STEPPER_MAX_SPEED / 10)
|
||||
|
||||
#define OLED_DISPLAY_I2C_ADDRESS 0x3C
|
||||
|
||||
#elif defined (UWE_BOARD_SETTINGS) // Setting for Uwe's Fahrstuhl System
|
||||
|
||||
// Uncomment the next line to reverse the direction of the stepper movement
|
||||
//#define REVERSE_STEPPER_DIRECTION
|
||||
|
||||
#define HOME_SENSOR_PIN 7
|
||||
|
||||
#define STEPPER_PULSE_PIN 4
|
||||
#define STEPPER_ENABLE_PIN 5
|
||||
#define STEPPER_DIR_PIN 6
|
||||
|
||||
#define STEPPER_MAX_SPEED 2100
|
||||
#define STEPPER_NORMAL_ACCELERATION 5000
|
||||
#define STEPPER_MAX_POSITION 1970000U // Maximum Steps to allow the stepper to drive Up Saftey mechanism
|
||||
|
||||
#define BUTTON_MANUAL 8
|
||||
#define BUTTON_DOWN 9
|
||||
#define BUTTON_UP 10
|
||||
#define BUTTON_STOP_HOME 11
|
||||
|
||||
long defaultPositions[NUM_LIFT_LEVELS] = {0, 161064, 32500, 483284, 645326, 808041, 1967457, 1130774}; // Default positions
|
||||
|
||||
#define STEPPER_INC_SPEED (STEPPER_MAX_SPEED / 2)
|
||||
|
||||
#define OLED_DISPLAY_I2C_ADDRESS 0x3C
|
||||
|
||||
#else
|
||||
#error No Board Settings Defined
|
||||
#endif
|
||||
|
||||
SSD1306AsciiWire oled;
|
||||
|
||||
#define STEPPER_MAN_SPEED_CHANGE_MILLIS 5
|
||||
#define STEPPER_EMERGENCY_STOP_ACCELERATION 100000
|
||||
#define LIFT_LEVEL_NOT_SET -1
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t numLiftLevels;
|
||||
uint8_t lastLiftLevel;
|
||||
long lastStepperPosition;
|
||||
long levelPositions[NUM_LIFT_LEVELS];
|
||||
uint16_t objectSignature;
|
||||
} PERSISTENT_VALUES;
|
||||
|
||||
PERSISTENT_VALUES persistentValues;
|
||||
|
||||
// Define a stepper and the pins it will use
|
||||
AccelStepper stepper(AccelStepper::DRIVER, STEPPER_PULSE_PIN, STEPPER_DIR_PIN, -1, -1, false);
|
||||
|
||||
EncButton2<EB_BTN> homeSensor(INPUT_PULLUP, HOME_SENSOR_PIN);
|
||||
|
||||
EncButton2<EB_BTN> btnManual(INPUT, BUTTON_MANUAL);
|
||||
EncButton2<EB_BTN> btnDown(INPUT, BUTTON_DOWN);
|
||||
EncButton2<EB_BTN> btnUp(INPUT, BUTTON_UP);
|
||||
EncButton2<EB_BTN> btnStopHome(INPUT, BUTTON_STOP_HOME);
|
||||
|
||||
// NMRA DCC Accessory Decoder object
|
||||
NmraDcc Dcc;
|
||||
|
||||
void displayLevel(int newLevel)
|
||||
{
|
||||
oled.setCursor(0,0);
|
||||
oled.set2X();
|
||||
oled.print("Level: ");
|
||||
oled.print(newLevel);
|
||||
oled.clearToEOL();
|
||||
}
|
||||
|
||||
void displayMessage(const char* Msg)
|
||||
{
|
||||
oled.setCursor(0,4);
|
||||
oled.set2X();
|
||||
oled.print(Msg); oled.clearToEOL();
|
||||
}
|
||||
|
||||
void displayMessageNumber(const char* Msg, int Number)
|
||||
{
|
||||
oled.setCursor(0,4);
|
||||
oled.set2X();
|
||||
oled.print(Msg);
|
||||
oled.print(Number);
|
||||
oled.clearToEOL();
|
||||
}
|
||||
|
||||
void displayPosition(long newPosition)
|
||||
{
|
||||
oled.setCursor(0,7);
|
||||
oled.set1X();
|
||||
oled.print("Pos: ");
|
||||
oled.print(newPosition);
|
||||
oled.clearToEOL();
|
||||
}
|
||||
|
||||
void initPersistentValues()
|
||||
{
|
||||
EEPROM.get(EEPROM_BASE_ADDR, persistentValues);
|
||||
|
||||
#ifdef EEPROM_FORCE_RELOAD_DEFAULT_VALUES
|
||||
persistentValues.objectSignature = 0;
|
||||
#endif
|
||||
|
||||
if(persistentValues.objectSignature != EEPROM_VALID_DATA_SIGNATURE)
|
||||
{
|
||||
Serial.println("initPersistentValues: set detault values");
|
||||
|
||||
persistentValues.numLiftLevels = NUM_LIFT_LEVELS;
|
||||
persistentValues.lastLiftLevel = 0;
|
||||
persistentValues.lastStepperPosition = 0;
|
||||
persistentValues.objectSignature = EEPROM_VALID_DATA_SIGNATURE;
|
||||
for(uint8_t i = 0; i < NUM_LIFT_LEVELS; i++)
|
||||
persistentValues.levelPositions[i] = defaultPositions[i];
|
||||
|
||||
EEPROM.put(EEPROM_BASE_ADDR, persistentValues);
|
||||
}
|
||||
else
|
||||
Serial.println("initPersistentValues: restored values from EEPROM");
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
uint8_t maxWaitLoops = 255;
|
||||
while(!Serial && maxWaitLoops--)
|
||||
delay(20);
|
||||
|
||||
Serial.println(); Serial.print(PROGRAM_NAME); Serial.print(" Version: "); Serial.println(PROGRAM_VERSION);
|
||||
|
||||
initPersistentValues();
|
||||
|
||||
Wire.begin();
|
||||
Wire.setClock(400000L);
|
||||
|
||||
oled.setFont(cp437font8x8);
|
||||
|
||||
oled.begin(&Adafruit128x64, OLED_DISPLAY_I2C_ADDRESS);
|
||||
oled.clear();
|
||||
oled.println(PROGRAM_NAME);
|
||||
oled.println();
|
||||
oled.print("Ver: "); oled.println(PROGRAM_VERSION);
|
||||
oled.println();
|
||||
oled.print("Max Levels: "); oled.println(NUM_LIFT_LEVELS);
|
||||
oled.println();
|
||||
oled.print("Used Levels: "); oled.println(persistentValues.numLiftLevels);
|
||||
delay(2000);
|
||||
oled.clear();
|
||||
displayLevel(persistentValues.lastLiftLevel + 1);
|
||||
displayPosition(persistentValues.lastStepperPosition);
|
||||
|
||||
stepper.setCurrentPosition(persistentValues.lastStepperPosition);
|
||||
|
||||
stepper.setEnablePin(STEPPER_ENABLE_PIN);
|
||||
#ifdef REVERSE_STEPPER_DIRECTION
|
||||
stepper.setPinsInverted(true, false, true);
|
||||
#else
|
||||
stepper.setPinsInverted(false, false, true);
|
||||
#endif
|
||||
|
||||
stepper.setMaxSpeed(STEPPER_MAX_SPEED);
|
||||
|
||||
btnStopHome.setHoldTimeout(BUTTON_LONG_PRESS_DELAY);
|
||||
btnManual.setHoldTimeout(BUTTON_LONG_PRESS_DELAY);
|
||||
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
Dcc.pin(DCC_PIN, 1);
|
||||
|
||||
// Call the main DCC Init function to enable the DCC Receiver
|
||||
Dcc.init(MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0);
|
||||
}
|
||||
|
||||
void stepperMoveTo(long newPosition)
|
||||
{
|
||||
stepper.enableOutputs();
|
||||
stepper.setAcceleration(STEPPER_NORMAL_ACCELERATION);
|
||||
stepper.moveTo(newPosition);
|
||||
}
|
||||
|
||||
void stepperMove(long newRelPosition)
|
||||
{
|
||||
stepper.enableOutputs();
|
||||
stepper.setAcceleration(STEPPER_NORMAL_ACCELERATION);
|
||||
stepper.move(newRelPosition);
|
||||
}
|
||||
void stopStepper(void)
|
||||
{
|
||||
stepper.setAcceleration(STEPPER_EMERGENCY_STOP_ACCELERATION);
|
||||
stepper.move(0);
|
||||
stepper.stop();
|
||||
while(stepper.run());
|
||||
stepper.disableOutputs();
|
||||
}
|
||||
|
||||
int lastSpeed = 0;
|
||||
int newSpeed = 0;
|
||||
bool wasRunning = false;
|
||||
bool configMode = false;
|
||||
bool homing = false;
|
||||
elapsedMillis lastSpeedChange = 0;
|
||||
|
||||
|
||||
// This function is called whenever a normal DCC Turnout Packet is received
|
||||
// The DCC Turnout Address is checked to see if it is within the range used to Select Elevator levels and starts a Move if a new level is selected
|
||||
void notifyDccAccTurnoutOutput(uint16_t receivedAddress, uint8_t direction, uint8_t outputPower)
|
||||
{
|
||||
if((receivedAddress >= DCC_ACCESSORY_DECODER_BASE_ADDRESS) && (receivedAddress < (DCC_ACCESSORY_DECODER_BASE_ADDRESS + NUM_LIFT_LEVELS)))
|
||||
{
|
||||
uint8_t newLevel = receivedAddress - DCC_ACCESSORY_DECODER_BASE_ADDRESS;
|
||||
if(persistentValues.lastLiftLevel != newLevel)
|
||||
{
|
||||
persistentValues.lastLiftLevel = newLevel;
|
||||
|
||||
long newPos = persistentValues.levelPositions[persistentValues.lastLiftLevel];
|
||||
stepperMoveTo(newPos);
|
||||
|
||||
Serial.print("notifyDccAccTurnoutOutput: Move to Level: "); Serial.print(persistentValues.lastLiftLevel); Serial.print(" Pos: "); Serial.println(newPos);
|
||||
|
||||
displayMessageNumber("Mv To: ", persistentValues.lastLiftLevel + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
Dcc.process();
|
||||
|
||||
//First check the Home Sensor and stop the motor if going in the down direction
|
||||
homeSensor.tick();
|
||||
if(homeSensor.state())
|
||||
{
|
||||
if((configMode || homing) && stepper.isRunning() && (lastSpeed <= 0))
|
||||
{
|
||||
stopStepper();
|
||||
|
||||
Serial.print("Home Sensor Hit - LastSpeed: ");
|
||||
Serial.print(lastSpeed);
|
||||
Serial.print(" Last Position: ");
|
||||
Serial.println(stepper.currentPosition());
|
||||
|
||||
newSpeed = 0;
|
||||
lastSpeed = newSpeed;
|
||||
|
||||
persistentValues.lastLiftLevel = 0;
|
||||
persistentValues.lastStepperPosition = 0;
|
||||
stepper.setCurrentPosition(persistentValues.lastStepperPosition);
|
||||
|
||||
EEPROM.put(EEPROM_BASE_ADDR, persistentValues);
|
||||
|
||||
if(homing)
|
||||
{
|
||||
long newPos = persistentValues.levelPositions[persistentValues.lastLiftLevel];
|
||||
stepperMoveTo(newPos);
|
||||
Serial.print("Home Sensor Hit: Move To: "); Serial.print(persistentValues.lastLiftLevel); Serial.print(" Pos: "); Serial.println(newPos);
|
||||
homing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we haven't gone beyond the end point of the traverser.
|
||||
if(stepper.currentPosition() >= STEPPER_MAX_POSITION)
|
||||
{
|
||||
if(configMode && stepper.isRunning() && (lastSpeed >= 0))
|
||||
{
|
||||
stopStepper();
|
||||
|
||||
Serial.print("Maximum Position Hit - LastSpeed: ");
|
||||
Serial.print(lastSpeed);
|
||||
Serial.print(" Last Position: ");
|
||||
Serial.println(stepper.currentPosition());
|
||||
|
||||
newSpeed = 0;
|
||||
lastSpeed = newSpeed;
|
||||
|
||||
displayMessage("At Max");
|
||||
}
|
||||
}
|
||||
|
||||
btnStopHome.tick();
|
||||
if(btnStopHome.press())
|
||||
{
|
||||
Serial.print("StopHome Click - Current Pos: "); Serial.println(stepper.currentPosition());
|
||||
displayMessage("Stop");
|
||||
if(stepper.isRunning())
|
||||
{
|
||||
newSpeed = 0;
|
||||
stopStepper();
|
||||
}
|
||||
}
|
||||
|
||||
if(btnStopHome.held())
|
||||
{
|
||||
Serial.println("StopHome Held: Moving to Home Position");
|
||||
displayMessage("Homing");
|
||||
homing = true;
|
||||
newSpeed = -STEPPER_MAX_SPEED;
|
||||
}
|
||||
|
||||
btnManual.tick();
|
||||
if(btnManual.press())
|
||||
{
|
||||
Serial.print("Manual Press - Current Pos: "); Serial.println(stepper.currentPosition());
|
||||
if(configMode)
|
||||
{
|
||||
configMode = false;
|
||||
Serial.println("Home Click - Exit Manual Mode");
|
||||
}
|
||||
}
|
||||
|
||||
if(btnManual.held())
|
||||
{
|
||||
Serial.print("Manual Held - Enter Manual Mode Pos: "); Serial.println(stepper.currentPosition());
|
||||
configMode = true;
|
||||
}
|
||||
|
||||
btnDown.tick();
|
||||
if(configMode)
|
||||
{
|
||||
if((btnDown.press() || btnDown.step()) && (stepper.currentPosition() < STEPPER_MAX_POSITION) && (lastSpeed <= (STEPPER_MAX_SPEED - STEPPER_INC_SPEED)))
|
||||
{
|
||||
newSpeed = lastSpeed + STEPPER_INC_SPEED;
|
||||
lastSpeedChange = STEPPER_MAN_SPEED_CHANGE_MILLIS;
|
||||
Serial.print("Down Press - Current Pos: "); Serial.print(stepper.currentPosition()); Serial.print(" New Speed: "); Serial.println(newSpeed);
|
||||
|
||||
displayMessage("Down");
|
||||
}
|
||||
}
|
||||
|
||||
else if((btnDown.press() || btnDown.step()) && persistentValues.lastLiftLevel > 0)
|
||||
{
|
||||
Serial.print("Down Press - Current Level: "); Serial.print(persistentValues.lastLiftLevel);
|
||||
persistentValues.lastLiftLevel--;
|
||||
long newPos = persistentValues.levelPositions[persistentValues.lastLiftLevel];
|
||||
stepperMoveTo(newPos);
|
||||
Serial.print(" Move To: "); Serial.print(persistentValues.lastLiftLevel); Serial.print(" Pos: "); Serial.println(newPos);
|
||||
|
||||
displayMessageNumber("Dn To: ", persistentValues.lastLiftLevel + 1);
|
||||
}
|
||||
|
||||
btnUp.tick();
|
||||
if(configMode)
|
||||
{
|
||||
if((btnUp.press() || btnDown.step()) && (homeSensor.state() == 0) && (lastSpeed >= -(STEPPER_MAX_SPEED - STEPPER_INC_SPEED)))
|
||||
{
|
||||
newSpeed = lastSpeed - STEPPER_INC_SPEED;
|
||||
lastSpeedChange = STEPPER_MAN_SPEED_CHANGE_MILLIS;
|
||||
Serial.print("Up Press - Current Pos: "); Serial.print(stepper.currentPosition()); Serial.print(" New Speed: "); Serial.println(newSpeed);
|
||||
|
||||
displayMessage("Up");
|
||||
}
|
||||
}
|
||||
|
||||
else if((btnUp.press() || btnDown.step()) && (persistentValues.lastLiftLevel < (persistentValues.numLiftLevels - 1)))
|
||||
{
|
||||
Serial.print("Up Press - Current Level: "); Serial.print(persistentValues.lastLiftLevel);
|
||||
persistentValues.lastLiftLevel++;
|
||||
long newPos = persistentValues.levelPositions[persistentValues.lastLiftLevel];
|
||||
stepperMoveTo(newPos);
|
||||
Serial.print(" Move To: "); Serial.print(persistentValues.lastLiftLevel); Serial.print(" Pos: "); Serial.println(newPos);
|
||||
|
||||
displayMessageNumber("Up To: ", persistentValues.lastLiftLevel + 1);
|
||||
}
|
||||
|
||||
|
||||
if(lastSpeed != newSpeed)
|
||||
{
|
||||
// Serial.print("Speed Change: Last: "); Serial.print(lastSpeed); Serial.print(" New: "); Serial.print(newSpeed);
|
||||
// Serial.print(" - Current Pos: "); Serial.print(stepper.currentPosition());
|
||||
|
||||
if( newSpeed == 0)
|
||||
{
|
||||
lastSpeed = newSpeed;
|
||||
stopStepper();
|
||||
Serial.print("Speed Change: Stopped Last: "); Serial.print(lastSpeed); Serial.print(" New: "); Serial.println(newSpeed);
|
||||
}
|
||||
|
||||
else if(lastSpeedChange >= STEPPER_MAN_SPEED_CHANGE_MILLIS)
|
||||
{
|
||||
lastSpeedChange = 0;
|
||||
|
||||
if(newSpeed > lastSpeed)
|
||||
lastSpeed++;
|
||||
else
|
||||
lastSpeed--;
|
||||
|
||||
stepper.setSpeed(lastSpeed);
|
||||
stepper.enableOutputs();
|
||||
|
||||
// Serial.print(" Set New Speed: "); Serial.println(newSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
if(lastSpeed)
|
||||
stepper.runSpeed();
|
||||
|
||||
else
|
||||
stepper.run();
|
||||
|
||||
if(!stepper.isRunning() && wasRunning)
|
||||
{
|
||||
Serial.println("Disable Outputs");
|
||||
stepper.disableOutputs();
|
||||
|
||||
displayLevel(persistentValues.lastLiftLevel + 1);
|
||||
displayMessage("");
|
||||
persistentValues.lastStepperPosition = stepper.currentPosition();
|
||||
displayPosition(persistentValues.lastStepperPosition);
|
||||
EEPROM.put(EEPROM_BASE_ADDR, persistentValues);
|
||||
}
|
||||
wasRunning = stepper.isRunning();
|
||||
}
|
||||
|
||||
#ifdef NOTIFY_DCC_MSG
|
||||
void notifyDccMsg( DCC_MSG * Msg)
|
||||
{
|
||||
Serial.print("notifyDccMsg: ") ;
|
||||
for(uint8_t i = 0; i < Msg->Size; i++)
|
||||
{
|
||||
Serial.print(Msg->Data[i], HEX);
|
||||
Serial.write(' ');
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
#endif
|
@@ -7,6 +7,9 @@
|
||||
NmraDcc Dcc ;
|
||||
DCC_MSG Packet ;
|
||||
|
||||
// Define the Arduino input Pin number for the DCC Signal
|
||||
#define DCC_PIN 2
|
||||
|
||||
struct CVPair
|
||||
{
|
||||
uint16_t CV;
|
||||
@@ -15,8 +18,8 @@ struct CVPair
|
||||
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, 1},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, DEFAULT_ACCESSORY_DECODER_ADDRESS & 0xFF},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, DEFAULT_ACCESSORY_DECODER_ADDRESS >> 8},
|
||||
};
|
||||
|
||||
uint8_t FactoryDefaultCVIndex = 0;
|
||||
@@ -92,6 +95,9 @@ void notifyDccSigOutputState( uint16_t Addr, uint8_t State)
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
uint8_t maxWaitLoops = 255;
|
||||
while(!Serial && maxWaitLoops--)
|
||||
delay(20);
|
||||
|
||||
// Configure the DCC CV Programing ACK pin for an output
|
||||
pinMode( DccAckPin, OUTPUT );
|
||||
@@ -99,7 +105,13 @@ void setup()
|
||||
Serial.println("NMRA DCC Example 1");
|
||||
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
Dcc.pin(0, 2, 1);
|
||||
// Many Arduino Cores now support the digitalPinToInterrupt() function that makes it easier to figure out the
|
||||
// Interrupt Number for the Arduino Pin number, which reduces confusion.
|
||||
#ifdef digitalPinToInterrupt
|
||||
Dcc.pin(DCC_PIN, 0);
|
||||
#else
|
||||
Dcc.pin(0, DCC_PIN, 1);
|
||||
#endif
|
||||
|
||||
// Call the main DCC Init function to enable the DCC Receiver
|
||||
Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 );
|
||||
|
@@ -9,7 +9,7 @@
|
||||
#define NOTIFY_TURNOUT_MSG
|
||||
|
||||
// You can also print other Debug Messages uncommenting the line below
|
||||
#define DEBUG_MSG
|
||||
//#define DEBUG_MSG
|
||||
|
||||
// Un-Comment the line below to force CVs to be written to the Factory Default values
|
||||
// defined in the FactoryDefaultCVs below on Start-Up
|
||||
@@ -18,6 +18,9 @@
|
||||
// Un-Comment the line below to Enable DCC ACK for Service Mode Programming Read CV Capablilty
|
||||
//#define ENABLE_DCC_ACK 15 // This is A1 on the Iowa Scaled Engineering ARD-DCCSHIELD DCC Shield
|
||||
|
||||
// Define the Arduino input Pin number for the DCC Signal
|
||||
#define DCC_PIN 2
|
||||
|
||||
#define NUM_TURNOUTS 8 // Set Number of Turnouts (Pairs of Pins)
|
||||
#define ACTIVE_OUTPUT_STATE LOW // Set the ACTIVE State of the output to Drive the Turnout motor electronics HIGH or LOW
|
||||
|
||||
@@ -40,8 +43,8 @@ struct CVPair
|
||||
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, 1}, // CV 1 Board Address (lower 6 bits)
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0}, // CV 9 Board Address (Upper 3 bits)
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, DEFAULT_ACCESSORY_DECODER_ADDRESS & 0xFF},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, DEFAULT_ACCESSORY_DECODER_ADDRESS >> 8},
|
||||
{CV_ACCESSORY_DECODER_OUTPUT_PULSE_TIME, 50}, // x 10mS for the output pulse duration
|
||||
{CV_ACCESSORY_DECODER_CDU_RECHARGE_TIME, 30}, // x 10mS for the CDU recharge delay time
|
||||
{CV_ACCESSORY_DECODER_ACTIVE_STATE, ACTIVE_OUTPUT_STATE},
|
||||
@@ -117,12 +120,21 @@ void initPinPulser(void)
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
uint8_t maxWaitLoops = 255;
|
||||
while(!Serial && maxWaitLoops--)
|
||||
delay(20);
|
||||
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
Dcc.pin(0, 2, 1);
|
||||
// Many Arduino Cores now support the digitalPinToInterrupt() function that makes it easier to figure out the
|
||||
// Interrupt Number for the Arduino Pin number, which reduces confusion.
|
||||
#ifdef digitalPinToInterrupt
|
||||
Dcc.pin(DCC_PIN, 0);
|
||||
#else
|
||||
Dcc.pin(0, DCC_PIN, 1);
|
||||
#endif
|
||||
|
||||
// Call the main DCC Init function to enable the DCC Receiver
|
||||
Dcc.init( MAN_ID_DIY, DCC_DECODER_VERSION_NUM, CV29_ACCESSORY_DECODER, 0 );
|
||||
Dcc.init( MAN_ID_DIY, DCC_DECODER_VERSION_NUM, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, 0 );
|
||||
|
||||
#ifdef DEBUG_MSG
|
||||
Serial.print("\nNMRA DCC 8-Turnout Accessory Decoder. Ver: "); Serial.println(DCC_DECODER_VERSION_NUM,DEC);
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#include <NmraDcc.h>
|
||||
|
||||
#define This_Decoder_Address 3
|
||||
// Define the Arduino input Pin number for the DCC Signal
|
||||
#define DCC_PIN 2
|
||||
|
||||
struct CVPair
|
||||
{
|
||||
@@ -11,11 +12,11 @@ struct CVPair
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
// The CV Below defines the Short DCC Address
|
||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address},
|
||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, DEFAULT_MULTIFUNCTION_DECODER_ADDRESS},
|
||||
|
||||
// These two CVs define the Long DCC Address
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, This_Decoder_Address},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB(DEFAULT_MULTIFUNCTION_DECODER_ADDRESS)},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_LSB(DEFAULT_MULTIFUNCTION_DECODER_ADDRESS)},
|
||||
|
||||
// ONLY uncomment 1 CV_29_CONFIG line below as approprate
|
||||
// {CV_29_CONFIG, 0}, // Short Address 14 Speed Steps
|
||||
@@ -163,14 +164,24 @@ void notifyCVAck(void)
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
uint8_t maxWaitLoops = 255;
|
||||
while(!Serial && maxWaitLoops--)
|
||||
delay(20);
|
||||
|
||||
Serial.println("NMRA Dcc Multifunction Decoder Demo 1");
|
||||
|
||||
// Configure the DCC CV Programing ACK pin for an output
|
||||
pinMode( DccAckPin, OUTPUT );
|
||||
digitalWrite( DccAckPin, LOW );
|
||||
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
Dcc.pin(0, 2, 0);
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
// Many Arduino Cores now support the digitalPinToInterrupt() function that makes it easier to figure out the
|
||||
// Interrupt Number for the Arduino Pin number, which reduces confusion.
|
||||
#ifdef digitalPinToInterrupt
|
||||
Dcc.pin(DCC_PIN, 0);
|
||||
#else
|
||||
Dcc.pin(0, DCC_PIN, 1);
|
||||
#endif
|
||||
|
||||
// Call the main DCC Init function to enable the DCC Receiver
|
||||
//Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 );
|
||||
@@ -192,4 +203,3 @@ void loop()
|
||||
Dcc.setCV( FactoryDefaultCVs[FactoryDefaultCVIndex].CV, FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,311 @@
|
||||
// NMRA Dcc Multifunction Motor Decoder Demo using the Seeed XIAO Expansion board
|
||||
// See: https://wiki.seeedstudio.com/Seeeduino-XIAO-Expansion-Board/
|
||||
//
|
||||
// Author: Alex Shepherd 2023-02-15
|
||||
//
|
||||
// This example requires these Arduino Libraries:
|
||||
//
|
||||
// 1) The NmraDcc Library from: http://mrrwa.org/download/
|
||||
//
|
||||
// These libraries can be found and installed via the Arduino IDE Library Manager
|
||||
//
|
||||
// This simple demo displays the Multifunction Decoder actions on the builtin OLED Display
|
||||
//
|
||||
|
||||
#include <NmraDcc.h>
|
||||
|
||||
#include <U8x8lib.h>
|
||||
#include <Wire.h>
|
||||
|
||||
// Uncomment any of the lines below to enable debug messages for different parts of the code
|
||||
#define DEBUG_FUNCTIONS
|
||||
#define DEBUG_SPEED
|
||||
//#define DEBUG_DCC_MSG
|
||||
|
||||
#if defined(DEBUG_FUNCTIONS) or defined(DEBUG_SPEED) or defined(DEBUG_PWM) or defined(DEBUG_DCC_MSG)
|
||||
#define DEBUG_PRINT
|
||||
#endif
|
||||
|
||||
// This is the default DCC Address
|
||||
#define DEFAULT_DECODER_ADDRESS 3
|
||||
|
||||
#ifndef ARDUINO_SEEED_XIAO_M0
|
||||
#error "Unsupported CPU, you need to add another configuration section for your CPU"
|
||||
#endif
|
||||
|
||||
// I used a IoTT DCC Interface connected to Grove Analog Input which has A0 or 0 Pin
|
||||
#define DCC_PIN 0
|
||||
|
||||
uint8_t newDirection = 0;
|
||||
uint8_t lastDirection = 0;
|
||||
|
||||
uint8_t newSpeed = 0;
|
||||
uint8_t lastSpeed = 0;
|
||||
uint8_t numSpeedSteps = SPEED_STEP_128;
|
||||
|
||||
uint8_t lastFuncStateList[FN_LAST+1];
|
||||
|
||||
// Structure for CV Values Table
|
||||
struct CVPair
|
||||
{
|
||||
uint16_t CV;
|
||||
uint8_t Value;
|
||||
};
|
||||
|
||||
// Default CV Values Table
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
// The CV Below defines the Short DCC Address
|
||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, DEFAULT_DECODER_ADDRESS},
|
||||
|
||||
// These two CVs define the Long DCC Address
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB(DEFAULT_DECODER_ADDRESS)},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_LSB(DEFAULT_DECODER_ADDRESS)},
|
||||
|
||||
// ONLY uncomment 1 CV_29_CONFIG line below as approprate
|
||||
// {CV_29_CONFIG, 0}, // Short Address 14 Speed Steps
|
||||
{CV_29_CONFIG, CV29_F0_LOCATION}, // Short Address 28/128 Speed Steps
|
||||
// {CV_29_CONFIG, CV29_EXT_ADDRESSING | CV29_F0_LOCATION}, // Long Address 28/128 Speed Steps
|
||||
};
|
||||
|
||||
NmraDcc Dcc ;
|
||||
|
||||
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(PIN_WIRE_SCL, PIN_WIRE_SDA, U8X8_PIN_NONE); // OLEDs without Reset of the Display
|
||||
|
||||
uint8_t FactoryDefaultCVIndex = 0;
|
||||
|
||||
void notifyCVResetFactoryDefault()
|
||||
{
|
||||
// Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset
|
||||
// to flag to the loop() function that a reset to Factory Defaults needs to be done
|
||||
FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
|
||||
};
|
||||
|
||||
// This call-back function is called whenever we receive a DCC Speed packet for our address
|
||||
void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps )
|
||||
{
|
||||
#ifdef DEBUG_SPEED
|
||||
Serial.print("notifyDccSpeed: Addr: ");
|
||||
Serial.print(Addr,DEC);
|
||||
Serial.print( (AddrType == DCC_ADDR_SHORT) ? "-S" : "-L" );
|
||||
Serial.print(" Speed: ");
|
||||
Serial.print(Speed,DEC);
|
||||
Serial.print(" Steps: ");
|
||||
Serial.print(SpeedSteps,DEC);
|
||||
Serial.print(" Dir: ");
|
||||
Serial.println( (Dir == DCC_DIR_FWD) ? "Forward" : "Reverse" );
|
||||
#endif
|
||||
|
||||
newDirection = Dir;
|
||||
newSpeed = Speed;
|
||||
numSpeedSteps = SpeedSteps;
|
||||
};
|
||||
|
||||
// This call-back function is called whenever we receive a DCC Function packet for our address
|
||||
void notifyDccFunc(uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState)
|
||||
{
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.print("notifyDccFunc: Addr: ");
|
||||
Serial.print(Addr,DEC);
|
||||
Serial.print( (AddrType == DCC_ADDR_SHORT) ? 'S' : 'L' );
|
||||
Serial.print(" Function Group: ");
|
||||
Serial.print(FuncGrp,DEC);
|
||||
Serial.println();
|
||||
#endif
|
||||
|
||||
if(lastFuncStateList[FuncGrp] != FuncState)
|
||||
{
|
||||
lastFuncStateList[FuncGrp] = FuncState;
|
||||
switch(FuncGrp)
|
||||
{
|
||||
#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
|
||||
case FN_0:
|
||||
Serial.print(" FN0: ");
|
||||
Serial.println((FuncState & FN_BIT_00) ? "1 " : "0 ");
|
||||
|
||||
u8x8.setCursor(0, 2);
|
||||
u8x8.print("FN0 : ");
|
||||
u8x8.println((FuncState & FN_BIT_00) ? "1" : "0");
|
||||
break;
|
||||
#endif
|
||||
|
||||
case FN_0_4:
|
||||
u8x8.setCursor(0, 2);
|
||||
u8x8.print("FN0 : ");
|
||||
|
||||
if(Dcc.getCV(CV_29_CONFIG) & CV29_F0_LOCATION) // Only process Function 0 in this packet if we're not in Speed Step 14 Mode
|
||||
{
|
||||
Serial.print(" FN 0: ");
|
||||
Serial.print((FuncState & FN_BIT_00) ? "1 ": "0 ");
|
||||
|
||||
u8x8.print((FuncState & FN_BIT_00) ? "1": "0");
|
||||
}
|
||||
|
||||
Serial.print(" FN 1-4: ");
|
||||
Serial.print((FuncState & FN_BIT_01) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_02) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_03) ? "1 ": "0 ");
|
||||
Serial.println((FuncState & FN_BIT_04) ? "1 ": "0 ");
|
||||
|
||||
u8x8.print((FuncState & FN_BIT_01) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_02) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_03) ? "1": "0");
|
||||
u8x8.println((FuncState & FN_BIT_04) ? "1": "0");
|
||||
break;
|
||||
|
||||
case FN_5_8:
|
||||
Serial.print(" FN 5-8: ");
|
||||
Serial.print((FuncState & FN_BIT_05) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_06) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_07) ? "1 ": "0 ");
|
||||
Serial.println((FuncState & FN_BIT_08) ? "1 ": "0 ");
|
||||
|
||||
u8x8.setCursor(0, 3);
|
||||
u8x8.print("FN5 : ");
|
||||
u8x8.print((FuncState & FN_BIT_05) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_06) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_07) ? "1": "0");
|
||||
u8x8.println((FuncState & FN_BIT_08) ? "1": "0");
|
||||
break;
|
||||
|
||||
case FN_9_12:
|
||||
Serial.print(" FN 9-12: ");
|
||||
Serial.print((FuncState & FN_BIT_09) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_10) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_11) ? "1 ": "0 ");
|
||||
Serial.println((FuncState & FN_BIT_12) ? "1 ": "0 ");
|
||||
|
||||
u8x8.setCursor(0, 4);
|
||||
u8x8.print("FN9 : ");
|
||||
u8x8.print((FuncState & FN_BIT_09) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_10) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_11) ? "1": "0");
|
||||
u8x8.println((FuncState & FN_BIT_12) ? "1": "0");
|
||||
break;
|
||||
|
||||
case FN_13_20:
|
||||
Serial.print(" FN 13-20: ");
|
||||
Serial.print((FuncState & FN_BIT_13) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_14) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_15) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_16) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_17) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_18) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_19) ? "1 ": "0 ");
|
||||
Serial.println((FuncState & FN_BIT_20) ? "1 ": "0 ");
|
||||
|
||||
u8x8.setCursor(0, 5);
|
||||
u8x8.print("FN13: ");
|
||||
u8x8.print((FuncState & FN_BIT_13) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_14) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_15) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_16) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_17) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_18) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_19) ? "1": "0");
|
||||
u8x8.println((FuncState & FN_BIT_20) ? "1": "0");
|
||||
break;
|
||||
|
||||
case FN_21_28:
|
||||
Serial.print(" FN 21-28: ");
|
||||
Serial.print((FuncState & FN_BIT_21) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_22) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_23) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_24) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_25) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_26) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_27) ? "1 ": "0 ");
|
||||
Serial.println((FuncState & FN_BIT_28) ? "1 ": "0 ");
|
||||
|
||||
u8x8.setCursor(0, 6);
|
||||
u8x8.print("FN21: ");
|
||||
u8x8.print((FuncState & FN_BIT_21) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_22) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_23) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_24) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_25) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_26) ? "1": "0");
|
||||
u8x8.print((FuncState & FN_BIT_27) ? "1": "0");
|
||||
u8x8.println((FuncState & FN_BIT_28) ? "1": "0");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This call-back function is called whenever we receive a DCC Packet
|
||||
#ifdef DEBUG_DCC_MSG
|
||||
void notifyDccMsg( DCC_MSG * Msg)
|
||||
{
|
||||
Serial.print("notifyDccMsg: ") ;
|
||||
for(uint8_t i = 0; i < Msg->Size; i++)
|
||||
{
|
||||
Serial.print(Msg->Data[i], HEX);
|
||||
Serial.write(' ');
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
#endif
|
||||
|
||||
void setup()
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
Serial.begin(115200);
|
||||
uint8_t maxWaitLoops = 255;
|
||||
while(!Serial && maxWaitLoops--)
|
||||
delay(20);
|
||||
|
||||
Serial.println("NMRA Dcc Multifunction Motor Decoder Demo");
|
||||
#endif
|
||||
|
||||
u8x8.begin();
|
||||
u8x8.setFlipMode(1);
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
u8x8.setCursor(0, 0);
|
||||
u8x8.println("NMRA DCC");
|
||||
u8x8.println("MultiFunction");
|
||||
u8x8.println("Decoder Demo");
|
||||
delay(2000);
|
||||
u8x8.clearDisplay();
|
||||
u8x8.setCursor(0, 0);
|
||||
u8x8.println("Speed:");
|
||||
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
// Many Arduino Cores now support the digitalPinToInterrupt() function that makes it easier to figure out the
|
||||
// Interrupt Number for the Arduino Pin number, which reduces confusion.
|
||||
#ifdef digitalPinToInterrupt
|
||||
Dcc.pin(DCC_PIN, 0);
|
||||
#else
|
||||
Dcc.pin(0, DCC_PIN, 1);
|
||||
#endif
|
||||
|
||||
Dcc.init( MAN_ID_DIY, 10, FLAGS_MY_ADDRESS_ONLY | FLAGS_AUTO_FACTORY_DEFAULT, 0 );
|
||||
|
||||
// Uncomment to force CV Reset to Factory Defaults
|
||||
// notifyCVResetFactoryDefault();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
|
||||
// Handle Speed changes
|
||||
if((lastSpeed != newSpeed) || (lastDirection != newDirection))
|
||||
{
|
||||
lastSpeed = newSpeed;
|
||||
lastDirection = newDirection;
|
||||
|
||||
u8x8.setCursor(0, 0);
|
||||
u8x8.print("Speed: ");
|
||||
u8x8.print(newSpeed);
|
||||
u8x8.print(":");
|
||||
u8x8.println( newDirection ? "Fwd" : "Rev");
|
||||
}
|
||||
|
||||
// Handle resetting CVs back to Factory Defaults
|
||||
if( FactoryDefaultCVIndex )
|
||||
{
|
||||
FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array
|
||||
Dcc.setCV( FactoryDefaultCVs[FactoryDefaultCVIndex].CV, FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
|
||||
}
|
||||
}
|
@@ -32,6 +32,7 @@
|
||||
// This section defines the Arduino UNO Pins to use
|
||||
#ifdef __AVR_ATmega328P__
|
||||
|
||||
// Define the Arduino input Pin number for the DCC Signal
|
||||
#define DCC_PIN 2
|
||||
|
||||
#define LED_PIN_FWD 5
|
||||
@@ -42,6 +43,7 @@
|
||||
// This section defines the Arduino ATTiny85 Pins to use
|
||||
#elif ARDUINO_AVR_ATTINYX5
|
||||
|
||||
// Define the Arduino input Pin number for the DCC Signal
|
||||
#define DCC_PIN 2
|
||||
|
||||
#define LED_PIN_FWD 0
|
||||
@@ -89,8 +91,8 @@ CVPair FactoryDefaultCVs [] =
|
||||
{CV_VHIGH, 255},
|
||||
|
||||
// These two CVs define the Long DCC Address
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, DEFAULT_DECODER_ADDRESS},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB(DEFAULT_DECODER_ADDRESS)},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_LSB(DEFAULT_DECODER_ADDRESS)},
|
||||
|
||||
// ONLY uncomment 1 CV_29_CONFIG line below as approprate
|
||||
// {CV_29_CONFIG, 0}, // Short Address 14 Speed Steps
|
||||
@@ -205,6 +207,10 @@ void setup()
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
Serial.begin(115200);
|
||||
uint8_t maxWaitLoops = 255;
|
||||
while(!Serial && maxWaitLoops--)
|
||||
delay(20);
|
||||
|
||||
Serial.println("NMRA Dcc Multifunction Motor Decoder Demo");
|
||||
#endif
|
||||
|
||||
@@ -218,7 +224,13 @@ void setup()
|
||||
|
||||
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
// Many Arduino Cores now support the digitalPinToInterrupt() function that makes it easier to figure out the
|
||||
// Interrupt Number for the Arduino Pin number, which reduces confusion.
|
||||
#ifdef digitalPinToInterrupt
|
||||
Dcc.pin(DCC_PIN, 0);
|
||||
#else
|
||||
Dcc.pin(0, DCC_PIN, 1);
|
||||
#endif
|
||||
|
||||
Dcc.init( MAN_ID_DIY, 10, FLAGS_MY_ADDRESS_ONLY | FLAGS_AUTO_FACTORY_DEFAULT, 0 );
|
||||
|
||||
@@ -292,8 +304,8 @@ void loop()
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.println("LED On");
|
||||
#endif
|
||||
digitalWrite(LED_PIN_FWD, newDirection ? LOW : HIGH);
|
||||
digitalWrite(LED_PIN_REV, newDirection ? HIGH : LOW);
|
||||
digitalWrite(LED_PIN_FWD, newDirection ? HIGH : LOW);
|
||||
digitalWrite(LED_PIN_REV, newDirection ? LOW : HIGH);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -26,6 +26,9 @@
|
||||
// Un-Comment the line below to Enable DCC ACK for Service Mode Programming Read CV Capablilty
|
||||
#define ENABLE_DCC_ACK 15 // This is A1 on the Iowa Scaled Engineering ARD-DCCSHIELD DCC Shield
|
||||
|
||||
// Define the Arduino input Pin number for the DCC Signal
|
||||
#define DCC_PIN 2
|
||||
|
||||
NmraDcc Dcc ;
|
||||
|
||||
struct CVPair
|
||||
@@ -36,8 +39,8 @@ struct CVPair
|
||||
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, 1},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, DEFAULT_ACCESSORY_DECODER_ADDRESS & 0xFF},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, DEFAULT_ACCESSORY_DECODER_ADDRESS >> 8},
|
||||
};
|
||||
|
||||
uint8_t FactoryDefaultCVIndex = 0;
|
||||
@@ -98,11 +101,20 @@ void notifyCVChange(uint16_t CV, uint8_t Value)
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
uint8_t maxWaitLoops = 255;
|
||||
while(!Serial && maxWaitLoops--)
|
||||
delay(20);
|
||||
|
||||
Serial.println("NMRA DCC Iowa Scaled Engineering ARD-DCCSHIELD Example");
|
||||
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
Dcc.pin(0, 2, 1);
|
||||
// Many Arduino Cores now support the digitalPinToInterrupt() function that makes it easier to figure out the
|
||||
// Interrupt Number for the Arduino Pin number, which reduces confusion.
|
||||
#ifdef digitalPinToInterrupt
|
||||
Dcc.pin(DCC_PIN, 1);
|
||||
#else
|
||||
Dcc.pin(0, DCC_PIN, 1);
|
||||
#endif
|
||||
|
||||
// Call the main DCC Init function to enable the DCC Receiver
|
||||
Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER, 0 );
|
||||
|
@@ -106,8 +106,8 @@ CVPair FactoryDefaultCVs [] =
|
||||
{CV_MANUF, MANUF_ID }, // Manufacturer ID.
|
||||
|
||||
// These two CVs define the Long DCC Address
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, // Extended address MSB.
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, DECODER_ADDR}, // Extended address LSB.
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB(DECODER_ADDR)},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_LSB(DECODER_ADDR)},
|
||||
|
||||
{CV_29_CONFIG, CV29_F0_LOCATION}, // Short Address 28/128 Speed Steps
|
||||
{CV_MANUF_01, VER_MINOR}, // Minor decoder version.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
name=NmraDcc
|
||||
version=2.0.6
|
||||
author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Müller, Sven (littleyoda), Hans Tanner
|
||||
version=2.0.15
|
||||
author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Müller, Sven (littleyoda), Hans Tanner, bugfixes by Jueff
|
||||
maintainer=Alex Shepherd <kiwi64ajs@gmail.com>
|
||||
sentence=Enables NMRA DCC Communication
|
||||
paragraph=This library allows you to interface to a NMRA DCC track signal and receive DCC commands. The library has been tested on AVR ATTiny84/85 & ATMega88/168/328/32u4, ESP8266 and Teensy 3.x using the INT0/1 Hardware Interrupt and micros() ONLY and no longer uses Timer0 Compare Match B, which makes it much more portable to other platforms.
|
||||
|
20
support/pre-commit
Executable file
20
support/pre-commit
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
|
||||
FORMAT_SOURCES="NmraDcc.h NmraDcc.cpp"
|
||||
|
||||
error=0
|
||||
|
||||
for file in ${FORMAT_SOURCES}
|
||||
do
|
||||
output=$(mktemp -t stylecheckXXXXXXX)
|
||||
astyle --options=.astylerc < $file > $output
|
||||
if ! cmp -s $file $output
|
||||
then
|
||||
echo "Formatting on $file doesn't match expectations"
|
||||
diff -u $file $output
|
||||
error=1
|
||||
fi
|
||||
[ -f $output ] && rm $output
|
||||
done
|
||||
|
||||
exit $error
|
Reference in New Issue
Block a user