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.h"
7#include "utils/mac.h"
8
10 4'000'000, MSBFIRST, SPI_MODE2 /* chip expects SPI MODE0, but CLK is inverted on the way */};
11
12FLASHMEM LUCIDAC::LUCIDAC(LUCIDAC_HAL *hardware) : Carrier({Cluster(0)}, hardware), hardware(hardware) {}
13
14FLASHMEM LUCIDAC::LUCIDAC() : LUCIDAC(new LUCIDAC_HAL()) {}
15
17 : f_acl_prg(bus::address_from_tuple(CARRIER_MADDR, ACL_PRG_FADDR), true),
18 f_acl_upd(bus::address_from_tuple(CARRIER_MADDR, ACL_UPD_FADDR)),
19 f_acl_clr(bus::address_from_tuple(CARRIER_MADDR, ACL_CRL_FADDR)),
20 f_adc_switcher_prg(bus::address_from_tuple(CARRIER_MADDR, ADC_PRG_FADDR),
21 F_ADC_SWITCHER_PRG_SPI_SETTINGS),
22 f_adc_switcher_sync(bus::address_from_tuple(CARRIER_MADDR, ADC_STROBE_FADDR)),
23 f_adc_switcher_sr_reset(bus::address_from_tuple(CARRIER_MADDR, ADC_RESET_SR_FADDR)),
24 f_adc_switcher_matrix_reset(bus::address_from_tuple(CARRIER_MADDR, ADC_RESET_8816_FADDR)),
25 f_temperature(bus::address_from_tuple(CARRIER_MADDR, TEMPERATURE_FADDR)) {}
26
27FLASHMEM bool LUCIDAC_HAL::write_acl(std::array<LUCIDAC_HAL::ACL, 8> acl) {
28 uint8_t sr = 0;
29 for (size_t idx = 0; idx < acl.size(); idx++) {
30 if (acl[idx] == ACL::EXTERNAL_) {
31 sr |= 1 << idx;
32 }
33 }
34 if (!f_acl_prg.transfer8(sr))
35 return false;
37 return true;
38}
39
40FLASHMEM void LUCIDAC_HAL::reset_acl() {
43}
44
45FLASHMEM bool LUCIDAC_HAL::write_adc_bus_mux(const std::array<int8_t, 8> &channels) {
46 // Reset previous connections
47 // It's easier to do a full reset then to remember all previous connections
49 delayNanoseconds(420);
50
51 // Write data to chip
52 for (uint8_t output_idx = 0; output_idx < channels.size(); output_idx++) {
53 if (channels[output_idx] >= 0) {
54 auto cmd = f_adc_switcher_prg.chip_cmd_word(channels[output_idx], output_idx);
56 return false;
58 }
59 }
60 return true;
61}
62
64
65FLASHMEM bool LUCIDAC::init() {
66 if (!Carrier::init())
67 return false;
68
69 LOG(ANABRID_DEBUG_INIT, "Detecting front panel...");
70 if (!front_panel) {
72 if (!front_panel) {
73 LOG(ANABRID_DEBUG_INIT, "Warning: Front panel is missing or unknown.");
74 }
75 }
76
77 LOG(ANABRID_DEBUG_INIT, "Initialising detected front panel...");
78 if (front_panel && !front_panel->init())
79 return false;
80 LOG(ANABRID_DEBUG_INIT, "Front panel initialized.");
81
82 return true;
83}
84
86 Carrier::reset(action);
87 if (front_panel)
88 front_panel->reset(action);
89
93 }
94}
95
96FLASHMEM std::vector<entities::Entity *> LUCIDAC::get_child_entities() {
98 if (front_panel)
99 entities.push_back(front_panel);
100 return entities;
101}
102
103FLASHMEM entities::Entity *LUCIDAC::get_child_entity(const std::string &child_id) {
104 if (child_id == "FP")
105 return front_panel;
106 return this->carrier::Carrier::get_child_entity(child_id);
107}
108
110 utils::status error = Carrier::write_to_hardware();
111 if (front_panel)
112 front_panel->write_to_hardware().attach_to(error, "Front Panel write failed.");
114 error.attach(1 << 5, "Write ACL failed");
115 return error;
116}
117
118FLASHMEM const std::array<LUCIDAC::ACL, 8> &LUCIDAC::get_acl_select() const { return acl_select; }
119
120FLASHMEM void LUCIDAC::set_acl_select(const std::array<ACL, 8> &acl_select_) { acl_select = acl_select_; }
121
122FLASHMEM bool LUCIDAC::set_acl_select(uint8_t idx, LUCIDAC::ACL acl) {
123 if (idx >= acl_select.size())
124 return false;
125 acl_select[idx] = acl;
126 return true;
127}
128
129FLASHMEM void LUCIDAC::reset_acl_select() { std::fill(acl_select.begin(), acl_select.end(), ACL::INTERNAL_); }
130
132 auto old_acl_selection = get_acl_select();
135 return false;
136
137 if (!Carrier::calibrate_routes())
138 return false;
139
140 set_acl_select(old_acl_selection);
142}
143
145 auto res = this->carrier::Carrier::config_self_from_json(cfg);
146 if (!res)
147 return res;
148
149 if(cfg.containsKey("acl_select")) {
150 auto res = _config_acl_from_json(cfg["acl_select"]);
151 if (!res)
152 return utils::status(531, "Could not configure ACLs from configuration.");
153 }
154
155 // TODO: Unfortunately, given the nested nature of the config_self_from_json,
156 // we no longer can check for passed but unknown configuration keys.
157 // This was not the case before the refactoring of LUCIDAC/REDAC classes
158 // into the carrier.
159
160 return utils::status::success();
161}
162
163FLASHMEM bool platform::LUCIDAC::_config_acl_from_json(const JsonVariantConst &cfg) {
164 if (!cfg.is<JsonArrayConst>())
165 return false;
166
167 auto cfg_acl_select = cfg.as<JsonArrayConst>();
168 for (size_t i = 0; i < cfg_acl_select.size() && i < acl_select.size(); i++) {
169 if (cfg_acl_select[i] == "internal") {
171 } else if (cfg_acl_select[i] == "external") {
173 } else {
174 LOG_ALWAYS("platform::LUCIDAC::config_self_from_json: Expected acl_select[i] to be either 'internal' "
175 "or 'external' string")
176 return false;
177 }
178 }
179 return hardware->write_acl(acl_select);
180}
181
182FLASHMEM void platform::LUCIDAC::config_self_to_json(JsonObject &cfg) {
184
185 // TODO: This code is very quick and dirty. Use JSON custom converters to make nicer.
186 auto cfg_acl_select = cfg.createNestedArray("acl_select");
187
188 for (size_t i = 0; i < acl_select.size(); i++)
189 cfg_acl_select.add(acl_select[i] == platform::LUCIDAC_HAL::ACL::INTERNAL_ ? "internal" : "external");
190}
Entity * get_child_entity(const std::string &child_id) override
Definition carrier.cpp:55
void config_self_to_json(JsonObject &cfg) override
Serialize the configuration of this entity to a JsonObject.
Definition carrier.cpp:89
void reset_adc_channels()
Definition carrier.cpp:261
std::vector< Entity * > get_child_entities() override
Definition carrier.cpp:45
utils::status config_self_from_json(JsonObjectConst cfg) override
Deserialize a new configuration for this entity from a JsonObject.
Definition carrier.cpp:67
static uint8_t chip_cmd_word(uint8_t chip_input_idx, uint8_t chip_output_idx, bool connect=true)
Definition iblock.cpp:16
bool transfer8(uint8_t data_in, uint8_t *data_out=nullptr) const
The Lucidac class represents a single cluster.
Definition cluster.h:20
utils::status write_to_hardware() override
Writes the hardware state of the LEDs and the signal generator.
void reset(entities::ResetAction action)
Resets the front panel to default state e.g. all LEDs off and signal generator sleeping.
bool init()
Initializes the front panel and puts the signal generator to sleep.
const functions::TriggerFunction f_adc_switcher_matrix_reset
Definition lucidac.h:42
const functions::ICommandRegisterFunction f_adc_switcher_prg
Definition lucidac.h:39
static const SPISettings F_ADC_SWITCHER_PRG_SPI_SETTINGS
Definition lucidac.h:9
void reset_adc_bus_mux() override
Definition lucidac.cpp:63
const functions::SR74HCT595 f_acl_prg
Definition lucidac.h:32
bool write_adc_bus_mux(const std::array< int8_t, 8 > &channels) override
Write channel selection to ADC bus muxer.
Definition lucidac.cpp:45
const functions::TriggerFunction f_adc_switcher_sync
Definition lucidac.h:40
const functions::TriggerFunction f_acl_clr
Definition lucidac.h:34
bool write_acl(std::array< ACL, 8 > acl)
Write bits to ACL shift register, from I-block input 24 (first element) to 31 (last element)
Definition lucidac.cpp:27
const functions::TriggerFunction f_acl_upd
Definition lucidac.h:33
Entity * get_child_entity(const std::string &child_id) override
Definition lucidac.cpp:103
LUCIDACFrontPanel * front_panel
Definition lucidac.h:76
const std::array< ACL, 8 > & get_acl_select() const
Definition lucidac.cpp:118
utils::status write_to_hardware() override
returns true in case of success
Definition lucidac.cpp:109
LUCIDAC_HAL * hardware
Definition lucidac.h:68
bool init() override
returns true in case of success
Definition lucidac.cpp:65
bool calibrate_routes() override
Definition lucidac.cpp:131
void config_self_to_json(JsonObject &cfg) override
Serialize the configuration of this entity to a JsonObject.
Definition lucidac.cpp:182
std::vector< Entity * > get_child_entities() override
Definition lucidac.cpp:96
void reset_acl_select()
Definition lucidac.cpp:129
std::array< ACL, 8 > acl_select
Definition lucidac.h:70
bool _config_acl_from_json(const JsonVariantConst &cfg)
Definition lucidac.cpp:163
void reset(entities::ResetAction action) override
Definition lucidac.cpp:85
utils::status config_self_from_json(JsonObjectConst cfg) override
Deserialize a new configuration for this entity from a JsonObject.
Definition lucidac.cpp:144
void set_acl_select(const std::array< ACL, 8 > &acl_select_)
Definition lucidac.cpp:120
A recoverable error, inspired from https://abseil.io/docs/cpp/guides/status and https://github....
Definition error.h:35
static status success()
Syntactic sugar for success.
Definition error.h:104
status & attach_to(status &other, const char *description="")
Attach this error message to another one. Is chainable, returns self.
Definition error.h:81
status & attach(const status &other, const char *description="")
Attach another error message to this one. Is chainable, returns self.
Definition error.h:72
#define LOG(LOG_FLAG, message)
Definition logging.h:36
#define LOG_ALWAYS(message)
Definition logging.h:38
Definition bus.h:22
constexpr addr_t address_from_tuple(uint8_t baddr, uint8_t faddr)
Definition bus.h:100
BlockT * detect(const bus::addr_t block_address)
Definition entity.h:69
bool has(uint8_t other)
Definition base.h:111
static constexpr uint8_t CIRCUIT_RESET
Definition base.h:102