Commanders
Arduino buttons/bus library
DccCommanderNMRA.cpp
1 /*************************************************************
2 project: <Commanders>
3 author: <Thierry PARIS>
4 description: <Dcc Commander>
5 *************************************************************/
6 
7 #include <Commanders.h>
8 
9 #ifdef NO_DCCCOMMANDERNMRA
10 #pragma message ("Commanders : No DCC NMRA commander !")
11 #else
12 
13 DccCommanderNMRAClass *DccCommanderNMRAClass::pDccCommander;
14 NmraDcc DccCommanderNMRAClass::Dcc;
15 
16 struct CVPair
17 {
18  uint16_t CV;
19  uint8_t Value;
20 };
21 
22 CVPair FactoryDefaultCVs[] =
23 {
24  {CV_ACCESSORY_DECODER_ADDRESS_LSB, 1},
25  {CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
26 };
27 
28 uint8_t FactoryDefaultCVIndex = 0;
29 
30 void notifyCVResetFactoryDefault()
31 {
32  // Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset
33  // to flag to the loop() function that a reset to Factory Defaults needs to be done
34  FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs) / sizeof(CVPair);
35 };
36 
38 //
39 // DCC accessory packet handler
40 //
41 void notifyDccAccTurnoutBoard(uint16_t inBoardAddr, uint8_t inOutputPair, uint8_t inDirection, uint8_t inOutputPower)
42 {
43  DccCommanderNMRAClass::CheckLastReception(inBoardAddr, inOutputPair, inDirection, inOutputPower);
44 }
45 
46 void DccCommanderNMRAClass::CheckLastReception(uint16_t inBoardAddr, uint8_t inOutputPair, uint8_t inDirection, uint8_t inOutputPower)
47 {
48  int realAddress = (inBoardAddr - (DccCommanderNMRA.GetRocoMode() ?0:1)) * 4 + inOutputPair + 1;
49 
50 #ifdef COMMANDERS_DEBUG_MODE
51 //#ifdef COMMANDERS_DEBUG_VERBOSE_MODE
52  Serial.print(F("Dcc packet found : real data : "));
53  Serial.print(inBoardAddr);
54  Serial.print(F(" / "));
55  Serial.print(inOutputPair);
56  Serial.print(F(" / "));
57  Serial.print(inDirection, DEC);
58  Serial.print(F(" / "));
59  Serial.print(inOutputPower, DEC);
60 
61  Serial.print(F(" converted : "));
62  Serial.print(realAddress);
63  Serial.print(F(" / "));
64  Serial.print(inDirection, DEC);
65  Serial.print(F(" / "));
66  Serial.println(inOutputPower, DEC);
67 //#endif
68 #endif
69 
70  // Sent packets are (on my MS2 !) :
71  // id / data / 1
72  // id / data / 1
73  // id / data / 1
74  // id / data / 0
75  // The last byte is to activate for a while (three times at 1 !) and then deactivate the motor !
76  // DccCommanderNMRA will react only on the deactivate flag to avoid double events.
77  if (inOutputPower == DccCommanderNMRA.raiseEventOnActivation)
78  {
79  if (DCCINT(realAddress, inDirection) == DccCommanderNMRA.lastDccId)
80  if (millis() - DccCommanderNMRA.lastEventDate < DccCommanderNMRA.raiseEventDebounceDelay)
81  {
82 #ifdef COMMANDERS_DEBUG_MODE
83  Serial.print(F("DccCommander packet IGNORED :"));
84  Serial.print(realAddress);
85  Serial.print(F(" / "));
86  Serial.println(inDirection, DEC);
87 #endif
88  return;
89  }
90 
91  DccCommanderNMRA.lastEventDate = millis();
92 
93 #ifdef COMMANDERS_DEBUG_MODE
94  Serial.print(F("DccCommander packet received :"));
95  Serial.print(realAddress);
96  Serial.print(F(" / "));
97  Serial.println(inDirection, DEC);
98 #endif
99 /* if (DccCommanderNMRAClass::func_AccPacket)
100  (DccCommanderNMRAClass::func_AccPacket)(realAddress, inOutputPower, inDirection);
101  else*/
102  {
103  Commanders::RaiseEvent(DCCINT(realAddress, inDirection), COMMANDERS_EVENT_MOVE, inDirection ? COMMANDERS_MOVE_LEFT : COMMANDERS_MOVE_RIGHT);
104 
105  DccCommanderNMRA.lastDccId = DCCINT(realAddress, inDirection);
106  }
107  }
108 }
109 
110 bool status = false;
111 void StatusBlink_handler()
112 {
113  digitalWrite2f(Commanders::StatusLedPin, status ? HIGH : LOW);
114  status = !status;
115 }
116 
117 void DccCommanderNMRAClass::beginByPin(int inManufacturerId, int inVersionId, int interruptPinNumber, boolean inInterruptMonitor, boolean inRocoMode)
118 {
119  Serial.println("Start beginByPin");
120  DccCommanderNMRAClass::Dcc.pin(interruptPinNumber, true);
121  Serial.println("pin ok");
122  DccCommanderNMRAClass::Dcc.initAccessoryDecoder(inManufacturerId, inVersionId, FLAGS_DCC_ACCESSORY_DECODER, 0);
123  Serial.println("init ok");
124 
125  this->rocoMode = inRocoMode;
126 #ifdef VISUALSTUDIO
127  // In VS, the interrupt address is also the pin number.
128  // pinMode() is just here to declare the pin used for the emulator...
129  pinMode(interruptPinNumber, OUTPUT_INTERRUPT);
130 #endif
131  this->lastDccId = UNDEFINED_ID;
132  this->lastEventDate = 0;
133  this->raiseEventOnActivation = false;
134  this->raiseEventDebounceDelay = 200;
135 
136  //if (inInterruptMonitor)
137  // DCC.SetInterruptMonitor(StatusBlink_handler);
138 
139 #ifdef COMMANDERS_PRINT_COMMANDERS
140  this->Interrupt = digitalPinToInterrupt(interruptPinNumber);
141 #endif
142  Serial.println("End beginByPin");
143 }
144 
145 void DccCommanderNMRAClass::RaiseEventWhen(boolean inRaiseEventOnActivation, int inRaiseEventDebounceDelay)
146 {
147  this->raiseEventOnActivation = inRaiseEventOnActivation;
148  this->raiseEventDebounceDelay = inRaiseEventDebounceDelay;
149 }
150 
152 {
154 }
155 
157 {
158  Dcc.process();
159 
160  if (FactoryDefaultCVIndex && Dcc.isSetCVReady())
161  {
162  FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array
163  Dcc.setCV(FactoryDefaultCVs[FactoryDefaultCVIndex].CV, FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
164  }
165 
166  if (this->lastDccId != UNDEFINED_ID)
167  {
168  unsigned long last = this->lastDccId;
169  this->lastDccId = UNDEFINED_ID;
172  return last;
173  }
174 
175  return UNDEFINED_ID;
176 }
177 
178 #ifdef COMMANDERS_DEBUG_MODE
179 void DccCommanderNMRAClass::printEvent(unsigned long inId, COMMANDERS_EVENT_TYPE inEventType, int inEventData)
180 {
181  Serial.print(F("DCC Commander event : Address : "));
182  Serial.print(DCCID(inId), DEC);
183  Serial.print(F(" / "));
184  Serial.print(DCCACTIVATION(inId), DEC);
185  Serial.print(F(" / "));
186  switch (inEventType)
187  {
188  case COMMANDERS_EVENT_NONE: Serial.println(F("NONE")); break;
189  case COMMANDERS_EVENT_TOGGLE: Serial.println(F("TOGGLE")); break;
190  case COMMANDERS_EVENT_MOVE:
191  Serial.print(F("MOVE "));
192  switch ((COMMANDERS_MOVE_TYPE)inEventData)
193  {
194  case COMMANDERS_MOVE_MORE: Serial.println(F("MORE")); break;
195  case COMMANDERS_MOVE_LESS: Serial.println(F("LESS")); break;
196  case COMMANDERS_MOVE_STOP: Serial.println(F("STOP")); break;
197  case COMMANDERS_MOVE_LEFT: Serial.println(F("LEFT")); break;
198  case COMMANDERS_MOVE_RIGHT: Serial.println(F("RIGHT")); break;
199  case COMMANDERS_MOVE_CENTER: Serial.println(F("CENTER")); break;
200  case COMMANDERS_MOVE_TOP: Serial.println(F("TOP")); break;
201  case COMMANDERS_MOVE_BOTTOM: Serial.println(F("BOTTOM")); break;
202  case COMMANDERS_MOVE_STRAIGHT: Serial.println(F("STRAIGHT")); break;
203  case COMMANDERS_MOVE_DIVERGE: Serial.println(F("DIVERGE")); break;
204  case COMMANDERS_MOVE_ON: Serial.println(F("ON")); break;
205  case COMMANDERS_MOVE_OFF: Serial.println(F("OFF")); break;
206  }
207  break;
209  Serial.print(F("MOVEPOSITION : "));
210  Serial.println(inEventData, DEC);
211  break;
213  Serial.println(F("MOVEPOSITIONID"));
214  break;
216  Serial.print(F("MOVEPOSITIONINDEX : "));
217  Serial.println(inEventData, DEC);
218  break;
220  Serial.print(F("CONFIG : "));
221  Serial.print(COMMANDERSCONFIGADDRESS(inEventData), DEC);
222  Serial.print(F(" / "));
223  Serial.println(COMMANDERSCONFIGVALUE(inEventData), DEC);
224  break;
225  }
226 }
227 #endif
228 
229 #ifdef COMMANDERS_PRINT_COMMANDERS
231 {
232  Serial.print(F("Commander: DccCommander - Interrupt: "));
233  Serial.println(this->Interrupt);
234 }
235 #endif
236 
237 #endif
COMMANDERS_MOVE_TYPE
Definition: Events.h:8
static void SetLastEventData(int inData)
Definition: Commanders.hpp:93
static void SetLastEventType(COMMANDERS_EVENT_TYPE inEvent)
Definition: Commanders.hpp:89
COMMANDERS_EVENT_TYPE
Definition: Events.h:25
void RaiseEventWhen(boolean inRaiseEventOnActivation, int inRaiseEventDebounceDelay = 200)
#define UNDEFINED_ID
Definition: Events.h:38
static void printEvent(unsigned long inId, COMMANDERS_EVENT_TYPE inEventType, int inEventData)
void beginByPin(int inManufacturerId, int inVersionId, int interruptNumber, boolean inInterruptMonitor = false, boolean inRocoMode = false)
static GPIO_pin_t StatusLedPin
Definition: Commanders.hpp:33
static unsigned long RaiseEvent(unsigned long inId, COMMANDERS_EVENT_TYPE inEvent = COMMANDERS_EVENT_MOVEPOSITIONID, int inData = 0)
Definition: Commanders.cpp:27
static void CheckLastReception(uint16_t inBoardAddr, uint8_t inOutputPair, uint8_t inDirection, uint8_t inOutputPower)