1 #include "config.h"
2
3 #include "i2c_occ.hpp"
4
5 #include <algorithm>
6 #include <cassert>
7 #include <fstream>
8
9 #ifdef I2C_OCC
10
11 namespace i2c_occ
12 {
13
14 namespace fs = std::filesystem;
15
16 // The occ_master sysfs file
17 constexpr auto OCC_MASTER_FILE = "occ_master";
18 // The device name's length, e.g. "p8-occ-hwmon"
19 constexpr auto DEVICE_NAME_LENGTH = 12;
20 // The occ name's length, e.g. "occ"
21 constexpr auto OCC_NAME_LENGTH = 3;
22
23 // static assert to make sure the i2c occ device name is expected
24 static_assert(sizeof(I2C_OCC_DEVICE_NAME) - 1 == DEVICE_NAME_LENGTH);
25 static_assert(sizeof(OCC_NAME) - 1 == OCC_NAME_LENGTH);
26
isMasterOcc(const fs::directory_entry & p)27 static bool isMasterOcc(const fs::directory_entry& p)
28 {
29 auto f = p / fs::path{OCC_MASTER_FILE};
30 auto str = getFileContent(f);
31 return (!str.empty()) && (str[0] == '1');
32 }
33
getFileContent(const fs::path & f)34 std::string getFileContent(const fs::path& f)
35 {
36 std::string ret(DEVICE_NAME_LENGTH, 0);
37 std::ifstream ifs(f.c_str(), std::ios::binary);
38 if (ifs.is_open())
39 {
40 ifs.read(&ret[0], DEVICE_NAME_LENGTH);
41 ret.resize(ifs.gcount());
42 }
43 return ret;
44 }
45
getOccHwmonDevices(const char * path)46 std::vector<std::string> getOccHwmonDevices(const char* path)
47 {
48 std::vector<std::string> result{};
49
50 if (fs::is_directory(path))
51 {
52 for (auto& p : fs::directory_iterator(path))
53 {
54 // Check if a device's name is "p8-occ-hwmon"
55 auto f = p / fs::path{"name"};
56 auto str = getFileContent(f);
57 if (str == I2C_OCC_DEVICE_NAME)
58 {
59 if (isMasterOcc(p))
60 {
61 // Insert master occ at the beginning
62 result.emplace(result.begin(), p.path().filename());
63 }
64 else
65 {
66 result.emplace_back(p.path().filename());
67 }
68 }
69 }
70 }
71 if (!result.empty())
72 {
73 // Sort the occ devices except for master
74 std::sort(result.begin() + 1, result.end());
75 }
76 return result;
77 }
78
i2cToDbus(std::string & path)79 void i2cToDbus(std::string& path)
80 {
81 std::replace(path.begin(), path.end(), '-', '_');
82 }
83
dbusToI2c(std::string & path)84 void dbusToI2c(std::string& path)
85 {
86 std::replace(path.begin(), path.end(), '_', '-');
87 }
88
getI2cDeviceName(const std::string & dbusPath)89 std::string getI2cDeviceName(const std::string& dbusPath)
90 {
91 auto name = fs::path(dbusPath).filename().string();
92
93 // Need to make sure the name starts with "occ"
94 assert(name.compare(0, OCC_NAME_LENGTH, OCC_NAME) == 0);
95
96 // Change name like occ_3_0050 to 3_0050
97 name.erase(0, OCC_NAME_LENGTH + 1);
98
99 dbusToI2c(name);
100 return name;
101 }
102
103 } // namespace i2c_occ
104
105 #endif
106