/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2020, Google Inc. * * ipa_data_serializer_test.cpp - Test serializing/deserializing with IPADataSerializer */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libcamera/internal/device_enumerator.h" #include "libcamera/internal/ipa_data_serializer.h" #include "libcamera/internal/ipa_manager.h" #include "libcamera/internal/ipa_module.h" #include "libcamera/internal/pipeline_handler.h" #include "serialization_test.h" #include "test.h" using namespace std; using namespace libcamera; static const ControlInfoMap Controls = ControlInfoMap({ { &controls::AeEnable, ControlInfo(false, true) }, { &controls::ExposureTime, ControlInfo(0, 999999) }, { &controls::AnalogueGain, ControlInfo(1.0f, 32.0f) }, { &controls::ColourGains, ControlInfo(0.0f, 32.0f) }, { &controls::Brightness, ControlInfo(-1.0f, 1.0f) }, }, controls::controls); namespace libcamera { static bool operator==(const ControlInfoMap &lhs, const ControlInfoMap &rhs) { return SerializationTest::equals(lhs, rhs); } } /* namespace libcamera */ template int testPodSerdes(T in) { std::vector buf; std::vector fds; std::tie(buf, fds) = IPADataSerializer::serialize(in); T out = IPADataSerializer::deserialize(buf, fds); if (in == out) return TestPass; char *name = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr); cerr << "Deserialized " << name << " doesn't match original" << endl; free(name); return TestFail; } template int testVectorSerdes(const std::vector &in, ControlSerializer *cs = nullptr) { std::vector buf; std::vector fds; std::tie(buf, fds) = IPADataSerializer>::serialize(in, cs); std::vector out = IPADataSerializer>::deserialize(buf, fds, cs); if (in == out) return TestPass; char *name = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr); cerr << "Deserialized std::vector<" << name << "> doesn't match original" << endl; free(name); return TestFail; } template int testMapSerdes(const std::map &in, ControlSerializer *cs = nullptr) { std::vector buf; std::vector fds; std::tie(buf, fds) = IPADataSerializer>::serialize(in, cs); std::map out = IPADataSerializer>::deserialize(buf, fds, cs); if (in == out) return TestPass; char *nameK = abi::__cxa_demangle(typeid(K).name(), nullptr, nullptr, nullptr); char *nameV = abi::__cxa_demangle(typeid(V).name(), nullptr, nullptr, nullptr); cerr << "Deserialized std::map<" << nameK << ", " << nameV << "> doesn't match original" << endl; free(nameK); free(nameV); return TestFail; } class IPADataSerializerTest : public CameraTest, public Test { public: IPADataSerializerTest() : CameraTest("platform/vimc.0 Sensor B") { } protected: int init() override { return status_; } int run() override { int ret; ret = testControls(); if (ret != TestPass) return ret; ret = testVector(); if (ret != TestPass) return ret; ret = testMap(); if (ret != TestPass) return ret; ret = testPod(); if (ret != TestPass) return ret; return TestPass; } private: ControlList generateControlList(const ControlInfoMap &infoMap) { /* Create a control list with three controls. */ ControlList list(infoMap); list.set(controls::Brightness, 0.5f); list.set(controls::Contrast, 1.2f); list.set(controls::Saturation, 0.2f); return list; } int testControls() { ControlSerializer cs; const ControlInfoMap &infoMap = camera_->controls(); ControlList list = generateControlList(infoMap); std::vector infoMapBuf; std::tie(infoMapBuf, std::ignore) = IPADataSerializer::serialize(infoMap, &cs); std::vector listBuf; std::tie(listBuf, std::ignore) = IPADataSerializer::serialize(list, &cs); const ControlInfoMap infoMapOut = IPADataSerializer::deserialize(infoMapBuf, &cs); ControlList listOut = IPADataSerializer::deserialize(listBuf, &cs); if (!SerializationTest::equals(infoMap, infoMapOut)) { cerr << "Deserialized map doesn't match original" << endl; return TestFail; } if (!SerializationTest::equals(list, listOut)) { cerr << "Deserialized list doesn't match original" << endl; return TestFail; } return TestPass; } int testVector() { ControlSerializer cs; /* * We don't test FileDescriptor serdes because it dup()s, so we * can't check for equality. */ std::vector vecUint8 = { 1, 2, 3, 4, 5, 6 }; std::vector vecUint16 = { 1, 2, 3, 4, 5, 6 }; std::vector vecUint32 = { 1, 2, 3, 4, 5, 6 }; std::vector vecUint64 = { 1, 2, 3, 4, 5, 6 }; std::vector vecInt8 = { 1, 2, 3, -4, 5, -6 }; std::vector vecInt16 = { 1, 2, 3, -4, 5, -6 }; std::vector vecInt32 = { 1, 2, 3, -4, 5, -6 }; std::vector vecInt64 = { 1, 2, 3, -4, 5, -6 }; std::vector vecFloat = { 1.1, 2.2, 3.3, -4.4, 5.5, -6.6 }; std::vector vecDouble = { 1.1, 2.2, 3.3, -4.4, 5.5, -6.6 }; std::vector vecBool = { true, true, false, false, true, false }; std::vector vecString = { "foo", "bar", "baz" }; std::vector vecControlInfoMap = { camera_->controls(), Controls, }; std::vector buf; std::vector fds; if (testVectorSerdes(vecUint8) != TestPass) return TestFail; if (testVectorSerdes(vecUint16) != TestPass) return TestFail; if (testVectorSerdes(vecUint32) != TestPass) return TestFail; if (testVectorSerdes(vecUint64) != TestPass) return TestFail; if (testVectorSerdes(vecInt8) != TestPass) return TestFail; if (testVectorSerdes(vecInt16) != TestPass) return TestFail; if (testVectorSerdes(vecInt32) != TestPass) return TestFail; if (testVectorSerdes(vecInt64) != TestPass) return TestFail; if (testVectorSerdes(vecFloat) != TestPass) return TestFail; if (testVectorSerdes(vecDouble) != TestPass) return TestFail; if (testVectorSerdes(vecBool) != TestPass) return TestFail; if (testVectorSerdes(vecString) != TestPass) return TestFail; if (testVectorSerdes(vecControlInfoMap, &cs) != TestPass) return TestFail; return TestPass; } int testMap() { ControlSerializer cs; /* * Realistically, only string and integral keys. * Test simple, complex, and nested compound value. */ std::map mapUintStr = { { 101, "foo" }, { 102, "bar" }, { 103, "baz" } }; std::map mapIntStr = { { 101, "foo" }, { -102, "bar" }, { -103, "baz" } }; std::map mapStrStr = { { "a", "foo" }, { "b", "bar" }, { "c", "baz" } }; std::map mapUintCIM = { { 201, camera_->controls() }, { 202, Controls } }; std::map mapIntCIM = { { 201, camera_->controls() }, { -202, Controls } }; std::map mapStrCIM = { { "a", camera_->controls() }, { "b", Controls } }; std::map> mapUintBVec = { { 301, { 1, 2, 3 } }, { 302, { 4, 5, 6 } }, { 303, { 7, 8, 9 } } }; std::map> mapIntBVec = { { 301, { 1, 2, 3 } }, { -302, { 4, 5, 6} }, { -303, { 7, 8, 9 } } }; std::map> mapStrBVec = { { "a", { 1, 2, 3 } }, { "b", { 4, 5, 6 } }, { "c", { 7, 8, 9 } } }; std::vector buf; std::vector fds; if (testMapSerdes(mapUintStr) != TestPass) return TestFail; if (testMapSerdes(mapIntStr) != TestPass) return TestFail; if (testMapSerdes(mapStrStr) != TestPass) return TestFail; if (testMapSerdes(mapUintCIM, &cs) != TestPass) return TestFail; if (testMapSerdes(mapIntCIM, &cs) != TestPass) return TestFail; if (testMapSerdes(mapStrCIM, &cs) != TestPass) return TestFail; if (testMapSerdes(mapUintBVec) != TestPass) return TestFail; if (testMapSerdes(mapIntBVec) != TestPass) return TestFail; if (testMapSerdes(mapStrBVec) != TestPass) return TestFail; return TestPass; } int testPod() { uint32_t u32min = std::numeric_limits::min(); uint32_t u32max = std::numeric_limits::max(); uint32_t u32one = 1; int32_t i32min = std::numeric_limits::min(); int32_t i32max = std::numeric_limits::max(); int32_t i32one = 1; uint64_t u64min = std::numeric_limits::min(); uint64_t u64max = std::numeric_limits::max(); uint64_t u64one = 1; int64_t i64min = std::numeric_limits::min(); int64_t i64max = std::numeric_limits::max(); int64_t i64one = 1; float flow = std::numeric_limits::lowest(); float fmin = std::numeric_limits::min(); float fmax = std::numeric_limits::max(); float falmostOne = 1 + 1.0e-37; double dlow = std::numeric_limits::lowest(); double dmin = std::numeric_limits::min(); double dmax = std::numeric_limits::max(); double dalmostOne = 1 + 1.0e-307; bool t = true; bool f = false; std::stringstream ss; for (unsigned int i = 0; i < (1 << 11); i++) ss << "0123456789"; std::string strLong = ss.str(); std::string strEmpty = ""; std::vector buf; std::vector fds; if (testPodSerdes(u32min) != TestPass) return TestFail; if (testPodSerdes(u32max) != TestPass) return TestFail; if (testPodSerdes(u32one) != TestPass) return TestFail; if (testPodSerdes(i32min) != TestPass) return TestFail; if (testPodSerdes(i32max) != TestPass) return TestFail; if (testPodSerdes(i32one) != TestPass) return TestFail; if (testPodSerdes(u64min) != TestPass) return TestFail; if (testPodSerdes(u64max) != TestPass) return TestFail; if (testPodSerdes(u64one) != TestPass) return TestFail; if (testPodSerdes(i64min) != TestPass) return TestFail; if (testPodSerdes(i64max) != TestPass) return TestFail; if (testPodSerdes(i64one) != TestPass) return TestFail; if (testPodSerdes(flow) != TestPass) return TestFail; if (testPodSerdes(fmin) != TestPass) return TestFail; if (testPodSerdes(fmax) != TestPass) return TestFail; if (testPodSerdes(falmostOne) != TestPass) return TestFail; if (testPodSerdes(dlow) != TestPass) return TestFail; if (testPodSerdes(dmin) != TestPass) return TestFail; if (testPodSerdes(dmax) != TestPass) return TestFail; if (testPodSerdes(dalmostOne) != TestPass) return TestFail; if (testPodSerdes(t) != TestPass) return TestFail; if (testPodSerdes(f) != TestPass) return TestFail; if (testPodSerdes(strLong) != TestPass) return TestFail; if (testPodSerdes(strEmpty) != TestPass) return TestFail; return TestPass; } }; TEST_REGISTER(IPADataSerializerTest)