Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
LogonFeedback.hxx
Go to the documentation of this file.
1
34#ifndef _DCC_LOGONFEEDBACK_HXX_
35#define _DCC_LOGONFEEDBACK_HXX_
36
37#include "dcc/RailcomHub.hxx"
38#include "utils/Crc.hxx"
39
40namespace dcc
41{
42
45{
46public:
64
68 virtual PacketType classify_packet(uintptr_t feedback_key) = 0;
69
76 uintptr_t feedback_key, bool error, uint64_t data) = 0;
77
84 uintptr_t feedback_key, bool error, uint64_t data) = 0;
85
91 virtual void process_decoder_id(
92 uintptr_t feedback_key, bool error, uint64_t data) = 0;
93};
94
97{
98public:
104 : cb_(cb)
105 , hub_(hub)
106 {
107 hub_->register_port(this);
108 }
109
111 {
112 hub_->unregister_port(this);
113 }
114
116 void send(Buffer<RailcomHubData> *b, unsigned priority) override
117 {
118 auto rb = get_buffer_deleter(b);
119 PacketType type = cb_->classify_packet(b->data()->feedbackKey);
120 if (type == PacketType::UNKNOWN)
121 {
122 return;
123 }
124 uint64_t data = parse_code(b->data());
125 bool any_error = data & ERROR_MASK;
126 auto key = b->data()->feedbackKey;
127 switch (type)
128 {
129 case PacketType::SELECT_SHORTINFO:
130 any_error |= has_crc_error(data);
131 any_error |= (((data >> 47) & 1) != 1);
133 key, any_error, data & PAYLOAD_MASK);
134 break;
135 case PacketType::LOGON_ASSIGN:
136 any_error |= has_crc_error(data);
137 any_error |=
138 (((data >> 44) & 0xf) != RMOB_LOGON_ASSIGN_FEEDBACK);
139 cb_->process_logon_assign(key, any_error, data & PAYLOAD_MASK);
140 break;
141 case PacketType::LOGON_ENABLE:
142 any_error |=
143 (((data >> 44) & 0xf) != RMOB_LOGON_ENABLE_FEEDBACK);
144 cb_->process_decoder_id(key, any_error, data & PAYLOAD_MASK);
145 break;
146 case PacketType::GET_DATA_START:
147 case PacketType::GET_DATA_CONT:
148 case PacketType::MISC_254:
149 case PacketType::UNKNOWN:
150 default:
151 break;
152 }
153 }
154
155#ifndef GTEST
156private:
157#endif
184
189 static void append_data(uint64_t &data, unsigned &shift, uint8_t next_byte)
190 {
191 uint8_t code = railcom_decode[next_byte];
192 if (code < 64)
193 {
194 data |= ((uint64_t)code) << shift;
195 if (data >> ERROR_SHIFT)
196 {
197 // Valid data beyond some error.
198 data |= ERROR_OUT_OF_ORDER;
199 }
200 data += LENGTH_OFFSET;
201 }
202 else if (code == RailcomDefs::ACK)
203 {
204 data |= ERROR_ACK;
205 }
206 else if (code == RailcomDefs::INV)
207 {
208 data |= ERROR_GARBAGE;
209 }
210 else
211 {
212 data |= ERROR_UNKNOWN;
213 }
214 shift -= 6;
215 }
216
227 static uint64_t parse_code(const Feedback *fb)
228 {
229 uint64_t data = 0;
230 unsigned shift = 48 - 6;
231 for (unsigned i = 0; i < 2; i++)
232 {
233 if (fb->ch1Size > i)
234 {
235 append_data(data, shift, fb->ch1Data[i]);
236 }
237 else
238 {
239 data |= ERROR_MISSING_DATA;
240 }
241 }
242 for (unsigned i = 0; i < 6; i++)
243 {
244 if (fb->ch2Size > i)
245 {
246 append_data(data, shift, fb->ch2Data[i]);
247 }
248 else
249 {
250 data |= ERROR_MISSING_DATA;
251 }
252 }
253 return data;
254 }
255
259 static bool has_crc_error(uint64_t data)
260 {
262 for (int i = 48 - 8; i >= 0; i -= 8)
263 {
264 m.update16((data >> i) & 0xff);
265 }
266 return !m.check_ok();
267 }
268
269private:
274};
275
276} // namespace dcc
277
278#endif // _DCC_LOGONFEEDBACK_HXX_
BufferPtr< T > get_buffer_deleter(Buffer< T > *b)
Helper function to create a BufferPtr of an appropriate type without having to explicitly specify the...
Definition Buffer.hxx:272
const uint8_t railcom_decode[256]
Table for 8-to-6 decoding of railcom data.
Definition RailCom.cxx:47
Base class for all QMember types that hold data in an expandable format.
Definition Buffer.hxx:195
T * data()
get a pointer to the start of the data.
Definition Buffer.hxx:215
Helper class for computing CRC-8 according to Dallas/Maxim specification for 1-wire protocol.
Definition Crc.hxx:83
bool check_ok()
Checks that the message has a correct CRC.
Definition Crc.hxx:105
void update16(uint8_t message_byte)
Processes one byte of the incoming message.
Definition Crc.hxx:164
Abstract class for message recipients.
Templated implementation of the HubFlow.
Definition Hub.hxx:150
void register_port(port_type *port)
Adds a new port.
Definition Hub.hxx:167
void unregister_port(port_type *port)
Removes a previously added port.
Definition Hub.hxx:174
Abstract class to get callbacks for recognized feedback messages.
virtual void process_decoder_id(uintptr_t feedback_key, bool error, uint64_t data)=0
Handles a Decoder ID feedback message.
virtual PacketType classify_packet(uintptr_t feedback_key)=0
Determines based on feedback key what the given DCC packet was.
virtual void process_logon_assign(uintptr_t feedback_key, bool error, uint64_t data)=0
Handles a Logon Assign feedback message.
virtual void process_select_shortinfo(uintptr_t feedback_key, bool error, uint64_t data)=0
Handles a Select ShortInfo feedback message.
@ GET_DATA_CONT
Get Data Continue packet.
@ LOGON_ENABLE
Logon Enable packet.
@ MISC_254
Misc 254 packet (ID based responses)
@ GET_DATA_START
Get Data Start packet.
@ SELECT_SHORTINFO
Select packet with Get Short Info command.
@ LOGON_ASSIGN
Logon Assign packet.
@ UNKNOWN
Non-254 packet or not known (not relevant) 254 packet type.
Parser for RailCom feedback that recognizes logon messages.
LogonFeedbackCallbacks * cb_
Callbacks object.
static bool has_crc_error(uint64_t data)
Checks the CRC8 on a 6-byte payload in this feedback.
@ ERROR_UNKNOWN
Found unknown codepoint (e.g. NACK or BUSY).
@ LENGTH_OFFSET
Counts the number of valid 6-bit counts.
@ ERROR_OUT_OF_ORDER
Found valid data past an ACK byte or a missing byte.
@ ERROR_MASK
Mask where the error bits are.
@ ERROR_ACK
Found an ACK byte.
@ ERROR_SHIFT
Which bit offset do the error bits start.
@ LENGTH_SHIFT
Which bit offset do the error bits start.
@ PAYLOAD_MASK
Mask where the decoded payload is.
@ LENGTH_MASK
Which bit offset do the error bits start.
@ ERROR_MISSING_DATA
Not enough bytes in the feedback response.
@ ERROR_GARBAGE
Found invalid 6/8 code.
LogonFeedbackParser(LogonFeedbackCallbacks *cb, RailcomHubFlow *hub)
Constructor.
void send(Buffer< RailcomHubData > *b, unsigned priority) override
Receives railcom feedback.
RailcomHubFlow * hub_
The railcom hub we are registered to.
static uint64_t parse_code(const Feedback *fb)
Parses a concatenated ch1+ch2 response into a single uint64_t.
static void append_data(uint64_t &data, unsigned &shift, uint8_t next_byte)
Appends 6 bits of incoming data from railcom.
uint8_t ch2Size
Number of bytes in channel two.
Definition railcom.h:49
uint8_t ch1Size
Number of bytes in channel one.
Definition railcom.h:45
uint8_t ch1Data[2]
Payload of channel 1.
Definition railcom.h:47
uint8_t ch2Data[6]
Payload of channel 2.
Definition railcom.h:51
Structure used for reading (railcom) feedback data from DCC / Railcom device drivers.
Definition RailCom.hxx:50
@ ACK
Railcom ACK; the decoder received the message ok.
Definition RailCom.hxx:103
@ INV
invalid value (not conforming to the 4bit weighting requirement)
Definition RailCom.hxx:100