Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
TivaRailcom.hxx
Go to the documentation of this file.
1
57#ifndef _FREERTOS_DRIVERS_TI_TIVARAILCOM_HXX_
58#define _FREERTOS_DRIVERS_TI_TIVARAILCOM_HXX_
59
60#if (!defined(TIVADCC_TIVA)) && (!defined(TIVADCC_CC3200))
61#error must define either TIVADCC_TIVA or TIVADCC_CC3200
62#endif
63
64#include "freertos_drivers/common/RailcomImpl.hxx"
65#include "dcc/RailCom.hxx"
66
67/*
68struct RailcomHw
69{
70 static const uint32_t CHANNEL_COUNT = 4;
71 static const uint32_t UART_PERIPH[CHANNEL_COUNT];
72 static const uint32_t UART_BASE[CHANNEL_COUNT];
73 // Make sure there are enough entries here for all the channels times a few
74 // DCC packets.
75 static const uint32_t Q_SIZE = 16;
76
77 static const auto OS_INTERRUPT = INT_UART2;
78
79 GPIO_HWPIN(CH1, GpioHwPin, C, 4, U4RX);
80 GPIO_HWPIN(CH2, GpioHwPin, C, 6, U3RX);
81 GPIO_HWPIN(CH3, GpioHwPin, G, 4, U2RX);
82 GPIO_HWPIN(CH4, GpioHwPin, E, 0, U7RX);
83
84 static void hw_init() {
85 CH1_Pin::hw_init();
86 CH2_Pin::hw_init();
87 CH3_Pin::hw_init();
88 CH4_Pin::hw_init();
89 }
90
91 static void set_input() {
92 CH1_Pin::set_input();
93 CH2_Pin::set_input();
94 CH3_Pin::set_input();
95 CH4_Pin::set_input();
96 }
97
98 static void set_hw() {
99 CH1_Pin::set_hw();
100 CH2_Pin::set_hw();
101 CH3_Pin::set_hw();
102 CH4_Pin::set_hw();
103 }
104
107 static uint8_t sample() {
108 uint8_t ret = 0;
109 if (!CH1_Pin::get()) ret |= 1;
110 if (!CH2_Pin::get()) ret |= 2;
111 if (!CH3_Pin::get()) ret |= 4;
112 if (!CH4_Pin::get()) ret |= 8;
113 return ret;
114 }
115};
116
117// The weak attribute is needed if the definition is put into a header file.
118const uint32_t RailcomHw::UART_BASE[] __attribute__((weak)) = {UART4_BASE, UART3_BASE, UART2_BASE, UART7_BASE};
119const uint32_t RailcomHw::UART_PERIPH[]
120__attribute__((weak)) = {SYSCTL_PERIPH_UART4, SYSCTL_PERIPH_UART3, SYSCTL_PERIPH_UART2, SYSCTL_PERIPH_UART7};
121
122*/
123
129template <class HW> class TivaRailcomDriver : public RailcomDriverBase<HW>
130{
131public:
133 TivaRailcomDriver(const char *path)
134 : RailcomDriverBase<HW>(path)
135 {
136 MAP_IntPrioritySet(HW::OS_INTERRUPT, configKERNEL_INTERRUPT_PRIORITY);
137 MAP_IntEnable(HW::OS_INTERRUPT);
138 }
139
141 {
142 MAP_IntDisable(HW::OS_INTERRUPT);
143 }
144
145private:
147 bool inCutout_ = false;
148
150
153 void int_set_pending(unsigned int_nr) override
154 {
155 MAP_IntPendSet(int_nr);
156 }
157
158 // File node interface
160 {
161 for (unsigned i = 0; i < ARRAYSIZE(HW::UART_BASE); ++i)
162 {
163#ifdef TIVADCC_TIVA
164 MAP_SysCtlPeripheralEnable(HW::UART_PERIPH[i]);
165#elif defined(TIVADCC_CC3200)
166 MAP_PRCMPeripheralClkEnable(HW::UART_PERIPH[i], PRCM_RUN_MODE_CLK);
167#endif
168 MAP_UARTConfigSetExpClk(HW::UART_BASE[i], cm3_cpu_clock_hz, 250000,
169 UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
170 UART_CONFIG_PAR_NONE);
171 MAP_UARTFIFOEnable(HW::UART_BASE[i]);
172 // Disables the receiver.
173 HWREGBITW(HW::UART_BASE[i] + UART_O_CTL, UART_CTL_RXE) = 0;
174 MAP_UARTEnable(HW::UART_BASE[i]);
175 }
176 }
178 {
179 for (unsigned i = 0; i < ARRAYSIZE(HW::UART_BASE); ++i)
180 {
181 MAP_UARTDisable(HW::UART_BASE[i]);
182 }
183 }
184
185 // RailcomDriver interface
187 HW::enable_measurement(true);
188 this->add_sample(HW::sample());
189 HW::disable_measurement();
190 }
191
193 {
194 HW::enable_measurement(false);
195 const bool need_ch1_cutout = HW::need_ch1_cutout() || (this->feedbackKey_ < 11000);
196 Debug::RailcomRxActivate::set(true);
197 for (unsigned i = 0; i < ARRAYSIZE(HW::UART_BASE); ++i)
198 {
199 if (need_ch1_cutout)
200 {
201 HWREG(HW::UART_BASE[i] + UART_O_CTL) |= UART_CTL_RXE;
202 }
203 // HWREGBITW(HW::UART_BASE[i] + UART_O_CTL, UART_CTL_RXE) =
204 // UART_CTL_RXE;
205 // flush fifo
206 while (MAP_UARTCharGetNonBlocking(HW::UART_BASE[i]) >= 0)
207 ;
208 returnedPackets_[i] = 0;
209 }
210 Debug::RailcomDriverCutout::set(true);
211 }
212
214 {
215 Debug::RailcomDriverCutout::set(false);
216 for (unsigned i = 0; i < ARRAYSIZE(HW::UART_BASE); ++i)
217 {
218 while (MAP_UARTCharsAvail(HW::UART_BASE[i]))
219 {
220 Debug::RailcomDataReceived::toggle();
221 Debug::RailcomAnyData::set(true);
222 if (!returnedPackets_[i])
223 {
225 }
226 if (!returnedPackets_[i])
227 {
228 break;
229 }
230 long data = MAP_UARTCharGetNonBlocking(HW::UART_BASE[i]);
231 if (data < 0 || data > 0xff) {
232 // We reset the receiver circuitry because we got an error
233 // in channel 1. Typical cause of this error is if there
234 // are multiple locomotives on the block (e.g. if this is
235 // the global detector) and they talk over each other
236 // during ch1 broadcast. There is a good likelihood that
237 // the asynchronous receiver is out of sync with the
238 // transmitter, but right now we should be in the
239 // between-byte space.
240 HWREG(HW::UART_BASE[i] + UART_O_CTL) &= ~UART_CTL_RXE;
241 Debug::RailcomError::toggle();
242 returnedPackets_[i]->add_ch1_data(0xF8 | ((data >> 8) & 0x7));
243 continue;
244 }
246 }
247 HWREG(HW::UART_BASE[i] + UART_O_CTL) |= UART_CTL_RXE;
248 }
249 HW::middle_cutout_hook();
250 Debug::RailcomDriverCutout::set(true);
251 }
252
254 {
255 HW::disable_measurement();
256 bool have_packets = false;
257 for (unsigned i = 0; i < ARRAYSIZE(HW::UART_BASE); ++i)
258 {
259 while (MAP_UARTCharsAvail(HW::UART_BASE[i]))
260 {
261 Debug::RailcomDataReceived::toggle();
262 Debug::RailcomAnyData::set(true);
263 Debug::RailcomCh2Data::set(true);
264 if (!returnedPackets_[i])
265 {
267 }
268 if (!returnedPackets_[i])
269 {
270 break;
271 }
272 long data = MAP_UARTCharGetNonBlocking(HW::UART_BASE[i]);
273 if (data < 0 || data > 0xff) {
274 Debug::RailcomError::toggle();
275 returnedPackets_[i]->add_ch2_data(0xF8 | ((data >> 8) & 0x7));
276 continue;
277 }
278 if (data == 0xE0) {
279 Debug::RailcomE0::toggle();
280 }
282 }
283 HWREG(HW::UART_BASE[i] + UART_O_CTL) &= ~UART_CTL_RXE;
284 Debug::RailcomRxActivate::set(false);
285 //HWREGBITW(HW::UART_BASE[i] + UART_O_CTL, UART_CTL_RXE) = 0;
286 if (returnedPackets_[i]) {
287 have_packets = true;
289 Debug::RailcomPackets::toggle();
290 returnedPackets_[i] = nullptr;
291 MAP_IntPendSet(HW::OS_INTERRUPT);
292 }
293 }
294 if (!have_packets)
295 {
296 // Ensures that at least one feedback packet is sent back even when
297 // it is with no railcom payload.
298 auto *p = this->alloc_new_packet(0);
299 if (p)
300 {
302 Debug::RailcomPackets::toggle();
303 MAP_IntPendSet(HW::OS_INTERRUPT);
304 }
305 }
306 Debug::RailcomCh2Data::set(false);
307 Debug::RailcomDriverCutout::set(false);
308 }
309
311 {
312 for (unsigned i = 0; i < ARRAYSIZE(HW::UART_BASE); ++i)
313 {
314 if (!returnedPackets_[i])
315 {
317 }
318 if (returnedPackets_[i])
319 {
321 Debug::RailcomPackets::toggle();
322 returnedPackets_[i] = nullptr;
323 MAP_IntPendSet(HW::OS_INTERRUPT);
324 }
325 }
326 }
327};
328
329#endif // _FREERTOS_DRIVERS_TI_TIVARAILCOM_HXX_
void commit_back()
Commits the oldest entry reserved by noncommit_back.
Base class for railcom drivers.
Definition Railcom.hxx:133
dcc::Feedback * returnedPackets_[HW::CHANNEL_COUNT]
Stores pointers to packets we are filling right now, one for each channel.
Definition Railcom.hxx:285
uint32_t feedbackKey_
Stores the key for the next packets to read.
Definition Railcom.hxx:282
dcc::Feedback * alloc_new_packet(uint8_t channel)
Takes a new empty packet at the front of the queue, fills in feedback key and channel information.
Definition Railcom.hxx:245
void add_sample(int sample)
Adds a sample for a preamble bit.
Definition Railcom.hxx:261
FixedQueue< dcc::Feedback, HW::Q_SIZE > feedbackQueue_
The packets we have read so far.
Definition Railcom.hxx:280
Railcom driver for TI Tiva-class microcontrollers using the TivaWare peripheral library.
Definition Railcom.hxx:294
bool inCutout_
True when we are currently within a cutout.
Definition Railcom.hxx:303
TivaRailcomDriver(const char *path)
Constructor.
void int_set_pending(unsigned int_nr) override
Sets a given software interrupt pending.
void start_cutout() OVERRIDE
Instructs the driver that the railcom cutout is starting now.
void disable() OVERRIDE
This will be called when reference count goes from non-zero to 0.
void end_cutout() OVERRIDE
Instructs the driver that the railcom cutout is over now.
void no_cutout() OVERRIDE
Called instead of start/mid/end-cutout at the end of the current packet if there was no cutout reques...
void enable() OVERRIDE
This will be called once when reference-count goes from 0 to positive.
void middle_cutout() OVERRIDE
Notifies the driver that the railcom cutout has reached the middle point, i.e., the first window is p...
void feedback_sample() OVERRIDE
Call to the driver for sampling the current sensors.
#define OVERRIDE
Function attribute for virtual functions declaring that this funciton is overriding a funciton that s...
Definition macros.h:180
#define ARRAYSIZE(a)
Returns the number of elements in a statically defined array (of static size)
Definition macros.h:185
void add_ch1_data(uint8_t data)
Appends a byte to the channel 1 payload.
Definition RailCom.hxx:61
void add_ch2_data(uint8_t data)
Appends a byte to the channel 2 payload.
Definition RailCom.hxx:70