1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 /* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019, Google Inc. * * v4l2_camera_proxy.h - Proxy to V4L2 compatibility camera */ #ifndef __V4L2_CAMERA_PROXY_H__ #define __V4L2_CAMERA_PROXY_H__ #include <linux/videodev2.h> #include <map> #include <memory> #include <set> #include <sys/mman.h> #include <sys/types.h> #include <vector> #include <libcamera/camera.h> #include "v4l2_camera.h" using namespace libcamera; class V4L2CameraFile; class V4L2CameraProxy { public: V4L2CameraProxy(unsigned int index, std::shared_ptr<Camera> camera); int open(V4L2CameraFile *file); void close(V4L2CameraFile *file); void *mmap(void *addr, size_t length, int prot, int flags, off64_t offset); int munmap(void *addr, size_t length); int ioctl(V4L2CameraFile *file, unsigned long request, void *arg); private: bool validateBufferType(uint32_t type); bool validateMemoryType(uint32_t memory); void setFmtFromConfig(const StreamConfiguration &streamConfig); void querycap(std::shared_ptr<Camera> camera); int tryFormat(struct v4l2_format *arg); enum v4l2_priority maxPriority(); void updateBuffers(); void freeBuffers(); int vidioc_querycap(struct v4l2_capability *arg); int vidioc_enum_framesizes(V4L2CameraFile *file, struct v4l2_frmsizeenum *arg); int vidioc_enum_fmt(V4L2CameraFile *file, struct v4l2_fmtdesc *arg); int vidioc_g_fmt(V4L2CameraFile *file, struct v4l2_format *arg); int vidioc_s_fmt(V4L2CameraFile *file, struct v4l2_format *arg); int vidioc_try_fmt(V4L2CameraFile *file, struct v4l2_format *arg); int vidioc_g_priority(V4L2CameraFile *file, enum v4l2_priority *arg); int vidioc_s_priority(V4L2CameraFile *file, enum v4l2_priority *arg); int vidioc_enuminput(V4L2CameraFile *file, struct v4l2_input *arg); /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2019, Google Inc. * * signal.cpp - Signal test */ #include <iostream> #include <string.h> #include <libcamera/object.h> #include <libcamera/signal.h> #include "test.h" using namespace std; using namespace libcamera; static int valueStatic_ = 0; static void slotStatic(int value) { valueStatic_ = value; } static int slotStaticReturn() { return 0; } class SlotObject : public Object { public: void slot() { valueStatic_ = 1; } }; class BaseClass { public: /* * A virtual method is required in the base class, otherwise the compiler * will always store Object before BaseClass in memory. */ virtual ~BaseClass() { } unsigned int data_[32]; }; class SlotMulti : public BaseClass, public Object { public: void slot() { valueStatic_ = 1; } }; class SignalTest : public Test { protected: void slotVoid() { called_ = true; } void slotDisconnect() { called_ = true; signalVoid_.disconnect(this, &SignalTest::slotDisconnect); } void slotInteger1(int value) { values_[0] = value; } void slotInteger2(int value) { values_[1] = value; } void slotMultiArgs(int value, const std::string &name) { values_[2] = value; name_ = name; } int slotReturn() { return 0; } int init() { return 0; } int run() { /* ----------------- Signal -> !Object tests ---------------- */ /* Test signal emission and reception. */ called_ = false; signalVoid_.connect(this, &SignalTest::slotVoid); signalVoid_.emit(); if (!called_) { cout << "Signal emission test failed" << endl; return TestFail; } /* Test signal with parameters. */ values_[2] = 0; name_.clear(); signalMultiArgs_.connect(this, &SignalTest::slotMultiArgs); signalMultiArgs_.emit(42, "H2G2"); if (values_[2] != 42 || name_ != "H2G2") { cout << "Signal parameters test failed" << endl; return TestFail; } /* Test signal connected to multiple slots. */ memset(values_, 0, sizeof(values_)); valueStatic_ = 0; signalInt_.connect(this, &SignalTest::slotInteger1); signalInt_.connect(this, &SignalTest::slotInteger2); signalInt_.connect(&slotStatic); signalInt_.emit(42); if (values_[0] != 42 || values_[1] != 42 || values_[2] != 0 || valueStatic_ != 42) { cout << "Signal multi slot test failed" << endl; return TestFail; } /* Test disconnection of a single slot. */ memset(values_, 0, sizeof(values_)); signalInt_.disconnect(this, &SignalTest::slotInteger2); signalInt_.emit(42); if (values_[0] != 42 || values_[1] != 0 || values_[2] != 0) { cout << "Signal slot disconnection test failed" << endl; return TestFail; } /* Test disconnection of a whole object. */ memset(values_, 0, sizeof(values_)); signalInt_.disconnect(this); signalInt_.emit(42); if (values_[0] != 0 || values_[1] != 0 || values_[2] != 0) { cout << "Signal object disconnection test failed" << endl; return TestFail; } /* Test disconnection of a whole signal. */ memset(values_, 0, sizeof(values_)); signalInt_.connect(this, &SignalTest::slotInteger1); signalInt_.connect(this, &SignalTest::slotInteger2); signalInt_.disconnect(); signalInt_.emit(42); if (values_[0] != 0 || values_[1] != 0 || values_[2] != 0) { cout << "Signal object disconnection test failed" << endl; return TestFail; } /* Test disconnection from slot. */ signalVoid_.disconnect(); signalVoid_.connect(this, &SignalTest::slotDisconnect); signalVoid_.emit(); called_ = false; signalVoid_.emit(); if (called_) { cout << "Signal disconnection from slot test failed" << endl; return TestFail; } /* * Test connecting to slots that return a value. This targets * compilation, there's no need to check runtime results. */ signalVoid_.connect(slotStaticReturn); signalVoid_.connect(this, &SignalTest::slotReturn); /* ----------------- Signal -> Object tests ----------------- */ /* * Test automatic disconnection on object deletion. Connect the * slot twice to ensure all instances are disconnected. */ signalVoid_.disconnect(); SlotObject *slotObject = new SlotObject(); signalVoid_.connect(slotObject, &SlotObject::slot); signalVoid_.connect(slotObject, &SlotObject::slot); delete slotObject; valueStatic_ = 0; signalVoid_.emit(); if (valueStatic_ != 0) { cout << "Signal disconnection on object deletion test failed" << endl; return TestFail; } /* * Test that signal deletion disconnects objects. This shall * not generate any valgrind warning. */ Signal<> *dynamicSignal = new Signal<>(); slotObject = new SlotObject(); dynamicSignal->connect(slotObject, &SlotObject::slot); delete dynamicSignal; delete slotObject; /* * Test that signal manual disconnection from Object removes * the signal for the object. This shall not generate any * valgrind warning. */ dynamicSignal = new Signal<>(); slotObject = new SlotObject(); dynamicSignal->connect(slotObject, &SlotObject::slot); dynamicSignal->disconnect(slotObject); delete dynamicSignal; delete slotObject; /* * Test that signal manual disconnection from all slots removes * the signal for the object. This shall not generate any * valgrind warning. */ dynamicSignal = new Signal<>(); slotObject = new SlotObject(); dynamicSignal->connect(slotObject, &SlotObject::slot); dynamicSignal->disconnect(); delete dynamicSignal; delete slotObject; /* Exercise the Object slot code paths. */ slotObject = new SlotObject(); signalVoid_.connect(slotObject, &SlotObject::slot); valueStatic_ = 0; signalVoid_.emit(); if (valueStatic_ == 0) { cout << "Signal delivery for Object test failed" << endl; return TestFail; } delete slotObject; /* --------- Signal -> Object (multiple inheritance) -------- */ /* * Test automatic disconnection on object deletion. Connect the * slot twice to ensure all instances are disconnected. */ signalVoid_.disconnect(); SlotMulti *slotMulti = new SlotMulti(); signalVoid_.connect(slotMulti, &SlotMulti::slot); signalVoid_.connect(slotMulti, &SlotMulti::slot); delete slotMulti; valueStatic_ = 0; signalVoid_.emit(); if (valueStatic_ != 0) { cout << "Signal disconnection on object deletion test failed" << endl; return TestFail; } /* * Test that signal deletion disconnects objects. This shall * not generate any valgrind warning. */ dynamicSignal = new Signal<>(); slotMulti = new SlotMulti(); dynamicSignal->connect(slotMulti, &SlotMulti::slot); delete dynamicSignal; delete slotMulti; /* Exercise the Object slot code paths. */ slotMulti = new SlotMulti(); signalVoid_.connect(slotMulti, &SlotMulti::slot); valueStatic_ = 0; signalVoid_.emit(); if (valueStatic_ == 0) { cout << "Signal delivery for Object test failed" << endl; return TestFail; } delete slotMulti; return TestPass; } void cleanup() { } private: Signal<> signalVoid_; Signal<int> signalInt_; Signal<int, const std::string &> signalMultiArgs_; bool called_; int values_[3]; std::string name_; }; TEST_REGISTER(SignalTest)