Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
Nodemcu Firmware
Commits
3bf8db13
Commit
3bf8db13
authored
Feb 03, 2021
by
Lukáš Voborský
Committed by
Marcel Stör
Mar 12, 2021
Browse files
NmraDcc upstream version
parent
e96078e6
Changes
2
Expand all
Hide whitespace changes
Inline
Side-by-side
app/driver/NmraDcc.c
View file @
3bf8db13
This diff is collapsed.
Click to expand it.
app/include/driver/NmraDcc.h
View file @
3bf8db13
...
...
@@ -2,11 +2,21 @@
//
// Model Railroading with Arduino - NmraDcc.h
//
// Copyright (c) 2008 - 20
18
Alex Shepherd
// Copyright (c) 2008 - 20
20
Alex Shepherd
//
// This source file is subject of the GNU general public license 2,
// that is available at the world-wide-web at
// http://www.gnu.org/licenses/gpl.txt
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//------------------------------------------------------------------------
//
...
...
@@ -29,30 +39,35 @@
//
//------------------------------------------------------------------------
// NodeMCU Lua port by @voborsky
// #define NODE_DEBUG
// #define DCC_DEBUG
// #define DCC_DBGVAR
// Uncomment the following Line to Enable Service Mode CV Programming
#define NMRA_DCC_PROCESS_SERVICEMODE
// Uncomment the following line to Enable MultiFunction Decoder Operations
#define NMRA_DCC_PROCESS_MULTIFUNCTION
// #ifndef NMRADCC_IS_IN
// #define NMRADCC_IS_IN
// 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
#include "WProgram.h"
#endif
#ifndef NMRADCC_IS_IN
#define NMRADCC_IS_IN
#define NMRADCC_VERSION 20
1
// Version 2.0.
1
#define NMRADCC_VERSION 20
6
// Version 2.0.
6
#define MAX_DCC_MESSAGE_LEN 6 // including XOR-Byte
//#define ALLOW_NESTED_IRQ // uncomment to enable nested IRQ's ( only for AVR! )
typedef
struct
{
uint8_t
Size
;
uint8_t
PreambleBits
;
uint8_t
Data
[
MAX_DCC_MESSAGE_LEN
]
;
uint8_t
Size
;
uint8_t
PreambleBits
;
uint8_t
Data
[
MAX_DCC_MESSAGE_LEN
]
;
}
DCC_MSG
;
//--------------------------------------------------------------------------
...
...
@@ -91,23 +106,39 @@ typedef struct
#define CV_MANUFACTURER_ID 8
#define CV_29_CONFIG 29
#if defined(ESP32)
#include <esp_spi_flash.h>
#define MAXCV SPI_FLASH_SEC_SIZE
#elif defined(ESP8266)
#include <spi_flash.h>
#define MAXCV SPI_FLASH_SEC_SIZE
#elif defined( __STM32F1__)
#define MAXCV (EEPROM_PAGE_SIZE/4 - 1) // number of storage places (CV address could be larger
// because STM32 uses virtual adresses)
#undef ALLOW_NESTED_IRQ // This is done with NVIC on STM32
#define PRIO_DCC_IRQ 9
#define PRIO_SYSTIC 8 // MUST be higher priority than DCC Irq
#else
#define MAXCV E2END // the upper limit of the CV value currently defined to max memory.
#endif
typedef
enum
{
CV29_LOCO_DIR
=
0
b00000001
,
/** bit 0: Locomotive Direction: "0" = normal, "1" = reversed */
CV29_F0_LOCATION
=
0
b00000010
,
/** bit 1: F0 location: "0" = bit 4 in Speed and Direction instructions, "1" = bit 4 in function group one instruction */
CV29_APS
=
0
b00000100
,
/** bit 2: Alternate Power Source (APS) "0" = NMRA Digital only, "1" = Alternate power source set by CV12 */
CV29_
ADV_ACK
=
0
b00001000
,
/** bit 3:
ACK, Advanced Acknowledge mode enabled if 1, disabled if 0
*/
CV29_SPEED_TABLE_ENABLE
=
0
b00010000
,
/** bit 4: STE, Speed Table Enable, "0" = values in CVs 2, 4 and 6, "1" = Custom table selected by CV 25 */
CV29_EXT_ADDRESSING
=
0
b00100000
,
/** bit 5: "0" = one byte addressing, "1" = two byte addressing */
CV29_OUTPUT_ADDRESS_MODE
=
0
b01000000
,
/** bit 6: "0" = Decoder Address Mode "1" = Output Address Mode */
CV29_ACCESSORY_DECODER
=
0
b10000000
,
/** bit 7: "0" = Multi-Function Decoder Mode "1" = Accessory Decoder Mode */
CV29_LOCO_DIR
=
0b00000001
,
/** bit 0: Locomotive Direction: "0" = normal, "1" = reversed */
CV29_F0_LOCATION
=
0b00000010
,
/** bit 1: F0 location: "0" = bit 4 in Speed and Direction instructions, "1" = bit 4 in function group one instruction */
CV29_APS
=
0b00000100
,
/** bit 2: Alternate Power Source (APS) "0" = NMRA Digital only, "1" = Alternate power source set by CV12 */
CV29_
RAILCOM_ENABLE
=
0b00001000
,
/** bit 3:
BiDi ( RailCom ) is active
*/
CV29_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 */
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 */
SPEED_STEP_28
=
29
,
/**< ESTOP=0, 1 to 29 */
SPEED_STEP_128
=
127
/**< ESTOP=0, 1 to 127 */
}
DCC_SPEED_STEPS
;
typedef
enum
{
...
...
@@ -122,97 +153,264 @@ typedef enum {
typedef
enum
{
FN_0_4
=
1
,
FN_5_8
,
FN_9_12
,
FN_13_20
,
FN_21_28
,
FN_0_4
=
1
,
FN_5_8
,
FN_9_12
,
FN_13_20
,
FN_21_28
,
#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
FN_0
/** function light is controlled by base line package (14 speed steps) */
FN_0
/** function light is controlled by base line package (14 speed steps) */
#endif
}
FN_GROUP
;
#define FN_BIT_00 0x10
#define FN_BIT_01 0x01
#define FN_BIT_02 0x02
#define FN_BIT_03 0x04
#define FN_BIT_04 0x08
#define FN_BIT_05 0x01
#define FN_BIT_06 0x02
#define FN_BIT_07 0x04
#define FN_BIT_08 0x08
#define FN_BIT_09 0x01
#define FN_BIT_10 0x02
#define FN_BIT_11 0x04
#define FN_BIT_12 0x08
#define FN_BIT_13 0x01
#define FN_BIT_14 0x02
#define FN_BIT_15 0x04
#define FN_BIT_16 0x08
#define FN_BIT_17 0x10
#define FN_BIT_18 0x20
#define FN_BIT_19 0x40
#define FN_BIT_20 0x80
#define FN_BIT_21 0x01
#define FN_BIT_22 0x02
#define FN_BIT_23 0x04
#define FN_BIT_24 0x08
#define FN_BIT_25 0x10
#define FN_BIT_26 0x20
#define FN_BIT_27 0x40
#define FN_BIT_28 0x80
#define FN_BIT_00 0x10
#define FN_BIT_01 0x01
#define FN_BIT_02 0x02
#define FN_BIT_03 0x04
#define FN_BIT_04 0x08
#define FN_BIT_05 0x01
#define FN_BIT_06 0x02
#define FN_BIT_07 0x04
#define FN_BIT_08 0x08
#define FN_BIT_09 0x01
#define FN_BIT_10 0x02
#define FN_BIT_11 0x04
#define FN_BIT_12 0x08
#define FN_BIT_13 0x01
#define FN_BIT_14 0x02
#define FN_BIT_15 0x04
#define FN_BIT_16 0x08
#define FN_BIT_17 0x10
#define FN_BIT_18 0x20
#define FN_BIT_19 0x40
#define FN_BIT_20 0x80
#define FN_BIT_21 0x01
#define FN_BIT_22 0x02
#define FN_BIT_23 0x04
#define FN_BIT_24 0x08
#define FN_BIT_25 0x10
#define FN_BIT_26 0x20
#define FN_BIT_27 0x40
#define FN_BIT_28 0x80
//#define DCC_DBGVAR
#ifdef DCC_DBGVAR
typedef
struct
countOf_t
{
unsigned
long
Tel
;
unsigned
long
Err
;
}
countOf_t
;
countOf_t
countOf
;
extern
struct
countOf_t
countOf
;
#endif
class
NmraDcc
{
private:
DCC_MSG
Msg
;
public:
NmraDcc
();
// Flag values to be logically ORed together and passed into the init() method
#define FLAGS_MY_ADDRESS_ONLY 0x01
// Only process DCC Packets with My Address
#define FLAGS_AUTO_FACTORY_DEFAULT 0x02
// Call notifyCVResetFactoryDefault() if CV 7 & 8 == 255
#define FLAGS_MY_ADDRESS_ONLY 0x01
// Only process DCC Packets with My Address
#define FLAGS_AUTO_FACTORY_DEFAULT 0x02
// Call notifyCVResetFactoryDefault() if CV 7 & 8 == 255
#define FLAGS_SETCV_CALLED 0x10 // only used internally !!
#define FLAGS_OUTPUT_ADDRESS_MODE 0x40 // CV 29/541 bit 6
#define FLAGS_DCC_ACCESSORY_DECODER 0x80 // CV 29/541 bit 7
// Flag Bits that are cloned from CV29 relating the DCC Accessory Decoder
#define FLAGS_CV29_BITS (FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER)
#define DCC_RESET 1
#define DCC_IDLE 2
#define DCC_SPEED 3
#define DCC_SPEED_RAW 4
#define DCC_FUNC 5
#define DCC_TURNOUT 6
#define DCC_ACCESSORY 7
#define DCC_RAW 8
#define DCC_SERVICEMODE 9
#define CV_VALID 10
#define CV_READ 11
#define CV_WRITE 12
#define CV_RESET 13
void
dcc_setup
(
uint8_t
pin
,
uint8_t
ManufacturerId
,
uint8_t
VersionId
,
uint8_t
Flags
,
uint8_t
OpsModeAddressBaseCV
);
void
dcc_close
();
#define FLAGS_CV29_BITS (FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER)
/*+
* pin() is called from setup() and sets up the pin used to receive DCC packets.
*
* Inputs:
* ExtIntNum - Interrupt number of the pin. Use digitalPinToInterrupt(ExtIntPinNum).
* ExtIntPinNum - Input pin number.
* EnablePullup - Set true to enable the pins pullup resistor.
*
* Returns:
* None.
*/
void
pin
(
uint8_t
ExtIntNum
,
uint8_t
ExtIntPinNum
,
uint8_t
EnablePullup
);
/*+
* pin() is called from setup() and sets up the pin used to receive DCC packets.
* This relies on the internal function: digitalPinToInterrupt() to map the input pin number to the right interrupt
*
* Inputs:
* ExtIntPinNum - Input pin number.
* EnablePullup - Set true to enable the pins pullup resistor.
*
* Returns:
* None.
*/
#ifdef digitalPinToInterrupt
void
pin
(
uint8_t
ExtIntPinNum
,
uint8_t
EnablePullup
);
#endif
void
dcc_init
();
/*+
* init() is called from setup() after the pin() command is called.
* It initializes the NmDcc object and makes it ready to process packets.
*
* Inputs:
* ManufacturerId - Manufacturer ID returned in CV 8.
* Commonly MAN_ID_DIY.
* VersionId - Version ID returned in CV 7.
* Flags - ORed flags beginning with FLAGS_...
* FLAGS_MY_ADDRESS_ONLY - Only process packets with My Address.
* FLAGS_DCC_ACCESSORY_DECODER - Decoder is an accessory decoder.
* FLAGS_OUTPUT_ADDRESS_MODE - This flag applies to accessory decoders only.
* Accessory decoders normally have 4 paired outputs
* and a single address refers to all 4 outputs.
* Setting FLAGS_OUTPUT_ADDRESS_MODE causes each
* address to refer to a single output.
* OpsModeAddressBaseCV - Ops Mode base address. Set it to 0?
*
* Returns:
* None.
*/
void
init
(
uint8_t
ManufacturerId
,
uint8_t
VersionId
,
uint8_t
Flags
,
uint8_t
OpsModeAddressBaseCV
);
/*+
* initAccessoryDecoder() is called from setup() for accessory decoders.
* It calls init() with FLAGS_DCC_ACCESSORY_DECODER ORed into Flags.
*
* Inputs:
* ManufacturerId - Manufacturer ID returned in CV 8.
* Commonly MAN_ID_DIY.
* VersionId - Version ID returned in CV 7.
* Flags - ORed flags beginning with FLAGS_...
* FLAGS_DCC_ACCESSORY_DECODER will be set for init() call.
* OpsModeAddressBaseCV - Ops Mode base address. Set it to 0?
*
* Returns:
* None.
*/
void
initAccessoryDecoder
(
uint8_t
ManufacturerId
,
uint8_t
VersionId
,
uint8_t
Flags
,
uint8_t
OpsModeAddressBaseCV
);
/*+
* process() is called from loop() to process DCC packets.
* It must be called very frequently to keep up with the packets.
*
* Inputs:
* None.
*
* Returns:
* 1 - Packet succesfully parsed on this call to process().
* 0 - Packet not ready or received packet had an error.
*/
uint8_t
process
();
/*+
* getCV() returns the selected CV value.
*
* Inputs:
* CV - CV number. It must point to a valid CV.
*
* Returns:
* Value - CV value. Invalid CV numbers will return an undefined result
* since nothing will have been set in that EEPROM position.
* Calls notifyCVRead() if it is defined.
*/
uint8_t
getCV
(
uint16_t
CV
);
/*+
* setCV() sets the value of a CV.
*
* Inputs:
* CV - CV number. It must point to a valid CV.
* Value - CV value.
*
* Returns:
* Value - CV value set by this call.
* since nothing will have been set in that EEPROM position.
* Calls notifyCVWrite() if it is defined.
* Calls notifyCVChange() if the value is changed by this call.
*/
uint8_t
setCV
(
uint16_t
CV
,
uint8_t
Value
);
/*+
* setAccDecDCCAddrNextReceived() enables/disables the setting of the board address from the next received turnout command
*
* Inputs:
* enable- boolean to enable or disable the mode
*
* Returns:
*/
void
setAccDecDCCAddrNextReceived
(
uint8_t
enable
);
/*+
* isSetCVReady() returns 1 if EEPROM is ready to write.
*
* Inputs:
* CV - CV number. It must point to a valid CV.
* Value - CV value.
*
* Returns:
* ready - 1 if ready to write, 0 otherwise. AVR processor will block
* for several ms. for each write cycle so you should check this to avoid blocks.
* Note: It returns the value returned by notifyIsSetCVReady() if it is defined.
* Calls notifyIsSetCVReady() if it is defined.
*/
uint8_t
isSetCVReady
(
void
);
/*+
* getAddr() return the currently active decoder address.
* based on decoder type and current address size.
*
* Inputs:
* None.
*
* Returns:
* Adr - The current decoder address based on decoder type(Multifunction, Accessory)
* and short or long address selection for Multifunction decoders.
*/
uint16_t
getAddr
(
void
);
/*+
* getX() return debugging data if DCC_DEBUG is defined.
* You would really need to be modifying the library to need them.
*
* Inputs:
* None.
*
* Returns:
* getIntCount - Init to 0 and apparently never incremented?
* getTickCount - Init to 0 and incremented each time interrupt handler
* completes without an error.
* getBitCount - Bit count of valid packet, 0 otherwise. Only valid until
* start of the next packet.
* getState - Current WAIT_... state as defined by DccRxWaitState in NmraDcc.cpp.
* getNestedIrqCount - Init to 0 and incremented each time the interrupt handler
* is called before the previous interrupt was complete.
* This is an error indication and may indicate the system
* is not handling packets fast enough or some other error is occurring.
*/
// #define DCC_DEBUG
#ifdef DCC_DEBUG
uint8_t
getIntCount
(
void
);
uint8_t
getTickCount
(
void
);
uint8_t
getBitCount
(
void
);
uint8_t
getState
(
void
);
uint8_t
getNestedIrqCount
(
void
);
#endif
};
/************************************************************************************
Call-back functions
************************************************************************************/
#if defined (__cplusplus)
extern
"C"
{
#endif
/*+
* notifyDccReset(uint8_t hardReset) Callback for a DCC reset command.
*
...
...
@@ -445,6 +643,45 @@ extern uint8_t notifyCVRead( uint16_t CV) __attribute__ ((weak));
*/
extern
uint8_t
notifyCVWrite
(
uint16_t
CV
,
uint8_t
Value
)
__attribute__
((
weak
));
/*+
* notifyIsSetCVReady() Callback to to determine if CVs can be written.
* This is called when the library needs to determine
* is ready to write without blocking or failing.
* Note: If defined, this callback
* MUST determine if a CV write would block or fail
* return the appropriate value.
* If this callback is not defined,
* the library determines if a write to the EEPROM
* would block.
*
* Inputs:
* None
*
* Returns:
* 1 - CV is ready to be written.
* 0 - CV is not ready to be written.
*/
extern
uint8_t
notifyIsSetCVReady
(
void
)
__attribute__
((
weak
));
/*+
* notifyCVChange() Called when a CV value is changed.
* This is called whenever a CV's value is changed.
* notifyDccCVChange() Called only when a CV value is changed by a Dcc packet or a internal lib function.
* it is NOT called if the CV is changed by means of the setCV() method.
* Note: It is not called if notifyCVWrite() is defined
* or if the value in the EEPROM is the same as the value
* in the write command.
*
* Inputs:
* CV - CV number.
* Value - Value of the CV.
*
* Returns:
* None
*/
extern
void
notifyCVChange
(
uint16_t
CV
,
uint8_t
Value
)
__attribute__
((
weak
));
extern
void
notifyDccCVChange
(
uint16_t
CV
,
uint8_t
Value
)
__attribute__
((
weak
));
/*+
* notifyCVResetFactoryDefault() Called when CVs must be reset.
* This is called when CVs must be reset
...
...
@@ -462,6 +699,29 @@ extern uint8_t notifyCVWrite( uint16_t CV, uint8_t Value) __attribute__ ((weak))
*/
extern
void
notifyCVResetFactoryDefault
(
void
)
__attribute__
((
weak
));
/*+
* notifyCVAck() Called when a CV write must be acknowledged.
* This callback must increase the current drawn by this
* decoder by at least 60mA for 6ms +/- 1ms.
*
* Inputs:
* None
* *
* Returns:
* None
*/
extern
void
notifyCVAck
(
void
)
__attribute__
((
weak
));
/*+
* notifyAdvancedCVAck() Called when a CV write must be acknowledged via Advanced Acknowledgement.
* This callback must send the Advanced Acknowledgement via RailComm.
*
* Inputs:
* None
* *
* Returns:
* None
*/
extern
void
notifyAdvancedCVAck
(
void
)
__attribute__
((
weak
));
/*+
* notifyServiceMode(bool) Called when state of 'inServiceMode' changes
*
...
...
@@ -475,5 +735,11 @@ extern void notifyServiceMode(bool) __attribute__ ((weak));
// Deprecated, only for backward compatibility with version 1.4.2.
// Don't use in new designs. These functions may be dropped in future versions
// extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State ) __attribute__ ((weak));
// extern void notifyDccSigState( uint16_t Addr, uint8_t OutputIndex, uint8_t State) __attribute__ ((weak));
extern
void
notifyDccAccState
(
uint16_t
Addr
,
uint16_t
BoardAddr
,
uint8_t
OutputAddr
,
uint8_t
State
)
__attribute__
((
weak
));
extern
void
notifyDccSigState
(
uint16_t
Addr
,
uint8_t
OutputIndex
,
uint8_t
State
)
__attribute__
((
weak
));
#if defined (__cplusplus)
}
#endif
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment