816a047920
Async: Use new [Non]PostedAsyncCont and callOriginalCb This new hierarchy of classes gives us a central mechanism for managing both reply-posting and lockSpec unlocking. * callOriginalCb: Now uses a modern C++ variadic template design enabling it to handle both direct calling and std::bind() re-binding of an arbitrary number of arguments from the caller. This enables us to mostly eliminate the repeated, bespoke definitions of callOriginalCb littered throughout the codebase. We've also propagated these changes throughout the codebase in this patch.
194 lines
4.9 KiB
C++
194 lines
4.9 KiB
C++
#include <iostream>
|
|
#include <opts.h>
|
|
#include <asynchronousContinuation.h>
|
|
#include <asynchronousLoop.h>
|
|
#include <body/body.h>
|
|
#include <componentThread.h>
|
|
#include <mind.h>
|
|
#include <senseApis/senseApiManager.h>
|
|
|
|
namespace smo {
|
|
namespace body {
|
|
|
|
Body::Body(Mind &parent, const std::shared_ptr<ComponentThread> &thread)
|
|
: MindComponent(parent, thread)
|
|
{
|
|
}
|
|
|
|
class Body::InitializeReq
|
|
: public PostedAsynchronousContinuation<bodyLifetimeMgmtOpCbFn>
|
|
{
|
|
public:
|
|
InitializeReq(
|
|
Mind &parent, const std::shared_ptr<ComponentThread> &caller,
|
|
bodyLifetimeMgmtOpCbFn callback)
|
|
: PostedAsynchronousContinuation<bodyLifetimeMgmtOpCbFn>(caller, callback),
|
|
parent(parent)
|
|
{}
|
|
|
|
private:
|
|
Mind &parent;
|
|
|
|
public:
|
|
void initializeReq1_posted(
|
|
[[maybe_unused]] std::shared_ptr<InitializeReq> context
|
|
)
|
|
{
|
|
auto self = ComponentThread::getSelf();
|
|
if (self->id != ComponentThread::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.
|
|
*
|
|
* Right now we use Marionette, but there's a strong argument for using
|
|
* Body instead since it's meant to handle device-management operations.
|
|
*/
|
|
sense_api::SenseApiManager::getInstance()
|
|
.loadAllSenseApiLibsFromOptions(caller);
|
|
|
|
/** EXPLANATION:
|
|
* Consider body::initializeReq to have been called if even one of its
|
|
* operations was executed at all, whether successfully or
|
|
* unsuccessfully.
|
|
*/
|
|
context->parent.bodyComponentInitialized = true;
|
|
|
|
std::cout << sense_api::SenseApiManager::getInstance().stringifyLibs()
|
|
<< std::endl;
|
|
|
|
if (OptionParser::getOptions().verbose)
|
|
{
|
|
std::cout << __func__ << ": About to initializeAllSenseApiLibs"
|
|
<< '\n';
|
|
}
|
|
sense_api::SenseApiManager::getInstance().initializeAllSenseApiLibs();
|
|
|
|
if (OptionParser::getOptions().verbose)
|
|
{
|
|
std::cout << __func__ << ": About to attachAllSenseDevicesFromSpecs"
|
|
<< '\n';
|
|
}
|
|
sense_api::SenseApiManager::getInstance()
|
|
.attachAllSenseDevicesFromSpecsReq(
|
|
std::bind(
|
|
&InitializeReq::initializeReq2,
|
|
context.get(), context,
|
|
std::placeholders::_1));
|
|
}
|
|
|
|
void initializeReq2(
|
|
[[maybe_unused]] std::shared_ptr<InitializeReq> context,
|
|
smo::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 = ComponentThread::getSelf();
|
|
if (self->id != ComponentThread::BODY)
|
|
{
|
|
throw std::runtime_error(std::string(__func__)
|
|
+ ": Must be executed on Body thread");
|
|
}
|
|
|
|
std::cout << "Mrntt: About to detach all sense devices." << "\n";
|
|
sense_api::SenseApiManager::getInstance().detachAllSenseDevicesReq(
|
|
std::bind(
|
|
&FinalizeReq::finalizeReq2,
|
|
context.get(), context,
|
|
std::placeholders::_1));
|
|
}
|
|
|
|
void finalizeReq2(
|
|
[[maybe_unused]] std::shared_ptr<FinalizeReq> context,
|
|
smo::AsynchronousLoop &results
|
|
)
|
|
{
|
|
std::cout << "Mrntt: Successfully detached "
|
|
<< results.nSucceeded << " of " << results.nTotal
|
|
<< " sense devices." << "\n";
|
|
|
|
std::cout << "Mrntt: About to finalize all sense api libs." << "\n";
|
|
sense_api::SenseApiManager::getInstance().finalizeAllSenseApiLibs();
|
|
|
|
std::cout << "Mrntt: About to unload all sense api libs." << "\n";
|
|
sense_api::SenseApiManager::getInstance().unloadAllSenseApiLibs();
|
|
callOriginalCb(results.nSucceeded == results.nTotal);
|
|
}
|
|
};
|
|
|
|
void Body::initializeReq(bodyLifetimeMgmtOpCbFn callback)
|
|
{
|
|
auto mrntt = ComponentThread::getSelf();
|
|
|
|
if (mrntt->id != ComponentThread::MRNTT)
|
|
{
|
|
throw std::runtime_error(std::string(__func__)
|
|
+ ": Must be invoked by Mrntt thread");
|
|
}
|
|
|
|
auto request = std::make_shared<InitializeReq>(
|
|
parent, mrntt, callback);
|
|
|
|
thread->getIoService().post(
|
|
std::bind(
|
|
&InitializeReq::initializeReq1_posted,
|
|
request.get(), request));
|
|
}
|
|
|
|
void Body::finalizeReq(bodyLifetimeMgmtOpCbFn callback)
|
|
{
|
|
auto mrntt = ComponentThread::getSelf();
|
|
|
|
if (mrntt->id != ComponentThread::MRNTT)
|
|
{
|
|
std::cerr << __func__ << ": Must be invoked by Mrntt thread"
|
|
<< std::endl;
|
|
callback(false);
|
|
return;
|
|
}
|
|
|
|
if (!parent.bodyComponentInitialized)
|
|
{
|
|
std::cout << "Mrntt: Body component not initialized. "
|
|
<< "Skipping finalization." << "\n";
|
|
callback(true);
|
|
return;
|
|
}
|
|
|
|
auto request = std::make_shared<FinalizeReq>(
|
|
parent, mrntt, callback);
|
|
|
|
thread->getIoService().post(
|
|
std::bind(
|
|
&FinalizeReq::finalizeReq1_posted,
|
|
request.get(), request));
|
|
}
|
|
|
|
} // namespace body
|
|
} // namespace smo
|