summaryrefslogtreecommitdiffstats
path: root/i2c_occ.cpp
blob: 1c1a9ffe8e390ec1130917adbba117a9a0e53d28 (plain)
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
#include "config.h"

#include "i2c_occ.hpp"

#include <algorithm>
#include <cassert>
#include <fstream>

#ifdef I2C_OCC

namespace i2c_occ
{

namespace fs = std::experimental::filesystem;

// The occ_master sysfs file
constexpr auto OCC_MASTER_FILE = "occ_master";
// The device name's length, e.g. "p8-occ-hwmon"
constexpr auto DEVICE_NAME_LENGTH = 12;
// The occ name's length, e.g. "occ"
constexpr auto OCC_NAME_LENGTH = 3;

// static assert to make sure the i2c occ device name is expected
static_assert(sizeof(I2C_OCC_DEVICE_NAME) - 1 == DEVICE_NAME_LENGTH);
static_assert(sizeof(OCC_NAME) - 1 == OCC_NAME_LENGTH);

static bool isMasterOcc(const fs::directory_entry& p)
{
    auto f = p / OCC_MASTER_FILE;
    auto str = getFileContent(f);
    return (!str.empty()) && (str[0] == '1');
}

std::string getFileContent(const fs::path& f)
{
    std::string ret(DEVICE_NAME_LENGTH, 0);
    std::ifstream ifs(f.c_str(), std::ios::binary);
    if (ifs.is_open())
    {
        ifs.read(&ret[0], DEVICE_NAME_LENGTH);
        ret.resize(ifs.gcount());
    }
    return ret;
}

std::vector<std::string> getOccHwmonDevices(const char* path)
{
    std::vector<std::string> result{};

    if (fs::is_directory(path))
    {
        for (auto& p : fs::directory_iterator(path))
        {
            // Check if a device's name is "p8-occ-hwmon"
            auto f = p / "name";
            auto str = getFileContent(f);
            if (str == I2C_OCC_DEVICE_NAME)
            {
                if (isMasterOcc(p))
                {
                    // Insert master occ at the beginning
                    result.emplace(result.begin(), p.path().filename());
                }
                else
                {
                    result.emplace_back(p.path().filename());
                }
            }
        }
    }
    if (!result.empty())
    {
        // Sort the occ devices except for master
        std::sort(result.begin() + 1, result.end());
    }
    return result;
}

void i2cToDbus(std::string& path)
{
    std::replace(path.begin(), path.end(), '-', '_');
}

void dbusToI2c(std::string& path)
{
    std::replace(path.begin(), path.end(), '_', '-');
}

std::string getI2cDeviceName(const std::string& dbusPath)
{
    auto name = fs::path(dbusPath).filename().string();

    // Need to make sure the name starts with "occ"
    assert(name.compare(0, OCC_NAME_LENGTH, OCC_NAME) == 0);

    // Change name like occ_3_0050 to 3_0050
    name.erase(0, OCC_NAME_LENGTH + 1);

    dbusToI2c(name);
    return name;
}

} // namespace i2c_occ

#endif
OpenPOWER on IntegriCloud