38
38
#include " dcc/PacketProcessor.hxx"
39
39
#include " dcc/packet.h"
40
40
41
+ struct DccDecoderDefs
42
+ {
43
+ // / Allowed values of DccDecoder::cutoutState_.
44
+ enum CutoutState : uint8_t
45
+ {
46
+ // / Next wakeup of the usec timer will be the beginning of the cutout
47
+ // / (nominally 26 usec after the last 1 bit), when the cutout FET
48
+ // / should be turned on.
49
+ CUTOUT_BEGIN,
50
+ // / Next wakeup of the cutout timer is the middle between the two
51
+ // / windows.
52
+ CUTOUT_MID,
53
+ // / Next wakeup of the cutout timer is the end of the cutout, when the
54
+ // / railcom fet should be switched off and the booster output be
55
+ // / reenabled.
56
+ CUTOUT_END,
57
+ // / Alias for the cutout end, but do not call the railcomDriver and do
58
+ // / not reset the module.
59
+ CUTOUT_END_AFTER_DRIVER
60
+ };
61
+ }; // struct DccDecoderDefs
62
+
41
63
/* *
42
64
Device driver for decoding a DCC signal using a Timer resource.
43
65
65
87
- SAMPLE_PERIOD_CLOCKS
66
88
- Q_SIZE
67
89
- TICKS_PER_USEC
90
+ - Output, which is a DccOutput compatible static object for creating
91
+ Railcom cutout.
68
92
- module_init()
69
93
- module_enable()
70
94
- module_disable()
84
108
template <class Module > class DccDecoder : public Node
85
109
{
86
110
public:
111
+ using Defs = DccDecoderDefs;
112
+
87
113
// / Constructor.
88
114
// /
89
115
// / @param name name of device node, e.g. "/dev/dccdecode0"
@@ -113,6 +139,16 @@ public:
113
139
/* * Handles a software interrupt to FreeRTOS. */
114
140
inline void os_interrupt_handler () __attribute__((always_inline));
115
141
142
+ // / How many usec the railcom has before the cutout (measured from the
143
+ // / packet end 1 bit complete)
144
+ static const auto RAILCOM_CUTOUT_PRE = 26 ;
145
+ // / How many usec the railcom has to the middle of window (measured from the
146
+ // / packet end 1 bit complete)
147
+ static const auto RAILCOM_CUTOUT_MID = 185 ;
148
+ // / How many usec the railcom has to the end of the window (measured from
149
+ // / the packet end 1 bit complete)
150
+ static const auto RAILCOM_CUTOUT_END = 471 ;
151
+
116
152
private:
117
153
/* * Read from a file or device.
118
154
* @param file file reference for this device
@@ -224,7 +260,7 @@ private:
224
260
// / colliding with cutout.
225
261
bool prepCutout_ = false ;
226
262
// / Which window of the cutout we are in.
227
- uint32_t cutoutState_;
263
+ Defs::CutoutState cutoutState_;
228
264
// / Counts unique identifiers for DCC packets to be returned.
229
265
uint32_t packetId_ = 0 ;
230
266
// / How many times did we lose a DCC packet due to no buffer available.
@@ -239,16 +275,6 @@ private:
239
275
// / DCC packet decoder state machine and internal state.
240
276
dcc::DccDecoder decoder_ {Module::get_ticks_per_usec ()};
241
277
242
- // / How many usec the railcom has before the cutout (measured from the
243
- // / packet end 1 bit complete)
244
- static const auto RAILCOM_CUTOUT_PRE = 26 ;
245
- // / How many usec the railcom has to the middle of window (measured from the
246
- // / packet end 1 bit complete)
247
- static const auto RAILCOM_CUTOUT_MID = 185 ;
248
- // / How many usec the railcom has to the end of the window (measured from
249
- // / the packet end 1 bit complete)
250
- static const auto RAILCOM_CUTOUT_END = 471 ;
251
-
252
278
DISALLOW_COPY_AND_ASSIGN (DccDecoder);
253
279
};
254
280
@@ -324,9 +350,24 @@ __attribute__((optimize("-O3"))) void DccDecoder<Module>::interrupt_handler()
324
350
debugLog_.add (new_value);
325
351
#endif
326
352
bool cutout_just_finished = false ;
353
+ Debug::DccDecodeInterrupts::set (false );
327
354
decoder_.process_data (new_value);
355
+ Debug::DccDecodeInterrupts::set (true );
356
+ if (decoder_.state () == dcc::DccDecoder::DCC_END_OF_PREAMBLE)
357
+ {
358
+ // Resets these state bits in case the state machines have
359
+ // diverged due to a bug.
360
+ inCutout_ = false ;
361
+ prepCutout_ = false ;
362
+ cutoutState_ = DccDecoderDefs::CUTOUT_BEGIN;
363
+ }
364
+ if (decoder_.state () == dcc::DccDecoder::DCC_MAYBE_CUTOUT)
365
+ {
366
+ Debug::DccInCutoutPin::set (true );
367
+ }
328
368
if (decoder_.before_dcc_cutout ())
329
369
{
370
+ Debug::RailComBeforeCutoutTiming::set (true );
330
371
prepCutout_ = true ;
331
372
auto * p = decoder_.pkt ();
332
373
if (p)
@@ -345,11 +386,12 @@ __attribute__((optimize("-O3"))) void DccDecoder<Module>::interrupt_handler()
345
386
true ) // Module::NRZ_Pin::get())
346
387
{
347
388
// Debug::RailcomDriverCutout::set(true);
389
+ Debug::RailComBeforeCutoutTiming::set (false );
348
390
Module::set_cap_timer_time ();
349
391
Module::set_cap_timer_delay_usec (
350
392
RAILCOM_CUTOUT_PRE + Module::time_delta_railcom_pre_usec ());
351
393
inCutout_ = true ;
352
- cutoutState_ = 0 ;
394
+ cutoutState_ = DccDecoderDefs::CUTOUT_BEGIN ;
353
395
if (decoder_.pkt ())
354
396
{
355
397
nextPacketFilled_ = true ;
@@ -361,21 +403,23 @@ __attribute__((optimize("-O3"))) void DccDecoder<Module>::interrupt_handler()
361
403
// railcomDriver_->start_cutout();
362
404
// inCutout_ = true;
363
405
}
364
- else if (decoder_.state () == dcc::DccDecoder::DCC_PACKET_FINISHED)
406
+ else if ((decoder_.state () == dcc::DccDecoder::DCC_PACKET_FINISHED &&
407
+ !inCutout_) ||
408
+ (decoder_.state () == dcc::DccDecoder::DCC_PREAMBLE && prepCutout_ &&
409
+ !inCutout_))
365
410
{
411
+ // The first partial bit after the cutout is done (for upstream
412
+ // cutout), or the preamble bit which came after the
413
+ // locally-generated cutout was finished.
366
414
Debug::DccPacketFinishedHook::set (true );
367
- if (inCutout_) {
368
- // railcomDriver_->end_cutout();
369
- inCutout_ = false ;
370
- }
371
415
Module::dcc_packet_finished_hook ();
372
416
prepCutout_ = false ;
373
417
cutout_just_finished = true ;
374
418
Debug::DccPacketFinishedHook::set (false );
375
419
}
376
420
lastTimerValue_ = raw_new_value;
377
- if (sampleActive_ && Module::NRZ_Pin::get () && !prepCutout_ &&
378
- ! cutout_just_finished)
421
+ if (sampleActive_ // && !inCutout_
422
+ && !prepCutout_ && ! cutout_just_finished && Module::NRZ_Pin::get () )
379
423
{
380
424
sampleActive_ = false ;
381
425
// The first positive edge after the sample timer expired (but
@@ -384,6 +428,8 @@ __attribute__((optimize("-O3"))) void DccDecoder<Module>::interrupt_handler()
384
428
Module::after_feedback_hook ();
385
429
}
386
430
}
431
+ Debug::DccInCutoutPin::set (inCutout_);
432
+ Debug::DccDecodeInterrupts::set (false );
387
433
}
388
434
389
435
template <class Module >
@@ -394,35 +440,67 @@ DccDecoder<Module>::rcom_interrupt_handler()
394
440
if (Module::int_get_and_clear_delay_event ())
395
441
{
396
442
// Debug::RailcomDriverCutout::set(false);
443
+ Module::rcom_cutout_hook (&cutoutState_);
397
444
switch (cutoutState_)
398
445
{
399
- case 0 :
446
+ case Defs::CUTOUT_BEGIN :
400
447
{
401
448
Module::set_cap_timer_delay_usec (
402
449
RAILCOM_CUTOUT_MID + Module::time_delta_railcom_mid_usec ());
450
+ if (Module::Output::need_railcom_cutout ())
451
+ {
452
+ Debug::RailcomTurnonPhase1::set (true );
453
+ unsigned delay_usec =
454
+ Module::Output::start_railcom_cutout_phase1 ();
455
+ Module::Output::isRailcomCutoutActive_ = 1 ;
456
+ microdelay (delay_usec);
457
+ Debug::RailcomTurnonPhase1::set (false );
458
+ delay_usec = Module::Output::start_railcom_cutout_phase2 ();
459
+ microdelay (delay_usec);
460
+ }
403
461
railcomDriver_->start_cutout ();
404
- cutoutState_ = 1 ;
462
+ cutoutState_ = Defs::CUTOUT_MID ;
405
463
break ;
406
464
}
407
- case 1 :
465
+ case Defs::CUTOUT_MID :
408
466
{
409
467
Module::set_cap_timer_delay_usec (
410
468
RAILCOM_CUTOUT_END + Module::time_delta_railcom_end_usec ());
411
469
railcomDriver_->middle_cutout ();
412
- cutoutState_ = 2 ;
470
+ cutoutState_ = Defs::CUTOUT_END ;
413
471
break ;
414
472
}
415
- default :
473
+ case Defs::CUTOUT_END :
416
474
{
417
475
Module::stop_cap_timer_time ();
418
476
Module::set_cap_timer_capture ();
419
477
railcomDriver_->end_cutout ();
478
+ } // fall through
479
+ case Defs::CUTOUT_END_AFTER_DRIVER:
480
+ {
481
+ if (Module::Output::isRailcomCutoutActive_)
482
+ {
483
+ Debug::RailcomTurnonPhase1::set (true );
484
+ unsigned delay_usec =
485
+ Module::Output::stop_railcom_cutout_phase1 ();
486
+ microdelay (delay_usec);
487
+ Debug::RailcomTurnonPhase1::set (false );
488
+ Module::Output::stop_railcom_cutout_phase2 ();
489
+ Module::Output::isRailcomCutoutActive_ = 0 ;
490
+ }
420
491
inCutout_ = false ;
492
+ if (Module::Output::should_be_enabled ())
493
+ {
494
+ Module::Output::enable_output ();
495
+ }
421
496
break ;
422
497
}
498
+ default :
499
+ break ;
423
500
}
424
501
}
425
502
Debug::DccDecodeInterrupts::set (false );
503
+ Debug::DccInCutoutPin::set (inCutout_);
426
504
}
427
505
428
506
template <class Module >
0 commit comments