diff --git a/cmake/targets/detector.cmake b/cmake/targets/detector.cmake index fec9942..20f2b91 100644 --- a/cmake/targets/detector.cmake +++ b/cmake/targets/detector.cmake @@ -5,6 +5,7 @@ set(DETECTOR_SOURCE_FILES "${PROJECT_SRC_DIR}/serial/i2cdevice.cpp" "${PROJECT_SRC_DIR}/serial/i2cbus.cpp" "${PROJECT_SRC_DIR}/serial/i2cdevices/generalcall.cpp" + "${PROJECT_SRC_DIR}/serial/i2cdevices/lm75.cpp" ) set(DETECTOR_HEADER_FILES @@ -16,6 +17,7 @@ set(DETECTOR_HEADER_FILES "${PROJECT_HEADER_DIR}/muonpi/serial/i2cbus.h" "${PROJECT_HEADER_DIR}/muonpi/serial/i2ceeprom.h" "${PROJECT_HEADER_DIR}/muonpi/serial/i2cdevices/generalcall.h" + "${PROJECT_HEADER_DIR}/muonpi/serial/i2cdevices/lm75.h" ) if (NOT LIBMUONPI_FORMAT_ONLY) if (LIBMUONPI_BUILD_DETECTOR) # libraries specific to the Detector library diff --git a/include/muonpi/serial/i2cdevices/lm75.h b/include/muonpi/serial/i2cdevices/lm75.h new file mode 100644 index 0000000..d1a6902 --- /dev/null +++ b/include/muonpi/serial/i2cdevices/lm75.h @@ -0,0 +1,119 @@ +#ifndef MUONPI_SERIAL_I2CDEVICES_LM75_H +#define MUONPI_SERIAL_I2CDEVICES_LM75_H + +#include "muonpi/addressrange.h" +#include "muonpi/serial/i2cdevice.h" + +namespace muonpi::serial::devices { + +/** + * @brief The lm75 class. Interaction for the LM75 Temperature Sensor. + * Closely follows the datasheet: + * https://datasheets.maximintegrated.com/en/ds/LM75.pdf + */ +class lm75 : public i2c_device { +public: + constexpr static address_range addresses {0b01001000, {0b111}}; + + /** + * @brief lm75 + * @param bus_traffic The bus traffic object from the i2c_bus. + * @param path The path of the i2c bus file descriptor + * @param address The address to use + */ + lm75(traffic_t& bus_traffic, const std::string& path, i2c_device::address_type address); + + /** + * @brief lm75 Attempts to automatically setup the device connection. + * @param bus_traffic The bus traffic object from the i2c_bus. + * @param path The path of the i2c bus file descriptor + */ + lm75(traffic_t& bus_traffic, const std::string& path); + + /** + * @brief identify Attempts to positively identify the device. + * @return True if identification was successful. + */ + [[nodiscard]] auto identify() -> bool override; + + template + struct basic_temperature_r : public simple_register { + using value_type = typename simple_register::value_type; + using address_type = + typename simple_register::address_type; + + value_type temperature : 9 {}; + const value_type reserved : 7 {}; + + [[nodiscard]] constexpr auto value() const noexcept -> double { + return static_cast(temperature) / 2.0; + } + + [[nodiscard]] constexpr auto get() const noexcept -> value_type override { + return static_cast(temperature << 7); + } + + constexpr explicit basic_temperature_r(value_type v) noexcept + : temperature {static_cast(v >> 7)} + , reserved {static_cast(v & 0b1111111)} {} + + constexpr explicit basic_temperature_r() noexcept = default; + }; + + struct temperature_r : public basic_temperature_r<0x00> { + constexpr static i2c_tag_type register_tag {i2c_register_tag::read}; + + constexpr explicit temperature_r(value_type v) noexcept + : basic_temperature_r {v} {} + + constexpr explicit temperature_r() noexcept = default; + }; + + struct t_hyst_r : public basic_temperature_r<0x01> { + constexpr static i2c_tag_type register_tag {i2c_register_tag::read_write}; + + constexpr explicit t_hyst_r(value_type v) noexcept + : basic_temperature_r {v} {} + + constexpr explicit t_hyst_r() noexcept + : basic_temperature_r {0b0100101100000000} {} + }; + + struct t_os_r : public basic_temperature_r<0x02> { + constexpr static i2c_tag_type register_tag {i2c_register_tag::read_write}; + + constexpr explicit t_os_r(value_type v) noexcept + : basic_temperature_r {v} {} + + constexpr explicit t_os_r() noexcept + : basic_temperature_r {0b0101000000000000} {} + }; + + struct configuration_r : public simple_register { + constexpr static i2c_tag_type register_tag {i2c_register_tag::read_write}; + + const value_type reserved : 3 {}; + value_type fault_queue : 2 {}; + value_type os_polarity : 1 {}; + value_type comparator : 1 {}; + value_type shutdown : 1 {}; + + [[nodiscard]] constexpr auto get() const noexcept -> value_type override { + return static_cast((fault_queue << 3) | (os_polarity << 2) + | (comparator << 1) | shutdown); + } + + constexpr explicit configuration_r(value_type v) noexcept + : reserved {static_cast((v & 0b11100000) >> 5)} + , fault_queue {static_cast((v & 0b11000) >> 3)} + , os_polarity {static_cast((v & 0b100) >> 2)} + , comparator {static_cast((v & 0b10) >> 1)} + , shutdown {static_cast(v & 0b1)} {} + + constexpr explicit configuration_r() noexcept = default; + }; +}; + +} // namespace muonpi::serial::devices + +#endif diff --git a/src/serial/i2cdevices/lm75.cpp b/src/serial/i2cdevices/lm75.cpp new file mode 100644 index 0000000..48c61a1 --- /dev/null +++ b/src/serial/i2cdevices/lm75.cpp @@ -0,0 +1,50 @@ +#include "muonpi/serial/i2cdevices/lm75.h" + +namespace muonpi::serial::devices { + +lm75::lm75(traffic_t& bus_traffic, const std::string& path, i2c_device::address_type address) + : i2c_device {bus_traffic, path, address} {} + +lm75::lm75(traffic_t& bus_traffic, const std::string& path) + : i2c_device {bus_traffic, path, addresses} {} + +auto lm75::identify() -> bool { + if (flag_set(Flags::Error)) { + return false; + } + if (!present()) { + return false; + } + + const auto config {read()}; + if (!config.has_value()) { + return false; + } + if (config.value().reserved != 0) { + return false; + } + const auto temp {read()}; + if (!temp.has_value()) { + return false; + } + if (temp.value().reserved != 0) { + return false; + } + const auto thyst {read()}; + if (!thyst.has_value()) { + return false; + } + if (thyst.value().reserved != 0) { + return false; + } + const auto tos {read()}; + if (!tos.has_value()) { + return false; + } + if (tos.value().reserved != 0) { + return false; + } + + return true; +} +} // namespace muonpi::serial::devices