-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathDCC_Decoder.h
206 lines (154 loc) · 8.59 KB
/
DCC_Decoder.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
//
// DCC_Decoder.h - Arduino library for NMRA DCC Decoding.
// Written by Kevin Snow, MynaBay.com, November, 2011.
// Questions: dcc@mynabay.com
// Released into the public domain.
//
#ifndef __DCC_DECODER_H__
#define __DCC_DECODER_H__
#include "Arduino.h"
///////////////////////////////////////////////////////////////////////////////////////
#define kDCC_STOP_SPEED 0xFE
#define kDCC_ESTOP_SPEED 0xFF
// Multifunction Decoders
#define kCV_PrimaryAddress 1
#define kCV_Vstart 2
#define kCV_AccelerationRate 3
#define kCV_Deceleration Rate 4
#define kCV_ManufacturerVersionNo 7
#define kCV_ManufacturedID 8
#define kCV_ExtendedAddress1 17
#define kCV_ExtendedAddress2 18
#define kCV_ConfigurationData1 29
// Accessory Decoders
#define kCV_AddressLSB 1
#define kCV_AddressMSB 9
// DCC_Decoder results/errors
#define kDCC_OK 0
#define kDCC_OK_UNHANDLED 1
#define kDCC_OK_BOOT 2
#define kDCC_OK_IDLE 3
#define kDCC_OK_RESET 4
#define kDCC_OK_RAW 5
#define kDCC_OK_BASELINE 6
#define kDCC_OK_BASIC_ACCESSORY 7
#define kDCC_OK_EXTENDED_ACCESSORY 8
#define kDCC_OK_MAX 99
#define kDCC_ERR_DETECTION_FAILED 100
#define kDCC_ERR_BASELINE_ADDR 101
#define kDCC_ERR_BASELINE_INSTR 102 // Baseline packet instruction isn't 0x01DCSSSS
#define kDCC_ERR_MISSED_BITS 103
#define kDCC_ERR_NOT_0_OR_1 104
#define kDCC_ERR_INVALID_LENGTH 105
#define kDCC_ERR_MISSING_END_BIT 106
// Min and max valid packet lengths
#define kPACKET_LEN_MIN 3
#define kPACKET_LEN_MAX 6
// CV 1..256 are supported
#define kCV_MAX 257
///////////////////////////////////////////////////////////////////////////////////////
typedef boolean (*RawPacket)(byte byteCount, byte* packetBytes);
typedef void (*IdleResetPacket)(byte byteCount, byte* packetBytes);
typedef void (*BaselineControlPacket)(int address, int speed, int direction);
typedef void (*BasicAccDecoderPacket)(int address, boolean activate, byte data);
typedef void (*ExtendedAccDecoderPacket)(int address, byte data);
typedef void (*DecodingEngineCompletion)(byte resultOfLastPacket);
///////////////////////////////////////////////////////////////////////////////////////
typedef void(*StateFunc)();
///////////////////////////////////////////////////////////////////////////////////////
class DCC_Decoder
{
public:
DCC_Decoder();
// Called from setup in Arduino Sketch. Set mfgID, mfgVers and interrupt. Call one SetupXXX
void SetupDecoder(byte mfgID, byte mfgVers, byte interrupt); // Used for Decoder
void SetupMonitor(byte interrupt); // Used when building a monitor
// All packets are sent to RawPacketHandler. Return true to stop dispatching to other handlers.
void SetRawPacketHandler(RawPacket func);
// S 9.2 defines two special packets. Idle and reset.
void SetIdlePacketHandler(IdleResetPacket func);
void SetResetPacketHandler(IdleResetPacket func);
// Handler for S 9.2 baseline packets. Speed value will be 1-14, 1-28, kDCC_STOP_SPEED or kDCC_ESTOP_SPEED
void SetBaselineControlPacketHandler(BaselineControlPacket func, boolean allPackets);
// Handler for RP 9.2.1 Accessory Decoders.
void SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket func, boolean allPackets);
void SetExtendedAccessoryDecoderPacketHandler(ExtendedAccDecoderPacket func, boolean allPackets);
// Read/Write CVs
byte ReadCV(int cv);
void WriteCV(int cv, byte data);
// Helper function to read decoder address
int Address();
// Call at least once from mainloop. Not calling frequently enough and library will miss data bits!
void loop();
// Returns the packet data in string form.
char* MakePacketString(char* buffer60Bytes, byte packetByteCount, byte* packet);
// Returns the number of bits in last preamble
int LastPreambleBitCount();
// Timing functions. These return MS since various packets
unsigned long MillisecondsSinceLastValidPacket();
unsigned long MillisecondsSinceLastPacketToThisDecoder();
unsigned long MillisecondsSinceLastIdlePacket();
unsigned long MillisecondsSinceLastResetPacket();
//======================= Debugging =======================//
// Everytime the DCC Decoder engine starts looking for preamble bits this will be
// called with result of last packet. (Debugging)
void SetDecodingEngineCompletionStatusHandler(DecodingEngineCompletion func);
// Converts code passed into completionStatusHandler to human readable string.
const char PROGMEM* ResultString(byte resultCode);
//======================= Library Internals =======================//
private:
// State machine functions
static void State_Boot();
static void State_ReadPreamble();
static void State_ReadPacket();
static void State_Execute();
static void State_Reset();
// Function pointers for the library callbacks
static RawPacket func_RawPacket;
static IdleResetPacket func_IdlePacket;
static IdleResetPacket func_ResetPacket;
static BasicAccDecoderPacket func_BasicAccPacket;
static boolean func_BasicAccPacket_All_Packets;
static ExtendedAccDecoderPacket func_ExtdAccPacket;
static boolean func_ExtdAccPacket_All_Packets;
static BaselineControlPacket func_BaselineControlPacket;
static boolean func_BaselineControlPacket_All_Packets;
static DecodingEngineCompletion func_DecodingEngineCompletion;
// Current state function pointer
static StateFunc gState; // Current state function pointer
// Timing data from last interrupt
static unsigned int gLastChaos; // Interrupt chaos count we processed
// Preamble bit count
static int gPreambleCount; // Bit count for reading preamble
// Reset reason
static byte gResetReason; // Result code of last reason decoder was reset
static boolean gHandledAsRawPacket;
// Packet data
static byte gPacket[kPACKET_LEN_MAX]; // The packet data.
static byte gPacketIndex; // Byte index to write to.
static byte gPacketMask; // Bit index to write to. 0x80,0x40,0x20,...0x01
static boolean gPacketEndedWith1; // Set true if packet ended on 1. Spec requires that the
// packet end bit can count as a bit in next preamble.
// CV Storage
static byte gCV[kCV_MAX]; // CV Storage (TODO - Storage in PROGMEM)
// Packet arrival timing
static unsigned long gThisPacketMS; // Milliseconds of this packet being parsed
static boolean gLastPacketToThisAddress; // Was last pack processed to this decoder's address?
static unsigned long gLastValidPacketMS; // Milliseconds of last valid packet
static unsigned long gLastValidPacketToAddressMS; // Milliseconds of last valid packet to this decoder
static unsigned long gLastValidIdlePacketMS; // Milliseconds of last valid idle packet
static unsigned long gLastValidResetPacketMS; // Milliseconds of last valid reset packet
//////////////////////////////////////////////////////
// Interrupt Support
static void StartInterrupt(byte interrupt);
static void DCC_Interrupt();
static void ShiftInterruptAlignment();
static unsigned long gInterruptMicros;
static byte gInterruptTimeIndex;
static volatile unsigned int gInterruptTime[2];
static volatile unsigned int gInterruptChaos;
};
///////////////////////////////////////////////////////////////////////////////////////
extern DCC_Decoder DCC;
///////////////////////////////////////////////////////////////////////////////////////
#endif