/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2019, Google Inc. * * Test the IPA interface */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libcamera/internal/camera_manager.h" #include "libcamera/internal/device_enumerator.h" #include "libcamera/internal/global_configuration.h" #include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/ipa_module.h" #include "libcamera/internal/pipeline_handler.h" #include "test.h" using namespace libcamera; using namespace std; using namespace std::chrono_literals; class IPAInterfaceTest : public Test, public Object { public: IPAInterfaceTest() : trace_(ipa::vimc::IPAOperationNone) { } ~IPAInterfaceTest() { notifier_.reset(); ipa_.reset(); ipaManager_.reset(); cameraManager_.reset(); } protected: int init() override { cameraManager_ = make_unique(); /* Create a pipeline handler for vimc. */ const std::vector &factories = PipelineHandlerFactoryBase::factories(); for (const PipelineHandlerFactoryBase *factory : factories) { if (factory->name() == "vimc") { pipe_ = factory->create(cameraManager_.get()); break; } } if (!pipe_) { cerr << "Vimc pipeline not found" << endl; return TestPass; } /* Create the communication pipe. */ int pipefds[2]; int ret = pipe2(pipefds, O_NONBLOCK); if (ret) { ret = errno; cerr << "Failed to create IPA test pipe: " << strerror(ret) << endl; return TestFail; } pipeReadFd_ = UniqueFD(pipefds[0]); pipeWriteFd_ = SharedFD(pipefds[1]); notifier_ = std::make_unique(pipeReadFd_.get(), EventNotifier::Read, this); notifier_->activated.connect(this, &IPAInterfaceTest::readTrace); /* Create the IPA manager. */ ipaManager_ = std::make_unique(*cameraManager_); return TestPass; } int run() override { EventDispatcher *dispatcher = thread()->eventDispatcher(); Timer timer; ipa_ = ipaManager_->createIPA(pipe_.get(), 0, 0); if (!ipa_) { cerr << "Failed to create VIMC IPA interface" << endl; return TestFail; } /* Test initialization of IPA module. */ std::string conf = ipa_->configurationFile("vimc.conf"); Flags inFlags; Flags outFlags; int ret = ipa_->init(IPASettings{ conf, "vimc" }, pipeWriteFd_, ipa::vimc::IPAOperationInit, inFlags, &outFlags); if (ret < 0) { cerr << "IPA interface init() failed" << endl; return TestFail; } timer.start(1000ms); while (timer.isRunning() && trace_ != ipa::vimc::IPAOperationInit) dispatcher->processEvents(); if (trace_ != ipa::vimc::IPAOperationInit) { cerr << "Failed to test IPA initialization sequence" << endl; return TestFail; } /* Test start of IPA module. */ ipa_->start(); timer.start(1000ms); while (timer.isRunning() && trace_ != ipa::vimc::IPAOperationStart) dispatcher->processEvents(); if (trace_ != ipa::vimc::IPAOperationStart) { cerr << "Failed to test IPA start sequence" << endl; return TestFail; } /* Test stop of IPA module. */ ipa_->stop(); timer.start(1000ms); while (timer.isRunning() && trace_ != ipa::vimc::IPAOperationStop) dispatcher->processEvents(); if (trace_ != ipa::vimc::IPAOperationStop) { cerr << "Failed to test IPA stop sequence" << endl; return TestFail; } return TestPass; } private: void readTrace() { ssize_t s = read(notifier_->fd(), &trace_, sizeof(trace_)); if (s < 0) { int ret = errno; cerr << "Failed to read from IPA test pipe: " << strerror(ret) << endl; trace_ = ipa::vimc::IPAOperationNone; } } std::shared_ptr pipe_; std::unique_ptr ipa_; std::unique_ptr cameraManager_; std::unique_ptr ipaManager_; enum ipa::vimc::IPAOperationCode trace_; std::unique_ptr notifier_; UniqueFD pipeReadFd_; SharedFD pipeWriteFd_; }; TEST_REGISTER(IPAInterfaceTest)