SenseApis: Make attachDeviceReq async in drivers and SenseApiMgr

Slowly retrogressively making these sequences async
This commit is contained in:
2025-09-10 06:51:55 -04:00
parent 5b5a701c69
commit 1b6b12256d
9 changed files with 282 additions and 116 deletions
+86 -76
View File
@@ -53,10 +53,12 @@ static std::vector<std::shared_ptr<livoxProto1::Device>> g_attachedDevices;
// Callback function declarations
extern "C" int livoxGen1_initializeInd(void);
extern "C" int livoxGen1_finalizeInd(void);
extern "C" int livoxGen1_attachDeviceReq(
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& desc);
extern "C" int livoxGen1_detachDeviceReq(
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& desc);
extern "C" void livoxGen1_attachDeviceReq(
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& desc,
smo::sense_api::sal_mlo_attachDeviceReqCbFn cb);
extern "C" void livoxGen1_detachDeviceReq(
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& desc,
smo::sense_api::sal_mlo_detachDeviceReqCbFn cb);
// Sense API descriptor
static const SenseApiDesc livoxGen1ApiDesc = {
@@ -151,8 +153,9 @@ extern "C" int livoxGen1_finalizeInd(void)
return 0; // Success
}
extern "C" int livoxGen1_attachDeviceReq(
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& desc
extern "C" void livoxGen1_attachDeviceReq(
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& desc,
smo::sense_api::sal_mlo_attachDeviceReqCbFn cb
)
{
if (!livoxProto1.livoxProto1_getOrCreateDeviceReq)
@@ -162,6 +165,17 @@ extern "C" int livoxGen1_attachDeviceReq(
"not available");
}
/** FIXME:
* We should acquire a spinlock here to ensure that the device isn't added
* in the interim while the async op executes.
*/
for (const auto& dev : g_attachedDevices)
{
if (dev->discoveredDevice.deviceIdentifier == desc->deviceIdentifier)
{ return; }
}
// Parse integer parameters from provider params with defaults
/* The Livox Avia will generally respond to a handshake request within
* 50ms. So we set the handshake timeout to 300ms to be safe.
@@ -233,59 +247,47 @@ extern "C" int livoxGen1_attachDeviceReq(
}
}
std::atomic<bool> callbackCalled{false};
std::shared_ptr<livoxProto1::Device> device = nullptr;
std::shared_ptr<ComponentThread> self = smoHooksPtr->
ComponentThread_getSelf();
(*livoxProto1.livoxProto1_getOrCreateDeviceReq)(
desc->deviceSelector, // deviceIdentifier (broadcast code)
smoThreadingModelDesc.componentThread,
handshakeTimeoutMs, retryDelayMs,
smoIp, smoSubnetNbits,
dataPort, cmdPort, imuPort,
[&callbackCalled, &device, self](
[desc, cb](
bool success, std::shared_ptr<livoxProto1::Device> dev) -> void
{
callbackCalled.store(true);
device = ((success) ? dev : nullptr);
// Ensure that the bridging loop below will get awakened.
self->getIoService().post([]{});
if (!dev)
{
std::cerr << __func__ << ": Failed to create Livox device: "
<< desc->deviceSelector << std::endl;
cb(false);
return;
}
g_attachedDevices.push_back(dev);
if (1 || OptionParser::getOptions().verbose)
{
std::cout << __func__ << ": Successfully attached Livox "
"device: " << desc->deviceSelector << " (ID: "
<< desc->deviceIdentifier << ")\n";
}
cb(success);
}
);
/** EXPLANATION:
* Bridge the async call by dequeueing until callbackCalled is true.
*/
for (;;)
{
self->getIoService().run_one();
if (callbackCalled.load() || self->getIoService().stopped())
{ break; }
}
if (!device)
{
throw std::runtime_error(
std::string(__func__) + ": Failed to create Livox device: "
+ desc->deviceSelector);
}
g_attachedDevices.push_back(device);
if (1 || OptionParser::getOptions().verbose)
{
std::cout << __func__ << ": Successfully attached Livox device: "
<< desc->deviceSelector << " (ID: " << desc->deviceIdentifier
<< ")\n";
}
return 0; // Success
}
extern "C" int livoxGen1_detachDeviceReq(
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& desc
extern "C" void livoxGen1_detachDeviceReq(
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& desc,
smo::sense_api::sal_mlo_detachDeviceReqCbFn cb
)
{
/** FIXME:
* We should acquire a spinlock here to ensure that iterator doesn't become
* invalid in the interim while the async op executes. In the meantime,
* we'll repeat the search in the callback.
*/
// Find and remove the device from our collection
auto it = std::find_if(g_attachedDevices.begin(), g_attachedDevices.end(),
[&desc](const std::shared_ptr<livoxProto1::Device>& dev) {
@@ -304,44 +306,52 @@ extern "C" int livoxGen1_detachDeviceReq(
if (it == g_attachedDevices.end())
{
std::cerr << __func__ << ": Device not found for detachment: "
<< desc->deviceIdentifier << "\n";
return -1; // Device not found
throw std::runtime_error(
std::string(__func__) +
": Device not found for detachment: " + desc->deviceIdentifier);
}
std::atomic<bool> callbackCalled{false};
bool retVal = false;
std::shared_ptr<ComponentThread> self = smoHooksPtr->
ComponentThread_getSelf();
(*livoxProto1.livoxProto1_destroyDeviceReq)(
*it,
[&callbackCalled, &retVal, self](bool success)
[cb, desc](bool success)
{
callbackCalled.store(true);
retVal = success;
self->getIoService().post([]{});
if (!success)
{
std::cerr << __func__ << ": Failed to destroy Livox device: "
<< desc->deviceIdentifier << "\n";
cb(false);
return;
}
// Find the device in g_attachedDevices and remove it.
auto eraseIt = std::find_if(
g_attachedDevices.begin(), g_attachedDevices.end(),
[desc](const std::shared_ptr<livoxProto1::Device>& dev)
{
const std::string& devId = dev->discoveredDevice.deviceIdentifier;
std::string devIdPrefix = devId.substr(
0, std::min<size_t>(14, devId.size()));
return devIdPrefix == desc->deviceSelector.substr(
0, std::min<size_t>(14, desc->deviceSelector.size()));
}
);
if (eraseIt == g_attachedDevices.end())
{
std::cerr << __func__ << ": Race condition: device not found "
"in g_attachedDevices for detachment: "
<< desc->deviceIdentifier << "\n";
cb(false);
return;
}
g_attachedDevices.erase(eraseIt);
std::cout << __func__ << ": Successfully detached Livox device: "
<< desc->deviceIdentifier << "\n";
cb(success);
}
);
for (;;)
{
self->getIoService().run_one();
if (callbackCalled.load() || self->getIoService().stopped())
{ break; }
}
if (!retVal)
{
std::cerr << __func__ << ": Failed to destroy Livox device: "
<< desc->deviceIdentifier << std::endl;
}
g_attachedDevices.erase(it);
std::cout << __func__ << ": Successfully detached Livox device: "
<< desc->deviceIdentifier << "\n";
return 0;
}
// Exported function
+15 -9
View File
@@ -273,8 +273,9 @@ static int xcbWindow_finalizeInd(void)
return 0;
}
static int xcbWindow_attachDeviceReq(
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& desc
static void xcbWindow_attachDeviceReq(
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& desc,
smo::sense_api::sal_mlo_attachDeviceReqCbFn cb
)
{
g_attachedWindows.emplace_back(
@@ -283,11 +284,13 @@ static int xcbWindow_attachDeviceReq(
std::cout << __func__ << ": Attached X11 window:\n "
<< g_attachedWindows.back()->stringify()
<< "\n";
return 0;
cb(true);
}
static int xcbWindow_detachDeviceReq(
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& spec
static void xcbWindow_detachDeviceReq(
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& spec,
smo::sense_api::sal_mlo_detachDeviceReqCbFn cb
)
{
auto it = std::find_if(g_attachedWindows.begin(), g_attachedWindows.end(),
@@ -298,15 +301,18 @@ static int xcbWindow_detachDeviceReq(
if (it == g_attachedWindows.end())
{
std::cerr << __func__ << ": Device not found for detachment:\n"
<< spec->stringify() << "\n";
return -1;
std::cerr << __func__ << ": Device not found for detachment:\n"
<< spec->stringify() << "\n";
cb(false);
return;
}
g_attachedWindows.erase(it);
std::cout << __func__ << ": Detached X11 window device:\n"
<< spec->stringify() << "\n";
return 0;
cb(true);
}
// SenseApi descriptor