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;
|
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()
|
void StimulusProducer::stop()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public:
|
|||||||
ringBufferConstraints)
|
ringBufferConstraints)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
~StimulusBuffer() = default;
|
virtual ~StimulusBuffer() = default;
|
||||||
|
|
||||||
// Non-copyable, movable
|
// Non-copyable, movable
|
||||||
StimulusBuffer(const StimulusBuffer&) = delete;
|
StimulusBuffer(const StimulusBuffer&) = delete;
|
||||||
|
|||||||
@@ -69,13 +69,16 @@ public:
|
|||||||
void allowNextStimulusFrame()
|
void allowNextStimulusFrame()
|
||||||
{ frameAssemblyRateLimiter.release(); }
|
{ frameAssemblyRateLimiter.release(); }
|
||||||
|
|
||||||
std::shared_ptr<StimulusBuffer> getAttachedStimulusBuffer(
|
virtual std::shared_ptr<StimulusBuffer> getAttachedStimulusBuffer(
|
||||||
const std::shared_ptr<device::DeviceAttachmentSpec>& spec) const;
|
const std::shared_ptr<device::DeviceAttachmentSpec>& spec) const;
|
||||||
|
|
||||||
virtual std::shared_ptr<StimulusBuffer> getOrCreateAttachedStimulusBuffer(
|
virtual std::shared_ptr<StimulusBuffer> getOrCreateAttachedStimulusBuffer(
|
||||||
const std::shared_ptr<device::DeviceAttachmentSpec>& deviceAttachmentSpec,
|
const std::shared_ptr<device::DeviceAttachmentSpec>& deviceAttachmentSpec,
|
||||||
int histbuffMs) = 0;
|
int histbuffMs) = 0;
|
||||||
|
|
||||||
|
// Check if any attached buffer has the specified qualeIfaceApi
|
||||||
|
bool hasBufferWithQualeIfaceApi(const std::string& qualeIfaceApi) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SpinLock frameAssemblyRateLimiter;
|
SpinLock frameAssemblyRateLimiter;
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ static SmoThreadingModelDesc smoThreadingModelDesc;
|
|||||||
// Local collection of stimulus producers
|
// Local collection of stimulus producers
|
||||||
static std::vector<std::shared_ptr<StimulusProducer>> attachedStimulusProducers;
|
static std::vector<std::shared_ptr<StimulusProducer>> attachedStimulusProducers;
|
||||||
|
|
||||||
|
static bool isSupportedQualeIfaceApi(const std::string& qualeIfaceApi);
|
||||||
|
|
||||||
// Check if a StimulusProducer matches the requested stim feature
|
// Check if a StimulusProducer matches the requested stim feature
|
||||||
static bool isProducerForStimFeature(
|
static bool isProducerForStimFeature(
|
||||||
const std::shared_ptr<StimulusProducer>& stimProducer,
|
const std::shared_ptr<StimulusProducer>& stimProducer,
|
||||||
@@ -192,6 +194,17 @@ private:
|
|||||||
return false;
|
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
|
// Parse histbuffMs
|
||||||
int histbuffMs = parseHistbuffMs(context->spec);
|
int histbuffMs = parseHistbuffMs(context->spec);
|
||||||
|
|
||||||
@@ -203,7 +216,7 @@ private:
|
|||||||
std::cerr << __func__ << ": Failed to create StimBuffer: "
|
std::cerr << __func__ << ": Failed to create StimBuffer: "
|
||||||
<< e.what() << ". Producer is committed, DeviceReattacher will retry."
|
<< e.what() << ". Producer is committed, DeviceReattacher will retry."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
// Return false so DeviceReattacher can retry later
|
// Return false so caller can handle error callback
|
||||||
return false;
|
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
|
// Callback function implementations
|
||||||
extern "C" int livoxGen1_initializeInd(void)
|
extern "C" int livoxGen1_initializeInd(void)
|
||||||
{
|
{
|
||||||
@@ -713,6 +733,29 @@ extern "C" void livoxGen1_attachDeviceReq(
|
|||||||
"not available");
|
"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);
|
auto request = std::make_shared<AttachDeviceReq>(desc, cb);
|
||||||
|
|
||||||
// Case 1: Check if StimBuffer already exists
|
// Case 1: Check if StimBuffer already exists
|
||||||
@@ -740,7 +783,23 @@ extern "C" void livoxGen1_attachDeviceReq(
|
|||||||
}
|
}
|
||||||
else
|
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;
|
request->stimProducer = stimProducer;
|
||||||
// Ensure StimBuffer is attached and enable pcloud data if needed
|
// Ensure StimBuffer is attached and enable pcloud data if needed
|
||||||
request->attachDeviceReq4_doCreateStimBuff_maybeDirectlyCalled(
|
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>
|
std::shared_ptr<StimulusBuffer>
|
||||||
PcloudStimulusProducer::getOrCreateAttachedStimulusBuffer(
|
PcloudStimulusProducer::getOrCreateAttachedStimulusBuffer(
|
||||||
const std::shared_ptr<device::DeviceAttachmentSpec>& deviceAttachmentSpec,
|
const std::shared_ptr<device::DeviceAttachmentSpec>& deviceAttachmentSpec,
|
||||||
@@ -117,15 +151,43 @@ PcloudStimulusProducer::getOrCreateAttachedStimulusBuffer(
|
|||||||
if (existingBuffer)
|
if (existingBuffer)
|
||||||
{ return existingBuffer; }
|
{ return existingBuffer; }
|
||||||
|
|
||||||
// Create new MeshStimulusBuffer (for now, always use XYZ type)
|
// Parse qualeIfaceApi to determine buffer type
|
||||||
auto buffer = std::make_shared<MeshStimulusBuffer>(
|
const std::string& qualeIfaceApi = deviceAttachmentSpec->qualeIfaceApi;
|
||||||
*this, deviceAttachmentSpec, histbuffMs, openClInputConstraints);
|
|
||||||
|
|
||||||
// Add to collection
|
if (qualeIfaceApi == "mesh")
|
||||||
attachedStimulusBuffers.push_back(buffer);
|
{
|
||||||
// Update specialized member
|
auto meshBuffer = std::make_shared<MeshStimulusBuffer>(
|
||||||
meshStimulusBuffer = buffer;
|
*this, deviceAttachmentSpec, histbuffMs, openClInputConstraints);
|
||||||
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()
|
void PcloudStimulusProducer::stimFrameProductionTimesliceInd()
|
||||||
|
|||||||
@@ -67,6 +67,10 @@ public:
|
|||||||
&deviceAttachmentSpec,
|
&deviceAttachmentSpec,
|
||||||
int histbuffMs) override;
|
int histbuffMs) override;
|
||||||
|
|
||||||
|
std::shared_ptr<StimulusBuffer> getAttachedStimulusBuffer(
|
||||||
|
const std::shared_ptr<device::DeviceAttachmentSpec>& spec)
|
||||||
|
const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void stimFrameProductionTimesliceInd() override;
|
void stimFrameProductionTimesliceInd() override;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user