ChimeraTK-DeviceAccess 03.29.00
Loading...
Searching...
No Matches
testDoubleBufferAccessor.cc
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
4#define BOOST_TEST_MODULE testDoubleBufferAccessor
5#include "Device.h"
6#include "DummyBackend.h"
8
9#include <boost/test/unit_test.hpp>
10
11#include <future>
12
13using namespace ChimeraTK;
14
15// ------------------------------------------------------------
16// Test that a full read cycle completes successfully.
17// Observable behaviour: after read(), the accessor holds data
18// and the enable register is left in the enabled state (value 1).
19BOOST_AUTO_TEST_CASE(test_full_read_cycle) {
21 device.open("(dummy?map=simpleJsonFile.jmap)");
22
23 // Get double-buffer accessor through the normal public API.
24 // DAQ.MACRO_PULSE_NUMBER is a simple 1-element uint32 register
25 // which uses double-buffering with index 1.
26 auto accessor = device.getOneDRegisterAccessor<int>("/DAQ/MACRO_PULSE_NUMBER", 1, 0);
27
28 // Perform a full read cycle through the public API
29 accessor.read();
30
31 // After the read cycle, we have valid data
32 BOOST_CHECK(accessor.dataValidity() != ChimeraTK::DataValidity::faulty);
33}
34
35// ------------------------------------------------------------
36// Test that concurrent reads on the same double-buffered register
37// complete successfully. The transfer lock ensures sequential
38// access to the handshake registers, so no data corruption occurs.
39BOOST_AUTO_TEST_CASE(test_concurrent_reads_same_register) {
41 device.open("(dummy?map=simpleJsonFile.jmap)");
42
43 // Two accessors on the same register
44 auto accessor1 = device.getOneDRegisterAccessor<int>("/DAQ/MACRO_PULSE_NUMBER", 1, 0);
45 auto accessor2 = device.getOneDRegisterAccessor<int>("/DAQ/MACRO_PULSE_NUMBER", 1, 0);
46
47 // Read concurrently from two threads. Both must complete without
48 // deadlock or data corruption.
49 auto future = std::async(std::launch::async, [&] { accessor1.read(); });
50 accessor2.read();
51
52 auto status = future.wait_for(std::chrono::milliseconds(200));
53 BOOST_CHECK(status == std::future_status::ready);
54}
55
56// ------------------------------------------------------------
57// Test that two registers sharing the same double buffering handshake
58// (index 1: DAQ.MACRO_PULSE_NUMBER and DAQ.FD both use DAQ.DOUBLE_BUF.ENA[1])
59// can be read concurrently without issues.
60BOOST_AUTO_TEST_CASE(test_shared_handshake_two_registers) {
62 device.open("(dummy?map=simpleJsonFile.jmap)");
63
64 // Two accessors with the same handshake index (index 1)
65 auto mpnAccessor1 = device.getOneDRegisterAccessor<int>("/DAQ/MACRO_PULSE_NUMBER", 1, 0);
66 auto mpnAccessor2 = device.getOneDRegisterAccessor<int>("/DAQ/MACRO_PULSE_NUMBER", 1, 0);
67
68 // Read concurrently from two threads
69 auto future = std::async(std::launch::async, [&] { mpnAccessor1.read(); });
70 mpnAccessor2.read();
71
72 auto status = future.wait_for(std::chrono::milliseconds(200));
73 BOOST_CHECK(status == std::future_status::ready);
74}
75
76// ------------------------------------------------------------
77// Test that buffer selection works with INACTIVE_BUF_ID=1.
78// This exercises the _currentBuffer==1 branch.
79BOOST_AUTO_TEST_CASE(test_buffer_selection_current_buffer_1) {
81 device.open("(dummy?map=simpleJsonFile.jmap)");
82
83 // Write INACTIVE_BUF_ID[index=1] = 1
84 auto inactiveBuf = device.getOneDRegisterAccessor<uint32_t>("/DAQ/DOUBLE_BUF/INACTIVE_BUF_ID", 1, 1);
85 inactiveBuf[0] = 1;
86 inactiveBuf.write();
87
88 auto accessor = device.getOneDRegisterAccessor<int>("/DAQ/MACRO_PULSE_NUMBER", 1, 0);
89
90 // Do a full read cycle with the _currentBuffer==1 path
91 accessor.read();
92
93 // Must not crash, and must have valid data
94 BOOST_CHECK(accessor.dataValidity() != ChimeraTK::DataValidity::faulty);
95}
Class allows to read/write registers from device.
Definition Device.h:39
OneDRegisterAccessor< UserType > getOneDRegisterAccessor(const RegisterPath &registerPathName, size_t numberOfWords=0, size_t wordOffsetInRegister=0, const AccessModeFlags &flags=AccessModeFlags({})) const
Get a OneDRegisterAccessor object for the given register.
Definition Device.h:276
void open(std::string const &aliasName)
Open a device by the given alias name from the DMAP file.
Definition Device.cc:58
@ faulty
The data is considered valid.
BOOST_AUTO_TEST_CASE(test_full_read_cycle)
ctk::Device device