REDAC HybridController
Firmware for LUCIDAC/REDAC Teensy
Loading...
Searching...
No Matches
front_panel.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 "front_panel.h"
7
9
11 leds.reset();
12 signal_generator.init();
13 return true;
14}
15
18 leds.reset();
19 signal_generator.sleep();
20 }
21}
22
24 utils::status ret;
25 ret.attach(leds.write_to_hardware(), "FP LED failure");
26 if (signal_generator.is_installed())
27 ret.attach(signal_generator.write_to_hardware(), "Signal generator failure");
28 return ret;
29}
30
32 : led_register(bus::address_from_tuple(2, LED_REGISTER_IDX), true),
33 led_register_store(bus::address_from_tuple(2, LED_REGISTER_STORE_IDX)),
34 led_register_reset(bus::address_from_tuple(2, LED_REGISTER_RESET_IDX)) {}
35
36FLASHMEM bool platform::LUCIDACFrontPanel::LEDs::set(const uint8_t led, bool on) {
37 if (led > 7)
38 return false;
39
40 if (on)
41 led_states |= (1 << led);
42 else
43 led_states &= ~(1 << led);
44
45 return true;
46}
47
48FLASHMEM void platform::LUCIDACFrontPanel::LEDs::set_all(const uint8_t states) { led_states = states; }
49
51 led_states = 0;
52 led_register_reset.trigger();
53}
54
55FLASHMEM uint8_t platform::LUCIDACFrontPanel::LEDs::get_all() const { return led_states; }
56
58 bool ret = led_register.transfer8(led_states);
59 led_register_store.trigger();
60 return utils::status(ret);
61}
62
64 : digital_analog_converter(bus::address_from_tuple(2, DAC_IDX)),
65 function_generator(bus::address_from_tuple(2, FUNCTION_GENERATOR_IDX)) {}
66
68 installed = digital_analog_converter.init() && function_generator.init();
69 return installed;
70}
71
73 _frequency = frequency;
74}
75
76FLASHMEM void platform::LUCIDACFrontPanel::SignalGenerator::set_phase(float phase) { _phase = phase; }
77
78FLASHMEM void
82
84 if (amplitude < 0.0f || amplitude > 1.0f)
85 return false;
86 _amplitude = amplitude;
87 return true;
88}
89
91 return set_square_voltage_low(low) && set_square_voltage_high(high);
92}
93
95 if (fabs(low) > 1.0f)
96 return false;
97 _square_low_voltage = low;
98 return true;
99}
100
102 if (fabs(high) > 1.0f)
103 return false;
104 _square_high_voltage = high;
105 return true;
106}
107
109 if (fabs(offset) > 1.0f)
110 return false;
111 _offset = offset;
112 return true;
113}
114
116 return function_generator.get_real_frequency();
117}
118
120 return function_generator.get_real_phase();
121}
122
123FLASHMEM float platform::LUCIDACFrontPanel::SignalGenerator::get_frequency() const { return _frequency; }
124
125FLASHMEM float platform::LUCIDACFrontPanel::SignalGenerator::get_phase() const { return _phase; }
126
130
131FLASHMEM float platform::LUCIDACFrontPanel::SignalGenerator::get_amplitude() const { return _amplitude; }
132
134 return _square_low_voltage;
135}
136
138 return _square_high_voltage;
139}
140
141FLASHMEM float platform::LUCIDACFrontPanel::SignalGenerator::get_offset() const { return _offset; }
142
143FLASHMEM bool platform::LUCIDACFrontPanel::SignalGenerator::get_sleep() const { return _sleep; }
144
145FLASHMEM float platform::LUCIDACFrontPanel::SignalGenerator::get_dac_out0() const { return _dac_out0; }
146
147FLASHMEM float platform::LUCIDACFrontPanel::SignalGenerator::get_dac_out1() const { return _dac_out1; }
148
150
152
154 if (fabs(value) > 1.0f)
155 return false;
156 _dac_out0 = value;
157 return true;
158}
159
161 if (fabs(value) > 1.0f)
162 return false;
163 _dac_out1 = value;
164 return true;
165}
166
167// TODO: Implement smart write to hardware for signal generator
169 if (_sleep)
170 function_generator.sleep();
171 else
172 function_generator.awake();
173
174 function_generator.write_frequency(_frequency);
175 function_generator.write_phase(_phase);
176 function_generator.write_wave_form(_wave_form);
177
178 if (!digital_analog_converter.set_channel(DAC_AMPLITUDE_CH, (1.0f - _amplitude) * 2.5f))
179 return utils::status(-1, "FP DAC");
180 if (!digital_analog_converter.set_channel(DAC_SQUARE_LOW_CH,
181 _map_dac_levelshift(_square_low_voltage * 2.0f)))
182 return utils::status(-2, "FP DSLC");
183 if (!digital_analog_converter.set_channel(DAC_SQUARE_HIGH_CH,
184 _map_dac_levelshift(_square_high_voltage * 2.0f)))
185 return utils::status(-3, "FP DSHC");
186 if (!digital_analog_converter.set_channel(DAC_OFFSET_CH, _map_dac_levelshift(_offset * 2.0f)))
187 return utils::status(-4, "FP DOC");
188 if (!digital_analog_converter.set_channel(DAC_OUT0_CH, _map_dac_levelshift(_dac_out0 * 2.0f)))
189 return utils::status(-5, "FP DO0C");
190 if (!digital_analog_converter.set_channel(DAC_OUT1_CH, _map_dac_levelshift(_dac_out1 * 2.0f)))
191 return utils::status(-6, "FP DO1C");
192
193 delay(50);
194 return utils::status::success();
195}
196
197FLASHMEM
200 __attribute__((__unused__)) bus::addr_t block_address) {
201 if (!classifier or classifier.class_enum != CLASS_)
202 return nullptr;
203
204 // Currently, there are no different variants
205 if (classifier.variant != entities::EntityClassifier::DEFAULT_)
206 return nullptr;
207
208 if (classifier.version < entities::Version(1, 1))
209 return nullptr;
210 if (classifier.version < entities::Version(1, 2)) {
211 auto *new_block = new LUCIDACFrontPanel;
212 new_block->classifier = classifier;
213 return new_block;
214 }
215 return nullptr;
216}
217
218FLASHMEM std::array<uint8_t, 8> platform::LUCIDACFrontPanel::get_entity_eui() const {
220}
221
223 for (auto cfgItr = cfg.begin(); cfgItr != cfg.end(); ++cfgItr) {
224 if (cfgItr->key() == "leds") {
225 auto res = _config_leds_from_json(cfgItr->value());
226 if (!res)
227 return res;
228 } else if (cfgItr->key() == "signal_generator") {
229 auto res = _config_signal_generator_from_json(cfgItr->value());
230 if (!res)
231 return res;
232 } else {
233 return utils::status("LUCIDACFrontPanel: Unknown configuration key");
234 }
235 }
236
237 return utils::status::success();
238}
239
241 if (!cfg.is<uint8_t>())
242 return utils::status("LUCIDACFrontPanel LED configuration must be encoded as single integer");
243 leds.set_all(cfg);
244 return utils::status::success();
245}
246
247FLASHMEM utils::status
249 if (!cfg.is<JsonObjectConst>())
250 return utils::status("LUCIDACFrontPanel signal generator configuration must be object");
251
252 auto cfg_generator = cfg.as<JsonObjectConst>();
253 for (auto cfgItr = cfg_generator.begin(); cfgItr != cfg_generator.end(); ++cfgItr) {
254 if (cfgItr->key() == "frequency") {
255 if (!cfgItr->value().is<float>())
256 return utils::status("LUCIDACFrontPanel frequency value must be float");
257
258 signal_generator.set_frequency(cfgItr->value());
259
260 } else if (cfgItr->key() == "phase") {
261 if (!cfgItr->value().is<float>())
262 return utils::status("LUCIDACFrontPanel phase value must be float");
263
264 signal_generator.set_phase(cfgItr->value());
265
266 } else if (cfgItr->key() == "wave_form") {
267 if (!cfgItr->value().is<std::string>())
268 return utils::status("LUCIDACFrontPanel wave form must be string");
269
270 std::string wave_form = cfg_generator["wave_form"];
271 if (wave_form == "sine")
273 else if (wave_form == "sine_and_square")
275 else if (wave_form == "triangle")
277 else
278 return utils::status("LUCIDACFrontPanel wave form illegal value");
279
280 } else if (cfgItr->key() == "amplitude") {
281 if (!cfgItr->value().is<float>())
282 return utils::status("LUCIDACFrontPanel amplitude must be float");
283
284 signal_generator.set_amplitude(cfgItr->value());
285
286 } else if (cfgItr->key() == "square_voltage_low") {
287 if (!cfgItr->value().is<float>())
288 return utils::status("LUCIDACFrontPanel square_voltage_low must be float");
289
291
292 } else if (cfgItr->key() == "square_voltage_high") {
293 if (!cfgItr->value().is<float>())
294 return utils::status("LUCIDACFrontPanel square_voltage_high must be float");
295
297
298 } else if (cfgItr->key() == "offset") {
299 if (!cfgItr->value().is<float>())
300 return utils::status("LUCIDACFrontPanel offset must be float");
301
302 signal_generator.set_offset(cfgItr->value());
303
304 } else if (cfgItr->key() == "sleep") {
305 if (!cfgItr->value().is<bool>())
306 return utils::status("LUCIDACFrontPanel sleep must be bool");
307
308 if (cfgItr->value())
310 else
312
313 } else if (cfgItr->key() == "dac_outputs") {
314 if (!cfgItr->value().is<JsonArrayConst>())
315 return utils::status("LUCIDACFrontPanel dac_outputs must be array");
316
317 auto dac_outputs = cfg_generator["dac_outputs"].as<JsonArrayConst>();
318 if (dac_outputs.size() != 2)
319 return utils::status("LUCIDACFrontPanel dac_outputs must be array of size 2");
320
321 if (!dac_outputs[0].is<float>())
322 return utils::status("LUCIDACFrontPanel dac_outputs[0] is not float");
323 if (!dac_outputs[1].is<float>())
324 return utils::status("LUCIDACFrontPanel dac_outputs[1] is not float");
325
326 if (!signal_generator.set_dac_out0(dac_outputs[0]))
327 return utils::status("LUCIDACFrontPanel dac_outputs[0] illegal value %d", dac_outputs[0]);
328 if (!signal_generator.set_dac_out1(dac_outputs[1]))
329 return utils::status("LUCIDACFrontPanel dac_outputs[1] illegal value %d", dac_outputs[1]);
330
331 } else {
332 return utils::status("LUCIDACFrontPanel: Unexpected keyword: %s", cfgItr->key().c_str());
333 }
334 }
335 return utils::status::success();
336}
337
339 Entity::config_self_to_json(cfg);
340
341 cfg["leds"] = leds.get_all();
342
343 auto cfg_generator = cfg.createNestedObject("signal_generator");
344 cfg_generator["frequency"] = signal_generator.get_frequency();
345 cfg_generator["phase"] = signal_generator.get_phase();
346
349 cfg_generator["wave_form"] = "sine";
350 break;
352 cfg_generator["wave_form"] = "sine_and_square";
353 break;
355 cfg_generator["wave_form"] = "triangle";
356 break;
357 }
358
359 cfg_generator["amplitude"] = signal_generator.get_amplitude();
360 cfg_generator["square_voltage_low"] = signal_generator.get_square_voltage_low();
361 cfg_generator["square_voltage_high"] = signal_generator.get_square_voltage_high();
362 cfg_generator["offset"] = signal_generator.get_offset();
363 cfg_generator["sleep"] = signal_generator.get_sleep();
364
365 auto cfg_dac = cfg_generator.createNestedArray("dac_outputs");
366 cfg_dac.add(signal_generator.get_dac_out0());
367 cfg_dac.add(signal_generator.get_dac_out1());
368}
EntityClassifier classifier
Definition base.h:217
eui_t read_eui() const
Definition entity.h:42
utils::status write_to_hardware() const
void set_all(const uint8_t states)
Sets all eight front leds at once.
void reset()
Disables all eight front leds.
uint8_t get_all() const
Returns the current state of the front leds.
bool set(const uint8_t led, bool on)
Sets specified front led to the specified value.
void awake()
Resumes outputs of the function generator to regular operation, according to the previously specified...
bool set_dac_out1(float value)
Writes the DACout1 constant voltage output. Possible values are: [-2V, 2V].
float get_real_phase() const
Returns the actually set phase of the function generator, containing rounding errors.
void sleep()
Sets the sine / triangle output of the function generator to zero.
void set_frequency(float frequency)
Sets the frequency of the sine / triangle output in Hz.
void set_wave_form(functions::AD9834::WaveForm wave_form)
Sets the wave form of the function generator output.
bool init()
Initializes the signal generator and puts it to sleep.
void set_phase(float phase)
Sets the phase of the frequency outputs synchronised to the reset pin.
bool set_square_voltage_high(float high)
Sets the upper value of the square output in machine units.
float get_real_frequency() const
Returns the actually set frequency of the function generator, containing rounding errors.
bool set_offset(float offset)
Sets the constant offset of the sine or triangle output in machine units.
bool set_dac_out0(float value)
Writes the DACout0 constant voltage output. Possible values are: [-2V, 2V].
bool set_square_voltage_low(float low)
Sets the lower value of the square output in machine units.
bool set_amplitude(float amplitude)
Sets the amplitude of the sine or triangle wave in machine units.
functions::AD9834::WaveForm get_wave_form() const
bool set_square_voltage_levels(float low, float high)
Sets the lower and upper value of the square output in machine units.
The Lucidac Front Panel is represented by this class.
Definition front_panel.h:26
utils::status write_to_hardware() override
Writes the hardware state of the LEDs and the signal generator.
utils::status _config_leds_from_json(const JsonVariantConst &cfg)
utils::status config_self_from_json(JsonObjectConst cfg) override
Deserialize a new configuration for this entity from a JsonObject.
void reset(entities::ResetAction action)
Resets the front panel to default state e.g. all LEDs off and signal generator sleeping.
static constexpr uint8_t DAC_OUT0_CH
Definition front_panel.h:58
static constexpr uint8_t DAC_AMPLITUDE_CH
Definition front_panel.h:54
class platform::LUCIDACFrontPanel::SignalGenerator signal_generator
static constexpr uint8_t DAC_SQUARE_LOW_CH
Definition front_panel.h:56
utils::status _config_signal_generator_from_json(const JsonVariantConst &cfg)
static constexpr uint8_t FUNCTION_GENERATOR_IDX
Definition front_panel.h:48
void config_self_to_json(JsonObject &cfg) override
Serialize the configuration of this entity to a JsonObject.
static constexpr uint8_t DAC_SQUARE_HIGH_CH
Definition front_panel.h:55
bool init()
Initializes the front panel and puts the signal generator to sleep.
static constexpr uint8_t DAC_IDX
Definition front_panel.h:49
static constexpr auto CLASS_
Definition front_panel.h:29
static constexpr uint8_t DAC_OFFSET_CH
Definition front_panel.h:57
std::array< uint8_t, 8 > get_entity_eui() const override
static LUCIDACFrontPanel * from_entity_classifier(entities::EntityClassifier classifier, __attribute__((__unused__)) bus::addr_t block_address)
static constexpr uint8_t DAC_OUT1_CH
Definition front_panel.h:59
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(const status &other, const char *description="")
Attach another error message to this one. Is chainable, returns self.
Definition error.h:72
__attribute__((section(".fastrun"), noinline, noclone, optimize("Os"))) int flash_sector_not_erased(uint32_t address)
Definition flasher.cpp:114
Definition bus.h:22
uint16_t addr_t
Definition bus.h:27
constexpr addr_t address_from_tuple(uint8_t baddr, uint8_t faddr)
Definition bus.h:100
bool has(uint8_t other)
Definition base.h:111
static constexpr uint8_t CIRCUIT_RESET
Definition base.h:102