|
30 | 30 | #ifdef ARDUINO_ARCH_STM32 |
31 | 31 |
|
32 | 32 | #include "DCCTimer.h" |
33 | | -#ifdef DEBUG_ADC |
34 | 33 | #include "TrackManager.h" |
35 | | -#endif |
36 | 34 | #include "DIAG.h" |
37 | 35 | #include <wiring_private.h> |
38 | 36 |
|
@@ -215,68 +213,106 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) { |
215 | 213 | interrupts(); |
216 | 214 | } |
217 | 215 |
|
218 | | -// Static variables for Railcom timer shared between functions |
219 | | -static HardwareTimer *railcomTimer = nullptr; |
220 | | -static byte railcomBrakePin = 255; |
| 216 | +// Static variables for Railcom timers - separate for main and prog tracks |
| 217 | +static HardwareTimer *railcomMainTimer = nullptr; |
| 218 | +static HardwareTimer *railcomProgTimer = nullptr; |
221 | 219 |
|
222 | | -// Timer callback functions |
223 | | -void railcomEndCallback() { |
224 | | - if (railcomBrakePin != 255) { |
225 | | - digitalWrite(railcomBrakePin, LOW); |
| 220 | +// Timer callback functions for main track |
| 221 | +void railcomMainEndCallback() { |
| 222 | + TrackManager::setMainBrake(false, true); |
| 223 | + if (railcomMainTimer) { |
| 224 | + railcomMainTimer->pause(); |
| 225 | + railcomMainTimer->detachInterrupt(); |
226 | 226 | } |
227 | | - if (railcomTimer) { |
228 | | - railcomTimer->pause(); |
229 | | - railcomTimer->detachInterrupt(); |
| 227 | +} |
| 228 | + |
| 229 | +void railcomMainStartCallback() { |
| 230 | + TrackManager::setMainBrake(true, true); |
| 231 | + if (railcomMainTimer) { |
| 232 | + railcomMainTimer->pause(); |
| 233 | + railcomMainTimer->detachInterrupt(); |
| 234 | + // Start timer for cutout duration (430us) |
| 235 | + railcomMainTimer->setOverflow(430, MICROSEC_FORMAT); |
| 236 | + railcomMainTimer->attachInterrupt(railcomMainEndCallback); |
| 237 | + railcomMainTimer->refresh(); |
| 238 | + railcomMainTimer->resume(); |
230 | 239 | } |
231 | 240 | } |
232 | 241 |
|
233 | | -void railcomStartCallback() { |
234 | | - if (railcomBrakePin != 255) { |
235 | | - digitalWrite(railcomBrakePin, HIGH); |
| 242 | +// Timer callback functions for prog track |
| 243 | +void railcomProgEndCallback() { |
| 244 | + TrackManager::setProgBrake(false, true); |
| 245 | + if (railcomProgTimer) { |
| 246 | + railcomProgTimer->pause(); |
| 247 | + railcomProgTimer->detachInterrupt(); |
236 | 248 | } |
237 | | - if (railcomTimer) { |
238 | | - railcomTimer->pause(); |
239 | | - railcomTimer->detachInterrupt(); |
| 249 | +} |
| 250 | + |
| 251 | +void railcomProgStartCallback() { |
| 252 | + TrackManager::setProgBrake(true, true); |
| 253 | + if (railcomProgTimer) { |
| 254 | + railcomProgTimer->pause(); |
| 255 | + railcomProgTimer->detachInterrupt(); |
240 | 256 | // Start timer for cutout duration (430us) |
241 | | - railcomTimer->setOverflow(430, MICROSEC_FORMAT); |
242 | | - railcomTimer->attachInterrupt(railcomEndCallback); |
243 | | - railcomTimer->refresh(); |
244 | | - railcomTimer->resume(); |
| 257 | + railcomProgTimer->setOverflow(430, MICROSEC_FORMAT); |
| 258 | + railcomProgTimer->attachInterrupt(railcomProgEndCallback); |
| 259 | + railcomProgTimer->refresh(); |
| 260 | + railcomProgTimer->resume(); |
245 | 261 | } |
246 | 262 | } |
247 | 263 |
|
248 | | -void DCCTimer::startRailcomTimer(byte brakePin) { |
249 | | - const uint32_t cutoutOffset = 10; // 26-32 microseconds after last DCC tick minus overhead |
| 264 | +void DCCTimer::startRailcomTimer(bool isMain, bool lastBit) { |
| 265 | + uint32_t cutoutOffset; |
| 266 | + HardwareTimer *timer = nullptr; |
| 267 | + |
| 268 | + // We're just starting the last XOR bit, wait for the bit length, terminator bit, and initial cutout delay, minus some overhead |
| 269 | + if (lastBit) { |
| 270 | + // 1-bit |
| 271 | + cutoutOffset = 2 * 58 + 116 + 10; |
| 272 | + } else { |
| 273 | + // 0-bit |
| 274 | + cutoutOffset = 2 * 116 + 116 + 10; |
| 275 | + } |
250 | 276 |
|
251 | | - // Configure brakePin as output |
252 | | - pinMode(brakePin, OUTPUT); |
253 | | - digitalWrite(brakePin, LOW); |
| 277 | + if (isMain) { |
| 278 | + TrackManager::setMainBrake(false, true); |
254 | 279 |
|
255 | | - // Initialize timer if not already done |
256 | | - if (!railcomTimer) { |
257 | | - railcomTimer = new HardwareTimer(TIM3); |
258 | | - } |
| 280 | + // Initialize main timer if not already done |
| 281 | + if (!railcomMainTimer) { |
| 282 | + railcomMainTimer = new HardwareTimer(TIM3); |
| 283 | + } |
| 284 | + timer = railcomMainTimer; |
| 285 | + } else { |
| 286 | + TrackManager::setProgBrake(false, true); |
259 | 287 |
|
260 | | - // Store the brake pin for callbacks |
261 | | - railcomBrakePin = brakePin; |
| 288 | + // Initialize prog timer if not already done (use TIM4 for prog track) |
| 289 | + if (!railcomProgTimer) { |
| 290 | + railcomProgTimer = new HardwareTimer(TIM4); |
| 291 | + } |
| 292 | + timer = railcomProgTimer; |
| 293 | + } |
262 | 294 |
|
263 | 295 | // Start timer for offset |
264 | | - railcomTimer->pause(); |
265 | | - railcomTimer->setPrescaleFactor(1); |
266 | | - railcomTimer->setOverflow(cutoutOffset, MICROSEC_FORMAT); |
267 | | - railcomTimer->attachInterrupt(railcomStartCallback); |
268 | | - railcomTimer->refresh(); |
269 | | - railcomTimer->resume(); |
| 296 | + timer->pause(); |
| 297 | + timer->setPrescaleFactor(1); |
| 298 | + timer->setOverflow(cutoutOffset, MICROSEC_FORMAT); |
| 299 | + timer->attachInterrupt(isMain ? railcomMainStartCallback : railcomProgStartCallback); |
| 300 | + timer->refresh(); |
| 301 | + timer->resume(); |
270 | 302 | } |
271 | 303 |
|
272 | | -void DCCTimer::ackRailcomTimer() { |
273 | | - // Immediately end the Railcom cutout: set brake pin LOW and stop timer |
274 | | - if (railcomBrakePin != 255) { |
275 | | - digitalWrite(railcomBrakePin, LOW); |
| 304 | +void DCCTimer::ackRailcomTimer(bool isMain) { |
| 305 | + // Immediately end the Railcom cutout for whichever timer is active |
| 306 | + // Check both timers and stop any that are running |
| 307 | + if (isMain && railcomMainTimer) { |
| 308 | + railcomMainTimer->pause(); |
| 309 | + railcomMainTimer->detachInterrupt(); |
| 310 | + TrackManager::setMainBrake(false, true); |
276 | 311 | } |
277 | | - if (railcomTimer) { |
278 | | - railcomTimer->pause(); |
279 | | - railcomTimer->detachInterrupt(); |
| 312 | + if (!isMain && railcomProgTimer) { |
| 313 | + railcomProgTimer->pause(); |
| 314 | + railcomProgTimer->detachInterrupt(); |
| 315 | + TrackManager::setProgBrake(false, true); |
280 | 316 | } |
281 | 317 | } |
282 | 318 |
|
|
0 commit comments