HDLC-Daemon
ProtocolState.cpp
Go to the documentation of this file.
1 
37 #include "ProtocolState.h"
38 #include <assert.h>
39 #include "FrameGenerator.h"
40 #include "ISerialPortHandler.h"
41 
42 ProtocolState::ProtocolState(std::shared_ptr<ISerialPortHandler> a_SerialPortHandler, boost::asio::io_service& a_IOService): m_SerialPortHandler(a_SerialPortHandler), m_FrameParser(*this), m_Timer(a_IOService) {
43  // Initialize alive state helper
44  m_AliveState = std::make_shared<AliveState>(a_IOService);
45  m_AliveState->SetSendProbeCallback([this]() {
46  m_bSendProbe = true;
47  if (m_SerialPortHandler) {
48  OpportunityForTransmission();
49  } else {
50  // Already closed or shutdown was called
51  } // else
52  });
53  m_AliveState->SetChangeBaudrateCallback([this]() {
54  if (m_SerialPortHandler) {
55  m_SerialPortHandler->ChangeBaudRate();
56  m_SerialPortHandler->PropagateSerialPortState();
57  } else {
58  // Already closed or shutdown was called
59  } // else
60  });
61 
62  Reset();
63 }
64 
65 void ProtocolState::Reset() {
66  m_AliveState->Stop();
67  m_Timer.cancel();
68  m_bStarted = false;
69  m_bAwaitsNextHDLCFrame = true;
70  m_SSeqOutgoing = 0;
71  m_RSeqIncoming = 0;
72  m_bSendProbe = false;
73  m_bPeerStoppedFlow = false;
74  m_bPeerStoppedFlowNew = false;
75  m_bPeerStoppedFlowQueried = false;
76  m_bPeerRequiresAck = false;
77  m_bWaitForAck = false;
78  m_SREJs.clear();
79  m_FrameParser.Reset();
80 }
81 
83  // Start the state machine
84  Reset();
85  m_bStarted = true;
86  m_AliveState->Start(); // trigger baud rate detection
87  OpportunityForTransmission();
88 }
89 
91  if (m_bStarted) {
92  // Stop the state machine
93  Reset();
94  m_SerialPortHandler->PropagateSerialPortState();
95  } // if
96 }
97 
99  if (m_bStarted) {
100  // Stop the state machine, but do not emit any subsequent events
101  Reset();
102  m_SerialPortHandler.reset();
103  } // if
104 }
105 
106 void ProtocolState::SendPayload(const std::vector<unsigned char> &a_Payload, bool a_bReliable) {
107  // Queue payload for later framing
108  if (a_bReliable) {
109  // TODO: assure that the size does not grow without limits!
110  m_WaitQueueReliable.emplace_back(std::move(a_Payload));
111  } else {
112  // TODO: assure that the size does not grow without limits!
113  m_WaitQueueUnreliable.emplace_back(std::move(a_Payload));
114  } // else
115 
116  bool l_bSendReliableFrames = m_bStarted;
117  l_bSendReliableFrames |= (m_bPeerStoppedFlow == false);
118  l_bSendReliableFrames |= (m_WaitQueueReliable.empty() == false);
119  bool l_bSendUnreliableFrames = m_bStarted;
120  l_bSendUnreliableFrames |= (m_WaitQueueUnreliable.empty() == false);
121  if ((m_bAwaitsNextHDLCFrame) && ((l_bSendReliableFrames) || (l_bSendUnreliableFrames))) {
122  OpportunityForTransmission();
123  } // if
124 }
125 
127  // Checks
128  if (!m_bStarted) {
129  return;
130  } // if
131 
132  // The SerialPortHandler is ready to transmit the next HDLC frame
133  m_bAwaitsNextHDLCFrame = true;
134  OpportunityForTransmission();
135 }
136 
137 void ProtocolState::AddReceivedRawBytes(const unsigned char* a_Buffer, size_t a_Bytes) {
138  // Checks
139  if (!m_bStarted) {
140  return;
141  } // if
142 
143  m_FrameParser.AddReceivedRawBytes(a_Buffer, a_Bytes);
144 }
145 
146 void ProtocolState::InterpretDeserializedFrame(const std::vector<unsigned char> &a_Payload, const HdlcFrame& a_HdlcFrame, bool a_bMessageInvalid) {
147  // Checks
148  if (!m_bStarted) {
149  return;
150  } // if
151 
152  // Deliver raw frame to clients that have interest
153  if (m_SerialPortHandler->RequiresBufferType(BUFFER_TYPE_RAW)) {
154  m_SerialPortHandler->DeliverBufferToClients(BUFFER_TYPE_RAW, a_Payload, false, a_bMessageInvalid, false); // not escaped
155  } // if
156 
157  if (m_SerialPortHandler->RequiresBufferType(BUFFER_TYPE_DISSECTED)) {
158  m_SerialPortHandler->DeliverBufferToClients(BUFFER_TYPE_DISSECTED, a_HdlcFrame.Dissect(), false, a_bMessageInvalid, false);
159  } // if
160 
161  // Stop here if the frame was considered broken
162  if (a_bMessageInvalid) {
163  return;
164  } // if
165 
166  // A valid frame was received
167  if (m_AliveState->OnFrameReceived()) {
168  m_SerialPortHandler->PropagateSerialPortState();
169  } // if
170 
171  // Go ahead interpreting the frame we received
172  if (a_HdlcFrame.HasPayload()) {
173  // I-Frame or U-Frame with UI
174  if (m_SerialPortHandler->RequiresBufferType(BUFFER_TYPE_PAYLOAD)) {
175  m_SerialPortHandler->DeliverBufferToClients(BUFFER_TYPE_PAYLOAD, a_HdlcFrame.GetPayload(), a_HdlcFrame.IsIFrame(), a_bMessageInvalid, false);
176  } // if
177 
178  // If it is an I-Frame, the data may have to be acked
179  if (a_HdlcFrame.IsIFrame()) {
180  if (m_RSeqIncoming != a_HdlcFrame.GetSSeq()) {
181  m_SREJs.clear();
182  for (unsigned char it = m_RSeqIncoming; (it & 0x07) != a_HdlcFrame.GetSSeq(); ++it) {
183  m_SREJs.emplace_back(it);
184  } // for
185  } // if
186 
187  m_RSeqIncoming = ((a_HdlcFrame.GetSSeq() + 1) & 0x07);
188  m_bPeerRequiresAck = true;
189  } // if
190  } // if
191 
192  // Check the various types of ACKs and NACKs
193  if ((a_HdlcFrame.IsIFrame()) || (a_HdlcFrame.IsSFrame())) {
194  if ((a_HdlcFrame.IsIFrame()) || (a_HdlcFrame.GetHDLCFrameType() == HdlcFrame::HDLC_FRAMETYPE_S_RR)) {
195  if ((m_bPeerStoppedFlow) && (a_HdlcFrame.GetHDLCFrameType() == HdlcFrame::HDLC_FRAMETYPE_S_RR)) {
196  // The peer restarted the flow: RR clears RNR condition
197  m_bPeerStoppedFlow = false;
198  m_bWaitForAck = false;
199  m_Timer.cancel();
200  } // if
201 
202  // Currently, we send only one I-frame at a time and wait until the respective ACK is received
203  if ((m_bWaitForAck) && (a_HdlcFrame.GetRSeq() == ((m_SSeqOutgoing + 1) & 0x07))) {
204  // We found the respective sequence number to the last transmitted I-frame
205  m_bWaitForAck = false;
206  m_Timer.cancel();
207  m_WaitQueueReliable.pop_front();
208  } // if
209 
210  m_SSeqOutgoing = a_HdlcFrame.GetRSeq();
211  } else if (a_HdlcFrame.GetHDLCFrameType() == HdlcFrame::HDLC_FRAMETYPE_S_RNR) {
212  // The peer wants us to stop sending subsequent data
213  if (!m_bPeerStoppedFlow) {
214  // Start periodical query
215  m_bPeerStoppedFlow = true;
216  m_bPeerStoppedFlowNew = true;
217  m_bPeerStoppedFlowQueried = false;
218  } // if
219 
220  if (m_bWaitForAck) {
221  m_bWaitForAck = false;
222  m_Timer.cancel();
223  if (a_HdlcFrame.GetRSeq() == ((m_SSeqOutgoing + 1) & 0x07)) {
224  // We found the respective sequence number to the last transmitted I-frame
225  m_WaitQueueReliable.pop_front();
226  } // if
227  } // if
228 
229  // Now we know which SeqNr the peer awaits next... after the RNR condition was cleared
230  m_SSeqOutgoing = a_HdlcFrame.GetRSeq();
231  } else if (a_HdlcFrame.GetHDLCFrameType() == HdlcFrame::HDLC_FRAMETYPE_S_REJ) {
232  if (m_bPeerStoppedFlow) {
233  // The peer restarted the flow: REJ clears RNR condition
234  m_bPeerStoppedFlow = false;
235  m_bWaitForAck = false;
236  m_Timer.cancel();
237  } // if
238 
239  // The peer requests for go-back-N. We have to retransmit all affected packets, but not with this version of HDLC.
240  if (a_HdlcFrame.GetRSeq() == m_SSeqOutgoing) {
241  // We found the respective sequence number to the last transmitted I-frame
242  m_bWaitForAck = false;
243  m_Timer.cancel();
244  } // if
245 
246  m_SSeqOutgoing = ((a_HdlcFrame.GetRSeq() + 0x07) & 0x07);
247  } else {
248  assert(a_HdlcFrame.GetHDLCFrameType() == HdlcFrame::HDLC_FRAMETYPE_S_SREJ);
249  if (m_bPeerStoppedFlow) {
250  // The peer restarted the flow: SREJ clears RNR condition
251  m_bPeerStoppedFlow = false;
252  m_bWaitForAck = false;
253  m_Timer.cancel();
254  } // if
255 
256  // The peer requests for the retransmission of a single segment with a specific sequence number
257  // This cannot be implemented using this reduced version of HDLC!
258  if ((m_bWaitForAck) && (a_HdlcFrame.GetRSeq() == m_SSeqOutgoing)) {
259  // We found the respective sequence number to the last transmitted I-frame.
260  // In this version of HDLC, this should not happen!
261  m_bWaitForAck = false;
262  m_Timer.cancel();
263  } // if
264  } // else
265  } // if
266 
267  if (m_bAwaitsNextHDLCFrame) {
268  // Check if we have to send something now
269  OpportunityForTransmission();
270  } // if
271 }
272 
273 void ProtocolState::OpportunityForTransmission() {
274  // Checks
275  if (!m_bAwaitsNextHDLCFrame) {
276  return;
277  } // if
278 
279  HdlcFrame l_HdlcFrame;
280  if (m_bSendProbe) {
281  // The correct baud rate setting is unknown yet, or it has to be checked again. Send an U-TEST frame.
282  m_bSendProbe = false;
283  l_HdlcFrame = PrepareUFrameTEST();
284  } // if
285 
286  if (l_HdlcFrame.IsEmpty() && m_AliveState->IsAlive()) {
287  // The serial link to the device is alive. Send all outstanding S-SREJs first.
288  if (m_SREJs.empty() == false) {
289  // Send SREJs first
290  l_HdlcFrame = PrepareSFrameSREJ();
291  } // if
292 
293  // Check if packets are waiting for reliable transmission
294  if (l_HdlcFrame.IsEmpty() && (m_WaitQueueReliable.empty() == false) && (!m_bWaitForAck) && (!m_bPeerStoppedFlow)) {
295  // Send an I-Frame now
296  l_HdlcFrame = PrepareIFrame();
297  m_bWaitForAck = true;
298 
299  // I-frames carry an ACK
300  m_bPeerRequiresAck = false;
301 
302  // Start retransmission timer
303  auto self(shared_from_this());
304  m_Timer.expires_from_now(boost::posix_time::milliseconds(500));
305  m_Timer.async_wait([this, self](const boost::system::error_code& ec) {
306  if (!ec) {
307  // Send the head element of the wait queue again
308  m_bWaitForAck = false;
309  OpportunityForTransmission();
310  } // if
311  });
312  } // if
313 
314  // Send outstanding RR?
315  if (l_HdlcFrame.IsEmpty() && ((m_bPeerRequiresAck) || m_bPeerStoppedFlowNew)) {
316  bool l_bStartTimer = false;
317  if (m_bPeerStoppedFlowNew) {
318  m_bPeerStoppedFlowNew = false;
319  l_bStartTimer = true;
320  } else {
321  // Prepare RR
322  l_HdlcFrame = PrepareSFrameRR();
323  m_bPeerRequiresAck = false;
324  if (m_bPeerStoppedFlow && !m_bPeerStoppedFlowQueried) {
325  // During the RNR confition at the peer, we query it periodically
326  l_HdlcFrame.SetPF(true); // This is a hack due to missing command/response support
327  m_bPeerStoppedFlowQueried = true;
328  l_bStartTimer = true;
329  } // if
330  } // else
331 
332  if (l_bStartTimer) {
333  m_Timer.cancel();
334  auto self(shared_from_this());
335  m_Timer.expires_from_now(boost::posix_time::milliseconds(500));
336  m_Timer.async_wait([this, self](const boost::system::error_code& ec) {
337  if (!ec) {
338  if (m_bPeerStoppedFlow) {
339  m_bPeerRequiresAck = true;
340  m_bPeerStoppedFlowQueried = false;
341  OpportunityForTransmission();
342  } // if
343  } // if
344  });
345  } // if
346  } // if
347 
348  // Check if packets are waiting for unreliable transmission
349  if (l_HdlcFrame.IsEmpty() && (m_WaitQueueUnreliable.empty() == false)) {
350  l_HdlcFrame = PrepareUFrameUI();
351  m_WaitQueueUnreliable.pop_front();
352  } // if
353 
354  // If there is nothing to send, try to fill the wait queues, but only if necessary.
355  if (l_HdlcFrame.IsEmpty()) {
356  // These expressions are the result of some boolean logic
357  bool l_bQueryReliable = (m_WaitQueueUnreliable.empty() && m_WaitQueueReliable.empty() && (!m_bPeerStoppedFlow));
358  bool l_bQueryUnreliable = (m_WaitQueueUnreliable.empty() && (m_WaitQueueReliable.empty() || m_bPeerStoppedFlow));
359  if (l_bQueryReliable || l_bQueryUnreliable) {
360  m_SerialPortHandler->QueryForPayload(l_bQueryReliable, l_bQueryUnreliable);
361  } // if
362  } // if
363  } // if
364 
365  if (l_HdlcFrame.IsEmpty() == false) {
366  // Deliver unescaped frame to clients that have interest
367  m_bAwaitsNextHDLCFrame = false;
368  auto l_HDLCFrameBuffer = FrameGenerator::SerializeFrame(l_HdlcFrame);
369  if (m_SerialPortHandler->RequiresBufferType(BUFFER_TYPE_RAW)) {
370  m_SerialPortHandler->DeliverBufferToClients(BUFFER_TYPE_RAW, l_HDLCFrameBuffer, l_HdlcFrame.IsIFrame(), false, true); // not escaped
371  } // if
372 
373  if (m_SerialPortHandler->RequiresBufferType(BUFFER_TYPE_DISSECTED)) {
374  m_SerialPortHandler->DeliverBufferToClients(BUFFER_TYPE_DISSECTED, l_HdlcFrame.Dissect(), l_HdlcFrame.IsIFrame(), false, true);
375  } // if
376 
377  m_SerialPortHandler->TransmitHDLCFrame(std::move(FrameGenerator::EscapeFrame(l_HDLCFrameBuffer)));
378  } // if
379 }
380 
381 HdlcFrame ProtocolState::PrepareIFrame() {
382  // Fresh Payload to be sent is available.
383  assert(m_WaitQueueReliable.empty() == false);
384  if (m_SerialPortHandler->RequiresBufferType(BUFFER_TYPE_PAYLOAD)) {
385  m_SerialPortHandler->DeliverBufferToClients(BUFFER_TYPE_PAYLOAD, m_WaitQueueReliable.front(), true, false, true);
386  } // if
387 
388  // Prepare I-Frame
389  HdlcFrame l_HdlcFrame;
390  l_HdlcFrame.SetAddress(0x30);
392  l_HdlcFrame.SetPF(false);
393  l_HdlcFrame.SetSSeq(m_SSeqOutgoing);
394  l_HdlcFrame.SetRSeq(m_RSeqIncoming);
395  l_HdlcFrame.SetPayload(m_WaitQueueReliable.front());
396  return(l_HdlcFrame);
397 }
398 
399 HdlcFrame ProtocolState::PrepareSFrameRR() {
400  HdlcFrame l_HdlcFrame;
401  l_HdlcFrame.SetAddress(0x30);
403  l_HdlcFrame.SetPF(false);
404  l_HdlcFrame.SetRSeq(m_RSeqIncoming);
405  return(l_HdlcFrame);
406 }
407 
408 HdlcFrame ProtocolState::PrepareSFrameSREJ() {
409  HdlcFrame l_HdlcFrame;
410  l_HdlcFrame.SetAddress(0x30);
412  l_HdlcFrame.SetPF(false);
413  l_HdlcFrame.SetRSeq(m_SREJs.front());
414  m_SREJs.pop_front();
415  return(l_HdlcFrame);
416 }
417 
418 HdlcFrame ProtocolState::PrepareUFrameUI() {
419  assert(m_WaitQueueUnreliable.empty() == false);
420  m_SerialPortHandler->DeliverBufferToClients(BUFFER_TYPE_PAYLOAD, m_WaitQueueUnreliable.front(), false, false, true);
421 
422  // Prepare UI-Frame
423  HdlcFrame l_HdlcFrame;
424  l_HdlcFrame.SetAddress(0x30);
426  l_HdlcFrame.SetPF(false);
427  l_HdlcFrame.SetPayload(m_WaitQueueUnreliable.front());
428  return(l_HdlcFrame);
429 }
430 
431 HdlcFrame ProtocolState::PrepareUFrameTEST() {
432  HdlcFrame l_HdlcFrame;
433  l_HdlcFrame.SetAddress(0x30);
435  l_HdlcFrame.SetPF(false);
436  return(l_HdlcFrame);
437 }
static std::vector< unsigned char > EscapeFrame(const std::vector< unsigned char > &a_HDLCFrame)
void SetRSeq(unsigned char a_RSeq)
Definition: HdlcFrame.h:79
static const std::vector< unsigned char > SerializeFrame(const HdlcFrame &a_HdlcFrame)
const std::vector< unsigned char > Dissect() const
Definition: HdlcFrame.cpp:41
bool HasPayload() const
Definition: HdlcFrame.h:87
void SetHDLCFrameType(E_HDLC_FRAMETYPE a_eHDLCFrameType)
Definition: HdlcFrame.h:69
void SetPayload(const std::vector< unsigned char > &a_Payload)
Definition: HdlcFrame.h:85
E_HDLC_FRAMETYPE GetHDLCFrameType() const
Definition: HdlcFrame.h:70
Copyright (c) 2016, Florian Evers, florian-evers@gmx.de All rights reserved.
bool IsEmpty() const
Definition: HdlcFrame.h:71
void TriggerNextHDLCFrame()
unsigned char GetSSeq() const
Definition: HdlcFrame.h:83
unsigned char GetRSeq() const
Definition: HdlcFrame.h:80
bool IsIFrame() const
Definition: HdlcFrame.h:72
void AddReceivedRawBytes(const unsigned char *a_Buffer, size_t a_Bytes)
Definition: FrameParser.cpp:53
void SetAddress(unsigned char a_Address)
Definition: HdlcFrame.h:47
bool IsSFrame() const
Definition: HdlcFrame.h:73
void InterpretDeserializedFrame(const std::vector< unsigned char > &a_Payload, const HdlcFrame &a_HdlcFrame, bool a_bMessageInvalid)
ProtocolState(std::shared_ptr< ISerialPortHandler > a_SerialPortHandler, boost::asio::io_service &a_IOService)
void Reset()
Definition: FrameParser.cpp:45
void SendPayload(const std::vector< unsigned char > &a_Payload, bool a_bReliable)
Copyright (c) 2016, Florian Evers, florian-evers@gmx.de All rights reserved.
void SetSSeq(unsigned char a_SSeq)
Definition: HdlcFrame.h:82
void SetPF(bool a_PF)
Definition: HdlcFrame.h:76
const std::vector< unsigned char > & GetPayload() const
Definition: HdlcFrame.h:86
void AddReceivedRawBytes(const unsigned char *a_Buffer, size_t a_Bytes)
Copyright (c) 2016, Florian Evers, florian-evers@gmx.de All rights reserved.