mirror of
https://github.com/nasa/fpp.git
synced 2025-12-11 11:16:42 -06:00
528 lines
18 KiB
Scala
528 lines
18 KiB
Scala
package fpp.compiler.codegen
|
|
|
|
import fpp.compiler.analysis._
|
|
import fpp.compiler.ast._
|
|
import fpp.compiler.codegen._
|
|
|
|
/** Writes out C++ for component parameters */
|
|
case class ComponentParameters (
|
|
s: CppWriterState,
|
|
aNode: Ast.Annotated[AstNode[Ast.DefComponent]]
|
|
) extends ComponentCppWriterUtils(s, aNode) {
|
|
|
|
def getConstantMembers: List[CppDoc.Class.Member] = {
|
|
if !hasParameters then Nil
|
|
else List(
|
|
linesClassMember(
|
|
List.concat(
|
|
Line.blank :: lines(s"//! Parameter IDs"),
|
|
wrapInEnum(
|
|
sortedParams.flatMap((id, param) =>
|
|
writeEnumConstant(
|
|
paramIdConstantName(param.getName),
|
|
id,
|
|
AnnotationCppWriter.asStringOpt(param.aNode),
|
|
CppWriterUtils.Hex
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
}
|
|
|
|
def getPublicFunctionMembers: List[CppDoc.Class.Member] = {
|
|
if !hasParameters then Nil
|
|
else getLoadFunction
|
|
}
|
|
|
|
def getProtectedFunctionMembers: List[CppDoc.Class.Member] = {
|
|
if !hasParameters then Nil
|
|
else List.concat(
|
|
getHookFunctions,
|
|
getGetterFunctions,
|
|
getExternalParameterFunctions
|
|
)
|
|
}
|
|
|
|
def getPrivateFunctionMembers: List[CppDoc.Class.Member] = {
|
|
if !hasParameters then Nil
|
|
else List.concat(
|
|
getSetters,
|
|
getSaveFunctions
|
|
)
|
|
}
|
|
|
|
def getVariableMembers: List[CppDoc.Class.Member] = {
|
|
if !hasParameters then Nil
|
|
else List.concat(
|
|
addAccessTagAndComment(
|
|
"private",
|
|
"Parameter validity flags",
|
|
sortedParams.flatMap { case (_, param) =>
|
|
guardedList (!param.isExternal) (
|
|
List(
|
|
linesClassMember(
|
|
lines(
|
|
s"""|
|
|
|//! True if ${param.getName} was successfully received
|
|
|Fw::ParamValid ${paramValidityFlagName(param.getName)};
|
|
|"""
|
|
)
|
|
)
|
|
)
|
|
)
|
|
},
|
|
CppDoc.Lines.Hpp
|
|
),
|
|
addAccessTagAndComment(
|
|
"private",
|
|
"Parameter variables",
|
|
sortedParams.flatMap { case (_, param) =>
|
|
guardedList (!param.isExternal) {
|
|
val paramType = writeParamType(param.paramType, "Fw::ParamString")
|
|
val paramVarName = paramVariableName(param.getName)
|
|
List(
|
|
linesClassMember(
|
|
List.concat(
|
|
addSeparatedPreComment(
|
|
s"Parameter ${param.getName}",
|
|
AnnotationCppWriter.asStringOpt(param.aNode)
|
|
),
|
|
lines(s"$paramType $paramVarName;")
|
|
)
|
|
)
|
|
)
|
|
}
|
|
},
|
|
CppDoc.Lines.Hpp
|
|
),
|
|
guardedList (hasExternalParameters) (
|
|
List.concat(
|
|
addAccessTagAndComment(
|
|
"private",
|
|
"Parameter delegates",
|
|
List(
|
|
linesClassMember(
|
|
lines(
|
|
s"""|
|
|
|//! Delegate to serialize/deserialize an externally stored parameter
|
|
|Fw::ParamExternalDelegate* paramDelegatePtr;
|
|
|"""
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
}
|
|
|
|
private def getLoadFunction: List[CppDoc.Class.Member] = {
|
|
addAccessTagAndComment(
|
|
"public",
|
|
"Parameter loading",
|
|
List(
|
|
functionClassMember(
|
|
Some(
|
|
s"""|\\brief Load the parameters from a parameter source
|
|
|
|
|
|Connect the parameter first
|
|
|"""
|
|
),
|
|
"loadParameters",
|
|
Nil,
|
|
CppDoc.Type("void"),
|
|
intersperseBlankLines(
|
|
List(
|
|
lines(
|
|
s"""|Fw::ParamBuffer _buff;
|
|
|Fw::SerializeStatus _stat = Fw::FW_SERIALIZE_OK;
|
|
|const FwPrmIdType _baseId = static_cast<FwPrmIdType>(this->getIdBase());
|
|
|FW_ASSERT(this->${portVariableName(prmGetPort.get)}[0].isConnected());
|
|
|
|
|
|FwPrmIdType _id{};
|
|
|"""
|
|
),
|
|
guardedList (hasExternalParameters) (lines("Fw::ParamValid param_valid;")),
|
|
intersperseBlankLines(
|
|
sortedParams.map((_, param) =>
|
|
if (param.isExternal) {
|
|
List.concat(
|
|
lines(
|
|
s"""|_id = _baseId + ${paramIdConstantName(param.getName)};
|
|
|
|
|
|// Get parameter ${param.getName}
|
|
|param_valid = this->${portVariableName(prmGetPort.get)}[0].invoke(
|
|
| _id,
|
|
| _buff
|
|
|);
|
|
|
|
|
|// Get the local ID to pass to the delegate
|
|
|_id = ${paramIdConstantName(param.getName)};
|
|
|// If there was a deserialization issue, mark it invalid
|
|
|"""
|
|
),
|
|
wrapInIfElse(
|
|
s"param_valid == Fw::ParamValid::VALID",
|
|
lines(
|
|
s"""|// Pass the local ID to the delegate
|
|
|_id = ${paramIdConstantName(param.getName)};
|
|
|
|
|
|FW_ASSERT(this->paramDelegatePtr != nullptr);
|
|
|// Call the delegate deserialize function for ${paramVariableName(param.getName)}
|
|
|_stat = this->paramDelegatePtr->deserializeParam(_baseId, _id, param_valid, _buff);
|
|
|"""
|
|
) ++
|
|
wrapInIf(
|
|
"_stat != Fw::FW_SERIALIZE_OK",
|
|
lines(
|
|
s"param_valid = Fw::ParamValid::INVALID;"
|
|
)
|
|
),
|
|
lines(s"param_valid = Fw::ParamValid::INVALID;")
|
|
)
|
|
)
|
|
} else {
|
|
List.concat(
|
|
lines(
|
|
s"""|_id = _baseId + ${paramIdConstantName(param.getName)};
|
|
|
|
|
|// Get parameter ${param.getName}
|
|
|this->${paramValidityFlagName(param.getName)} =
|
|
| this->${portVariableName(prmGetPort.get)}[0].invoke(
|
|
| _id,
|
|
| _buff
|
|
| );
|
|
|
|
|
|// Deserialize value
|
|
|this->m_paramLock.lock();
|
|
|
|
|
|// If there was a deserialization issue, mark it invalid
|
|
|"""
|
|
),
|
|
wrapInIfElse(
|
|
s"this->${paramValidityFlagName(param.getName)} == Fw::ParamValid::VALID",
|
|
line(s"_stat = _buff.deserializeTo(this->${paramVariableName(param.getName)});") ::
|
|
wrapInIf(
|
|
"_stat != Fw::FW_SERIALIZE_OK",
|
|
param.default match {
|
|
case Some(value) => lines(
|
|
s"""|this->${paramValidityFlagName(param.getName)} = Fw::ParamValid::DEFAULT;
|
|
|// Set default value
|
|
|this->${paramVariableName(param.getName)} = ${ValueCppWriter.write(s, value)};
|
|
|"""
|
|
)
|
|
case None => lines(
|
|
s"this->${paramValidityFlagName(param.getName)} = Fw::ParamValid::INVALID;"
|
|
)
|
|
}
|
|
),
|
|
param.default match {
|
|
case Some(value) => lines(
|
|
s"""|// Set default value
|
|
|this->${paramValidityFlagName(param.getName)} = Fw::ParamValid::DEFAULT;
|
|
|this->${paramVariableName(param.getName)} = ${ValueCppWriter.write(s, value)};
|
|
|"""
|
|
)
|
|
case None => lines("// No default")
|
|
}
|
|
),
|
|
Line.blank :: lines("this->m_paramLock.unLock();")
|
|
)
|
|
}
|
|
)
|
|
),
|
|
lines(
|
|
"""|// Call notifier
|
|
|this->parametersLoaded();
|
|
|"""
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
}
|
|
|
|
private def getHookFunctions: List[CppDoc.Class.Member] = {
|
|
addAccessTagAndComment(
|
|
"protected",
|
|
"Parameter update hook",
|
|
List(
|
|
functionClassMember(
|
|
Some(
|
|
s"""|\\brief Called whenever a parameter is updated
|
|
|
|
|
|This function does nothing by default. You may override it.
|
|
|"""
|
|
),
|
|
"parameterUpdated",
|
|
List(
|
|
CppDoc.Function.Param(
|
|
CppDoc.Type("FwPrmIdType"),
|
|
"id",
|
|
Some("The parameter ID")
|
|
)
|
|
),
|
|
CppDoc.Type("void"),
|
|
lines("// Do nothing by default"),
|
|
CppDoc.Function.Virtual
|
|
),
|
|
linesClassMember(
|
|
CppDocWriter.writeBannerComment(
|
|
"Parameter load hook"
|
|
)
|
|
),
|
|
functionClassMember(
|
|
Some(
|
|
s"""|\\brief Called whenever parameters are loaded
|
|
|
|
|
|This function does nothing by default. You may override it.
|
|
|"""
|
|
),
|
|
"parametersLoaded",
|
|
Nil,
|
|
CppDoc.Type("void"),
|
|
lines("// Do nothing by default"),
|
|
CppDoc.Function.Virtual
|
|
)
|
|
)
|
|
)
|
|
}
|
|
|
|
private def getGetterFunctions: List[CppDoc.Class.Member] = {
|
|
addAccessTagAndComment(
|
|
"protected",
|
|
"Parameter get functions",
|
|
sortedParams.map((_, param) =>
|
|
functionClassMember(
|
|
Some(
|
|
addSeparatedString(
|
|
s"Get parameter ${param.getName}\n\n\\return The parameter value",
|
|
AnnotationCppWriter.asStringOpt(param.aNode)
|
|
)
|
|
),
|
|
paramGetterName(param.getName),
|
|
List(
|
|
CppDoc.Function.Param(
|
|
CppDoc.Type("Fw::ParamValid&"),
|
|
"valid",
|
|
Some("Whether the parameter is valid")
|
|
)
|
|
),
|
|
CppDoc.Type(writeParamType(param.paramType, "Fw::ParamString")),
|
|
if(param.isExternal) {
|
|
lines(
|
|
s"""|${writeParamType(param.paramType, "Fw::ParamString")} _local{};
|
|
|Fw::ParamBuffer _getBuff;
|
|
|// Get the base ID
|
|
|const FwPrmIdType _baseId = static_cast<FwPrmIdType>(this->getIdBase());
|
|
|// Get the local ID to pass to the delegate
|
|
|const FwPrmIdType _localId = ${paramIdConstantName(param.getName)};
|
|
|
|
|
|FW_ASSERT(this->paramDelegatePtr != nullptr);
|
|
|// Get the external parameter from the delegate
|
|
|Fw::SerializeStatus _stat = this->paramDelegatePtr->serializeParam(_baseId, _localId, _getBuff);
|
|
|if(_stat == Fw::FW_SERIALIZE_OK) {
|
|
| _stat = _getBuff.deserializeTo(_local);
|
|
| FW_ASSERT(_stat == Fw::FW_SERIALIZE_OK, static_cast<FwAssertArgType>(_stat));
|
|
| valid = Fw::ParamValid::VALID;
|
|
|} else {
|
|
| valid = Fw::ParamValid::INVALID;
|
|
|}
|
|
|return _local;
|
|
|"""
|
|
)
|
|
}
|
|
else
|
|
{
|
|
lines(
|
|
s"""|${writeParamType(param.paramType, "Fw::ParamString")} _local{};
|
|
|this->m_paramLock.lock();
|
|
|valid = this->${paramValidityFlagName(param.getName)};
|
|
|_local = this->${paramVariableName(param.getName)};
|
|
|this->m_paramLock.unLock();
|
|
|return _local;
|
|
|"""
|
|
)
|
|
}
|
|
)
|
|
)
|
|
)
|
|
}
|
|
|
|
private def getSetters: List[CppDoc.Class.Member] = {
|
|
addAccessTagAndComment(
|
|
"private",
|
|
"Parameter set functions",
|
|
sortedParams.map((_, param) =>
|
|
functionClassMember(
|
|
Some(
|
|
s"""|Set parameter ${param.getName}
|
|
|
|
|
|\\return The command response
|
|
|"""
|
|
),
|
|
paramHandlerName(param.getName, Command.Param.Set),
|
|
List(
|
|
CppDoc.Function.Param(
|
|
CppDoc.Type("Fw::SerializeBufferBase&"),
|
|
"val",
|
|
Some("The serialization buffer")
|
|
),
|
|
),
|
|
CppDoc.Type("Fw::CmdResponse"),
|
|
if (param.isExternal) {
|
|
lines(
|
|
s"""|const FwPrmIdType _localId = ${paramIdConstantName(param.getName)};
|
|
|const FwPrmIdType _baseId = static_cast<FwPrmIdType>(this->getIdBase());
|
|
|
|
|
|FW_ASSERT(this->paramDelegatePtr != nullptr);
|
|
|// Call the delegate serialize function for ${paramVariableName(param.getName)}
|
|
|const Fw::SerializeStatus _stat = this->paramDelegatePtr->deserializeParam(
|
|
| _baseId,
|
|
| _localId,
|
|
| Fw::ParamValid::VALID,
|
|
| val
|
|
|);
|
|
|if (_stat != Fw::FW_SERIALIZE_OK) {
|
|
| return Fw::CmdResponse::VALIDATION_ERROR;
|
|
|}
|
|
|
|
|
|// Call notifier
|
|
|this->parameterUpdated(${paramIdConstantName(param.getName)});
|
|
|return Fw::CmdResponse::OK;
|
|
|"""
|
|
)
|
|
} else {
|
|
lines(
|
|
s"""|${writeParamType(param.paramType, "Fw::ParamString")} _localVal{};
|
|
|const Fw::SerializeStatus _stat = val.deserializeTo(_localVal);
|
|
|if (_stat != Fw::FW_SERIALIZE_OK) {
|
|
| return Fw::CmdResponse::VALIDATION_ERROR;
|
|
|}
|
|
|
|
|
|// Assign value only if successfully deserialized
|
|
|this->m_paramLock.lock();
|
|
|this->${paramVariableName(param.getName)} = _localVal;
|
|
|this->${paramValidityFlagName(param.getName)} = Fw::ParamValid::VALID;
|
|
|this->m_paramLock.unLock();
|
|
|
|
|
|// Call notifier
|
|
|this->parameterUpdated(${paramIdConstantName(param.getName)});
|
|
|return Fw::CmdResponse::OK;
|
|
|"""
|
|
)
|
|
}
|
|
)
|
|
)
|
|
)
|
|
}
|
|
|
|
private def getSaveFunctions: List[CppDoc.Class.Member] = {
|
|
addAccessTagAndComment(
|
|
"private",
|
|
"Parameter save functions",
|
|
sortedParams.map((_, param) =>
|
|
functionClassMember(
|
|
Some(
|
|
s"""|Save parameter ${param.getName}
|
|
|
|
|
|\\return The command response
|
|
|"""
|
|
),
|
|
paramHandlerName(param.getName, Command.Param.Save),
|
|
Nil,
|
|
CppDoc.Type("Fw::CmdResponse"),
|
|
List.concat(
|
|
lines(
|
|
s"""|Fw::ParamBuffer _saveBuff;
|
|
|FwPrmIdType _id;
|
|
|Fw::SerializeStatus _stat;
|
|
|
|
|
|"""
|
|
),
|
|
wrapInIf(
|
|
s"this->${portVariableName(prmSetPort.get)}[0].isConnected()",
|
|
List.concat(
|
|
if (param.isExternal) {
|
|
lines(
|
|
s"""|// Get the local and base ID to pass to the delegate
|
|
|_id = ${paramIdConstantName(param.getName)};
|
|
|const FwPrmIdType _baseId = static_cast<FwPrmIdType>(this->getIdBase());
|
|
|
|
|
|FW_ASSERT(this->paramDelegatePtr != nullptr);
|
|
|_stat = this->paramDelegatePtr->serializeParam(_baseId, _id, _saveBuff);
|
|
|"""
|
|
)
|
|
} else {
|
|
lines(
|
|
s"""|this->m_paramLock.lock();
|
|
|
|
|
|_stat = _saveBuff.serializeFrom(${paramVariableName(param.getName)});
|
|
|
|
|
|this->m_paramLock.unLock();
|
|
|"""
|
|
)
|
|
}
|
|
) ++ lines(
|
|
s"""|if (_stat != Fw::FW_SERIALIZE_OK) {
|
|
| return Fw::CmdResponse::VALIDATION_ERROR;
|
|
|}
|
|
|
|
|
|_id = static_cast<FwPrmIdType>(this->getIdBase() + ${paramIdConstantName(param.getName)});
|
|
|
|
|
|// Save the parameter
|
|
|this->${portVariableName(prmSetPort.get)}[0].invoke(
|
|
| _id,
|
|
| _saveBuff
|
|
|);
|
|
|
|
|
|return Fw::CmdResponse::OK;
|
|
|"""
|
|
)
|
|
),
|
|
Line.blank :: lines("return Fw::CmdResponse::EXECUTION_ERROR;")
|
|
)
|
|
)
|
|
)
|
|
)
|
|
}
|
|
|
|
private def getExternalParameterFunctions: List[CppDoc.Class.Member] = {
|
|
guardedList (hasExternalParameters) (
|
|
addAccessTagAndComment(
|
|
"protected",
|
|
"External parameter delegate initialization",
|
|
List(
|
|
functionClassMember(
|
|
Some("Initialize the external parameter delegate"),
|
|
"registerExternalParameters",
|
|
List(
|
|
CppDoc.Function.Param(
|
|
CppDoc.Type("Fw::ParamExternalDelegate*"),
|
|
"paramExternalDelegatePtr",
|
|
Some("The delegate for externally managed parameters")
|
|
)
|
|
),
|
|
CppDoc.Type("void"),
|
|
lines(
|
|
"""|FW_ASSERT(paramExternalDelegatePtr != nullptr);
|
|
|this->paramDelegatePtr = paramExternalDelegatePtr;
|
|
|"""
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
}
|
|
|
|
private def paramGetterName(name: String) =
|
|
s"paramGet_$name"
|
|
|
|
private def paramVariableName(name: String) =
|
|
s"m_$name"
|
|
|
|
}
|