YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
UltraPythonCameraHelper.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
20
21#include <fcntl.h>
22#include <libudev.h>
23#include <linux/media.h>
24#include <linux/v4l2-subdev.h>
25#include <linux/videodev2.h>
26#include <sys/ioctl.h>
27#include <sys/mman.h>
28#include <sys/stat.h>
29#include <sys/types.h>
30#include <unistd.h>
32
33#include <chrono>
34#include <sstream>
35
36#include "Statistics.h"
37#include "common.h"
39
40#define CLEAR(x) memset(&(x), 0, sizeof(x))
41
43{
44 Log(*this, Severity::debug) << "::UltraPythonCameraHelper";
45 if (interfaceC == nullptr)
46 {
47 ownerCApi_ = true;
48 interfaceC = new InterfaceForCApi();
49 }
50 interfaceCApi_ = interfaceC;
51}
52
54{
55 Log(*this, Severity::debug) << "::~UltraPythonCameraHelper";
56 if (interfaceCApi_ != nullptr && ownerCApi_)
57 {
58 delete interfaceCApi_;
59 }
60}
61
62bool UltraPythonCameraHelper::openPipeline()
63{
64 Log(*this, Severity::debug) << "::openPipeline";
65
66 // Open main device
67 int fd = interfaceCApi_->open_c(mediaName_, O_RDWR);
68 if (fd == -1)
69 {
70 Log(*this, Severity::error) << "ERROR-cannot open media dev.Are modules loaded?";
71 return false;
72 }
73
74 struct udev *udev;
75 udev = interfaceCApi_->udev_new_c();
76 if (udev == nullptr)
77 {
78 Log(*this, Severity::error) << "ERROR-cannot open udev. Is libudev installed?";
79 return false;
80 }
81
82 // find subdevice
83 struct media_entity_desc info;
84 int subdeviceIndex = 0;
85 for (int id = 0;; id = info.id)
86 {
87 memset(&info, 0, sizeof(info));
88 info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
89
90 int ret = interfaceCApi_->ioctl_media_c(fd, MEDIA_IOC_ENUM_ENTITIES, info);
91 if (ret < 0)
92 {
93 Log(*this, Severity::warning) << "WARNING-cannot open device not media";
94 break;
95 }
96 Log(*this, Severity::debug) << "found entity name:" << std::string(info.name);
97
98 dev_t devnum = interfaceCApi_->makedev_c(info.v4l.major, info.v4l.minor);
99 struct udev_device *device;
100 device = interfaceCApi_->udev_device_new_from_devnum_c(udev, 'c', devnum);
101 if (device == nullptr)
102 {
103 udev_device_unref(device);
104 continue;
105 }
106
107 const char *deviceName;
108 deviceName = interfaceCApi_->udev_device_get_devnode_c(device);
109
110 // Open main subdevice
111 if ((std::strcmp(info.name, pipelineVideoName) == 0))
112 {
113 mainSubdeviceFd_ = interfaceCApi_->open_c(deviceName, O_RDWR | O_NONBLOCK, 0);
114 if (mainSubdeviceFd_ == -1)
115 {
116 Log(*this, Severity::error) << "ERROR-cannot open device:" << std::string(deviceName);
117 return false;
118 }
119 Log(*this, Severity::debug) << "open no pipeline:" << std::string(deviceName);
120 }
121 else
122 {
123 // Open other subdevice
124 /*
125 * If a python camera is found in pipeline, then that's the
126 * source. If only a TPG is present, then it's the source.
127 * In case both are found, stick to camera
128 */
129 if (std::strcmp(info.name, pipelinePythonName) == 0)
130 {
131 if (sourceSubDeviceIndex1_ == -1)
132 {
133 sourceSubDeviceIndex1_ = subdeviceIndex;
134 }
135 else
136 {
137 sourceSubDeviceIndex2_ = subdeviceIndex;
138 }
139 }
140 else if (std::strstr(info.name, pipelineTpgName))
141 {
142 tpgIndex_ = subdeviceIndex;
143 }
144 else if (std::strstr(info.name, pipelineCscName))
145 {
146 cscIndex_ = subdeviceIndex;
147 }
148 else if (std::strstr(info.name, pipelineImgfusionName))
149 {
150 imgfusionIndex_ = subdeviceIndex;
151 }
152 else if (std::strstr(info.name, pipelinePacket32Name))
153 {
154 packet32Index_ = subdeviceIndex;
155 }
156 else if (std::strcmp(info.name, pipelineRxifName) == 0)
157 {
158 if (rxif1Index_ == -1)
159 {
160 rxif1Index_ = subdeviceIndex;
161 }
162 else
163 {
164 rxif2Index_ = subdeviceIndex;
165 }
166 }
167 pipelineSubdeviceFd_[subdeviceIndex] = interfaceCApi_->open_c(deviceName, O_RDWR | O_NONBLOCK, 0);
168 if (pipelineSubdeviceFd_[subdeviceIndex] == -1)
169 {
170 Log(*this, Severity::error) << "ERROR-cannot open device:" << std::string(deviceName);
171 return false;
172 }
173 Log(*this, Severity::debug) << "Open pipeline devicename:" << std::string(deviceName) << " info name:" << info.name << " fd:" << pipelineSubdeviceFd_[subdeviceIndex]
174 << " index:" << subdeviceIndex;
175 subdeviceIndex++;
176 }
177 interfaceCApi_->udev_device_unref_c(device);
178 }
179 Log(*this, Severity::debug) << "open:" << mediaName_;
180 return checkIndex();
181}
182
183bool UltraPythonCameraHelper::checkIndex()
184{
185 if (mainSubdeviceFd_ == -1)
186 {
187 Log(*this, Severity::error) << "Cannot find main pipe V4L2 device";
188 return false;
189 }
190 if (sourceSubDeviceIndex1_ == -1)
191 {
192 Log(*this, Severity::error) << "Cannot find source subdev1";
193 return false;
194 }
195 if (sourceSubDeviceIndex2_ == -1)
196 {
197 Log(*this, Severity::error) << "Cannot find source subdev2";
198 return false;
199 }
200 if (rxif1Index_ == -1)
201 {
202 Log(*this, Severity::error) << "Cannot find rxif1Index";
203 return false;
204 }
205 if (rxif2Index_ == -1)
206 {
207 Log(*this, Severity::error) << "Cannot find rxif2Index";
208 return false;
209 }
210 if (cscIndex_ == -1)
211 {
212 Log(*this, Severity::error) << "Cannot find cscIndex";
213 return false;
214 }
215 if (tpgIndex_ == -1)
216 {
217 Log(*this, Severity::error) << "Cannot find tpgIndex";
218 return false;
219 }
220 if (imgfusionIndex_ == -1)
221 {
222 Log(*this, Severity::error) << "Cannot find imgfusionIndex";
223 return false;
224 }
225 return true;
226}
227
228bool UltraPythonCameraHelper::setSubDevFormat(int width, int height)
229{
230 int i;
231 int j;
232 int n;
233 struct v4l2_subdev_format fmt;
234
235 for (i = 0; pipelineSubdeviceFd_[i] != -1; i++)
236 {
237 if (i == imgfusionIndex_)
238 {
239 n = 3;
240 }
241 else
242 {
243 n = 2;
244 }
245 for (j = 0; j < n; j++)
246 {
247 CLEAR(fmt);
248 fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
249 fmt.pad = j;
250 if (-1 == interfaceCApi_->xioctl(pipelineSubdeviceFd_[i], VIDIOC_SUBDEV_G_FMT, &fmt))
251 {
252 Log(*this, Severity::error) << "VIDIOC_SUBDEV_G_FMT. subdev" << i << "pad" << j;
253 return false;
254 }
255
256 fmt.format.width = width;
257 fmt.format.height = height;
258
259 /* if yuv is required, then set that on the source PAD of VPSS */
260 if ((i == cscIndex_) && (j == 1) && spaceColor_ == SpaceColor::yuv)
261 {
262 fmt.format.code = MEDIA_BUS_FMT_UYVY8_1X16;
263 }
264
265 /* csc, when there is an imgfusion IP receives 2x width frames */
266 if ((imgfusionIndex_ != -1) && (i == cscIndex_))
267 {
268 fmt.format.width *= 2;
269 }
270 /* packet32, when there is an imgfusion IP receives 2x width frames */
271 if ((imgfusionIndex_ != -1) && (i == packet32Index_))
272 {
273 fmt.format.width *= 2;
274 }
275 /* tpg when there is an imgfusion IP receives 2x width frames */
276 if ((imgfusionIndex_ != -1) && (i == tpgIndex_))
277 {
278 fmt.format.width *= 2;
279 }
280
281 /* imgfusion source pad has 2* width */
282 if (j == 2)
283 {
284 fmt.format.width *= 2;
285 }
286
287 {
288 Log(*this, Severity::debug) << "subdev idx:" << i << " pad" << j << " setting format:" << fmt.format.width << ":" << fmt.format.height;
289 }
290 if (-1 == interfaceCApi_->xioctl(pipelineSubdeviceFd_[i], VIDIOC_SUBDEV_S_FMT, &fmt))
291 {
292 Log(*this, Severity::error) << "VIDIOC_SUBDEV_S_FMT. subdev" << i << "pad" << j;
293
294 return false;
295 }
296 if ((i == sourceSubDeviceIndex1_) || (i == sourceSubDeviceIndex2_))
297 {
298 break; /* only one pad */
299 }
300 }
301 }
302 return true;
303}
304
305bool UltraPythonCameraHelper::setFormat()
306{
307 struct v4l2_format fmt;
308 // todo check dimensions correctness
309 CLEAR(fmt);
310 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
311
312 if (forceFormatProperty_ || cropEnabledProperty_)
313 {
314 // Not tested nor enabled
315 fmt.fmt.pix.width = cropEnabledProperty_ ? cropWidth_ : nativeWidth_;
316 fmt.fmt.pix.height = cropEnabledProperty_ ? cropHeight_ : nativeHeight_;
317
318 if (subsamplingEnabledProperty_)
319 {
320 fmt.fmt.pix.width /= 2;
321 fmt.fmt.pix.height /= 2;
322 }
323
324 if (spaceColor_ == SpaceColor::grgb)
325 {
326 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
327 }
328 else if (spaceColor_ == SpaceColor::yuv)
329 {
330 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
331 }
332 else if (spaceColor_ == SpaceColor::rgb)
333 {
334 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
335 }
336
337 fmt.fmt.pix.field = 1;
338 fmt.fmt.pix.colorspace = 8;
339
340 if (!setSubDevFormat(fmt.fmt.pix.width, fmt.fmt.pix.height))
341 {
342 return false;
343 }
344
345 if (imgfusionIndex_ != -1)
346 {
347 fmt.fmt.pix.width *= 2;
348 }
349
350 if (-1 == interfaceCApi_->xioctl(mainSubdeviceFd_, VIDIOC_S_FMT, &fmt))
351 {
352 return false;
353 }
354
355 /* Note VIDIOC_S_FMT may change width and height. */
356 return true;
357 }
358 /* Preserve original settings as set by v4l2-ctl for example */
359 if (interfaceCApi_->xioctl(mainSubdeviceFd_, VIDIOC_G_FMT, &fmt) == -1)
360 {
361 return false;
362 }
363 return true;
364}
365
366/*Unused for now*/
367bool UltraPythonCameraHelper::crop(int top, int left, int w, int h, int mytry)
368{
369 cropCheck();
370
371 Log(*this, Severity::debug) << "crop is" << std::string(cropEnabledProperty_ ? "ENABLED" : "DISABLED");
372 if (!cropEnabledProperty_)
373 {
374 return true;
375 }
376
377 struct v4l2_subdev_crop _crop;
378
379 _crop.rect.left = left;
380 _crop.rect.top = top;
381 _crop.rect.width = w;
382 _crop.rect.height = h;
383
384 _crop.which = mytry ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
385 _crop.pad = 0;
386
387 if (-1 == interfaceCApi_->xioctl(pipelineSubdeviceFd_[sourceSubDeviceIndex1_], VIDIOC_SUBDEV_S_CROP, &_crop))
388 {
389 return false;
390 }
391 if (sourceSubDeviceIndex2_ != -1)
392 {
393 if (-1 == interfaceCApi_->xioctl(pipelineSubdeviceFd_[sourceSubDeviceIndex2_], VIDIOC_SUBDEV_S_CROP, &_crop))
394 {
395 return false;
396 }
397 }
398 return true;
399}
400
401bool UltraPythonCameraHelper::setSubsampling()
402{
403 Log(*this, Severity::debug) << "subsampling is" << std::string(subsamplingEnabledProperty_ ? "ENABLED" : "DISABLED");
404 int subSamplingValue = 0;
405 if (subsamplingEnabledProperty_)
406 {
407 subSamplingValue = 1;
408 }
409
410 Log(*this, Severity::debug) << "setSubsampling";
411 struct v4l2_control ctrl;
412
414 ctrl.value = subSamplingValue;
415 if (-1 == interfaceCApi_->xioctl(pipelineSubdeviceFd_[sourceSubDeviceIndex1_], VIDIOC_S_CTRL, &ctrl))
416 {
417 Log(*this, Severity::error) << "setSubsampling";
418 return false;
419 }
420
421 if (sourceSubDeviceIndex2_ != -1)
422 {
423 if (-1 == interfaceCApi_->xioctl(pipelineSubdeviceFd_[sourceSubDeviceIndex2_], VIDIOC_S_CTRL, &ctrl))
424 {
425 Log(*this, Severity::error) << "setSubsampling";
426 return false;
427 }
428 }
429
431 ctrl.value = subSamplingValue;
432 if (-1 == interfaceCApi_->xioctl(pipelineSubdeviceFd_[rxif1Index_], VIDIOC_S_CTRL, &ctrl))
433 {
434 Log(*this, Severity::error) << "setSubsampling remapper";
435 return false;
436 }
437
438 if (rxif2Index_ != -1)
439 {
440 if (-1 == interfaceCApi_->xioctl(pipelineSubdeviceFd_[rxif2Index_], VIDIOC_S_CTRL, &ctrl))
441 {
442 Log(*this, Severity::error) << "setSubsampling remapper2";
443 return false;
444 }
445 }
446 return true;
447}
448
449bool UltraPythonCameraHelper::checkDevice(int mainSubdeviceFd)
450{
451 struct v4l2_capability cap;
452 if (-1 == interfaceCApi_->xioctl(mainSubdeviceFd, VIDIOC_QUERYCAP, &cap))
453 {
454 // Should not happen
455 if (EINVAL == errno)
456 {
457 Log(*this, Severity::error) << "checkDevice:device is no V4L2 device";
458 }
459 return false;
460 }
461 return true;
462}
463
464bool UltraPythonCameraHelper::initDevice()
465{
466 Log(*this, Severity::debug) << "initDevice";
467
468 if (!checkDevice(mainSubdeviceFd_))
469 {
470 return false;
471 }
472 if (!setSubsampling())
473 {
474 return false;
475 }
476 if (!setFormat())
477 {
478 return false;
479 }
480 if (!crop(cropTop_, cropLeft_, cropWidth_, cropHeight_, 0))
481 {
482 return false;
483 }
484 if (!initMmap())
485 {
486 return false;
487 }
488
489 return true;
490}
491
492bool UltraPythonCameraHelper::cropCheck()
493{
494 struct v4l2_cropcap cropcap;
495 struct v4l2_crop tmpCrop;
496 CLEAR(cropcap);
497
498 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
499 if (0 == interfaceCApi_->xioctl(mainSubdeviceFd_, VIDIOC_CROPCAP, &cropcap))
500 {
501 tmpCrop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
502 tmpCrop.c = cropcap.defrect; /* reset to default */
503
504 if (-1 == interfaceCApi_->xioctl(mainSubdeviceFd_, VIDIOC_S_CROP, &tmpCrop))
505 {
506 switch (errno)
507 {
508 case EINVAL:
509 Log(*this, Severity::error) << "cropping not supported";
510 break;
511 default:
512 Log(*this, Severity::error) << "cropping";
513 break;
514 }
515 }
516 }
517 else
518 {
519 Log(*this, Severity::warning) << "cropping-2";
520 }
521 return true;
522}
523
524bool UltraPythonCameraHelper::initMmap()
525{
526 Log(*this, Severity::debug) << "initMmap";
527 struct v4l2_requestbuffers req;
528
529 CLEAR(req);
530
531 req.count = requestBufferNumber_;
532 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
533 req.memory = V4L2_MEMORY_MMAP;
534
535 if (-1 == interfaceCApi_->xioctl(mainSubdeviceFd_, VIDIOC_REQBUFS, &req))
536 {
537 if (EINVAL == errno)
538 {
539 Log(*this, Severity::error) << "device does not support memmap";
540 return false;
541 }
542 Log(*this, Severity::error) << "device does not support memmap";
543 return false;
544 }
545
546 if (req.count < 1)
547 {
548 Log(*this, Severity::error) << "Insufficient buffer memory on";
549 return false;
550 }
551
552 for (unsigned int currentUsedBufferIndex = 0; currentUsedBufferIndex < req.count; ++currentUsedBufferIndex)
553 {
554 struct v4l2_buffer buf;
555
556 CLEAR(buf);
557
558 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
559 buf.memory = V4L2_MEMORY_MMAP;
560 buf.index = currentUsedBufferIndex;
561
562 if (-1 == interfaceCApi_->xioctl(mainSubdeviceFd_, VIDIOC_QUERYBUF, &buf))
563 {
564 return false;
565 }
566
567 mMapBuffers_[currentUsedBufferIndex].length = buf.length;
568 mMapBuffers_[currentUsedBufferIndex].start =
569 interfaceCApi_->mmap_c(nullptr /* start anywhere */, buf.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */, mainSubdeviceFd_, buf.m.offset);
570
571 if (MAP_FAILED == mMapBuffers_[currentUsedBufferIndex].start)
572 {
573 return false;
574 }
575 }
576 return true;
577}
578
579bool UltraPythonCameraHelper::startCapturing()
580{
581 Log(*this, Severity::debug) << "startCapturing";
582 enum v4l2_buf_type type;
583
584 for (size_t i = 0; i < requestBufferNumber_; ++i)
585 {
586 struct v4l2_buffer buf;
587
588 CLEAR(buf);
589 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
590 buf.memory = V4L2_MEMORY_MMAP;
591 buf.index = i;
592
593 if (-1 == interfaceCApi_->xioctl(mainSubdeviceFd_, VIDIOC_QBUF, &buf))
594 {
595 Log(*this, Severity::error) << "VIDIOC_QBUF";
596 return false;
597 }
598 }
599 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
600 if (-1 == interfaceCApi_->xioctl(mainSubdeviceFd_, VIDIOC_STREAMON, &type))
601 {
602 Log(*this, Severity::error) << "VIDIOC_STREAMON";
603 return false;
604 }
605 return true;
606}
607
608bool UltraPythonCameraHelper::step(unsigned char *yarpbuffer)
609{
610 static int seq = 0;
611 static int sequence = 0;
612
613 fd_set fds;
614 struct timeval tv
615 {
616 80, 0
617 }; // Timeout
618
619 FD_ZERO(&fds);
620 FD_SET(mainSubdeviceFd_, &fds);
621
622 int ret = interfaceCApi_->select_c(mainSubdeviceFd_ + 1, &fds, nullptr, nullptr, &tv);
623 if (ret == -1)
624 {
625 if (EINTR == errno)
626 {
627 // Not a real error
628 return false;
629 }
630 Log(*this, Severity::error) << "on select";
631 return false;
632 }
633
634 if (ret == 0)
635 {
636 Log(*this, Severity::error) << "-select timeout";
637 return false;
638 }
639
640 seq = readFrame(yarpbuffer);
641 if (seq == -1)
642 {
643 return false;
644 }
645 if (seq != sequence++)
646 {
647 Log(*this, Severity::warning) << "dropped frame..";
648 sequence = seq + 1;
649 }
650
651 statistics_.setExposure(getCurrentExposure());
652 statistics_.add();
653 return true;
654}
655
656int UltraPythonCameraHelper::readFrame(unsigned char *yarpbuffer)
657{
658 struct v4l2_buffer buf;
659 int seq = 1;
660 CLEAR(buf);
661
662 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
663 buf.memory = V4L2_MEMORY_MMAP;
664
665 if (interfaceCApi_->xioctl_v4l2(mainSubdeviceFd_, VIDIOC_DQBUF, &buf) == -1)
666 {
667 switch (errno)
668 {
669 case EAGAIN:
670
671 Log(*this, Severity::error) << "VIDIOC_DQBUF eagain";
672 return -1;
673 default:
674 Log(*this, Severity::error) << "-VIDIOC_DQBUF";
675 return -1;
676 }
677 }
678
679 if (buf.index >= requestBufferNumber_)
680 {
681 Log(*this, Severity::error) << "readframe";
682 return -1;
683 }
684
685 if (buf.flags & V4L2_BUF_FLAG_ERROR)
686 {
687 Log(*this, Severity::error) << "V4L2_BUF_FLAG_ERROR";
688 return -1;
689 }
690
691 seq = buf.sequence;
692
693 memcpy(yarpbuffer, mMapBuffers_[buf.index].start,
694 buf.bytesused); // Copy to out Yarp buffer
695 processImage(mMapBuffers_[buf.index].start, buf.bytesused); // Nothing to do
696 //**Debug for Kernel start
697 memset(mMapBuffers_[buf.index].start, 111, buf.bytesused);
698 //**Debug end
699 if (interfaceCApi_->xioctl(mainSubdeviceFd_, VIDIOC_QBUF, &buf) == -1)
700 {
701 Log(*this, Severity::error) << "VIDIOC_QBUF";
702 return -1;
703 }
704
705 return seq;
706}
707
708void UltraPythonCameraHelper::processImage(const void *p, int size)
709{
710 if (injectedProcessImage_ == nullptr)
711 {
712 return;
713 }
714 injectedProcessImage_(p, size);
715}
716
718{
719 if (!stopCapturing())
720 {
721 return false;
722 }
723 if (!unInitDevice())
724 {
725 return false;
726 }
727 if (!closePipeline())
728 {
729 return false;
730 }
731 return true;
732}
733
734bool UltraPythonCameraHelper::unInitDevice()
735{
736 Log(*this, Severity::debug) << "uninit_device";
737 unsigned int i;
738
739 for (i = 0; i < requestBufferNumber_; ++i)
740 {
741 if (-1 == munmap(mMapBuffers_[i].start, mMapBuffers_[i].length))
742 {
743 Log(*this, Severity::error) << "munmap";
744 return false;
745 }
746 }
747 return true;
748}
749
750bool UltraPythonCameraHelper::stopCapturing()
751{
752 enum v4l2_buf_type type;
753
754 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
755 if (-1 == interfaceCApi_->xioctl(mainSubdeviceFd_, VIDIOC_STREAMOFF, &type))
756 {
757 Log(*this, Severity::error) << "VIDIOC_STREAMOFF";
758 return false;
759 }
760 return true;
761}
762
763bool UltraPythonCameraHelper::closePipeline()
764{
765 int i;
766
767 for (i = 0; pipelineSubdeviceFd_[i] != -1; i++)
768 {
769 if (-1 == close(pipelineSubdeviceFd_[i]))
770 {
771 Log(*this, Severity::error) << "close pipeline";
772 return false;
773 }
774 }
775 return true;
776}
777
778void UltraPythonCameraHelper::setInjectedProcess(std::function<void(const void *, int)> toinJect)
779{
780 injectedProcessImage_ = toinJect;
781}
782void UltraPythonCameraHelper::setInjectedUnlock(std::function<void()> toinJect)
783{
784 unlock_ = toinJect;
785}
786void UltraPythonCameraHelper::setInjectedLock(std::function<void()> toinJect)
787{
788 lock_ = toinJect;
789}
790
792{
793 subsamplingEnabledProperty_ = value;
794
795 if (value)
796 {
797 currentHeight_ = lowresHeight_;
798 currentWidth_ = lowresWidth_;
799 }
800 else
801 {
802 currentHeight_ = hiresHeight_;
803 currentWidth_ = hiresWidth_;
804 }
805}
806
808{
809 if (!openPipeline())
810 {
811 return false;
812 }
813
814 if (!initDevice())
815 {
816 return false;
817 }
818
819 if (!setDefaultControl())
820 {
821 return false;
822 }
823
824 if (!startCapturing())
825 {
826 return false;
827 }
828 return true;
829}
830
832{
833 stepPeriod_ = msec;
834}
836{
837 honorfps_ = value;
838 if (value)
839 {
840 setControl(V4L2_EXPOSURE_ULTRA_PYTHON, minPermittedExposition_, true);
841 }
842}
843
844void UltraPythonCameraHelper::setInjectedLog(std::function<void(const std::string &, Severity)> toinJect)
845{
846 log_ = toinJect;
847}
848
849bool UltraPythonCameraHelper::setControl(uint32_t v4lCtrl, double value, bool absolute)
850{
851 if (value < 0)
852 {
853 return false;
854 }
855
856 if (!absolute)
857 {
858 if (value > 1.0 || value < 0.0)
859 {
860 Log(*this, Severity::error) << "Not absolute settings should be between 0,1:" << v4lCtrl;
861 return false;
862 }
863 }
864
865 if (!FeatureHelper::isV4Lcontrol(v4lCtrl))
866 {
867 switch (v4lCtrl)
868 {
869 case YARP_FEATURE_HONOR_FPS:
870 setHonorFps((bool)value);
871 return true;
872 default:
873 Log(*this, Severity::error) << "setControl wrong not v4l control id:" << v4lCtrl;
874 return -1;
875 }
876 }
877 if (!internalHasControl(v4lCtrl))
878 {
879 Log(*this, Severity::error) << "setControl Missing ctr id:" << v4lCtrl;
880 return false;
881 }
882 Log(*this, Severity::debug) << "try setControl for:" << v4lCtrl << " value:" << value;
883 switch (v4lCtrl)
884 {
885 case V4L2_CID_GAIN:
886 return setGain(value, absolute);
888 case V4L2_CID_BRIGHTNESS:
889 case V4L2_EXTTRIGGER_ULTRA_PYTHON: // EXT_TRIGGER
890 bool out;
891 out = setControl(v4lCtrl, pipelineSubdeviceFd_[sourceSubDeviceIndex1_], value, absolute);
892 out = out & setControl(v4lCtrl, pipelineSubdeviceFd_[sourceSubDeviceIndex2_], value, absolute);
893 return out;
894 case V4L2_REDBALANCE_ULTRA_PYTHON: // V4L2_CID_RED_BALANCE
895 case V4L2_GREENBALANCE_ULTRA_PYTHON: // V4L2_CID_BLUE_BALANCE
896 case V4L2_BLUEBALANCE_ULTRA_PYTHON: // V4L2_CID_BLUE_BALANCE
897 case V4L2_DEADTIME_ULTRA_PYTHON: // trg_h
898 case V4L2_EXPOSURE_ULTRA_PYTHON: // EXPOSURE trg_l
900 return setControl(v4lCtrl, mainSubdeviceFd_, value, absolute);
901 default:
902 return false;
903 }
904 return false;
905}
906
907bool UltraPythonCameraHelper::setControl(uint32_t v4lCtrl, int fd, double value, bool absolute)
908{
909 if (value < 0)
910 {
911 Log(*this, Severity::error) << "setControl wrong value control";
912 return false;
913 }
914
915 struct v4l2_queryctrl queryctrl;
916 struct v4l2_control control;
917
918 memset(&queryctrl, 0, sizeof(queryctrl));
919 queryctrl.id = v4lCtrl;
920
921 if (-1 == interfaceCApi_->ioctl_query_c(fd, VIDIOC_QUERYCTRL, queryctrl))
922 {
923 if (errno != EINVAL)
924 {
925 Log(*this, Severity::error) << "Cannot setControl1 value:" << value << " fd:" << fd;
926 }
927 else
928 {
929 Log(*this, Severity::error) << "Cannot setControl2 value:" << value << " fd:" << fd;
930 }
931 return false;
932 }
933
934 if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
935 {
936 Log(*this, Severity::error) << "Cannot setControl is disabled";
937 return false;
938 }
939 memset(&control, 0, sizeof(control));
940 control.id = v4lCtrl;
941
942 if (v4lCtrl == V4L2_EXPOSURE_ULTRA_PYTHON) // trg_l
943 {
944 queryctrl.maximum = maxPermittedExposition_;
945 queryctrl.minimum = minPermittedExposition_;
946 }
947 if (!absolute)
948 {
949 control.value = static_cast<int32_t>(value * (queryctrl.maximum - queryctrl.minimum) + queryctrl.minimum);
950 }
951 else
952 {
953 control.value = static_cast<int32_t>(value);
954 }
955
956 if (v4lCtrl == V4L2_EXPOSURE_ULTRA_PYTHON)
957 {
958 double limit = control.value + deadTime_ + 2;
959 if (stepPeriod_ <= limit)
960 {
961 if (!honorfps_)
962 {
963 Log(*this, Severity::warning) << "Exposition will decrease FPS no honorfps. Limit:" << limit << " current step:" << stepPeriod_;
964 }
965 else
966 {
967 Log(*this, Severity::error) << "Exposition will decrease FPS honorfps so blocked. Limit:" << limit << " current step:" << stepPeriod_;
968 return false;
969 }
970 }
971 else
972 {
973 Log(*this, Severity::debug) << "Exposition will mantain current FPS Limit:" << limit << " current step:" << stepPeriod_;
974 }
975 currentExposure_ = control.value; // Logging purpouse
976 }
977
978 // Do set
979 if (-1 == interfaceCApi_->ioctl_control_c(fd, VIDIOC_S_CTRL, control))
980 {
981 Log(*this, Severity::error) << "Cannot setControl3";
982 return false;
983 }
984
985 Log(*this, Severity::debug) << "SetControl done --> Ctrl name:" << queryctrl.name << " Ctrl value:" << control.value << " Ctrl id:" << control.id;
986 return true;
987}
988
989double UltraPythonCameraHelper::getControl(uint32_t v4lCtrl, bool absolute)
990{
991 if (!FeatureHelper::isV4Lcontrol(v4lCtrl))
992 {
993 switch (v4lCtrl)
994 {
995 case YARP_FEATURE_HONOR_FPS:
996 return honorfps_;
997 case YARP_FEATURE_FPS:
998 return statistics_.getFps();
999 case YARP_FEATURE_SUBSAMPLING:
1000 if (subsamplingEnabledProperty_)
1001 return 1;
1002 return 0;
1003 default:
1004 Log(*this, Severity::error) << "getControl wrong not v4l control id:" << v4lCtrl;
1005 return -1;
1006 }
1007 }
1008
1009 if (!internalHasControl(v4lCtrl))
1010 {
1011 Log(*this, Severity::error) << "getControl Missing ctr id:" << v4lCtrl;
1012 return false;
1013 }
1014
1015 switch (v4lCtrl)
1016 {
1017 case V4L2_CID_GAIN:
1019 case V4L2_CID_BRIGHTNESS:
1020 case V4L2_EXTTRIGGER_ULTRA_PYTHON: // EXT_TRIGGER
1021 {
1022 double left = getControl(v4lCtrl, pipelineSubdeviceFd_[sourceSubDeviceIndex1_], absolute);
1023 double right = getControl(v4lCtrl, pipelineSubdeviceFd_[sourceSubDeviceIndex2_], absolute);
1024 if (left != right)
1025 {
1026 Log(*this, Severity::error) << "getControl left and right different";
1027 }
1028 return left;
1029 }
1030 case V4L2_REDBALANCE_ULTRA_PYTHON: // V4L2_CID_RED_BALANCE
1031 case V4L2_GREENBALANCE_ULTRA_PYTHON: // V4L2_CID_GREEN_BALANCE
1032 case V4L2_BLUEBALANCE_ULTRA_PYTHON: // V4L2_CID_BLUE_BALANCE
1033 case V4L2_EXPOSURE_ULTRA_PYTHON: // EXPOSURE trg_l
1034 case V4L2_DEADTIME_ULTRA_PYTHON: // trg_h
1035 case V4L2_CONTRAST_ULTRA_PYTHON: // Contrast
1036 return getControl(v4lCtrl, mainSubdeviceFd_, absolute);
1037 default:
1038 return -1.0;
1039 }
1040}
1041
1042double UltraPythonCameraHelper::getControl(uint32_t v4lCtrl, int fd, bool absolute)
1043{
1044 if (v4lCtrl == V4L2_CID_GAIN)
1045 {
1046 double min = gainMap_.begin()->first;
1047 double max = gainMap_.end()->first;
1048 if (absolute)
1049 return currentGainValue_;
1050 return (currentGainValue_ - min) / (max - min);
1051 }
1052
1053 struct v4l2_queryctrl queryctrl;
1054 struct v4l2_control control;
1055
1056 memset(&control, 0, sizeof(control));
1057 memset(&queryctrl, 0, sizeof(queryctrl));
1058
1059 control.id = v4lCtrl;
1060 queryctrl.id = v4lCtrl;
1061
1062 if (interfaceCApi_->ioctl_query_c(fd, VIDIOC_QUERYCTRL, queryctrl) == -1)
1063 {
1064 if (errno != EINVAL)
1065 {
1066 Log(*this, Severity::error) << "getControl VIDIOC_QUERYCTRL:" << v4lCtrl;
1067 }
1068 return -1.0;
1069 }
1070
1071 if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
1072 {
1073 Log(*this, Severity::error) << "Control is disabled:" << v4lCtrl;
1074 }
1075 else
1076 {
1077 if (interfaceCApi_->ioctl_control_c(fd, VIDIOC_G_CTRL, control) == -1)
1078 {
1079 Log(*this, Severity::error) << "getControl VIDIOC_G_CTRL:" << v4lCtrl;
1080 return -1.0;
1081 }
1082 }
1083
1084 if (v4lCtrl == V4L2_EXPOSURE_ULTRA_PYTHON) // trg_l
1085 {
1086 queryctrl.maximum = maxPermittedExposition_;
1087 queryctrl.minimum = minPermittedExposition_;
1088 }
1089
1090 if (absolute)
1091 return control.value;
1092 return static_cast<double>(control.value - queryctrl.minimum) / (queryctrl.maximum - queryctrl.minimum);
1093}
1094
1095bool UltraPythonCameraHelper::internalHasControl(uint32_t v4lCtrl) const
1096{
1097 bool ret = false;
1098 switch (v4lCtrl)
1099 {
1100 case V4L2_CID_GAIN:
1102 case V4L2_CID_BRIGHTNESS:
1104 case V4L2_REDBALANCE_ULTRA_PYTHON: // V4L2_CID_RED_BALANCE
1105 case V4L2_GREENBALANCE_ULTRA_PYTHON: // V4L2_CID_GREEN_BALANCE
1106 case V4L2_BLUEBALANCE_ULTRA_PYTHON: // V4L2_CID_BLUE_BALANCE
1107 case V4L2_EXTTRIGGER_ULTRA_PYTHON: // EXT_TRIGGER
1108 case V4L2_EXPOSURE_ULTRA_PYTHON: // EXPOSURE trg_l
1109 case V4L2_DEADTIME_ULTRA_PYTHON: // trg_h
1110 ret = true;
1111 break;
1112 default:
1113 ret = false;
1114 }
1115 Log(*this, Severity::debug) << "internalHasControl for original:" << v4lCtrl << " value:" << ret;
1116 return ret;
1117}
1118
1119bool UltraPythonCameraHelper::setDefaultControl()
1120{
1121 setControl(V4L2_EXTTRIGGER_ULTRA_PYTHON, 1, true); // ext_trigger
1122 setControl(V4L2_EXPOSURE_ULTRA_PYTHON, 20, true); // trg_l
1123 setControl(V4L2_DEADTIME_ULTRA_PYTHON, deadTime_, true); // trg_h
1125 setControl(V4L2_CID_BRIGHTNESS, 50, true);
1126 setControl(V4L2_CID_GAIN, 1, true);
1127 return true;
1128}
1129
1130bool UltraPythonCameraHelper::setGain(double value, bool absolute)
1131{
1132 double min = gainMap_.begin()->first;
1133 double max = gainMap_.end()->first;
1134 int absoluteValue = static_cast<int32_t>(value);
1135 if (!absolute)
1136 {
1137 absoluteValue = static_cast<int32_t>(value * (max - min) + min);
1138 }
1139
1140 auto it = gainMap_.find(absoluteValue);
1141 if (it == gainMap_.end())
1142 {
1143 Log(*this, Severity::error) << "wrong gain value";
1144 return false;
1145 }
1146
1147 auto current = gainMap_.at(absoluteValue);
1148 currentGainValue_ = absoluteValue;
1149 Log(*this, Severity::debug) << "gain:" << absoluteValue << " digital:" << current.first << " analog:" << current.second;
1150
1151 setControl(V4L2_CID_GAIN, pipelineSubdeviceFd_[sourceSubDeviceIndex1_], current.first, true);
1152 setControl(V4L2_CID_GAIN, pipelineSubdeviceFd_[sourceSubDeviceIndex2_], current.first, true);
1153 setControl(V4L2_ANALOGGAIN_ULTRA_PYTHON, pipelineSubdeviceFd_[sourceSubDeviceIndex1_], current.second, true);
1154 setControl(V4L2_ANALOGGAIN_ULTRA_PYTHON, pipelineSubdeviceFd_[sourceSubDeviceIndex2_], current.second, true);
1155 return true;
1156}
1157
1159{
1160 return cropEnabledProperty_;
1161}
1163{
1164 return forceFormatProperty_;
1165}
1166
1168{
1169 return honorfps_;
1170}
1172{
1173 return stepPeriod_;
1174}
1176{
1177 return currentExposure_;
1178};
1179
1180// Test only
1181void UltraPythonCameraHelper::mapBufferFill(unsigned char *tofillWith, unsigned int index)
1182{
1183 mMapBuffers_[index].start = tofillWith;
1184}
bool ret
#define CLEAR
Definition Log.cpp:199
struct v4l2_queryctrl queryctrl
virtual int xioctl_v4l2(int fh, int request, struct v4l2_buffer *arg)
virtual int ioctl_query_c(int fd, int value, struct v4l2_queryctrl &info)
virtual struct udev * udev_new_c()
virtual struct udev_device * udev_device_new_from_devnum_c(struct udev *udev, char type, dev_t devnum)
virtual dev_t makedev_c(int major, int minor)
virtual int open_c(const char *path, int oflag)
virtual struct udev_device * udev_device_unref_c(struct udev_device *udev_device)
virtual const char * udev_device_get_devnode_c(struct udev_device *udev_device)
virtual int xioctl(int fh, int request, void *arg)
virtual int ioctl_media_c(int fd, int value, struct media_entity_desc &info)
virtual int select_c(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
virtual void * mmap_c(void *addr, size_t len, int prot, int flags, int fd, __off_t offset)
virtual int ioctl_control_c(int fd, int value, struct v4l2_control &info)
void setExposure(double value)
double getFps() const
static constexpr unsigned int V4L2_ANALOGGAIN_ULTRA_PYTHON
void setInjectedUnlock(std::function< void()> toinJect)
void setInjectedLog(std::function< void(const std::string &, Severity severity)> toinJect)
void mapBufferFill(unsigned char *tofillWith, unsigned int index)
static constexpr unsigned int V4L2_EXTTRIGGER_ULTRA_PYTHON
static constexpr unsigned int V4L2_CONTRAST_ULTRA_PYTHON
static constexpr unsigned int V4L2_BLUEBALANCE_ULTRA_PYTHON
bool step(unsigned char *yarpbuffer)
void setInjectedLock(std::function< void()> toinJect)
void setInjectedProcess(std::function< void(const void *, int)> toinJect)
static constexpr unsigned int V4L2_DEADTIME_ULTRA_PYTHON
UltraPythonCameraHelper(InterfaceForCApi *interfaceCt)
static constexpr unsigned int V4L2_EXPOSURE_ULTRA_PYTHON
bool setControl(uint32_t v4lCtrl, double value, bool absolute)
static constexpr unsigned int V4L2_GREENBALANCE_ULTRA_PYTHON
double getControl(uint32_t v4lCtrl, bool absolute)
static constexpr unsigned int V4L2_REDBALANCE_ULTRA_PYTHON
#define V4L2_CID_XILINX_PYTHON1300_SUBSAMPLING
#define V4L2_CID_XILINX_PYTHON1300_RXIF_REMAPPER_MODE