~aleteoryx/muditaos

ref: 6665a43d2b901b89809c4f18338d8ea6c0b08df7 muditaos/module-bsp/devices/temperature/CT7117.cpp -rw-r--r-- 4.7 KiB
6665a43d — Lefucjusz [BH-1780] Fix uncaught std::filesystem::file_size exception 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "CT7117.hpp"

#include <array>

namespace
{
    enum class Registers
    {
        Temp          = 0x00,
        Config        = 0x01,
        Low_Temp_Set  = 0x02,
        High_Temp_Set = 0x03,
        ID            = 0x07
    };

    enum class ConfigReg
    {
        OTS  = (1 << 15),
        F1   = (1 << 12),
        F0   = (1 << 11),
        ALTM = (1 << 9),
        SD   = (1 << 8),
        EM   = (1 << 7),
        RES1 = (1 << 6),
        RES0 = (1 << 5),
        TO   = (1 << 4),
        PEC  = (1 << 3),
        CR1  = (1 << 2),
        CR0  = (1 << 1),
        OS   = (1 << 0)
    };

    using namespace bsp::devices::temperature::CT7117;

    std::array<std::uint8_t, 2U> to_bytes(const std::uint16_t value)
    {
        return {static_cast<std::uint8_t>(value & 0xFF00 >> 8U), static_cast<std::uint8_t>(value & 0xFF)};
    }

    std::uint16_t from_bytes(std::array<std::uint8_t, 2U> bytes)
    {
        return bytes[0] << 8U | bytes[1];
    }

    ssize_t write_register16(const std::uint8_t dev_id,
                             drivers::DriverI2C &i2c,
                             const Registers address,
                             const std::uint16_t reg)
    {
        const drivers::I2CAddress addr = {
            .deviceAddress = dev_id, .subAddress = static_cast<std::uint32_t>(address), .subAddressSize = 1};

        return i2c.Write(addr, &to_bytes(reg)[0], sizeof(reg));
    }

    std::optional<std::uint16_t> read_register16(const std::uint8_t dev_id,
                                                 drivers::DriverI2C &i2c,
                                                 const Registers address)
    {
        const drivers::I2CAddress addr = {
            .deviceAddress = dev_id, .subAddress = static_cast<std::uint32_t>(address), .subAddressSize = 1};
        std::array<std::uint8_t, 2U> ret_value{};

        if (const auto result = i2c.Read(addr, &ret_value[0], ret_value.size()); result == ret_value.size()) {
            return from_bytes(ret_value);
        }
        return std::nullopt;
    }

    units::Temperature from_raw(const std::uint16_t raw)
    {
        auto is_sign_present = [](const std::uint16_t raw) { return ((raw & 0x8000) != 0); };

        if (is_sign_present(raw)) {
            const auto integer =
                static_cast<std::uint16_t>(((~raw + 1) & 0x7FFF) >> 7); // remove sign bit and shift to lower byte
            const auto fractional = static_cast<std::uint16_t>(((~raw + 1) & 0x7F) * 0.78125);
            return -1 * (static_cast<float>(integer) + (static_cast<float>(fractional) / 100.0));
        }
        else {
            const auto integer =
                static_cast<std::uint16_t>((raw & 0x7FFF) >> 7); // remove sign bit and shift to lower byte
            const auto fractional = static_cast<std::uint16_t>((raw & 0x7F) * 0.78125);
            return static_cast<float>(integer) + (static_cast<float>(fractional) / 100.0);
        }
    }

    std::uint16_t adjust_resolution(const std::uint16_t value)
    {
        /// Resolution = 0.25°C
        return value & 0xFFE0;
    }
} // namespace

namespace bsp::devices::temperature::CT7117
{

    CT7117::CT7117(const std::uint8_t id, drivers::DriverI2C &i2c) : device_id{id}, i2c{i2c}
    {}

    CT7117::~CT7117()
    {
        standby();
    }

    bool CT7117::standby()
    {
        auto reg = read_register16(device_id, i2c, Registers::Config);
        if (not reg) {
            return false;
        }
        *reg |= static_cast<std::uint16_t>(ConfigReg::SD);
        return write_register16(device_id, i2c, Registers::Config, *reg) == sizeof(*reg);
    }

    bool CT7117::wakeup()
    {
        auto reg = read_register16(device_id, i2c, Registers::Config);
        if (not reg) {
            return false;
        }
        *reg &= ~(static_cast<std::uint16_t>(ConfigReg::SD));
        return write_register16(device_id, i2c, Registers::Config, *reg) == sizeof(*reg);
    }

    std::optional<units::Temperature> CT7117::get_temperature() const
    {
        auto reg = read_register16(device_id, i2c, Registers::Temp);
        if (not reg) {
            return std::nullopt;
        }

        return from_raw(adjust_resolution(*reg));
    }

    bool CT7117::poll() const
    {
        constexpr auto DEVICE_ID      = 0x59;
        const drivers::I2CAddress reg = {
            .deviceAddress = device_id, .subAddress = static_cast<std::uint32_t>(Registers::ID), .subAddressSize = 1};

        std::uint8_t id{};
        const auto id_size = sizeof id;

        return i2c.Read(reg, &id, id_size) == id_size and id == DEVICE_ID;
    }
} // namespace bsp::devices::temperature::CT7117