129 portENTER_CRITICAL();
142 if (file->flags & O_NONBLOCK)
146 inputData_->block_until_condition(file,
true);
171 portENTER_CRITICAL();
201#ifdef DCC_DECODER_DEBUG
208 bool nextPacketFilled_{
false};
255template <
class Module>
258 , railcomDriver_(railcom_driver)
260 Module::NRZ_Pin::hw_init();
261 Module::module_init();
269 Module::module_enable();
270 Module::set_cap_timer_capture();
272 lastTimerValue_ = Module::TIMER_MAX_VALUE;
273 nextSample_ = lastTimerValue_ - Module::SAMPLE_PERIOD_CLOCKS;
275 if (!decoder_.pkt() && inputData_->space())
278 inputData_->data_write_pointer(&next);
279 decoder_.set_packet(next);
285 Module::module_disable();
288template <
class Module>
289__attribute__((optimize(
"-O3"))) void
DccDecoder<Module>::interrupt_handler()
291 Debug::DccDecodeInterrupts::set(
true);
292 if (Module::int_get_and_clear_capture_event())
296 uint32_t raw_new_value = Module::get_capture_counter();
297 uint32_t old_value = lastTimerValue_;
298#ifdef DCC_DECODER_DEBUG
300 debugLog_.add(old_value);
301 debugLog_.add(raw_new_value);
303 if (raw_new_value > old_value) {
305 if (nextSample_ < old_value) {
306 nextSample_ += Module::TIMER_MAX_VALUE;
308 old_value += Module::TIMER_MAX_VALUE;
309 waitSampleForOverflow_ =
false;
310 Debug::CapTimerOverflow::set(
false);
312 if (raw_new_value < nextSample_ && !waitSampleForOverflow_) {
313 sampleActive_ =
true;
314 if (nextSample_ <= Module::SAMPLE_PERIOD_CLOCKS)
316 nextSample_ += Module::TIMER_MAX_VALUE;
317 waitSampleForOverflow_ =
true;
318 Debug::CapTimerOverflow::set(
true);
320 nextSample_ -= Module::SAMPLE_PERIOD_CLOCKS;
322 uint32_t new_value = old_value - raw_new_value;
323#ifdef DCC_DECODER_DEBUG
324 debugLog_.add(new_value);
326 bool cutout_just_finished =
false;
327 decoder_.process_data(new_value);
328 if (decoder_.before_dcc_cutout())
331 auto* p = decoder_.pkt();
334 p->feedback_key = ++packetId_;
336 railcomDriver_->set_feedback_key(packetId_);
337 Module::dcc_before_cutout_hook();
344 else if (decoder_.state() == dcc::DccDecoder::DCC_MAYBE_CUTOUT &&
348 Module::set_cap_timer_time();
349 Module::set_cap_timer_delay_usec(
350 RAILCOM_CUTOUT_PRE + Module::time_delta_railcom_pre_usec());
355 nextPacketFilled_ =
true;
357 Module::trigger_os_interrupt();
359 else if (decoder_.state() == dcc::DccDecoder::DCC_CUTOUT)
364 else if (decoder_.state() == dcc::DccDecoder::DCC_PACKET_FINISHED)
366 Debug::DccPacketFinishedHook::set(
true);
371 Module::dcc_packet_finished_hook();
373 cutout_just_finished =
true;
374 Debug::DccPacketFinishedHook::set(
false);
376 lastTimerValue_ = raw_new_value;
377 if (sampleActive_ && Module::NRZ_Pin::get() && !prepCutout_ &&
378 !cutout_just_finished)
380 sampleActive_ =
false;
383 railcomDriver_->feedback_sample();
384 Module::after_feedback_hook();
389template <
class Module>
390__attribute__((optimize(
"-O3"))) void
393 Debug::DccDecodeInterrupts::set(
true);
394 if (Module::int_get_and_clear_delay_event())
397 switch (cutoutState_)
401 Module::set_cap_timer_delay_usec(
402 RAILCOM_CUTOUT_MID + Module::time_delta_railcom_mid_usec());
403 railcomDriver_->start_cutout();
409 Module::set_cap_timer_delay_usec(
410 RAILCOM_CUTOUT_END + Module::time_delta_railcom_end_usec());
411 railcomDriver_->middle_cutout();
417 Module::stop_cap_timer_time();
418 Module::set_cap_timer_capture();
419 railcomDriver_->end_cutout();
425 Debug::DccDecodeInterrupts::set(
false);
428template <
class Module>
429__attribute__((optimize(
"-O3"))) void
DccDecoder<Module>::os_interrupt_handler()
432 if (nextPacketFilled_)
434 if (packetProcessor_)
436 packetProcessor_->packet_arrived(decoder_.pkt(), railcomDriver_);
438 inputData_->advance(1);
439 nextPacketFilled_ =
false;
440 inputData_->signal_condition_from_isr();
442 decoder_.set_packet(
nullptr);
444 if (!decoder_.pkt() && inputData_->space())
447 inputData_->data_write_pointer(&next);
448 decoder_.set_packet(next);
450 portYIELD_FROM_ISR(woken);
Device driver for decoding a DCC signal using a Timer resource.
bool prepCutout_
True for the last bit time before the cutout, to prevent sampling fro colliding with cutout.
RailcomDriver * railcomDriver_
How many times did we lose a DCC packet due to no buffer available.
DccDecoder(const char *name, RailcomDriver *railcom_driver)
Constructor.
static const auto RAILCOM_CUTOUT_END
How many usec the railcom has to the end of the window (measured from the packet end 1 bit complete)
bool select(File *file, int mode) OVERRIDE
Device select method.
bool waitSampleForOverflow_
if true then sampling will be suspended until the timer overflows.
dcc::PacketProcessor * packetProcessor_
notified for every arrived DCC / MM packet within the interrupt.
void os_interrupt_handler()
Handles a software interrupt to FreeRTOS.
ssize_t read(File *file, void *buf, size_t count) OVERRIDE
Read from a file or device.
uint32_t cutoutState_
Which window of the cutout we are in.
unsigned lastLevel_
Seems unused?
void set_packet_processor(dcc::PacketProcessor *p)
Installs a hook that will be called in the interrupt context for each incoming packet.
static const auto RAILCOM_CUTOUT_MID
How many usec the railcom has to the middle of window (measured from the packet end 1 bit complete)
uint32_t nextSample_
Holds the timer value when we should be taking an occupancy sample the next time.
static const auto RAILCOM_CUTOUT_PRE
How many usec the railcom has before the cutout (measured from the packet end 1 bit complete)
ssize_t write(File *file, const void *buf, size_t count) OVERRIDE
Write to a file or device.
void interrupt_handler()
Handles a raw interrupt.
void disable() override
function to disable device
bool sampleActive_
true if the next edge we shall sample.
bool inCutout_
True if the current internal state is the cutout state.
void enable() override
function to enable device
void flush_buffers() override
Discards all pending buffers.
uint32_t packetId_
Counts unique identifiers for DCC packets to be returned.
void rcom_interrupt_handler()
Handles interrupt from the second timer used for railcom timing.
uint32_t lastTimerValue_
Holds the value of the free running timer at the time we captured the previous edge.
dcc::DccDecoder decoder_
DCC packet decoder state machine and internal state.
void flush()
flush all the data out of the buffer and reset the buffer.
size_t space()
Return the number of items for which space is available.
size_t pending()
Return the number of items in the queue.
void select_insert()
Add client to list of clients needing woken.
Implements a smart buffer specifically designed for character device drivers.
size_t get(T *buf, size_t items)
remove a number of items from the buffer.
static constexpr unsigned member_size()
size_t data_write_pointer(T **buf)
Get a reference to the current location in the buffer for write.
void destroy()
Destroy an existing DeviceBuffer instance.
static DeviceBuffer * create(size_t size, size_t level=0)
Create a DeviceBuffer instance.
const char * name
device name
Alternative for hundreds of entries.
Abstract base class for railcom drivers.
State machine for decoding a DCC packet flow.
void set_packet(DCCPacket *pkt)
Sets where to write the decoded DCC data to.
DCCPacket * pkt()
Retrieves the last applied DCC packet pointer.
Abstract class that is used as a plugin in the DCC decoder.
#define FREAD
Workaround for missing header defines on some newlib versions.
#define OVERRIDE
Function attribute for virtual functions declaring that this funciton is overriding a funciton that s...
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Removes default copy-constructor and assignment added by C++.
Stores a DCC packet in memory.
Device * next
next device in linked list