/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2019, Google Inc. * * object-invoke.cpp - Cross-thread Object method invocation test */ #include #include #include #include #include "libcamera/internal/thread.h" #include "test.h" using namespace std; using namespace libcamera; class InvokedObject : public Object { public: enum Status { NoCall, InvalidThread, CallReceived, }; InvokedObject() : status_(NoCall) { } Status status() const { return status_; } int value() const { return value_; } void reset() { status_ = NoCall; value_ = 0; } void method(int value) { if (Thread::current() != thread()) status_ = InvalidThread; else status_ = CallReceived; value_ = value; } void methodWithReference([[maybe_unused]] const int &value) { } int methodWithReturn() { return 42; } private: Status status_; int value_; }; class ObjectInvokeTest : public Test { protected: int run() { EventDispatcher *dispatcher = Thread::current()->eventDispatcher(); /* * Test that queued method invocation in the same thread goes * through the event dispatcher. */ object_.invokeMethod(&InvokedObject::method, ConnectionTypeQueued, 42); if (object_.status() != InvokedObject::NoCall) { cerr << "Method not invoked asynchronously" << endl; return TestFail; } dispatcher->processEvents(); switch (object_.status()) { case InvokedObject::NoCall: cout << "Method not invoked for main thread" << endl; return TestFail; case InvokedObject::InvalidThread: cout << "Method invoked in incorrect thread for main thread" << endl; return TestFail; default: break; } if (object_.value() != 42) { cout << "Method invoked with incorrect value for main thread" << endl; return TestFail; } /* * Test that blocking invocation is delivered directly when the * caller and callee live in the same thread. */ object_.reset(); object_.invokeMethod(&InvokedObject::method, ConnectionTypeBlocking, 42); switch (object_.status()) { case InvokedObject::NoCall: cout << "Method not invoked for main thread (blocking)" << endl; return TestFail; case InvokedObject::InvalidThread: cout << "Method invoked in incorrect thread for main thread (blocking)" << endl; return TestFail; default: break; } /* * Move the object to a thread and verify that auto method * invocation is delivered in the correct thread. */ object_.reset(); object_.moveToThread(&thread_); thread_.start(); object_.invokeMethod(&InvokedObject::method, ConnectionTypeBlocking, 42); switch (object_.status()) { case InvokedObject::NoCall: cout << "Method not invoked for custom thread" << endl; return TestFail; case InvokedObject::InvalidThread: cout << "Method invoked in incorrect thread for custom thread" << endl; return TestFail; default: break; } if (object_.value() != 42) { cout << "Method invoked with incorrect value for custom thread" << endl; return TestFail; } /* Test that direct method invocation bypasses threads. */ object_.reset(); object_.invokeMethod(&InvokedObject::method, ConnectionTypeDirect, 42); switch (object_.status()) { case InvokedObject::NoCall: cout << "Method not invoked for custom thread" << endl; return TestFail; case InvokedObject::CallReceived: cout << "Method invoked in incorrect thread for direct call" << endl; return TestFail; default: break; } if (object_.value() != 42) { cout << "Method invoked with incorrect value for direct call" << endl; return TestFail; } /* * Test invoking a method that takes reference arguments. This * targets compilation, there's no need to check runtime * results. */ object_.invokeMethod(&InvokedObject::methodWithReference, ConnectionTypeBlocking, 42); /* Test invoking a method that returns a value. */ int ret = object_.invokeMethod(&InvokedObject::methodWithReturn, ConnectionTypeBlocking); if (ret != 42) { cout << "Method invoked return incorrect value (" << ret << ")" << endl; return TestFail; } return TestPass; } void cleanup() { thread_.exit(0); thread_.wait(); } private: Thread thread_; InvokedObject object_; }; TEST_REGISTER(ObjectInvokeTest) 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 109 110 111 112 113 114 115
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2020, Linaro
 *
 * Based on test/pipeline/ipu3/ipu3_pipeline_test.cpp
 *
 * rkisp1_pipeline_test.cpp - Rockchip RK3399 rkisp1 pipeline test
 */

#include <iostream>

#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <libcamera/camera.h>
#include <libcamera/camera_manager.h>

#include "libcamera/internal/device_enumerator.h"
#include "libcamera/internal/media_device.h"
#include "libcamera/internal/media_object.h"

#include "test.h"

using namespace std;
using namespace libcamera;

/*
 * Verify that the RK3399 pipeline handler gets matched and cameras
 * are enumerated correctly.
 *
 * The test is supposed to be run on rockchip platform.
 *
 * The test lists all cameras registered in the system, if any camera is
 * available at all.
 */
class RKISP1PipelineTest : public Test
{
protected:
	int init();
	int run();
	void cleanup();

private:
	CameraManager *cameraManager_;
	unsigned int sensors_;
};

int RKISP1PipelineTest::init()
{
	unique_ptr<DeviceEnumerator> enumerator = DeviceEnumerator::create();
	if (!enumerator) {
		cerr << "Failed to create device enumerator" << endl;
		return TestFail;
	}

	if (enumerator->enumerate()) {
		cerr << "Failed to enumerate media devices" << endl;
		return TestFail;
	}

	DeviceMatch dm("rkisp1");

	std::shared_ptr<MediaDevice> rkisp1 = enumerator->search(dm);
	if (!rkisp1) {
		cerr << "Failed to find rkisp1: test skip" << endl;
		return TestSkip;
	}

	int ret = rkisp1->populate();
	if (ret) {
		cerr << "Failed to populate media device "
		     << rkisp1->deviceNode() << endl;
		return TestFail;
	}

	sensors_ = 0;
	const vector<MediaEntity *> &entities = rkisp1->entities();
	for (MediaEntity *entity : entities) {
		if (entity->function() == MEDIA_ENT_F_CAM_SENSOR)
			sensors_++;
	}

	cameraManager_ = new CameraManager();
	ret = cameraManager_->start();
	if (ret) {
		cerr << "Failed to start the CameraManager" << endl;
		return TestFail;
	}

	return 0;
}

int RKISP1PipelineTest::run()
{
	auto cameras = cameraManager_->cameras();
	for (const std::shared_ptr<Camera> &cam : cameras)
		cout << "Found camera '" << cam->id() << "'" << endl;

	if (cameras.size() != sensors_) {
		cerr << cameras.size() << " cameras registered, but " << sensors_
		     << " were expected" << endl;
		return TestFail;
	}

	return TestPass;
}

void RKISP1PipelineTest::cleanup()
{
	cameraManager_->stop();
	delete cameraManager_;
}

TEST_REGISTER(RKISP1PipelineTest)