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