REDAC HybridController
Firmware for LUCIDAC/REDAC Teensy
Loading...
Searching...
No Matches
lucidac.cpp
Go to the documentation of this file.
1// Copyright (c) 2024 anabrid GmbH
2// Contact: https://www.anabrid.com/licensing/
3//
4// SPDX-License-Identifier: MIT OR GPL-2.0-or-later
5
6#include "pb_decode.h"
7
8#include <entity/visitor.h>
9#include <lucidac/lucidac.h>
10#include <utils/mac.h>
11
12platform::LUCIDAC::LUCIDAC(LUCIDAC_HAL *hardware)
13 : Carrier({Cluster(0)}, hardware), hardware(hardware) {}
14
15bool platform::LUCIDAC::init() {
16 LOG(ANABRID_DEBUG_INIT, __PRETTY_FUNCTION__);
17 if (!Carrier::init())
18 return false;
19
20 LOG(ANABRID_DEBUG_INIT, "Detecting front panel...");
21 if (!front_panel) {
22 front_panel = entities::detect<LUCIDACFrontPanel>(bus::address_from_tuple(bus::FRONTPLANE_BADDR, 0));
23 if (!front_panel) {
24 LOG_ALWAYS("Warning: Front panel is missing or unknown.");
25 } else {
26 LOG(ANABRID_DEBUG_INIT, "Initialising detected front panel...");
27 if (!front_panel->init()) {
28 LOG_ALWAYS("Error: Could not initialize front panel");
29 } else {
30 LOG(ANABRID_DEBUG_INIT, "Front panel initialized.");
31 }
32 }
33 }
34
35 return status::success();
36}
37
38void platform::LUCIDAC::reset(entities::ResetAction action) {
39 Carrier::reset(action);
40 if (front_panel)
41 front_panel->reset(action);
42
43 if (action.has(entities::ResetAction::CIRCUIT_RESET)) {
44 reset_acl_select();
45 reset_adc_channels();
46 }
47}
48
49status platform::LUCIDAC::route_in_external(uint8_t in, uint8_t i_out) {
50 if (in > 7)
51 return status("in must be less or equal to 7");
52
53 if (!clusters[0].iblock->connect(in + 24, i_out))
54 return status("I block connection not possible");
55 return status::success();
56}
57
58status platform::LUCIDAC::route_out_external(uint8_t u_in, uint8_t out, float c_factor) {
59 if (out > 7)
60 return status("out must be less or equal to 7");
61
62 if (!clusters[0].ublock->connect(u_in, out + 24))
63 return status("U block connection not possible");
64 if (!clusters[0].cblock->set_factor(out + 24, c_factor))
65 return status("C block configuration not possible");
66 return status::success();
67}
68
69std::vector<entities::Entity *> platform::LUCIDAC::get_child_entities() {
70 auto entities = this->Carrier::get_child_entities();
71 if (front_panel)
72 entities.push_back(front_panel);
73 return entities;
74}
75
76entities::Entity *platform::LUCIDAC::get_child_entity(std::string_view child_id) {
77 if (child_id == "FP")
78 return front_panel;
79 return this->carrier::Carrier::get_child_entity(child_id);
80}
81
82status platform::LUCIDAC::write_to_hardware() {
83 status error = Carrier::write_to_hardware();
84 if (front_panel)
85 front_panel->write_to_hardware().attach_to(error, "Front Panel write failed.");
86 if (!hardware->write_acl(acl_select))
87 error.attach(1 << 5, "Write ACL failed");
88 return error;
89}
90
91const std::array<platform::LUCIDAC::ACL, 8> &platform::LUCIDAC::get_acl_select() const {
92 return acl_select;
93}
94
95void platform::LUCIDAC::set_acl_select(const std::array<ACL, 8> &acl_select_) {
96 acl_select = acl_select_;
97}
98
99bool platform::LUCIDAC::set_acl_select(uint8_t idx, LUCIDAC::ACL acl) {
100 if (idx >= acl_select.size())
101 return false;
102 acl_select[idx] = acl;
103 return true;
104}
105
106void platform::LUCIDAC::reset_acl_select() {
107 std::fill(acl_select.begin(), acl_select.end(), ACL::INTERNAL_);
108}
109
110// this variant of the config saves full and partial connections from the U-block
111// as the Carrier class restores only
112status platform::LUCIDAC::calibrate_routes() {
113 LOG(ANABRID_DEBUG_CALIBRATION, __PRETTY_FUNCTION__);
114 status success = status::success();
115
116 // collect current I-block connections (includes partial connections due to
117 // analog IO)
118 auto& cluster = clusters[0];
119 std::array<std::vector<uint8_t>, blocks::IBlock::NUM_OUTPUTS> old_i_block_connections;
120 for (auto i_out_idx : blocks::IBlock::OUTPUT_IDX_RANGE())
121 for (auto i_in_idx : blocks::IBlock::INPUT_IDX_RANGE())
122 if (cluster.iblock->is_connected(i_in_idx, i_out_idx))
123 old_i_block_connections[i_out_idx].emplace_back(i_in_idx);
124
125 // disconnect ACLs for Carrier-based calibration
126 auto old_acl_selection = get_acl_select();
127 reset_acl_select();
128 if (!hardware->write_acl(acl_select))
129 success.attach("Writing ACL before calibrate_routes() failed");
130
131 success.attach(Carrier::calibrate_routes());
132
133 set_acl_select(old_acl_selection);
134 if (!hardware->write_acl(acl_select))
135 success.attach("Writing ACL after calibrate_routes() failed");
136
137 // Restore I-block connections
138 for (auto i_out_idx : blocks::IBlock::OUTPUT_IDX_RANGE())
139 for (auto i_in_idx : old_i_block_connections[i_out_idx])
140 if (!cluster.iblock->connect(i_in_idx, i_out_idx))
141 LOG_ANABRID_DEBUG_CALIBRATION("Connecting i-block failed");
142
143 if (!cluster.iblock->write_to_hardware())
144 success.attach("Restoring i-block failed");
145
146 LOG(ANABRID_DEBUG_CALIBRATION, __PRETTY_FUNCTION__);
147
148 return success;
149}
150
151ConfigResult platform::LUCIDAC::config(const pb_Config &cfg) {
152 if (cfg.which_kind == pb_Config_port_config_tag) {
153 auto& port_config = cfg.kind.port_config;
154
155 reset_acl_select();
156 for (size_t idx = 0; idx < port_config.states_count ; ++idx) {
157 acl_select[idx] = (port_config.states[idx] == pb_PortConfig_AclState_EXTERNAL) ?
158 ACL::EXTERNAL_ : ACL::INTERNAL_;
159 }
160
161 if (!hardware->write_acl(acl_select))
162 return ConfigResult::err("cannot write acl select to hardware");
163
164 return ConfigResult::ok(true);
165 }
166
167 return Carrier::config(cfg);
168}
169
170void platform::LUCIDAC::extract(entities::ExtractVisitor &collector) {
171 Carrier::extract(collector);
172
173 auto& cfg = collector.create(pb_Config_port_config_tag);
174 auto& lucidac_config = cfg.kind.port_config;
175
176 lucidac_config.states_count = acl_select.size();
177 for (size_t idx = 0; idx < acl_select.size(); idx++) {
178 lucidac_config.states[idx] =
179 (acl_select[idx] == ACL::EXTERNAL_)
180 ? pb_PortConfig_AclState_EXTERNAL
181 : pb_PortConfig_AclState_INTERNAL;
182 }
183}
184
185status platform::LUCIDAC::calibrate_offsets() {
186 LOG(ANABRID_DEBUG_CALIBRATION, __PRETTY_FUNCTION__);
187 status success = status::success();
188
189 auto old_acl_selection = get_acl_select();
190 reset_acl_select();
191 if (!hardware->write_acl(acl_select))
192 success.attach("Writing ACL before calibrate_offsets() failed");
193
194 success.attach(Carrier::calibrate_offsets());
195
196 set_acl_select(old_acl_selection);
197 if (!hardware->write_acl(acl_select))
198 success.attach("Writing ACL after calibrate_offsets() failed");
199
200 LOG(ANABRID_DEBUG_CALIBRATION, __PRETTY_FUNCTION__);
201
202 return success;
203}
utils::status status
Definition daq.h:21
static constexpr int success
Definition flasher.cpp:275