LivoxGen1: Port to coros

No longer uses CPS. We also found and documented a potential bug in
the way we deal with disablePcloudData during detachDeviceReq.
This commit is contained in:
2026-05-28 15:17:50 -04:00
parent 7643cf7fed
commit fc5ebb72b9
10 changed files with 966 additions and 741 deletions
+95
View File
@@ -0,0 +1,95 @@
#ifndef ADAPTERS_SMO_CPS_CALLBACK_AREQ_H
#define ADAPTERS_SMO_CPS_CALLBACK_AREQ_H
#include <boostAsioLinkageFix.h>
#include <atomic>
#include <coroutine>
#include <functional>
#include <memory>
#include <boost/asio/io_service.hpp>
#include <boost/asio/post.hpp>
#include <spinscale/cps/callback.h>
namespace smo {
namespace cpsBoundary {
/** Eager-start CPS callback -> coroutine adapter (mirrors
* PuppetThread::ViralThreadLifetimeMgmtInvoker).
*/
template <typename Result, typename CallbackFn, typename StartFn>
class CpsCallbackAReq
{
public:
struct AsyncState
{
std::atomic<bool> settled{false};
Result result{};
std::coroutine_handle<> callerSchedHandle;
};
CpsCallbackAReq(
boost::asio::io_service &resumeIoService,
StartFn startFn)
: asyncState(std::make_shared<AsyncState>()),
resumeIoService(resumeIoService)
{
startFn(sscl::cps::Callback<CallbackFn>{
nullptr,
[this](auto &&...args)
{
storeResult(std::forward<decltype(args)>(args)...);
signalSettledAndResumeCaller();
}});
}
bool await_ready() const noexcept
{
return asyncState->settled.load(std::memory_order_acquire);
}
bool await_suspend(std::coroutine_handle<> callerSchedHandle) noexcept
{
if (asyncState->settled.load(std::memory_order_acquire)) {
return false;
}
asyncState->callerSchedHandle = callerSchedHandle;
return true;
}
Result await_resume() noexcept
{
return asyncState->result;
}
private:
template <typename... Args>
void storeResult(Args &&...args)
{
asyncState->result = Result{std::forward<Args>(args)...};
}
void signalSettledAndResumeCaller() noexcept
{
asyncState->settled.store(true, std::memory_order_release);
std::coroutine_handle<> handle = asyncState->callerSchedHandle;
if (!handle) {
return;
}
boost::asio::post(
resumeIoService,
[handle]() { handle.resume(); });
}
std::shared_ptr<AsyncState> asyncState;
boost::asio::io_service &resumeIoService;
};
} // namespace cpsBoundary
} // namespace smo
#endif // ADAPTERS_SMO_CPS_CALLBACK_AREQ_H
@@ -0,0 +1,121 @@
#ifndef ADAPTERS_SMO_LIVOX_PROTO1_CPS_AWAITERS_H
#define ADAPTERS_SMO_LIVOX_PROTO1_CPS_AWAITERS_H
#include <cstdint>
#include <memory>
#include <adapters/smo/cpsCallbackAReq.h>
#include <livoxProto1/livoxProto1.h>
#include <spinscale/componentThread.h>
namespace adapters::smo {
struct GetOrCreateDeviceResult
{
bool success = false;
std::shared_ptr<livoxProto1::Device> device;
};
struct GetReturnModeResult
{
bool success = false;
uint8_t returnMode = 0;
};
inline auto getGetOrCreateDeviceReqAReqAwaiter(
boost::asio::io_service &resumeIoService,
livoxProto1_getOrCreateDeviceReqFn *fn,
const std::string &deviceIdentifier,
const std::shared_ptr<sscl::ComponentThread> &componentThread,
int commandTimeoutMs,
int retryDelayMs,
const std::string &smoIp,
uint8_t smoSubnetNbits,
uint16_t dataPort,
uint16_t cmdPort,
uint16_t imuPort)
{
return ::smo::cpsBoundary::CpsCallbackAReq<
GetOrCreateDeviceResult,
livoxProto1_getOrCreateDeviceReqCbFn,
std::function<void(sscl::cps::Callback<livoxProto1_getOrCreateDeviceReqCbFn>)>>(
resumeIoService,
[=](sscl::cps::Callback<livoxProto1_getOrCreateDeviceReqCbFn> cb)
{
(*fn)(
deviceIdentifier,
componentThread,
commandTimeoutMs, retryDelayMs,
smoIp, smoSubnetNbits,
dataPort, cmdPort, imuPort,
std::move(cb));
});
}
inline auto getDeviceGetReturnModeReqAReqAwaiter(
boost::asio::io_service &resumeIoService,
livoxProto1_device_getReturnModeReqFn *fn,
std::shared_ptr<livoxProto1::Device> device)
{
return ::smo::cpsBoundary::CpsCallbackAReq<
GetReturnModeResult,
livoxProto1_device_getReturnModeReqCbFn,
std::function<void(sscl::cps::Callback<livoxProto1_device_getReturnModeReqCbFn>)>>(
resumeIoService,
[=](sscl::cps::Callback<livoxProto1_device_getReturnModeReqCbFn> cb)
{
(*fn)(device, std::move(cb));
});
}
inline auto getDeviceEnablePcloudDataReqAReqAwaiter(
boost::asio::io_service &resumeIoService,
livoxProto1_device_enablePcloudDataReqFn *fn,
std::shared_ptr<livoxProto1::Device> device)
{
return ::smo::cpsBoundary::CpsCallbackAReq<
bool,
livoxProto1_device_enablePcloudDataReqCbFn,
std::function<void(sscl::cps::Callback<livoxProto1_device_enablePcloudDataReqCbFn>)>>(
resumeIoService,
[=](sscl::cps::Callback<livoxProto1_device_enablePcloudDataReqCbFn> cb)
{
(*fn)(device, std::move(cb));
});
}
inline auto getDeviceDisablePcloudDataReqAReqAwaiter(
boost::asio::io_service &resumeIoService,
livoxProto1_device_disablePcloudDataReqFn *fn,
std::shared_ptr<livoxProto1::Device> device)
{
return ::smo::cpsBoundary::CpsCallbackAReq<
bool,
livoxProto1_device_disablePcloudDataReqCbFn,
std::function<void(sscl::cps::Callback<livoxProto1_device_disablePcloudDataReqCbFn>)>>(
resumeIoService,
[=](sscl::cps::Callback<livoxProto1_device_disablePcloudDataReqCbFn> cb)
{
(*fn)(device, std::move(cb));
});
}
inline auto getDestroyDeviceReqAReqAwaiter(
boost::asio::io_service &resumeIoService,
livoxProto1_destroyDeviceReqFn *fn,
std::shared_ptr<livoxProto1::Device> device)
{
return ::smo::cpsBoundary::CpsCallbackAReq<
bool,
livoxProto1_destroyDeviceReqCbFn,
std::function<void(sscl::cps::Callback<livoxProto1_destroyDeviceReqCbFn>)>>(
resumeIoService,
[=](sscl::cps::Callback<livoxProto1_destroyDeviceReqCbFn> cb)
{
(*fn)(device, std::move(cb));
});
}
} // namespace adapters::smo
#endif // ADAPTERS_SMO_LIVOX_PROTO1_CPS_AWAITERS_H