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 <lucidac/lucidac.h>
7#include <utils/mac.h>
8
9FLASHMEM platform::LUCIDAC::LUCIDAC(LUCIDAC_HAL *hardware)
10 : Carrier({Cluster(0)}, hardware), hardware(hardware) {}
11
12FLASHMEM bool platform::LUCIDAC::init() {
13 if (!Carrier::init())
14 return false;
15
16 LOG(ANABRID_DEBUG_INIT, "Detecting front panel...");
17 if (!front_panel) {
18 front_panel = entities::detect<LUCIDACFrontPanel>(bus::address_from_tuple(2, 0));
19 if (!front_panel) {
20 LOG_ALWAYS("Warning: Front panel is missing or unknown.");
21 }
22 }
23
24 LOG(ANABRID_DEBUG_INIT, "Initialising detected front panel...");
25 if (front_panel && !front_panel->init()) {
26 // return false; // No, this is NOT fatal. Continue working.
27 LOG_ALWAYS("Error: Could not initialize front panel");
28 }
29 LOG(ANABRID_DEBUG_INIT, "Front panel initialized.");
30
31 return utils::status::success();
32}
33
34FLASHMEM void platform::LUCIDAC::reset(entities::ResetAction action) {
35 Carrier::reset(action);
36 if (front_panel)
37 front_panel->reset(action);
38
39 if (action.has(entities::ResetAction::CIRCUIT_RESET)) {
40 reset_acl_select();
41 reset_adc_channels();
42 }
43}
44
45FLASHMEM std::vector<entities::Entity *> platform::LUCIDAC::get_child_entities() {
46 auto entities = this->Carrier::get_child_entities();
47 if (front_panel)
48 entities.push_back(front_panel);
49 return entities;
50}
51
52FLASHMEM entities::Entity *platform::LUCIDAC::get_child_entity(const std::string &child_id) {
53 if (child_id == "FP")
54 return front_panel;
55 return this->carrier::Carrier::get_child_entity(child_id);
56}
57
58FLASHMEM utils::status platform::LUCIDAC::write_to_hardware() {
59 utils::status error = Carrier::write_to_hardware();
60 if (front_panel)
61 front_panel->write_to_hardware().attach_to(error, "Front Panel write failed.");
62 if (!hardware->write_acl(acl_select))
63 error.attach(1 << 5, "Write ACL failed");
64 return error;
65}
66
67FLASHMEM const std::array<platform::LUCIDAC::ACL, 8> &platform::LUCIDAC::get_acl_select() const {
68 return acl_select;
69}
70
71FLASHMEM void platform::LUCIDAC::set_acl_select(const std::array<ACL, 8> &acl_select_) {
72 acl_select = acl_select_;
73}
74
75FLASHMEM bool platform::LUCIDAC::set_acl_select(uint8_t idx, LUCIDAC::ACL acl) {
76 if (idx >= acl_select.size())
77 return false;
78 acl_select[idx] = acl;
79 return true;
80}
81
82FLASHMEM void platform::LUCIDAC::reset_acl_select() {
83 std::fill(acl_select.begin(), acl_select.end(), ACL::INTERNAL_);
84}
85
86FLASHMEM bool platform::LUCIDAC::calibrate_routes() {
87 auto old_acl_selection = get_acl_select();
88 reset_acl_select();
89 if (!hardware->write_acl(acl_select))
90 return false;
91
92 if (!Carrier::calibrate_routes())
93 return false;
94
95 set_acl_select(old_acl_selection);
96 return hardware->write_acl(acl_select);
97}
98
99FLASHMEM utils::status platform::LUCIDAC::config_self_from_json(JsonObjectConst cfg) {
100 auto res = Carrier::config_self_from_json(cfg);
101 if (!res)
102 return res;
103
104 for (auto cfgItr = cfg.begin(); cfgItr != cfg.end(); ++cfgItr) {
105 if (cfgItr->key() == "adc_channels") {
106 auto res = _config_adc_from_json(cfgItr->value());
107 if (!res)
108 return utils::status(530, "Could not configure ADCs from configuration.");
109 } else if (cfgItr->key() == "acl_select") {
110 auto res = _config_acl_from_json(cfgItr->value());
111 if (!res)
112 return utils::status(531, "Could not configure ACLs from configuration.");
113 } else if (strlen(cfgItr->key().c_str()) >= 1 && cfgItr->key().c_str()[0] == '/') {
114 // An sub-entity is refered to. This is already handled by
115 // config_from_json() towards the children so it is ignored here.
116 } else {
117 return utils::status(532, "LUCIDAC: Unknown configuration key");
118 }
119 }
120
121 return utils::status::success();
122}
123
124FLASHMEM bool platform::LUCIDAC::_config_adc_from_json(const JsonVariantConst &cfg) {
125 if (!cfg.is<JsonArrayConst>())
126 return false;
127
128 auto cfg_adc_channels = cfg.as<JsonArrayConst>();
129 for (size_t i = 0; i < cfg_adc_channels.size() && i < adc_channels.size(); i++) {
130 adc_channels[i] = cfg_adc_channels[i].isNull() ? ADC_CHANNEL_DISABLED : cfg_adc_channels[i];
131 }
132 return hardware->write_adc_bus_mux(adc_channels);
133}
134
135FLASHMEM bool platform::LUCIDAC::_config_acl_from_json(const JsonVariantConst &cfg) {
136 if (!cfg.is<JsonArrayConst>())
137 return false;
138
139 auto cfg_acl_select = cfg.as<JsonArrayConst>();
140 for (size_t i = 0; i < cfg_acl_select.size() && i < acl_select.size(); i++) {
141 if (cfg_acl_select[i] == "internal") {
142 acl_select[i] = ACL::INTERNAL_;
143 } else if (cfg_acl_select[i] == "external") {
144 acl_select[i] = ACL::EXTERNAL_;
145 } else {
146 LOG_ALWAYS("platform::LUCIDAC::config_self_from_json: Expected acl_select[i] to be either 'internal' "
147 "or 'external' string")
148 return false;
149 }
150 }
151 return hardware->write_acl(acl_select);
152}
153
154FLASHMEM void platform::LUCIDAC::config_self_to_json(JsonObject &cfg) {
155 // TODO: This code is very quick and dirty. Use JSON custom converters to make nicer.
156
157 auto cfg_adc_channels = cfg.createNestedArray("adc_channels");
158 auto cfg_acl_select = cfg.createNestedArray("acl_select");
159
160 for (size_t i = 0; i < adc_channels.size(); i++) {
161 if (adc_channels[i] == ADC_CHANNEL_DISABLED)
162 cfg_adc_channels.add(nullptr); // json "none"
163 else
164 cfg_adc_channels.add(adc_channels[i]);
165 }
166
167 for (size_t i = 0; i < acl_select.size(); i++)
168 cfg_acl_select.add(acl_select[i] == ACL::INTERNAL_ ? "internal" : "external");
169}
Definition leds.h:7