|
Open Model Railroad Network (OpenMRN)
|
A device driver for sending DCC packets. More...
#include <TivaDCC.hxx>
Classes | |
| struct | Timing |
| Structure for supporting bit timing. More... | |
Public Member Functions | |
| TivaDCC (const char *name, RailcomDriver *railcom) | |
| Constructor. | |
| ~TivaDCC () | |
| Destructor. | |
| void | interrupt_handler () |
| Handle an interrupt. | |
| void | os_interrupt_handler () |
| Handles a software interrupt to FreeRTOS. | |
Public Member Functions inherited from Device | |
| Device (const char *name) | |
| Constructor. | |
| virtual | ~Device () |
| Destructor. | |
Static Public Member Functions | |
| static void | hw_preinit () |
| Initializes the DCC output hardware. | |
Static Public Member Functions inherited from Device | |
| static int | open (struct _reent *reent, const char *path, int flags, int mode) |
| Open a file or device. | |
| static int | close (struct _reent *reent, int fd) |
| Close a file or device. | |
| static int | stat (struct _reent *reent, const char *path, struct stat *stat) |
| Get the status information of a file or device. | |
| static int | select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, long long timeout) |
| POSIX select(). | |
| static void | select_clear () |
| Clears the current thread's select bits. | |
Static Public Member Functions inherited from FileIO | |
| static ssize_t | read (struct _reent *reent, int fd, void *buf, size_t count) |
| Read from a file or device. | |
| static ssize_t | write (struct _reent *reent, int fd, const void *buf, size_t count) |
| Write to a file or device. | |
| static _off_t | lseek (struct _reent *reent, int fd, _off_t offset, int whence) |
| Change the offset index of a file or device. | |
| static int | fstat (struct _reent *reent, int fd, struct stat *stat) |
| Get the status information of a file or device. | |
| static int | ioctl (int fd, unsigned long int key, unsigned long data) |
| Request and ioctl transaction. | |
| static int | fcntl (int fd, int cmd, unsigned long data) |
| Manipulate a file descriptor. | |
| static bool | is_device (int fd) |
| Test if the file descriptor belongs to a device. | |
Private Types | |
| enum | BitEnum { DCC_ZERO , DCC_ONE , DCC_EOP_ONE , DCC_RC_ONE , DCC_RC_HALF_ZERO , RAILCOM_CUTOUT_PRE , RAILCOM_CUTOUT_FIRST , RAILCOM_CUTOUT_SECOND , RAILCOM_CUTOUT_POST , MM_PREAMBLE , MM_ZERO , MM_ONE , NUM_TIMINGS } |
| Bit timings that we store and precalculate. More... | |
| enum | State { PREAMBLE , START , DATA_0 , DATA_1 , DATA_2 , DATA_3 , DATA_4 , DATA_5 , DATA_6 , DATA_7 , FRAME , ST_MM_PREAMBLE , MM_DATA_0 , MM_DATA_1 , MM_DATA_2 , MM_DATA_3 , MM_DATA_4 , MM_DATA_5 , MM_DATA_6 , MM_DATA_7 , RESYNC , DCC_MAYBE_RAILCOM , DCC_NO_CUTOUT , DCC_CUTOUT_PRE , DCC_START_RAILCOM_RECEIVE , DCC_MIDDLE_RAILCOM_CUTOUT , DCC_STOP_RAILCOM_RECEIVE , MM_LEADOUT , POWER_IMM_TURNON } |
| Internal state machine states. More... | |
Private Member Functions | |
| ssize_t | read (File *file, void *buf, size_t count) OVERRIDE |
| Read from a file or device. | |
| ssize_t | write (File *file, const void *buf, size_t count) OVERRIDE |
| Write to a file or device. | |
| int | ioctl (File *file, unsigned long int key, unsigned long data) OVERRIDE |
| Request an ioctl transaction. | |
| void | enable () OVERRIDE |
| function to enable device | |
| void | disable () OVERRIDE |
| function to disable device | |
| void | flush_buffers () override |
| Discards all pending buffers. | |
| void | fill_timing (BitEnum ofs, uint32_t period_usec, uint32_t transition_usec, uint32_t interval_period_usec, uint32_t timing_spread_usec=0) |
| Prepares a timing entry. | |
| void | check_and_enable_outputs () |
| Checks each output and enables those that need to be on. | |
| TivaDCC () | |
| Default constructor. | |
| DISALLOW_COPY_AND_ASSIGN (TivaDCC) | |
Private Attributes | |
| int | hDeadbandDelay_ |
| low->high deadband delay in clock count | |
| int | lDeadbandDelay_ |
| high->low deadband delay in clock count | |
| int | usecDelay_ |
| 1 usec of delay in clock count | |
| Timing | timings [NUM_TIMINGS] |
| Precalculated bit timings (translated to clock cycles). | |
| State | state_ |
| Current state of internal state machine. | |
| FixedQueue< dcc::Packet, HW::Q_SIZE > | packetQueue_ |
| Packets still waiting to be sent. | |
| Notifiable * | writableNotifiable_ |
| Notify this when we have free buffers. | |
| RailcomDriver * | railcomDriver_ |
| Will be notified for railcom cutout events. | |
| unsigned | seed_ = 0xb7a11bae |
| Seed for a pseudorandom sequence. | |
Static Private Attributes | |
| static const size_t | MAX_PKT_SIZE = 6 |
| maximum packet size we can support | |
| static dcc::Packet | IDLE_PKT = dcc::Packet::DCC_IDLE() |
| idle packet | |
| static constexpr unsigned | RAILCOM_CUTOUT_START_USEC = 26 |
| Standard timing value of when the railcom cutout should start, measured from the transition of the end-of-packet-one-bit. | |
| static constexpr unsigned | RAILCOM_CUTOUT_MID_USEC = 185 |
| Standard timing value of the railcom cutout middle, measured from the transition of the end-of-packet-one-bit. | |
| static constexpr unsigned | RAILCOM_CUTOUT_END_USEC = 486 |
| Standard timing value of the railcom cutout end, measured from the transition of the end-of-packet-one-bit. | |
| static constexpr unsigned | PMOD = 65213 |
| Parameters for a linear RNG: modulus. | |
| static constexpr unsigned | PMUL = 52253 |
| Parameters for a linear RNG: multiplier. | |
| static constexpr unsigned | PADD = 42767 |
| Parameters for a linear RNG: additive. | |
Additional Inherited Members | |
Protected Member Functions inherited from Node | |
| Node (const char *name) | |
| Constructor. | |
| virtual | ~Node () |
| Destructor. | |
| int | open (File *, const char *, int, int) OVERRIDE |
| Open method. | |
| int | close (File *) OVERRIDE |
| Close method. | |
| virtual int | fstat (File *file, struct stat *stat) override |
| Get the status information of a file or device. | |
Protected Member Functions inherited from FileIO | |
| FileIO (const char *name) | |
| Constructor. | |
| virtual | ~FileIO () |
| Destructor. | |
| virtual off_t | lseek (File *f, off_t offset, int whence) |
| Seek method. | |
| virtual int | fcntl (File *file, int cmd, unsigned long data) |
| Manipulate a file descriptor. | |
| virtual bool | select (File *file, int mode) |
| Device select method. | |
Static Protected Member Functions inherited from Device | |
| static void | select_insert (SelectInfo *info) |
| Add client to list of clients needing woken. | |
| static void | select_wakeup (SelectInfo *info) |
| Wakeup the list of clients needing woken. | |
| static void | select_wakeup_from_isr (SelectInfo *info, int *woken) |
| Wakeup the list of clients needing woken. | |
Static Protected Member Functions inherited from FileIO | |
| static int | fd_alloc (void) |
| Allocate a free file descriptor. | |
| static void | fd_free (int fd) |
| Free up a file descriptor. | |
| static File * | file_lookup (int fd) |
| Looks up a reference to a File corresponding to a given file descriptor. | |
| static int | fd_lookup (File *file) |
| Looks up a file descriptor corresponding to a given File reference. | |
Protected Attributes inherited from Node | |
| OSMutex | lock_ |
| protects internal structures. | |
| mode_t | mode_ |
| File open mode, such as O_NONBLOCK. | |
| unsigned int | references_ |
| number of open references | |
Protected Attributes inherited from FileIO | |
| const char * | name |
| device name | |
Static Protected Attributes inherited from FileIO | |
| static const unsigned int | numOpenFiles = 20 |
| static File | files [] |
| File descriptor pool. | |
| static OSMutex | mutex |
| mutual exclusion for fileio | |
A device driver for sending DCC packets.
If the packet queue is empty, then the device driver automatically sends out idle DCC packets. The device driver uses two instances of the 16/32-bit timer pairs. The user is responsible for providing interrupt entry point for the interval timer and calling the inline method interrupt_handler on behalf of this device driver.
Write calls work by sending the packet in the format of dcc::Packet. The payload should include the X-OR linkage byte. Only one DCC packet may be written per call to the write method. If there is no space currently available in the write queue, the write method will return -1 with errno set to ENOSPC.
Handling of write throttling:
The driver uses a second interrupt, used as a software interrupt at the FreeRTOS priority level, to communicate back information on when the device is writable. It is okay to use the interrupt for the second timer for this purpose. This interrupt will be enabled in the IOCTL after the writenotifiable is set, disabled in the interrupt itself when the writenotifiable is cleared. It is set pending at startup and when the dcc interrupt frees up a packet from the queue, and it is cleared pending when a write realizes there is no space for a buffer.
The user must ensure that the 'interrupt' has a very high priority, whereas 'os_interrupt' has a priority that's at or lower than the FreeRTOS kernel.
Handling of feedback data:
The driver may generate return data for the application layer in the form of dcc::Feedback messages. These will be attributed to the incoming packets by an opaque key that the application sets. For each packet that has a non-zero feedback a dcc::Feedback message will be sent to the application layer, which will be readable using the read method on the fd.
The application can request notification of readable and writable status using the regular IOCTL method.
EMC spectrum spreading
There is an optional feature that helps with passing EMC certification for systems that are built on this driver. The observation is that if the output signal has may repeats of a certain period, then in the measured spectrum there will be a big spike in energy that might exceed the thresholds for compliance. However, by slightly varying the timing of the output signal, the energy will be spread across a wider spectrum, thus the peak of emission will be smaller.
This feature is enabled by extern uint8_t spreadSpectrum;. This can come from a constant or configuration dependent variable. If enabled, then the timing of DCC zero bits are stretched to be a random value between 100.5 and 105 usec each half; the timing of DCC one bits will be stretched from 56.5 to 60 usec per half. The symmetry within each bit is still perfectly matched. Marklin-Motorola packets get up to 2 usec of stretching on each phase.
The actual stretching is generated using a uniform random number generator within said limits to ensure we spread uniformly across the available timings. Up to four bits are output with the same timing, then a new random timing is generated.
Definition at line 143 of file TivaDCC.hxx.
|
private |
Bit timings that we store and precalculate.
| Enumerator | |
|---|---|
| DCC_ZERO | Zero bit for DCC (this is the longer) |
| DCC_ONE | One bit for DCC (this is the shorter) |
| DCC_EOP_ONE | One bit for DCC that we generate at the end of packet transition. This has a stretched negative part so that the next packet resync avoids a glitch in the output. |
| DCC_RC_ONE | One bit for DCC that we generate during the railcom cutout. Can be used to play with alignment of edges coming out of the railcom cutout. |
| DCC_RC_HALF_ZERO | Half zero bit which is sent directly after the railcom cutout is over. Needed to reset certain old decoders packet recognizer. Recommended by https://nmra.org/sites/default/files/standards/sandrp/pdf/tn-2-05draft2005-02-25_for_rp-9.2.3.pdf |
| RAILCOM_CUTOUT_PRE | This is not a bit, but specifies when to wake up during the railcom cutout. The time is T_CS, usually 26 usec. |
| RAILCOM_CUTOUT_FIRST | This is not a bit, but specifies when to wake up during the railcom cutout. The time is the time elapsed between T_CS and the middle of the two windows. |
| RAILCOM_CUTOUT_SECOND | This is not a bit, but specifies when to wake up during the railcom cutout. The time is the time elapsed between the end of the cutout and the the middle of the two windows. |
| RAILCOM_CUTOUT_POST | This is not a bit, but specifies when to wake up during the railcom cutout. This is used for re-synchronizing the |
| MM_PREAMBLE | Long negative DC pulse to act as a preamble for a Marklin packet. |
| MM_ZERO | Zero bit for MM packet, which is a short pulse in one direction, then a long pulse in the other. |
| MM_ONE | One bit for MM packet, which is a long pulse in one direction, then a short pulse in the other. |
Definition at line 257 of file TivaDCC.hxx.
|
private |
Internal state machine states.
Definition at line 310 of file TivaDCC.hxx.
| TivaDCC< HW >::TivaDCC | ( | const char * | name, |
| RailcomDriver * | railcom | ||
| ) |
Constructor.
| name | name of this device instance in the file system |
| railcom | is the associated railcom driver, which will get the callbacks from the timing derived by the internal signal generator. |
Definition at line 965 of file TivaDCC.hxx.
Destructor.
Definition at line 155 of file TivaDCC.hxx.
|
inlineprivate |
Checks each output and enables those that need to be on.
Definition at line 389 of file TivaDCC.hxx.
|
inlineprivatevirtual |
|
inlineprivatevirtual |
|
private |
Prepares a timing entry.
| ofs | is the bit timing that we are defining. |
| period_usec | is the total length of the bit. |
| transition_usec | is the time of the transition inside the bit, counted from the beginning of the bit (i.e. the length of the HIGH part of the period). Can be zero for DC output LOW or can be == period_usec for DC output HIGH. |
| interval_period_usec | tells when the interval timer should expire (next interrupt). Most of the time this should be the same as period_usec. |
| timing_spread_usec | if non-zero, allows the high and low of the timing to be stretched by at most this many usec. |
Definition at line 933 of file TivaDCC.hxx.
|
inlineoverrideprivatevirtual |
Discards all pending buffers.
Called after disable().
Implements Node.
Definition at line 247 of file TivaDCC.hxx.
|
inlinestatic |
Initializes the DCC output hardware.
Definition at line 192 of file TivaDCC.hxx.
|
inline |
Handle an interrupt.
Definition at line 450 of file TivaDCC.hxx.
|
privatevirtual |
Request an ioctl transaction.
| file | file reference for this device |
| key | ioctl key |
| data | key data |
| file | file reference for this device |
| node | node reference for this device |
| key | ioctl key |
| data | key data |
Reimplemented from FileIO.
Definition at line 1174 of file TivaDCC.hxx.
|
inline |
Handles a software interrupt to FreeRTOS.
This should be called on the interrupt number that is submitted as os_interrupt to the constructor.
Definition at line 1209 of file TivaDCC.hxx.
|
privatevirtual |
Read from a file or device.
| file | file reference for this device |
| buf | location to place read data |
| count | number of bytes to read |
Implements FileIO.
Definition at line 1114 of file TivaDCC.hxx.
|
privatevirtual |
Write to a file or device.
| file | file reference for this device |
| buf | location to find write data |
| count | number of bytes to write |
Implements FileIO.
Definition at line 1127 of file TivaDCC.hxx.
|
private |
low->high deadband delay in clock count
Definition at line 302 of file TivaDCC.hxx.
|
staticprivate |
idle packet
Definition at line 254 of file TivaDCC.hxx.
|
private |
high->low deadband delay in clock count
Definition at line 303 of file TivaDCC.hxx.
|
staticprivate |
maximum packet size we can support
Definition at line 250 of file TivaDCC.hxx.
|
private |
Packets still waiting to be sent.
Definition at line 426 of file TivaDCC.hxx.
|
staticconstexprprivate |
Parameters for a linear RNG: additive.
Definition at line 437 of file TivaDCC.hxx.
|
staticconstexprprivate |
Parameters for a linear RNG: modulus.
Definition at line 433 of file TivaDCC.hxx.
|
staticconstexprprivate |
Parameters for a linear RNG: multiplier.
Definition at line 435 of file TivaDCC.hxx.
|
staticconstexprprivate |
Standard timing value of the railcom cutout end, measured from the transition of the end-of-packet-one-bit.
Minimum 454 (end of channel one), maximum 488. Can be adjusted by HW.
Definition at line 423 of file TivaDCC.hxx.
|
staticconstexprprivate |
Standard timing value of the railcom cutout middle, measured from the transition of the end-of-packet-one-bit.
Minimum 177 (end of channel one), maximum 193 (start channel 2) usec. Can be adjusted by HW.
Definition at line 419 of file TivaDCC.hxx.
|
staticconstexprprivate |
Standard timing value of when the railcom cutout should start, measured from the transition of the end-of-packet-one-bit.
Minimum 26, max 32 usec. Can be adjusted by HW.
Definition at line 415 of file TivaDCC.hxx.
|
private |
Will be notified for railcom cutout events.
Definition at line 428 of file TivaDCC.hxx.
|
private |
Seed for a pseudorandom sequence.
Definition at line 430 of file TivaDCC.hxx.
Current state of internal state machine.
Definition at line 368 of file TivaDCC.hxx.
Precalculated bit timings (translated to clock cycles).
Definition at line 307 of file TivaDCC.hxx.
|
private |
1 usec of delay in clock count
Definition at line 304 of file TivaDCC.hxx.
|
private |
Notify this when we have free buffers.
Definition at line 427 of file TivaDCC.hxx.