StimBuff: Make virtual so we can dynamic_cast in getOrCreateStimBuff

This commit is contained in:
2025-11-16 02:23:53 -04:00
parent addd2e275d
commit c5ed453bb4
6 changed files with 162 additions and 12 deletions
@@ -29,6 +29,28 @@ std::shared_ptr<StimulusBuffer> StimulusProducer::getAttachedStimulusBuffer(
return nullptr;
}
bool StimulusProducer::hasBufferWithQualeIfaceApi(
const std::string& qualeIfaceApi) const
{
for (const auto& buffer : attachedStimulusBuffers)
{
if (!buffer || !buffer->deviceAttachmentSpec)
{
throw std::runtime_error(
"StimulusProducer::hasBufferWithQualeIfaceApi: encountered "
"null buffer or null deviceAttachmentSpec in "
"attachedStimulusBuffers (should never happen)");
}
if (buffer->deviceAttachmentSpec->qualeIfaceApi != qualeIfaceApi)
{ continue; }
return true;
}
return false;
}
void StimulusProducer::stop()
{
{
+1 -1
View File
@@ -39,7 +39,7 @@ public:
ringBufferConstraints)
{}
~StimulusBuffer() = default;
virtual ~StimulusBuffer() = default;
// Non-copyable, movable
StimulusBuffer(const StimulusBuffer&) = delete;
+4 -1
View File
@@ -69,13 +69,16 @@ public:
void allowNextStimulusFrame()
{ frameAssemblyRateLimiter.release(); }
std::shared_ptr<StimulusBuffer> getAttachedStimulusBuffer(
virtual std::shared_ptr<StimulusBuffer> getAttachedStimulusBuffer(
const std::shared_ptr<device::DeviceAttachmentSpec>& spec) const;
virtual std::shared_ptr<StimulusBuffer> getOrCreateAttachedStimulusBuffer(
const std::shared_ptr<device::DeviceAttachmentSpec>& deviceAttachmentSpec,
int histbuffMs) = 0;
// Check if any attached buffer has the specified qualeIfaceApi
bool hasBufferWithQualeIfaceApi(const std::string& qualeIfaceApi) const;
protected:
SpinLock frameAssemblyRateLimiter;
+61 -2
View File
@@ -30,6 +30,8 @@ static SmoThreadingModelDesc smoThreadingModelDesc;
// Local collection of stimulus producers
static std::vector<std::shared_ptr<StimulusProducer>> attachedStimulusProducers;
static bool isSupportedQualeIfaceApi(const std::string& qualeIfaceApi);
// Check if a StimulusProducer matches the requested stim feature
static bool isProducerForStimFeature(
const std::shared_ptr<StimulusProducer>& stimProducer,
@@ -192,6 +194,17 @@ private:
return false;
}
// Check for duplicate qualeIfaceApi
const std::string& qualeIfaceApi = context->spec->qualeIfaceApi;
if (context->stimProducer->hasBufferWithQualeIfaceApi(qualeIfaceApi))
{
std::cerr << __func__ << ": Buffer with qualeIfaceApi '"
<< qualeIfaceApi << "' already exists for this producer. "
"Each producer can only have one buffer per qualeIfaceApi."
<< std::endl;
return false;
}
// Parse histbuffMs
int histbuffMs = parseHistbuffMs(context->spec);
@@ -203,7 +216,7 @@ private:
std::cerr << __func__ << ": Failed to create StimBuffer: "
<< e.what() << ". Producer is committed, DeviceReattacher will retry."
<< std::endl;
// Return false so DeviceReattacher can retry later
// Return false so caller can handle error callback
return false;
}
@@ -604,6 +617,13 @@ static const StimBuffApiDesc livoxGen1ApiDesc = {
}
};
static bool isSupportedQualeIfaceApi(const std::string& qualeIfaceApi)
{
// Check if this is a supported (implemented) qualeIfaceApi
return qualeIfaceApi == "mesh" || qualeIfaceApi == "pcloudIntensity" ||
qualeIfaceApi == "pcloudAmbience";
}
// Callback function implementations
extern "C" int livoxGen1_initializeInd(void)
{
@@ -713,6 +733,29 @@ extern "C" void livoxGen1_attachDeviceReq(
"not available");
}
// Validate qualeIfaceApi
const std::string& qualeIfaceApi = desc->qualeIfaceApi;
if (qualeIfaceApi == "gyro" || qualeIfaceApi == "accel")
{
// These are for ImuStimulusProducer (not yet implemented)
std::cerr << __func__ << ": qualeIfaceApi '" << qualeIfaceApi
<< "' requires ImuStimulusProducer which is not yet implemented"
<< std::endl;
cb.callbackFn(false, desc);
return;
}
if (!isSupportedQualeIfaceApi(qualeIfaceApi))
{
// Unknown qualeIfaceApi
std::cerr << __func__ << ": Unsupported qualeIfaceApi '"
<< qualeIfaceApi << "' for LivoxGen1. "
"Supported values: mesh, pcloudIntensity, pcloudAmbience"
<< std::endl;
cb.callbackFn(false, desc);
return;
}
auto request = std::make_shared<AttachDeviceReq>(desc, cb);
// Case 1: Check if StimBuffer already exists
@@ -740,7 +783,23 @@ extern "C" void livoxGen1_attachDeviceReq(
}
else
{
// StimProducer exists, StimBuffer doesn't
/** EXPLANATION:
* StimProducer exists, StimBuffer doesn't (DASpec doesn't match)
* Check if producer already has a buffer with the requested
* qualeIfaceApi but different DASpec - this is not allowed.
*/
if (stimProducer->hasBufferWithQualeIfaceApi(desc->qualeIfaceApi))
{
std::cerr << __func__ << ": Producer already has a buffer with "
"qualeIfaceApi '" << desc->qualeIfaceApi
<< "' but with a different DeviceAttachmentSpec. "
"A single LivoxGen1 device cannot support multiple DASpecs "
"with the same qualeIfaceApi." << std::endl;
cb.callbackFn(false, desc);
return;
}
request->stimProducer = stimProducer;
// Ensure StimBuffer is attached and enable pcloud data if needed
request->attachDeviceReq4_doCreateStimBuff_maybeDirectlyCalled(
@@ -106,6 +106,40 @@ void produceStimFrameAck(void)
{
}
std::shared_ptr<StimulusBuffer>
PcloudStimulusProducer::getAttachedStimulusBuffer(
const std::shared_ptr<device::DeviceAttachmentSpec>& spec) const
{
// Call base class implementation
auto buffer = StimulusProducer::getAttachedStimulusBuffer(spec);
if (!buffer)
{
return nullptr;
}
// Optionally validate/upcast the buffer type matches expected type
// based on qualeIfaceApi (for type safety)
const std::string& qualeIfaceApi = spec->qualeIfaceApi;
if (qualeIfaceApi == "mesh")
{
if (std::dynamic_pointer_cast<MeshStimulusBuffer>(buffer))
{ return buffer; }
}
else if (qualeIfaceApi == "pcloudIntensity")
{
if (std::dynamic_pointer_cast<PcloudIntensityStimulusBuffer>(buffer))
{ return buffer; }
}
else if (qualeIfaceApi == "pcloudAmbience")
{
if (std::dynamic_pointer_cast<PcloudAmbienceStimulusBuffer>(buffer))
{ return buffer; }
}
// Type mismatch - return nullptr
return nullptr;
}
std::shared_ptr<StimulusBuffer>
PcloudStimulusProducer::getOrCreateAttachedStimulusBuffer(
const std::shared_ptr<device::DeviceAttachmentSpec>& deviceAttachmentSpec,
@@ -117,15 +151,43 @@ PcloudStimulusProducer::getOrCreateAttachedStimulusBuffer(
if (existingBuffer)
{ return existingBuffer; }
// Create new MeshStimulusBuffer (for now, always use XYZ type)
auto buffer = std::make_shared<MeshStimulusBuffer>(
// Parse qualeIfaceApi to determine buffer type
const std::string& qualeIfaceApi = deviceAttachmentSpec->qualeIfaceApi;
if (qualeIfaceApi == "mesh")
{
auto meshBuffer = std::make_shared<MeshStimulusBuffer>(
*this, deviceAttachmentSpec, histbuffMs, openClInputConstraints);
// Add to collection
attachedStimulusBuffers.push_back(buffer);
// Update specialized member
meshStimulusBuffer = buffer;
return buffer;
meshStimulusBuffer = meshBuffer;
attachedStimulusBuffers.push_back(meshBuffer);
return meshBuffer;
}
else if (qualeIfaceApi == "pcloudIntensity")
{
auto intensityBuffer = std::make_shared<PcloudIntensityStimulusBuffer>(
*this, deviceAttachmentSpec, histbuffMs, openClInputConstraints);
intensityStimulusBuffer = intensityBuffer;
attachedStimulusBuffers.push_back(intensityBuffer);
return intensityBuffer;
}
else if (qualeIfaceApi == "pcloudAmbience")
{
auto ambienceBuffer = std::make_shared<PcloudAmbienceStimulusBuffer>(
*this, deviceAttachmentSpec, histbuffMs, openClInputConstraints);
ambienceStimulusBuffer = ambienceBuffer;
attachedStimulusBuffers.push_back(ambienceBuffer);
return ambienceBuffer;
}
else
{
throw std::runtime_error(
"Unsupported qualeIfaceApi: '" + qualeIfaceApi + "' for "
"PcloudStimulusProducer. "
"Supported values: mesh, pcloudIntensity, pcloudAmbience");
}
}
void PcloudStimulusProducer::stimFrameProductionTimesliceInd()
@@ -67,6 +67,10 @@ public:
&deviceAttachmentSpec,
int histbuffMs) override;
std::shared_ptr<StimulusBuffer> getAttachedStimulusBuffer(
const std::shared_ptr<device::DeviceAttachmentSpec>& spec)
const override;
protected:
void stimFrameProductionTimesliceInd() override;