REDAC HybridController
Firmware for LUCIDAC/REDAC Teensy
Loading...
Searching...
No Matches
protocol_oob.cpp
Go to the documentation of this file.
1// Copyright (c) 2024 anabrid GmbH
2// Contact: https://www.anabrid.com/licensing/
3// SPDX-License-Identifier: MIT OR GPL-2.0-or-later
4
5#include <bitset>
6#include <cstring>
7#include <sstream>
8#include <daq/daq.h>
9#include <proto/main.pb.h>
10#include <protocol/protocol_oob.h>
11#include <run/run.h>
12#include <utils/logging.h>
13#include <utils/streaming_json.h>
14#include <Arduino.h>
15
16
17
18
19void client::RunProtobufDataHandler::handle(const run::RunStateChange change,
20 const run::Run &run, const char *reason) {
21 pb_Envelope envelope;
22 auto& msg = transport::init_v1_message(envelope, pb_MessageV1_run_state_change_message_tag);
23 auto& run_state_change = msg.kind.run_state_change_message = pb_RunStateChangeMessage pb_RunStateChangeMessage_init_default;
24 run_state_change.has_run = true;
25 std::strncpy(run_state_change.run.id, run.id.c_str(), sizeof(run_state_change.run.id));
26 run_state_change.run.chunk = run.next_chunk();
27
28 run_state_change.has_time = true;
29 auto& time = run_state_change.time;
30 time.prefix = pb_Prefix_NANO;
31 time.value = change.t;
32
33 run_state_change.old = static_cast<pb_RunState>(change.old);
34 run_state_change.new_ = static_cast<pb_RunState>(change.new_);
35
36 if (reason) {
37 std::strncpy(run_state_change.reason, reason, sizeof(run_state_change.reason));
38 }
39
40 stream->write(envelope);
41}
42
43struct SizedPtr {
44 size_t size;
45 const void* data;
46};
47
48FASTRUN bool encode_byte_array(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
49 if (!pb_encode_tag_for_field(stream, field))
50 return false;
51
52 auto ptr = static_cast<SizedPtr*>(*arg);
53 return pb_encode_string(stream, static_cast<const uint8_t*>(ptr->data), ptr->size);
54}
55
56struct GainOffset {
57 double gain = 1.0;
58 double offset = 0.0;
59
60 void apply(double gain, double offset) {
61 this->gain *= gain;
62 this->offset = this->offset * gain + offset;
63 }
64};
65
66FASTRUN void client::RunProtobufDataHandler::prepare(const run::Run &run, size_t channel_stride) {
67 auto& msg = transport::init_v1_message(envelope, pb_MessageV1_run_data_message_tag);
68 auto& run_data = msg.kind.run_data_message;
69 run_data = pb_RunDataMessage pb_RunDataMessage_init_default;
70 run_data.has_entity = true;
71 run_data.has_run = true;
72 std::strncpy(run_data.run.id, run.id.c_str(), sizeof(run_data.run.id));
73
74 auto& entity = run_data.entity;
75 auto& entity_id = carrier::Carrier::get().get_entity_id();
76
77 std::stringstream ss;
78 ss << entity_id;
79 ss.read(entity.path, sizeof(entity.path));
80
81 run_data.has_data = true;
82 auto& data = run_data.data;
83 data.has_type = true;
84 data.type = {
85 .which_kind = pb_DataType_integer_tag,
86 .kind = {
87 .integer = {
88 .signess = pb_IntegerType_Signedness_Unsigned,
89 .bitwidth = 16
90 }
91 }
92 };
93
94 data.channel_stride = channel_stride;
95 data.data.funcs.encode = encode_byte_array;
96
97 auto& carrier = carrier::Carrier::get();
98 auto& adc_channels = carrier.get_adc_channels();
99
100 auto& channel_idx = data.channels_count = 0;
101 for (size_t idx = 0; idx < adc_channels.size(); ++idx) {
102 auto& channel = adc_channels[idx];
103 if (channel.src == carrier::ADCChannel::DISABLED) continue;
104
105 auto &pb_channel = data.channels[channel_idx];
106 pb_channel.idx = idx;
107
108 GainOffset gain_offset;
109
110 //adc gain and offset correction
111 gain_offset.apply(1.0, daq::details::raw_zero_offsets[idx]);
112
113 //discrete to float
114 constexpr double adc_discrete_gain = -0.00015265824;
115 constexpr double adc_discrete_offset = 1.25;
116 gain_offset.apply(adc_discrete_gain, adc_discrete_offset);
117
118 //user gain and offset
119 gain_offset.apply(channel.gain, channel.offset);
120
121 pb_channel.gain = gain_offset.gain;
122 pb_channel.offset = gain_offset.offset;
123 pb_channel.probe = channel.probe;
124 ++channel_idx;
125 }
126
127 chunk = 0;
128}
129
130FASTRUN run::RunHandleResult client::RunProtobufDataHandler::handle(const run::Run &run, uint16_t *data,
131 size_t sample_count) {
132 if (sample_count == 0)
133 return run::RunHandleResult::ok({});
134
135 auto& message = envelope.kind.message_v1;
136 auto& run_data = message.kind.run_data_message;
137
138 auto& pb_data = run_data.data;
139 if (pb_data.channels_count == 0)
140 return run::RunHandleResult::ok({});
141
142 pb_data.sample_count = sample_count;
143 run_data.run.chunk = run.next_chunk();
144 auto& values = pb_data.data;
145 values.funcs.encode = encode_byte_array;
146 SizedPtr sized_ptr{
147 .size = sample_count * pb_data.channel_stride * sizeof(uint16_t),
148 .data = reinterpret_cast<uint8_t*>(data)
149 };
150 values.arg = &sized_ptr;
151 return stream->write(envelope);
152}
153
154run::RunHandleResult client::RunProtobufDataHandler::handle_op_end(const run::Run &run,
155 std::array<std::array<float, 8>, 6> data) {
156 auto& msg = transport::init_v1_message(envelope, pb_MessageV1_run_data_end_message_tag);
157 auto& run_data = msg.kind.run_data_end_message;
158 run_data = pb_RunDataEndMessage pb_RunDataEndMessage_init_default;
159 run_data.has_run = true;
160 std::strncpy(run_data.run.id, run.id.c_str(), sizeof(run_data.run.id));
161 run_data.run.chunk = run.next_chunk();
162
163 run_data.has_entity = true;
164 auto& entity = run_data.entity;
165 auto& entity_id = carrier::Carrier::get().get_entity_id();
166 entity_id.copy(entity.path, sizeof(entity.path));
167
168 run_data.has_data = true;
169 auto& data_pb = run_data.data;
170 data_pb.sample_count = 1;
171 data_pb.channel_stride = 48;
172 data_pb.has_type = true;
173 data_pb.type = {
174 .which_kind = pb_DataType_float__tag,
175 .kind = {
176 .float_ = {
177 .bitwidth = 32
178 }
179 }
180 };
181
182 SizedPtr sized_ptr{
183 .size = 48 * sizeof(float),
184 .data = reinterpret_cast<void*>(data.data())
185 };
186
187 //cannot use adc_scaling, because config configurates only 8 channels
188 auto& idx = data_pb.channels_count = 0;
189 for (; idx < 48; ++idx) {
190 auto& scaling = data_pb.channels[idx];
191 scaling.idx = idx;
192 scaling.gain = 1.0;
193 scaling.offset = 0.0;
194 }
195
196 data_pb.data.funcs.encode = encode_byte_array;
197 data_pb.data.arg = &sized_ptr;
198 return stream->write(envelope);
199}
Definition daq.h:14
pb_MessageV1 & init_v1_message(pb_Envelope &envelope, pb_size_t which_kind)
Definition transport.cpp:32
FASTRUN bool encode_byte_array(pb_ostream_t *stream, const pb_field_t *field, void *const *arg)
void apply(double gain, double offset)
const void * data
size_t size