20#include <boost/algorithm/string.hpp>
21#include <ipcq/adapter.hpp>
22#include <ipcq/reader.hpp>
24#include <numapp/numapolicies.hpp>
25#include <numapp/thread.hpp>
29template <
typename RecInfoType>
31 SetState(State::PREPARING, State::STOPPED,
"tried to prepare a non-stopped ipcqRecordingUnit");
33 m_file_path =
file_path / (GetId() +
".fits");
36 auto policies = numapp::NumaPolicies();
37 if (m_cpu_affinity.has_value()) {
39 numapp::Cpumask::MakeFromCpuStringAll(std::to_string(m_cpu_affinity.value()).c_str());
44 numapp::MakeThread(m_unit_id.substr(0, 15),
policies, [&]() { return Process(); });
47template <
typename RecInfoType>
52template <
typename RecInfoType>
55 if (m_process_thread.joinable()) {
56 m_process_thread.join();
58 std::vector<std::filesystem::path>
files;
60 files.push_back(*m_file_path);
67template <
typename RecInfoType>
69 if (GetState() == State::RUNNING) {
74 DataPointPath(fmt::format(RTR_PATH_SUBSAMPLE_FACTOR, m_comp_id, m_unit_id));
78 m_rtr,
DataPointPath(fmt::format(RTR_PATH_TELEMETRY_SUBSET, m_comp_id, m_unit_id)));
82 DataPointPath(fmt::format(RTR_PATH_START_SAMPLE_ID, m_comp_id, m_unit_id));
86 DataPointPath(fmt::format(RTR_PATH_STOP_AFTER_NUM_SAMPLES, m_comp_id, m_unit_id));
90template <
typename RecInfoType>
92 using namespace std::chrono_literals;
95 std::vector<typename RecInfoType::Topic>
buffer;
96 buffer.reserve(MAX_SAMPLES_READ);
98 const std::error_code
ok{};
99 std::pair<std::error_code, size_t> result;
102 m_samples_written.Store(0);
103 m_last_observed_sample_id.Store(0);
105 auto reader = ipcq::Reader<typename RecInfoType::Topic>(m_queue_name.c_str());
109 if (
not SetState(State::IDLE, State::PREPARING)) {
112 "IpcqRecordingUnit not in preparing before starting thread");
114 SetFailed(std::current_exception());
119 while (m_stop ==
false) {
120 switch (GetState()) {
124 SetState(State::WAITING,
126 "IpcqRecordingUnit not in IDLE before entering WAITING");
128 CII_THROW(IpcqError,
"Error resetting ipcq Reader");
132 std::this_thread::sleep_for(1
ms);
135 case State::WAITING: {
137 if (
not(result.first ==
ok or result.first == ipcq::Error::Timeout)) {
138 std::string error =
"Error reading from ipcq: " + result.first.message();
142 m_last_observed_sample_id.Store(
element.sample_id);
146 if ((m_last_observed_sample_id.Load() >= m_start_sample_id - 1)
and
147 (
not HasLeaders()
or (HasLeaders()
and HasFirstLeaderStarted()))) {
148 m_sampling_counter = 0;
149 SetState(State::RUNNING,
151 "Expected to be in WAITING, before going RUNNING");
155 case State::RUNNING: {
156 if (HasLeaders()
and HasLastLeaderFinished()) {
157 SetState(State::FINISHED,
159 "Expected to be in WAITING, before going RUNNING");
170 if (m_subsample_factor > 1) {
171 m_sampling_counter = m_sampling_counter % m_subsample_factor;
172 if (m_sampling_counter == 0) {
175 to_skip = std::min(
to_read, m_subsample_factor - m_sampling_counter);
183 m_last_observed_sample_id.Store(
element.sample_id);
184 auto t1 = std::chrono::steady_clock::now();
188 m_output.SetColumnLength(
sample);
189 m_output.Open(*m_file_path);
193 auto t2 = std::chrono::steady_clock::now();
194 m_dur_monitor->Tick(
t2 -
t1);
195 m_freq_estimator->Tick();
197 if (m_stop_after_num_samples > 0
and
198 m_samples_written.Load() >= m_stop_after_num_samples) {
199 SetState(State::FINISHED,
201 "Expected to be in RUNNING, before going FINISHED");
209 m_sampling_counter += result.second;
211 if (
not(result.first ==
ok or result.first == ipcq::Error::Timeout)) {
212 std::string error =
"Error reading from ipcq: " + result.first.message();
218 std::this_thread::sleep_for(1
ms);
234 }
catch (
const FitsDataRecorderFitsError&
e) {
239 SetFailed(std::current_exception());
244template <
typename RecInfoType>
245typename RecInfoType::Recorder::DisabledFields
247 typename RecInfoType::Recorder::DisabledFields result{};
249 if (
not rtr.DataPointExists(path)) {
252 auto fields =
rtr.GetDataPoint<std::vector<std::string>>(path);
258 if (
fields.size() > std::tuple_size<typename RecInfoType::Recorder::DisabledFields>::value) {
267 for (
const auto& name :
fields) {
271 if (name == RecInfoType::COLUMNS[
i].name) {
279 std::string{
"Invalid disabled fields setting: Could not find field '" + name +
This class provides a wrapper for a data point path.
Definition dataPointPath.hpp:74
This Exception is raised when a invalid setting was used in the runtime repo.
Definition exceptions.hpp:338
This Exception is raised when the state change requested is invalid.
Definition exceptions.hpp:324
Recording Unit that can record from shared memory queue.
Definition ipcqRecordingUnit.hpp:52
std::vector< std::filesystem::path > Stop() override
Stop the recording thread and wait for it's termination.
Definition ipcqRecordingUnit.ipp:53
void Update() override
Update settings from RuntimeRepo.
Definition ipcqRecordingUnit.ipp:68
void Prepare(const std::filesystem::path &file_path) override
Prepare the recording thread and start recording.
Definition ipcqRecordingUnit.ipp:30
static RecInfoType::Recorder::DisabledFields GetDisabled(RepositoryIf &rtr, const DataPointPath &sub_path)
get disabled fields from a DataPoint in the runtime repo.
Definition ipcqRecordingUnit.ipp:246
void Start() override
Start the recording.
Definition ipcqRecordingUnit.ipp:48
Abstract interface providing basic read and write facilities to a repository.
Definition repositoryIf.hpp:104
FitsRecorder allows to write ColumnData to into fits files in a specified directory.
Definition commandReplier.cpp:22
elt::mal::future< std::string > InjectReqRepEvent(StateMachineEngine &engine)
Definition malEventInjector.hpp:23