#ifndef _LIVOX_GEN1_PCLOUD_AMBIENCE_INTRIN_STIMULUS_BUFFER_H #define _LIVOX_GEN1_PCLOUD_AMBIENCE_INTRIN_STIMULUS_BUFFER_H #include #include #include #include #include #include #include #include #include #include "pcloudAmbienceQualeIfaceApi.h" namespace smo { namespace stim_buff { enum class IntrinStatus { DISABLED, NEGTRIN, POSTRIN, }; struct ParsedAmbienceIntrinConfig { IntrinStatus status; uint32_t interestPercentage; uint32_t interestThreshold; }; inline bool isAmbienceIntrinEnabled(IntrinStatus intrinStatus) { return intrinStatus != IntrinStatus::DISABLED; } inline intrin::ParsedThresholdParam parseAmbienceThresholdParam( const std::string& paramName, const std::string& paramValue, intrin::ThresholdUnit unit) { try { return intrin::ParsedThresholdParam{ .value = std::stoi(paramValue), .unit = unit, .matchedName = paramName, .wasSpecified = true, }; } catch (const std::exception& e) { throw std::runtime_error( "Failed to parse '" + paramName + "' param value '" + paramValue + "' as integer: " + e.what()); } } inline ParsedAmbienceIntrinConfig buildAmbienceIntrinConfig( IntrinStatus status, const intrin::ParsedThresholdParam& thresholdParam, size_t nDgramsPerFrame) { return ParsedAmbienceIntrinConfig{ .status = status, .interestPercentage = thresholdParam.unit == intrin::ThresholdUnit::Percentage ? static_cast(thresholdParam.value) : 0U, .interestThreshold = intrin::resolveThresholdValue( thresholdParam, nDgramsPerFrame), }; } inline std::optional tryParseAmbienceIntrinConfig( const std::string& paramName, const std::string& paramValue, size_t nDgramsPerFrame, const std::string& qualeIfaceApi) { using intrin::ThresholdUnit; const bool apiIsPostrin = (qualeIfaceApi == "postrin"); const bool apiIsNegtrin = (qualeIfaceApi == "negtrin"); if (intrin::namesContain(intrin::kPosIntPcParamNames, paramName) || (apiIsPostrin && intrin::namesContain( intrin::kIntrinInterestPcUnprefixed, paramName))) { return buildAmbienceIntrinConfig( IntrinStatus::POSTRIN, parseAmbienceThresholdParam( paramName, paramValue, ThresholdUnit::Percentage), nDgramsPerFrame); } if (intrin::namesContain(intrin::kPosIntThrParamNames, paramName) || (apiIsPostrin && intrin::namesContain( intrin::kIntrinInterestThrUnprefixed, paramName))) { return buildAmbienceIntrinConfig( IntrinStatus::POSTRIN, parseAmbienceThresholdParam( paramName, paramValue, ThresholdUnit::Absolute), nDgramsPerFrame); } if (intrin::namesContain(intrin::kNegIntPcParamNames, paramName) || (apiIsNegtrin && intrin::namesContain( intrin::kIntrinInterestPcUnprefixed, paramName))) { return buildAmbienceIntrinConfig( IntrinStatus::NEGTRIN, parseAmbienceThresholdParam( paramName, paramValue, ThresholdUnit::Percentage), nDgramsPerFrame); } if (intrin::namesContain(intrin::kNegIntThrParamNames, paramName) || (apiIsNegtrin && intrin::namesContain( intrin::kIntrinInterestThrUnprefixed, paramName))) { return buildAmbienceIntrinConfig( IntrinStatus::NEGTRIN, parseAmbienceThresholdParam( paramName, paramValue, ThresholdUnit::Absolute), nDgramsPerFrame); } return std::nullopt; } inline ParsedAmbienceIntrinConfig parseAmbienceIntrinConfig( const std::shared_ptr& deviceAttachmentSpec, size_t nDgramsPerFrame) { const auto& params = deviceAttachmentSpec->qualeIfaceApiParams; for (auto paramIt = params.rbegin(); paramIt != params.rend(); ++paramIt) { const auto& [paramName, paramValue] = *paramIt; const auto parsedConfig = tryParseAmbienceIntrinConfig( paramName, paramValue, nDgramsPerFrame, deviceAttachmentSpec->qualeIfaceApi); if (parsedConfig.has_value()) { return parsedConfig.value(); } } return ParsedAmbienceIntrinConfig{ .status = IntrinStatus::DISABLED, .interestPercentage = 0U, .interestThreshold = 0U, }; } inline void validateAmbienceIntrinComparatorConfig( IntrinStatus intrinStatus, const std::optional& passbandCountComparator) { if (isAmbienceIntrinEnabled(intrinStatus) && !passbandCountComparator.has_value()) { throw std::runtime_error( "A PcloudAmbience intrinsic pipeline with an intrin threshold " "must also specify either 'passband-count-gt-val' or " "'passband-count-lt-val'"); } } class StimulusProducer; /** * Intrinsic pipeline for LivoxGen1 ambience: attaches as qualeIfaceApi * negtrin(...) or postrin(...) with from-stimbuff=pcloudAmbience. Parses * interest thresholds and passband comparators; sensory data still flows * through PcloudAmbienceStimulusBuffer. */ class PcloudAmbienceIntrinStimulusBuffer : public StimulusBuffer { public: explicit PcloudAmbienceIntrinStimulusBuffer( StimulusProducer& parent, const std::shared_ptr& deviceAttachmentSpec, int histbuffMs, const StagingBuffer::IOEngineConstraints& inputEngineConstraints, const StagingBuffer::IOEngineConstraints& outputEngineConstraints, const SmoCallbacks& callbacks, cl_mem_flags flags, size_t nDgramsPerFrame_) : StimulusBuffer( parent, deviceAttachmentSpec, histbuffMs, inputEngineConstraints, outputEngineConstraints, callbacks, flags), nDgramsPerFrame(nDgramsPerFrame_) { intrin::validateIntrinsQualeApiPolicy( deviceAttachmentSpec->qualeIfaceApi, deviceAttachmentSpec->qualeIfaceApiParams); intrin::validateNoForbiddenUnitlessIntrinParams( deviceAttachmentSpec->qualeIfaceApiParams); const auto intrinConfig = parseAmbienceIntrinConfig( deviceAttachmentSpec, nDgramsPerFrame_); intrinStatus = intrinConfig.status; intrinInterestPercentage = intrinConfig.interestPercentage; intrinInterestThreshold = intrinConfig.interestThreshold; passbandCountComparator = parseOptionalPcloudAmbienceParamComparator( deviceAttachmentSpec); validateAmbienceIntrinComparatorConfig( intrinStatus, passbandCountComparator); } ~PcloudAmbienceIntrinStimulusBuffer() = default; bool shouldTriggerIntrinEvent(uint32_t ambiencePassbandCount) const { if (!isAmbienceIntrinEnabled(intrinStatus)) { return false; } return ambiencePassbandCount >= intrinInterestThreshold; } PcloudAmbienceIntrinStimulusBuffer( const PcloudAmbienceIntrinStimulusBuffer&) = delete; PcloudAmbienceIntrinStimulusBuffer& operator=( const PcloudAmbienceIntrinStimulusBuffer&) = delete; PcloudAmbienceIntrinStimulusBuffer(PcloudAmbienceIntrinStimulusBuffer&&) = delete; PcloudAmbienceIntrinStimulusBuffer& operator=( PcloudAmbienceIntrinStimulusBuffer&&) = delete; public: IntrinStatus intrinStatus; uint32_t intrinInterestPercentage; uint32_t intrinInterestThreshold; std::optional passbandCountComparator; size_t nDgramsPerFrame; }; } // namespace stim_buff } // namespace smo #endif // _LIVOX_GEN1_PCLOUD_AMBIENCE_INTRIN_STIMULUS_BUFFER_H