usb_linux_utils.cpp
Go to the documentation of this file.
1 /*
2  * BSD 3-Clause License
3  *
4  * Copyright (c) 2019, Analog Devices, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  * list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived from
19  * this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 #include "usb_linux_utils.h"
33 
34 #include <errno.h>
35 #ifdef USE_GLOG
36 #include <glog/logging.h>
37 #else
38 #include <aditof/log.h>
39 #include <cstring>
40 #include <stdio.h>
41 #include <unistd.h>
42 #endif
43 #include <linux/usb/video.h>
44 #include <linux/uvcvideo.h>
45 #include <memory>
46 #include <sys/ioctl.h>
47 
48 #ifdef DEBUG_USB
49 #include <iostream>
50 #include <linux/uvcvideo.h>
51 #include <string.h>
52 #endif
53 
54 int UsbLinuxUtils::xioctl(int fh, unsigned long request, void *arg) {
55  int r;
56 
57  do {
58  r = ioctl(fh, request, arg);
59  // printf("Error=%d\n",errno);
60  } while (-1 == r && (EINTR == errno || EIO == errno) && errno != 0);
61 
62 #ifdef DEBUG_USB
63  if (request == (int)UVCIOC_CTRL_QUERY) {
64  static int count = 0;
65  struct uvc_xu_control_query *cq = (struct uvc_xu_control_query *)arg;
66  count++;
67  printf("%d Calling IOCTL with bRequest %02x, wValue %04x, wIndex "
68  "%04x, "
69  "wLength %04x\n",
70  count, cq->query, cq->selector, cq->unit, cq->size);
71  if (r != 0) {
72  printf("Return values: %d \n", r);
73  printf("IOCTL failed, error num: %d, %s\n", errno, strerror(errno));
74  }
75  }
76 #endif
77  return r;
78 }
79 
80 int UsbLinuxUtils::uvcExUnitReadOnePacket(int fd, uint8_t selector,
81  uint8_t *BytesToWrite,
82  uint8_t nbBytesToWrite, uint8_t *data,
83  uint8_t nbPacketBytes,
84  uint8_t nbBytesToRead) {
85  int ret = 0;
86 
87  if (nbPacketBytes > MAX_BUF_SIZE) {
88  LOG(ERROR)
89  << nbPacketBytes
90  << " is greater than the maximum size for a packet which is: "
91  << MAX_BUF_SIZE;
92  return -EINVAL;
93  }
94 
95  if (nbBytesToWrite > MAX_BUF_SIZE) {
96  LOG(ERROR)
97  << nbBytesToWrite
98  << " is greater than the maximum size for a packet which is: "
99  << MAX_BUF_SIZE;
100  return -EINVAL;
101  }
102 
103  struct uvc_xu_control_query cq;
104  uint8_t packet[nbPacketBytes];
105 
106  if (nbBytesToWrite > 0) {
107  memcpy(packet, BytesToWrite, nbBytesToWrite);
108  packet[nbBytesToWrite] = nbPacketBytes;
109 
110  // This set property will send bytes needed by get property
111  CLEAR(cq);
112  cq.query = UVC_SET_CUR;
113  cq.data = static_cast<unsigned char *>(packet);
114  cq.size = nbPacketBytes;
115  cq.unit = 0x03;
116  cq.selector = selector;
117 
118  ret = UsbLinuxUtils::xioctl(fd, UVCIOC_CTRL_QUERY, &cq);
119  if (ret == -1) {
120  LOG(WARNING) << "Error in sending address to device, error: "
121  << errno << "(" << strerror(errno) << ")";
122  return ret;
123  }
124  }
125 
126  // This get property will get the bytes
127  CLEAR(cq);
128  cq.query = UVC_GET_CUR;
129  cq.data = static_cast<unsigned char *>(packet);
130  cq.size = nbPacketBytes;
131  cq.unit = 0x03;
132  cq.selector = selector;
133 
134  ret = UsbLinuxUtils::xioctl(fd, UVCIOC_CTRL_QUERY, &cq);
135  if (ret == -1) {
136  LOG(WARNING) << "Error in reading data from device, error: " << errno
137  << "(" << strerror(errno) << ")";
138  return ret;
139  }
140 
141  memcpy(data, packet, nbBytesToRead);
142 
143  return ret;
144 }
145 
146 int UsbLinuxUtils::uvcExUnitReadBuffer(int fd, uint8_t selector, int16_t id,
147  uint32_t address, uint8_t *data,
148  uint32_t bufferLength) {
149  int ret = 0;
150 
151  if (id < -1 || id > 255) {
152  LOG(ERROR)
153  << id
154  << " is greater than the maximum size (255) accepted for an id";
155  return -EINVAL;
156  }
157 
158  uint8_t nbWrPacketBytes = sizeof(address) + (id > -1 ? 1 : 0);
159  uint8_t wrPacket[nbWrPacketBytes];
160  uint32_t *crtAddress =
161  reinterpret_cast<uint32_t *>(wrPacket + (id > -1 ? 1 : 0));
162 
163  uint32_t readBytes = 0;
164  uint32_t readLength = 0;
165 
166  *crtAddress = address;
167  if (id > -1) {
168  wrPacket[0] = id;
169  }
170  while (readBytes < bufferLength) {
171  readLength = bufferLength - readBytes < MAX_BUF_SIZE
172  ? bufferLength - readBytes
173  : MAX_BUF_SIZE;
174  ret =
175  uvcExUnitReadOnePacket(fd, selector, wrPacket, nbWrPacketBytes,
176  data + readBytes, MAX_BUF_SIZE, readLength);
177  if (ret < 0) {
178  LOG(WARNING) << "Failed to read a packet via UVC extension unit";
179  return ret;
180  }
181  *crtAddress += readLength;
182  readBytes += readLength;
183  }
184 
185  return ret;
186 }
187 
188 int UsbLinuxUtils::uvcExUnitWriteBuffer(int fd, uint8_t selector, int16_t id,
189  uint32_t address, const uint8_t *data,
190  uint32_t bufferLength) {
191  int ret = 0;
192 
193  if (id < -1 || id > 255) {
194  LOG(ERROR)
195  << id
196  << " is greater than the maximum size (255) accepted for an id";
197  return -EINVAL;
198  }
199 
200  uint8_t nbLeadingBytes = sizeof(address) + (id > -1 ? 1 : 0);
201  struct uvc_xu_control_query cq;
202  uint8_t packet[MAX_BUF_SIZE];
203  uint32_t *crtAddress =
204  reinterpret_cast<uint32_t *>(packet + (id > -1 ? 1 : 0));
205  size_t writeLen = 0;
206  size_t writtenBytes = 0;
207 
208  *crtAddress = address;
209  if (id > -1) {
210  packet[0] = static_cast<uint8_t>(id);
211  }
212 
213  // This set property will send the address and data to be written at the address
214  CLEAR(cq);
215  cq.query = UVC_SET_CUR;
216  cq.data = static_cast<unsigned char *>(packet);
217  cq.size = MAX_BUF_SIZE;
218  cq.unit = 0x03;
219  cq.selector = selector;
220 
221  while (writtenBytes < bufferLength) {
222  writeLen =
223  bufferLength - writtenBytes > MAX_BUF_SIZE - (nbLeadingBytes + 1)
224  ? MAX_BUF_SIZE - (nbLeadingBytes + 1)
225  : bufferLength - writtenBytes;
226  packet[nbLeadingBytes] = writeLen;
227  memcpy(&packet[nbLeadingBytes + 1], data + writtenBytes, writeLen);
228 
229  ret = UsbLinuxUtils::xioctl(fd, UVCIOC_CTRL_QUERY, &cq);
230  if (ret == -1) {
231  LOG(WARNING) << "Failed to write a packet via UVC extension unit";
232  return ret;
233  }
234  writtenBytes += writeLen;
235  *crtAddress += writeLen;
236  }
237 
238  return ret;
239 }
240 
242  std::string &outStr) {
243  uint16_t bufferLength;
244 
246  fd, uvcControlId, -1, 0, reinterpret_cast<uint8_t *>(&bufferLength),
247  sizeof(bufferLength));
248 
249  if (ret < 0) {
250  LOG(WARNING)
251  << "Failed to read size of buffer holding sensors info. Error: "
252  << ret;
254  }
255 
256  std::unique_ptr<uint8_t[]> data(new uint8_t[bufferLength + 1]);
258  fd, uvcControlId, -1, sizeof(bufferLength), data.get(), bufferLength);
259  if (ret < 0) {
260  LOG(WARNING) << "Failed to read the content of buffer holding sensors "
261  "info. Error: "
262  << ret;
264  }
265 
266  data[bufferLength] = '\0';
267  outStr = reinterpret_cast<char *>(data.get());
268 
269  return aditof::Status::OK;
270 }
271 
272 int UsbLinuxUtils::UvcExUnitSetProperty(int fd, uint8_t selector,
273  const uint8_t *data, size_t nbBytes) {
274  struct uvc_xu_control_query cq;
275  uint8_t *nonConstBuffer = const_cast<uint8_t *>(data);
276 
277  CLEAR(cq);
278  cq.query = UVC_SET_CUR;
279  cq.data = static_cast<unsigned char *>(nonConstBuffer);
280  cq.size = nbBytes;
281  cq.unit = 0x03;
282  cq.selector = selector;
283 
284  return UsbLinuxUtils::xioctl(fd, UVCIOC_CTRL_QUERY, &cq);
285 }
286 
287 int UsbLinuxUtils::UvcExUnitGetProperty(int fd, uint8_t selector, uint8_t *data,
288  size_t nbBytes) {
289  struct uvc_xu_control_query cq;
290 
291  CLEAR(cq);
292  cq.query = UVC_GET_CUR;
293  cq.data = static_cast<unsigned char *>(data);
294  cq.size = nbBytes;
295  cq.unit = 0x03;
296  cq.selector = selector;
297 
298  return UsbLinuxUtils::xioctl(fd, UVCIOC_CTRL_QUERY, &cq);
299 }
300 
303  const uint8_t uvcSendRequestControl = 1;
304 
305  // Send the size of the string we're about to send so that UVC gadget knows how many bytes to expect
306  size_t stringLength = requestStr.size();
307  int ret = UvcExUnitSetProperty(fd, uvcSendRequestControl,
308  reinterpret_cast<uint8_t *>(&stringLength),
309  MAX_BUF_SIZE);
310  if (ret < 0) {
311  LOG(WARNING)
312  << "Failed to write the length of the request string. Error: "
313  << ret << "(" << strerror(ret) << ")";
315  }
316 
317  // Send the entire string to the UVC-gadget
318  uint8_t packet[MAX_BUF_SIZE];
319  size_t writeLen = 0;
320  size_t writtenBytes = 0;
321  const char *data = requestStr.data();
322 
323  while (writtenBytes < stringLength) {
324  writeLen = stringLength - writtenBytes > MAX_BUF_SIZE
325  ? MAX_BUF_SIZE
326  : stringLength - writtenBytes;
327  memcpy(&packet, data + writtenBytes, writeLen);
328 
329  ret = UvcExUnitSetProperty(fd, uvcSendRequestControl, packet,
330  MAX_BUF_SIZE);
331  if (ret < 0) {
332  LOG(WARNING) << "Failed to write a packet of the send request "
333  "string. Error: "
334  << ret << "(" << strerror(ret) << ")";
336  }
337  writtenBytes += writeLen;
338  }
339 
340  return aditof::Status::OK;
341 }
342 
344  std::string &responseStr) {
345  const uint8_t uvcGetRequestControl = 2;
346 
347  uint8_t packet[MAX_BUF_SIZE];
348 
349  // Read the length of the string we're about to read next from the UVC gadget
350  int ret =
351  UvcExUnitGetProperty(fd, uvcGetRequestControl, packet, MAX_BUF_SIZE);
352  if (ret < 0) {
353  LOG(WARNING)
354  << "Failed to read the length of the response string. Error: "
355  << ret << "(" << strerror(ret) << ")";
357  }
358  size_t stringLength = reinterpret_cast<size_t *>(packet)[0];
359 
360  responseStr.reserve(stringLength);
361 
362  size_t readBytes = 0;
363  size_t readlength = 0;
364 
365  while (readBytes < stringLength) {
366  readlength = stringLength - readBytes > MAX_BUF_SIZE
367  ? MAX_BUF_SIZE
368  : stringLength - readBytes;
369 
370  ret = UvcExUnitGetProperty(fd, uvcGetRequestControl, packet,
371  MAX_BUF_SIZE);
372  if (ret < 0) {
373  LOG(WARNING)
374  << "Failed to read a packet of the response string. Error: "
375  << ret << "(" << strerror(ret) << ")";
377  }
378  responseStr.append(reinterpret_cast<const char *>(packet), readlength);
379  readBytes += readlength;
380  }
381 
382  return aditof::Status::OK;
383 }
ERROR
const int ERROR
Definition: log_severity.h:60
EINTR
#define EINTR
Definition: errno.hpp:7
EINVAL
#define EINVAL
Definition: errno.hpp:25
aditof::Status::GENERIC_ERROR
@ GENERIC_ERROR
An error occured but there are no details available.
log.h
MAX_BUF_SIZE
#define MAX_BUF_SIZE
Definition: usb_linux_utils.h:42
string
GLsizei const GLchar *const * string
Definition: glcorearb.h:3083
errno
int errno
WARNING
const int WARNING
Definition: log_severity.h:59
address
const char * address
Definition: builds/zos/test_fork.cpp:6
responseStr
ROSCPP_DECL XmlRpc::XmlRpcValue responseStr(int code, const std::string &msg, const std::string &response)
id
GLenum GLuint id
Definition: glcorearb.h:2695
UsbLinuxUtils::uvcExUnitReadBuffer
static int uvcExUnitReadBuffer(int fd, uint8_t selector, int16_t id, uint32_t address, uint8_t *data, uint32_t bufferLength)
uvcExUnitReadBuffer - Reads a chunk of data (a buffer) through the UVC Extension Unit
Definition: usb_linux_utils.cpp:146
UsbLinuxUtils::uvcExUnitGetString
static aditof::Status uvcExUnitGetString(int fd, int uvcControlId, std::string &outStr)
uvcExUnitGetString
Definition: usb_linux_utils.cpp:241
UsbLinuxUtils::uvcExUnitWriteBuffer
static int uvcExUnitWriteBuffer(int fd, uint8_t selector, int16_t id, uint32_t address, const uint8_t *data, uint32_t bufferLength)
uvcExUnitWriteBuffer
Definition: usb_linux_utils.cpp:188
aditof::Status
Status
Status of any operation that the TOF sdk performs.
Definition: status_definitions.h:48
LOG
#define LOG(x)
Definition: sdk/include/aditof/log.h:72
UsbLinuxUtils::UvcExUnitGetProperty
static int UvcExUnitGetProperty(int fd, uint8_t selector, uint8_t *data, size_t nbBytes)
Read bytes from one of the controls of the UVC extension unit.
Definition: usb_linux_utils.cpp:287
aditof::Status::OK
@ OK
Success.
CLEAR
#define CLEAR(x)
Definition: adsd3500_sensor.cpp:43
usb_linux_utils.h
r
GLboolean r
Definition: glcorearb.h:3228
strerror
char * strerror(int errno)
UsbLinuxUtils::uvcExUnitGetResponse
static aditof::Status uvcExUnitGetResponse(int fd, std::string &responseStr)
Get the response (which is encoded in a protobuf message) for the last request that was made....
Definition: usb_linux_utils.cpp:343
UsbLinuxUtils::UvcExUnitSetProperty
static int UvcExUnitSetProperty(int fd, uint8_t selector, const uint8_t *data, size_t nbBytes)
Send bytes to one of the controls of the UVC extension unit.
Definition: usb_linux_utils.cpp:272
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: glcorearb.h:2879
count
GLint GLsizei count
Definition: glcorearb.h:2830
UsbLinuxUtils::xioctl
static int xioctl(int fh, unsigned long request, void *arg)
Definition: usb_linux_utils.cpp:54
UsbLinuxUtils::uvcExUnitSendRequest
static aditof::Status uvcExUnitSendRequest(int fd, const std::string &requestStr)
Send a request (which is encoded in a protobuf message) via the UVC extension unit.
Definition: usb_linux_utils.cpp:302
UsbLinuxUtils::uvcExUnitReadOnePacket
static int uvcExUnitReadOnePacket(int fd, uint8_t selector, uint8_t *BytesToWrite, uint8_t nbBytesToWrite, uint8_t *data, uint8_t nbPacketBytes, uint8_t nbBytesToRead)
uvcExUnitReadOnePacket - Reads one packet of data through the UVC Extension Unit
Definition: usb_linux_utils.cpp:80


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:07:01