summaryrefslogtreecommitdiff
path: root/test/ipa/ipa_interface_test.cpp
blob: 0bdeb167a6759753064560e989ee30595e363397 (plain)
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * ipa_interface_test.cpp - Test the IPA interface
 */

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

#include <iostream>

#include <libcamera/event_dispatcher.h>
#include <libcamera/event_notifier.h>
#include <libcamera/timer.h>

#include <ipa/ipa_vimc.h>

#include "device_enumerator.h"
#include "ipa_manager.h"
#include "ipa_module.h"
#include "pipeline_handler.h"
#include "test.h"
#include "thread.h"

using namespace std;
using namespace libcamera;

class IPAInterfaceTest : public Test, public Object
{
public:
	IPAInterfaceTest()
		: trace_(IPAOperationNone), notifier_(nullptr), fd_(-1)
	{
	}

	~IPAInterfaceTest()
	{
		delete notifier_;
	}

protected:
	int init() override
	{
		/* Create a pipeline handler for vimc. */
		std::vector<PipelineHandlerFactory *> &factories =
			PipelineHandlerFactory::factories();
		for (PipelineHandlerFactory *factory : factories) {
			if (factory->name() == "PipelineHandlerVimc") {
				pipe_ = factory->create(nullptr);
				break;
			}
		}

		if (!pipe_) {
			cerr << "Vimc pipeline not found" << endl;
			return TestPass;
		}

		/* Create and open the communication FIFO. */
		int ret = mkfifo(VIMC_IPA_FIFO_PATH, S_IRUSR | S_IWUSR);
		if (ret) {
			ret = errno;
			cerr << "Failed to create IPA test FIFO at '"
			     << VIMC_IPA_FIFO_PATH << "': " << strerror(ret)
			     << endl;
			return TestFail;
		}

		ret = open(VIMC_IPA_FIFO_PATH, O_RDONLY | O_NONBLOCK);
		if (ret < 0) {
			ret = errno;
			cerr << "Failed to open IPA test FIFO at '"
			     << VIMC_IPA_FIFO_PATH << "': " << strerror(ret)
			     << endl;
			unlink(VIMC_IPA_FIFO_PATH);
			return TestFail;
		}
		fd_ = ret;

		notifier_ = new EventNotifier(fd_, EventNotifier::Read, this);
		notifier_->activated.connect(this, &IPAInterfaceTest::readTrace);

		return TestPass;
	}

	int run() override
	{
		EventDispatcher *dispatcher = thread()->eventDispatcher();
		Timer timer;

		ipa_ = IPAManager::instance()->createIPA(pipe_.get(), 0, 0);
		if (!ipa_) {
			cerr << "Failed to create VIMC IPA interface" << endl;
			return TestFail;
		}

		/* Test initialization of IPA module. */
		ipa_->init();
		timer.start(1000);
		while (timer.isRunning() && trace_ != IPAOperationInit)
			dispatcher->processEvents();

		if (trace_ != IPAOperationInit) {
			cerr << "Failed to test IPA initialization sequence"
			     << endl;
			return TestFail;
		}

		return TestPass;
	}

	void cleanup() override
	{
		close(fd_);
		unlink(VIMC_IPA_FIFO_PATH);
	}

private:
	void readTrace(EventNotifier *notifier)
	{
		ssize_t s = read(notifier->fd(), &trace_, sizeof(trace_));
		if (s < 0) {
			int ret = errno;
			cerr << "Failed to read from IPA test FIFO at '"
			     << VIMC_IPA_FIFO_PATH << "': " << strerror(ret)
			     << endl;
			trace_ = IPAOperationNone;
		}
	}

	std::shared_ptr<PipelineHandler> pipe_;
	std::unique_ptr<IPAInterface> ipa_;
	enum IPAOperationCode trace_;
	EventNotifier *notifier_;
	int fd_;
};

TEST_REGISTER(IPAInterfaceTest)