HDLC-Daemon
SerialPortHandler.cpp
Go to the documentation of this file.
1 
22 #include "SerialPortHandler.h"
23 #include <boost/system/system_error.hpp>
24 #include "HdlcdServerHandler.h"
26 #include "ProtocolState.h"
27 #include <string.h>
28 
29 SerialPortHandler::SerialPortHandler(const std::string &a_SerialPortName, std::shared_ptr<SerialPortHandlerCollection> a_SerialPortHandlerCollection, boost::asio::io_service &a_IOService): m_SerialPort(a_IOService), m_IOService(a_IOService) {
30  m_Registered = true;
31  m_SerialPortName = a_SerialPortName;
32  m_SerialPortHandlerCollection = a_SerialPortHandlerCollection;
33  m_SendBufferOffset = 0;
34  ::memset(m_BufferTypeSubscribers, 0x00, sizeof(m_BufferTypeSubscribers));
35 }
36 
38  Stop();
39 }
40 
41 void SerialPortHandler::AddHdlcdServerHandler(std::shared_ptr<HdlcdServerHandler> a_HdlcdServerHandler) {
42  assert(a_HdlcdServerHandler->GetBufferType() < BUFFER_TYPE_ARITHMETIC_ENDMARKER);
43  ++(m_BufferTypeSubscribers[a_HdlcdServerHandler->GetBufferType()]);
44  m_HdlcdServerHandlerList.push_back(a_HdlcdServerHandler);
45  if ((m_ProtocolState) && (m_ProtocolState->IsRunning())) {
46  // Trigger state update messages, to inform the freshly added client
48  } // if
49 }
50 
52  if (m_Registered == false) {
53  return;
54  } // if
55 
56  if (m_SerialPortLock.SuspendSerialPort()) {
57  // The serial port is now suspended!
58  m_ProtocolState->Stop();
59  m_SerialPort.cancel();
60  m_SerialPort.close();
61  } // if
62 
64 }
65 
67  if (m_Registered == false) {
68  return;
69  } // if
70 
71  if (m_SerialPortLock.ResumeSerialPort()) {
72  // The serial port is now resumed. Restart activity.
73  OpenSerialPort();
74  } else {
76  } // else
77 }
78 
80  ForEachHdlcdServerHandler([this](std::shared_ptr<HdlcdServerHandler> a_HdlcdServerHandler) {
81  a_HdlcdServerHandler->UpdateSerialPortState(m_ProtocolState->IsAlive(), m_SerialPortLock.GetLockHolders());
82  });
83 }
84 
85 void SerialPortHandler::DeliverPayloadToHDLC(const std::vector<unsigned char> &a_Payload, bool a_bReliable) {
86  m_ProtocolState->SendPayload(a_Payload, a_bReliable);
87 }
88 
89 bool SerialPortHandler::RequiresBufferType(E_BUFFER_TYPE a_eBufferType) const {
90  assert(a_eBufferType < BUFFER_TYPE_ARITHMETIC_ENDMARKER);
91  return (m_BufferTypeSubscribers[a_eBufferType] != 0);
92 }
93 
94 void SerialPortHandler::DeliverBufferToClients(E_BUFFER_TYPE a_eBufferType, const std::vector<unsigned char> &a_Payload, bool a_bReliable, bool a_bInvalid, bool a_bWasSent) {
95  ForEachHdlcdServerHandler([a_eBufferType, &a_Payload, a_bReliable, a_bInvalid, a_bWasSent](std::shared_ptr<HdlcdServerHandler> a_HdlcdServerHandler) {
96  a_HdlcdServerHandler->DeliverBufferToClient(a_eBufferType, a_Payload, a_bReliable, a_bInvalid, a_bWasSent);
97  });
98 }
99 
101  m_ProtocolState = std::make_shared<ProtocolState>(shared_from_this(), m_IOService);
102  return OpenSerialPort();
103 }
104 
106  if (m_Registered) {
107  m_Registered = false;
108 
109  // Keep a copy here to keep this object alive!
110  auto self(shared_from_this());
111  m_SerialPort.cancel();
112  m_SerialPort.close();
113  m_ProtocolState->Shutdown();
114  if (auto l_SerialPortHandlerCollection = m_SerialPortHandlerCollection.lock()) {
115  l_SerialPortHandlerCollection->DeregisterSerialPortHandler(self);
116  } // if
117 
118  ForEachHdlcdServerHandler([](std::shared_ptr<HdlcdServerHandler> a_HdlcdServerHandler) {
119  a_HdlcdServerHandler->Stop();
120  });
121  } // if
122 }
123 
124 bool SerialPortHandler::OpenSerialPort() {
125  bool l_bResult = true;
126  try {
127  // Open the serial port and start processing
128  m_SerialPort.open(m_SerialPortName);
129  m_SerialPort.set_option(boost::asio::serial_port::parity(boost::asio::serial_port::parity::none));
130  m_SerialPort.set_option(boost::asio::serial_port::character_size(boost::asio::serial_port::character_size(8)));
131  m_SerialPort.set_option(boost::asio::serial_port::stop_bits(boost::asio::serial_port::stop_bits::one));
132  m_SerialPort.set_option(boost::asio::serial_port::flow_control(boost::asio::serial_port::flow_control::none));
133  m_SerialPort.set_option(boost::asio::serial_port::baud_rate(m_BaudRate.GetBaudRate()));
134 
135  // Start processing
136  m_ProtocolState->Start();
137  DoRead();
138 
139  // Trigger first state update message
141  } catch (boost::system::system_error& error) {
142  std::cerr << error.what() << std::endl;
143  l_bResult = false;
144  m_Registered = false;
145 
146  // TODO: ugly, code duplication. We must assure that cancel is not called!
147  auto self(shared_from_this());
148  m_ProtocolState->Shutdown();
149  if (auto l_SerialPortHandlerCollection = m_SerialPortHandlerCollection.lock()) {
150  l_SerialPortHandlerCollection->DeregisterSerialPortHandler(self);
151  } // if
152 
153  ForEachHdlcdServerHandler([](std::shared_ptr<HdlcdServerHandler> a_HdlcdServerHandler) {
154  a_HdlcdServerHandler->Stop();
155  });
156  } // catch
157 
158  return l_bResult;
159 }
160 
161 void SerialPortHandler::ChangeBaudRate() {
162  if (m_Registered) {
163  m_BaudRate.ToggleBaudRate();
164  m_SerialPort.set_option(boost::asio::serial_port::baud_rate(m_BaudRate.GetBaudRate()));
165  } // if
166 }
167 
168 void SerialPortHandler::TransmitHDLCFrame(const std::vector<unsigned char> &a_Payload) {
169  // Copy buffer holding the escaped HDLC frame for transmission via the serial interface
170  assert(m_SendBufferOffset == 0);
171  assert(m_SerialPortLock.GetSerialPortState() == false);
172  m_SendBuffer = std::move(a_Payload);
173 
174  // Trigger transmission
175  DoWrite();
176 }
177 
178 void SerialPortHandler::QueryForPayload(bool a_bQueryReliable, bool a_bQueryUnreliable) {
179  ForEachHdlcdServerHandler([a_bQueryReliable, a_bQueryUnreliable](std::shared_ptr<HdlcdServerHandler> a_HdlcdServerHandler) {
180  a_HdlcdServerHandler->QueryForPayload(a_bQueryReliable, a_bQueryUnreliable);
181  });
182 }
183 
184 void SerialPortHandler::DoRead() {
185  auto self(shared_from_this());
186  m_SerialPort.async_read_some(boost::asio::buffer(m_ReadBuffer, max_length),[this, self](boost::system::error_code a_ErrorCode, std::size_t a_BytesRead) {
187  if (!a_ErrorCode) {
188  m_ProtocolState->AddReceivedRawBytes(m_ReadBuffer, a_BytesRead);
189  if (m_SerialPortLock.GetSerialPortState() == false) {
190  DoRead();
191  } // if
192  } else {
193  if (m_SerialPortLock.GetSerialPortState() == false) {
194  std::cerr << "SERIAL READ ERROR:" << a_ErrorCode << std::endl;
195  Stop();
196  } // if
197  }
198  });
199 }
200 
201 void SerialPortHandler::DoWrite() {
202  auto self(shared_from_this());
203  m_SerialPort.async_write_some(boost::asio::buffer(&m_SendBuffer[m_SendBufferOffset], (m_SendBuffer.size() - m_SendBufferOffset)),[this, self](boost::system::error_code a_ErrorCode, std::size_t a_BytesSent) {
204  if (!a_ErrorCode) {
205  m_SendBufferOffset += a_BytesSent;
206  if (m_SendBufferOffset == m_SendBuffer.size()) {
207  // Indicate that we are ready to transmit the next HDLC frame
208  m_SendBufferOffset = 0;
209  if (m_SerialPortLock.GetSerialPortState() == false) {
210  m_ProtocolState->TriggerNextHDLCFrame();
211  } // if
212  } else {
213  // Only a partial transmission. We are not done yet.
214  if (m_SerialPortLock.GetSerialPortState() == false) {
215  DoWrite();
216  } // if
217  } // else
218  } else {
219  if (m_SerialPortLock.GetSerialPortState() == false) {
220  std::cerr << "SERIAL WRITE ERROR:" << a_ErrorCode << std::endl;
221  Stop();
222  } // if
223  } // else
224  });
225 }
226 
227 void SerialPortHandler::ForEachHdlcdServerHandler(std::function<void(std::shared_ptr<HdlcdServerHandler>)> a_Function) {
228  assert(a_Function);
229  bool l_RebuildSubscriptions = false;
230  static bool s_bCyclicCallGuard = false;
231  for (auto cur = m_HdlcdServerHandlerList.begin(); cur != m_HdlcdServerHandlerList.end();) {
232  auto next = cur;
233  ++next;
234  if (auto l_ClientHandler = cur->lock()) {
235  // Be careful here, as there are cyclic calls back to this method resulting in an invalid "next" iterator!
236  bool l_bGuardLocked = false;
237  if (!s_bCyclicCallGuard) {
238  s_bCyclicCallGuard = true;
239  l_bGuardLocked = true;
240  } // if
241 
242  a_Function(l_ClientHandler);
243  if (l_bGuardLocked) {
244  s_bCyclicCallGuard = false;
245  } // if
246  } else {
247  // Outdated entry. Only remove it if this is not a cyclic call
248  if (!s_bCyclicCallGuard) {
249  m_HdlcdServerHandlerList.erase(cur);
250  l_RebuildSubscriptions = true;
251  } // if
252  } // else
253 
254  cur = next;
255  } // for
256 
257  if (l_RebuildSubscriptions) {
258  // Rebuild the subscription database
259  ::memset(m_BufferTypeSubscribers, 0x00, sizeof(m_BufferTypeSubscribers));
260  ForEachHdlcdServerHandler([this](std::shared_ptr<HdlcdServerHandler> a_HdlcdServerHandler) {
261  assert(a_HdlcdServerHandler->GetBufferType() < BUFFER_TYPE_ARITHMETIC_ENDMARKER);
262  ++(m_BufferTypeSubscribers[a_HdlcdServerHandler->GetBufferType()]);
263  });
264  } // if
265 }
The HDLC Deamon implements the HDLC protocol to easily talk to devices connected via serial communica...
size_t GetLockHolders() const
SerialPortHandler(const std::string &a_SerialPortName, std::shared_ptr< SerialPortHandlerCollection > a_SerialPortHandlerCollection, boost::asio::io_service &a_IOService)
void DeliverPayloadToHDLC(const std::vector< unsigned char > &a_Payload, bool a_bReliable)
void ToggleBaudRate()
Iterate to another baud rate setting.
Definition: BaudRate.h:58
unsigned int GetBaudRate() const
Deliver the currently used baud rate setting.
Definition: BaudRate.h:44
bool SuspendSerialPort()
bool GetSerialPortState() const
void AddHdlcdServerHandler(std::shared_ptr< HdlcdServerHandler > a_HdlcdServerHandler)
E_BUFFER_TYPE
Definition: BufferType.h:40
The HDLC Deamon implements the HDLC protocol to easily talk to devices connected via serial communica...
The HDLC Deamon implements the HDLC protocol to easily talk to devices connected via serial communica...
Copyright (c) 2016, Florian Evers, florian-evers@gmx.de All rights reserved.