DeviceMgmt.cpp (dabd48dd9ad9c05b1ad67e3540385bd69fe20239) DeviceMgmt.cpp (3ee959ad5e8691e352f1a8424a0dafe0d8ceaff0)
1#include <DeviceMgmt.hpp>
2
3#include <filesystem>
4#include <fstream>
5
6namespace fs = std::filesystem;
7
1#include <DeviceMgmt.hpp>
2
3#include <filesystem>
4#include <fstream>
5
6namespace fs = std::filesystem;
7
8std::optional<I2CDevice> getI2CDevice(const I2CDeviceTypeMap& dtmap,
9 const SensorBaseConfigMap& cfg)
8std::optional<I2CDeviceParams>
9 getI2CDeviceParams(const I2CDeviceTypeMap& dtmap,
10 const SensorBaseConfigMap& cfg)
10{
11 auto findType = cfg.find("Type");
12 auto findBus = cfg.find("Bus");
13 auto findAddr = cfg.find("Address");
14
15 if (findType == cfg.end() || findBus == cfg.end() || findAddr == cfg.end())
16 {
17 return std::nullopt;

--- 9 unchanged lines hidden (view full) ---

27 }
28
29 auto findDevType = dtmap.find(type->c_str());
30 if (findDevType == dtmap.end())
31 {
32 return std::nullopt;
33 }
34
11{
12 auto findType = cfg.find("Type");
13 auto findBus = cfg.find("Bus");
14 auto findAddr = cfg.find("Address");
15
16 if (findType == cfg.end() || findBus == cfg.end() || findAddr == cfg.end())
17 {
18 return std::nullopt;

--- 9 unchanged lines hidden (view full) ---

28 }
29
30 auto findDevType = dtmap.find(type->c_str());
31 if (findDevType == dtmap.end())
32 {
33 return std::nullopt;
34 }
35
35 return I2CDevice(findDevType->second, *bus, *addr);
36 return I2CDeviceParams(findDevType->second, *bus, *addr);
36}
37
38static fs::path i2cBusPath(uint64_t bus)
39{
40 return {"/sys/bus/i2c/devices/i2c-" + std::to_string(bus)};
41}
42
43static std::string deviceDirName(uint64_t bus, uint64_t address)
44{
45 std::ostringstream name;
46 name << bus << "-" << std::hex << std::setw(4) << std::setfill('0')
47 << address;
48 return name.str();
49}
50
37}
38
39static fs::path i2cBusPath(uint64_t bus)
40{
41 return {"/sys/bus/i2c/devices/i2c-" + std::to_string(bus)};
42}
43
44static std::string deviceDirName(uint64_t bus, uint64_t address)
45{
46 std::ostringstream name;
47 name << bus << "-" << std::hex << std::setw(4) << std::setfill('0')
48 << address;
49 return name.str();
50}
51
51bool I2CDevice::present(void) const
52bool I2CDeviceParams::devicePresent(void) const
52{
53 fs::path path = i2cBusPath(bus) / deviceDirName(bus, address);
54
55 if (type->createsHWMon)
56 {
57 path /= "hwmon";
58 }
59
60 // Ignore errors; anything but a clean 'true' is fine as 'false'
61 std::error_code ec;
62 return fs::exists(path, ec);
63}
64
53{
54 fs::path path = i2cBusPath(bus) / deviceDirName(bus, address);
55
56 if (type->createsHWMon)
57 {
58 path /= "hwmon";
59 }
60
61 // Ignore errors; anything but a clean 'true' is fine as 'false'
62 std::error_code ec;
63 return fs::exists(path, ec);
64}
65
66I2CDevice::I2CDevice(I2CDeviceParams params) : params(params)
67{
68 if (create() != 0)
69 {
70 throw std::runtime_error("failed to instantiate i2c device");
71 }
72}
73
74I2CDevice::~I2CDevice()
75{
76 destroy();
77}
78
65int I2CDevice::create(void) const
66{
67 // If it's already instantiated, there's nothing we need to do.
79int I2CDevice::create(void) const
80{
81 // If it's already instantiated, there's nothing we need to do.
68 if (present())
82 if (params.devicePresent())
69 {
70 return 0;
71 }
72
73 // Try to create it: 'echo $devtype $addr > .../i2c-$bus/new_device'
83 {
84 return 0;
85 }
86
87 // Try to create it: 'echo $devtype $addr > .../i2c-$bus/new_device'
74 fs::path ctorPath = i2cBusPath(bus) / "new_device";
88 fs::path ctorPath = i2cBusPath(params.bus) / "new_device";
75 std::ofstream ctor(ctorPath);
76 if (!ctor.good())
77 {
78 std::cerr << "Failed to open " << ctorPath << "\n";
79 return -1;
80 }
81
89 std::ofstream ctor(ctorPath);
90 if (!ctor.good())
91 {
92 std::cerr << "Failed to open " << ctorPath << "\n";
93 return -1;
94 }
95
82 ctor << type->name << " " << address << "\n";
96 ctor << params.type->name << " " << params.address << "\n";
83 ctor.flush();
84 if (!ctor.good())
85 {
86 std::cerr << "Failed to write to " << ctorPath << "\n";
87 return -1;
88 }
89
90 // Check if that created the requisite sysfs directory
97 ctor.flush();
98 if (!ctor.good())
99 {
100 std::cerr << "Failed to write to " << ctorPath << "\n";
101 return -1;
102 }
103
104 // Check if that created the requisite sysfs directory
91 if (!present())
105 if (!params.devicePresent())
92 {
93 destroy();
94 return -1;
95 }
96
97 return 0;
98}
99
100int I2CDevice::destroy(void) const
101{
106 {
107 destroy();
108 return -1;
109 }
110
111 return 0;
112}
113
114int I2CDevice::destroy(void) const
115{
102 // No present() check on this like in create(), since it might be used to
103 // clean up after a device instantiation that was only partially
104 // successful (i.e. when present() would return false but there's still a
105 // dummy i2c client device to remove)
116 // No params.devicePresent() check on this like in create(), since it
117 // might be used to clean up after a device instantiation that was only
118 // partially successful (i.e. when params.devicePresent() would return
119 // false but there's still a dummy i2c client device to remove)
106
120
107 fs::path dtorPath = i2cBusPath(bus) / "delete_device";
121 fs::path dtorPath = i2cBusPath(params.bus) / "delete_device";
108 std::ofstream dtor(dtorPath);
109 if (!dtor.good())
110 {
111 std::cerr << "Failed to open " << dtorPath << "\n";
112 return -1;
113 }
114
122 std::ofstream dtor(dtorPath);
123 if (!dtor.good())
124 {
125 std::cerr << "Failed to open " << dtorPath << "\n";
126 return -1;
127 }
128
115 dtor << address << "\n";
129 dtor << params.address << "\n";
116 dtor.flush();
117 if (!dtor.good())
118 {
119 std::cerr << "Failed to write to " << dtorPath << "\n";
120 return -1;
121 }
122
123 return 0;
124}
130 dtor.flush();
131 if (!dtor.good())
132 {
133 std::cerr << "Failed to write to " << dtorPath << "\n";
134 return -1;
135 }
136
137 return 0;
138}