[{"id":29026,"web_url":"https://patchwork.libcamera.org/comment/29026/","msgid":"<urtr3pxbq36yjlxmcijs37acv6nlf5cn7anbq45av4wpvi2pon@yhg6mndl42fu>","date":"2024-03-21T11:28:58","subject":"Re: [PATCH v3 04/16] libcamera: delayed_controls: Update unit tests\n\tto expected semantics","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"Hi Stefan\n\nOn Tue, Mar 19, 2024 at 01:05:05PM +0100, Stefan Klug wrote:\n> This patches changes the tests in a way DelayedControls is expected to\n> work. It does not require a interface change in DelayedControls.\n>\n> The changes are:\n> - It is expected that for every apply() there was a previous push().\n> - When a control is pushed for frame 0, that request is not lost, but\n>   applied as soon as possible\n>\n> Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\n> ---\n>  test/delayed_controls.cpp | 256 +++++++++++++++++++++++++++++++-------\n>  1 file changed, 209 insertions(+), 47 deletions(-)\n>\n> diff --git a/test/delayed_controls.cpp b/test/delayed_controls.cpp\n> index a8ce9828..fe183de5 100644\n> --- a/test/delayed_controls.cpp\n> +++ b/test/delayed_controls.cpp\n> @@ -84,11 +84,8 @@ protected:\n>  \t\tdev_->setControls(&ctrls);\n>  \t\tdelayed->reset();\n>\n> -\t\t/* Trigger the first frame start event */\n> -\t\tdelayed->applyControls(0);\n> -\n>  \t\t/* Test control without delay are set at once. */\n> -\t\tfor (unsigned int i = 1; i < 100; i++) {\n> +\t\tfor (unsigned int i = 0; i < 100; i++) {\n>  \t\t\tint32_t value = 100 + i;\n>\n>  \t\t\tctrls.set(V4L2_CID_BRIGHTNESS, value);\n> @@ -121,25 +118,30 @@ protected:\n>  \t\tControlList ctrls;\n>\n>  \t\t/* Reset control to value that will be first in test. */\n> -\t\tint32_t expected = 4;\n> -\t\tctrls.set(V4L2_CID_BRIGHTNESS, expected);\n> +\t\tint32_t initial = 4;\n> +\t\tctrls.set(V4L2_CID_BRIGHTNESS, initial);\n>  \t\tdev_->setControls(&ctrls);\n>  \t\tdelayed->reset();\n>\n> -\t\t/* Trigger the first frame start event */\n> -\t\tdelayed->applyControls(0);\n> +\t\t/* Push a request for frame 0 */\n> +\t\tctrls.set(V4L2_CID_BRIGHTNESS, 10);\n> +\t\tdelayed->push(ctrls);\n>\n>  \t\t/* Test single control with delay. */\n> -\t\tfor (unsigned int i = 1; i < 100; i++) {\n> +\t\tfor (unsigned int i = 0; i < 100; i++) {\n>  \t\t\tint32_t value = 10 + i;\n> +\t\t\tint32_t expected = i < 1 ? initial : value;\n\nThat's a bit weird to read as then to me you expect 'value ==\nexpected'\n>\n> -\t\t\tctrls.set(V4L2_CID_BRIGHTNESS, value);\n> +\t\t\t/* push the request for frame i+1 */\n> +\t\t\tctrls.set(V4L2_CID_BRIGHTNESS, value + 1);\n\nWhile the 'value' you're actually pushing is 'value + 1'\n\n>  \t\t\tdelayed->push(ctrls);\n>\n>  \t\t\tdelayed->applyControls(i);\n>\n>  \t\t\tControlList result = delayed->get(i);\n>  \t\t\tint32_t brightness = result.get(V4L2_CID_BRIGHTNESS).get<int32_t>();\n> +\t\t\tControlList ctrlsV4L = dev_->getControls({ V4L2_CID_BRIGHTNESS });\n> +\t\t\tint32_t brightnessV4L = ctrlsV4L.get(V4L2_CID_BRIGHTNESS).get<int32_t>();\n>  \t\t\tif (brightness != expected) {\n>  \t\t\t\tcerr << \"Failed single control with delay\"\n>  \t\t\t\t     << \" frame \" << i\n> @@ -149,7 +151,121 @@ protected:\n>  \t\t\t\treturn TestFail;\n>  \t\t\t}\n>\n> -\t\t\texpected = value;\n> +\t\t\tif (i > 0 && brightnessV4L != value + 1) {\n\nThis I don't get it.\n\nAs I read it, you get the 'current' brightness from the video device\nand you expect it to be equal to the value you just pushed, which I\nwould instead expect to get realized at the -next- frame (frame delay\n= 1). What am I missing ?\n\n> +\t\t\t\tcerr << \"Failed single control with delay\"\n> +\t\t\t\t     << \" frame \" << i\n> +\t\t\t\t     << \" expected V4L \" << value + 1\n> +\t\t\t\t     << \" got \" << brightnessV4L\n> +\t\t\t\t     << endl;\n> +\t\t\t\treturn TestFail;\n> +\t\t\t}\n> +\t\t}\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +\n> +\t/* This fails on the old delayed controls implementation */\n> +\tint singleControlWithDelayStartUp()\n\nI really must have missed something, as this seems identical to the\nprevious function\n\nThis is the diff I get between the two\n\n-------------------------------------------------------------------------------\n2c2,3\n< \tint singleControlWithDelay()\n---\n> \t/* This fails on the old delayed controls implementation */\n> \tint singleControlWithDelayStartUp()\n17c18\n< \t\t/* Push a request for frame 0 */\n---\n> \t\t/* push a request for frame 0 */\n35a37\n>\n37c39\n< \t\t\t\tcerr << \"Failed single control with delay\"\n---\n> \t\t\t\tcerr << \"Failed single control with delay start up\"\n46c48\n< \t\t\t\tcerr << \"Failed single control with delay\"\n---\n> \t\t\t\tcerr << \"Failed single control with delay start up\"\n-------------------------------------------------------------------------------\n\n> +\t{\n> +\t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {\n> +\t\t\t{ V4L2_CID_BRIGHTNESS, { 1, false } },\n> +\t\t};\n> +\t\tstd::unique_ptr<DelayedControls> delayed =\n> +\t\t\tstd::make_unique<DelayedControls>(dev_.get(), delays);\n> +\t\tControlList ctrls;\n> +\n> +\t\t/* Reset control to value that will be first in test. */\n> +\t\tint32_t initial = 4;\n> +\t\tctrls.set(V4L2_CID_BRIGHTNESS, initial);\n> +\t\tdev_->setControls(&ctrls);\n> +\t\tdelayed->reset();\n> +\n> +\t\t/* push a request for frame 0 */\n> +\t\tctrls.set(V4L2_CID_BRIGHTNESS, 10);\n> +\t\tdelayed->push(ctrls);\n> +\n> +\t\t/* Test single control with delay. */\n> +\t\tfor (unsigned int i = 0; i < 100; i++) {\n> +\t\t\tint32_t value = 10 + i;\n> +\t\t\tint32_t expected = i < 1 ? initial : value;\n> +\n> +\t\t\t/* push the request for frame i+1 */\n> +\t\t\tctrls.set(V4L2_CID_BRIGHTNESS, value + 1);\n> +\t\t\tdelayed->push(ctrls);\n> +\n> +\t\t\tdelayed->applyControls(i);\n> +\n> +\t\t\tControlList result = delayed->get(i);\n> +\t\t\tint32_t brightness = result.get(V4L2_CID_BRIGHTNESS).get<int32_t>();\n> +\t\t\tControlList ctrlsV4L = dev_->getControls({ V4L2_CID_BRIGHTNESS });\n> +\t\t\tint32_t brightnessV4L = ctrlsV4L.get(V4L2_CID_BRIGHTNESS).get<int32_t>();\n> +\n> +\t\t\tif (brightness != expected) {\n> +\t\t\t\tcerr << \"Failed single control with delay start up\"\n> +\t\t\t\t     << \" frame \" << i\n> +\t\t\t\t     << \" expected \" << expected\n> +\t\t\t\t     << \" got \" << brightness\n> +\t\t\t\t     << endl;\n> +\t\t\t\treturn TestFail;\n> +\t\t\t}\n> +\n> +\t\t\tif (i > 0 && brightnessV4L != value + 1) {\n> +\t\t\t\tcerr << \"Failed single control with delay start up\"\n> +\t\t\t\t     << \" frame \" << i\n> +\t\t\t\t     << \" expected V4L \" << value + 1\n> +\t\t\t\t     << \" got \" << brightnessV4L\n> +\t\t\t\t     << endl;\n> +\t\t\t\treturn TestFail;\n> +\t\t\t}\n> +\t\t}\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +\n> +\t/* This fails on the old delayed controls implementation */\n> +\tint doNotLoseFirstRequest()\n> +\t{\n> +\t\t/* no delay at all */\n> +\t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {\n> +\t\t\t{ V4L2_CID_BRIGHTNESS, { 0, false } },\n> +\t\t};\n> +\t\tstd::unique_ptr<DelayedControls> delayed =\n> +\t\t\tstd::make_unique<DelayedControls>(dev_.get(), delays);\n> +\t\tControlList ctrls;\n> +\n> +\t\t/* Reset control to value that will be first in test. */\n> +\t\tint32_t initial = 4;\n> +\t\tctrls.set(V4L2_CID_BRIGHTNESS, initial);\n> +\t\tdev_->setControls(&ctrls);\n> +\t\tdelayed->reset();\n> +\n> +\t\t/* push a request for frame 0 */\n> +\t\tint32_t expected = 10;\n> +\t\tctrls.set(V4L2_CID_BRIGHTNESS, expected);\n> +\t\tdelayed->push(ctrls);\n> +\t\tdelayed->applyControls(0);\n> +\n> +\t\tControlList result = delayed->get(0);\n> +\t\tint32_t brightness = result.get(V4L2_CID_BRIGHTNESS).get<int32_t>();\n> +\t\tControlList ctrlsV4L = dev_->getControls({ V4L2_CID_BRIGHTNESS });\n> +\t\tint32_t brightnessV4L = ctrlsV4L.get(V4L2_CID_BRIGHTNESS).get<int32_t>();\n> +\n> +\t\tif (brightness != expected) {\n\n\nIs this testing only frame #0, right ?\n\nSo you set a control value with 0 delay, apply it, and make sure it\ngets applied and overwites the initial value from the video device.\n\nConsidering that controls handled with delayed controls will always\n(?) have a delay, I'm not sure this situation will ever be possible in\na real use case ? Or will there be cases where controls won't have a\ndelay ?\n\n> +\t\t\tcerr << \"Failed doNotLoseFirstRequest\"\n> +\t\t\t     << \" frame \" << 0\n> +\t\t\t     << \" expected \" << expected\n> +\t\t\t     << \" got \" << brightness\n> +\t\t\t     << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (brightnessV4L != expected) {\n> +\t\t\tcerr << \"Failed doNotLoseFirstRequest\"\n> +\t\t\t     << \" frame \" << 0\n> +\t\t\t     << \" expected V4L \" << expected\n> +\t\t\t     << \" got \" << brightnessV4L\n> +\t\t\t     << endl;\n> +\t\t\treturn TestFail;\n>  \t\t}\n>\n>  \t\treturn TestPass;\n> @@ -157,7 +273,7 @@ protected:\n>\n>  \tint dualControlsWithDelay()\n>  \t{\n> -\t\tstatic const unsigned int maxDelay = 2;\n> +\t\tstatic const int maxDelay = 2;\n>\n>  \t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {\n>  \t\t\t{ V4L2_CID_BRIGHTNESS, { 1, false } },\n> @@ -174,15 +290,21 @@ protected:\n>  \t\tdev_->setControls(&ctrls);\n>  \t\tdelayed->reset();\n>\n> -\t\t/* Trigger the first frame start event */\n> -\t\tdelayed->applyControls(0);\n> +\t\t/* push two requests into the queue */\n> +\t\tctrls.set(V4L2_CID_BRIGHTNESS, 10);\n> +\t\tctrls.set(V4L2_CID_CONTRAST, 10);\n> +\t\tdelayed->push(ctrls);\n> +\t\tctrls.set(V4L2_CID_BRIGHTNESS, 11);\n> +\t\tctrls.set(V4L2_CID_CONTRAST, 11);\n> +\t\tdelayed->push(ctrls);\n>\n>  \t\t/* Test dual control with delay. */\n> -\t\tfor (unsigned int i = 1; i < 100; i++) {\n> +\t\tfor (unsigned int i = 0; i < 100; i++) {\n>  \t\t\tint32_t value = 10 + i;\n>\n> -\t\t\tctrls.set(V4L2_CID_BRIGHTNESS, value);\n> -\t\t\tctrls.set(V4L2_CID_CONTRAST, value + 1);\n> +\t\t\t/* we are pushing 2 frames ahead */\n> +\t\t\tctrls.set(V4L2_CID_BRIGHTNESS, value + 2);\n> +\t\t\tctrls.set(V4L2_CID_CONTRAST, value + 2);\n>  \t\t\tdelayed->push(ctrls);\n>\n>  \t\t\tdelayed->applyControls(i);\n> @@ -190,17 +312,32 @@ protected:\n>  \t\t\tControlList result = delayed->get(i);\n>  \t\t\tint32_t brightness = result.get(V4L2_CID_BRIGHTNESS).get<int32_t>();\n>  \t\t\tint32_t contrast = result.get(V4L2_CID_CONTRAST).get<int32_t>();\n> -\t\t\tif (brightness != expected || contrast != expected + 1) {\n> -\t\t\t\tcerr << \"Failed dual controls\"\n> -\t\t\t\t     << \" frame \" << i\n> -\t\t\t\t     << \" brightness \" << brightness\n> -\t\t\t\t     << \" contrast \" << contrast\n> -\t\t\t\t     << \" expected \" << expected\n> -\t\t\t\t     << endl;\n> -\t\t\t\treturn TestFail;\n> -\t\t\t}\n>\n> -\t\t\texpected = i < maxDelay ? expected : value - 1;\n> +\t\t\tControlList ctrlsV4L = dev_->getControls({ V4L2_CID_BRIGHTNESS, V4L2_CID_CONTRAST });\n> +\t\t\tint32_t brightnessV4L = ctrlsV4L.get(V4L2_CID_BRIGHTNESS).get<int32_t>();\n> +\t\t\tint32_t contrastV4L = ctrlsV4L.get(V4L2_CID_CONTRAST).get<int32_t>();\n> +\n> +\t\t\tif (i > maxDelay) {\n> +\t\t\t\tif (brightness != value || contrast != value) {\n> +\t\t\t\t\tcerr << \"Failed dual controls\"\n> +\t\t\t\t\t     << \" frame \" << i\n> +\t\t\t\t\t     << \" brightness \" << brightness\n> +\t\t\t\t\t     << \" contrast \" << contrast\n> +\t\t\t\t\t     << \" expected \" << value\n> +\t\t\t\t\t     << endl;\n> +\t\t\t\t\treturn TestFail;\n> +\t\t\t\t}\n> +\t\t\t\tif (brightnessV4L != value + 1 || contrastV4L != value + maxDelay) {\n> +\t\t\t\t\tcerr << \"Failed dual controls\"\n> +\t\t\t\t\t     << \" frame \" << i\n> +\t\t\t\t\t     << \" brightnessV4L \" << brightnessV4L\n> +\t\t\t\t\t     << \" expected \" << value + 1\n> +\t\t\t\t\t     << \" contrastV4L \" << contrastV4L\n> +\t\t\t\t\t     << \" expected \" << value + maxDelay\n> +\t\t\t\t\t     << endl;\n> +\t\t\t\t\treturn TestFail;\n> +\t\t\t\t}\n> +\t\t\t}\n\nI might have missed the behavioral change you tried to capture here\nbetween your forthcoming delay controls changes and the current\nversion. If I'm not mistaken the test ignores the first two frames,\nyou don't see any change related to the startup condition ?\n\n>  \t\t}\n>\n>  \t\treturn TestPass;\n> @@ -208,7 +345,7 @@ protected:\n>\n>  \tint dualControlsMultiQueue()\n>  \t{\n> -\t\tstatic const unsigned int maxDelay = 2;\n> +\t\tstatic const int maxDelay = 2;\n>\n>  \t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> delays = {\n>  \t\t\t{ V4L2_CID_BRIGHTNESS, { 1, false } },\n> @@ -218,22 +355,19 @@ protected:\n>  \t\t\tstd::make_unique<DelayedControls>(dev_.get(), delays);\n>  \t\tControlList ctrls;\n>\n> -\t\t/* Reset control to value that will be first two frames in test. */\n> -\t\tint32_t expected = 100;\n> -\t\tctrls.set(V4L2_CID_BRIGHTNESS, expected);\n> -\t\tctrls.set(V4L2_CID_CONTRAST, expected);\n> +\t\t/* Reset control to a value that will be first two frames in test. */\n> +\t\tint32_t initial = 100;\n> +\t\tctrls.set(V4L2_CID_BRIGHTNESS, initial);\n> +\t\tctrls.set(V4L2_CID_CONTRAST, initial);\n>  \t\tdev_->setControls(&ctrls);\n>  \t\tdelayed->reset();\n>\n> -\t\t/* Trigger the first frame start event */\n> -\t\tdelayed->applyControls(0);\n> -\n>  \t\t/*\n> -\t\t * Queue all controls before any fake frame start. Note we\n> +\t\t * Queue all controls before applyControls(). Note we\n>  \t\t * can't queue up more then the delayed controls history size\n> -\t\t * which is 16. Where one spot is used by the reset control.\n> +\t\t * which is 16.\n>  \t\t */\n> -\t\tfor (unsigned int i = 0; i < 15; i++) {\n> +\t\tfor (unsigned int i = 0; i < 14; i++) {\n>  \t\t\tint32_t value = 10 + i;\n>\n>  \t\t\tctrls.set(V4L2_CID_BRIGHTNESS, value);\n> @@ -241,9 +375,9 @@ protected:\n>  \t\t\tdelayed->push(ctrls);\n>  \t\t}\n>\n> -\t\t/* Process all queued controls. */\n> -\t\tfor (unsigned int i = 1; i < 16; i++) {\n> -\t\t\tint32_t value = 10 + i - 1;\n> +\t\t/* Process 2 frames less than queued, so that the V4L controls are correct */\n> +\t\tfor (unsigned int i = 0; i < 12; i++) {\n> +\t\t\tint32_t expected = i < maxDelay ? initial : 10 + i;\n>\n>  \t\t\tdelayed->applyControls(i);\n>\n> @@ -251,6 +385,11 @@ protected:\n>\n>  \t\t\tint32_t brightness = result.get(V4L2_CID_BRIGHTNESS).get<int32_t>();\n>  \t\t\tint32_t contrast = result.get(V4L2_CID_CONTRAST).get<int32_t>();\n> +\n> +\t\t\tControlList ctrlsV4L = dev_->getControls({ V4L2_CID_BRIGHTNESS, V4L2_CID_CONTRAST });\n> +\t\t\tint32_t brightnessV4L = ctrlsV4L.get(V4L2_CID_BRIGHTNESS).get<int32_t>();\n> +\t\t\tint32_t contrastV4L = ctrlsV4L.get(V4L2_CID_CONTRAST).get<int32_t>();\n> +\n>  \t\t\tif (brightness != expected || contrast != expected) {\n>  \t\t\t\tcerr << \"Failed multi queue\"\n>  \t\t\t\t     << \" frame \" << i\n> @@ -261,7 +400,17 @@ protected:\n>  \t\t\t\treturn TestFail;\n>  \t\t\t}\n>\n> -\t\t\texpected = i < maxDelay ? expected : value - 1;\n> +\t\t\t/* Check v4l values after they've settled */\n> +\t\t\tif (i >= maxDelay && (brightnessV4L != expected + 1 || contrastV4L != expected + maxDelay)) {\n> +\t\t\t\tcerr << \"Failed multi queue\"\n> +\t\t\t\t     << \" frame \" << i\n> +\t\t\t\t     << \" brightnessV4L \" << brightnessV4L\n> +\t\t\t\t     << \" expected \" << expected + 1\n> +\t\t\t\t     << \" contrastV4L \" << contrastV4L\n> +\t\t\t\t     << \" expected \" << expected + maxDelay\n> +\t\t\t\t     << endl;\n> +\t\t\t\treturn TestFail;\n> +\t\t\t}\n>  \t\t}\n>\n>  \t\treturn TestPass;\n> @@ -269,27 +418,40 @@ protected:\n>\n>  \tint run() override\n>  \t{\n> -\t\tint ret;\n> +\t\tint ret = 0;\n> +\t\tbool failed = false;\n>\n>  \t\t/* Test single control without delay. */\n>  \t\tret = singleControlNoDelay();\n>  \t\tif (ret)\n> -\t\t\treturn ret;\n> +\t\t\tfailed = true;\n>\n>  \t\t/* Test single control with delay. */\n>  \t\tret = singleControlWithDelay();\n>  \t\tif (ret)\n> -\t\t\treturn ret;\n> +\t\t\tfailed = true;\n> +\n> +\t\t/* Test single control with delay. */\n> +\t\tret = singleControlWithDelayStartUp();\n> +\t\tif (ret)\n> +\t\t\tfailed = true;\n> +\n> +\t\tret = doNotLoseFirstRequest();\n> +\t\tif (ret)\n> +\t\t\tfailed = true;\n>\n>  \t\t/* Test dual controls with different delays. */\n>  \t\tret = dualControlsWithDelay();\n>  \t\tif (ret)\n> -\t\t\treturn ret;\n> +\t\t\tfailed = true;\n>\n>  \t\t/* Test control values produced faster than consumed. */\n>  \t\tret = dualControlsMultiQueue();\n>  \t\tif (ret)\n> -\t\t\treturn ret;\n> +\t\t\tfailed = true;\n> +\n> +\t\tif (failed)\n> +\t\t\treturn TestFail;\n>\n>  \t\treturn TestPass;\n>  \t}\n> --\n> 2.40.1\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 6B82BC3272\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 21 Mar 2024 11:29:05 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 81E1063055;\n\tThu, 21 Mar 2024 12:29:04 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 5C40662827\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 21 Mar 2024 12:29:02 +0100 (CET)","from ideasonboard.com (unknown\n\t[IPv6:2001:b07:5d2e:52c9:cc1e:e404:491f:e6ea])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 0CD677E9;\n\tThu, 21 Mar 2024 12:28:33 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"Rc5UraoE\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1711020514;\n\tbh=gzwHEedS3ucfnGxfb1Cct1Nm482AFxM0x8zjsOQ6EQg=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=Rc5UraoEYd/AH6ilyazf+dB/XjxG1O+HLMnE2ejJY5k5bOsnFGhE+3j4WjSEixT4G\n\t27dmoSaKc5gBCprC2j9Y/4GlWtw83gneXgf0eG4FBhb63XGwvf4GqvLxMFkU1sx3ZA\n\tSiFgT3g7/seDb/quXvgACpRDTZ78ua7sW+Kzib6o=","Date":"Thu, 21 Mar 2024 12:28:58 +0100","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Stefan Klug <stefan.klug@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH v3 04/16] libcamera: delayed_controls: Update unit tests\n\tto expected semantics","Message-ID":"<urtr3pxbq36yjlxmcijs37acv6nlf5cn7anbq45av4wpvi2pon@yhg6mndl42fu>","References":"<20240319120517.362082-1-stefan.klug@ideasonboard.com>\n\t<20240319120517.362082-5-stefan.klug@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20240319120517.362082-5-stefan.klug@ideasonboard.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]