CoLa2ProtocolHandler.cpp
Go to the documentation of this file.
1 //
2 // Copyright (c) 2023 SICK AG, Waldkirch
3 //
4 // SPDX-License-Identifier: Unlicense
5 
6 #include "CoLa2ProtocolHandler.h"
7 
8 #include <cassert>
9 #include <cstddef> // for size_t
10 
11 #include "VisionaryEndian.h"
12 
13 namespace {
14 constexpr std::uint8_t kStx = 0x02u;
15 }
16 
17 namespace visionary {
18 
20  : m_rtransport(rTransport), m_reqID(0), m_sessionID(0)
21 {
22 }
23 
25 
27 {
28  return ++m_reqID;
29 }
30 
31 // parse a protocol response
33 {
34  ByteBuffer buffer;
35  buffer.reserve(64u); // typical maximum response size
36 
37  // get response
38  // check for a run of 4 STX
39  constexpr std::size_t numExpectedStx = 4u;
40  std::size_t stxRecvLeft = numExpectedStx;
41 
42  while (stxRecvLeft > 0u)
43  {
44  ITransport::send_return_t nReceived = m_rtransport.recv(buffer, stxRecvLeft);
45 
46  if (nReceived <= 0)
47  {
48  // error or stream closed
49  // return an empty buffer as indicator
50  buffer.clear();
51  return buffer;
52  }
53 
54  // check if we have only STX in a row
55  // if another byte was encountered, reset all counters so that we are looking for a new run of 4 STX
56  ByteBuffer::iterator it{buffer.begin()};
57  while (it != buffer.end())
58  {
59  if (kStx == *it++)
60  {
61  --stxRecvLeft;
62  }
63  else
64  {
65  buffer.erase(buffer.begin(), it);
66  stxRecvLeft = numExpectedStx;
67  it = buffer.begin();
68  }
69  }
70  }
71  buffer.clear();
72 
73  // get length
74  if (static_cast<ITransport::recv_return_t>(sizeof(std::uint32_t)) != m_rtransport.read(buffer, sizeof(std::uint32_t)))
75  {
76  // error or stream closed
77  // return an empty buffer as indicator
78  buffer.clear();
79  return buffer;
80  }
81  const std::uint32_t length = readUnalignBigEndian<std::uint32_t>(buffer.data());
82 
83  buffer.clear();
84  if (static_cast<ITransport::recv_return_t>(length) != m_rtransport.read(buffer, length))
85  {
86  // error or stream closed
87  // return an empty buffer as indicator
88  buffer.clear();
89  return buffer;
90  }
91 
92  if (length < 2u)
93  {
94  // invalid length
95  // return an empty buffer as indicator
96  buffer.clear();
97  return buffer;
98  }
99 
100  // skip HubCtr und NoC
101  buffer.erase(buffer.begin(), buffer.begin() + 2u);
102 
103  return buffer;
104 }
105 
106 // parse a command response
107 CoLa2ProtocolHandler::ByteBuffer CoLa2ProtocolHandler::readResponse(std::uint32_t& rSessionId, std::uint16_t& rReqId)
108 {
109  ByteBuffer buffer{readProtocol()};
110 
111  // read 4 byte sessionId and 2 byte reqId
112  if (buffer.size() < 4u + 2u)
113  {
114  // buffer too short / malformed
115  buffer.clear();
116  return buffer;
117  }
118 
119  rSessionId = readUnalignBigEndian<std::uint32_t>(buffer.data());
120  rReqId = readUnalignBigEndian<std::uint16_t>(buffer.data() + 4u);
121 
122  buffer.erase(buffer.begin(), buffer.begin() + (4u + 2u));
123 
124  return buffer;
125 }
126 
127 // build a protocol header
129  std::size_t extraReserve)
130 {
132  header.reserve(4u + 4u + 1u + 1u + extraReserve);
133 
134  // insert magic bytes
135  header.insert(header.end(), {kStx, kStx, kStx, kStx});
136 
137  // insert length
138  {
139  const std::uint32_t v = static_cast<std::uint32_t>(payloadSize) + 1u + 1u; // HubCtr + NoC
140  std::uint8_t b[4u];
141  writeUnalignBigEndian<std::uint32_t>(b, sizeof(b), v);
142  header.insert(header.end(), b, b + 4u);
143  }
144 
145  // add HubCntr
146  header.push_back(0u); // client starts with 0 here
147 
148  // add NoC
149  header.push_back(0u); // client starts with 0 here
150 
151  return header;
152 }
153 
154 // build a message header
156  std::size_t extraReserve)
157 {
158  constexpr std::size_t cmdHeaderSize = 4u + 2u; // sessionID und ReqID;
160  createProtocolHeader(payloadSize + cmdHeaderSize, cmdHeaderSize + extraReserve)}; // sessionID und ReqID
161 
162  // add SessionID
163  {
164  std::uint8_t b[4];
165 
166  writeUnalignBigEndian(b, sizeof(b), static_cast<std::uint32_t>(m_sessionID));
167  header.insert(header.end(), b, b + 4u);
168  }
169 
170  // add ReqID
171  {
172  std::uint8_t b[2];
173 
174  writeUnalignBigEndian(b, sizeof(b), static_cast<std::uint16_t>(createReqId()));
175  header.insert(header.end(), b, b + 2u);
176  }
177 
178  return header;
179 }
180 
181 // send a command using the control session
183 {
184  const ByteBuffer& cmdBuffer{cmd.getBuffer()};
185  // create buffer with command header in place
186  constexpr std::size_t cmdOffset = 1u; // we skip the initial 's' from CoLaCommand buffer, not used in CoLa2
187  ByteBuffer buffer{createCommandHeader(cmdBuffer.size() - cmdOffset, cmdBuffer.size() - cmdOffset)};
188 
189  // add cmd
190  buffer.insert(buffer.end(), cmdBuffer.begin() + cmdOffset, cmdBuffer.end());
191 
192  // send to socket
193  if (m_rtransport.send(buffer) != static_cast<ITransport::send_return_t>(buffer.size()))
194  {
196  }
197 
198  buffer.clear();
199 
200  // get response
201  std::uint32_t sessionId;
202  std::uint16_t reqId;
203 
204  ByteBuffer response{readResponse(sessionId, reqId)};
205  if (0u == response.size())
206  {
208  }
209 
210  if ((sessionId != m_sessionID) || (reqId != m_reqID))
211  {
212  // communication stream out of sync
214  }
215 
216  // we re-insert the compatibility 's' # TODO: get rid of it
217  response.insert(response.begin(), 's');
218 
219  return CoLaCommand(response);
220 }
221 
222 // open a new control session
223 bool CoLa2ProtocolHandler::openSession(std::uint8_t sessionTimeout /*secs*/)
224 {
225  static const std::string clientid = "svs"; // Sick Visionary Shared - arbitrary client identifier
226  const std::size_t cmdSize = 2u + 1u + 2u + clientid.size(); // session ID, ReqId, Cmd+Mode, Timeout, clientId
227 
228  // create buffer with command header in place
229  ByteBuffer buffer{createCommandHeader(cmdSize, cmdSize)};
230 
231  // Add command
232  buffer.push_back(static_cast<std::uint8_t>('O')); // Open Session
233  buffer.push_back(static_cast<std::uint8_t>('x'));
234  buffer.push_back(sessionTimeout); // sessionTimeout secs timeout
235 
236  {
237  const std::uint16_t v = static_cast<std::uint16_t>(clientid.size());
238  std::uint8_t b[2u];
239  writeUnalignBigEndian<std::uint16_t>(b, sizeof(b), v);
240  buffer.insert(buffer.end(), b, b + 2u);
241 
242  for (auto c : clientid)
243  {
244  buffer.push_back(static_cast<std::uint8_t>(c));
245  }
246  }
247 
248  // send to socket
249  if (m_rtransport.send(buffer) != static_cast<ITransport::send_return_t>(buffer.size()))
250  {
251  return false;
252  }
253 
254  buffer.clear();
255 
256  // get response
257  std::uint32_t sessionId = 0u;
258  std::uint16_t reqId = 0u;
259 
260  ByteBuffer response{readResponse(sessionId, reqId)};
261 
262  if (reqId != m_reqID)
263  {
264  // communication stream out of sync
265  return false;
266  }
267 
268  m_sessionID = sessionId;
269 
270  return true;
271 }
272 
273 // close the control session
275 {
276  ByteBuffer cmd{'s', 'C', 'x'};
277 
279 }
280 
281 } // namespace visionary
response
const std::string response
VisionaryEndian.h
visionary::ITransport::read
virtual recv_return_t read(ByteBuffer &buffer, std::size_t nBytesToReceive)=0
visionary::CoLaCommand::networkErrorCommand
static CoLaCommand networkErrorCommand()
Create a command for network errors.
Definition: CoLaCommand.cpp:164
visionary::ITransport::recv_return_t
ssize_t recv_return_t
Definition: ITransport.h:29
visionary
Definition: MD5.cpp:44
visionary::CoLaCommand
Definition: CoLaCommand.h:17
visionary::CoLa2ProtocolHandler::createReqId
std::uint16_t createReqId()
Definition: CoLa2ProtocolHandler.cpp:26
visionary::CoLa2ProtocolHandler::readResponse
ByteBuffer readResponse(std::uint32_t &rSessionId, uint16_t &rReqId)
read a command response packet
Definition: CoLa2ProtocolHandler.cpp:107
visionary::CoLa2ProtocolHandler::send
CoLaCommand send(CoLaCommand cmd) override
Definition: CoLa2ProtocolHandler.cpp:182
visionary::CoLa2ProtocolHandler::m_reqID
std::uint16_t m_reqID
Definition: CoLa2ProtocolHandler.h:52
visionary::CoLa2ProtocolHandler::createProtocolHeader
ByteBuffer createProtocolHeader(std::size_t payloadSize, std::size_t extraReserve=0u)
Definition: CoLa2ProtocolHandler.cpp:128
CoLa2ProtocolHandler.h
visionary::CoLa2ProtocolHandler::m_sessionID
std::uint32_t m_sessionID
Definition: CoLa2ProtocolHandler.h:53
visionary::CoLa2ProtocolHandler::createCommandHeader
ByteBuffer createCommandHeader(std::size_t payloadSize, std::size_t extraReserve=0u)
Definition: CoLa2ProtocolHandler.cpp:155
visionary::CoLa2ProtocolHandler::~CoLa2ProtocolHandler
~CoLa2ProtocolHandler() override
visionary::ITransport::send_return_t
ssize_t send_return_t
Definition: ITransport.h:28
visionary::CoLa2ProtocolHandler::CoLa2ProtocolHandler
CoLa2ProtocolHandler(ITransport &rTransport)
Definition: CoLa2ProtocolHandler.cpp:19
visionary::ITransport::send
send_return_t send(const std::vector< T > &buffer)
Definition: ITransport.h:45
visionary::CoLa2ProtocolHandler::m_rtransport
ITransport & m_rtransport
Definition: CoLa2ProtocolHandler.h:51
length
TFSIMD_FORCE_INLINE tfScalar length(const Quaternion &q)
visionary::CoLa2ProtocolHandler::closeSession
void closeSession() override
Definition: CoLa2ProtocolHandler.cpp:274
visionary::ITransport::recv
virtual recv_return_t recv(ByteBuffer &buffer, std::size_t maxBytesToReceive)=0
visionary::ITransport
Definition: ITransport.h:19
cmd
string cmd
header
const std::string header
visionary::CoLa2ProtocolHandler::openSession
bool openSession(std::uint8_t sessionTimeout) override
Definition: CoLa2ProtocolHandler.cpp:223
visionary::CoLa2ProtocolHandler::ByteBuffer
std::vector< std::uint8_t > ByteBuffer
Definition: CoLa2ProtocolHandler.h:39
visionary::writeUnalignBigEndian
void writeUnalignBigEndian(void *ptr, std::size_t nBytes, const T &value)
Definition: VisionaryEndian.h:310
visionary::CoLa2ProtocolHandler::readProtocol
ByteBuffer readProtocol()
parse a response on protocol level
Definition: CoLa2ProtocolHandler.cpp:32


sick_visionary_ros
Author(s): SICK AG TechSupport 3D Snapshot
autogenerated on Thu Feb 8 2024 03:38:05