libvisiontransfer  6.5.0
parametertransfer.cpp
1 /*******************************************************************************
2  * Copyright (c) 2019 Nerian Vision GmbH
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *******************************************************************************/
14 
15 #include "visiontransfer/parametertransfer.h"
16 #include "visiontransfer/exceptions.h"
17 #include "visiontransfer/internalinformation.h"
18 #include "visiontransfer/standardparameterids.h"
19 #include "visiontransfer/parametertransferdata.h"
20 #include <cstring>
21 #include <string>
22 
23 using namespace std;
24 using namespace visiontransfer;
25 using namespace visiontransfer::internal;
26 
27 namespace visiontransfer {
28 namespace internal {
29 
30 constexpr int ParameterTransfer::SOCKET_TIMEOUT_MS;
31 
32 ParameterTransfer::ParameterTransfer(const char* address, const char* service)
33  : socket(INVALID_SOCKET) {
34 
35  Networking::initNetworking();
36  addrinfo* addressInfo = Networking::resolveAddress(address, service);
37 
38  socket = Networking::connectTcpSocket(addressInfo);
39  Networking::setSocketTimeout(socket, SOCKET_TIMEOUT_MS);
40  checkProtocolVersion();
41 
42  freeaddrinfo(addressInfo);
43 }
44 
45 ParameterTransfer::~ParameterTransfer() {
46  if(socket != INVALID_SOCKET) {
47  Networking::closeSocket(socket);
48  }
49 }
50 
51 std::map<std::string, ParameterInfo> ParameterTransfer::recvEnumeration() {
52  std::map<std::string, ParameterInfo> pi;
53  const size_t bufsize = 4096;
54  char buf[bufsize];
55  char* recv_buf = buf;
56 
57  int bytesReceived = recv(socket, recv_buf, 4, 0);
58  if(bytesReceived < 0) {
59  TransferException ex("Error receiving network packet: " + string(strerror(errno)));
60  throw ex;
61  } else if (bytesReceived == 0) {
62  TransferException ex("Error receiving network packet: connection closed");
63  throw ex;
64  } else if (bytesReceived < 4) {
65  TransferException ex("Error receiving parameter enumeration - no length!");
66  throw ex;
67  }
68  recv_buf += 4;
69 
70  // Number of parameters in the first received uint32
71  uint32_t num_params = ntohl(reinterpret_cast<uint32_t*>(buf)[0]);
72  // Expected size of following data block, read until met
73  size_t expected_remaining_size = num_params * sizeof(TransportParameterInfo);
74  if (expected_remaining_size > bufsize - 4) {
75  TransferException ex("Remote parameter enumeration exceeds expected maximum size");
76  throw ex;
77  }
78  while (expected_remaining_size > 0) {
79  bytesReceived = recv(socket, recv_buf, expected_remaining_size, 0);
80  if (bytesReceived < 0) {
81  TransferException ex("Error receiving network packet: " + string(strerror(errno)));
82  throw ex;
83  } else if (bytesReceived == 0) {
84  TransferException ex("Error receiving network packet: connection closed");
85  throw ex;
86  } else {
87  expected_remaining_size -= bytesReceived;
88  recv_buf += bytesReceived;
89  }
90  }
91 
92  TransportParameterInfo* tpi = reinterpret_cast<TransportParameterInfo*>(buf + 4);
93  for (unsigned int i = 0; i < num_params; ++i) {
94  StandardParameterIDs::ParameterID id = (StandardParameterIDs::ParameterID) ntohl(tpi->id);
95  ParameterInfo::ParameterType type = (ParameterInfo::ParameterType) ntohl(tpi->type);
96  bool writeable = ntohl(tpi->flags & StandardParameterIDs::ParameterFlags::PARAMETER_WRITEABLE) != 0;
97  //
98  auto nameIt = internal::StandardParameterIDs::parameterNameByID.find(id);
99  if (nameIt == StandardParameterIDs::parameterNameByID.end()) {
100  ParameterException ex("Enumeration contained a ParameterID for which no name is known: "+std::to_string(id));
101  throw ex;
102  }
103  switch(type) {
104  case ParameterInfo::TYPE_INT: {
105  pi[nameIt->second] = visiontransfer::ParameterInfo::fromInt(nameIt->second, writeable,
106  ntohl(tpi->value.intVal), ntohl(tpi->min.intVal), ntohl(tpi->max.intVal), ntohl(tpi->inc.intVal)
107  );
108  break;
109  }
110  case ParameterInfo::TYPE_BOOL: {
111  pi[nameIt->second] = visiontransfer::ParameterInfo::fromBool(nameIt->second, writeable, ntohl(tpi->value.boolVal) != 0);
112  break;
113  }
114  case ParameterInfo::TYPE_DOUBLE: {
115  pi[nameIt->second] = visiontransfer::ParameterInfo::fromDouble(nameIt->second, writeable,
116  tpi->value.doubleVal, tpi->min.doubleVal, tpi->max.doubleVal, tpi->inc.doubleVal
117  );
118  break;
119  }
120  default: {
121  }
122  }
123  ++tpi;
124  }
125  return pi;
126 }
127 
128 void ParameterTransfer::recvData(unsigned char* dest, int length) {
129  int bytesReceived = recv(socket, reinterpret_cast<char*>(dest), length, 0);
130  if(bytesReceived < 0) {
131  TransferException ex("Error receiving network packet: " + string(strerror(errno)));
132  throw ex;
133  } else if(bytesReceived < length) {
134  throw TransferException("Received too short network packet!");
135  }
136 }
137 
138 void ParameterTransfer::checkProtocolVersion() {
139  unsigned int version = 0;
140  recvData(reinterpret_cast<unsigned char*>(&version), sizeof(version));
141 
142  if(ntohl(version) != static_cast<unsigned int>(InternalInformation::CURRENT_PROTOCOL_VERSION)) {
143  throw ParameterException("Protocol version mismatch! Expected "
144  + std::to_string(InternalInformation::CURRENT_PROTOCOL_VERSION)
145  + " but received " + std::to_string(ntohl(version)));
146  }
147 }
148 
149 void ParameterTransfer::readParameter(unsigned char messageType, int32_t id, unsigned char* dest, int length) {
150  if(length > 8) {
151  throw ParameterException("Parameter type size mismatch!");
152  }
153 
154  unsigned int networkId = htonl(id);
155  unsigned char messageBuf[13];
156  memset(messageBuf, 0, sizeof(messageBuf));
157 
158  messageBuf[0] = messageType;
159  memcpy(&messageBuf[1], &networkId, 4);
160 
161  int written = send(socket, reinterpret_cast<char*>(messageBuf), sizeof(messageBuf), 0);
162  if(written != sizeof(messageBuf)) {
163  TransferException ex("Error sending parameter read request: " + string(strerror(errno)));
164  throw ex;
165  }
166 
167  unsigned char replyBuf[8];
168  recvData(replyBuf, sizeof(replyBuf));
169  memcpy(dest, replyBuf, length);
170 }
171 
172 template<typename T>
173 void ParameterTransfer::writeParameter(unsigned char messageType, int32_t id, T value) {
174  static_assert(sizeof(T) <= 8, "Parameter type musst be smaller or equal to 8 bytes");
175 
176  unsigned int networkId = htonl(id);
177  unsigned char messageBuf[13];
178 
179  memset(messageBuf, 0, sizeof(messageBuf));
180  messageBuf[0] = messageType;
181  memcpy(&messageBuf[1], &networkId, 4);
182  memcpy(&messageBuf[5], &value, sizeof(value));
183 
184  int written = send(socket, reinterpret_cast<char*>(messageBuf), sizeof(messageBuf), 0);
185  if(written != sizeof(messageBuf)) {
186  TransferException ex("Error sending parameter write request: " + string(strerror(errno)));
187  throw ex;
188  }
189 
190  unsigned char replyBuf[8];
191  recvData(replyBuf, sizeof(replyBuf));
192 
193  if(replyBuf[0] == 0 && replyBuf[1] == 0 && replyBuf[2] == 0 && replyBuf[3] == 0) {
194  throw ParameterException("Unable to write parameter");
195  }
196 }
197 
199  unsigned int data;
200  readParameter(MESSAGE_READ_INT, id, reinterpret_cast<unsigned char*>(&data), sizeof(data));
201  return static_cast<int>(ntohl(data));
202 }
203 
205  double data;
206  readParameter(MESSAGE_READ_DOUBLE, id, reinterpret_cast<unsigned char*>(&data), sizeof(data));
207  return data;
208 }
209 
211  unsigned int data;
212  readParameter(MESSAGE_READ_BOOL, id, reinterpret_cast<unsigned char*>(&data), sizeof(data));
213  return (data != 0);
214 }
215 
216 void ParameterTransfer::writeIntParameter(int32_t id, int32_t value) {
217  writeParameter(MESSAGE_WRITE_INT, id, htonl(static_cast<uint32_t>(value)));
218 }
219 
220 void ParameterTransfer::writeDoubleParameter(int32_t id, double value) {
221  writeParameter(MESSAGE_WRITE_DOUBLE, id, value);
222 }
223 
224 void ParameterTransfer::writeBoolParameter(int32_t id, int32_t value) {
225  writeParameter(MESSAGE_WRITE_BOOL, id, htonl(static_cast<uint32_t>(value)));
226 }
227 
228 std::map<std::string, ParameterInfo> ParameterTransfer::getAllParameters() {
229  unsigned char messageBuf[13]; // padded to common message size, payload ignored
230  memset(messageBuf, 0, sizeof(messageBuf));
231  messageBuf[0] = MESSAGE_ENUMERATE_PARAMS;
232 
233  int written = send(socket, reinterpret_cast<char*>(messageBuf), sizeof(messageBuf), 0);
234  if(written != sizeof(messageBuf)) {
235  TransferException ex("Error sending parameter enumeration request: " + string(strerror(errno)));
236  throw ex;
237  }
238  auto enumeration = recvEnumeration();
239  return enumeration;
240 }
241 
242 }} // namespace
243 
bool readBoolParameter(int32_t id)
Reads a boolean value from the parameter server.
int readIntParameter(int32_t id)
Reads an integer value from the parameter server.
void writeBoolParameter(int32_t id, int32_t value)
Writes a boolean value to a parameter of the parameter server.
Exception class that is used for all parameter-related exceptions.
Definition: exceptions.h:41
void writeIntParameter(int32_t id, int32_t value)
Writes an integer value to a parameter of the parameter server.
void writeDoubleParameter(int32_t id, double value)
Writes a double precision floating point value to a parameter of the parameter server.
std::map< std::string, ParameterInfo > getAllParameters()
Enumerates all parameters as reported by the device.
double readDoubleParameter(int32_t id)
Reads a double precision floating point value from the parameter server.
Exception class that is used for all transfer exceptions.
Definition: exceptions.h:33
Nerian Vision Technologies