Libspinscale: Initial top-level SMO port to coroutine framework
We haven't ported everything. Just the top-level methods. We'll dig in to the leaf stuff later. Surprisingly, this all went without any real difficulties. Runs like a charm on first try.
This commit is contained in:
+72
-163
@@ -1,15 +1,12 @@
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <opts.h>
|
||||
#include <spinscale/asynchronousContinuation.h>
|
||||
#include <spinscale/asynchronousLoop.h>
|
||||
#include <spinscale/callback.h>
|
||||
#include <spinscale/callableTracer.h>
|
||||
#include <spinscale/puppetApplication.h>
|
||||
#include <body/body.h>
|
||||
#include <body/bodyThread.h>
|
||||
#include <componentThread.h>
|
||||
#include <deviceManager/deviceManager.h>
|
||||
#include <mind.h>
|
||||
#include <stimBuffApis/stimBuffApiManager.h>
|
||||
#include <deviceManager/deviceManager.h>
|
||||
|
||||
namespace smo {
|
||||
namespace body {
|
||||
@@ -19,165 +16,71 @@ Body::Body(Mind &parent, const std::shared_ptr<sscl::PuppetThread> &thread)
|
||||
{
|
||||
}
|
||||
|
||||
class Body::InitializeReq
|
||||
: public sscl::PostedAsynchronousContinuation<bodyLifetimeMgmtOpCbFn>
|
||||
BodyViralPostingInvoker<bool> Body::initializeCReq()
|
||||
{
|
||||
public:
|
||||
InitializeReq(
|
||||
sscl::PuppetApplication &parent,
|
||||
const std::shared_ptr<sscl::ComponentThread> &caller,
|
||||
sscl::Callback<bodyLifetimeMgmtOpCbFn> callback)
|
||||
: sscl::PostedAsynchronousContinuation<bodyLifetimeMgmtOpCbFn>(caller, callback),
|
||||
parent(parent)
|
||||
{}
|
||||
|
||||
private:
|
||||
sscl::PuppetApplication &parent;
|
||||
|
||||
public:
|
||||
void initializeReq1_posted(
|
||||
[[maybe_unused]] std::shared_ptr<InitializeReq> context
|
||||
)
|
||||
{
|
||||
auto self = sscl::ComponentThread::getSelf();
|
||||
if (self->id != SmoThreadId::BODY)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Must be executed on Body thread");
|
||||
}
|
||||
|
||||
/** EXPLANATION:
|
||||
* The ComponentThread instance we pass in here is the one that will be
|
||||
* used by Senseapi libs to perform device-independent background
|
||||
* operations.
|
||||
* For example, liblivoxProto1's BroadcastListener will use this thread
|
||||
* to listen for UDP broadcast dgrams from Livox devices.
|
||||
*
|
||||
* We used to use Marionette, but there's a strong argument for using
|
||||
* Body instead since it's meant to handle device-management operations.
|
||||
*/
|
||||
// Upcast to Mind to access Mind-specific members
|
||||
Mind &mind = static_cast<Mind&>(context->parent);
|
||||
stim_buff::StimBuffApiManager::getInstance()
|
||||
.loadAllStimBuffApiLibsFromOptions(mind.body.thread);
|
||||
|
||||
/** EXPLANATION:
|
||||
* Consider body::initializeReq to have been called if even one of its
|
||||
* operations was executed at all, whether successfully or
|
||||
* unsuccessfully.
|
||||
*/
|
||||
mind.bodyComponentInitialized = true;
|
||||
|
||||
std::cout << stim_buff::StimBuffApiManager::getInstance().stringifyLibs()
|
||||
<< std::endl;
|
||||
|
||||
if (OptionParser::getOptions().verbose)
|
||||
{
|
||||
std::cout << __func__ << ": About to initializeAllStimBuffApiLibs"
|
||||
<< '\n';
|
||||
}
|
||||
stim_buff::StimBuffApiManager::getInstance()
|
||||
.initializeAllStimBuffApiLibs();
|
||||
|
||||
if (OptionParser::getOptions().verbose)
|
||||
{
|
||||
std::cout << __func__ << ": About to attachAllSenseDevicesFromSpecs"
|
||||
<< '\n';
|
||||
}
|
||||
device::DeviceManager::getInstance()
|
||||
.attachAllUnattachedDevicesFromCmdlineReq(
|
||||
{context, std::bind(
|
||||
&InitializeReq::initializeReq2,
|
||||
context.get(), context,
|
||||
std::placeholders::_1)});
|
||||
}
|
||||
|
||||
void initializeReq2(
|
||||
[[maybe_unused]] std::shared_ptr<InitializeReq> context,
|
||||
sscl::AsynchronousLoop &results
|
||||
)
|
||||
{
|
||||
std::cout << "Mrntt: attached "
|
||||
<< results.nSucceeded << " of " << results.nTotal
|
||||
<< " sense devices." << "\n";
|
||||
|
||||
callOriginalCb(results.nSucceeded > 0);
|
||||
}
|
||||
};
|
||||
|
||||
class Body::FinalizeReq
|
||||
: public InitializeReq
|
||||
{
|
||||
public:
|
||||
using InitializeReq::InitializeReq;
|
||||
|
||||
public:
|
||||
void finalizeReq1_posted(
|
||||
[[maybe_unused]] std::shared_ptr<FinalizeReq> context
|
||||
)
|
||||
{
|
||||
auto self = sscl::ComponentThread::getSelf();
|
||||
if (self->id != SmoThreadId::BODY)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Must be executed on Body thread");
|
||||
}
|
||||
|
||||
std::cout << "Mrntt: About to detach all sense devices." << "\n";
|
||||
device::DeviceManager::getInstance().detachAllAttachedDeviceRoles(
|
||||
{context, std::bind(
|
||||
&FinalizeReq::finalizeReq2,
|
||||
context.get(), context,
|
||||
std::placeholders::_1)});
|
||||
}
|
||||
|
||||
void finalizeReq2(
|
||||
[[maybe_unused]] std::shared_ptr<FinalizeReq> context,
|
||||
sscl::AsynchronousLoop &results
|
||||
)
|
||||
{
|
||||
std::cout << "Mrntt: Successfully detached "
|
||||
<< results.nSucceeded << " of " << results.nTotal
|
||||
<< " sense devices." << "\n";
|
||||
|
||||
std::cout << "Mrntt: About to finalize all stim buff api libs." << "\n";
|
||||
stim_buff::StimBuffApiManager::getInstance().finalizeAllStimBuffApiLibs();
|
||||
|
||||
std::cout << "Mrntt: About to unload all stim buff api libs." << "\n";
|
||||
stim_buff::StimBuffApiManager::getInstance().unloadAllStimBuffApiLibs();
|
||||
callOriginalCb(results.nSucceeded == results.nTotal);
|
||||
}
|
||||
};
|
||||
|
||||
void Body::initializeReq(sscl::Callback<bodyLifetimeMgmtOpCbFn> callback)
|
||||
{
|
||||
auto mrntt = sscl::ComponentThread::getSelf();
|
||||
|
||||
if (mrntt->id != SmoThreadId::MRNTT)
|
||||
auto self = sscl::ComponentThread::getSelf();
|
||||
if (self->id != SmoThreadId::BODY)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Must be invoked by Mrntt thread");
|
||||
+ ": Must be executed on Body thread");
|
||||
}
|
||||
|
||||
auto request = std::make_shared<InitializeReq>(
|
||||
parent, mrntt, callback);
|
||||
/** EXPLANATION:
|
||||
* The ComponentThread instance we pass in here is the one that will be
|
||||
* used by Senseapi libs to perform device-independent background
|
||||
* operations.
|
||||
* For example, liblivoxProto1's BroadcastListener will use this thread
|
||||
* to listen for UDP broadcast dgrams from Livox devices.
|
||||
*
|
||||
* We used to use Marionette, but there's a strong argument for using
|
||||
* Body instead since it's meant to handle device-management operations.
|
||||
*/
|
||||
// Upcast to Mind to access Mind-specific members
|
||||
Mind &mind = static_cast<Mind&>(parent);
|
||||
stim_buff::StimBuffApiManager::getInstance()
|
||||
.loadAllStimBuffApiLibsFromOptions(mind.body.thread);
|
||||
|
||||
thread->getIoService().post(
|
||||
STC(std::bind(
|
||||
&InitializeReq::initializeReq1_posted,
|
||||
request.get(), request)));
|
||||
/** EXPLANATION:
|
||||
* Consider body::initializeCReq to have been called if even one of its
|
||||
* operations was executed at all, whether successfully or
|
||||
* unsuccessfully.
|
||||
*/
|
||||
mind.bodyComponentInitialized = true;
|
||||
|
||||
std::cout << stim_buff::StimBuffApiManager::getInstance().stringifyLibs()
|
||||
<< std::endl;
|
||||
|
||||
if (OptionParser::getOptions().verbose)
|
||||
{
|
||||
std::cout << __func__ << ": About to initializeAllStimBuffApiLibs"
|
||||
<< '\n';
|
||||
}
|
||||
stim_buff::StimBuffApiManager::getInstance()
|
||||
.initializeAllStimBuffApiLibs();
|
||||
|
||||
if (OptionParser::getOptions().verbose)
|
||||
{
|
||||
std::cout << __func__ << ": About to attachAllUnattachedDevicesFromCmdline"
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
sscl::MultiOperationResultSet attachResults = co_await
|
||||
device::DeviceManager::getInstance()
|
||||
.attachAllUnattachedDevicesFromCmdlineCReq();
|
||||
std::cout << "Mrntt: attached "
|
||||
<< attachResults.nSucceeded << " of " << attachResults.nTotal
|
||||
<< " sense devices." << "\n";
|
||||
|
||||
co_return attachResults.nSucceeded > 0;
|
||||
}
|
||||
|
||||
void Body::finalizeReq(sscl::Callback<bodyLifetimeMgmtOpCbFn> callback)
|
||||
BodyViralPostingInvoker<bool> Body::finalizeCReq()
|
||||
{
|
||||
auto mrntt = sscl::ComponentThread::getSelf();
|
||||
|
||||
if (mrntt->id != SmoThreadId::MRNTT)
|
||||
auto self = sscl::ComponentThread::getSelf();
|
||||
if (self->id != SmoThreadId::BODY)
|
||||
{
|
||||
std::cerr << __func__ << ": Must be invoked by Mrntt thread"
|
||||
<< std::endl;
|
||||
callback.callbackFn(false);
|
||||
return;
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Must be executed on Body thread");
|
||||
}
|
||||
|
||||
// Upcast to Mind to access Mind-specific members
|
||||
@@ -186,17 +89,23 @@ void Body::finalizeReq(sscl::Callback<bodyLifetimeMgmtOpCbFn> callback)
|
||||
{
|
||||
std::cout << "Mrntt: Body component not initialized. "
|
||||
<< "Skipping finalization." << "\n";
|
||||
callback.callbackFn(true);
|
||||
return;
|
||||
co_return true;
|
||||
}
|
||||
|
||||
auto request = std::make_shared<FinalizeReq>(
|
||||
parent, mrntt, callback);
|
||||
std::cout << "Mrntt: About to detach all sense devices." << "\n";
|
||||
sscl::MultiOperationResultSet detachResults = co_await
|
||||
device::DeviceManager::getInstance().detachAllAttachedDeviceRolesCReq();
|
||||
std::cout << "Mrntt: Successfully detached "
|
||||
<< detachResults.nSucceeded << " of " << detachResults.nTotal
|
||||
<< " sense devices." << "\n";
|
||||
|
||||
thread->getIoService().post(
|
||||
STC(std::bind(
|
||||
&FinalizeReq::finalizeReq1_posted,
|
||||
request.get(), request)));
|
||||
std::cout << "Mrntt: About to finalize all stim buff api libs." << "\n";
|
||||
stim_buff::StimBuffApiManager::getInstance().finalizeAllStimBuffApiLibs();
|
||||
|
||||
std::cout << "Mrntt: About to unload all stim buff api libs." << "\n";
|
||||
stim_buff::StimBuffApiManager::getInstance().unloadAllStimBuffApiLibs();
|
||||
|
||||
co_return detachResults.nSucceeded == detachResults.nTotal;
|
||||
}
|
||||
|
||||
} // namespace body
|
||||
|
||||
Reference in New Issue
Block a user