19 Commits

Author SHA1 Message Date
Alex Shepherd
4b52381fa4 added RP2040 Pico 16 Servo project 2022-02-28 00:35:59 +13:00
Alex Shepherd
5f1e271f2c added CV Storage EEPROM delayed commit
fixed debug for RP2040
2022-02-28 00:35:14 +13:00
Alex Shepherd
6f91d4f7d4 added wait for USB Device to enumerate to some examples
added CV_MANUFACTURER_START
2022-02-27 18:21:52 +13:00
Alex Shepherd
b35c1fbbd0 add .gitignore 2021-09-12 01:23:23 +12:00
Alex Shepherd
f59048383f Reworked the handling of Accessory OPS Mode CV writing to handle the difference of 11-bit Basic Extended Commands and 11-bit Signal Commands 2021-09-12 01:22:21 +12:00
Alex Shepherd
6333abf691 made some changes to the handling of Accessory Basic and Extended OPS Mode CV Programming 2021-09-05 00:28:15 +12:00
Alex Shepherd
afe488d792 bumbump version to 2.0.10 to force update of Arduino Library Manager Indexer 2021-08-30 22:48:44 +12:00
Alex Shepherd
61a730bf82 unified example folder/sketch name that was detected by the arduino-lint utility 2021-08-30 17:55:25 +12:00
Alex Shepherd
b0b27ce0cc bump version to 2.0.9 2021-08-30 14:14:38 +12:00
Alex Shepherd
c3dc28479a corrected Fwd/Rev LED logic in NmraDccMultiFunctionMotorDecoder example
added conditional compilation to use the newer Dcc.pin() method that used digitalPinToInterrupt() to determine the Ext Interrupt Number based on Arduino Pin to reduce confusion
2021-08-30 14:11:54 +12:00
Alex Shepherd
a05c12ce95 tidied up Ardunio Every and Raspberry Pi Pico attachInterrupt() function calls 2021-07-23 21:38:24 +12:00
Alex Shepherd
0a72fc610b reformatted the NmraDcc.h & NmraDcc.cpp files using the astyle rules in the new file: .astyle as per the PR from David Zuhn (davidzuhn) 2021-05-09 16:56:08 +12:00
Alex Shepherd
ad5ce96253 after making a mess of a PR from davidzuhn and not having the git skills to fix it, I've resorted to simply copying the desired files from his PR.
I've excluded his reformatted NmraDcc.h NmraDcc.cpp because there were too many merge conflicts now, so I'll reapply his formatting rules in another commit
2021-05-09 16:51:08 +12:00
Alex Shepherd
1e81b95044 removed incorrect comment about notifyDccAccTurnoutOutput() callback function 2021-05-02 23:06:59 +12:00
Alex Shepherd
84fdf45dce added support for the Arduino AVR Nano Every 2021-05-02 23:02:37 +12:00
Jueff
037070b899 Add support for Raspberry Pico (#56)
* fix ESP32 bug on interrupt reinitialisation

* - add first version of Raspberry Pico support

* - add first version of Raspberry Pico support

* Fix problem with missing type PinStatus
merge changes from master project

* fix encoding issue
2021-04-26 23:33:17 +12:00
Fred
eb15c25491 Update NmraDcc.h (#53)
Fix notifyDccAccTurnoutOutput() comments to show this is used when CV29_OUTPUT_ADDRESS_MODE IS set. Add emphasis to this and notifyDccAccTurnoutBoard() similar routine.
2021-04-26 23:32:58 +12:00
Alex Shepherd
681b362811 Added MACROs CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB and CALC_MULTIFUNCTION_EXTENDED_ADDRESS_LSB to correctly compute the DCC Address for CV storage
Corrected bug:  ESP32 version stops working when loosing interupts or signal is bad (#48)
bumped version to 2.0.7
2021-04-04 14:01:35 +12:00
Geoff Bunza
f5d7e9b8c3 Gbidec (#44)
* Create IDEC

* Delete IDEC

* Add files via upload

* Add files via upload
2020-11-20 12:10:19 +13:00
17 changed files with 3146 additions and 2491 deletions

55
.astylerc Normal file
View 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

3
.gitignore vendored
View File

@@ -1,2 +1,5 @@
.development
*.zip
*.orig
*~
*.txt

File diff suppressed because it is too large Load Diff

152
NmraDcc.h
View File

@@ -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
@@ -81,6 +81,10 @@ typedef struct
#define MAN_ID_DIY 0x0D
#define MAN_ID_SILICON_RAILWAY 0x21
#if defined(ESP8266) || defined(ESP32) || defined(ARDUINO_ARCH_RP2040)
#define EEPROM_COMMIT_DELAY_MS 3000
#endif
//--------------------------------------------------------------------------
// This section contains the Product/Version Id Codes for projects
//
@@ -94,6 +98,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,9 +110,14 @@ 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>
@@ -118,11 +131,15 @@ typedef struct
#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
#else
#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 */
@@ -133,20 +150,23 @@ typedef enum {
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;
@@ -158,9 +178,9 @@ typedef enum
FN_9_12,
FN_13_20,
FN_21_28,
#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
FN_0 /** function light is controlled by base line package (14 speed steps) */
#endif
#endif
} FN_GROUP;
#define FN_BIT_00 0x10
@@ -197,33 +217,40 @@ typedef enum
#define FN_BIT_27 0x40
#define FN_BIT_28 0x80
//#define DCC_DBGVAR
// #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
#define FLAGS_MY_ADDRESS_ONLY 0x01 // Only process DCC Packets with My Address
#define FLAGS_AUTO_FACTORY_DEFAULT 0x02 // Call notifyCVResetFactoryDefault() if CV 7 & 8 == 255
#define FLAGS_SETCV_CALLED 0x10 // only used internally !!
#define FLAGS_OUTPUT_ADDRESS_MODE 0x40 // CV 29/541 bit 6
#define FLAGS_DCC_ACCESSORY_DECODER 0x80 // CV 29/541 bit 7
#define FLAGS_EXTENDED_ADDRESS_MODE 0x20 // CV 29/541 bit 5 0 = 9-bit Board or Decoder Addressing mode, 1 = 11-bit Extended Address using middle 2 DD of the CDDD bits for the extra 2 bits
#define FLAGS_OUTPUT_ADDRESS_MODE 0x40 // CV 29/541 bit 6 0 = Board or Extended Addressing Mode, 1 = Signal Decoder Output Addressing Mode
#define FLAGS_DCC_ACCESSORY_DECODER 0x80 // CV 29/541 bit 7 0 = Multifunction Decoder, 1 = Accessory Decoder
#define FLAGS_MULTIFUNCTION_DECODER ()
#define FLAGS_BASIC_ACCESSORY_DECODER (FLAGS_DCC_ACCESSORY_DECODER)
#define FLAGS_EXTENDED_ACCESSORY_DECODER (FLAGS_DCC_ACCESSORY_DECODER | FLAGS_EXTENDED_ADDRESS_MODE)
#define FLAGS_SIGNAL_ACCESSORY_DECODER (FLAGS_DCC_ACCESSORY_DECODER | FLAGS_OUTPUT_ADDRESS_MODE)
// Flag Bits that are cloned from CV29 relating the DCC Accessory Decoder
#define FLAGS_CV29_BITS (FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER)
#define FLAGS_CV29_BITS (FLAGS_EXTENDED_ACCESSORY_DECODER | FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER)
/*+
@@ -237,7 +264,7 @@ class NmraDcc
* Returns:
* None.
*/
void pin( uint8_t ExtIntNum, uint8_t ExtIntPinNum, uint8_t EnablePullup);
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.
@@ -250,9 +277,9 @@ class NmraDcc
* Returns:
* None.
*/
#ifdef digitalPinToInterrupt
void pin( uint8_t ExtIntPinNum, uint8_t EnablePullup);
#endif
#ifdef digitalPinToInterrupt
void pin (uint8_t ExtIntPinNum, uint8_t EnablePullup);
#endif
/*+
* init() is called from setup() after the pin() command is called.
@@ -275,7 +302,7 @@ void pin( uint8_t ExtIntPinNum, uint8_t EnablePullup);
* Returns:
* None.
*/
void init( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV );
void init (uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV);
/*+
* initAccessoryDecoder() is called from setup() for accessory decoders.
@@ -292,7 +319,7 @@ void pin( uint8_t ExtIntPinNum, uint8_t EnablePullup);
* Returns:
* None.
*/
void initAccessoryDecoder( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV );
void initAccessoryDecoder (uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV);
/*+
* process() is called from loop() to process DCC packets.
@@ -318,7 +345,7 @@ void pin( uint8_t ExtIntPinNum, uint8_t EnablePullup);
* since nothing will have been set in that EEPROM position.
* Calls notifyCVRead() if it is defined.
*/
uint8_t getCV( uint16_t CV );
uint8_t getCV (uint16_t CV);
/*+
* setCV() sets the value of a CV.
@@ -333,7 +360,7 @@ void pin( uint8_t ExtIntPinNum, uint8_t EnablePullup);
* 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);
uint8_t setCV (uint16_t CV, uint8_t Value);
/*+
* setAccDecDCCAddrNextReceived() enables/disables the setting of the board address from the next received turnout command
@@ -343,7 +370,7 @@ void pin( uint8_t ExtIntPinNum, uint8_t EnablePullup);
*
* Returns:
*/
void setAccDecDCCAddrNextReceived(uint8_t enable);
void setAccDecDCCAddrNextReceived (uint8_t enable);
/*+
* isSetCVReady() returns 1 if EEPROM is ready to write.
@@ -358,7 +385,7 @@ void pin( uint8_t ExtIntPinNum, uint8_t EnablePullup);
* Note: It returns the value returned by notifyIsSetCVReady() if it is defined.
* Calls notifyIsSetCVReady() if it is defined.
*/
uint8_t isSetCVReady( void );
uint8_t isSetCVReady (void);
/*+
* getAddr() return the currently active decoder address.
@@ -371,7 +398,7 @@ void pin( uint8_t ExtIntPinNum, uint8_t EnablePullup);
* Adr - The current decoder address based on decoder type(Multifunction, Accessory)
* and short or long address selection for Multifunction decoders.
*/
uint16_t getAddr(void);
uint16_t getAddr (void);
/*+
* getX() return debugging data if DCC_DEBUG is defined.
@@ -393,13 +420,13 @@ void pin( uint8_t ExtIntPinNum, uint8_t EnablePullup);
* 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 +435,7 @@ void pin( uint8_t ExtIntPinNum, uint8_t EnablePullup);
************************************************************************************/
#if defined (__cplusplus)
extern "C" {
extern "C" {
#endif
/*+
@@ -421,7 +448,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 +459,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 +480,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 +494,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 +516,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 +538,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 +556,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 +572,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 +588,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 +601,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 +616,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 +634,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 +650,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 +667,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 +687,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 +705,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 +723,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 +736,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 +747,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 +757,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)
}

View File

@@ -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'

View File

@@ -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
@@ -244,7 +247,13 @@ 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 );

View File

@@ -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,8 @@ void notifyDccSigOutputState( uint16_t Addr, uint8_t State)
void setup()
{
Serial.begin(115200);
elapsedMillis millisWaitedForUSB = 0;
while(!Serial && (millisWaitedForUSB < 3000)); // Wait up to 3 seconds for USB to Connect
// Configure the DCC CV Programing ACK pin for an output
pinMode( DccAckPin, OUTPUT );
@@ -99,7 +104,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 );

View File

@@ -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},
@@ -119,7 +122,13 @@ void setup()
Serial.begin(115200);
// 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 );

View File

@@ -0,0 +1,377 @@
// This Example shows how to use the library as a DCC Accessory Decoder to drive 16 Servos to control Turnouts
#include <NmraDcc.h>
#include <Servo.h>
#include <SlowMotionServo.h>
#include <elapsedMillis.h>
#include <EEPROM.h>
// You can print every DCC packet by un-commenting the line below
//#define NOTIFY_DCC_MSG
// You can print every notifyDccAccTurnoutOutput call-back by un-commenting the line below
#define NOTIFY_TURNOUT_MSG
// You can also print other Debug Messages uncommenting the line below
#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
//#define FORCE_RESET_FACTORY_DEFAULT_CV
// Un-Comment the line below to Enable DCC ACK for Service Mode Programming Read CV Capablilty
#define ENABLE_DCC_ACK 27 // 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 26
#define NUM_SERVOS 16 // Set Number of Servos
#define DCC_DECODER_VERSION_NUM 12 // Set the Decoder Version - Used by JMRI to Identify the decoder
#define EEPROM_COMMIT_DELAY_MS 3000
struct CVPair
{
uint16_t CV;
uint8_t Value;
};
#define CV_VALUE_SERVO_DETACH_MILLIS 0 // CV Default Value for the delay in ms x 10ms to Detach the servo signal to stop chattering
#define CV_ADDRESS_SERVO_DETACH_MILLIS CV_MANUFACTURER_START
#define CV_VALUE_SERVO_MOVE_SPEED 40 // CV Default Value for the Serov movement speed x 10
#define CV_ADDRESS_SERVO_MOVE_SPEED (CV_MANUFACTURER_START + 1)
#define CV_ADDRESS_SERVO_INDIVIDUAL_VALUES (CV_MANUFACTURER_START + 2)
#define CV_ADDRESS_LAST_POS_LSB (CV_MANUFACTURER_START + (NUM_SERVOS * 2 ) + 3)
#define CV_ADDRESS_LAST_POS_MSB (CV_MANUFACTURER_START + (NUM_SERVOS * 2 ) + 4)
#define CV_VALUE_SERVO_MIN_POS 40 // CV Default Value for the Minimum Servo Position as a % of Full Scale
#define CV_ADDRESS_SERVO_MIN_POS(x) (CV_ADDRESS_SERVO_INDIVIDUAL_VALUES + (2 * x) + 1)
#define CV_VALUE_SERVO_MAX_POS 60 // CV Default Value for the Maximum Servo Position as a % of Full Scale
#define CV_ADDRESS_SERVO_MAX_POS(x) (CV_ADDRESS_SERVO_INDIVIDUAL_VALUES + (2 * x) + 2)
// To set the Turnout Addresses for this board you need to change the CV values for CV1 (CV_ACCESSORY_DECODER_ADDRESS_LSB) and
// CV9 (CV_ACCESSORY_DECODER_ADDRESS_MSB) in the FactoryDefaultCVs structure below. The Turnout Addresses are defined as:
// Base Turnout Address is: ((((CV9 * 64) + CV1) - 1) * 4) + 1
// With NUM_TURNOUTS 8 (above) a CV1 = 1 and CV9 = 0, the Turnout Addresses will be 1..8, for CV1 = 2 the Turnout Address is 5..12
CVPair FactoryDefaultCVs [] =
{
{CV_ACCESSORY_DECODER_ADDRESS_LSB, DEFAULT_ACCESSORY_DECODER_ADDRESS & 0xFF},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, DEFAULT_ACCESSORY_DECODER_ADDRESS >> 8},
{CV_ADDRESS_SERVO_DETACH_MILLIS, CV_VALUE_SERVO_DETACH_MILLIS}, // 0 = don't Detach else the Detach will occur after the CV Value x 10ms
{CV_ADDRESS_SERVO_MOVE_SPEED, CV_VALUE_SERVO_MOVE_SPEED}, // 0 = don't Detach else the Detach will occur after the CV Value x 10ms
{CV_ADDRESS_SERVO_MIN_POS(0), CV_VALUE_SERVO_MIN_POS}, // Servo 0
{CV_ADDRESS_SERVO_MAX_POS(0), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(1), CV_VALUE_SERVO_MIN_POS}, // Servo 1
{CV_ADDRESS_SERVO_MAX_POS(1), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(2), CV_VALUE_SERVO_MIN_POS}, // Servo 2
{CV_ADDRESS_SERVO_MAX_POS(2), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(3), CV_VALUE_SERVO_MIN_POS}, // Servo 3
{CV_ADDRESS_SERVO_MAX_POS(3), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(4), CV_VALUE_SERVO_MIN_POS}, // Servo 4
{CV_ADDRESS_SERVO_MAX_POS(4), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(5), CV_VALUE_SERVO_MIN_POS}, // Servo 5
{CV_ADDRESS_SERVO_MAX_POS(5), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(6), CV_VALUE_SERVO_MIN_POS}, // Servo 6
{CV_ADDRESS_SERVO_MAX_POS(6), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(7), CV_VALUE_SERVO_MIN_POS}, // Servo 7
{CV_ADDRESS_SERVO_MAX_POS(7), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(8), CV_VALUE_SERVO_MIN_POS}, // Servo 8
{CV_ADDRESS_SERVO_MAX_POS(8), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(9), CV_VALUE_SERVO_MIN_POS}, // Servo 9
{CV_ADDRESS_SERVO_MAX_POS(9), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(10), CV_VALUE_SERVO_MIN_POS}, // Servo 10
{CV_ADDRESS_SERVO_MAX_POS(10), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(11), CV_VALUE_SERVO_MIN_POS}, // Servo 11
{CV_ADDRESS_SERVO_MAX_POS(11), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(12), CV_VALUE_SERVO_MIN_POS}, // Servo 12
{CV_ADDRESS_SERVO_MAX_POS(12), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(13), CV_VALUE_SERVO_MIN_POS}, // Servo 13
{CV_ADDRESS_SERVO_MAX_POS(13), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(14), CV_VALUE_SERVO_MIN_POS}, // Servo 14
{CV_ADDRESS_SERVO_MAX_POS(14), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(15), CV_VALUE_SERVO_MIN_POS}, // Servo 15
{CV_ADDRESS_SERVO_MAX_POS(15), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_LAST_POS_LSB, 0},
{CV_ADDRESS_LAST_POS_MSB, 0},
};
uint8_t FactoryDefaultCVIndex = 0;
NmraDcc Dcc ;
DCC_MSG Packet ;
uint16_t BaseTurnoutAddress;
uint16_t lastPositionBits;
SMSSmooth Servos[NUM_SERVOS];
// This function is called whenever a normal DCC Turnout Packet is received
void notifyDccAccTurnoutOutput (uint16_t OutputAddress, uint8_t Direction, uint8_t OutputPower)
{
#ifdef NOTIFY_TURNOUT_MSG
Serial.print("notifyDccAccTurnoutOutput: Output Addr: ") ;
Serial.print(OutputAddress,DEC) ;
Serial.print(" Direction: ");
Serial.print(Direction ? "Closed" : "Thrown") ;
Serial.print(" Output: ");
Serial.print(OutputPower ? "On" : "Off") ;
#endif
if(( OutputAddress >= BaseTurnoutAddress ) && ( OutputAddress < (BaseTurnoutAddress + NUM_SERVOS )) && OutputPower ) // Only Drive the Servo on Activation
{
uint16_t servoIndex = OutputAddress - BaseTurnoutAddress;
#ifdef NOTIFY_TURNOUT_MSG
Serial.print(" Servo Num: ");
Serial.println(servoIndex,DEC);
#endif
setServoPos(servoIndex, Direction != 0);
}
else
{
#ifdef NOTIFY_TURNOUT_MSG
Serial.println();
#endif
}
}
void notifyDccAccTurnoutBoard (uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower)
{
uint16_t Addr = ((BoardAddr - 1) * 4) + OutputPair + 1;
#ifdef NOTIFY_TURNOUT_MSG
Serial.print("notifyDccAccTurnoutBoard: Board Addr: ") ;
Serial.print(BoardAddr,DEC) ;
Serial.print(" Output Pair: ");
Serial.print(OutputPair,DEC) ;
Serial.print(" Turnout Addr: ");
Serial.print(Addr,DEC) ;
Serial.print(" Base Turnout Addr: ");
Serial.print(BaseTurnoutAddress,DEC) ;
Serial.print(" Direction: ");
Serial.print(Direction ? "Closed" : "Thrown") ;
Serial.print(" Output: ");
Serial.print(OutputPower ? "On" : "Off") ;
#endif
if(( Addr >= BaseTurnoutAddress ) && ( Addr < (BaseTurnoutAddress + NUM_SERVOS )) && OutputPower ) // Only Drive the Servo on Activation
{
uint16_t servoIndex = Addr - BaseTurnoutAddress;
#ifdef NOTIFY_TURNOUT_MSG
Serial.print(" Servo Num: ");
Serial.println(servoIndex,DEC);
#endif
setServoPos(servoIndex, Direction != 0);
}
else
{
#ifdef NOTIFY_TURNOUT_MSG
Serial.println();
#endif
}
}
void setServoPos(uint8_t index, bool position)
{
if(index < NUM_SERVOS)
{
Servos[index].goTo( position ? 1.0 : 0.0);
setLastTurnoutPosition(index, position);
}
}
bool getLastTurnoutPosition(uint8_t index)
{
if(index < NUM_SERVOS)
{
uint16_t bitMask = 1 << index;
return lastPositionBits & bitMask ? true : false;
}
return 0;
}
void setLastTurnoutPosition(uint8_t index, bool position)
{
if(index < NUM_SERVOS)
{
uint16_t bitMask = 1 << index;
if(position)
lastPositionBits |= bitMask;
else
lastPositionBits &= ~bitMask;
Dcc.setCV(CV_ADDRESS_LAST_POS_LSB, lastPositionBits & 0x00ff);
Dcc.setCV(CV_ADDRESS_LAST_POS_MSB, (lastPositionBits >> 8) & 0x00ff);
}
}
void initServos()
{
BaseTurnoutAddress = (((Dcc.getCV(CV_ACCESSORY_DECODER_ADDRESS_MSB) * 64) + Dcc.getCV(CV_ACCESSORY_DECODER_ADDRESS_LSB) - 1) * 4) + 1 ;
uint16_t servoDetachMillis = Dcc.getCV(CV_ADDRESS_SERVO_DETACH_MILLIS) * 10;
SlowMotionServo::setDelayUntilStop(servoDetachMillis); // This is a static class member so only needs to be set once and is used globally
#ifdef DEBUG_MSG
Serial.print("initServos: DCC Turnout Base Address: "); Serial.print(BaseTurnoutAddress, DEC);
Serial.print(" Detach Servo Signal MilliSeconds: "); Serial.print(servoDetachMillis);
#endif
float servoMoveSpeed = Dcc.getCV(CV_ADDRESS_SERVO_MOVE_SPEED) / 10.0;
lastPositionBits = Dcc.getCV(CV_ADDRESS_LAST_POS_LSB) | (Dcc.getCV(CV_ADDRESS_LAST_POS_MSB) << 8);
for(uint8_t i = 0; i < NUM_SERVOS; i++)
{
Servos[i].setPin(i);
Servos[i].setupMin( map(Dcc.getCV(CV_ADDRESS_SERVO_MIN_POS(i)), 0, 100, 544, 2400));
Servos[i].setupMax( map(Dcc.getCV(CV_ADDRESS_SERVO_MAX_POS(i)), 0, 100, 544, 2400));
Servos[i].setSpeed(servoMoveSpeed);
Servos[i].setDetach(servoDetachMillis != 0);
Servos[i].setInitialPosition(getLastTurnoutPosition(i) ? 1.0 : 0.0);
}
SlowMotionServo::update();
#ifdef DEBUG_MSG
Serial.println("\ninitServos: Done");
#endif
}
void setup()
{
Serial.begin(115200);
elapsedMillis millisWaitedForUSB = 0;
while(!Serial && (millisWaitedForUSB < 3000)); // Wait up to 3 seconds for USB to Connect
#ifdef DEBUG_MSG
Serial.print("\nNMRA DCC 16-Servo Accessory Decoder. Ver: "); Serial.println(DCC_DECODER_VERSION_NUM,DEC);
#endif
// 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, 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, DCC_DECODER_VERSION_NUM, FLAGS_DCC_ACCESSORY_DECODER|FLAGS_EXTENDED_ADDRESS_MODE, 0);
#ifdef FORCE_RESET_FACTORY_DEFAULT_CV
Serial.println("Resetting CVs to Factory Defaults");
notifyCVResetFactoryDefault();
#endif
if( FactoryDefaultCVIndex == 0) // Not forcing a reset CV Reset to Factory Defaults so initPinPulser
initServos();
}
void loop()
{
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
Dcc.process();
if( FactoryDefaultCVIndex && Dcc.isSetCVReady())
{
FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array
uint16_t cv = FactoryDefaultCVs[FactoryDefaultCVIndex].CV;
uint8_t val = FactoryDefaultCVs[FactoryDefaultCVIndex].Value;
#ifdef DEBUG_MSG
Serial.print("loop: Write Default CV: "); Serial.print(cv,DEC); Serial.print(" Value: "); Serial.println(val,DEC);
#endif
Dcc.setCV( cv, val );
if( FactoryDefaultCVIndex == 0) // Is this the last Default CV to set? if so re-initPinPulser
initServos();
}
SlowMotionServo::update();
}
void notifyCVChange(uint16_t CV, uint8_t Value)
{
#ifdef DEBUG_MSG
Serial.print("notifyCVChange: CV: ") ;
Serial.print(CV,DEC) ;
Serial.print(" Value: ") ;
Serial.println(Value, DEC) ;
#endif
Value = Value; // Silence Compiler Warnings...
if((CV == CV_ACCESSORY_DECODER_ADDRESS_MSB) || (CV == CV_ACCESSORY_DECODER_ADDRESS_LSB) ||
((CV >= CV_ADDRESS_SERVO_DETACH_MILLIS) && (CV < CV_ADDRESS_LAST_POS_LSB)) && (FactoryDefaultCVIndex == 0))
initServos(); // Some CV we care about changed so re-init the PinPulser with the new CV settings
}
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 function is called by the NmraDcc library when a DCC ACK needs to be sent
// Calling this function should cause an increased 60ma current drain on the power supply for 6ms to ACK a CV Read
#ifdef ENABLE_DCC_ACK
void notifyCVAck(void)
{
#ifdef DEBUG_MSG
Serial.println("notifyCVAck") ;
#endif
// Configure the DCC CV Programing ACK pin for an output
pinMode( ENABLE_DCC_ACK, OUTPUT );
// Generate the DCC ACK 60mA pulse
digitalWrite( ENABLE_DCC_ACK, HIGH );
delay( 10 ); // The DCC Spec says 6ms but 10 makes sure... ;)
digitalWrite( ENABLE_DCC_ACK, LOW );
}
#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

View File

@@ -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
@@ -170,7 +171,13 @@ void setup()
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);
// 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 );

View File

@@ -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
@@ -218,7 +220,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 +300,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
{

View File

@@ -1,5 +1,3 @@
#include <NmraDcc.h>
// This Example shows how to use the library with the Iowa Scaled Engineering ARD-DCCSHIELD
// You can find out more about this DCC Interface here: http://www.iascaled.com/store/ARD-DCCSHIELD
//
@@ -16,6 +14,9 @@
// JP6 - Boards without VIO - User Choice
// JP7 - Enable Programming ACK - 1-2 ON 3-4 ON
//
#include <NmraDcc.h>
#include <elapsedMillis.h>
// It is a very basic DCC Accessory Decoder that does nothing except allow CV Read/Write and
// you can also print every DCC packet by uncommenting the "#define NOTIFY_DCC_MSG" line below
#define NOTIFY_DCC_MSG
@@ -26,6 +27,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 +40,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 +102,19 @@ void notifyCVChange(uint16_t CV, uint8_t Value)
void setup()
{
Serial.begin(115200);
elapsedMillis millisWaitedForUSB = 0;
while(!Serial && (millisWaitedForUSB < 3000)); // Wait up to 3 seconds for USB to Connect
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, 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, 0 );

View File

@@ -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.

View File

@@ -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.11
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
View 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