diff --git a/include/chappi_ad5621.h b/include/chappi_ad5621.h new file mode 100644 index 0000000..f59953d --- /dev/null +++ b/include/chappi_ad5621.h @@ -0,0 +1,70 @@ +/* + +MIT License + +Copyright (c) 2019 Alexander Chernenko (achernenko@mail.ru) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#pragma once + +#include "chappi_base.h" + +namespace chappi { + +namespace detail { +struct ad5621_counter { + chips_counter data; +}; +} // namespace detail + +template +class ad5621 final : public chip_base { + static constexpr auto _chip_name = "AD5621"; + detail::ad5621_counter _counter; + + public: + CHIP_BASE_RESOLVE + + ad5621(bool log_enable) + : ad5621{(log_enable) ? std::clog.rdbuf() : nullptr} {} + ad5621(std::streambuf *buf_ptr = {}, reg_read_fn reg_read = {}, + reg_write_fn reg_write = {}) + : chip_base{buf_ptr} { + log_created(get_name()); + } + ~ad5621() noexcept { log_destroyed(get_name()); } + int get_num() const noexcept final { return _counter.data.get_num(); } + int get_counts() const noexcept final { return _counter.data.get_counts(); } + std::string get_name() const noexcept final { + return get_name(_chip_name, get_num()); + } + void set_value(value_type value) const { write(0x00, value << 2); } + void set_value(value_type value, error_type &error) const noexcept { + helpers::noexcept_set_function(this, value, error); + } +}; + +} // namespace chappi diff --git a/include/chappi_adn4600.h b/include/chappi_adn4600.h new file mode 100644 index 0000000..d3d31a3 --- /dev/null +++ b/include/chappi_adn4600.h @@ -0,0 +1,79 @@ +/* + +MIT License + +Copyright (c) 2019 Alexander Chernenko (achernenko@mail.ru) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#pragma once + +#include "chappi_base.h" + +namespace chappi { + +namespace detail { +struct adn4600_counter { + chips_counter data; +}; +} // namespace detail + +template +class adn4600 final : public chip_base { + static constexpr auto _chip_name = "ADN4600"; + detail::adn4600_counter _counter; + + public: + CHIP_BASE_RESOLVE + + adn4600(bool log_enable) + : adn4600{(log_enable) ? std::clog.rdbuf() : nullptr} {} + adn4600(std::streambuf *buf_ptr = {}, reg_read_fn reg_read = {}, + reg_write_fn reg_write = {}) + : chip_base{buf_ptr} { + log_created(get_name()); + } + ~adn4600() noexcept { log_destroyed(get_name()); } + int get_num() const noexcept final { return _counter.data.get_num(); } + int get_counts() const noexcept final { return _counter.data.get_counts(); } + std::string get_name() const noexcept final { + return get_name(_chip_name, get_num()); + } + void reset() const { write(0x00, 0x01); } + void reset(error_type &error) const noexcept { + helpers::noexcept_void_function(this, error); + } + void xpt_config(value_type in, value_type out) const { + const value_type value = ((in << 4) & 0x70) | (out & 0x07); + write(0x40, value); + } + void xpt_update() const { write(0x41, 0x01); } + void xpt_update(error_type &error) const noexcept { + helpers::noexcept_void_function(this, error); + } +}; + +} // namespace chappi diff --git a/include/chappi_hmc987.h b/include/chappi_hmc987.h new file mode 100644 index 0000000..351716a --- /dev/null +++ b/include/chappi_hmc987.h @@ -0,0 +1,186 @@ +/* + +MIT License + +Copyright (c) 2019 Alexander Chernenko (achernenko@mail.ru) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#pragma once + +#include "chappi_base.h" + +namespace chappi { + +union hmc987_outputs { + enum class outs_bitmask : uint8_t { + Out1 = (1 << 0), + Out2 = (1 << 1), + Out3 = (1 << 2), + Out4 = (1 << 3), + Out5 = (1 << 4), + Out6 = (1 << 5), + Out7 = (1 << 6), + Out8 = (1 << 7), + All = 0xFF, + None = 0 + }; + outs_bitmask bitmask; + struct __attribute__((packed)) { + bool out1 : 1; + bool out2 : 1; + bool out3 : 1; + bool out4 : 1; + bool out5 : 1; + bool out6 : 1; + bool out7 : 1; + bool out8 : 1; + } bits; +}; + +enum class hmc987_gain : uint8_t { + Disable = 0, + neg_9_dBm, + neg_6_dBm, + neg_3_dBm, + zero_dBm, + pos_3_dBm +}; + +namespace detail { +struct hmc987_counter { + chips_counter data; +}; +} // namespace detail + +template +class hmc987 final : public chip_base { + static constexpr auto _chip_name = "HMC987"; + detail::hmc987_counter _counter; + + public: + CHIP_BASE_RESOLVE + + hmc987(bool log_enable) + : hmc987{(log_enable) ? std::clog.rdbuf() : nullptr} {} + hmc987(std::streambuf *buf_ptr = {}, reg_read_fn reg_read = {}, + reg_write_fn reg_write = {}) + : chip_base{buf_ptr} { + log_created(get_name()); + } + ~hmc987() noexcept { log_destroyed(get_name()); } + int get_num() const noexcept final { return _counter.data.get_num(); } + int get_counts() const noexcept final { return _counter.data.get_counts(); } + std::string get_name() const noexcept final { + return get_name(_chip_name, get_num()); + } + void init() const { write(0x00, 0x00); } + void init(error_type &error) const noexcept { + helpers::noexcept_void_function(this, error); + } + + void read_id(value_type &id) const { read(0x00, id); } + value_type read_id() const { + return helpers::retval_get_function(this); + } + value_type read_id(error_type &error) const noexcept { + return helpers::noexcept_get_function(this, + error); + } + + void chip_enable(bool enabled) const { write(0x01, (enabled) ? 0x01 : 0x00); } + void chip_enable(bool enabled, error_type &error) const noexcept { + helpers::noexcept_set_function(this, enabled, error); + } + void is_enabled(bool &enabled) const { + value_type value; + write(0x00, 0x01); + read(0x00, value); + enabled = (value != 0) ? true : false; + } + bool is_enabled() const { + return helpers::retval_get_function(this); + } + bool is_enabled(error_type &error) const noexcept { + return helpers::noexcept_get_function(this, + error); + } + void enable_buffers(hmc987_outputs::outs_bitmask bitmask) const { + write(0x02, static_cast(bitmask)); + } + void enable_buffers(hmc987_outputs::outs_bitmask bitmask, + error_type &error) const noexcept { + helpers::noexcept_set_function(this, bitmask, + error); + } + void state_buffers(hmc987_outputs::outs_bitmask &bitmask) const { + value_type value; + write(0x00, 0x02); + read(0x00, value); + bitmask = static_cast(value); + } + hmc987_outputs::outs_bitmask state_buffers() const { + return helpers::retval_get_function(this); + } + hmc987_outputs::outs_bitmask state_buffers(error_type &error) const noexcept { + return helpers::noexcept_get_function(this, error); + } + void set_gain(hmc987_gain gain) const { + write(0x04, static_cast(gain) & 0x07); + } + void set_gain(hmc987_gain gain, error_type &error) const noexcept { + helpers::noexcept_set_function(this, gain, + error); + } + void get_gain(hmc987_gain &gain) const { + value_type value; + write(0x00, 0x04); + read(0x00, value); + gain = static_cast(value); + } + hmc987_gain get_gain() const { + return helpers::retval_get_function(this); + } + hmc987_gain get_gain(error_type &error) const noexcept { + return helpers::noexcept_get_function( + this, error); + } +}; + +} // namespace chappi diff --git a/include/chappi_ina219.h b/include/chappi_ina219.h new file mode 100644 index 0000000..9f4b451 --- /dev/null +++ b/include/chappi_ina219.h @@ -0,0 +1,109 @@ +/* + +MIT License + +Copyright (c) 2019 Alexander Chernenko (achernenko@mail.ru) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#pragma once + +#include "chappi_base.h" + +namespace chappi { + +namespace detail { +struct ina219_counter { + chips_counter data; +}; +} // namespace detail + +template +class ina219 final : public chip_base { + static constexpr auto _chip_name = "INA219"; + detail::ina219_counter _counter; + + public: + CHIP_BASE_RESOLVE + + ina219(bool log_enable) + : ina219{(log_enable) ? std::clog.rdbuf() : nullptr} {} + ina219(std::streambuf *buf_ptr = {}, reg_read_fn reg_read = {}, + reg_write_fn reg_write = {}) + : chip_base{buf_ptr} { + log_created(get_name()); + } + ~ina219() noexcept { log_destroyed(get_name()); } + int get_num() const noexcept final { return _counter.data.get_num(); } + int get_counts() const noexcept final { return _counter.data.get_counts(); } + std::string get_name() const noexcept final { + return get_name(_chip_name, get_num()); + } + void configure(value_type value) const { write(0x00, value); } + void configure(value_type value, error_type &error) const noexcept { + helpers::noexcept_set_function(this, value, error); + } + void reset() const { + value_type value{}; + read(0x00, value); + value |= (0x8000); + write(0x00, value); + } + void reset(error_type &error) const noexcept { + helpers::noexcept_void_function(this, error); + } + void get_shunt_voltage(double &value) const { + value_type retval{}; + read(0x01, retval); + value = (retval & 0x3FFF); + } + double get_shunt_voltage(error_type &error) const noexcept { + return helpers::noexcept_get_function( + this, error); + } + double get_shunt_voltage() const { + return helpers::retval_get_function( + this); + } + void get_bus_voltage(double &value) const { + value_type retval{}; + read(0x02, retval); + value = ((retval >> 3) & 0x1FFF); + } + double get_bus_voltage(error_type &error) const noexcept { + return helpers::noexcept_get_function( + this, error); + } + double get_bus_voltage() const { + return helpers::retval_get_function(this); + } +}; + +} // namespace chappi diff --git a/include/chappi_ltc2991.h b/include/chappi_ltc2991.h new file mode 100644 index 0000000..71c9c46 --- /dev/null +++ b/include/chappi_ltc2991.h @@ -0,0 +1,226 @@ +/* + +MIT License + +Copyright (c) 2019 Alexander Chernenko (achernenko@mail.ru) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#pragma once + +#include "chappi_base.h" + +namespace chappi { + +struct ltc2991_data { + double Tint; + double V1; + double V2; + double V3; + double V4; + double V5; + double V6; + double V7; + double V8; +}; + +namespace detail { +struct ltc2991_counter { + chips_counter data; +}; +} // namespace detail + +template +class ltc2991 final : public chip_base { + static constexpr auto _chip_name = "LTC2991"; + detail::ltc2991_counter _counter; + + public: + CHIP_BASE_RESOLVE + + ltc2991(bool log_enable) + : ltc2991{(log_enable) ? std::clog.rdbuf() : nullptr} {} + ltc2991(std::streambuf *buf_ptr = {}, reg_read_fn reg_read = {}, + reg_write_fn reg_write = {}) + : chip_base{buf_ptr} { + log_created(get_name()); + } + ~ltc2991() noexcept { log_destroyed(get_name()); } + int get_num() const noexcept final { return _counter.data.get_num(); } + int get_counts() const noexcept final { return _counter.data.get_counts(); } + std::string get_name() const noexcept final { + return get_name(_chip_name, get_num()); + } + void enable_all_channels() const { + value_type value{}; + read(0x01, value); + value |= 0b11111000; + write(0x01, value); + } + void enable_all_channels(error_type &error) const noexcept { + helpers::noexcept_void_function(this, error); + } + void repeated_mode(bool enable) const { + value_type value{}; + read(0x08, value); + if (enable) { + value |= 0b00010000; + } else { + value &= ~0b00010000; + } + write(0x08, value); + } + void repeated_mode(bool enable, error_type &error) const noexcept { + helpers::noexcept_set_function(this, enable, + error); + } + void get_temperature(double &value) const { + value_type lsb{}, msb{}; + read(0x1A, msb); + read(0x1B, lsb); + value = ((msb & 0b00011111) << 8 | lsb) / 16.0; + } + double get_temperature() const { + return helpers::retval_get_function( + this); + } + double get_temperature(error_type &error) const noexcept { + return helpers::noexcept_get_function( + this, error); + } + void get_voltage_1(double &value) const { _get_voltage(0x0A, value); } + double get_voltage_1() const { + return helpers::retval_get_function(this); + } + double get_voltage_1(error_type &error) const noexcept { + return helpers::noexcept_get_function( + this, error); + } + void get_voltage_2(double &value) const { _get_voltage(0x0C, value); } + double get_voltage_2() const { + return helpers::retval_get_function(this); + } + double get_voltage_2(error_type &error) const noexcept { + return helpers::noexcept_get_function( + this, error); + } + void get_voltage_3(double &value) const { _get_voltage(0x0E, value); } + double get_voltage_3() const { + return helpers::retval_get_function(this); + } + double get_voltage_3(error_type &error) const noexcept { + return helpers::noexcept_get_function( + this, error); + } + void get_voltage_4(double &value) const { _get_voltage(0x10, value); } + double get_voltage_4() const { + return helpers::retval_get_function(this); + } + double get_voltage_4(error_type &error) const noexcept { + return helpers::noexcept_get_function( + this, error); + } + void get_voltage_5(double &value) const { _get_voltage(0x12, value); } + double get_voltage_5() const { + return helpers::retval_get_function(this); + } + double get_voltage_5(error_type &error) const noexcept { + return helpers::noexcept_get_function( + this, error); + } + void get_voltage_6(double &value) const { _get_voltage(0x14, value); } + double get_voltage_6() const { + return helpers::retval_get_function(this); + } + double get_voltage_6(error_type &error) const noexcept { + return helpers::noexcept_get_function( + this, error); + } + void get_voltage_7(double &value) const { _get_voltage(0x16, value); } + double get_voltage_7() const { + return helpers::retval_get_function(this); + } + double get_voltage_7(error_type &error) const noexcept { + return helpers::noexcept_get_function( + this, error); + } + void get_voltage_8(double &value) const { _get_voltage(0x18, value); } + double get_voltage_8() const { + return helpers::retval_get_function(this); + } + double get_voltage_8(error_type &error) const noexcept { + return helpers::noexcept_get_function( + this, error); + } + void get_data(ltc2991_data &value) const { + value.Tint = get_temperature(); + value.V1 = get_voltage_1(); + value.V2 = get_voltage_2(); + value.V3 = get_voltage_3(); + value.V4 = get_voltage_4(); + value.V5 = get_voltage_5(); + value.V6 = get_voltage_6(); + value.V7 = get_voltage_7(); + value.V8 = get_voltage_8(); + } + ltc2991_data get_data() const { + return helpers::retval_get_function(this); + } + ltc2991_data get_data(error_type &error) const { + return helpers::noexcept_get_function( + this, error); + } + + private: + void _get_voltage(addr_type addr_msb, double &value) const { + value_type val_lsb{}, val_msb{}; + read(addr_msb, val_msb); + read(addr_msb + 1, val_lsb); + value = ((val_msb & 0b00111111) << 8 | val_lsb) * 0.000305180; + } +}; + +} // namespace chappi diff --git a/include/chappi_si57x.h b/include/chappi_si57x.h new file mode 100644 index 0000000..972c9e6 --- /dev/null +++ b/include/chappi_si57x.h @@ -0,0 +1,258 @@ +/* + +MIT License + +Copyright (c) 2019 Alexander Chernenko (achernenko@mail.ru) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#pragma once + +#include +#include + +#include "chappi_base.h" + +namespace chappi { + +namespace detail { +struct si57x_counter { + chips_counter data; +}; +} // namespace detail + +template +class si57x final : public chip_base { + static constexpr auto _chip_name = "Si57x"; + detail::si57x_counter _counter; + static const int _freq_regs_num{12}; + static constexpr double _fxtal_default{114.285e6}; + double _fxtal{_fxtal_default}; + + constexpr int reg_addr_to_idx(int addr) const noexcept { + return addr - start_addr; + } + + public: + CHIP_BASE_RESOLVE + + si57x(bool log_enable) : si57x{(log_enable) ? std::clog.rdbuf() : nullptr} {} + si57x(std::streambuf *buf_ptr = {}, reg_read_fn reg_read = {}, + reg_write_fn reg_write = {}) + : chip_base{buf_ptr} { + log_created(get_name()); + } + ~si57x() noexcept { log_destroyed(get_name()); } + int get_num() const noexcept final { return _counter.data.get_num(); } + int get_counts() const noexcept final { return _counter.data.get_counts(); } + std::string get_name() const noexcept final { + return get_name(_chip_name, get_num()); + } + void reset() const { write(135, 0x80); } + void reset(error_type &error) const noexcept { + helpers::noexcept_void_function(this, error); + } + void freeze_dco(bool enabled) const { write(137, (enabled) ? 0x10 : 0x00); } + void freeze_dco(bool enabled, error_type &error) const noexcept { + helpers::noexcept_set_function(this, enabled, error); + } + void apply_freq() const { write(135, 0x40); } + void apply_freq(error_type &error) const noexcept { + helpers::noexcept_void_function(this, error); + } + void set_freq(double value) const { + freq_regs_type freq_regs{}; + if (_make_freq_regs(value, _fxtal, freq_regs) != true) { + auto error_msg = + std::string("can't calulate parameters for ") + get_name(); + throw std::runtime_error(error_msg); + } + addr_type addr{start_addr}; + for (auto ® : freq_regs) { + write(addr, reg); + ++addr; + } + } + void set_freq(double value, error_type &error) const noexcept { + helpers::noexcept_set_function(this, value, error); + } + void get_freq(double &value) const { + freq_regs_type freq_regs{}; + addr_type addr{start_addr}; + for (auto ® : freq_regs) { + read(addr, reg); + ++addr; + } + value = _calculate_freq(_fxtal, freq_regs); + } + + double get_freq(error_type &error) const noexcept { + return helpers::noexcept_get_function(this, + error); + } + double get_freq() const { + return helpers::retval_get_function(this); + } + void set_fxtal(double fxtal) noexcept { _fxtal = fxtal; } + double get_fxtal() const noexcept { return _fxtal; } + void calib_fxtal(double freq_gen) noexcept { + freq_regs_type freq_regs{}; + addr_type addr{start_addr}; + for (auto ® : freq_regs) { + read(addr, reg); + ++addr; + } + _fxtal = _calculate_fxtal(freq_gen, freq_regs); + log << '[' << get_name() << ']' << " Fxtal = " << std::setprecision(12) + << _fxtal << '\n'; + } + void calib_fxtal(double freq_gen, error_type &error) const noexcept { + helpers::noexcept_set_function(this, freq_gen, error); + } + + private: + using freq_regs_type = std::array; + static const addr_type start_addr{7}; + double _calculate_fxtal(double freq_gen, freq_regs_type ®) { + uint32_t rfreq_lo = 0xFF & reg[reg_addr_to_idx(12)]; + rfreq_lo |= (0xFF & reg[reg_addr_to_idx(11)]) << 8; + rfreq_lo |= (0xFF & reg[reg_addr_to_idx(10)]) << 16; + rfreq_lo |= (0xF & reg[reg_addr_to_idx(9)]) << 24; + uint32_t rfreq_hi = (0xF0 & reg[reg_addr_to_idx(9)]) >> 4; + rfreq_hi |= (0x3F & reg[reg_addr_to_idx(8)]) << 4; + uint32_t hs_div = (0xE0 & reg[reg_addr_to_idx(7)]) >> 5; + uint32_t n1 = (0xC0 & reg[reg_addr_to_idx(8)]) >> 6; + n1 |= (0x1F & reg[reg_addr_to_idx(7)]) << 2; + auto rfreq = double(rfreq_lo); + rfreq /= 1024.0 * 1024.0 * 256.0; + rfreq += double(rfreq_hi); + auto hs_div_tmp = double(hs_div + 4); + auto n1_tmp = (n1 == 1) ? 1.0 : double(0xFE & (n1 + 1)); + double fxtal = freq_gen; + fxtal /= rfreq; + fxtal *= hs_div_tmp * n1_tmp; + return fxtal; + } + bool _make_freq_regs(double freq, double fxtal, freq_regs_type ®) const + noexcept { + if (freq < 10000000.0) { + freq = 10000000.0; + } + uint32_t rfreq_lo{}; + uint32_t rfreq_hi{}; + uint32_t hs_div{}; + uint32_t n1{}; + auto success = + _calculate_divider(freq, fxtal, rfreq_lo, rfreq_hi, hs_div, n1); + if (!success) { + return false; + } + reg[reg_addr_to_idx(7)] = reg[reg_addr_to_idx(13)] = + (hs_div << 5) | (n1 >> 2); + reg[reg_addr_to_idx(8)] = reg[reg_addr_to_idx(14)] = + (n1 << 6) | (rfreq_hi >> 4); + reg[reg_addr_to_idx(9)] = reg[reg_addr_to_idx(15)] = + (rfreq_hi << 4) | (rfreq_lo >> 24); + reg[reg_addr_to_idx(10)] = reg[reg_addr_to_idx(16)] = + (rfreq_lo >> 16) & 0xFF; + reg[reg_addr_to_idx(11)] = reg[reg_addr_to_idx(17)] = + (rfreq_lo >> 8) & 0xFF; + reg[reg_addr_to_idx(12)] = reg[reg_addr_to_idx(18)] = rfreq_lo & 0xFF; + return true; + } + bool _calculate_divider(double freq, double fxtal, uint32_t &rfreq_lo, + uint32_t &rfreq_hi, uint32_t &hs_div, + uint32_t &n1) const noexcept { + double hs_div_tmp{}; + double n1_tmp{}; + if (freq >= 1212500000.0) { + hs_div_tmp = 4; + n1_tmp = 1; + } else if (freq >= 970000000.0) { + hs_div_tmp = 5; + n1_tmp = 1; + } else { + double dco_min{4850000000.0}; + double dco_max{5670000000.0}; + double hs_div_valid[]{4.0, 5.0, 6.0, 7.0, 9.0, 11.0}; + double freq_dco{}; + double freq_tmp{}; + freq_dco = dco_max; + for (int n1_count{1}; n1_count <= 128; ++n1_count) { + if (n1_count & 0x1) { + continue; + } + for (int hs_div_count{}; + hs_div_count < int(sizeof(hs_div_valid) / sizeof(hs_div_valid[0])); + ++hs_div_count) { + freq_tmp = freq * hs_div_valid[hs_div_count] * double(n1_count); + if ((freq_tmp >= dco_min) && (freq_tmp <= freq_dco)) { + freq_dco = freq_tmp; + hs_div_tmp = hs_div_valid[hs_div_count]; + n1_tmp = double(n1_count); + } + } + } + } + if ((hs_div_tmp == 0.0) || (n1_tmp == 0.0)) { + return false; + } + double rfreq = freq * hs_div_tmp * n1_tmp; + rfreq /= fxtal; + rfreq_hi = uint32_t(rfreq); + rfreq_lo = uint32_t((rfreq - double(rfreq_hi)) * 1024.0 * 1024.0 * 256.0); + hs_div = uint32_t(hs_div_tmp - 4.0); + n1 = uint32_t(n1_tmp - 1.0); + return true; + } + double _calculate_freq(double fxtal, freq_regs_type ®) const noexcept { + uint32_t rfreq_lo = 0xFF & reg[reg_addr_to_idx(12)]; + rfreq_lo |= (0xFF & reg[reg_addr_to_idx(11)]) << 8; + rfreq_lo |= (0xFF & reg[reg_addr_to_idx(10)]) << 16; + rfreq_lo |= (0xF & reg[reg_addr_to_idx(9)]) << 24; + uint32_t rfreq_ho = (0xF0 & reg[reg_addr_to_idx(9)]) >> 4; + rfreq_ho |= (0x3F & reg[reg_addr_to_idx(8)]) << 4; + uint32_t hs_div = (0xE0 & reg[reg_addr_to_idx(7)]) >> 5; + uint32_t n1 = (0xC0 & reg[reg_addr_to_idx(8)]) >> 6; + n1 |= (0x1F & reg[reg_addr_to_idx(7)]) << 2; + auto rfreq = double(rfreq_lo); + rfreq /= 1024.0 * 1024.0 * 256.0; + rfreq += double(rfreq_ho); + auto hs_div_tmp = double(hs_div + 4); + auto n1_tmp = (n1 == 0) ? 1.0 : double(0xFE & (n1 + 1)); + double freq = fxtal; + freq /= hs_div_tmp * n1_tmp; + freq *= rfreq; + return freq; + } +}; // namespace chappi + +} // namespace chappi diff --git a/include/chappi_tca6424.h b/include/chappi_tca6424.h new file mode 100644 index 0000000..cadd97c --- /dev/null +++ b/include/chappi_tca6424.h @@ -0,0 +1,132 @@ +/* + +MIT License + +Copyright (c) 2019 Alexander Chernenko (achernenko@mail.ru) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#pragma once + +#include "chappi_base.h" + +namespace chappi { + +namespace detail { +struct tca6424_counter { + chips_counter data; +}; +} // namespace detail + +template +class tca6424 final : public chip_base { + static constexpr auto _chip_name = "TCA6424"; + detail::tca6424_counter _counter; + + public: + CHIP_BASE_RESOLVE + + tca6424(bool log_enable) + : tca6424{(log_enable) ? std::clog.rdbuf() : nullptr} {} + tca6424(std::streambuf *buf_ptr = {}, reg_read_fn reg_read = {}, + reg_write_fn reg_write = {}) + : chip_base{buf_ptr} { + log_created(get_name()); + } + ~tca6424() noexcept { log_destroyed(get_name()); } + int get_num() const noexcept final { return _counter.data.get_num(); } + int get_counts() const noexcept final { return _counter.data.get_counts(); } + std::string get_name() const noexcept final { + return get_name(_chip_name, get_num()); + } + void configure_port_0(value_type value) const { write(0x0c, value); } + void configure_port_0(value_type value, error_type &error) const noexcept { + helpers::noexcept_set_function( + this, value, error); + } + void configure_port_1(value_type value) const { write(0x0d, value); } + void configure_port_1(value_type value, error_type &error) const noexcept { + helpers::noexcept_set_function( + this, value, error); + } + void configure_port_2(value_type value) const { write(0x0e, value); } + void configure_port_2(value_type value, error_type &error) const noexcept { + helpers::noexcept_set_function( + this, value, error); + } + + void set_port_0(value_type value) const { write(0x04, value); } + void set_port_0(value_type value, error_type &error) const noexcept { + helpers::noexcept_set_function( + this, value, error); + } + void set_port_1(value_type value) const { write(0x05, value); } + void set_port_1(value_type value, error_type &error) const noexcept { + helpers::noexcept_set_function( + this, value, error); + } + void set_port_2(value_type value) const { write(0x06, value); } + void set_port_2(value_type value, error_type &error) const noexcept { + helpers::noexcept_set_function( + this, value, error); + } + void get_port_0(value_type &value) const { read(0x04, value); } + value_type get_port_0() const { + return helpers::retval_get_function(this); + } + value_type get_port_0(error_type &error) const noexcept { + return helpers::noexcept_get_function( + this, error); + } + void get_port_1(value_type &value) const { read(0x05, value); } + value_type get_port_1() const { + return helpers::retval_get_function(this); + } + value_type get_port_1(error_type &error) const noexcept { + return helpers::noexcept_get_function( + this, error); + } + void get_port_2(value_type &value) const { read(0x06, value); } + value_type get_port_2() const { + return helpers::retval_get_function(this); + } + value_type get_port_2(error_type &error) const noexcept { + return helpers::noexcept_get_function( + this, error); + } +}; + +} // namespace chappi