Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
TivaNRZ.hxx
Go to the documentation of this file.
1
38#include "TivaDCC.hxx" // for FixedQueue
39
40/*
41struct DCCDecode
42{
43 static const auto TIMER_BASE = WTIMER4_BASE;
44 static const auto TIMER_PERIPH = SYSCTL_PERIPH_WTIMER4;
45 static const auto TIMER_INTERRUPT = INT_WTIMER4A;
46 static const auto TIMER = TIMER_A;
47 static const auto CFG_CAP_TIME_UP =
48 TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME_UP | TIMER_CFG_B_ONE_SHOT;
49 // Interrupt bits.
50 static const auto TIMER_CAP_EVENT = TIMER_CAPA_EVENT;
51 static const auto TIMER_TIM_TIMEOUT = TIMER_TIMA_TIMEOUT;
52
53 static const auto OS_INTERRUPT = INT_WTIMER4B;
54 DECL_PIN(NRZPIN, D, 4);
55 static const auto NRZPIN_CONFIG = GPIO_PD4_WT4CCP0;
56
57 static const uint32_t TIMER_MAX_VALUE = 0x8000000UL;
58
59 static const int Q_SIZE = 16;
60
61};
62*/
63
72template <class HW> class TivaNRZ : public Node
73{
74public:
77 TivaNRZ(const char *name);
78
79 ~TivaNRZ()
80 {
81 }
82
84 inline void interrupt_handler() __attribute__((always_inline));
85
87 inline void os_interrupt_handler() __attribute__((always_inline));
88
89private:
97 ssize_t read(File *file, void *buf, size_t count) OVERRIDE;
98
106 ssize_t write(File *file, const void *buf, size_t count) OVERRIDE
107 {
108 return -EINVAL;
109 }
110
116 int ioctl(File *file, unsigned long int key, unsigned long data) OVERRIDE;
117
118 void enable();
119 void disable();
124 {
125 while (!inputData_.empty())
126 {
128 }
129 };
130
136 uint32_t reloadCount_;
138 unsigned lastLevel_;
140 bool overflowed_ = false;
143
145};
146
147template <class HW>
148TivaNRZ<HW>::TivaNRZ(const char *name)
149 : Node(name)
150{
151 MAP_SysCtlPeripheralEnable(HW::TIMER_PERIPH);
152 MAP_SysCtlPeripheralEnable(HW::NRZPIN_PERIPH);
153 MAP_GPIOPinConfigure(HW::NRZPIN_CONFIG);
154 MAP_GPIOPinTypeTimer(HW::NRZPIN_BASE, HW::NRZPIN_PIN);
155
156 disable();
157}
158
159template <class HW> void TivaNRZ<HW>::enable()
160{
161 disable();
162 MAP_TimerClockSourceSet(HW::TIMER_BASE, TIMER_CLOCK_SYSTEM);
163 MAP_TimerConfigure(HW::TIMER_BASE, HW::CFG_CAP_TIME_UP);
164 MAP_TimerControlStall(HW::TIMER_BASE, HW::TIMER, true);
165 MAP_TimerControlEvent(HW::TIMER_BASE, HW::TIMER, TIMER_EVENT_BOTH_EDGES);
166 MAP_TimerLoadSet(HW::TIMER_BASE, HW::TIMER, HW::TIMER_MAX_VALUE);
167 MAP_TimerPrescaleSet(HW::TIMER_BASE, HW::TIMER, HW::PS_MAX);
168
169 reloadCount_ = 0;
170 lastTimerValue_ = 0;
171
172 MAP_TimerIntEnable(HW::TIMER_BASE, HW::TIMER_CAP_EVENT);
173 MAP_TimerIntEnable(HW::TIMER_BASE, HW::TIMER_TIM_TIMEOUT);
174
175 MAP_IntPrioritySet(HW::TIMER_INTERRUPT, 0);
176 MAP_IntPrioritySet(HW::OS_INTERRUPT, configKERNEL_INTERRUPT_PRIORITY);
177 MAP_IntEnable(HW::OS_INTERRUPT);
178 MAP_IntEnable(HW::TIMER_INTERRUPT);
179
180 MAP_TimerEnable(HW::TIMER_BASE, HW::TIMER);
181}
182
183template <class HW> void TivaNRZ<HW>::disable()
184{
185 MAP_IntDisable(HW::TIMER_INTERRUPT);
186 MAP_IntDisable(HW::OS_INTERRUPT);
187 MAP_TimerDisable(HW::TIMER_BASE, HW::TIMER);
188}
189
190template <class HW>
191__attribute__((optimize("-O3"))) void TivaNRZ<HW>::interrupt_handler()
192{
193 // get masked interrupt status
194 auto status = MAP_TimerIntStatus(HW::TIMER_BASE, true);
195 if (status & HW::TIMER_TIM_TIMEOUT)
196 {
197 // The timer got reloaded.
198 reloadCount_++;
199 MAP_TimerIntClear(HW::TIMER_BASE, HW::TIMER_TIM_TIMEOUT);
200 }
201 // TODO(balazs.racz): Technically it is possible that the timer reload
202 // happens between the event match and the interrupt entry. In this case we
203 // will incorrectly add a full cycle to the event length.
204 if (status & HW::TIMER_CAP_EVENT)
205 {
206 MAP_TimerIntClear(HW::TIMER_BASE, HW::TIMER_CAP_EVENT);
207 MAP_GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_0, 0);
208 static uint32_t raw_new_value;
209 raw_new_value = MAP_TimerValueGet(HW::TIMER_BASE, HW::TIMER);
210 static uint32_t new_value;
211 new_value = raw_new_value;
212 while (reloadCount_ > 0)
213 {
214 new_value += HW::TIMER_MAX_VALUE;
215 reloadCount_--;
216 }
217 //HASSERT(new_value > lastTimerValue_);
218 new_value -= lastTimerValue_;
219 if (!inputData_.full())
220 {
221 inputData_.back() = overflowed_ ? 3 : new_value;
222 overflowed_ = false;
223 inputData_.increment_back();
224 } else {
225 overflowed_ = true;
226 }
227 lastTimerValue_ = raw_new_value;
228 MAP_IntPendSet(HW::OS_INTERRUPT);
229 }
230}
231
232template <class HW>
233__attribute__((optimize("-O3"))) void TivaNRZ<HW>::os_interrupt_handler()
234{
235 if (!inputData_.empty())
236 {
237 Notifiable *n = readableNotifiable_;
238 readableNotifiable_ = nullptr;
239 if (n) {
240 n->notify_from_isr();
241 os_isr_exit_yield_test(true);
242 }
243 }
244}
245
246template <class HW>
247int TivaNRZ<HW>::ioctl(File *file, unsigned long int key, unsigned long data)
248{
249 if (IOC_TYPE(key) == CAN_IOC_MAGIC && IOC_SIZE(key) == NOTIFIABLE_TYPE &&
250 key == CAN_IOC_READ_ACTIVE)
251 {
252 Notifiable *n = reinterpret_cast<Notifiable *>(data);
253 HASSERT(n);
254 // If there is no data for reading, we put the incoming notification
255 // into the holder. Otherwise we notify it immediately.
256 if (inputData_.empty())
257 {
258 portENTER_CRITICAL();
259 if (inputData_.empty())
260 {
261 // We are in a critical section now. If we got into this
262 // branch, then the buffer was full at the beginning of the
263 // critical section. If the hardware interrupt kicks in now,
264 // and sets the os_interrupt to pending, the os interrupt will
265 // not happen until we leave the critical section, and thus the
266 // swap will be in effect by then.
267 std::swap(n, readableNotifiable_);
268 }
269 portEXIT_CRITICAL();
270 }
271 if (n)
272 {
273 n->notify();
274 }
275 return 0;
276 }
277 errno = EINVAL;
278 return -1;
279}
280
287template<class HW>
288ssize_t TivaNRZ<HW>::read(File *file, void *buf, size_t count)
289{
290 if (count != 4)
291 {
292 return -EINVAL;
293 }
294 // We only need this critical section to prevent concurrent threads from
295 // reading at the same time.
296 portENTER_CRITICAL();
297 if (inputData_.empty()) {
298 portEXIT_CRITICAL();
299 return -EAGAIN;
300 }
301 uint32_t v = reinterpret_cast<uint32_t>(buf);
302 HASSERT((v & 3) == 0); // alignment check.
303 uint32_t* pv = static_cast<uint32_t*>(buf);
304 *pv = inputData_.front();
305 inputData_.increment_front();
306 portEXIT_CRITICAL();
307 return count;
308}
const char * name
device name
Definition Devtab.hxx:266
This structure is safe to use from an interrupt context and a regular context at the same time,...
bool empty()
void increment_front()
Removes the head of the FIFO from the queue.
Node information.
Definition Devtab.hxx:549
An object that can schedule itself on an executor to run.
virtual void notify()=0
Generic callback.
Protocol-independent driver for decoding NRZ codes using a TI Tiva class microcontroller.
Definition TivaNRZ.hxx:73
FixedQueue< uint32_t, HW::Q_SIZE > inputData_
Data to send measurements back to the application level.
Definition TivaNRZ.hxx:132
bool overflowed_
Flags when we lost data due to buffer overrun.
Definition TivaNRZ.hxx:140
void disable()
function to disable device
Definition TivaNRZ.hxx:183
ssize_t read(File *file, void *buf, size_t count) OVERRIDE
Read from a file or device.
Definition TivaNRZ.hxx:288
unsigned lastLevel_
unused.
Definition TivaNRZ.hxx:138
void os_interrupt_handler()
Handles a software interrupt to FreeRTOS.
Definition TivaNRZ.hxx:233
void interrupt_handler()
Handles a raw interrupt.
Definition TivaNRZ.hxx:191
void flush_buffers()
Discards all pending buffers.
Definition TivaNRZ.hxx:123
uint32_t lastTimerValue_
Free running timer's last value.
Definition TivaNRZ.hxx:134
ssize_t write(File *file, const void *buf, size_t count) OVERRIDE
Write to a file or device.
Definition TivaNRZ.hxx:106
int ioctl(File *file, unsigned long int key, unsigned long data) OVERRIDE
Request an ioctl transaction.
Definition TivaNRZ.hxx:247
Notifiable * readableNotifiable_
Notifiable for asynchronous support.
Definition TivaNRZ.hxx:142
TivaNRZ(const char *name)
Constructor.
Definition TivaNRZ.hxx:148
void enable()
function to enable device
Definition TivaNRZ.hxx:159
uint32_t reloadCount_
How many times the free running timer overflowed.
Definition TivaNRZ.hxx:136
#define CAN_IOC_READ_ACTIVE
read active ioctl.
#define NOTIFIABLE_TYPE
ioctl minor type used for the read/write active notifiable integration.
#define CAN_IOC_MAGIC
Magic number for this driver's ioctl calls.
#define IOC_SIZE(_num)
Decode ioctl size.
#define IOC_TYPE(_num)
Decode ioctl type.
#define OVERRIDE
Function attribute for virtual functions declaring that this funciton is overriding a funciton that s...
Definition macros.h:180
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Removes default copy-constructor and assignment added by C++.
Definition macros.h:171
File information.
Definition Devtab.hxx:52