DeviceMgmt: split I2CDeviceParams out of I2CDevice

The parameters struct now exists on its own, separately from the device
struct which instantiates the kernel device in its constructor and
removes it in its destructor.  This allows the parameters to exist
standalone so that we can do things like use an instance of it to check
if a device is already instantiated without attempting to do so.

Signed-off-by: Zev Weiss <zev@bewilderbeest.net>
Change-Id: Ib1c37ee26e27e59020a8e26916e697729a3661af
diff --git a/src/DeviceMgmt.cpp b/src/DeviceMgmt.cpp
index ca52a3a..fdf7577 100644
--- a/src/DeviceMgmt.cpp
+++ b/src/DeviceMgmt.cpp
@@ -5,8 +5,9 @@
 
 namespace fs = std::filesystem;
 
-std::optional<I2CDevice> getI2CDevice(const I2CDeviceTypeMap& dtmap,
-                                      const SensorBaseConfigMap& cfg)
+std::optional<I2CDeviceParams>
+    getI2CDeviceParams(const I2CDeviceTypeMap& dtmap,
+                       const SensorBaseConfigMap& cfg)
 {
     auto findType = cfg.find("Type");
     auto findBus = cfg.find("Bus");
@@ -32,7 +33,7 @@
         return std::nullopt;
     }
 
-    return I2CDevice(findDevType->second, *bus, *addr);
+    return I2CDeviceParams(findDevType->second, *bus, *addr);
 }
 
 static fs::path i2cBusPath(uint64_t bus)
@@ -48,7 +49,7 @@
     return name.str();
 }
 
-bool I2CDevice::present(void) const
+bool I2CDeviceParams::devicePresent(void) const
 {
     fs::path path = i2cBusPath(bus) / deviceDirName(bus, address);
 
@@ -62,16 +63,29 @@
     return fs::exists(path, ec);
 }
 
+I2CDevice::I2CDevice(I2CDeviceParams params) : params(params)
+{
+    if (create() != 0)
+    {
+        throw std::runtime_error("failed to instantiate i2c device");
+    }
+}
+
+I2CDevice::~I2CDevice()
+{
+    destroy();
+}
+
 int I2CDevice::create(void) const
 {
     // If it's already instantiated, there's nothing we need to do.
-    if (present())
+    if (params.devicePresent())
     {
         return 0;
     }
 
     // Try to create it: 'echo $devtype $addr > .../i2c-$bus/new_device'
-    fs::path ctorPath = i2cBusPath(bus) / "new_device";
+    fs::path ctorPath = i2cBusPath(params.bus) / "new_device";
     std::ofstream ctor(ctorPath);
     if (!ctor.good())
     {
@@ -79,7 +93,7 @@
         return -1;
     }
 
-    ctor << type->name << " " << address << "\n";
+    ctor << params.type->name << " " << params.address << "\n";
     ctor.flush();
     if (!ctor.good())
     {
@@ -88,7 +102,7 @@
     }
 
     // Check if that created the requisite sysfs directory
-    if (!present())
+    if (!params.devicePresent())
     {
         destroy();
         return -1;
@@ -99,12 +113,12 @@
 
 int I2CDevice::destroy(void) const
 {
-    // No present() check on this like in create(), since it might be used to
-    // clean up after a device instantiation that was only partially
-    // successful (i.e. when present() would return false but there's still a
-    // dummy i2c client device to remove)
+    // No params.devicePresent() check on this like in create(), since it
+    // might be used to clean up after a device instantiation that was only
+    // partially successful (i.e. when params.devicePresent() would return
+    // false but there's still a dummy i2c client device to remove)
 
-    fs::path dtorPath = i2cBusPath(bus) / "delete_device";
+    fs::path dtorPath = i2cBusPath(params.bus) / "delete_device";
     std::ofstream dtor(dtorPath);
     if (!dtor.good())
     {
@@ -112,7 +126,7 @@
         return -1;
     }
 
-    dtor << address << "\n";
+    dtor << params.address << "\n";
     dtor.flush();
     if (!dtor.good())
     {