StimBuff: Make virtual so we can dynamic_cast in getOrCreateStimBuff
This commit is contained in:
@@ -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()
|
||||
{
|
||||
{
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
ringBufferConstraints)
|
||||
{}
|
||||
|
||||
~StimulusBuffer() = default;
|
||||
virtual ~StimulusBuffer() = default;
|
||||
|
||||
// Non-copyable, movable
|
||||
StimulusBuffer(const StimulusBuffer&) = delete;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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>(
|
||||
*this, deviceAttachmentSpec, histbuffMs, openClInputConstraints);
|
||||
// Parse qualeIfaceApi to determine buffer type
|
||||
const std::string& qualeIfaceApi = deviceAttachmentSpec->qualeIfaceApi;
|
||||
|
||||
// Add to collection
|
||||
attachedStimulusBuffers.push_back(buffer);
|
||||
// Update specialized member
|
||||
meshStimulusBuffer = buffer;
|
||||
return buffer;
|
||||
if (qualeIfaceApi == "mesh")
|
||||
{
|
||||
auto meshBuffer = std::make_shared<MeshStimulusBuffer>(
|
||||
*this, deviceAttachmentSpec, histbuffMs, openClInputConstraints);
|
||||
|
||||
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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user