diff --git a/smocore/deviceManager/deviceManager.cpp b/smocore/deviceManager/deviceManager.cpp index 23eeec2..a495609 100644 --- a/smocore/deviceManager/deviceManager.cpp +++ b/smocore/deviceManager/deviceManager.cpp @@ -40,16 +40,18 @@ class DeviceManager::NewDeviceAttachmentSpecInd { public: NewDeviceAttachmentSpecInd( - std::shared_ptr s, + const std::shared_ptr &s, + const std::shared_ptr &d, const std::shared_ptr &caller, Callback cb) : PostedAsynchronousContinuation( caller, cb), - spec(s) + spec(s), device(d) {} public: std::shared_ptr spec; + std::shared_ptr device; public: void newDeviceAttachmentSpecInd1_posted( @@ -79,32 +81,6 @@ public: } try { - /** EXPLANATION: - * Remember that deviceAttachmentSpecs don't refer to devices, but - * rather to roles that a device can enact when attached to in the - * described manner. Therefore, it's possible for multiple DA specs - * to refer to the same device. - * - * That's why we need to ensure that the device doesn't already - * exist before trying to create a new device for it. - */ - std::shared_ptr device = nullptr; - for (const auto& existingDevice : devices) - { - if (existingDevice->deviceIdentifier != spec->deviceIdentifier) - { continue; } - - device = existingDevice; - break; - } - - // If device doesn't exist, create a new one and add it - if (!device) - { - device = std::make_shared(spec->deviceIdentifier); - devices.push_back(device); - } - // Create DeviceRole and add it to both DeviceManager's and Device's collections auto deviceRole = std::make_shared(*device, spec); device->deviceRoles.push_back(deviceRole); @@ -134,25 +110,65 @@ void DeviceManager::newDeviceAttachmentSpecInd( } } - if (!specExists) { - deviceAttachmentSpecs.push_back(spec); + if (!specExists) + { + deviceAttachmentSpecs.push_back( + std::make_shared(*spec)); + } + + // Find or create the Device for this spec + bool deviceExists = false; + std::shared_ptr device = nullptr; + for (const auto& existingDevice : devices) + { + if (existingDevice->deviceIdentifier != spec->deviceIdentifier) + { continue; } + + device = existingDevice; + deviceExists = true; + break; + } + + // If device doesn't exist, create a new one and add it + if (!device) + { + device = std::make_shared(spec->deviceIdentifier); + devices.push_back(device); } // Check if a DeviceRole w/ this spec already exists in attachedDeviceRoles - for (const auto& existingDeviceRole : attachedDeviceRoles) + bool deviceRoleExists = false; + std::shared_ptr existingDeviceRole = nullptr; + for (const auto& role : attachedDeviceRoles) { - if (*existingDeviceRole->deviceAttachmentSpec == *spec) + if (*role->deviceAttachmentSpec == *spec) { - // Already attached, callback with success - callback.callbackFn(true, existingDeviceRole, spec); - return; + deviceRoleExists = true; + existingDeviceRole = role; + break; } } + // Consistency check: if DeviceRole exists, both spec and device must also exist + if (deviceRoleExists) + { + if (!specExists || !deviceExists) + { + throw std::runtime_error( + "Program error: DeviceRole exists but spec or device doesn't " + "pre-exist. specExists=" + std::to_string(specExists) + + ", deviceExists=" + std::to_string(deviceExists)); + } + + // Already attached, callback with success + callback.callbackFn(true, existingDeviceRole, spec); + return; + } + // Create async continuation const auto& caller = ComponentThread::getSelf(); auto continuation = std::make_shared( - spec, caller, callback); + spec, device, caller, callback); mrntt::mrntt.thread->getIoService().post( std::bind(