diff --git a/NmraDcc.cpp b/NmraDcc.cpp old mode 100755 new mode 100644 index 42f8288..2de7675 --- a/NmraDcc.cpp +++ b/NmraDcc.cpp @@ -14,6 +14,10 @@ // author: Alex Shepherd // webpage: http://opendcc.org/ // history: 2011-06-26 Initial Version copied in from OpenDCC +// 2014 Added getAddr to NmraDcc Geoff Bunza +// 2015-11-06 Martin Pischky (martin@pischky.de): +// Experimental Version to support 14 speed steps +// and new signature of notifyDccSpeed and notifyDccFunc // //------------------------------------------------------------------------ // @@ -260,13 +264,13 @@ uint16_t getMyAddr(void) CV29Value = readCV( CV_29_CONFIG ) ; - if( CV29Value & 0b10000000 ) // Accessory Decoder? + if( CV29Value & CV29_ACCESSORY_DECODER ) // Accessory Decoder? Addr = ( readCV( CV_ACCESSORY_DECODER_ADDRESS_MSB ) << 6 ) | readCV( CV_ACCESSORY_DECODER_ADDRESS_LSB ) ; else // Multi-Function Decoder? { - if( CV29Value & 0b00100000 ) // Two Byte Address? - Addr = ( readCV( CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB ) << 8 ) | readCV( CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB ) ; + if( CV29Value & CV29_EXT_ADDRESSING ) // Two Byte Address? + Addr = ( ( readCV( CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB ) - 192 ) << 8 ) | readCV( CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB ) ; else Addr = readCV( 1 ) ; @@ -345,10 +349,12 @@ void processDirectOpsOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value ) } #ifdef NMRA_DCC_PROCESS_MULTIFUNCTION -void processMultiFunctionMessage( uint16_t Addr, uint8_t Cmd, uint8_t Data1, uint8_t Data2 ) +void processMultiFunctionMessage( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Cmd, uint8_t Data1, uint8_t Data2 ) { uint8_t speed ; uint16_t CVAddr ; + DCC_DIRECTION dir ; + DCC_SPEED_STEPS speedSteps ; uint8_t CmdMasked = Cmd & 0b11100000 ; @@ -407,61 +413,90 @@ void processMultiFunctionMessage( uint16_t Addr, uint8_t Cmd, uint8_t Data1, uin { switch( Data1 & 0b01111111 ) { - case 0b00000000: - speed = 1 ; + case 0b00000000: // 0=STOP + speed = 1 ; // => 1 break ; - case 0b00000001: - speed = 0 ; + case 0b00000001: // 1=EMERGENCY_STOP + speed = 0 ; // => 0 break ; - default: - speed = (Data1 & 0b01111111) - 1 ; + default: // 2..127 + speed = (Data1 & 0b01111111) ; } - - notifyDccSpeed( Addr, speed, Data1 & 0b10000000, 127 ) ; + dir = (DCC_DIRECTION) ((Data1 & 0b10000000) >> 7) ; + notifyDccSpeed( Addr, AddrType, speed, dir, SPEED_STEP_128 ) ; } } break; case 0b01000000: case 0b01100000: + //TODO should we cache this info in DCC_PROCESSOR_STATE.Flags ? +#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE + speedSteps = (readCV( CV_29_CONFIG ) & CV29_F0_LOCATION) ? SPEED_STEP_28 : SPEED_STEP_14 ; +#else + speedSteps = SPEED_STEP_28 ; +#endif if( notifyDccSpeed ) { switch( Cmd & 0b00011111 ) { - case 0b00000000: - case 0b00010000: - speed = 1 ; + case 0b00000000: // 0 0000 = STOP + case 0b00010000: // 1 0000 = STOP + speed = 1 ; // => 1 break ; - case 0b00000001: - case 0b00010001: - speed = 0 ; + case 0b00000001: // 0 0001 = EMERGENCY STOP + case 0b00010001: // 1 0001 = EMERGENCY STOP + speed = 0 ; // => 0 break ; default: - // This speed is not quite right as 14 bit mode can happen and we should check CV29 but... - speed = (((Cmd & 0b00001111) << 1 ) | ((Cmd & 0b00010000) >> 4)) - 2 ; +#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE + if( speedSteps == SPEED_STEP_14 ) + { + speed = (Cmd & 0b00001111) ; // => 2..15 + } + else + { +#endif + speed = (((Cmd & 0b00001111) << 1 ) | ((Cmd & 0b00010000) >> 4)) - 2 ; // => 2..29 +#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE + } +#endif } - - notifyDccSpeed( Addr, speed, Cmd & 0b00100000, 28 ) ; + dir = (DCC_DIRECTION) ((Cmd & 0b00100000) >> 5) ; + notifyDccSpeed( Addr, AddrType, speed, dir, speedSteps ) ; } + if( notifyDccSpeedRaw ) + notifyDccSpeedRaw(Addr, AddrType, Cmd ); +#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE + if( notifyDccFunc && (speedSteps == SPEED_STEP_14) ) + { + // function light is controlled by this package + uint8_t fn0 = (Cmd & 0b00010000) ; + notifyDccFunc( Addr, AddrType, FN_0, fn0 ) ; + } break; +#endif case 0b10000000: // Function Group 0..4 if( notifyDccFunc ) - notifyDccFunc( Addr, FN_0_4, Cmd & 0b00011111 ) ; + { + // function light is controlled by this package (28 or 128 speed steps) + notifyDccFunc( Addr, AddrType, FN_0_4, Cmd & 0b00011111 ) ; + } break; case 0b10100000: // Function Group 5..8 if( notifyDccFunc) { if (Cmd & 0b00010000 ) - notifyDccFunc( Addr, FN_5_8, Cmd & 0b00001111 ) ; + notifyDccFunc( Addr, AddrType, FN_5_8, Cmd & 0b00001111 ) ; else - notifyDccFunc( Addr, FN_9_12, Cmd & 0b00001111 ) ; + notifyDccFunc( Addr, AddrType, FN_9_12, Cmd & 0b00001111 ) ; } break; @@ -470,12 +505,12 @@ void processMultiFunctionMessage( uint16_t Addr, uint8_t Cmd, uint8_t Data1, uin { case 0B00011110: if( notifyDccFunc ) - notifyDccFunc( Addr, FN_13_20, Data1 ) ; + notifyDccFunc( Addr, AddrType, FN_13_20, Data1 ) ; break; case 0B00011111: if( notifyDccFunc ) - notifyDccFunc( Addr, FN_21_28, Data1 ) ; + notifyDccFunc( Addr, AddrType, FN_21_28, Data1 ) ; break; } break; @@ -620,7 +655,7 @@ void execDccProcessor( DCC_MSG * pDccMsg ) #ifdef NMRA_DCC_PROCESS_MULTIFUNCTION // Multi Function Decoders (7-bit address) else if( pDccMsg->Data[0] < 128 ) - processMultiFunctionMessage( pDccMsg->Data[0], pDccMsg->Data[1], pDccMsg->Data[2], pDccMsg->Data[3] ) ; + processMultiFunctionMessage( pDccMsg->Data[0], DCC_ADDR_SHORT, pDccMsg->Data[1], pDccMsg->Data[2], pDccMsg->Data[3] ) ; // Basic Accessory Decoders (9-bit) & Extended Accessory Decoders (11-bit) else if( pDccMsg->Data[0] < 192 ) @@ -666,8 +701,9 @@ void execDccProcessor( DCC_MSG * pDccMsg ) else if( pDccMsg->Data[0] < 232 ) { uint16_t Address ; - Address = ( pDccMsg->Data[0] << 8 ) | pDccMsg->Data[1]; - processMultiFunctionMessage( Address, pDccMsg->Data[2], pDccMsg->Data[3], pDccMsg->Data[4] ) ; + Address = ( ( pDccMsg->Data[0] - 192 ) << 8 ) | pDccMsg->Data[1]; + //TODO should we convert Address to 1 .. 10239 ? + processMultiFunctionMessage( Address, DCC_ADDR_LONG, pDccMsg->Data[2], pDccMsg->Data[3], pDccMsg->Data[4] ) ; } #endif #ifdef NMRA_DCC_PROCESS_SERVICEMODE @@ -676,10 +712,6 @@ void execDccProcessor( DCC_MSG * pDccMsg ) } } -void initDccProcessor( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV ) -{ -} - NmraDcc::NmraDcc() { } @@ -710,7 +742,7 @@ void NmraDcc::init( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, ui DccProcState.Flags = Flags ; DccProcState.OpsModeAddressBaseCV = OpsModeAddressBaseCV ; - uint8_t cv29Mask = Flags & 0b11000000 ; // peal off the top two bits + uint8_t cv29Mask = Flags & (CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE) ; // peal off the top two bits writeCV( 7, VersionId ) ; writeCV( 8, ManufacturerId ) ; @@ -732,6 +764,11 @@ uint8_t NmraDcc::setCV( uint16_t CV, uint8_t Value) return writeCV(CV,Value); } +uint16_t NmraDcc::getAddr(void) +{ + return getMyAddr(); +} + uint8_t NmraDcc::isSetCVReady(void) { if(notifyIsSetCVReady) diff --git a/NmraDcc.h b/NmraDcc.h old mode 100755 new mode 100644 index 1cc80f7..28a9c77 --- a/NmraDcc.h +++ b/NmraDcc.h @@ -14,6 +14,10 @@ // author: Alex Shepherd // webpage: http://opendcc.org/ // history: 2008-03-20 Initial Version +// 2014 Added getAddr to NmraDcc Geoff Bunza +// 2015-11-06 Martin Pischky (martin@pischky.de): +// Experimental Version to support 14 speed steps +// and new signature of notifyDccSpeed and notifyDccFunc // //------------------------------------------------------------------------ // @@ -28,6 +32,9 @@ // Uncomment the following line to Enable MutliFunction Decoder Operations #define NMRA_DCC_PROCESS_MULTIFUNCTION +// Uncomment the following line to Enable 14 Speed Step Support +//#define NMRA_DCC_ENABLE_14_SPEED_STEP_MODE + #if defined(ARDUINO) && ARDUINO >= 100 #include "Arduino.h" #else @@ -83,13 +90,45 @@ typedef struct #define CV_29_CONFIG 29 #define MAXCV E2END // the upper limit of the CV value currently defined to max memory. +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_ADV_ACK = 0b00001000, /** bit 3: ACK, Advanced Acknowledge mode enabled if 1, disabled if 0 */ + CV29_SPEED_TABLE_ENABLE = 0b00010000, /** bit 4: STE, Speed Table Enable, "0" = values in CVs 2, 4 and 6, "1" = Custom table selected by CV 25 */ + CV29_EXT_ADDRESSING = 0b00100000, /** bit 5: "0" = one byte addressing, "1" = two byte addressing */ + CV29_OUTPUT_ADDRESS_MODE = 0b01000000, /** bit 6: "0" = Decoder Address Mode "1" = Output Address Mode */ + 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 + SPEED_STEP_14 = 15, /**< ESTOP=0, 1 to 15 */ +#endif + SPEED_STEP_28 = 29, /**< ESTOP=0, 1 to 29 */ + SPEED_STEP_128 = 127 /**< ESTOP=0, 1 to 127 */ +} DCC_SPEED_STEPS; + +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 { + 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 + 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_GROUP; #define FN_BIT_00 0x10 @@ -139,11 +178,12 @@ class NmraDcc #define FLAGS_OUTPUT_ADDRESS_MODE 0x40 // CV 29/541 bit 6 #define FLAGS_DCC_ACCESSORY_DECODER 0x80 // CV 29/541 bit 7 void pin( uint8_t ExtIntNum, uint8_t ExtIntPinNum, uint8_t EnablePullup); - void init( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV ); - uint8_t process(); - uint8_t getCV( uint16_t CV ); - uint8_t setCV( uint16_t CV, uint8_t Value); + void init( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV ); + uint8_t process(); + uint8_t getCV( uint16_t CV ); + uint8_t setCV( uint16_t CV, uint8_t Value); uint8_t isSetCVReady( void ); + uint16_t getAddr(void); // #define DCC_DEBUG #ifdef DCC_DEBUG @@ -166,8 +206,10 @@ class NmraDcc extern void notifyDccReset(uint8_t hardReset ) __attribute__ ((weak)); extern void notifyDccIdle(void) __attribute__ ((weak)); -extern void notifyDccSpeed( uint16_t Addr, uint8_t Speed, uint8_t ForwardDir, uint8_t MaxSpeed ) __attribute__ ((weak)); -extern void notifyDccFunc( uint16_t Addr, FN_GROUP FuncGrp, uint8_t FuncState) __attribute__ ((weak)); +extern void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps ) __attribute__ ((weak)); +extern void notifyDccSpeedRaw( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Raw) __attribute__ ((weak)); + +extern void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) __attribute__ ((weak)); extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State ) __attribute__ ((weak)); diff --git a/examples/NmraDccExample_1/NmraDccExample_1.ino b/examples/NmraDccExample_1/NmraDccExample_1.ino old mode 100755 new mode 100644 index 3963f9a..56cecf3 --- a/examples/NmraDccExample_1/NmraDccExample_1.ino +++ b/examples/NmraDccExample_1/NmraDccExample_1.ino @@ -12,7 +12,7 @@ struct CVPair uint16_t CV; uint8_t Value; }; - + CVPair FactoryDefaultCVs [] = { {CV_ACCESSORY_DECODER_ADDRESS_LSB, 1}, @@ -93,7 +93,8 @@ void setup() Dcc.pin(0, 2, 1); // Call the main DCC Init function to enable the DCC Receiver - Dcc.init( MAN_ID_DIY, 10, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, 0 ); + Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 ); + Serial.println("Init Done"); } @@ -107,4 +108,4 @@ void loop() FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array Dcc.setCV( FactoryDefaultCVs[FactoryDefaultCVIndex].CV, FactoryDefaultCVs[FactoryDefaultCVIndex].Value); } -} +} diff --git a/examples/SMA/AccessoryDecoder_17LED_1Function/AccessoryDecoder_17LED_1Function.ino b/examples/SMA/AccessoryDecoder_17LED_1Function/AccessoryDecoder_17LED_1Function.ino new file mode 100755 index 0000000..cd223bf --- /dev/null +++ b/examples/SMA/AccessoryDecoder_17LED_1Function/AccessoryDecoder_17LED_1Function.ino @@ -0,0 +1,103 @@ +// Working 17 Function ACESSORY DCC Decoder No CV Programming DccAckPin not needed +// Version 3.0 Geoff Bunza 2014 +// This uses Accessory addresses defined from This_Decoder_Address + 16 +// +// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP +// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!! +//#define DECODER_LOADED + +#include + +int tim_delay = 500; +#define numleds 17 +byte ledpins [] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; +const int FunctionPin0 = 3; +const int FunctionPin1 = 4; +const int FunctionPin2 = 5; +const int FunctionPin3 = 6; +const int FunctionPin4 = 7; +const int FunctionPin5 = 8; +const int FunctionPin6 = 9; +const int FunctionPin7 = 10; +const int FunctionPin8 = 11; +const int FunctionPin9 = 12; +const int FunctionPin10 = 13; +const int FunctionPin11 = 14; //A0 +const int FunctionPin12 = 15; //A1 +const int FunctionPin13 = 16; //A2 +const int FunctionPin14 = 17; //A3 +const int FunctionPin15 = 18; //A4 +const int FunctionPin16 = 19; //A5 +NmraDcc Dcc ; +DCC_MSG Packet ; + +#define This_Decoder_Address 40 //ACCESSORY DECODER ADDRESS + //Start of SWITCHES RANGE +uint8_t CV_DECODER_MASTER_RESET = 120; +struct CVPair +{ + uint16_t CV; + uint8_t Value; +}; +CVPair FactoryDefaultCVs [] = +{ + {CV_ACCESSORY_DECODER_ADDRESS_LSB, This_Decoder_Address}, + {CV_ACCESSORY_DECODER_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, + {CV_DECODER_MASTER_RESET, 0}, +}; + +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); +}; + +void setup() +{ + //Serial.begin(115200); + // initialize the digital pins as an outputs + for (int i=0; i< numleds; i++) { + pinMode(ledpins[i], OUTPUT); + digitalWrite(ledpins[i], LOW); + } + for (int i=0; i< numleds; i++) { + digitalWrite(ledpins[i], HIGH); + delay (tim_delay/10); + } + delay( tim_delay); + for (int i=0; i< numleds; i++) { + digitalWrite(ledpins[i], LOW); + delay (tim_delay/10); + } + delay( tim_delay); + + #if defined(DECODER_LOADED) + if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET ) + #endif + { + for (int j=0; j < FactoryDefaultCVIndex; j++ ) + Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value); + digitalWrite(ledpins[14], 1); + delay (1000); + digitalWrite(ledpins[14], 0); + } + // Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up + Dcc.pin(0, 2, 0); + // Call the main DCC Init function to enable the DCC Receiver + Dcc.init( MAN_ID_DIY, 100, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, 0 ); +} +void loop() +{ + // You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation + Dcc.process(); +} +extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) { + uint8_t Bit_State = OutputAddr & 0x01; + if ( Addr >= This_Decoder_Address || Addr < This_Decoder_Address+17) //Controls This_Decoder_Address+16 + digitalWrite( ledpins[Addr-This_Decoder_Address], Bit_State ); +} + diff --git a/examples/SMA/AccessoryDecoder_17LED_4Function/AccessoryDecoder_17LED_4Function.ino b/examples/SMA/AccessoryDecoder_17LED_4Function/AccessoryDecoder_17LED_4Function.ino new file mode 100755 index 0000000..4a913e4 --- /dev/null +++ b/examples/SMA/AccessoryDecoder_17LED_4Function/AccessoryDecoder_17LED_4Function.ino @@ -0,0 +1,541 @@ +// Production 17 Function DCC Acessory Decoder Dual Address w/CV Access +// Version 4.0 Geoff Bunza 2014 +// Uses modified software servo Lib +// +// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP +// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!! +//#define DECODER_LOADED + +#include +#include + +SoftwareServo servo0; +SoftwareServo servo1; +SoftwareServo servo2; +SoftwareServo servo3; +SoftwareServo servo4; +SoftwareServo servo5; +SoftwareServo servo6; +SoftwareServo servo7; +SoftwareServo servo8; +SoftwareServo servo9; +SoftwareServo servo10; +SoftwareServo servo11; +SoftwareServo servo12; +SoftwareServo servo13; +SoftwareServo servo14; +SoftwareServo servo15; +SoftwareServo servo16; +#define servo_start_delay 50 +#define servo_init_delay 7 + +int tim_delay = 500; +int numfpins = 17; +byte fpins [] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; +const int FunctionPin0 = 3; +const int FunctionPin1 = 4; +const int FunctionPin2 = 5; +const int FunctionPin3 = 6; +const int FunctionPin4 = 7; +const int FunctionPin5 = 8; +const int FunctionPin6 = 9; +const int FunctionPin7 = 10; +const int FunctionPin8 = 11; +const int FunctionPin9 = 12; +const int FunctionPin10 = 13; +const int FunctionPin11 = 14; //A0 +const int FunctionPin12 = 15; //A1 +const int FunctionPin13 = 16; //A2 +const int FunctionPin14 = 17; //A3 +const int FunctionPin15 = 18; //A4 +const int FunctionPin16 = 19; //A5 +NmraDcc Dcc ; +DCC_MSG Packet ; + +int t; // temp +#define SET_CV_Address 24 // THIS ADDRESS IS FOR SETTING CV'S Like a Loco +#define Accessory_Address 40 // THIS ADDRESS IS THE START OF THE SWITCHES RANGE + // WHICH WILL EXTEND FOR 16 MORE SWITCH ADDRESSES +uint8_t CV_DECODER_MASTER_RESET = 120; // THIS IS THE CV ADDRESS OF THE FULL RESET +#define CV_To_Store_SET_CV_Address 121 +#define CV_Accessory_Address CV_ACCESSORY_DECODER_ADDRESS_LSB + +struct QUEUE +{ + int inuse; + int current_position; + int increment; + int stop_value; + int start_value; +}; +QUEUE *ftn_queue = new QUEUE[16]; + +struct CVPair +{ + uint16_t CV; + uint8_t Value; +}; +CVPair FactoryDefaultCVs [] = +{ + {CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address}, + {CV_ACCESSORY_DECODER_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, + {CV_DECODER_MASTER_RESET, 0}, + {CV_To_Store_SET_CV_Address, SET_CV_Address}, + {CV_To_Store_SET_CV_Address+1, 0}, + {30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate + {32, 28}, //F0 Start Position F0=0 + {33, 140}, //F0 End Position F0=1 + {34, 28}, //F0 Current Position + {35, 0}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {37, 28}, // Start Position Fx=0 + {38, 140}, // End Position Fx=1 + {39, 28}, // Current Position + {40, 0}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {42, 28}, // Start Position Fx=0 + {43, 140}, // End Position Fx=1 + {44, 28}, // Current Position + {45, 0}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {47, 28}, // Start Position Fx=0 + {48, 140}, // End Position Fx=1 + {49, 28}, // Current Position + {50, 0}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {52, 28}, // Start Position Fx=0 + {53, 140}, // End Position Fx=1 + {54, 28}, // Current Position + {55, 0}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {56, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {57, 28}, // Start Position Fx=0 + {58, 140}, // End Position Fx=1 + {59, 28}, // Current Position + {60, 0}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {62, 28}, // Start Position Fx=0 + {63, 140}, // End Position Fx=1 + {64, 28}, // Current Position + {65, 0}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {67, 1}, // Start Position Fx=0 + {68,35}, // End Position Fx=1 + {69, 1}, // Current Position + {70, 0}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {72, 1}, // Start Position Fx=0 + {73, 100}, // End Position Fx=1 + {74, 1}, // Current Position + {75, 0}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {77, 1}, // Start Position Fx=0 + {78, 10}, // End Position Fx=1 + {79, 1}, // Current Position + {80, 0}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {81, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {82, 1}, // Start Position Fx=0 + {83, 5}, // End Position Fx=1 + {84, 1}, // Current Position + {85, 0}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {86, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {87, 1}, // Start Position Fx=0 + {88, 5}, // End Position Fx=1 + {89, 1}, // Current Position + {90, 0}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {92, 1}, // Start Position Fx=0 + {93, 20}, // End Position Fx=1 + {94, 1}, // Current Position + {95, 0}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {97, 1}, // Start Position Fx=0 + {98, 35}, // End Position Fx=1 + {99, 2}, // Current Position + {100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {102, 1}, // Start Position Fx=0 + {103, 4}, // End Position Fx=1 + {104, 1}, // Current Position + {105, 0}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {107, 1}, // Start Position Fx=0 + {108, 60}, // End Position Fx=1 + {109, 20}, // Current Position + {110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {112, 1}, // Start Position Fx=0 + {113, 4}, // End Position Fx=1 + {114, 1}, // Current Position +//FUTURE USE + {115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {116, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {117, 28}, // Start Position Fx=0 + {118, 50}, // End Position Fx=1 + {119, 28}, // Current Position +}; +uint8_t FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair); + +void setup() //****************************************************** +{ + int i; + uint8_t cv_value; + Serial.begin(115200); + // initialize the digital pins as outputs + for (int i=0; i < numfpins; i++) { + pinMode(fpins[i], OUTPUT); + digitalWrite(fpins[i], 0); + } + for (int i=0; i < numfpins; i++) { + digitalWrite(fpins[i], 1); + delay (tim_delay/10); + } + delay( tim_delay); + for (int i=0; i < numfpins; i++) { + digitalWrite(fpins[i], 0); + delay (tim_delay/10); + } + delay( tim_delay); + + // Setup which External Interrupt, the Pin it's associated with that we're using + Dcc.pin(0, 2, 0); + // Call the main DCC Init function to enable the DCC Receiver + Dcc.init( MAN_ID_DIY, 100, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address); + delay(800); + + #if defined(DECODER_LOADED) + if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET ) + #endif + + { + for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ ) + Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value); + digitalWrite(fpins[14], 1); + delay (1000); + digitalWrite(fpins[14], 0); + } + for ( i=0; i < numfpins; i++) { + cv_value = Dcc.getCV( 30+(i*5)) ; + //Serial.print(" cv_value: "); + //Serial.println(cv_value, DEC) ; + switch ( cv_value ) { + case 0: // LED on/off + ftn_queue[i].inuse = 0; + break; + case 1: // LED Blink + { + ftn_queue[i].inuse = 0; + ftn_queue[i].current_position = 0; + ftn_queue[i].start_value = 0; + ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5)))); + digitalWrite(fpins[i], 0); + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) ; + } + break; + case 2: //servo + { ftn_queue[i].current_position =int (Dcc.getCV( 34+(i*5))); + ftn_queue[i].stop_value = int (Dcc.getCV( 33+(i*5))); + ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5))); + ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5)))); + switch ( i ) { + case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object + ftn_queue[i].inuse = 1; + servo0.write(ftn_queue[i].start_value); + for (t=0; t ftn_queue[i].stop_value) { + ftn_queue[i].start_value = ~ftn_queue[i].start_value; + digitalWrite(fpins[i], ftn_queue[i].start_value); + ftn_queue[i].current_position = 0; + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); + } + break; + case 2: + { + if (ftn_queue[i].increment > 0) { + if (ftn_queue[i].current_position > ftn_queue[i].stop_value) + ftn_queue[i].current_position = ftn_queue[i].stop_value; + } + if (ftn_queue[i].increment < 0) { + if (ftn_queue[i].current_position < ftn_queue[i].start_value) + ftn_queue[i].current_position = ftn_queue[i].start_value; + } + set_servo(i, ftn_queue[i].current_position); + } + break; + case 3: + if (ftn_queue[i].current_position > ftn_queue[i].stop_value) { + ftn_queue[i].start_value = ~ftn_queue[i].start_value; + digitalWrite(fpins[i], ftn_queue[i].start_value); + digitalWrite(fpins[i]+1, ~ftn_queue[i].start_value); + ftn_queue[i].current_position = 0; + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); + } + i++; + break; + case 4: //FUTURE FUNCTION + break; + default: + break; + } + } + } +} + +extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) { + uint16_t Current_Decoder_Addr; + uint8_t Bit_State; + Current_Decoder_Addr = Dcc.getAddr(); + Bit_State = OutputAddr & 0x01; + + if ( Addr >= Current_Decoder_Addr || Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16 + switch (Addr-Current_Decoder_Addr) { + case 0: exec_function( 0, FunctionPin0, Bit_State ); + break; + case 1: exec_function( 1, FunctionPin1, Bit_State ); + break; + case 2: exec_function( 2, FunctionPin2, Bit_State ); + break; + case 3: exec_function( 3, FunctionPin3, Bit_State ); + break; + case 4: exec_function( 4, FunctionPin4, Bit_State ); + break; + case 5: exec_function( 5, FunctionPin5, Bit_State ); + break; + case 6: exec_function( 6, FunctionPin6, Bit_State ); + break; + case 7: exec_function( 7, FunctionPin7, Bit_State ); + break; + case 8: exec_function( 8, FunctionPin8, Bit_State ); + break; + case 9: exec_function( 9, FunctionPin9, Bit_State ); + break; + case 10: exec_function( 10, FunctionPin10, Bit_State ); + break; + case 11: exec_function( 11, FunctionPin11, Bit_State ); + break; + case 12: exec_function( 12, FunctionPin12, Bit_State ); + break; + case 13: exec_function( 13, FunctionPin13, Bit_State ); + break; + case 14: exec_function( 14, FunctionPin14, Bit_State ); + break; + case 15: exec_function( 15, FunctionPin15, Bit_State ); + break; + case 16: exec_function( 16, FunctionPin16, Bit_State ); + break; + default: + break; + } + } +} +void exec_function (int function, int pin, int FuncState) { + switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + case 0: // On - Off LED + digitalWrite (pin, FuncState); + ftn_queue[function].inuse = 0; + break; + case 1: // Blinking LED + if ((ftn_queue[function].inuse==0) && (FuncState==1)) { + ftn_queue[function].inuse = 1; + ftn_queue[function].start_value = 0; + digitalWrite(pin, 0); + ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))); + } else { + if ((ftn_queue[function].inuse==1) && (FuncState==0)) { + ftn_queue[function].inuse = 0; + digitalWrite(pin, 0); + } + } + break; + case 2: // Servo + ftn_queue[function].inuse = 1; + if (FuncState==1) ftn_queue[function].increment = char ( Dcc.getCV( 31+(function*5))); + else ftn_queue[function].increment = - char(Dcc.getCV( 31+(function*5))); + if (FuncState==1) ftn_queue[function].stop_value = Dcc.getCV( 33+(function*5)); + else ftn_queue[function].stop_value = Dcc.getCV( 32+(function*5)); + break; + case 3: // Blinking LED PAIR + if ((ftn_queue[function].inuse==0) && (FuncState==1)) { + ftn_queue[function].inuse = 1; + ftn_queue[function].start_value = 0; + digitalWrite(fpins[function], 0); + digitalWrite(fpins[function+1], 1); + ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))); + } else { + if (FuncState==0) { + ftn_queue[function].inuse = 0; + digitalWrite(fpins[function], 0); + digitalWrite(fpins[function+1], 0); + } + } + break; + case 4: // Future Function + ftn_queue[function].inuse = 0; + break; + default: + ftn_queue[function].inuse = 0; + break; + } +} +void set_servo (int servo_num, int servo_pos) { + switch (servo_num) { + case 0: servo0.write(servo_pos); + break; + case 1: servo1.write(servo_pos); + break; + case 2: servo2.write(servo_pos); + break; + case 3: servo3.write(servo_pos); + break; + case 4: servo4.write(servo_pos); + break; + case 5: servo5.write(servo_pos); + break; + case 6: servo6.write(servo_pos); + break; + case 7: servo7.write(servo_pos); + break; + case 8: servo8.write(servo_pos); + break; + case 9: servo9.write(servo_pos); + break; + case 10: servo10.write(servo_pos); + break; + case 11: servo11.write(servo_pos); + break; + case 12: servo12.write(servo_pos); + break; + case 13: servo13.write(servo_pos); + break; + case 14: servo14.write(servo_pos); + break; + case 15: servo15.write(servo_pos); + break; + case 16: servo16.write(servo_pos); + break; + default: + break; + } +} diff --git a/examples/SMA/AccessoryDecoder_17Pulsed_5Function/AccessoryDecoder_17Pulsed_5Function.ino b/examples/SMA/AccessoryDecoder_17Pulsed_5Function/AccessoryDecoder_17Pulsed_5Function.ino new file mode 100755 index 0000000..00e8af1 --- /dev/null +++ b/examples/SMA/AccessoryDecoder_17Pulsed_5Function/AccessoryDecoder_17Pulsed_5Function.ino @@ -0,0 +1,564 @@ +// Production 17 Function DCC Acessory Decoder Dual Address w/CV Access +// Version 4.0 Geoff Bunza 2014 +// Uses modified software servo Lib +// +// This configuration supports 5 Modes per pin: +// 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed +// It is recommended that you NOT MIX pulsed and servo control +// simultaneously as the servo timing will be off +// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP +// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!! +//#define DECODER_LOADED + +#include +#include + +SoftwareServo servo0; +SoftwareServo servo1; +SoftwareServo servo2; +SoftwareServo servo3; +SoftwareServo servo4; +SoftwareServo servo5; +SoftwareServo servo6; +SoftwareServo servo7; +SoftwareServo servo8; +SoftwareServo servo9; +SoftwareServo servo10; +SoftwareServo servo11; +SoftwareServo servo12; +SoftwareServo servo13; +SoftwareServo servo14; +SoftwareServo servo15; +SoftwareServo servo16; +#define servo_start_delay 50 +#define servo_init_delay 7 + +int tim_delay = 500; +int numfpins = 17; +byte fpins [] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; +const int FunctionPin0 = 3; +const int FunctionPin1 = 4; +const int FunctionPin2 = 5; +const int FunctionPin3 = 6; +const int FunctionPin4 = 7; +const int FunctionPin5 = 8; +const int FunctionPin6 = 9; +const int FunctionPin7 = 10; +const int FunctionPin8 = 11; +const int FunctionPin9 = 12; +const int FunctionPin10 = 13; +const int FunctionPin11 = 14; //A0 +const int FunctionPin12 = 15; //A1 +const int FunctionPin13 = 16; //A2 +const int FunctionPin14 = 17; //A3 +const int FunctionPin15 = 18; //A4 +const int FunctionPin16 = 19; //A5 +NmraDcc Dcc ; +DCC_MSG Packet ; + +int t; // temp +#define SET_CV_Address 24 // THIS ADDRESS IS FOR SETTING CV'S Like a Loco +#define Accessory_Address 40 // THIS ADDRESS IS THE START OF THE SWITCHES RANGE + // WHICH WILL EXTEND FOR 16 MORE SWITCH ADDRESSES +uint8_t CV_DECODER_MASTER_RESET = 120; // THIS IS THE CV ADDRESS OF THE FULL RESET +#define CV_To_Store_SET_CV_Address 121 +#define CV_Accessory_Address CV_ACCESSORY_DECODER_ADDRESS_LSB + +struct QUEUE +{ + int inuse; + int current_position; + int increment; + int stop_value; + int start_value; +}; +QUEUE *ftn_queue = new QUEUE[16]; + +struct CVPair +{ + uint16_t CV; + uint8_t Value; +}; +CVPair FactoryDefaultCVs [] = +{ + {CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address}, + {CV_ACCESSORY_DECODER_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, + {CV_DECODER_MASTER_RESET, 0}, + {CV_To_Store_SET_CV_Address, SET_CV_Address}, + {CV_To_Store_SET_CV_Address+1, 0}, + {30, 4}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {31, 10}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {32, 28}, //F0 Start Position F0=0 + {33, 140}, //F0 End Position F0=1 + {34, 0}, //F0 Current Position + {35, 4}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {36, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {37, 28}, // Start Position Fx=0 + {38, 140}, // End Position Fx=1 + {39, 0}, // Current Position + {40, 4}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {41, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {42, 28}, // Start Position Fx=0 + {43, 140}, // End Position Fx=1 + {44, 0}, // Current Position + {45, 4}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {46, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {47, 28}, // Start Position Fx=0 + {48, 140}, // End Position Fx=1 + {49, 0}, // Current Position + {50, 4}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {51, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {52, 28}, // Start Position Fx=0 + {53, 140}, // End Position Fx=1 + {54, 0}, // Current Position + {55, 4}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {56, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {57, 28}, // Start Position Fx=0 + {58, 140}, // End Position Fx=1 + {59, 0}, // Current Position + {60, 4}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {61, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {62, 28}, // Start Position Fx=0 + {63, 140}, // End Position Fx=1 + {64, 0}, // Current Position + {65, 4}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {66, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {67, 1}, // Start Position Fx=0 + {68,35}, // End Position Fx=1 + {69, 0}, // Current Position + {70, 4}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {71, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {72, 1}, // Start Position Fx=0 + {73, 100}, // End Position Fx=1 + {74, 0}, // Current Position + {75, 4}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {76, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {77, 1}, // Start Position Fx=0 + {78, 10}, // End Position Fx=1 + {79, 0}, // Current Position + {80, 4}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {81, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {82, 1}, // Start Position Fx=0 + {83, 5}, // End Position Fx=1 + {84, 0}, // Current Position + {85, 4}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {86, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {87, 1}, // Start Position Fx=0 + {88, 5}, // End Position Fx=1 + {89, 0}, // Current Position + {90, 4}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {91, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {92, 1}, // Start Position Fx=0 + {93, 20}, // End Position Fx=1 + {94, 0}, // Current Position + {95, 4}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {96, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {97, 1}, // Start Position Fx=0 + {98, 35}, // End Position Fx=1 + {99, 0}, // Current Position + {100, 4}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {101, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {102, 1}, // Start Position Fx=0 + {103, 4}, // End Position Fx=1 + {104, 0}, // Current Position + {105, 4}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {106, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {107, 1}, // Start Position Fx=0 + {108, 60}, // End Position Fx=1 + {109, 0}, // Current Position + {110, 4}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {111, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {112, 1}, // Start Position Fx=0 + {113, 4}, // End Position Fx=1 + {114, 0}, // Current Position +//FUTURE USE + {115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {116, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {117, 28}, // Start Position Fx=0 + {118, 50}, // End Position Fx=1 + {119, 28}, // Current Position +}; +uint8_t FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair); + +void setup() //****************************************************** +{ + int i; + uint8_t cv_value; + Serial.begin(115200); + // initialize the digital pins as outputs + for (int i=0; i < numfpins; i++) { + pinMode(fpins[i], OUTPUT); + digitalWrite(fpins[i], 0); + } + for (int i=0; i < numfpins; i++) { + digitalWrite(fpins[i], 1); + delay (tim_delay/10); + } + delay( tim_delay); + for (int i=0; i < numfpins; i++) { + digitalWrite(fpins[i], 0); + delay (tim_delay/10); + } + delay( tim_delay); + + // Setup which External Interrupt, the Pin it's associated with that we're using + Dcc.pin(0, 2, 0); + // Call the main DCC Init function to enable the DCC Receiver + Dcc.init( MAN_ID_DIY, 100, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address); + delay(800); + + #if defined(DECODER_LOADED) + if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET ) + #endif + + { + for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ ) + Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value); + digitalWrite(fpins[14], 1); + delay (1000); + digitalWrite(fpins[14], 0); + } + for ( i=0; i < numfpins; i++) { + cv_value = Dcc.getCV( 30+(i*5)) ; + //Serial.print(" cv_value: "); + //Serial.println(cv_value, DEC) ; + switch ( cv_value ) { + case 0: // LED on/off + ftn_queue[i].inuse = 0; + break; + case 1: // LED Blink + { + ftn_queue[i].inuse = 0; + ftn_queue[i].current_position = 0; + ftn_queue[i].start_value = 0; + ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5)))); + digitalWrite(fpins[i], 0); + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) ; + } + break; + case 2: //servo + { ftn_queue[i].current_position =int (Dcc.getCV( 34+(i*5))); + ftn_queue[i].stop_value = int (Dcc.getCV( 33+(i*5))); + ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5))); + ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5)))); + switch ( i ) { + case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object + ftn_queue[i].inuse = 1; + servo0.write(ftn_queue[i].start_value); + for (t=0; t ftn_queue[i].stop_value) { + ftn_queue[i].start_value = ~ftn_queue[i].start_value; + digitalWrite(fpins[i], ftn_queue[i].start_value); + ftn_queue[i].current_position = 0; + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); + } + break; + case 2: + { + if (ftn_queue[i].increment > 0) { + if (ftn_queue[i].current_position > ftn_queue[i].stop_value) + ftn_queue[i].current_position = ftn_queue[i].stop_value; + } + if (ftn_queue[i].increment < 0) { + if (ftn_queue[i].current_position < ftn_queue[i].start_value) + ftn_queue[i].current_position = ftn_queue[i].start_value; + } + set_servo(i, ftn_queue[i].current_position); + } + break; + case 3: + if (ftn_queue[i].current_position > ftn_queue[i].stop_value) { + ftn_queue[i].start_value = ~ftn_queue[i].start_value; + digitalWrite(fpins[i], ftn_queue[i].start_value); + digitalWrite(fpins[i]+1, ~ftn_queue[i].start_value); + ftn_queue[i].current_position = 0; + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); + } + i++; + break; + case 4: // Simple Pulsed Output based on saved Rate =10*Rate in Milliseconds + break; + case 5: //FUTURE FUNCTION + break; + default: + break; + } + } + } +} + +extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) { + uint16_t Current_Decoder_Addr; + uint8_t Bit_State; + Current_Decoder_Addr = Dcc.getAddr(); + Bit_State = OutputAddr & 0x01; + + if ( Addr >= Current_Decoder_Addr || Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16 + switch (Addr-Current_Decoder_Addr) { + case 0: exec_function( 0, FunctionPin0, Bit_State ); + break; + case 1: exec_function( 1, FunctionPin1, Bit_State ); + break; + case 2: exec_function( 2, FunctionPin2, Bit_State ); + break; + case 3: exec_function( 3, FunctionPin3, Bit_State ); + break; + case 4: exec_function( 4, FunctionPin4, Bit_State ); + break; + case 5: exec_function( 5, FunctionPin5, Bit_State ); + break; + case 6: exec_function( 6, FunctionPin6, Bit_State ); + break; + case 7: exec_function( 7, FunctionPin7, Bit_State ); + break; + case 8: exec_function( 8, FunctionPin8, Bit_State ); + break; + case 9: exec_function( 9, FunctionPin9, Bit_State ); + break; + case 10: exec_function( 10, FunctionPin10, Bit_State ); + break; + case 11: exec_function( 11, FunctionPin11, Bit_State ); + break; + case 12: exec_function( 12, FunctionPin12, Bit_State ); + break; + case 13: exec_function( 13, FunctionPin13, Bit_State ); + break; + case 14: exec_function( 14, FunctionPin14, Bit_State ); + break; + case 15: exec_function( 15, FunctionPin15, Bit_State ); + break; + case 16: exec_function( 16, FunctionPin16, Bit_State ); + break; + default: + break; + } + } +} +void exec_function (int function, int pin, int FuncState) { + switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + case 0: // On - Off LED + digitalWrite (pin, FuncState); + ftn_queue[function].inuse = 0; + break; + case 1: // Blinking LED + if ((ftn_queue[function].inuse==0) && (FuncState==1)) { + ftn_queue[function].inuse = 1; + ftn_queue[function].start_value = 0; + digitalWrite(pin, 0); + ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))); + } else { + if ((ftn_queue[function].inuse==1) && (FuncState==0)) { + ftn_queue[function].inuse = 0; + digitalWrite(pin, 0); + } + } + break; + case 2: // Servo + ftn_queue[function].inuse = 1; + if (FuncState==1) ftn_queue[function].increment = char ( Dcc.getCV( 31+(function*5))); + else ftn_queue[function].increment = - char(Dcc.getCV( 31+(function*5))); + if (FuncState==1) ftn_queue[function].stop_value = Dcc.getCV( 33+(function*5)); + else ftn_queue[function].stop_value = Dcc.getCV( 32+(function*5)); + break; + case 3: // Blinking LED PAIR + if ((ftn_queue[function].inuse==0) && (FuncState==1)) { + ftn_queue[function].inuse = 1; + ftn_queue[function].start_value = 0; + digitalWrite(fpins[function], 0); + digitalWrite(fpins[function+1], 1); + ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))); + } else { + if (FuncState==0) { + ftn_queue[function].inuse = 0; + digitalWrite(fpins[function], 0); + digitalWrite(fpins[function+1], 0); + } + } + break; + case 4: // Pulse Output based on Rate*10 Milliseconds + if ((ftn_queue[function].inuse==0) && (FuncState==1)) { //First Turn On Detected + digitalWrite(fpins[function], 1); + delay (10*ftn_queue[function].increment); + digitalWrite(fpins[function], 0); + ftn_queue[function].inuse = 1; //inuse set to 1 says we already pulsed + } else + if (FuncState==0) ftn_queue[function].inuse = 0; + break; + case 5: // Future Function + ftn_queue[function].inuse = 0; + break; + default: + ftn_queue[function].inuse = 0; + break; + } +} +void set_servo (int servo_num, int servo_pos) { + switch (servo_num) { + case 0: servo0.write(servo_pos); + break; + case 1: servo1.write(servo_pos); + break; + case 2: servo2.write(servo_pos); + break; + case 3: servo3.write(servo_pos); + break; + case 4: servo4.write(servo_pos); + break; + case 5: servo5.write(servo_pos); + break; + case 6: servo6.write(servo_pos); + break; + case 7: servo7.write(servo_pos); + break; + case 8: servo8.write(servo_pos); + break; + case 9: servo9.write(servo_pos); + break; + case 10: servo10.write(servo_pos); + break; + case 11: servo11.write(servo_pos); + break; + case 12: servo12.write(servo_pos); + break; + case 13: servo13.write(servo_pos); + break; + case 14: servo14.write(servo_pos); + break; + case 15: servo15.write(servo_pos); + break; + case 16: servo16.write(servo_pos); + break; + default: + break; + } +} diff --git a/examples/SMA/AccessoryDecoder_7ServoBackandForth/AccessoryDecoder_7ServoBackandForth.ino b/examples/SMA/AccessoryDecoder_7ServoBackandForth/AccessoryDecoder_7ServoBackandForth.ino new file mode 100755 index 0000000..3b20ce9 --- /dev/null +++ b/examples/SMA/AccessoryDecoder_7ServoBackandForth/AccessoryDecoder_7ServoBackandForth.ino @@ -0,0 +1,548 @@ +// Production 7 Servo Back and Forth DCC Acessory Decoder Dual Address w/CV Access +// Version 1.2 Geoff Bunza 2014 +// Uses modified software servo Lib +// This Decoder Version has been modified so that each Switch Closure Transition from Thrown to Closed +// Swings the Servo Quickly from Start to Stop and Back to Start +// This is ONLY done in the transition from Thrown to Closed Servo Speed can be slowed by changing the +// RATE CV towards 1 +// +// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP +// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!! +//#define DECODER_LOADED + +#include +#include + +SoftwareServo servo0; +SoftwareServo servo1; +SoftwareServo servo2; +SoftwareServo servo3; +SoftwareServo servo4; +SoftwareServo servo5; +SoftwareServo servo6; +SoftwareServo servo7; +SoftwareServo servo8; +SoftwareServo servo9; +SoftwareServo servo10; +SoftwareServo servo11; +SoftwareServo servo12; +SoftwareServo servo13; +SoftwareServo servo14; +SoftwareServo servo15; +SoftwareServo servo16; +#define servo_start_delay 50 +#define servo_init_delay 7 + +int tim_delay = 500; +int numfpins = 17; +byte fpins [] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; +const int FunctionPin0 = 3; +const int FunctionPin1 = 4; +const int FunctionPin2 = 5; +const int FunctionPin3 = 6; +const int FunctionPin4 = 7; +const int FunctionPin5 = 8; +const int FunctionPin6 = 9; +const int FunctionPin7 = 10; +const int FunctionPin8 = 11; +const int FunctionPin9 = 12; +const int FunctionPin10 = 13; +const int FunctionPin11 = 14; //A0 +const int FunctionPin12 = 15; //A1 +const int FunctionPin13 = 16; //A2 +const int FunctionPin14 = 17; //A3 +const int FunctionPin15 = 18; //A4 +const int FunctionPin16 = 19; //A5 +NmraDcc Dcc ; +DCC_MSG Packet ; + +int t; // temp +#define SET_CV_Address 24 // THIS ADDRESS IS FOR SETTING CV'S Like a Loco +#define Accessory_Address 40 // THIS ADDRESS IS THE START OF THE SWITCHES RANGE + // WHICH WILL EXTEND FOR 16 MORE SWITCH ADDRESSES +uint8_t CV_DECODER_MASTER_RESET = 120; // THIS IS THE CV ADDRESS OF THE FULL RESET +#define CV_To_Store_SET_CV_Address 121 +#define CV_Accessory_Address CV_ACCESSORY_DECODER_ADDRESS_LSB +int servo_temp; +struct QUEUE +{ + int inuse; + int current_position; + int increment; + int stop_value; + int start_value; +}; +QUEUE *ftn_queue = new QUEUE[16]; + +struct CVPair +{ + uint16_t CV; + uint8_t Value; +}; +CVPair FactoryDefaultCVs [] = +{ + {CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address}, + {CV_ACCESSORY_DECODER_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, + {CV_DECODER_MASTER_RESET, 0}, + {CV_To_Store_SET_CV_Address, SET_CV_Address}, + {CV_To_Store_SET_CV_Address+1, 0}, + {30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {31, 3}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate + {32, 28}, //F0 Start Position F0=0 + {33, 140}, //F0 End Position F0=1 + {34, 28}, //F0 Current Position + {35, 2}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {36, 3}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {37, 28}, // Start Position Fx=0 + {38, 140}, // End Position Fx=1 + {39, 28}, // Current Position + {40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {41, 3}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {42, 28}, // Start Position Fx=0 + {43, 140}, // End Position Fx=1 + {44, 28}, // Current Position + {45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {46, 3}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {47, 28}, // Start Position Fx=0 + {48, 140}, // End Position Fx=1 + {49, 28}, // Current Position + {50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {51, 3}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {52, 28}, // Start Position Fx=0 + {53, 140}, // End Position Fx=1 + {54, 28}, // Current Position + {55, 2}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {56, 3}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {57, 28}, // Start Position Fx=0 + {58, 140}, // End Position Fx=1 + {59, 28}, // Current Position + {60, 2}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {61, 3}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {62, 28}, // Start Position Fx=0 + {63, 140}, // End Position Fx=1 + {64, 28}, // Current Position + {65, 1}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {67, 1}, // Start Position Fx=0 + {68,35}, // End Position Fx=1 + {69, 1}, // Current Position + {70, 1}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {72, 1}, // Start Position Fx=0 + {73, 100}, // End Position Fx=1 + {74, 1}, // Current Position + {75, 0}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {77, 1}, // Start Position Fx=0 + {78, 10}, // End Position Fx=1 + {79, 1}, // Current Position + {80, 0}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {81, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {82, 1}, // Start Position Fx=0 + {83, 5}, // End Position Fx=1 + {84, 1}, // Current Position + {85, 1}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {86, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {87, 1}, // Start Position Fx=0 + {88, 5}, // End Position Fx=1 + {89, 1}, // Current Position + {90, 1}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {92, 1}, // Start Position Fx=0 + {93, 20}, // End Position Fx=1 + {94, 1}, // Current Position + {95, 1}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=PWM + {96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {97, 1}, // Start Position Fx=0 + {98, 20}, // End Position Fx=1 + {99, 1}, // Current Position + {100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=PWM + {101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {102, 1}, // Start Position Fx=0 + {103, 4}, // End Position Fx=1 + {104, 1}, // Current Position + {105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=PWM + {106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {107, 1}, // Start Position Fx=0 + {108, 60}, // End Position Fx=1 + {109, 20}, // Current Position + {110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=PWM + {111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {112, 1}, // Start Position Fx=0 + {113, 4}, // End Position Fx=1 + {114, 1}, // Current Position +//FUTURE USE + {115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=PWM + {116, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {117, 28}, // Start Position Fx=0 + {118, 50}, // End Position Fx=1 + {119, 28}, // Current Position +}; +uint8_t FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair); + +void setup() //****************************************************** +{ + int i; + uint8_t cv_value; + //Serial.begin(115200); + // initialize the digital pins as outputs + for (int i=0; i < numfpins; i++) { + pinMode(fpins[i], OUTPUT); + digitalWrite(fpins[i], 0); + } + for (int i=0; i < numfpins; i++) { + digitalWrite(fpins[i], 1); + delay (tim_delay/10); + } + delay( tim_delay); + for (int i=0; i < numfpins; i++) { + digitalWrite(fpins[i], 0); + delay (tim_delay/10); + } + delay( tim_delay); + + // Setup which External Interrupt, the Pin it's associated with that we're using + Dcc.pin(0, 2, 0); + // Call the main DCC Init function to enable the DCC Receiver + Dcc.init( MAN_ID_DIY, 100, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address); + delay(800); + + #if defined(DECODER_LOADED) + if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET ) + #endif + + { + for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ ) + Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value); + digitalWrite(fpins[14], 1); + delay (1000); + digitalWrite(fpins[14], 0); + } + for ( i=0; i < numfpins; i++) { + cv_value = Dcc.getCV( 30+(i*5)) ; + //Serial.print(" cv_value: "); + //Serial.println(cv_value, DEC) ; + switch ( cv_value ) { + case 0: // LED on/off + ftn_queue[i].inuse = 0; + break; + case 1: // LED Blink + { + ftn_queue[i].inuse = 0; + ftn_queue[i].current_position = 0; + ftn_queue[i].start_value = 0; + ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5)))); + digitalWrite(fpins[i], 0); + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) ; + } + break; + case 2: //servo + { ftn_queue[i].current_position =int (Dcc.getCV( 34+(i*5))); + ftn_queue[i].stop_value = int (Dcc.getCV( 33+(i*5))); + ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5))); + ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5)))); + switch ( i ) { + case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object + ftn_queue[i].inuse = 0; + servo0.write(ftn_queue[i].start_value); + for (t=0; t ftn_queue[i].stop_value) { + ftn_queue[i].start_value = ~ftn_queue[i].start_value; + digitalWrite(fpins[i], ftn_queue[i].start_value); + ftn_queue[i].current_position = 0; + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); + } + break; + case 2: // All Servo service timing is now local to the Turn on transition + + break; + case 3: + if (ftn_queue[i].current_position > ftn_queue[i].stop_value) { + ftn_queue[i].start_value = ~ftn_queue[i].start_value; + digitalWrite(fpins[i], ftn_queue[i].start_value); + digitalWrite(fpins[i]+1, ~ftn_queue[i].start_value); + ftn_queue[i].current_position = 0; + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); + } + i++; + break; + case 4: //FUTURE FUNCTION + break; + default: + break; + } + } + } +} + +extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) { + uint16_t Current_Decoder_Addr; + uint8_t Bit_State; + Current_Decoder_Addr = Dcc.getAddr(); + Bit_State = OutputAddr & 0x01; + + if ( Addr >= Current_Decoder_Addr || Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16 + switch (Addr-Current_Decoder_Addr) { + case 0: exec_function( 0, FunctionPin0, Bit_State ); + break; + case 1: exec_function( 1, FunctionPin1, Bit_State ); + break; + case 2: exec_function( 2, FunctionPin2, Bit_State ); + break; + case 3: exec_function( 3, FunctionPin3, Bit_State ); + break; + case 4: exec_function( 4, FunctionPin4, Bit_State ); + break; + case 5: exec_function( 5, FunctionPin5, Bit_State ); + break; + case 6: exec_function( 6, FunctionPin6, Bit_State ); + break; + case 7: exec_function( 7, FunctionPin7, Bit_State ); + break; + case 8: exec_function( 8, FunctionPin8, Bit_State ); + break; + case 9: exec_function( 9, FunctionPin9, Bit_State ); + break; + case 10: exec_function( 10, FunctionPin10, Bit_State ); + break; + case 11: exec_function( 11, FunctionPin11, Bit_State ); + break; + case 12: exec_function( 12, FunctionPin12, Bit_State ); + break; + case 13: exec_function( 13, FunctionPin13, Bit_State ); + break; + case 14: exec_function( 14, FunctionPin14, Bit_State ); + break; + case 15: exec_function( 15, FunctionPin15, Bit_State ); + break; + case 16: exec_function( 16, FunctionPin16, Bit_State ); + break; + default: + break; + } + } +} +void exec_function (int function, int pin, int FuncState) { + switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + case 0: // On - Off LED + digitalWrite (pin, FuncState); + ftn_queue[function].inuse = 0; + break; + case 1: // Blinking LED + if ((ftn_queue[function].inuse==0) && (FuncState==1)) { + ftn_queue[function].inuse = 1; + ftn_queue[function].start_value = 0; + digitalWrite(pin, 0); + ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))); + } else { + if ((ftn_queue[function].inuse==1) && (FuncState==0)) { + ftn_queue[function].inuse = 0; + digitalWrite(pin, 0); + } + } + break; + case 2: { // Servo + if ((ftn_queue[function].inuse == 0) && (FuncState==1)) { // We have an OFF->ON transition + ftn_queue[function].increment = char ( Dcc.getCV( 31+(function*5))); + ftn_queue[function].start_value = Dcc.getCV( 32+(function*5)); + ftn_queue[function].stop_value = Dcc.getCV( 33+(function*5)); + for (servo_temp=ftn_queue[function].start_value; servo_tempftn_queue[function].start_value; servo_temp=servo_temp-ftn_queue[function].increment) { + set_servo(function,servo_temp); + SoftwareServo::refresh(); + delay(4); + } + ftn_queue[function].inuse = 1; + } + if (FuncState==0) ftn_queue[function].inuse = 0; + break; + } + case 3: // Blinking LED PAIR + if ((ftn_queue[function].inuse==0) && (FuncState==1)) { + ftn_queue[function].inuse = 1; + ftn_queue[function].start_value = 0; + digitalWrite(fpins[function], 0); + digitalWrite(fpins[function+1], 1); + ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))); + } else { + if (FuncState==0) { + ftn_queue[function].inuse = 0; + digitalWrite(fpins[function], 0); + digitalWrite(fpins[function+1], 0); + } + } + break; + case 4: // Future Function + ftn_queue[function].inuse = 0; + break; + default: + ftn_queue[function].inuse = 0; + break; + } +} +void set_servo (int servo_num, int servo_pos) { + switch (servo_num) { + case 0: servo0.write(servo_pos); + break; + case 1: servo1.write(servo_pos); + break; + case 2: servo2.write(servo_pos); + break; + case 3: servo3.write(servo_pos); + break; + case 4: servo4.write(servo_pos); + break; + case 5: servo5.write(servo_pos); + break; + case 6: servo6.write(servo_pos); + break; + case 7: servo7.write(servo_pos); + break; + case 8: servo8.write(servo_pos); + break; + case 9: servo9.write(servo_pos); + break; + case 10: servo10.write(servo_pos); + break; + case 11: servo11.write(servo_pos); + break; + case 12: servo12.write(servo_pos); + break; + case 13: servo13.write(servo_pos); + break; + case 14: servo14.write(servo_pos); + break; + case 15: servo15.write(servo_pos); + break; + case 16: servo16.write(servo_pos); + break; + default: + break; + } +} diff --git a/examples/Decoder_10Serv_7LED_4Function/Decoder_10Serv_7LED_4Function.ino b/examples/SMA/Decoder_10Serv_7LED_4Function/Decoder_10Serv_7LED_4Function.ino similarity index 100% rename from examples/Decoder_10Serv_7LED_4Function/Decoder_10Serv_7LED_4Function.ino rename to examples/SMA/Decoder_10Serv_7LED_4Function/Decoder_10Serv_7LED_4Function.ino diff --git a/examples/Decoder_13Serv_4LED_4Function/Decoder_13Serv_4LED_4Function.ino b/examples/SMA/Decoder_13Serv_4LED_4Function/Decoder_13Serv_4LED_4Function.ino similarity index 100% rename from examples/Decoder_13Serv_4LED_4Function/Decoder_13Serv_4LED_4Function.ino rename to examples/SMA/Decoder_13Serv_4LED_4Function/Decoder_13Serv_4LED_4Function.ino diff --git a/examples/Decoder_15_Servos_1LED_4Function/Decoder_15_Servos_1LED_4Function.ino b/examples/SMA/Decoder_15_Servos_1LED_4Function/Decoder_15_Servos_1LED_4Function.ino similarity index 100% rename from examples/Decoder_15_Servos_1LED_4Function/Decoder_15_Servos_1LED_4Function.ino rename to examples/SMA/Decoder_15_Servos_1LED_4Function/Decoder_15_Servos_1LED_4Function.ino diff --git a/examples/Decoder_17LED_1Function/DecoderNmraDcc_4.ino b/examples/SMA/Decoder_17LED_1Function/DecoderNmraDcc_4.ino similarity index 100% rename from examples/Decoder_17LED_1Function/DecoderNmraDcc_4.ino rename to examples/SMA/Decoder_17LED_1Function/DecoderNmraDcc_4.ino diff --git a/examples/Decoder_17LED_4Function/Decoder_17LED_4Function.ino b/examples/SMA/Decoder_17LED_4Function/Decoder_17LED_4Function.ino similarity index 100% rename from examples/Decoder_17LED_4Function/Decoder_17LED_4Function.ino rename to examples/SMA/Decoder_17LED_4Function/Decoder_17LED_4Function.ino diff --git a/examples/SMA/Decoder_17LED_5FTN_Fade/Decoder_17LED_5FTN_Fade.ino b/examples/SMA/Decoder_17LED_5FTN_Fade/Decoder_17LED_5FTN_Fade.ino new file mode 100755 index 0000000..169e87c --- /dev/null +++ b/examples/SMA/Decoder_17LED_5FTN_Fade/Decoder_17LED_5FTN_Fade.ino @@ -0,0 +1,566 @@ + // Production 17 Function DCC Decoder +// Uses modified software servo Lib +// + +// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP +// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!! +//#define DECODER_LOADED + +#include +#include + +SoftwareServo servo0; +SoftwareServo servo1; +SoftwareServo servo2; +SoftwareServo servo3; +SoftwareServo servo4; +SoftwareServo servo5; +SoftwareServo servo6; +SoftwareServo servo7; +SoftwareServo servo8; +SoftwareServo servo9; +SoftwareServo servo10; +SoftwareServo servo11; +SoftwareServo servo12; +SoftwareServo servo13; +SoftwareServo servo14; +SoftwareServo servo15; +SoftwareServo servo16; +#define servo_start_delay 50 +#define servo_init_delay 7 + +int tim_delay = 500; +int numfpins = 17; +byte fpins [] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; +const int FunctionPin0 = 3; +const int FunctionPin1 = 4; +const int FunctionPin2 = 5; +const int FunctionPin3 = 6; +const int FunctionPin4 = 7; + +const int FunctionPin5 = 8; +const int FunctionPin6 = 9; +const int FunctionPin7 = 10; +const int FunctionPin8 = 11; + +const int FunctionPin9 = 12; +const int FunctionPin10 = 13; +const int FunctionPin11 = 14; //A0 +const int FunctionPin12 = 15; //A1 + +const int FunctionPin13 = 16; //A2 +const int FunctionPin14 = 17; //A3 & LOAD ACK +const int FunctionPin15 = 18; //A4 +const int FunctionPin16 = 19; //A5 +NmraDcc Dcc ; +DCC_MSG Packet ; +uint8_t CV_DECODER_MASTER_RESET = 120; +int t; // temp +#define This_Decoder_Address 24 +struct QUEUE +{ + int inuse; + int current_position; + int increment; + int stop_value; + int start_value; +}; +QUEUE *ftn_queue = new QUEUE[16]; + +extern uint8_t Decoder_Address = This_Decoder_Address; +struct CVPair +{ + uint16_t CV; + uint8_t Value; +}; +CVPair FactoryDefaultCVs [] = +{ + {CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address}, + {CV_ACCESSORY_DECODER_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, + {CV_DECODER_MASTER_RESET, 0}, + {30, 0}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate + {32, 28}, //F0 Start Position F0=0 + {33, 140}, //F0 End Position F0=1 + {34, 28}, //F0 Current Position + {35, 4}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {37, 0}, // Start Position Fx=0 + {38, 8}, // End Position Fx=1 + {39, 1}, // Current Position + {40, 0}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {42, 28}, // Start Position Fx=0 + {43, 140}, // End Position Fx=1 + {44, 28}, // Current Position + {45, 0}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {47, 28}, // Start Position Fx=0 + {48, 140}, // End Position Fx=1 + {49, 28}, // Current Position + {50, 0}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {52, 28}, // Start Position Fx=0 + {53, 140}, // End Position Fx=1 + {54, 28}, // Current Position + {55, 0}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {56, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {57, 28}, // Start Position Fx=0 + {58, 140}, // End Position Fx=1 + {59, 28}, // Current Position + {60, 0}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {62, 28}, // Start Position Fx=0 + {63, 140}, // End Position Fx=1 + {64, 28}, // Current Position + {65, 0}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {67, 28}, // Start Position Fx=0 + {68,140}, // End Position Fx=1 + {69, 28}, // Current Position + {70, 0}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {72, 28}, // Start Position Fx=0 + {73, 140}, // End Position Fx=1 + {74, 28}, // Current Position + {75, 0}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {77, 28}, // Start Position Fx=0 + {78, 140}, // End Position Fx=1 + {79, 28}, // Current Position + {80, 0}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {81, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {82, 1}, // Start Position Fx=0 + {83, 5}, // End Position Fx=1 + {84, 1}, // Current Position + {85, 1}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {86, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {87, 1}, // Start Position Fx=0 + {88, 5}, // End Position Fx=1 + {89, 1}, // Current Position + {90, 1}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {92, 1}, // Start Position Fx=0 + {93, 10}, // End Position Fx=1 + {94, 1}, // Current Position + {95, 3}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {97, 1}, // Start Position Fx=0 + {98, 6}, // End Position Fx=1 + {99, 1}, // Current Position + {100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {102, 1}, // Start Position Fx=0 + {103, 6}, // End Position Fx=1 + {104, 1}, // Current Position + {105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {107, 1}, // Start Position Fx=0 + {108, 10}, // End Position Fx=1 + {109, 1}, // Current Position + {110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {112, 1}, // Start Position Fx=0 + {113, 10}, // End Position Fx=1 + {114, 1}, // Current Position +//FUTURE USE + {115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {116, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {117, 28}, // Start Position Fx=0 + {118, 50}, // End Position Fx=1 + {119, 28}, // Current Position +}; + +uint8_t FactoryDefaultCVIndex = 95; +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); +}; + +void setup() //****************************************************** +{ + int i; + uint8_t cv_value; + Serial.begin(115200); + // initialize the digital pins as outputs + for (int i=0; i < numfpins; i++) { + pinMode(fpins[i], OUTPUT); + digitalWrite(fpins[i], 0); + } + for (int i=0; i < numfpins; i++) { + digitalWrite(fpins[i], 1); + delay (tim_delay/10); + } + delay( tim_delay); + for (int i=0; i < numfpins; i++) { + digitalWrite(fpins[i], 0); + delay (tim_delay/10); + } + delay( tim_delay); + + // Setup which External Interrupt, the Pin it's associated with that we're using + Dcc.pin(0, 2, 0); + // Call the main DCC Init function to enable the DCC Receiver + Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 ); + delay(800); + + #if defined(DECODER_LOADED) + if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET ) + #endif + + { + for (int j=0; j < FactoryDefaultCVIndex; j++ ) + Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value); + digitalWrite(fpins[14], 1); + delay (1000); + digitalWrite(fpins[14], 0); + } + for ( i=0; i < numfpins; i++) { + cv_value = Dcc.getCV( 30+(i*5)) ; + //Serial.print(" cv_value: "); + //Serial.println(cv_value, DEC) ; + switch ( cv_value ) { + case 0: // LED on/off + ftn_queue[i].inuse = 0; + break; + case 1: // LED Blink + { + ftn_queue[i].inuse = 0; + ftn_queue[i].start_value = 0; + ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5)))); + digitalWrite(fpins[i], 0); + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) *10.; + } + break; + case 2: //servo + { ftn_queue[i].current_position =int (Dcc.getCV( 34+(i*5))); + ftn_queue[i].stop_value = int (Dcc.getCV( 33+(i*5))); + ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5))); + ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5)))); + switch ( i ) { + case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object + ftn_queue[i].inuse = 1; + servo0.write(ftn_queue[i].start_value); + for (t=0; t ftn_queue[i].stop_value) { + ftn_queue[i].start_value = ~ftn_queue[i].start_value; + digitalWrite(fpins[i], ftn_queue[i].start_value); + ftn_queue[i].current_position = 0; + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) *10.; + } + break; + case 2: + { + if (ftn_queue[i].increment > 0) { + if (ftn_queue[i].current_position > ftn_queue[i].stop_value) + ftn_queue[i].current_position = ftn_queue[i].stop_value; + } + if (ftn_queue[i].increment < 0) { + if (ftn_queue[i].current_position < ftn_queue[i].start_value) + ftn_queue[i].current_position = ftn_queue[i].start_value; + } + set_servo(i, ftn_queue[i].current_position); + } + break; + case 3: + if (ftn_queue[i].current_position > ftn_queue[i].stop_value) { + ftn_queue[i].start_value = ~ftn_queue[i].start_value; + digitalWrite(fpins[i], ftn_queue[i].start_value); + digitalWrite(fpins[i]+1, ~ftn_queue[i].start_value); + ftn_queue[i].current_position = 0; + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) *10.; + } + i++; + break; + case 4: // Fade On + + break; + case 5: //FUTURE FUNCTION + break; + default: + break; + } + } + } +} + +extern void notifyDccFunc( uint16_t Addr, uint8_t FuncNum, uint8_t FuncState) { + if (FuncNum==1) { //Function Group 1 F0 F4 F3 F2 F1 + exec_function( 0, FunctionPin0, (FuncState&0x10)>>4 ); + exec_function( 1, FunctionPin1, (FuncState&0x01 )); + exec_function( 2, FunctionPin2, (FuncState&0x02)>>1 ); + exec_function( 3, FunctionPin3, (FuncState&0x04)>>2 ); + exec_function( 4, FunctionPin4, (FuncState&0x08)>>3 ); + } + else if (FuncNum==2) { //Function Group 1 S FFFF == 1 F8 F7 F6 F5 & == 0 F12 F11 F10 F9 F8 + if ((FuncState & 0x10)==0x10) { + exec_function( 5, FunctionPin5, (FuncState&0x01 )); + exec_function( 6, FunctionPin6, (FuncState&0x02)>>1 ); + exec_function( 7, FunctionPin7, (FuncState&0x04)>>2 ); + exec_function( 8, FunctionPin8, (FuncState&0x08)>>3 ); + } + else { + exec_function( 9, FunctionPin9, (FuncState&0x01 )); + exec_function( 10, FunctionPin10, (FuncState&0x02)>>1 ); + exec_function( 11, FunctionPin11, (FuncState&0x04)>>2 ); + exec_function( 12, FunctionPin12, (FuncState&0x08)>>3 ); + } + } + else if (FuncNum==3) { //Function Group 2 FuncState == F20-F13 Function Control + exec_function( 13, FunctionPin13, (FuncState&0x01 )); + exec_function( 14, FunctionPin14, (FuncState&0x02)>>1 ); + exec_function( 15, FunctionPin15, (FuncState&0x04)>>2 ); + exec_function( 16, FunctionPin16, (FuncState&0x08)>>3 ); + } +} +void exec_function (int function, int pin, int FuncState) { + switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + case 0: // On - Off LED + //Serial.println("****************cv:0 ") ; + digitalWrite (pin, FuncState); + ftn_queue[function].inuse = 0; + break; + case 1: // Blinking LED + if ((ftn_queue[function].inuse==0) && (FuncState==1)) { + ftn_queue[function].inuse = 1; + ftn_queue[function].start_value = 0; + digitalWrite(fpins[function], 0); + ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))) *10.; + } else { + if ((ftn_queue[function].inuse==1) && (FuncState==0)) { + ftn_queue[function].inuse = 0; + digitalWrite(fpins[function], 0); + } + } + break; + case 2: // Servo + ftn_queue[function].inuse = 1; + if (FuncState==1) ftn_queue[function].increment = char ( Dcc.getCV( 31+(function*5))); + else ftn_queue[function].increment = - char(Dcc.getCV( 31+(function*5))); + if (FuncState==1) ftn_queue[function].stop_value = Dcc.getCV( 33+(function*5)); + else ftn_queue[function].stop_value = Dcc.getCV( 32+(function*5)); + /* + Serial.print("servo inc: ") ; + Serial.print(ftn_queue[function].increment,DEC) ; + Serial.print("servo inuse: ") ; + Serial.print(ftn_queue[function].inuse,DEC) ; + Serial.print("servo num: ") ; + Serial.print(function,DEC) ; + Serial.print(" stop: "); + Serial.println(ftn_queue[function].stop_value,DEC) ; + */ + break; + case 3: // Blinking LED PAIR + if ((ftn_queue[function].inuse==0) && (FuncState==1)) { + ftn_queue[function].inuse = 1; + ftn_queue[function].start_value = 0; + digitalWrite(fpins[function], 0); + digitalWrite(fpins[function+1], 1); + ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))) *10.; + } else { + if (FuncState==0) { + ftn_queue[function].inuse = 0; + digitalWrite(fpins[function], 0); + digitalWrite(fpins[function+1], 0); + } + } + break; + case 4: // Fade On +#define fadedelay 24 + if ((ftn_queue[function].inuse==0) && (FuncState==1)) { + ftn_queue[function].inuse = 1; + for (t=0; t +#include + +SoftwareServo servo0; +SoftwareServo servo1; +SoftwareServo servo2; +SoftwareServo servo3; +SoftwareServo servo4; +SoftwareServo servo5; +SoftwareServo servo6; +SoftwareServo servo7; +SoftwareServo servo8; +SoftwareServo servo9; +SoftwareServo servo10; +SoftwareServo servo11; +SoftwareServo servo12; +SoftwareServo servo13; +SoftwareServo servo14; +SoftwareServo servo15; +SoftwareServo servo16; +#define servo_start_delay 50 +#define servo_init_delay 7 + +int tim_delay = 500; +int numfpins = 17; +byte fpins [] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; +const int FunctionPin0 = 3; +const int FunctionPin1 = 4; +const int FunctionPin2 = 5; +const int FunctionPin3 = 6; +const int FunctionPin4 = 7; + +const int FunctionPin5 = 8; +const int FunctionPin6 = 9; +const int FunctionPin7 = 10; +const int FunctionPin8 = 11; + +const int FunctionPin9 = 12; +const int FunctionPin10 = 13; +const int FunctionPin11 = 14; //A0 +const int FunctionPin12 = 15; //A1 + +const int FunctionPin13 = 16; //A2 +const int FunctionPin14 = 17; //A3 & LOAD ACK +const int FunctionPin15 = 18; //A4 +const int FunctionPin16 = 19; //A5 +NmraDcc Dcc ; +DCC_MSG Packet ; +uint8_t CV_DECODER_MASTER_RESET = 120; +int t; // temp +#define This_Decoder_Address 24 +struct QUEUE +{ + int inuse; + int current_position; + int increment; + int stop_value; + int start_value; +}; +QUEUE *ftn_queue = new QUEUE[16]; + +extern uint8_t Decoder_Address = This_Decoder_Address; +struct CVPair +{ + uint16_t CV; + uint8_t Value; +}; +CVPair FactoryDefaultCVs [] = +{ + {CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address}, + {CV_ACCESSORY_DECODER_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, + {CV_DECODER_MASTER_RESET, 0}, + {30, 4}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {31, 10}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {32, 28}, //F0 Start Position F0=0 + {33, 140}, //F0 End Position F0=1 + {34, 0}, //F0 Current Position + {35, 4}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {36, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {37, 28}, // Start Position Fx=0 + {38, 140}, // End Position Fx=1 + {39, 0}, // Current Position + {40, 4}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {41, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {42, 28}, // Start Position Fx=0 + {43, 140}, // End Position Fx=1 + {44, 0}, // Current Position + {45, 4}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {46, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {47, 28}, // Start Position Fx=0 + {48, 140}, // End Position Fx=1 + {49, 0}, // Current Position + {50, 4}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {51, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {52, 28}, // Start Position Fx=0 + {53, 140}, // End Position Fx=1 + {54, 0}, // Current Position + {55, 4}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {56, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {57, 28}, // Start Position Fx=0 + {58, 140}, // End Position Fx=1 + {59, 0}, // Current Position + {60, 4}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {61, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {62, 28}, // Start Position Fx=0 + {63, 140}, // End Position Fx=1 + {64, 0}, // Current Position + {65, 4}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {66, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {67, 1}, // Start Position Fx=0 + {68,35}, // End Position Fx=1 + {69, 0}, // Current Position + {70, 4}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {71, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {72, 1}, // Start Position Fx=0 + {73, 100}, // End Position Fx=1 + {74, 0}, // Current Position + {75, 4}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {76, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {77, 1}, // Start Position Fx=0 + {78, 10}, // End Position Fx=1 + {79, 0}, // Current Position + {80, 4}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {81, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {82, 1}, // Start Position Fx=0 + {83, 5}, // End Position Fx=1 + {84, 0}, // Current Position + {85, 4}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {86, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {87, 1}, // Start Position Fx=0 + {88, 5}, // End Position Fx=1 + {89, 0}, // Current Position + {90, 4}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {91, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {92, 1}, // Start Position Fx=0 + {93, 20}, // End Position Fx=1 + {94, 0}, // Current Position + {95, 4}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {96, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {97, 1}, // Start Position Fx=0 + {98, 35}, // End Position Fx=1 + {99, 0}, // Current Position + {100, 4}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {101, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {102, 1}, // Start Position Fx=0 + {103, 4}, // End Position Fx=1 + {104, 0}, // Current Position + {105, 4}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {106, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {107, 1}, // Start Position Fx=0 + {108, 60}, // End Position Fx=1 + {109, 0}, // Current Position + {110, 4}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {111, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {112, 1}, // Start Position Fx=0 + {113, 4}, // End Position Fx=1 + {114, 0}, // Current Position +//FUTURE USE + {115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed + {116, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10 + {117, 28}, // Start Position Fx=0 + {118, 50}, // End Position Fx=1 + {119, 28}, // Current Position +}; + +uint8_t FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair); +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); +}; + +void setup() //****************************************************** +{ + int i; + uint8_t cv_value; + //Serial.begin(115200); + // initialize the digital pins as outputs + for (int i=0; i < numfpins; i++) { + pinMode(fpins[i], OUTPUT); + digitalWrite(fpins[i], 0); + } + for (int i=0; i < numfpins; i++) { + digitalWrite(fpins[i], 1); + delay (tim_delay/10); + } + delay( tim_delay); + for (int i=0; i < numfpins; i++) { + digitalWrite(fpins[i], 0); + delay (tim_delay/10); + } + delay( tim_delay); + + // Setup which External Interrupt, the Pin it's associated with that we're using + Dcc.pin(0, 2, 0); + // Call the main DCC Init function to enable the DCC Receiver + Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 ); + delay(800); + + #if defined(DECODER_LOADED) + if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET ) + #endif + + { + for (int j=0; j < FactoryDefaultCVIndex; j++ ) + Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value); + digitalWrite(fpins[14], 1); + delay (1000); + digitalWrite(fpins[14], 0); + } + for ( i=0; i < numfpins; i++) { + cv_value = Dcc.getCV( 30+(i*5)) ; + //Serial.print(" cv_value: "); + //Serial.println(cv_value, DEC) ; + switch ( cv_value ) { + case 0: // LED on/off + ftn_queue[i].inuse = 0; + break; + case 1: // LED Blink + { + ftn_queue[i].inuse = 0; + ftn_queue[i].current_position = 0; + ftn_queue[i].start_value = 0; + ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5)))); + digitalWrite(fpins[i], 0); + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) ; + } + break; + case 2: //servo + { ftn_queue[i].current_position =int (Dcc.getCV( 34+(i*5))); + ftn_queue[i].stop_value = int (Dcc.getCV( 33+(i*5))); + ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5))); + ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5)))); + switch ( i ) { + case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object + ftn_queue[i].inuse = 1; + servo0.write(ftn_queue[i].start_value); + for (t=0; t ftn_queue[i].stop_value) { + ftn_queue[i].start_value = ~ftn_queue[i].start_value; + digitalWrite(fpins[i], ftn_queue[i].start_value); + ftn_queue[i].current_position = 0; + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); + } + break; + case 2: + { + if (ftn_queue[i].increment > 0) { + if (ftn_queue[i].current_position > ftn_queue[i].stop_value) + ftn_queue[i].current_position = ftn_queue[i].stop_value; + } + if (ftn_queue[i].increment < 0) { + if (ftn_queue[i].current_position < ftn_queue[i].start_value) + ftn_queue[i].current_position = ftn_queue[i].start_value; + } + set_servo(i, ftn_queue[i].current_position); + } + break; + case 3: + if (ftn_queue[i].current_position > ftn_queue[i].stop_value) { + ftn_queue[i].start_value = ~ftn_queue[i].start_value; + digitalWrite(fpins[i], ftn_queue[i].start_value); + digitalWrite(fpins[i]+1, ~ftn_queue[i].start_value); + ftn_queue[i].current_position = 0; + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); + } + i++; + break; + case 4: // Simple Pulsed Output based on saved Rate =10*Rate in Milliseconds + break; + case 5: //FUTURE FUNCTION + break; + default: + break; + } + } + } +} + +extern void notifyDccFunc( uint16_t Addr, FN_GROUP FuncGrp, uint8_t FuncState) { + switch(FuncGrp) + { + case FN_0_4: //Function Group 1 F0 F4 F3 F2 F1 + exec_function( 0, FunctionPin0, (FuncState & FN_BIT_00)>>4 ); + exec_function( 1, FunctionPin1, (FuncState & FN_BIT_01)); + exec_function( 2, FunctionPin2, (FuncState & FN_BIT_02)>>1); + exec_function( 3, FunctionPin3, (FuncState & FN_BIT_03)>>2 ); + exec_function( 4, FunctionPin4, (FuncState & FN_BIT_04)>>3 ); + break; + + case FN_5_8: //Function Group 1 S FFFF == 1 F8 F7 F6 F5 & == 0 F12 F11 F10 F9 F8 + exec_function( 5, FunctionPin5, (FuncState & FN_BIT_05)); + exec_function( 6, FunctionPin6, (FuncState & FN_BIT_06)>>1 ); + exec_function( 7, FunctionPin7, (FuncState & FN_BIT_07)>>2 ); + exec_function( 8, FunctionPin8, (FuncState & FN_BIT_08)>>3 ); + break; + + case FN_9_12: + exec_function( 9, FunctionPin9, (FuncState & FN_BIT_09)); + exec_function( 10, FunctionPin10, (FuncState & FN_BIT_10)>>1 ); + exec_function( 11, FunctionPin11, (FuncState & FN_BIT_11)>>2 ); + exec_function( 12, FunctionPin12, (FuncState & FN_BIT_12)>>3 ); + break; + + case FN_13_20: //Function Group 2 FuncState == F20-F13 Function Control + exec_function( 13, FunctionPin13, (FuncState & FN_BIT_13)); + exec_function( 14, FunctionPin14, (FuncState & FN_BIT_14)>>1 ); + exec_function( 15, FunctionPin15, (FuncState & FN_BIT_15)>>2 ); + exec_function( 16, FunctionPin16, (FuncState & FN_BIT_16)>>3 ); + break; + + case FN_21_28: + break; + } +} +void exec_function (int function, int pin, int FuncState) { + switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + case 0: // On - Off LED + //Serial.println("****************cv:0 ") ; + digitalWrite (pin, FuncState); + ftn_queue[function].inuse = 0; + break; + case 1: // Blinking LED + if ((ftn_queue[function].inuse==0) && (FuncState==1)) { + ftn_queue[function].inuse = 1; + ftn_queue[function].start_value = 0; + digitalWrite(pin, 0); + ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))); + } else { + if ((ftn_queue[function].inuse==1) && (FuncState==0)) { + ftn_queue[function].inuse = 0; + digitalWrite(pin, 0); + } + } + break; + case 2: // Servo + ftn_queue[function].inuse = 1; + if (FuncState==1) ftn_queue[function].increment = char ( Dcc.getCV( 31+(function*5))); + else ftn_queue[function].increment = - char(Dcc.getCV( 31+(function*5))); + if (FuncState==1) ftn_queue[function].stop_value = Dcc.getCV( 33+(function*5)); + else ftn_queue[function].stop_value = Dcc.getCV( 32+(function*5)); + /* + Serial.print("servo inc: ") ; + Serial.print(ftn_queue[function].increment,DEC) ; + Serial.print("servo inuse: ") ; + Serial.print(ftn_queue[function].inuse,DEC) ; + Serial.print("servo num: ") ; + Serial.print(function,DEC) ; + Serial.print(" stop: "); + Serial.println(ftn_queue[function].stop_value,DEC) ; + */ + break; + case 3: // Blinking LED PAIR + if ((ftn_queue[function].inuse==0) && (FuncState==1)) { + ftn_queue[function].inuse = 1; + ftn_queue[function].start_value = 0; + digitalWrite(fpins[function], 0); + digitalWrite(fpins[function+1], 1); + ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))); + } else { + if (FuncState==0) { + ftn_queue[function].inuse = 0; + digitalWrite(fpins[function], 0); + digitalWrite(fpins[function+1], 0); + } + } + break; + case 4: // Pulse Output based on Rate*10 Milliseconds + if ((ftn_queue[function].inuse==0) && (FuncState==1)) { //First Turn On Detected + digitalWrite(fpins[function], 1); + delay (10*ftn_queue[function].increment); + digitalWrite(fpins[function], 0); + ftn_queue[function].inuse = 1; //inuse set to 1 says we already pulsed + } else + if (FuncState==0) ftn_queue[function].inuse = 0; + break; + case 5: // Future Function + ftn_queue[function].inuse = 0; + break; + default: + ftn_queue[function].inuse = 0; + break; + } +} +void set_servo (int servo_num, int servo_pos) { + switch (servo_num) { + case 0: servo0.write(servo_pos); + break; + case 1: servo1.write(servo_pos); + break; + case 2: servo2.write(servo_pos); + break; + case 3: servo3.write(servo_pos); + break; + case 4: servo4.write(servo_pos); + break; + case 5: servo5.write(servo_pos); + break; + case 6: servo6.write(servo_pos); + break; + case 7: servo7.write(servo_pos); + break; + case 8: servo8.write(servo_pos); + break; + case 9: servo9.write(servo_pos); + break; + case 10: servo10.write(servo_pos); + break; + case 11: servo11.write(servo_pos); + break; + case 12: servo12.write(servo_pos); + break; + case 13: servo13.write(servo_pos); + break; + case 14: servo14.write(servo_pos); + break; + case 15: servo15.write(servo_pos); + break; + case 16: servo16.write(servo_pos); + break; + default: + break; + } +} diff --git a/examples/SMA/Decoder_2MotDrive_12LED_1Servo/Decoder_2MotDrive_12LED_1Servo.ino b/examples/SMA/Decoder_2MotDrive_12LED_1Servo/Decoder_2MotDrive_12LED_1Servo.ino new file mode 100755 index 0000000..60c6a73 --- /dev/null +++ b/examples/SMA/Decoder_2MotDrive_12LED_1Servo/Decoder_2MotDrive_12LED_1Servo.ino @@ -0,0 +1,672 @@ +// Production Motor Drive 13 Pin Function DCC Decoder with Motor Drive +// F13 and F14 enable speed control of MOTOR1 and MOTOR2 respectively +// Version 5.0 Geoff Bunza 2015 +// Uses modified software servo Lib +// +// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP +// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!! +//#define DECODER_LOADED + +#include +#include + +SoftwareServo servo0; +SoftwareServo servo1; +SoftwareServo servo2; +SoftwareServo servo3; +SoftwareServo servo4; +SoftwareServo servo5; +SoftwareServo servo6; +SoftwareServo servo7; +SoftwareServo servo8; +SoftwareServo servo9; +SoftwareServo servo10; +SoftwareServo servo11; +SoftwareServo servo12; +#define servo_start_delay 50 +#define servo_init_delay 7 + +uint8_t Motor1Speed = 0; +uint8_t Motor1ForwardDir = 1; +uint8_t Motor1MaxSpeed = 127; +uint8_t Motor2Speed = 0; +uint8_t Motor2ForwardDir = 1; +uint8_t Motor2MaxSpeed = 127; +int kickstarton = 1400; //kick start cycle on time +int kickstarttime = 5; //kick start duration on time +int fwdon = 0; +int fwdtime = 1; +int bwdon = 0; +int bwdtime = 1; +int bwdshift = 0; +int cyclewidth = 2047; +int m2h = 3; //R H Bridge //Motor1 +int m2l = 4; //B H Bridge //Motor1 +int m0h = 9; //R H Bridge //Motor2 +int m0l = 10; //B H Bridge //Motor2 + +int speedup = 112; //Right track time differntial +int deltime = 1500; +int tim_delay = 100; +int numfpins = 17; +int num_active_fpins = 13; +byte fpins [] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; +const int FunctionPin0 = 5; +const int FunctionPin1 = 6; +const int FunctionPin2 = 7; +const int FunctionPin3 = 8; +const int FunctionPin4 = 11; + +const int FunctionPin5 = 12; +const int FunctionPin6 = 13; +const int FunctionPin7 = 14; //A0 +const int FunctionPin8 = 15; //A1 + +const int FunctionPin9 = 16; //A2 +const int FunctionPin10 = 17; //A3 +const int FunctionPin11 = 18; //A4 +const int FunctionPin12 = 19; //A5 + +int Function13_value = 0; +int Function14_value = 0; + +NmraDcc Dcc ; +DCC_MSG Packet ; +uint8_t CV_DECODER_MASTER_RESET = 120; +int t; // temp +#define This_Decoder_Address 24 +struct QUEUE +{ + int inuse; + int current_position; + int increment; + int stop_value; + int start_value; +}; +QUEUE *ftn_queue = new QUEUE[16]; + +extern uint8_t Decoder_Address = This_Decoder_Address; +struct CVPair +{ + uint16_t CV; + uint8_t Value; +}; +CVPair FactoryDefaultCVs [] = +{ + {CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address}, + {CV_ACCESSORY_DECODER_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, + {CV_DECODER_MASTER_RESET, 0}, + {30, 0}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate + {32, 1}, //F0 Start Position F0=0 + {33, 1}, //F0 End Position F0=1 + {34, 10}, //F0 Current Position + {35, 0}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {37, 1}, // Start Position Fx=0 + {38, 1}, // End Position Fx=1 + {39, 10}, // Current Position + {40, 0}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {42, 1}, // Start Position Fx=0 + {43, 10}, // End Position Fx=1 + {44, 10}, // Current Position + {45, 0}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {47, 1}, // Start Position Fx=0 + {48, 1}, // End Position Fx=1 + {49, 10}, // Current Position + {50, 0}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {52, 1}, // Start Position Fx=0 + {53, 1}, // End Position Fx=1 + {54, 10}, // Current Position + {55, 0}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {56, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {57, 1}, // Start Position Fx=0 + {58, 1}, // End Position Fx=1 + {59, 10}, // Current Position + {60, 0}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {62, 1}, // Start Position Fx=0 + {63, 1}, // End Position Fx=1 + {64, 10}, // Current Position + {65, 0}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {67, 1}, // Start Position Fx=0 + {68, 1}, // End Position Fx=1 + {69, 1}, // Current Position + {70, 0}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {72, 1}, // Start Position Fx=0 + {73, 10}, // End Position Fx=1 + {74, 1}, // Current Position + {75, 0}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {77, 1}, // Start Position Fx=0 + {78, 10}, // End Position Fx=1 + {79, 1}, // Current Position + {80, 2}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {81, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {82, 28}, // Start Position Fx=0 + {83, 140}, // End Position Fx=1 + {84, 28}, // Current Position + {85, 0}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {86, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {87, 1}, // Start Position Fx=0 + {88, 5}, // End Position Fx=1 + {89, 1}, // Current Position + {90, 0}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {92, 1}, // Start Position Fx=0 + {93, 1}, // End Position Fx=1 + {94, 28}, // Current Position + {95, 0}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {97, 1}, // Start Position Fx=0 + {98, 28}, // End Position Fx=1 + {99, 2}, // Current Position + {100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {102, 1}, // Start Position Fx=0 + {103, 4}, // End Position Fx=1 + {104, 1}, // Current Position + {105, 0}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {107, 1}, // Start Position Fx=0 + {108, 1}, // End Position Fx=1 + {109, 20}, // Current Position + {110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {112, 1}, // Start Position Fx=0 + {113, 1}, // End Position Fx=1 + {114, 1}, // Current Position +//FUTURE USE + {115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + {116, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate + {117, 28}, // Start Position Fx=0 + {118, 140}, // End Position Fx=1 + {119, 28}, // Current Position +}; + +uint8_t FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair); +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); +}; + +void setup() //****************************************************** +{ + int i; + uint8_t cv_value; + // initialize the digital pins as outputs + for (int i=0; i < numfpins; i++) { + pinMode(fpins[i], OUTPUT); + digitalWrite(fpins[i], 0); + } + for (int i=0; i < numfpins; i++) { + digitalWrite(fpins[i], 1); + delay (tim_delay/10); + } + delay( tim_delay); + for (int i=0; i < numfpins; i++) { + digitalWrite(fpins[i], 0); + delay (tim_delay/10); + } + delay( tim_delay); + + // Setup which External Interrupt, the Pin it's associated with that we're using + Dcc.pin(0, 2, 0); + // Call the main DCC Init function to enable the DCC Receiver + Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 ); + delay(800); + + #if defined(DECODER_LOADED) + if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET ) + #endif + + { + for (int j=0; j < FactoryDefaultCVIndex; j++ ) + Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value); + digitalWrite(fpins[14], 1); + delay (1000); + digitalWrite(fpins[14], 0); + } + for ( i=0; i < num_active_fpins; i++) { + cv_value = Dcc.getCV( 30+(i*5)) ; + switch ( cv_value ) { + case 0: // LED on/off + ftn_queue[i].inuse = 0; + break; + case 1: // LED Blink + { + ftn_queue[i].inuse = 0; + ftn_queue[i].current_position = 0; + ftn_queue[i].start_value = 0; + ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5)))); + digitalWrite(fpins[i], 0); + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) ; + } + break; + case 2: //servo + { ftn_queue[i].current_position =int (Dcc.getCV( 34+(i*5))); + ftn_queue[i].stop_value = int (Dcc.getCV( 33+(i*5))); + ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5))); + ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5)))); + switch ( i ) { + case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object + ftn_queue[i].inuse = 1; + servo0.write(ftn_queue[i].start_value); + for (t=0; t ftn_queue[i].stop_value) { + ftn_queue[i].start_value = ~ftn_queue[i].start_value; + digitalWrite(fpins[i], ftn_queue[i].start_value); + ftn_queue[i].current_position = 0; + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); + } + break; + case 2: + { + if (ftn_queue[i].increment > 0) { + if (ftn_queue[i].current_position > ftn_queue[i].stop_value) { + ftn_queue[i].current_position = ftn_queue[i].stop_value; + servo_on = false; + detach_servo (i); + } + } + if (ftn_queue[i].increment < 0) { + if (ftn_queue[i].current_position < ftn_queue[i].start_value) { + ftn_queue[i].current_position = ftn_queue[i].start_value; + servo_on = false; + detach_servo (i); + } + } + if (servo_on) { + set_servo(i, ftn_queue[i].current_position); + } + } + break; + case 3: + if (ftn_queue[i].current_position > ftn_queue[i].stop_value) { + ftn_queue[i].start_value = ~ftn_queue[i].start_value; + digitalWrite(fpins[i], ftn_queue[i].start_value); + digitalWrite(fpins[i]+1, ~ftn_queue[i].start_value); + ftn_queue[i].current_position = 0; + ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); + } + i++; + break; + case 4: //FUTURE FUNCTION + break; + default: + break; + } + } + + } + // +} +void gofwd1(int fcnt,int fcycle) { + int icnt; + int totcycle; + icnt = 0; + while (icnt < fcnt) + { + digitalWrite(m2h, HIGH); //Motor1 + delayMicroseconds(fcycle); + digitalWrite(m2h, LOW); //Motor1 + delayMicroseconds(cyclewidth - fcycle); + icnt++; + } +} +void gobwd1(int bcnt,int bcycle) { + int icnt; + icnt=0; + while (icnt < bcnt) + { + digitalWrite(m2l, HIGH); //Motor1 + delayMicroseconds(bcycle); + digitalWrite(m2l, LOW); //Motor1 + delayMicroseconds(cyclewidth - bcycle); + icnt++; + } +} +void gofwd2(int fcnt,int fcycle) { + int icnt; + int totcycle; + icnt = 0; + while (icnt < fcnt) + { + digitalWrite(m0h, HIGH); //Motor2 + delayMicroseconds(fcycle); + digitalWrite(m0h, LOW); //Motor2 + delayMicroseconds(cyclewidth - fcycle); + icnt++; + } +} +void gobwd2(int bcnt,int bcycle) { + int icnt; + icnt=0; + while (icnt < bcnt) + { + digitalWrite(m0l, HIGH); //Motor2 + delayMicroseconds(bcycle); + digitalWrite(m0l, LOW); //Motor2 + delayMicroseconds(cyclewidth - bcycle); + icnt++; + } +} +extern void notifyDccSpeed( uint16_t Addr, uint8_t Speed, uint8_t ForwardDir, uint8_t MaxSpeed ) { + if (Function13_value==1) { + Motor1Speed = Speed; + Motor1ForwardDir = ForwardDir; + Motor1MaxSpeed = MaxSpeed; + } + if (Function14_value==1) { + Motor2Speed = Speed; + Motor2ForwardDir = ForwardDir; + Motor2MaxSpeed = MaxSpeed; + } +} +extern void notifyDccFunc( uint16_t Addr, FN_GROUP FuncGrp, uint8_t FuncState) { + switch(FuncGrp) + { + case FN_0_4: //Function Group 1 F0 F4 F3 F2 F1 + exec_function( 0, FunctionPin0, (FuncState & FN_BIT_00)>>4 ); + exec_function( 1, FunctionPin1, (FuncState & FN_BIT_01)); + exec_function( 2, FunctionPin2, (FuncState & FN_BIT_02)>>1); + exec_function( 3, FunctionPin3, (FuncState & FN_BIT_03)>>2 ); + exec_function( 4, FunctionPin4, (FuncState & FN_BIT_04)>>3 ); + break; + + case FN_5_8: //Function Group 1 S FFFF == 1 F8 F7 F6 F5 & == 0 F12 F11 F10 F9 F8 + exec_function( 5, FunctionPin5, (FuncState & FN_BIT_05)); + exec_function( 6, FunctionPin6, (FuncState & FN_BIT_06)>>1 ); + exec_function( 7, FunctionPin7, (FuncState & FN_BIT_07)>>2 ); + exec_function( 8, FunctionPin8, (FuncState & FN_BIT_08)>>3 ); + break; + + case FN_9_12: + exec_function( 9, FunctionPin9, (FuncState & FN_BIT_09)); + exec_function( 10, FunctionPin10, (FuncState & FN_BIT_10)>>1 ); + exec_function( 11, FunctionPin11, (FuncState & FN_BIT_11)>>2 ); + exec_function( 12, FunctionPin12, (FuncState & FN_BIT_12)>>3 ); + break; + + case FN_13_20: //Function Group 2 FuncState == F20-F13 Function Control + Function13_value = (FuncState & FN_BIT_13); + Function14_value = (FuncState & FN_BIT_14)>>1; +/* + exec_function( 15, FunctionPin15, (FuncState & FN_BIT_15)>>2 ); + exec_function( 16, FunctionPin16, (FuncState & FN_BIT_16)>>3 ); +*/ + break; + case FN_21_28: + break; + } +} +void exec_function (int function, int pin, int FuncState) { + switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink + case 0: // On - Off LED + digitalWrite (pin, FuncState); + ftn_queue[function].inuse = 0; + break; + case 1: // Blinking LED + if ((ftn_queue[function].inuse==0) && (FuncState==1)) { + ftn_queue[function].inuse = 1; + ftn_queue[function].start_value = 0; + digitalWrite(pin, 0); + ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))); + } else { + if ((ftn_queue[function].inuse==1) && (FuncState==0)) { + ftn_queue[function].inuse = 0; + digitalWrite(pin, 0); + } + } + break; + case 2: // Servo + ftn_queue[function].inuse = 1; + if (FuncState==1) ftn_queue[function].increment = char ( Dcc.getCV( 31+(function*5))); + else ftn_queue[function].increment = - char(Dcc.getCV( 31+(function*5))); + if (FuncState==1) ftn_queue[function].stop_value = Dcc.getCV( 33+(function*5)); + else ftn_queue[function].stop_value = Dcc.getCV( 32+(function*5)); + break; + case 3: // Blinking LED PAIR + if ((ftn_queue[function].inuse==0) && (FuncState==1)) { + ftn_queue[function].inuse = 1; + ftn_queue[function].start_value = 0; + digitalWrite(fpins[function], 0); + digitalWrite(fpins[function+1], 1); + ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))); + } else { + if (FuncState==0) { + ftn_queue[function].inuse = 0; + digitalWrite(fpins[function], 0); + digitalWrite(fpins[function+1], 0); + } + } + break; + case 4: // Future Function + ftn_queue[function].inuse = 0; + break; + default: + ftn_queue[function].inuse = 0; + break; + } +} +void set_servo (int servo_num, int servo_pos) { + switch (servo_num) { + case 0: + if (servo0.attached()==0) servo0.attach(FunctionPin0); + servo0.write(servo_pos); + break; + case 1: + if (servo1.attached()==0) servo1.attach(FunctionPin1); + servo1.write(servo_pos); + break; + case 2: + if (servo2.attached()==0) servo2.attach(FunctionPin2); + servo2.write(servo_pos); + break; + case 3: + if (servo3.attached()==0) servo3.attach(FunctionPin3); + servo3.write(servo_pos); + break; + case 4: + if (servo4.attached()==0) servo4.attach(FunctionPin4); + servo4.write(servo_pos); + break; + case 5: + if (servo5.attached()==0) servo5.attach(FunctionPin5); + servo5.write(servo_pos); + break; + case 6: + if (servo6.attached()==0) servo6.attach(FunctionPin6); + servo6.write(servo_pos); + break; + case 7: + if (servo7.attached()==0) servo7.attach(FunctionPin7); + servo7.write(servo_pos); + break; + case 8: + if (servo8.attached()==0) servo8.attach(FunctionPin8); + servo8.write(servo_pos); + break; + case 9: + if (servo9.attached()==0) servo9.attach(FunctionPin9); + servo9.write(servo_pos); + break; + case 10: + if (servo10.attached()==0) servo10.attach(FunctionPin10); + servo10.write(servo_pos); + break; + case 11: + if (servo11.attached()==0) servo11.attach(FunctionPin11); + servo11.write(servo_pos); + break; + case 12: + if (servo12.attached()==0) servo12.attach(FunctionPin12); + servo12.write(servo_pos); + break; + default: + break; + } +} +void detach_servo (int servo_num) { + switch (servo_num) { + case 0: + if (servo0.attached()!=0) servo0.detach(); + break; + case 1: + if (servo1.attached()!=0) servo1.detach(); + break; + case 2: + if (servo2.attached()!=0) servo2.detach(); + break; + case 3: + if (servo3.attached()!=0) servo3.detach(); + break; + case 4: + if (servo4.attached()!=0) servo4.detach(); + break; + case 5: + if (servo5.attached()!=0) servo5.detach(); + break; + case 6: + if (servo6.attached()!=0) servo6.detach(); + break; + case 7: + if (servo7.attached()!=0) servo7.detach(); + break; + case 8: + if (servo8.attached()!=0) servo8.detach(); + break; + case 9: + if (servo9.attached()!=0) servo9.detach(); + break; + case 10: + if (servo10.attached()!=0) servo10.detach(); + break; + case 11: + if (servo11.attached()!=0) servo11.detach(); + break; + case 12: + if (servo12.attached()!=0) servo12.detach(); + default: + break; + } +} diff --git a/examples/Decoder_7Servos_10LED_4Function/Decoder_7Servos_10LED_4Function.ino b/examples/SMA/Decoder_7Servos_10LED_4Function/Decoder_7Servos_10LED_4Function.ino similarity index 100% rename from examples/Decoder_7Servos_10LED_4Function/Decoder_7Servos_10LED_4Function.ino rename to examples/SMA/Decoder_7Servos_10LED_4Function/Decoder_7Servos_10LED_4Function.ino diff --git a/examples/SMA/Decoder_Dir_and_Fade/Decoder_Dir_and_Fade.ino b/examples/SMA/Decoder_Dir_and_Fade/Decoder_Dir_and_Fade.ino new file mode 100755 index 0000000..f18c087 --- /dev/null +++ b/examples/SMA/Decoder_Dir_and_Fade/Decoder_Dir_and_Fade.ino @@ -0,0 +1,199 @@ +#include +// Working 17 Function DCC Decoder DccAckPin not needed +// LED control is dependent on direction of travel +// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP +// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!! +//#define DECODER_LOADED + +int tim_delay = 500; +#define numleds 17 +byte ledpins [] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; //Defines all possible LED pins + +// The following list defines how each of the 17 function pins operate: +// a 0 allows for normal On/Off control with fade on and fade off +// a 1 allows for normal control when the decoder sees a forward speed setting, reverse turns the LED off +// a 2 allows for normal control when the decoder sees a reverse speed setting, forward turns the LED off +byte led_direction [] = {0,1,2,0,1,1,1,1,2,2,2,2,0,0,0,0,0}; //0=On/Off, 1=On Forward, 2=On Reverse + +boolean led_last_state [] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false}; //last state of led +boolean Last_Function_State[] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false}; //These hold the last Fx assignments +uint8_t Decoder_direction = 0; +uint8_t Last_Decoder_direction = 0; +int fade_time = 170; +const int FunctionPin0 = 3; +const int FunctionPin1 = 4; +const int FunctionPin2 = 5; +const int FunctionPin3 = 6; +const int FunctionPin4 = 7; + +const int FunctionPin5 = 8; +const int FunctionPin6 = 9; +const int FunctionPin7 = 10; +const int FunctionPin8 = 11; + +const int FunctionPin9 = 12; +const int FunctionPin10 = 13; +const int FunctionPin11 = 14; //A0 +const int FunctionPin12 = 15; //A1 + +const int FunctionPin13 = 16; //A2 +const int FunctionPin14 = 17; //A3 +const int FunctionPin15 = 18; //A4 +const int FunctionPin16 = 19; //A5 +NmraDcc Dcc ; +DCC_MSG Packet ; + +#define This_Decoder_Address 24 +struct CVPair +{ + uint16_t CV; + uint8_t Value; +}; +CVPair FactoryDefaultCVs [] = +{ + {CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address}, + {CV_ACCESSORY_DECODER_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, +}; +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); +}; +void setup() +{ + //Serial.begin(115200); + // initialize the digital pins as an outputs + for (int i=0; i< numleds; i++) { + pinMode(ledpins[i], OUTPUT); + digitalWrite(ledpins[i], LOW); + } + for (int i=0; i< numleds; i++) { + digitalWrite(ledpins[i], HIGH); + delay (tim_delay/10); + } + delay( tim_delay); + for (int i=0; i< numleds; i++) { + digitalWrite(ledpins[i], LOW); + delay (tim_delay/10); + } + delay( tim_delay); + #if defined(DECODER_LOADED) + if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET ) + #endif + { + for (int j=0; j < FactoryDefaultCVIndex; j++ ) + Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value); + digitalWrite(ledpins[14], 1); + delay (1000); + digitalWrite(ledpins[14], 0); + } + // Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up + Dcc.pin(0, 2, 0); + // Call the main DCC Init function to enable the DCC Receiver + Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 ); +} +void loop() +{ + // You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation + Dcc.process(); +} +extern void notifyDccFunc( uint16_t Addr, FN_GROUP FuncGrp, uint8_t FuncState) { +int f_index; +switch (FuncGrp) { + case FN_0_4: //Function Group 1 F0 F4 F3 F2 F1 + exec_function( 0, (FuncState & FN_BIT_00)>>4 ); + exec_function( 1, (FuncState & FN_BIT_01)); + exec_function( 2, (FuncState & FN_BIT_02)>>1); + exec_function( 3, (FuncState & FN_BIT_03)>>2 ); + exec_function( 4, (FuncState & FN_BIT_04)>>3 ); + break; + + case FN_5_8: //Function Group 1 S FFFF == 1 F8 F7 F6 F5 & == 0 F12 F11 F10 F9 F8 + exec_function( 5, (FuncState & FN_BIT_05)); + exec_function( 6, (FuncState & FN_BIT_06)>>1 ); + exec_function( 7, (FuncState & FN_BIT_07)>>2 ); + exec_function( 8, (FuncState & FN_BIT_08)>>3 ); + break; + + case FN_9_12: + exec_function( 9, (FuncState & FN_BIT_09)); + exec_function( 10,(FuncState & FN_BIT_10)>>1 ); + exec_function( 11,(FuncState & FN_BIT_11)>>2 ); + exec_function( 12,(FuncState & FN_BIT_12)>>3 ); + break; + + case FN_13_20: //Function Group 2 FuncState == F20-F13 Function Control + exec_function( 13, (FuncState & FN_BIT_13)); + exec_function( 14, (FuncState & FN_BIT_14)>>1 ); + exec_function( 15, (FuncState & FN_BIT_15)>>2 ); + exec_function( 16, (FuncState & FN_BIT_16)>>3 ); + break; + + } +} +void exec_function (int f_index, int FuncState) { + if ((FuncState==1) && (!Last_Function_State[f_index])) { + Last_Function_State[f_index] = true; + Set_LED (f_index,true); + } + else if ((FuncState==0) && Last_Function_State[f_index]) { + Last_Function_State[f_index] = false; + Set_LED (f_index,false); + } +} +extern void notifyDccSpeed( uint16_t Addr, uint8_t Speed, uint8_t ForwardDir, uint8_t MaxSpeed ) { + Last_Decoder_direction = Decoder_direction; + Decoder_direction = ForwardDir; + if ( Decoder_direction==Last_Decoder_direction) return; + for (int i=0; i +// Working 12 Function DCC Decoder DccAckPin not needed +// 5 pin Arbitrary Group Lighting Functions Set in 4-Function Groups +// With Fade On and Fade Off +// Rev 4 Geoff Bunza September 2015 +// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP +// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!! +//#define DECODER_LOADED + +int tim_delay = 500; +#define numleds 17 +byte ledpins [] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; +byte FPins_Assigned [12][5] = { // This array defines the pins controlled by each function + {3,4,5,6,7}, // F0 + {3,4,5,6,7}, // F1 + {3,4,5,6,7}, // F2 + {3,4,5,6,7}, // F3 + {8,9,10,11,12}, // F4 + {8,9,10,11,12}, // F5 + {8,9,10,11,12}, // F6 + {8,9,10,11,12}, // F7 + {13,14,15,16,17}, // F8 + {13,14,15,16,17}, // F9 + {13,14,15,16,17}, // F10 + {13,14,15,16,17} // F11 + }; +byte Function_Lites [12][5] = { // This array defines the Lights/LEDs controlled in each light group per function + {1,1,0,0,0}, // F0 Hp0 + {0,0,1,0,0}, // F1 Hp1 + {0,0,1,0,1}, // F2 Hp2 + {0,0,1,1,0}, // F3 Sh1 + {1,1,0,0,0}, // F4 Hp0 + {0,0,1,0,0}, // F5 Hp1 + {0,0,1,0,1}, // F6 Hp2 + {0,0,1,1,0}, // F7 Sh1 + {1,1,0,0,0}, // F8 Hp0 + {0,0,1,0,0}, // F9 Hp1 + {0,0,1,0,1}, // F10 Hp2 + {0,0,1,1,0} // F11 Sh1 + }; +boolean Last_Function_State[] = {false,false,false,false,false,false,false,false,false,false,false,false}; + +const int FunctionPin0 = 3; +const int FunctionPin1 = 4; +const int FunctionPin2 = 5; +const int FunctionPin3 = 6; +const int FunctionPin4 = 7; +const int FunctionPin5 = 8; +const int FunctionPin6 = 9; +const int FunctionPin7 = 10; +const int FunctionPin8 = 11; +const int FunctionPin9 = 12; +const int FunctionPin10 = 13; +const int FunctionPin11 = 14; //A0 +const int FunctionPin12 = 15; //A1 +const int FunctionPin13 = 16; //A2 +const int FunctionPin14 = 17; //A3 +const int FunctionPin15 = 18; //A4 +const int FunctionPin16 = 19; //A5 +NmraDcc Dcc ; +DCC_MSG Packet ; + +#define This_Decoder_Address 24 + +struct CVPair +{ + uint16_t CV; + uint8_t Value; +}; +CVPair FactoryDefaultCVs [] = +{ + {CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address}, + {CV_ACCESSORY_DECODER_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, + {CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, +}; + +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); +}; + +void setup() +{ + //Serial.begin(115200); + // initialize the digital pins as an outputs + for (int i=0; i< numleds; i++) { + pinMode(ledpins[i], OUTPUT); + digitalWrite(ledpins[i], LOW); + } + for (int i=0; i< numleds; i++) { + digitalWrite(ledpins[i], HIGH); + delay (tim_delay/10); + } + delay( tim_delay); + for (int i=0; i< numleds; i++) { + digitalWrite(ledpins[i], LOW); + delay (tim_delay/10); + } + delay( tim_delay); + + #if defined(DECODER_LOADED) + if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET ) + #endif + { + for (int j=0; j < FactoryDefaultCVIndex; j++ ) + Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value); + digitalWrite(ledpins[14], 1); + delay (1000); + digitalWrite(ledpins[14], 0); + } + // Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up + Dcc.pin(0, 2, 0); + // Call the main DCC Init function to enable the DCC Receiver + Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 ); +} +void loop() +{ + // You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation + Dcc.process(); +} + +extern void notifyDccFunc( uint16_t Addr, FN_GROUP FuncGrp, uint8_t FuncState) { +int f_index; +switch (FuncGrp) { + case FN_0_4: //Function Group 1 F0 F4 F3 F2 F1 + exec_function( 0, (FuncState & FN_BIT_00)>>4 ); + exec_function( 1, (FuncState & FN_BIT_01)); + exec_function( 2, (FuncState & FN_BIT_02)>>1); + exec_function( 3, (FuncState & FN_BIT_03)>>2 ); + exec_function( 4, (FuncState & FN_BIT_04)>>3 ); + break; + + case FN_5_8: //Function Group 1 S FFFF == 1 F8 F7 F6 F5 & == 0 F12 F11 F10 F9 F8 + exec_function( 5, (FuncState & FN_BIT_05)); + exec_function( 6, (FuncState & FN_BIT_06)>>1 ); + exec_function( 7, (FuncState & FN_BIT_07)>>2 ); + exec_function( 8, (FuncState & FN_BIT_08)>>3 ); + break; + + case FN_9_12: + exec_function( 9, (FuncState & FN_BIT_09)); + exec_function( 10,(FuncState & FN_BIT_10)>>1 ); + exec_function( 11,(FuncState & FN_BIT_11)>>2 ); + break; + + } +} +void exec_function (int f_index, int FuncState) { + #define fadedelay 5 + if ((FuncState==1) && (!Last_Function_State[f_index])) { + for (int i=0; i<60; i++) { + for (int j=0; j<5; j++) if (Function_Lites[f_index][j]==1) digitalWrite( FPins_Assigned[f_index][j],1); + delay(fadedelay*i/60.0); + for (int j=0; j<5; j++) if (Function_Lites[f_index][j]==1) digitalWrite( FPins_Assigned[f_index][j],0); + delay(fadedelay-(fadedelay*i/60.0)); + } + for (int j=0; j<5; j++) digitalWrite( FPins_Assigned[f_index][j],Function_Lites[f_index][j]); + Last_Function_State[f_index] = true; + } + else if ((FuncState==0) && Last_Function_State[f_index]) { + for (int i=0; i<60; i++) { + for (int j=0; j<5; j++) if (Function_Lites[f_index][j]==1) digitalWrite( FPins_Assigned[f_index][j],0); + delay(fadedelay*i/60.0); + for (int j=0; j<5; j++) if (Function_Lites[f_index][j]==1) digitalWrite( FPins_Assigned[f_index][j],1); + delay(fadedelay-(fadedelay*i/60.0)); + } + for (int j=0; j<5; j++) digitalWrite( FPins_Assigned[f_index][j], 0); + Last_Function_State[f_index] = false; + } +} + diff --git a/library.properties b/library.properties index 4fa783b..e8eb40a 100644 --- a/library.properties +++ b/library.properties @@ -1,6 +1,6 @@ name=NmraDcc -version=1.0.0 -author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza +version=1.1.0 +author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky maintainer=Alex Shepherd sentence=Enables NMRA DCC Communication paragraph=This library allows you to interface to a NMRA DCC track signal and receive DCC commands. The library currently supports the AVR ATTiny84/85 & ATMega88/168/328/32u4 using the INT0/1 Hardware Interrupt and Timer0 Compare Match B