Merge remote-tracking branch 'nasa/main' into feat/dictionary-specifier

This commit is contained in:
Rob Bocchino 2025-10-28 15:42:56 -07:00
commit 00be092850
447 changed files with 14654 additions and 20545 deletions

View File

@ -0,0 +1,28 @@
name: 'native-tools-setup'
description: 'Set Up GraalVM Native Image Tools'
inputs:
binary-directory:
required: true
trace-directory:
required: false
default: ""
runs:
using: "composite"
steps:
- name: "Setting up GraalVM/Java Environment"
run: |
echo "Run Native Image Build"
if [ -d "${{ inputs.trace-directory }}" ]; then
export CLASSPATH="`cd ${{ inputs.trace-directory }}/../..; pwd`:${CLASSPATH}"
fi
# Attempt to use the action path to find native-images. If this fails, use a relative path in hopes
# the working directory is the root of the repository.
#
# Docker containers don't seem to get the action path set correctly, so we need the relative path fallback.
if [ -f "${{ github.action_path }}/native-images" ]
then
"${{ github.action_path }}/native-images" ${{ inputs.binary-directory }}
else
./.github/actions/build-native-images/native-images ${{ inputs.binary-directory }}
fi
shell: bash

View File

@ -0,0 +1,59 @@
#!/bin/bash
# Print and evaluate
evalp()
{
echo "$@"
"$@"
}
# Get tool names from a directory
get_tool_names()
{
dir=$1
for file in $dir/*.jar
do
basename $file .jar
done
}
# Check arguments
if [ ! -d "$1" ]
then
echo "[ERROR] Must supply binary directory"
exit 1
fi
# Calculate directories
tool_dir="$1"
native_dir="${tool_dir}-native"
native_final="${tool_dir}-final"
mkdir -p "${native_dir}"
mkdir -p "${native_final}"
# Remove $1
shift;
tool_names="$@"
if [[ "${tool_names}" == "" ]]
then
tool_names="$(get_tool_names ${tool_dir})"
fi
# Generate a native emage
for tool_name in $tool_names
do
jar_file="$tool_dir/$tool_name.jar"
out_file="$native_dir/$tool_name"
echo "Building $out_file"
class_path="${CLASSPATH}"
evalp "$GRAALVM_JAVA_HOME/bin/native-image" -H:PageSize=65536 -cp "${class_path}" $FPP_NATIVE_IMAGE_FLAGS \
--no-fallback --install-exit-handlers \
-jar "$jar_file" "$out_file"
if [ $? -ne 0 ]
then
echo "[ERROR] Failed to build $out_file"
exit 1
fi
sync; sync; sync; # Magic to fix filesystem woes
cp "${out_file}" "${native_final}"
done
mv "$tool_dir" "$tool_dir.old"
mv "$native_final" "$tool_dir"

View File

@ -0,0 +1,19 @@
name: 'native-tools-setup'
description: 'Set Up GraalVM Native Image Tools'
runs:
using: "composite"
steps:
- name: "Setting up GraalVM/Java Environment"
run: |
echo "Setup GraalVM Environment"
# Attempt to use the action path to find env-setup. If this fails, use a relative path in hopes
# the working directory is the root of the repository.
#
# Docker containers don't seem to get the action path set correctly, so we need the relative path fallback.
if [ -f "${{ github.action_path }}/env-setup" ]
then
"${{ github.action_path }}/env-setup"
else
./.github/actions/native-tools-setup/env-setup
fi
shell: bash

46
.github/actions/native-tools-setup/env-setup vendored Executable file
View File

@ -0,0 +1,46 @@
#!/bin/bash
# Resolve architecture. Note: this is dependent on the graal version
graal_arch="$(uname -m)"
# Override graal_arch when on amd64
if [[ "$graal_arch" == "x86_64" ]] || [[ "$graal_arch" == "x64" ]]
then
graal_arch="amd64"
elif [[ "$graal_arch" == "arm64" ]] || [[ "$graal_arch" == "aarch64" ]]
then
graal_arch="aarch64"
fi
graal_ver="22.3.0"
graal_os="$( uname -s | tr "[:upper:]" "[:lower:]")"
graal_ar="graalvm-ce-java11-${graal_os}-${graal_arch}-${graal_ver}.tar.gz"
graal_dir="$(pwd)/graalvm-ce-java11-${graal_ver}"
graal_url="https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-${graal_ver}/${graal_ar}"
# Start fresh
if [ -d "${graal_dir}" ]
then
rm -r "${graal_dir}"
fi
# Download Graal
echo "Downloading GraalVM from: ${graal_url}"
curl -L "${graal_url}" > "${graal_ar}"
tar -xzf "${graal_ar}"
graal_bin="${graal_dir}/bin"
if [ ! -d "${graal_bin}" ]
then
graal_bin="${graal_dir}/Contents/Home/bin"
fi
export PATH="${graal_bin}:${PATH}"
export GRAALVM_JAVA_HOME="$(dirname ${graal_bin})"
# Install native image
${graal_bin}/gu install native-image
if [ -n "$GITHUB_ENV" ]
then
echo PATH="${PATH}" >> $GITHUB_ENV
echo GRAALVM_JAVA_HOME="${GRAALVM_JAVA_HOME}" >> $GITHUB_ENV
fi

View File

@ -17,7 +17,5 @@ jobs:
build: ./compiler/install build: ./compiler/install
test: ./compiler/test test: ./compiler/test
output-directory: ./compiler/bin output-directory: ./compiler/bin
meta-package: fpp
fast-hack: true
trace: false trace: false
secrets: inherit secrets: inherit

View File

@ -1,20 +0,0 @@
#!/bin/bash
graal_arch=$1
graal_ver="22.3.0"
graal_os="$( uname -s | tr "[:upper:]" "[:lower:]")"
graal_ar="graalvm-ce-java11-${graal_os}-${graal_arch}-${graal_ver}.tar.gz"
graal_dir="$(pwd)/graalvm-ce-java11-${graal_ver}"
graal_url="https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-${graal_ver}/${graal_ar}"
# Download Graal
curl -L "${graal_url}" | tar -xz
graal_bin="${graal_dir}/bin"
if [ ! -d "${graal_bin}" ]
then
graal_bin="${graal_dir}/Contents/Home/bin"
fi
export PATH="${graal_bin}:${PATH}"
export GRAALVM_JAVA_HOME="$(dirname ${graal_bin})"
# Install native image
${graal_bin}/gu install native-image

View File

@ -32,21 +32,11 @@ on:
required: false required: false
default: trace/META-INF/native-image default: trace/META-INF/native-image
type: string type: string
meta-package:
description: "Meta-package name to publish"
required: false
default: ""
type: string
extra-tools: extra-tools:
description: "Extra meta-package tools publish" description: "Extra meta-package tools publish"
required: false required: false
default: "" default: ""
type: string type: string
fast-hack:
description: "Publish fast (deprecated) packages"
required: false
default: false
type: boolean
jobs: jobs:
build-jars: build-jars:
runs-on: "ubuntu-22.04" runs-on: "ubuntu-22.04"
@ -57,7 +47,7 @@ jobs:
with: with:
submodules: recursive submodules: recursive
- name: "Setup Native Image Tools" - name: "Setup Native Image Tools"
uses: fprime-community/native-images-action@main uses: ./.github/actions/native-tools-setup
- name: "Building JAR files" - name: "Building JAR files"
run: | run: |
cd ${{ inputs.working-directory }} cd ${{ inputs.working-directory }}
@ -67,7 +57,7 @@ jobs:
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: build-jar name: build-jar
path: ${{ inputs.output-directory }}/* path: ${{ inputs.output-directory }}/fpp.jar
retention-days: 5 retention-days: 5
if-no-files-found: error if-no-files-found: error
- if: ${{ inputs.trace }} - if: ${{ inputs.trace }}
@ -102,8 +92,12 @@ jobs:
matrix = { matrix = {
"run": [ "run": [
{ {
"runner": "macos-13", "runner": "macos-14",
"tag": "macosx_13_0_universal2" "tag": "macosx_14_0_arm64"
},
{
"runner": "macos-15-intel",
"tag": "macosx_15_0_x86_64"
}, },
{ {
"runner": "ubuntu-22.04", "runner": "ubuntu-22.04",
@ -135,8 +129,6 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: "Setup Native Image Tools"
uses: fprime-community/native-images-action@main
- name: "Download JARs" - name: "Download JARs"
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
@ -148,21 +140,32 @@ jobs:
with: with:
name: jar-traces name: jar-traces
path: ${{ inputs.trace-directory }} path: ${{ inputs.trace-directory }}
- name: "Setting up GraalVM/Java Environment"
uses: ./.github/actions/native-tools-setup
- name: "Build Native Images" - name: "Build Native Images"
run: | uses: ./.github/actions/build-native-images
export CLASSPATH="`cd ${{ inputs.trace-directory }}/../..; pwd`:${CLASSPATH}" with:
cd ${{ inputs.working-directory }} binary-directory: ${{ inputs.output-directory }}
$NATIVE_IMAGE_TOOLS_PATH/native-images ${{ inputs.output-directory }} ${{ inputs.tools }} trace-directory: ${{ inputs.trace-directory }}
shell: bash
- name: "Archive Native Images" - name: "Archive Native Images"
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: build-${{ matrix.run.tag }} name: build-${{ matrix.run.tag }}
path: ${{ inputs.output-directory }}/* path: ${{ inputs.output-directory }}/fpp
retention-days: 5 retention-days: 5
if-no-files-found: error if-no-files-found: error
- name: "Testing Native Images via Unit-Tests" - name: "Testing Native Images via Unit-Tests"
run: | run: |
# Generate wrappers for tools
tool_names=`cat ${{ inputs.working-directory }}/compiler/tools.txt`
for tool in $tool_names
do
tool_wrapper="${{ inputs.output-directory }}/fpp-$tool"
echo "Generating wrapper for fpp-$tool in $tool_wrapper"
echo '#!/bin/sh
"`dirname $0`/fpp" '$tool' "$@"' > $tool_wrapper
chmod +x $tool_wrapper
done
cd ${{ inputs.working-directory }} cd ${{ inputs.working-directory }}
${{ inputs.test }} ${{ inputs.test }}
build-wheels: build-wheels:
@ -175,27 +178,27 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: "Make Output Directory"
run: mkdir -p ${{ inputs.output-directory }}
- name: "Download Package" - name: "Download Package"
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: build-${{ matrix.tag }} name: build-${{ matrix.tag }}
path: ${{ inputs.output-directory }} path: ${{ inputs.output-directory }}
- name: "Install Builder"
run: pip install fprime-native-images
shell: bash
- name: "Run Builder" - name: "Run Builder"
run: | run: |
FLAGS="--package-tag ${{ matrix.tag }} --extra-tools ${{ inputs.extra-tools }}" pip install build
if [[ "${{ matrix.tag }}" == "jar" ]] && [[ "${{ inputs.meta-package }}" != "" ]] # Place the native files in the python package and determine platform options
then PLATFORM_OPTIONS=""
echo "[INFO] Generating Meta-Package: ${{ inputs.meta-package }}" if [[ "${{ matrix.tag }}" != "jar" ]]; then
FLAGS="${FLAGS} --meta-package ${{ inputs.meta-package }}" PLATFORM_OPTIONS="--config-setting=--build-option=--plat-name=${{ matrix.tag }}"
elif [[ "${{ inputs.fast-hack }}" == "true" ]] cp -vr ${{ inputs.output-directory }}/fpp python/fprime_fpp/
then else
echo "[INFO] Generating fast-hack packages" cp -vr ${{ inputs.output-directory }}/*.jar python/fprime_fpp/
FLAGS="${FLAGS} --fast-hack"
fi fi
fprime-native-packager ${{ inputs.output-directory }} ${FLAGS} # Github archiving clears executable flag, so put it back
chmod +x python/fprime_fpp/fpp*
python3 -m build --wheel --outdir packages/dist $PLATFORM_OPTIONS .
shell: bash shell: bash
- name: "Archiving Wheels" - name: "Archiving Wheels"
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@ -211,7 +214,7 @@ jobs:
runs-on: ${{ matrix.run.runner }} runs-on: ${{ matrix.run.runner }}
steps: steps:
- name: "Setup Native Image Tools" - name: "Setup Native Image Tools"
uses: fprime-community/native-images-action@main uses: fprime-community/native-images-action@unified-tool
- name: "Download Native Wheels" - name: "Download Native Wheels"
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:

1
.gitignore vendored
View File

@ -3,6 +3,7 @@
*.tasty *.tasty
*~ *~
.* .*
!.gitignore
!.gitattributes !.gitattributes
__SHADOW__ __SHADOW__
__pycache__ __pycache__

View File

@ -29,85 +29,13 @@ lazy val root = (project in file("."))
.settings(settings) .settings(settings)
.aggregate( .aggregate(
lib, lib,
fpp_check, fpp
fpp_depend,
fpp_filenames,
fpp_format,
fpp_from_xml,
fpp_locate_defs,
fpp_locate_uses,
fpp_syntax,
fpp_to_cpp,
fpp_to_json,
fpp_to_xml,
fpp_to_dict,
fpp_to_layout
) )
lazy val lib = project lazy val lib = project
.settings(settings) .settings(settings)
lazy val fpp_check = (project in file("tools/fpp-check")) lazy val fpp = (project in file("tools/fpp"))
.settings(settings)
.dependsOn(lib)
.enablePlugins(AssemblyPlugin)
lazy val fpp_depend = (project in file("tools/fpp-depend"))
.settings(settings)
.dependsOn(lib)
.enablePlugins(AssemblyPlugin)
lazy val fpp_filenames = (project in file("tools/fpp-filenames"))
.settings(settings)
.dependsOn(lib)
.enablePlugins(AssemblyPlugin)
lazy val fpp_format = (project in file("tools/fpp-format"))
.settings(settings)
.dependsOn(lib)
.enablePlugins(AssemblyPlugin)
lazy val fpp_syntax = (project in file("tools/fpp-syntax"))
.settings(settings)
.dependsOn(lib)
.enablePlugins(AssemblyPlugin)
lazy val fpp_from_xml = (project in file("tools/fpp-from-xml"))
.settings(settings)
.dependsOn(lib)
.enablePlugins(AssemblyPlugin)
lazy val fpp_locate_defs = (project in file("tools/fpp-locate-defs"))
.settings(settings)
.dependsOn(lib)
.enablePlugins(AssemblyPlugin)
lazy val fpp_locate_uses = (project in file("tools/fpp-locate-uses"))
.settings(settings)
.dependsOn(lib)
.enablePlugins(AssemblyPlugin)
lazy val fpp_to_cpp = (project in file("tools/fpp-to-cpp"))
.settings(settings)
.dependsOn(lib)
.enablePlugins(AssemblyPlugin)
lazy val fpp_to_json = (project in file("tools/fpp-to-json"))
.settings(settings)
.dependsOn(lib)
.enablePlugins(AssemblyPlugin)
lazy val fpp_to_xml = (project in file("tools/fpp-to-xml"))
.settings(settings)
.dependsOn(lib)
.enablePlugins(AssemblyPlugin)
lazy val fpp_to_dict = (project in file("tools/fpp-to-dict"))
.settings(settings)
.dependsOn(lib)
.enablePlugins(AssemblyPlugin)
lazy val fpp_to_layout = (project in file("tools/fpp-to-layout"))
.settings(settings) .settings(settings)
.dependsOn(lib) .dependsOn(lib)
.enablePlugins(AssemblyPlugin) .enablePlugins(AssemblyPlugin)

View File

@ -51,21 +51,7 @@ dir=`cd $dir; pwd`
base=`basename $dest` base=`basename $dest`
dest=$dir/$base dest=$dir/$base
tools=" tools=`cat ./tools.txt`
fpp-check
fpp-depend
fpp-filenames
fpp-format
fpp-from-xml
fpp-locate-defs
fpp-locate-uses
fpp-syntax
fpp-to-cpp
fpp-to-json
fpp-to-xml
fpp-to-dict
fpp-to-layout
"
if git describe --tags --always > /dev/null 2>&1 if git describe --tags --always > /dev/null 2>&1
then then
@ -91,13 +77,18 @@ sed -i.restore.bak -e "s/val v = .*/val v = \"[unknown version]\"/" \
mkdir -p $dest mkdir -p $dest
echo "Installing fpp at $dest"
jar=`find tools/fpp -name "*$name*assembly*.jar" | grep "target/scala-$scala_version"`
echo " $jar"
cp $jar $dest/fpp.jar
echo '#!/bin/sh
'$java' -jar "`dirname $0`/'fpp'.jar" "$@"' > $dest/fpp
chmod +x $dest/fpp
echo "Installing tools at $dest" echo "Installing tools at $dest"
for tool in $tools for tool in $tools
do do
jar=`find tools/$tool -name "*$name*assembly*.jar" | grep "target/scala-$scala_version"`
echo " $jar"
cp $jar $dest/$tool.jar
echo '#!/bin/sh echo '#!/bin/sh
'$java' -jar "`dirname $0`/'$tool'.jar" "$@"' > $dest/$tool '$java' -jar "`dirname $0`/'fpp'.jar" '$tool' "$@"' > $dest/fpp-$tool
chmod +x $dest/$tool chmod +x $dest/fpp-$tool
done done

View File

@ -1,54 +1,6 @@
[ [
{ {
"name":"fpp.compiler.FPPFormat", "name":"fpp.compiler.tools.FPP",
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
},
{
"name":"fpp.compiler.FPPSyntax",
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
},
{
"name":"fpp.compiler.FPPToDict",
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
},
{
"name":"fpp.compiler.FPPToLayout",
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
},
{
"name":"fpp.compiler.FPPtoJson",
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
},
{
"name":"fpp.compiler.tools.FPPCheck",
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
},
{
"name":"fpp.compiler.tools.FPPDepend",
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
},
{
"name":"fpp.compiler.tools.FPPFilenames",
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
},
{
"name":"fpp.compiler.tools.FPPFromXml",
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
},
{
"name":"fpp.compiler.tools.FPPLocateDefs",
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
},
{
"name":"fpp.compiler.tools.FPPLocateUses",
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
},
{
"name":"fpp.compiler.tools.FPPToCpp",
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
},
{
"name":"fpp.compiler.tools.FPPToXml",
"methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }] "methods":[{"name":"main","parameterTypes":["java.lang.String[]"] }]
}, },
{ {

View File

@ -192,12 +192,19 @@ trait TypeExpressionAnalyzer
} }
override def specEventAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.SpecEvent]]) = { override def specEventAnnotatedNode(a: Analysis, node: Ast.Annotated[AstNode[Ast.SpecEvent]]) = {
def eventThrottle(a: Analysis, node: AstNode[Ast.EventThrottle]) = {
for {
a <- exprNode(a, node.data.count)
a <- opt(exprNode)(a, node.data.every)
} yield a
}
val (_, node1, _) = node val (_, node1, _) = node
val data = node1.data val data = node1.data
for { for {
a <- visitList(a, data.params, formalParamNode) a <- visitList(a, data.params, formalParamNode)
a <- opt(exprNode)(a, data.id) a <- opt(exprNode)(a, data.id)
a <- opt(exprNode)(a, data.throttle) a <- opt(eventThrottle)(a, data.throttle)
} yield a } yield a
} }

View File

@ -282,10 +282,27 @@ object CheckExprTypes extends UseAnalyzer {
override def specEventAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecEvent]]) = { override def specEventAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecEvent]]) = {
val (_, node, _) = aNode val (_, node, _) = aNode
val data = node.data val data = node.data
def checkThrottleInterval (a: Analysis) (every: AstNode[Ast.Expr]) = {
val id = every.id
val t = a.typeMap(id)
val loc = Locations.get(id)
Analysis.convertTypes(loc, t -> Type.AnonStruct(
Map(
("seconds", Type.U32),
("useconds", Type.U32),
)
))
}
def checkThrottle (a: Analysis) (throttle: AstNode[Ast.EventThrottle]) = {
for {
_ <- convertNodeToNumeric(a, throttle.data.count)
_ <- Result.mapOpt(throttle.data.every, checkThrottleInterval(a))
} yield a
}
for { for {
a <- super.specEventAnnotatedNode(a, aNode) a <- super.specEventAnnotatedNode(a, aNode)
_ <- convertNodeToNumericOpt(a, data.id) _ <- convertNodeToNumericOpt(a, data.id)
_ <- convertNodeToNumericOpt(a, data.throttle) _ <- Result.mapOpt(data.throttle, checkThrottle(a))
} }
yield a yield a
} }

View File

@ -14,14 +14,29 @@ object CheckInterfaceDefs
a: Analysis, a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.DefInterface]] aNode: Ast.Annotated[AstNode[Ast.DefInterface]]
) = { ) = {
val a1 = a.copy(interface = Some(Interface(aNode))) val symbol = Symbol.Interface(aNode)
for { a.interfaceMap.get(symbol) match {
a <- super.defInterfaceAnnotatedNode(a1, aNode) case None =>
} // Interface is not in the map: visit it
yield { val a1 = a.copy(interface = Some(Interface(aNode)))
val symbol = Symbol.Interface(aNode) for {
a.copy(interfaceMap = a.interfaceMap + (symbol -> a.interface.get)) a <- super.defInterfaceAnnotatedNode(a1, aNode)
iface <- Right(a.interface.get)
a <- {
// Resolve interfaces directly imported by iface, updating a
val ifaces = iface.importMap.toList
Result.foldLeft (ifaces) (a) ((a, tl) => {
defInterfaceAnnotatedNode(a, tl._1.node)
})
}
// Use the updated analysis to resolve iface
iface <- ResolveInterface.resolve(a, iface)
} yield a.copy(interfaceMap = a.interfaceMap + (symbol -> iface))
// Interface is already in the map: nothing to do
case _ => Right(a)
} }
} }
override def specPortInstanceAnnotatedNode( override def specPortInstanceAnnotatedNode(
@ -42,8 +57,8 @@ object CheckInterfaceDefs
val node = aNode._2 val node = aNode._2
val ifaceNode = node.data.sym val ifaceNode = node.data.sym
for { for {
iface <- a.getInterface(ifaceNode.id) iface <- a.getInterfaceSymbol(ifaceNode.id)
i <- a.interface.get.addImportedInterface( i <- a.interface.get.addImportedInterfaceSymbol(
iface, iface,
node.id, node.id,
) )

View File

@ -49,6 +49,9 @@ object CheckUseDefCycles extends UseAnalyzer {
visitDefPost(a, symbol, node, super.defInterfaceAnnotatedNode) visitDefPost(a, symbol, node, super.defInterfaceAnnotatedNode)
} }
override def interfaceUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified) =
visitUse(a, node, use)
override def topologyUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified) = override def topologyUse(a: Analysis, node: AstNode[Ast.QualIdent], use: Name.Qualified) =
visitUse(a, node, use) visitUse(a, node, use)
@ -71,6 +74,7 @@ object CheckUseDefCycles extends UseAnalyzer {
case Symbol.Constant(node) => defConstantAnnotatedNode(a, node) case Symbol.Constant(node) => defConstantAnnotatedNode(a, node)
case Symbol.Enum(node) => defEnumAnnotatedNode(a, node) case Symbol.Enum(node) => defEnumAnnotatedNode(a, node)
case Symbol.EnumConstant(node) => defEnumConstantAnnotatedNode(a, node) case Symbol.EnumConstant(node) => defEnumConstantAnnotatedNode(a, node)
case Symbol.Interface(node) => defInterfaceAnnotatedNode(a, node)
case Symbol.Struct(node) => defStructAnnotatedNode(a, node) case Symbol.Struct(node) => defStructAnnotatedNode(a, node)
case Symbol.Topology(node) => defTopologyAnnotatedNode(a, node) case Symbol.Topology(node) => defTopologyAnnotatedNode(a, node)
case _ => Right(a) case _ => Right(a)

View File

@ -7,7 +7,7 @@ import fpp.compiler.util._
final case class Event( final case class Event(
aNode: Ast.Annotated[AstNode[Ast.SpecEvent]], aNode: Ast.Annotated[AstNode[Ast.SpecEvent]],
format: Format, format: Format,
throttle: Option[Int] throttle: Option[Event.Throttle]
) { ) {
/** Gets the name of the event */ /** Gets the name of the event */
@ -20,6 +20,16 @@ final case class Event(
object Event { object Event {
case class TimeInterval(
seconds: Long,
useconds: Int,
)
case class Throttle(
count: Int,
every: Option[TimeInterval]
)
type Id = BigInt type Id = BigInt
/** Creates a event from an event specifier */ /** Creates a event from an event specifier */
@ -35,6 +45,45 @@ object Event {
) )
else Right(()) else Right(())
} }
def getEveryIntervalValue(every: AstNode[Ast.Expr]) = {
val loc = Locations.get(every.id)
val Value.AnonStruct(intervalValue) = Analysis.convertValueToType(a.valueMap(every.id), Type.AnonStruct(
Map(
("seconds", Type.U32),
("useconds", Type.U32),
)
))
def getMember(member: String, maxValue: BigInt) = {
val Value.PrimitiveInt(v, Type.PrimitiveInt.U32) = Analysis.convertValueToType(
intervalValue.get(member).get,
Type.U32
)
if v < 0 || v > maxValue
then Left(
SemanticError.InvalidIntValue(
loc, v, s"$member must be in the range [0, $maxValue]"
)
)
else Right(v.longValue)
}
for {
seconds <- getMember("seconds", UInt.MaxValue)
useconds <- getMember("useconds", 999_999)
} yield TimeInterval(seconds, useconds.toInt)
}
def checkEventThrottle(throttle: AstNode[Ast.EventThrottle]) = {
for {
count <- a.getNonnegativeIntValue(throttle.data.count.id)
_ <- {
if count > 0 then Right(())
else Left(SemanticError.InvalidEvent(
loc, s"event throttle count must be greater than zero"
))
}
every <- Result.mapOpt(throttle.data.every, getEveryIntervalValue)
} yield Throttle(count, every)
}
for { for {
_ <- checkRefParams(data.params) _ <- checkRefParams(data.params)
_ <- a.checkDisplayableParams(data.params, "type of event is not displayable") _ <- a.checkDisplayableParams(data.params, "type of event is not displayable")
@ -42,7 +91,7 @@ object Event {
data.format, data.format,
data.params.map(aNode => a.typeMap(aNode._2.data.typeName.id)) data.params.map(aNode => a.typeMap(aNode._2.data.typeName.id))
) )
throttle <- a.getNonnegativeIntValueOpt(data.throttle) throttle <- Result.mapOpt(data.throttle, checkEventThrottle)
} }
yield Event(aNode, format, throttle) yield Event(aNode, format, throttle)
} }

View File

@ -5,8 +5,10 @@ import fpp.compiler.util.*
/** An FPP interface */ /** An FPP interface */
case class Interface( case class Interface(
/** The AST node defining the component */ /** The AST node defining the interface */
aNode: Ast.Annotated[AstNode[Ast.DefInterface]], aNode: Ast.Annotated[AstNode[Ast.DefInterface]],
/** The imported interfaces */
importMap: Map[Symbol.Interface, (AstNode.Id, Location)] = Map(),
/** The map from port names to port instances */ /** The map from port names to port instances */
portMap: Map[Name.Unqualified, PortInstance] = Map(), portMap: Map[Name.Unqualified, PortInstance] = Map(),
/** The map from special port kinds to special port instances */ /** The map from special port kinds to special port instances */
@ -19,4 +21,21 @@ case class Interface(
newSpecialPortMap: Map[Ast.SpecPortInstance.SpecialKind, PortInstance.Special] newSpecialPortMap: Map[Ast.SpecPortInstance.SpecialKind, PortInstance.Special]
): Interface = this.copy(specialPortMap = newSpecialPortMap) ): Interface = this.copy(specialPortMap = newSpecialPortMap)
def addImportedInterfaceSymbol(
symbol: Symbol.Interface,
importNodeId: AstNode.Id
): Result.Result[Interface] = {
importMap.get(symbol) match {
case Some((_, prevLoc)) => Left(
SemanticError.DuplicateInterface(
symbol.getUnqualifiedName,
Locations.get(importNodeId),
prevLoc
)
)
case None =>
val map = importMap + (symbol -> (importNodeId, Locations.get(importNodeId)))
Right(this.copy(importMap = map))
}
}
} }

View File

@ -0,0 +1,16 @@
package fpp.compiler.analysis
import fpp.compiler.ast._
import fpp.compiler.util._
object ResolveInterface {
/** Resolve an interface */
def resolve(a: Analysis, i: Interface): Result.Result[Interface] = {
def resolveImport(i: Interface, ii: (Symbol.Interface, (AstNode.Id, Location))) =
i.addImportedInterface(a.interfaceMap(ii._1), ii._2._1)
Result.foldLeft(List.from(i.importMap)) (i) (resolveImport)
}
}

View File

@ -517,6 +517,11 @@ object Ast {
defaultPriority: Option[AstNode[Expr]] defaultPriority: Option[AstNode[Expr]]
) )
final case class EventThrottle(
count: AstNode[Expr],
every: Option[AstNode[Expr]]
)
/** Event specifier */ /** Event specifier */
final case class SpecEvent( final case class SpecEvent(
name: Ident, name: Ident,
@ -524,7 +529,7 @@ object Ast {
severity: SpecEvent.Severity, severity: SpecEvent.Severity,
id: Option[AstNode[Expr]], id: Option[AstNode[Expr]],
format: AstNode[String], format: AstNode[String],
throttle: Option[AstNode[Expr]] throttle: Option[AstNode[EventThrottle]]
) )
object SpecEvent { object SpecEvent {
/** Event severity */ /** Event severity */

View File

@ -428,6 +428,14 @@ object AstWriter extends AstVisitor with LineUtils {
) = { ) = {
val (_, node, _) = aNode val (_, node, _) = aNode
val data = node.data val data = node.data
def throttleClause(throttle: AstNode[Ast.EventThrottle]) = {
List.concat(
addPrefix("throttle", exprNode) (throttle.data.count),
linesOpt(addPrefix("every", exprNode), throttle.data.every),
)
}
lines("spec event") ++ lines("spec event") ++
List.concat( List.concat(
ident(data.name), ident(data.name),
@ -435,7 +443,7 @@ object AstWriter extends AstVisitor with LineUtils {
lines(s"severity ${data.severity.toString}"), lines(s"severity ${data.severity.toString}"),
linesOpt(addPrefix("id", exprNode), data.id), linesOpt(addPrefix("id", exprNode), data.id),
addPrefix("format", string) (data.format.data), addPrefix("format", string) (data.format.data),
linesOpt(addPrefix("throttle", exprNode), data.throttle), linesOpt(throttleClause, data.throttle)
).map(indentIn) ).map(indentIn)
} }

View File

@ -347,8 +347,7 @@ case class ArrayCppWriter (
), ),
), ),
CppDoc.Type(s"$name&"), CppDoc.Type(s"$name&"),
lines("""|// Since we are required to use C++11, this has to be a runtime check lines("""|// Check that the initializer has the expected size
|// In C++14, it can be a static check
|FW_ASSERT(il.size() == SIZE, static_cast<FwAssertArgType>(il.size()), static_cast<FwAssertArgType>(SIZE)); |FW_ASSERT(il.size() == SIZE, static_cast<FwAssertArgType>(il.size()), static_cast<FwAssertArgType>(SIZE));
|FwSizeType i = 0; |FwSizeType i = 0;
|for (const auto& e : il) { |for (const auto& e : il) {
@ -484,13 +483,19 @@ case class ArrayCppWriter (
CppDoc.Type("Fw::SerializeBufferBase&"), CppDoc.Type("Fw::SerializeBufferBase&"),
"buffer", "buffer",
Some("The serial buffer"), Some("The serial buffer"),
),
CppDoc.Function.Param(
CppDoc.Type("Fw::Endianness"),
"mode",
Some("Endianness of serialized buffer"),
Some("Fw::Endianness::BIG"),
) )
), ),
CppDoc.Type("Fw::SerializeStatus"), CppDoc.Type("Fw::SerializeStatus"),
List.concat( List.concat(
lines("Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK;"), lines("Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK;"),
indexIterator( indexIterator(
line("status = buffer.serializeFrom((*this)[index]);") :: line("status = buffer.serializeFrom((*this)[index], mode);") ::
wrapInIf("status != Fw::FW_SERIALIZE_OK", lines("return status;")), wrapInIf("status != Fw::FW_SERIALIZE_OK", lines("return status;")),
), ),
lines("return status;"), lines("return status;"),
@ -506,13 +511,19 @@ case class ArrayCppWriter (
CppDoc.Type("Fw::SerializeBufferBase&"), CppDoc.Type("Fw::SerializeBufferBase&"),
"buffer", "buffer",
Some("The serial buffer"), Some("The serial buffer"),
),
CppDoc.Function.Param(
CppDoc.Type("Fw::Endianness"),
"mode",
Some("Endianness of serialized buffer"),
Some("Fw::Endianness::BIG"),
) )
), ),
CppDoc.Type("Fw::SerializeStatus"), CppDoc.Type("Fw::SerializeStatus"),
List.concat( List.concat(
lines("Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK;"), lines("Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK;"),
indexIterator( indexIterator(
line("status = buffer.deserializeTo((*this)[index]);") :: line("status = buffer.deserializeTo((*this)[index], mode);") ::
wrapInIf("status != Fw::FW_SERIALIZE_OK", lines("return status;")), wrapInIf("status != Fw::FW_SERIALIZE_OK", lines("return status;")),
), ),
lines("return status;"), lines("return status;"),

View File

@ -510,21 +510,6 @@ case class ComponentCppWriter (
} }
private def getProtectedComponentFunctionMembers: List[CppDoc.Class.Member] = { private def getProtectedComponentFunctionMembers: List[CppDoc.Class.Member] = {
def writeChannelInit(channel: TlmChannel) = {
List(
lines(
s"""|// Write telemetry channel ${channel.getName}
|this->${channelUpdateFlagName(channel.getName)} = true;
|"""
),
channel.channelType match {
case t if s.isPrimitive(t, writeChannelType(t)) => lines(
s"this->${channelStorageName(channel.getName)} = 0;"
)
case _ => Nil
}
).flatten
}
addAccessTagAndComment( addAccessTagAndComment(
"protected", "protected",
@ -541,7 +526,7 @@ case class ComponentCppWriter (
) )
), ),
List(s"Fw::${kindStr}ComponentBase(compName)") ::: List(s"Fw::${kindStr}ComponentBase(compName)") :::
(if (hasExternalParameters) List("paramDelegatePtr(NULL)") else Nil) ::: (if (hasExternalParameters) List("paramDelegatePtr(nullptr)") else Nil) :::
smInstancesByName.map { (name, smi) => smInstancesByName.map { (name, smi) =>
val sm = s.a.stateMachineMap(smi.symbol) val sm = s.a.stateMachineMap(smi.symbol)
val hasActionsOrGuards = sm.hasActions || sm.hasGuards val hasActionsOrGuards = sm.hasActions || sm.hasGuards
@ -554,14 +539,12 @@ case class ComponentCppWriter (
}, },
intersperseBlankLines( intersperseBlankLines(
List( List(
intersperseBlankLines(
updateOnChangeChannels.map((_, channel) =>
writeChannelInit(channel)
)
),
throttledEvents.map((_, event) => line( throttledEvents.map((_, event) => line(
s"this->${eventThrottleCounterName(event.getName)} = 0;" s"this->${eventThrottleCounterName(event.getName)} = 0;"
)), )),
throttledEventsWithTimeout.map((_, event) => line(
s"this->${eventThrottleTimeName(event.getName)} = Fw::Time();"
)),
sortedParams.flatMap((_, param) => guardedList(!param.isExternal) ( sortedParams.flatMap((_, param) => guardedList(!param.isExternal) (
lines(s"this->${paramValidityFlagName(param.getName)} = Fw::ParamValid::UNINIT;") lines(s"this->${paramValidityFlagName(param.getName)} = Fw::ParamValid::UNINIT;")
)) ))
@ -992,7 +975,7 @@ case class ComponentCppWriter (
} }
private def getMutexVariableMembers: List[CppDoc.Class.Member] = { private def getMutexVariableMembers: List[CppDoc.Class.Member] = {
if !(hasGuardedInputPorts || hasGuardedCommands || hasParameters) then Nil if !(hasGuardedInputPorts || hasGuardedCommands || hasParameters || hasEventsWithTimeout) then Nil
else List( else List(
linesClassMember( linesClassMember(
List( List(
@ -1013,6 +996,13 @@ case class ComponentCppWriter (
|//! Mutex for locking parameters during sets and saves |//! Mutex for locking parameters during sets and saves
|Os::Mutex m_paramLock; |Os::Mutex m_paramLock;
|""" |"""
),
if !hasEventsWithTimeout then Nil
else lines(
"""|
|//! Mutex for locking event throttle timeout and counter
|Os::Mutex m_eventLock;
|"""
) )
).flatten ).flatten
) )

View File

@ -202,6 +202,22 @@ abstract class ComponentCppWriterUtils(
} }
) )
/** List of throttled events no timeout */
val throttledEventsNoTimeout: List[(Event.Id, Event)] = sortedEvents.filter((_, event) =>
event.throttle match {
case Some(Event.Throttle(_, None)) => true
case _ => false
}
)
/** List of throttled events with finite timeout intervals */
val throttledEventsWithTimeout: List[(Event.Id, Event)] = sortedEvents.filter((_, event) =>
event.throttle match {
case Some(Event.Throttle(_, Some(_))) => true
case _ => false
}
)
/** List of channels sorted by ID */ /** List of channels sorted by ID */
val sortedChannels: List[(TlmChannel.Id, TlmChannel)] = component.tlmChannelMap.toList.sortBy(_._1) val sortedChannels: List[(TlmChannel.Id, TlmChannel)] = component.tlmChannelMap.toList.sortBy(_._1)
@ -319,6 +335,8 @@ abstract class ComponentCppWriterUtils(
val hasContainers: Boolean = containersByName != Nil val hasContainers: Boolean = containersByName != Nil
val hasEventsWithTimeout: Boolean = throttledEventsWithTimeout.nonEmpty
val hasExternalStateMachineInstances: Boolean = val hasExternalStateMachineInstances: Boolean =
component.hasStateMachineInstancesOfKind(StateMachine.Kind.External) component.hasStateMachineInstancesOfKind(StateMachine.Kind.External)
@ -815,6 +833,10 @@ abstract class ComponentCppWriterUtils(
def eventThrottleCounterName(name: String) = def eventThrottleCounterName(name: String) =
s"m_${name}Throttle" s"m_${name}Throttle"
/** Get the name for an event throttle timeout interval variable */
def eventThrottleTimeName(name: String) =
s"m_${name}ThrottleTime"
/** Get the name for an event ID constant */ /** Get the name for an event ID constant */
def eventIdConstantName(name: String) = def eventIdConstantName(name: String) =
s"EVENTID_${name.toUpperCase}" s"EVENTID_${name.toUpperCase}"
@ -956,6 +978,12 @@ abstract class ComponentCppWriterUtils(
object ComponentCppWriterUtils { object ComponentCppWriterUtils {
/** Whether code generation is internal or external to the component */
enum InternalOrExternal {
case Internal
case External
}
/** ( parameter name, parameter type name, parameter type ) **/ /** ( parameter name, parameter type name, parameter type ) **/
type ParamTypeMapInfo = (String, String, Type) type ParamTypeMapInfo = (String, String, Type)
type CmdParamTypeMap = Map[Command.Opcode, List[ParamTypeMapInfo]] type CmdParamTypeMap = Map[Command.Opcode, List[ParamTypeMapInfo]]

View File

@ -21,7 +21,7 @@ case class ComponentEvents (
throttledEvents.flatMap((_, event) => throttledEvents.flatMap((_, event) =>
writeEnumConstant( writeEnumConstant(
eventThrottleConstantName(event.getName), eventThrottleConstantName(event.getName),
event.throttle.get, event.throttle.get.count,
Some(s"Throttle reset count for ${event.getName}") Some(s"Throttle reset count for ${event.getName}")
) )
) )
@ -60,12 +60,26 @@ case class ComponentEvents (
addAccessTagAndComment( addAccessTagAndComment(
"private", "private",
"Counter values for event throttling", "Counter values for event throttling",
throttledEvents.map((_, event) => List.concat(
linesClassMember( throttledEventsNoTimeout.map((_, event) =>
Line.blank :: lines( linesClassMember(
s"""|//! Throttle for ${event.getName} Line.blank :: lines(
|std::atomic<FwIndexType> ${eventThrottleCounterName(event.getName)}; s"""|//! Throttle for ${event.getName}
|""" |std::atomic<FwIndexType> ${eventThrottleCounterName(event.getName)};
|"""
)
)
),
throttledEventsWithTimeout.map((_, event) =>
linesClassMember(
Line.blank :: lines(
s"""|//! Throttle for ${event.getName}
|FwIndexType ${eventThrottleCounterName(event.getName)};
|
|//! Throttle time for ${event.getName}
|Fw::Time ${eventThrottleTimeName(event.getName)};
|"""
)
) )
) )
), ),
@ -246,18 +260,20 @@ case class ComponentEvents (
) )
def writeBody(id: Event.Id, event: Event) = intersperseBlankLines( def writeBody(id: Event.Id, event: Event) = intersperseBlankLines(
List( List(
// Hard throttle counter can be checked immediately
// We don't need to get time
event.throttle match { event.throttle match {
case None => Nil case Some(Event.Throttle(_, None)) => lines(
case Some(_) => lines(
s"""|// Check throttle value s"""|// Check throttle value
|if (this->${eventThrottleCounterName(event.getName)} >= ${eventThrottleConstantName(event.getName)}) { |if (this->${eventThrottleCounterName(event.getName)} >= ${eventThrottleConstantName(event.getName)}) {
| return; | return;
|} |}
|else { |else {
| (void) this->${eventThrottleCounterName(event.getName)}.fetch_add(1); | this->${eventThrottleCounterName(event.getName)}++;
|} |}
|""" |"""
) )
case _ => Nil
}, },
lines( lines(
s"""|// Get the time s"""|// Get the time
@ -271,6 +287,37 @@ case class ComponentEvents (
|_id = this->getIdBase() + ${eventIdConstantName(event.getName)}; |_id = this->getIdBase() + ${eventIdConstantName(event.getName)};
|""" |"""
), ),
// Time based throttle timeout needs above time
event.throttle match {
case Some(Event.Throttle(_, Some(Event.TimeInterval(seconds, useconds)))) => lines(
s"""|// Check throttle value & throttle timeout
|{
| Os::ScopeLock scopedLock(this->m_eventLock);
|
| if (this->${eventThrottleCounterName(event.getName)} >= ${eventThrottleConstantName(event.getName)}) {
| // The counter has overflowed, check if time interval has passed
| if (Fw::TimeInterval(this->${eventThrottleTimeName(event.getName)}, _logTime) >= Fw::TimeInterval($seconds, $useconds)) {
| // Reset the count
| this->${eventThrottleCounterName(event.getName)} = 0;
| } else {
| // Throttle the event
| return;
| }
| }
|
| // Reset the throttle time if needed
| if (this->${eventThrottleCounterName(event.getName)} == 0) {
| // This is the first event, reset the throttle time
| this->${eventThrottleTimeName(event.getName)} = _logTime;
| }
|
| // Increment the count
| this->${eventThrottleCounterName(event.getName)}++;
|}
|"""
)
case _ => Nil
},
writeLogBody(id, event), writeLogBody(id, event),
writeTextLogBody(event) writeTextLogBody(event)
) )
@ -309,16 +356,40 @@ case class ComponentEvents (
addAccessTagAndComment( addAccessTagAndComment(
"protected", "protected",
"Event throttle reset functions", "Event throttle reset functions",
throttledEvents.map((_, event) => List.concat(
functionClassMember( throttledEventsNoTimeout.map((_, event) =>
Some(s"Reset throttle value for ${event.getName}"), functionClassMember(
eventThrottleResetName(event), Some(s"Reset throttle value for ${event.getName}"),
Nil, eventThrottleResetName(event),
CppDoc.Type("void"), Nil,
lines( CppDoc.Type("void"),
s"""|// Reset throttle counter List(
|this->${eventThrottleCounterName(event.getName)} = 0; lines(
|""" s"""|// Reset throttle counter
|this->${eventThrottleCounterName(event.getName)} = 0;
|"""
)
).flatten
)
),
throttledEventsWithTimeout.map((_, event) =>
functionClassMember(
Some(s"Reset throttle value for ${event.getName}"),
eventThrottleResetName(event),
Nil,
CppDoc.Type("void"),
lines(
s"""|{
| Os::ScopeLock scopedLock(this->m_eventLock);
|
| // Reset throttle counter
| this->${eventThrottleCounterName(event.getName)} = 0;
|
| // Reset the throttle time
| this->${eventThrottleTimeName(event.getName)} = Fw::Time(0, 0);
|}
|"""
)
) )
) )
) )

View File

@ -169,7 +169,7 @@ case class ComponentParameters (
s"""|// Pass the local ID to the delegate s"""|// Pass the local ID to the delegate
|_id = ${paramIdConstantName(param.getName)}; |_id = ${paramIdConstantName(param.getName)};
| |
|FW_ASSERT(this->paramDelegatePtr != NULL); |FW_ASSERT(this->paramDelegatePtr != nullptr);
|// Call the delegate deserialize function for ${paramVariableName(param.getName)} |// Call the delegate deserialize function for ${paramVariableName(param.getName)}
|_stat = this->paramDelegatePtr->deserializeParam(_baseId, _id, param_valid, _buff); |_stat = this->paramDelegatePtr->deserializeParam(_baseId, _id, param_valid, _buff);
|""" |"""
@ -321,7 +321,7 @@ case class ComponentParameters (
|// Get the local ID to pass to the delegate |// Get the local ID to pass to the delegate
|const FwPrmIdType _localId = ${paramIdConstantName(param.getName)}; |const FwPrmIdType _localId = ${paramIdConstantName(param.getName)};
| |
|FW_ASSERT(this->paramDelegatePtr != NULL); |FW_ASSERT(this->paramDelegatePtr != nullptr);
|// Get the external parameter from the delegate |// Get the external parameter from the delegate
|Fw::SerializeStatus _stat = this->paramDelegatePtr->serializeParam(_baseId, _localId, _getBuff); |Fw::SerializeStatus _stat = this->paramDelegatePtr->serializeParam(_baseId, _localId, _getBuff);
|if(_stat == Fw::FW_SERIALIZE_OK) { |if(_stat == Fw::FW_SERIALIZE_OK) {
@ -378,7 +378,7 @@ case class ComponentParameters (
s"""|const FwPrmIdType _localId = ${paramIdConstantName(param.getName)}; s"""|const FwPrmIdType _localId = ${paramIdConstantName(param.getName)};
|const FwPrmIdType _baseId = static_cast<FwPrmIdType>(this->getIdBase()); |const FwPrmIdType _baseId = static_cast<FwPrmIdType>(this->getIdBase());
| |
|FW_ASSERT(this->paramDelegatePtr != NULL); |FW_ASSERT(this->paramDelegatePtr != nullptr);
|// Call the delegate serialize function for ${paramVariableName(param.getName)} |// Call the delegate serialize function for ${paramVariableName(param.getName)}
|const Fw::SerializeStatus _stat = this->paramDelegatePtr->deserializeParam( |const Fw::SerializeStatus _stat = this->paramDelegatePtr->deserializeParam(
| _baseId, | _baseId,
@ -452,7 +452,7 @@ case class ComponentParameters (
|_id = ${paramIdConstantName(param.getName)}; |_id = ${paramIdConstantName(param.getName)};
|const FwPrmIdType _baseId = static_cast<FwPrmIdType>(this->getIdBase()); |const FwPrmIdType _baseId = static_cast<FwPrmIdType>(this->getIdBase());
| |
|FW_ASSERT(this->paramDelegatePtr != NULL); |FW_ASSERT(this->paramDelegatePtr != nullptr);
|_stat = this->paramDelegatePtr->serializeParam(_baseId, _id, _saveBuff); |_stat = this->paramDelegatePtr->serializeParam(_baseId, _id, _saveBuff);
|""" |"""
) )
@ -508,7 +508,7 @@ case class ComponentParameters (
), ),
CppDoc.Type("void"), CppDoc.Type("void"),
lines( lines(
"""|FW_ASSERT(paramExternalDelegatePtr != NULL); """|FW_ASSERT(paramExternalDelegatePtr != nullptr);
|this->paramDelegatePtr = paramExternalDelegatePtr; |this->paramDelegatePtr = paramExternalDelegatePtr;
|""" |"""
) )

View File

@ -14,167 +14,145 @@ case class ComponentPorts(
private val outputPortWriter = ComponentOutputPorts(s, aNode) private val outputPortWriter = ComponentOutputPorts(s, aNode)
def getConstantMembers: List[CppDoc.Class.Member] = { def getConstantMembers: List[CppDoc.Class.Member] = List.concat(
List( getConstants(specialInputPorts),
getConstants(specialInputPorts), getConstants(typedInputPorts),
getConstants(typedInputPorts), getConstants(serialInputPorts),
getConstants(serialInputPorts), getConstants(specialOutputPorts),
getConstants(specialOutputPorts), getConstants(typedOutputPorts),
getConstants(typedOutputPorts), getConstants(serialOutputPorts),
getConstants(serialOutputPorts), )
).flatten
}
def getPublicFunctionMembers: List[CppDoc.Class.Member] = { def getPublicFunctionMembers: List[CppDoc.Class.Member] = List.concat(
List( inputPortWriter.getGetters(specialInputPorts),
inputPortWriter.getGetters(specialInputPorts), inputPortWriter.getGetters(typedInputPorts),
inputPortWriter.getGetters(typedInputPorts), inputPortWriter.getGetters(serialInputPorts),
inputPortWriter.getGetters(serialInputPorts), outputPortWriter.getTypedConnectors(specialOutputPorts),
outputPortWriter.getTypedConnectors(specialOutputPorts), outputPortWriter.getTypedConnectors(typedOutputPorts),
outputPortWriter.getTypedConnectors(typedOutputPorts), outputPortWriter.getSerialConnectors(specialOutputPorts),
outputPortWriter.getSerialConnectors(specialOutputPorts), outputPortWriter.getSerialConnectors(typedOutputPorts),
outputPortWriter.getSerialConnectors(typedOutputPorts), outputPortWriter.getSerialConnectors(serialOutputPorts),
outputPortWriter.getSerialConnectors(serialOutputPorts), )
).flatten
}
def getProtectedFunctionMembers: List[CppDoc.Class.Member] = { def getProtectedFunctionMembers: List[CppDoc.Class.Member] = List.concat(
List( getNumGetters(specialInputPorts),
getNumGetters(specialInputPorts), getNumGetters(typedInputPorts),
getNumGetters(typedInputPorts), getNumGetters(serialInputPorts),
getNumGetters(serialInputPorts), getNumGetters(specialOutputPorts),
getNumGetters(specialOutputPorts), getNumGetters(typedOutputPorts),
getNumGetters(typedOutputPorts), getNumGetters(serialOutputPorts),
getNumGetters(serialOutputPorts), outputPortWriter.getConnectionStatusQueries(specialOutputPorts),
outputPortWriter.getConnectionStatusQueries(specialOutputPorts), outputPortWriter.getConnectionStatusQueries(typedOutputPorts),
outputPortWriter.getConnectionStatusQueries(typedOutputPorts), outputPortWriter.getConnectionStatusQueries(serialOutputPorts),
outputPortWriter.getConnectionStatusQueries(serialOutputPorts), inputPortWriter.getHandlerBases(dataProductInputPorts),
inputPortWriter.getHandlerBases(dataProductInputPorts), inputPortWriter.getHandlers(typedInputPorts),
inputPortWriter.getHandlers(typedInputPorts), inputPortWriter.getHandlerBases(typedInputPorts),
inputPortWriter.getHandlerBases(typedInputPorts), inputPortWriter.getHandlers(serialInputPorts),
inputPortWriter.getHandlers(serialInputPorts), inputPortWriter.getHandlerBases(serialInputPorts),
inputPortWriter.getHandlerBases(serialInputPorts), inputPortWriter.getPreMsgHooks(dataProductAsyncInputPorts),
inputPortWriter.getPreMsgHooks(dataProductAsyncInputPorts), inputPortWriter.getPreMsgHooks(typedAsyncInputPorts),
inputPortWriter.getPreMsgHooks(typedAsyncInputPorts), inputPortWriter.getPreMsgHooks(serialAsyncInputPorts),
inputPortWriter.getPreMsgHooks(serialAsyncInputPorts), inputPortWriter.getOverflowHooks(dataProductHookPorts),
inputPortWriter.getOverflowHooks(dataProductHookPorts), inputPortWriter.getOverflowHooks(typedHookPorts),
inputPortWriter.getOverflowHooks(typedHookPorts), inputPortWriter.getOverflowHooks(serialHookPorts),
inputPortWriter.getOverflowHooks(serialHookPorts), outputPortWriter.getInvokers(dataProductOutputPorts),
outputPortWriter.getInvokers(dataProductOutputPorts), outputPortWriter.getInvokers(typedOutputPorts),
outputPortWriter.getInvokers(typedOutputPorts), outputPortWriter.getInvokers(serialOutputPorts),
outputPortWriter.getInvokers(serialOutputPorts), )
).flatten
}
def getPrivateFunctionMembers: List[CppDoc.Class.Member] = { def getPrivateFunctionMembers: List[CppDoc.Class.Member] = List.concat(
List( inputPortWriter.getCallbacks(specialInputPorts),
inputPortWriter.getCallbacks(specialInputPorts), inputPortWriter.getCallbacks(typedInputPorts),
inputPortWriter.getCallbacks(typedInputPorts), inputPortWriter.getCallbacks(serialInputPorts)
inputPortWriter.getCallbacks(serialInputPorts) )
).flatten
}
def getVariableMembers: List[CppDoc.Class.Member] = { def getVariableMembers: List[CppDoc.Class.Member] = List.concat(
List( getVariables(specialInputPorts),
getVariables(specialInputPorts), getVariables(typedInputPorts),
getVariables(typedInputPorts), getVariables(serialInputPorts),
getVariables(serialInputPorts), getVariables(specialOutputPorts),
getVariables(specialOutputPorts), getVariables(typedOutputPorts),
getVariables(typedOutputPorts), getVariables(serialOutputPorts),
getVariables(serialOutputPorts), )
).flatten
}
private def getConstants(ports: List[PortInstance]): List[CppDoc.Class.Member] = { private def getConstants(ports: List[PortInstance]): List[CppDoc.Class.Member] = {
if ports.isEmpty then Nil lazy val member = {
else List( val kind = getPortListTypeString(ports)
val direction = ports.head.getDirection.get.toString
def enumConstant(p: PortInstance) =
writeEnumConstant(portConstantName(p), p.getArraySize)
linesClassMember( linesClassMember(
List( Line.blank ::
Line.blank :: lines( line(s"//! Enumerations for numbers of $kind $direction ports") ::
s"//! Enumerations for numbers of ${getPortListTypeString(ports)} ${ports.head.getDirection.get.toString} ports" wrapInEnum(ports.flatMap(enumConstant))
),
wrapInEnum(
ports.flatMap(p =>
writeEnumConstant(
portConstantName(p),
p.getArraySize,
)
)
)
).flatten
) )
) }
guardedList (!ports.isEmpty) (List(member))
} }
def generateNumGetters( def generateNumGetters(
ports: List[PortInstance], ports: List[PortInstance],
portName: PortInstance => String, portName: PortInstance => String,
numGetterName: PortInstance => String, numGetterName: PortInstance => String,
variableName: PortInstance => String ioe: ComponentCppWriterUtils.InternalOrExternal =
ComponentCppWriterUtils.InternalOrExternal.Internal
) = { ) = {
mapPorts(ports, p => List( lazy val constantPrefix = ioe match {
functionClassMember( case ComponentCppWriterUtils.InternalOrExternal.Internal => ""
Some( case ComponentCppWriterUtils.InternalOrExternal.External =>
s"""|Get the number of ${portName(p)} ports s"$componentClassName::"
| }
|\\return The number of ${portName(p)} ports def generateNumGetter(p: PortInstance) = lines(
|""" s"""|
), |//! Get the number of ${portName(p)} ports
numGetterName(p), |//!
Nil, |//! \\return The number of ${portName(p)} ports
CppDoc.Type("FwIndexType"), |static constexpr FwIndexType ${numGetterName(p)}() {
lines( | return ${constantPrefix}${portConstantName(p)};
s"return static_cast<FwIndexType>(FW_NUM_ARRAY_ELEMENTS(this->${variableName(p)}));" |}
), |"""
CppDoc.Function.NonSV, )
CppDoc.Function.Const mapPorts(
) ports,
)) p => List(linesClassMember(generateNumGetter(p))),
CppDoc.Lines.Hpp
)
} }
private def getNumGetters(ports: List[PortInstance]): List[CppDoc.Class.Member] = { private def getNumGetters(ports: List[PortInstance]): List[CppDoc.Class.Member] = {
val dirStr = ports match { lazy val direction = ports.headOption.map(_.getDirection.get.toString).getOrElse("")
case Nil => "" lazy val kind = getPortListTypeString(ports)
case _ => ports.head.getDirection.get.toString def portName(p: PortInstance) =
} s"${p.getUnqualifiedName} ${p.getDirection.get.toString}"
addAccessTagAndComment( addAccessTagAndComment(
"protected", "protected",
s"Getters for numbers of ${getPortListTypeString(ports)} $dirStr ports", s"Getters for numbers of $kind $direction ports",
generateNumGetters( generateNumGetters(ports, portName, portNumGetterName),
ports, CppDoc.Lines.Hpp
(p: PortInstance) => s"${p.getUnqualifiedName} ${p.getDirection.get.toString}",
portNumGetterName,
portVariableName
)
) )
} }
private def getVariables(ports: List[PortInstance]): List[CppDoc.Class.Member] = { private def getVariables(ports: List[PortInstance]): List[CppDoc.Class.Member] = {
val dirStr = ports match { lazy val direction = ports.headOption.map(_.getDirection.get.toString).getOrElse("")
case Nil => "" def variable(p: PortInstance) = {
case _ => ports.head.getDirection.get.toString val typeName = getQualifiedPortTypeName(p, p.getDirection.get)
val name = portVariableName(p)
val num = portConstantName(p)
lines(
s"""|
|//! ${p.getDirection.get.toString.capitalize} port ${p.getUnqualifiedName}
|$typeName $name[$num];
|"""
)
} }
addAccessTagAndComment( addAccessTagAndComment(
"private", "private",
s"${getPortListTypeString(ports).capitalize} $dirStr ports", s"${getPortListTypeString(ports).capitalize} $direction ports",
mapPorts(ports, p => { mapPorts(
val typeName = getQualifiedPortTypeName(p, p.getDirection.get) ports,
val name = portVariableName(p) p => List(linesClassMember(variable(p))),
val num = portConstantName(p) CppDoc.Lines.Hpp
),
List(
linesClassMember(
lines(
s"""|
|//! ${p.getDirection.get.toString.capitalize} port ${p.getUnqualifiedName}
|$typeName $name[$num];
|"""
)
)
)
}, CppDoc.Lines.Hpp),
CppDoc.Lines.Hpp CppDoc.Lines.Hpp
) )
} }

View File

@ -36,7 +36,7 @@ case class ComponentTelemetry (
} }
def getVariableMembers: List[CppDoc.Class.Member] = { def getVariableMembers: List[CppDoc.Class.Member] = {
List( List.concat(
addAccessTagAndComment( addAccessTagAndComment(
"private", "private",
"First update flags for telemetry channels", "First update flags for telemetry channels",
@ -45,7 +45,7 @@ case class ComponentTelemetry (
lines( lines(
s"""| s"""|
|//! Initialized to true; cleared when channel ${channel.getName} is first updated |//! Initialized to true; cleared when channel ${channel.getName} is first updated
|bool ${channelUpdateFlagName(channel.getName)}; |bool ${channelUpdateFlagName(channel.getName)} = true;
|""" |"""
) )
) )
@ -63,14 +63,14 @@ case class ComponentTelemetry (
lines( lines(
s"""| s"""|
|//! Records the last emitted value for channel $channelName |//! Records the last emitted value for channel $channelName
|$channelType $channelStoreName; |$channelType $channelStoreName = {};
|""" |"""
) )
) )
}), }),
CppDoc.Lines.Hpp CppDoc.Lines.Hpp
) )
).flatten )
} }
private def getWriteFunctions: List[CppDoc.Class.Member] = { private def getWriteFunctions: List[CppDoc.Class.Member] = {

View File

@ -167,7 +167,7 @@ abstract class ComponentTestUtils(
def outputPortName(name: String) = def outputPortName(name: String) =
s"to_$name" s"to_$name"
/** Get the corresponding tester port name for a port in the component under test */ /** Get the corresponding tester port name for a port in the component under test */
def testerPortName(p: PortInstance) = def testerPortName(p: PortInstance) =
p.getDirection.get match { p.getDirection.get match {
case PortInstance.Direction.Input => outputPortName(p.getUnqualifiedName) case PortInstance.Direction.Input => outputPortName(p.getUnqualifiedName)

View File

@ -505,8 +505,9 @@ case class ComponentTesterBaseWriter(
inputPorts ++ outputPorts, inputPorts ++ outputPorts,
testerPortName, testerPortName,
testerPortNumGetterName, testerPortNumGetterName,
testerPortVariableName ComponentCppWriterUtils.InternalOrExternal.External
) ),
CppDoc.Lines.Hpp
) )
} }

View File

@ -316,12 +316,19 @@ case class EnumCppWriter(
CppDoc.Type("Fw::SerializeBufferBase&"), CppDoc.Type("Fw::SerializeBufferBase&"),
"buffer", "buffer",
Some("The serial buffer") Some("The serial buffer")
),
CppDoc.Function.Param(
CppDoc.Type("Fw::Endianness"),
"mode",
Some("Endianness of serialized buffer"),
Some("Fw::Endianness::BIG"),
) )
), ),
CppDoc.Type("Fw::SerializeStatus"), CppDoc.Type("Fw::SerializeStatus"),
lines( lines(
s"""|const Fw::SerializeStatus status = buffer.serializeFrom( s"""|const Fw::SerializeStatus status = buffer.serializeFrom(
| static_cast<SerialType>(this->e) | static_cast<SerialType>(this->e),
| mode
|); |);
|return status;""" |return status;"""
), ),
@ -336,12 +343,18 @@ case class EnumCppWriter(
CppDoc.Type("Fw::SerializeBufferBase&"), CppDoc.Type("Fw::SerializeBufferBase&"),
"buffer", "buffer",
Some("The serial buffer") Some("The serial buffer")
),
CppDoc.Function.Param(
CppDoc.Type("Fw::Endianness"),
"mode",
Some("Endianness of serialized buffer"),
Some("Fw::Endianness::BIG"),
) )
), ),
CppDoc.Type("Fw::SerializeStatus"), CppDoc.Type("Fw::SerializeStatus"),
lines( lines(
s"""|SerialType es; s"""|SerialType es;
|Fw::SerializeStatus status = buffer.deserializeTo(es); |Fw::SerializeStatus status = buffer.deserializeTo(es, mode);
|if (status == Fw::FW_SERIALIZE_OK) { |if (status == Fw::FW_SERIALIZE_OK) {
| this->e = static_cast<T>(es); | this->e = static_cast<T>(es);
| if (!this->isValid()) { | if (!this->isValid()) {

View File

@ -466,9 +466,9 @@ case class StructCppWriter(
lines("return status;") lines("return status;")
) )
def writeSerializeCall(n: String) = def writeSerializeCall(n: String) =
line(s"status = buffer.serializeFrom(this->m_$n);") :: writeSerializeStatusCheck line(s"status = buffer.serializeFrom(this->m_$n, mode);") :: writeSerializeStatusCheck
def writeDeserializeCall(n: String) = def writeDeserializeCall(n: String) =
line(s"status = buffer.deserializeTo(this->m_$n);") :: writeSerializeStatusCheck line(s"status = buffer.deserializeTo(this->m_$n, mode);") :: writeSerializeStatusCheck
List( List(
List( List(
@ -487,6 +487,12 @@ case class StructCppWriter(
CppDoc.Type("Fw::SerializeBufferBase&"), CppDoc.Type("Fw::SerializeBufferBase&"),
"buffer", "buffer",
Some("The serial buffer") Some("The serial buffer")
),
CppDoc.Function.Param(
CppDoc.Type("Fw::Endianness"),
"mode",
Some("Endianness of serialized buffer"),
Some("Fw::Endianness::BIG"),
) )
), ),
CppDoc.Type("Fw::SerializeStatus"), CppDoc.Type("Fw::SerializeStatus"),
@ -511,6 +517,12 @@ case class StructCppWriter(
CppDoc.Type("Fw::SerializeBufferBase&"), CppDoc.Type("Fw::SerializeBufferBase&"),
"buffer", "buffer",
Some("The serial buffer") Some("The serial buffer")
),
CppDoc.Function.Param(
CppDoc.Type("Fw::Endianness"),
"mode",
Some("Endianness of serialized buffer"),
Some("Fw::Endianness::BIG"),
) )
), ),
CppDoc.Type("Fw::SerializeStatus"), CppDoc.Type("Fw::SerializeStatus"),

View File

@ -461,6 +461,25 @@ case class DictionaryJsonEncoder(
} }
} }
/** JSON Encoding for Event.Throttle */
private implicit def eventThrottleEncoder: Encoder[Event.Throttle] = new Encoder[Event.Throttle] {
override def apply(throttle: Event.Throttle): Json = {
throttle match {
case Event.Throttle(count, Some(every)) => Json.obj(
"count" -> count.asJson,
"every" -> Json.obj(
"seconds" -> every.seconds.asJson,
"useconds" -> every.useconds.asJson
)
)
case Event.Throttle(count, None) => Json.obj(
"count" -> count.asJson,
"every" -> Json.Null
)
}
}
}
/** JSON Encoding for TlmChannel.Limits */ /** JSON Encoding for TlmChannel.Limits */
private implicit def channelLimitEncoder: Encoder[TlmChannel.Limits] = new Encoder[TlmChannel.Limits] { private implicit def channelLimitEncoder: Encoder[TlmChannel.Limits] = new Encoder[TlmChannel.Limits] {
override def apply(limits: TlmChannel.Limits): Json = { override def apply(limits: TlmChannel.Limits): Json = {
@ -604,6 +623,7 @@ case class DictionaryJsonEncoder(
} }
case x: Value => Json.obj(key -> valueAsJson(x)).deepMerge(json) case x: Value => Json.obj(key -> valueAsJson(x)).deepMerge(json)
case x: Ast.QueueFull => Json.obj(key -> x.toString.asJson).deepMerge(json) case x: Ast.QueueFull => Json.obj(key -> x.toString.asJson).deepMerge(json)
case x: Event.Throttle => Json.obj(key -> x.asJson).deepMerge(json)
} }
case None => json case None => json
} }

View File

@ -483,6 +483,11 @@ object FppWriter extends AstVisitor with LineUtils {
in: In, in: In,
aNode: Ast.Annotated[AstNode[Ast.SpecEvent]] aNode: Ast.Annotated[AstNode[Ast.SpecEvent]]
) = { ) = {
def eventThrottle(throttle: AstNode[Ast.EventThrottle]) = {
Line.addPrefix("throttle ", exprNode(throttle.data.count)).
joinOpt (throttle.data.every) (" every ") (exprNode)
}
val (_, node, _) = aNode val (_, node, _) = aNode
val data = node.data val data = node.data
val severity = data.severity.toString val severity = data.severity.toString
@ -491,7 +496,7 @@ object FppWriter extends AstVisitor with LineUtils {
joinWithBreak ("severity ") (lines(severity)). joinWithBreak ("severity ") (lines(severity)).
joinOptWithBreak (data.id) ("id ") (exprNode). joinOptWithBreak (data.id) ("id ") (exprNode).
joinWithBreak ("format ") (string(data.format.data)). joinWithBreak ("format ") (string(data.format.data)).
joinOptWithBreak (data.throttle) ("throttle ") (exprNode) joinOptWithBreak (data.throttle) ("") (eventThrottle)
} }
override def specIncludeAnnotatedNode( override def specIncludeAnnotatedNode(

View File

@ -28,6 +28,10 @@ object AstJsonEncoder extends JsonEncoder {
implicit val exprEncoder: Encoder[Ast.Expr] = implicit val exprEncoder: Encoder[Ast.Expr] =
io.circe.generic.semiauto.deriveEncoder[Ast.Expr] io.circe.generic.semiauto.deriveEncoder[Ast.Expr]
// JSON encoder for event throttle
implicit val eventThrottleEncoder: Encoder[Ast.EventThrottle] =
io.circe.generic.semiauto.deriveEncoder[Ast.EventThrottle]
// JSON encoder for module member nodes // JSON encoder for module member nodes
implicit val moduleMemberNodeEncoder: Encoder[Ast.ModuleMember.Node] = implicit val moduleMemberNodeEncoder: Encoder[Ast.ModuleMember.Node] =
io.circe.generic.semiauto.deriveEncoder[Ast.ModuleMember.Node] io.circe.generic.semiauto.deriveEncoder[Ast.ModuleMember.Node]

View File

@ -315,7 +315,11 @@ object ComponentXmlFppWriter extends LineUtils {
severity, severity,
id, id,
AstNode.create(format), AstNode.create(format),
throttle throttle match {
case Some(count) =>
Some(AstNode.create(Ast.EventThrottle(count, None)))
case None => None
},
) )
val node = AstNode.create(event) val node = AstNode.create(event)
val memberNode = Ast.ComponentMember.SpecEvent(node) val memberNode = Ast.ComponentMember.SpecEvent(node)

View File

@ -54,6 +54,7 @@ object Lexer {
("entry", ENTRY), ("entry", ENTRY),
("enum", ENUM), ("enum", ENUM),
("event", EVENT), ("event", EVENT),
("every", EVERY),
("exit", EXIT), ("exit", EXIT),
("external", EXTERNAL), ("external", EXTERNAL),
("false", FALSE), ("false", FALSE),
@ -248,6 +249,7 @@ object Lexer {
case EOL => Token.EOL() case EOL => Token.EOL()
case EQUALS => Token.EQUALS() case EQUALS => Token.EQUALS()
case EVENT => Token.EVENT() case EVENT => Token.EVENT()
case EVERY => Token.EVERY()
case EXIT => Token.EXIT() case EXIT => Token.EXIT()
case EXTERNAL => Token.EXTERNAL() case EXTERNAL => Token.EXTERNAL()
case F32 => Token.F32() case F32 => Token.F32()

View File

@ -620,10 +620,16 @@ object Parser extends Parsers {
failure("severity level expected") failure("severity level expected")
} }
def throttleClause = {
(throttle ~>! exprNode) ~! opt(every ~>! exprNode) ^^ {
case throttle ~ duration => Ast.EventThrottle(throttle, duration)
}
}
(event ~> ident) ~! formalParamList ~! (severity ~>! severityLevel) ~! (event ~> ident) ~! formalParamList ~! (severity ~>! severityLevel) ~!
opt(id ~>! exprNode) ~! opt(id ~>! exprNode) ~!
(format ~>! node(literalString)) ~! (format ~>! node(literalString)) ~!
opt(throttle ~>! exprNode) ^^ { opt(node(throttleClause)) ^^ {
case name ~ params ~ severity ~ id ~ format ~ throttle => case name ~ params ~ severity ~ id ~ format ~ throttle =>
Ast.SpecEvent(name, params, severity, id, format, throttle) Ast.SpecEvent(name, params, severity, id, format, throttle)
} }
@ -1131,6 +1137,8 @@ object Parser extends Parsers {
private def event = accept("event", { case t: Token.EVENT => t }) private def event = accept("event", { case t: Token.EVENT => t })
private def every = accept("every", { case t: Token.EVERY => t })
private def exit = accept("exit", { case t: Token.EXIT => t }) private def exit = accept("exit", { case t: Token.EXIT => t })
private def external = accept("external", { case t : Token.EXTERNAL => t }) private def external = accept("external", { case t : Token.EXTERNAL => t })

View File

@ -40,6 +40,7 @@ object Token {
final case class EOL() extends Token final case class EOL() extends Token
final case class EQUALS() extends Token final case class EQUALS() extends Token
final case class EVENT() extends Token final case class EVENT() extends Token
final case class EVERY() extends Token
final case class EXIT() extends Token final case class EXIT() extends Token
final case class EXTERNAL() extends Token final case class EXTERNAL() extends Token
final case class F32() extends Token final case class F32() extends Token
@ -186,6 +187,7 @@ enum TokenId {
case ENTRY case ENTRY
case ENUM case ENUM
case EVENT case EVENT
case EVERY
case EXIT case EXIT
case EXTERNAL case EXTERNAL
case F32 case F32

View File

@ -126,6 +126,9 @@ sealed trait Error {
case SemanticError.DuplicateTopology(name, loc, prevLoc) => case SemanticError.DuplicateTopology(name, loc, prevLoc) =>
Error.print (Some(loc)) (s"duplicate topology ${name}") Error.print (Some(loc)) (s"duplicate topology ${name}")
printPrevLoc(prevLoc) printPrevLoc(prevLoc)
case SemanticError.DuplicateInterface(name, loc, prevLoc) =>
Error.print (Some(loc)) (s"duplicate interface ${name}")
printPrevLoc(prevLoc)
case SemanticError.EmptyArray(loc) => case SemanticError.EmptyArray(loc) =>
Error.print (Some(loc)) ("array expression may not be empty") Error.print (Some(loc)) ("array expression may not be empty")
case SemanticError.ImplicitDuplicateConnectionAtMatchedPort( case SemanticError.ImplicitDuplicateConnectionAtMatchedPort(
@ -496,6 +499,12 @@ object SemanticError {
loc: Location, loc: Location,
prevLoc: Location prevLoc: Location
) extends Error ) extends Error
/** Duplicate interface */
final case class DuplicateInterface(
name: String,
loc: Location,
prevLoc: Location
) extends Error
/** Implicit duplicate connection at matched port */ /** Implicit duplicate connection at matched port */
final case class ImplicitDuplicateConnectionAtMatchedPort( final case class ImplicitDuplicateConnectionAtMatchedPort(
loc: Location, loc: Location,

View File

@ -16,7 +16,7 @@ object Result {
/** Left fold with a function that returns a result */ /** Left fold with a function that returns a result */
@tailrec @tailrec
def foldLeft[A,B] def foldLeft[A, B]
(as: List[A]) (as: List[A])
(b: B) (b: B)
(f: (B, A) => Result.Result[B]): Result.Result[B] = (f: (B, A) => Result.Result[B]): Result.Result[B] =

View File

@ -0,0 +1,10 @@
package fpp.compiler.util
object UInt {
/** The smallest value representable as a UInt. */
final val MinValue = 0
/** The largest value representable as a UInt. */
final val MaxValue = 4294967295L
}

View File

@ -454,6 +454,7 @@ class ParserSpec extends AnyWordSpec {
"event E severity activity high id 0x100 format \"event E\"", "event E severity activity high id 0x100 format \"event E\"",
"event E (x: U32) severity activity high id 0x100 format \"x={}\"", "event E (x: U32) severity activity high id 0x100 format \"x={}\"",
"event E (x: U32) severity activity high id 0x100 format \"x={}\" throttle 10", "event E (x: U32) severity activity high id 0x100 format \"x={}\" throttle 10",
"event E (x: U32) severity activity high id 0x100 format \"x={}\" throttle 10 every {seconds=10,useconds=11}",
) )
) )
} }

View File

@ -25,10 +25,13 @@ evalp()
# Get tool names from a directory # Get tool names from a directory
get_tool_names() get_tool_names()
{ {
prefix="fpp-"
dir=$1 dir=$1
for file in $dir/*.jar for file in $dir/$prefix*
do do
basename $file .jar base=`basename $file`
result="${base#$prefix}"
echo $result
done done
} }
@ -86,26 +89,30 @@ print_phase "Constructing binary tools in $native_bin"
# Get the tool names from bin # Get the tool names from bin
tool_names=`get_tool_names bin` tool_names=`get_tool_names bin`
jar_file="bin/fpp.jar"
out_file="$native_bin/fpp"
echo "Building fpp"
evalp "$native_image" $FPP_NATIVE_IMAGE_FLAGS \
--no-fallback --install-exit-handlers \
-jar "$jar_file" "$out_file"
if [ $? -ne 0 ]
then
echo "[ERROR] Failed to build $out_file"
exit 1
fi
sync; sync; sync;
if ! $out_file --help 1>/dev/null
then
echo "[ERROR] $out_file not executable"
exit 1
fi
# Use GraalVM to convert the jar files to native binaries # Use GraalVM to convert the jar files to native binaries
for tool_name in $tool_names for tool in $tool_names
do do
jar_file="bin/$tool_name.jar" echo '#!/bin/sh
out_file="$native_bin/$tool_name" "`dirname $0`/fpp" '$tool' "$@"' > $native_bin/fpp-$tool
echo "Building $out_file" chmod +x $native_bin/fpp-$tool
evalp "$native_image" $FPP_NATIVE_IMAGE_FLAGS \
--no-fallback --install-exit-handlers \
-jar "$jar_file" "$out_file"
if [ $? -ne 0 ]
then
echo "[ERROR] Failed to build $out_file"
exit 1
fi
sync; sync; sync;
if ! $out_file --help 1>/dev/null
then
echo "[ERROR] $out_file not executable"
exit 1
fi
done done
sync; sync; sync; sync; sync; sync;

View File

@ -40,7 +40,6 @@ os=`uname`
case "$os" in case "$os" in
Darwin) Darwin)
os_type=DARWIN os_type=DARWIN
#os_flags='-ferror-limit=1'
;; ;;
Linux) Linux)
os_type=LINUX os_type=LINUX
@ -51,7 +50,7 @@ case "$os" in
;; ;;
esac esac
g++ --std=c++11 \ g++ --std=c++14 \
$flags \ $flags \
$os_flags \ $os_flags \
-DTGT_OS_TYPE_$os_type \ -DTGT_OS_TYPE_$os_type \

12
compiler/tools.txt Normal file
View File

@ -0,0 +1,12 @@
check
depend
filenames
format
from-xml
locate-defs
locate-uses
syntax
to-cpp
to-json
to-dict
to-layout

View File

@ -0,0 +1,5 @@
active component C {
event E severity activity low format "" throttle 10 every false
}

View File

@ -0,0 +1,5 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/event/bad_throttle_interval.fpp:3.61
event E severity activity low format "" throttle 10 every false
^
error: cannot convert bool to { seconds: U32, useconds: U32 }

View File

@ -0,0 +1,7 @@
active component C {
event E severity activity low \
format "" throttle 10 \
every {seconds=1,minutes=10}
}

View File

@ -0,0 +1,5 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/event/bad_throttle_interval_extra_member.fpp:5.11
every {seconds=1,minutes=10}
^
error: cannot convert { seconds: Integer, minutes: Integer } to { seconds: U32, useconds: U32 }

View File

@ -0,0 +1,7 @@
active component C {
event E severity activity low \
format "" throttle 10 \
every {seconds=-1}
}

View File

@ -0,0 +1,6 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/event/bad_throttle_interval_seconds.fpp:5.11
every {seconds=-1}
^
error: invalid integer value -1
seconds must be in the range [0, 4294967295]

View File

@ -0,0 +1,7 @@
active component C {
event E severity activity low \
format "" throttle 10 \
every {useconds=1000000}
}

View File

@ -0,0 +1,6 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/event/bad_throttle_interval_useconds.fpp:5.11
every {useconds=1000000}
^
error: invalid integer value 1000000
useconds must be in the range [0, 999999]

View File

@ -0,0 +1,7 @@
active component C {
event E severity activity low \
format "" throttle 10 \
every {seconds=4294967295 + 1}
}

View File

@ -0,0 +1,6 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/event/bad_throttle_seconds.fpp:5.11
every {seconds=4294967295 + 1}
^
error: invalid integer value 4294967296
seconds must be in the range [0, 4294967295]

View File

@ -46,4 +46,16 @@ passive component C {
format "Saw value {} for case {}" \ format "Saw value {} for case {}" \
throttle 10 throttle 10
@ Event 3
@ Sample output: "Saw value [ 0.001, 0.002, 0.003 ] for case A"
event Event3(
case: Case @< The case
value: F64x3 @< The value
) \
severity warning low \
id 0x03 \
format "Saw value {} for case {}" \
throttle 10 \
every {seconds=10,useconds=500000}
} }

View File

@ -1,5 +1,10 @@
tests=" tests="
bad_id bad_id
bad_throttle_interval_extra_member
bad_throttle_interval_seconds
bad_throttle_interval_useconds
bad_throttle_interval
bad_throttle_seconds
bad_throttle bad_throttle
duplicate_id_explicit duplicate_id_explicit
duplicate_id_implicit duplicate_id_implicit
@ -15,4 +20,5 @@ not_displayable
ok ok
ref_params ref_params
throttle_too_large throttle_too_large
zero_throttle_count
" "

View File

@ -0,0 +1,6 @@
passive component C {
event E severity activity low \
format "" throttle 0
}

View File

@ -0,0 +1,5 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/event/zero_throttle_count.fpp:3.3
event E severity activity low \
^
error: event throttle count must be greater than zero

View File

@ -0,0 +1,3 @@
interface I {
import I
}

View File

@ -0,0 +1,6 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/interface/cycles.fpp:1.1
interface I {
^
error: encountered a use-def cycle:
use I at [ local path prefix ]/compiler/tools/fpp-check/test/interface/cycles.fpp:2.12 refers to definition I at [ local path prefix ]/compiler/tools/fpp-check/test/interface/cycles.fpp:1.1

View File

@ -0,0 +1,7 @@
interface I {
}
interface I2 {
import I
import I
}

View File

@ -0,0 +1,9 @@
fpp-check
[ local path prefix ]/compiler/tools/fpp-check/test/interface/duplicate_import.fpp:6.5
import I
^
error: duplicate interface I
previous occurrence is here:
[ local path prefix ]/compiler/tools/fpp-check/test/interface/duplicate_import.fpp:5.5
import I
^

View File

@ -1,5 +1,12 @@
port P() port P()
interface I1 {
import I2
}
interface I2 {
}
module Fw { module Fw {
port Cmd port Cmd
port CmdReg port CmdReg
@ -27,4 +34,9 @@ interface I {
active component C { active component C {
import Cmd import Cmd
import I import I
import I3
}
interface I3 {
async input port pAsync2: P
} }

View File

@ -1,6 +1,8 @@
tests=" tests="
async_port_in_passive async_port_in_passive
conflict_name conflict_name
cycles
duplicate_import
duplicate_name duplicate_name
empty_ok empty_ok
ok ok

View File

@ -1 +0,0 @@
sbt.version=1.6.1

View File

@ -1,9 +1,10 @@
locate type T at "T.fpp" locate type T at "T.fpp"
locate constant a at "a.fpp" locate constant a at "a.fpp"
locate constant b at "b.fpp" locate constant b at "b.fpp"
locate constant c at "c.fpp"
active component C { active component C {
event E(x: T) severity activity low id a format "x={}" throttle b event E(x: T) severity activity low id a format "x={}" throttle b every c
} }

View File

@ -1,3 +1,4 @@
[ local path prefix ]/compiler/tools/fpp-depend/test/T.fpp [ local path prefix ]/compiler/tools/fpp-depend/test/T.fpp
[ local path prefix ]/compiler/tools/fpp-depend/test/a.fpp [ local path prefix ]/compiler/tools/fpp-depend/test/a.fpp
[ local path prefix ]/compiler/tools/fpp-depend/test/b.fpp [ local path prefix ]/compiler/tools/fpp-depend/test/b.fpp
[ local path prefix ]/compiler/tools/fpp-depend/test/c.fpp

View File

@ -1 +0,0 @@
sbt.version=1.6.1

View File

@ -124,6 +124,18 @@ module DefinitionsAndSpecifiers {
format "{} counts" \ format "{} counts" \
throttle 10 @< Event specifier throttle 10 @< Event specifier
@ Event specifier with throttle timeout
event ET(
a: U32
b: F32
) \
severity activity high \
id 0x00 \
format "{} counts" \
throttle 10 every {
seconds = 10
} @< Event specifier
@ Internal port specifier @ Internal port specifier
internal port I( internal port I(
a: U32 a: U32

View File

@ -124,6 +124,18 @@ module DefinitionsAndSpecifiers {
format "{} counts" \ format "{} counts" \
throttle 10 @< Event specifier throttle 10 @< Event specifier
@ Event specifier with throttle timeout
event ET(
a: U32
b: F32
) \
severity activity high \
id 0x00 \
format "{} counts" \
throttle 10 every {
seconds = 10
} @< Event specifier
@ Internal port specifier @ Internal port specifier
internal port I( internal port I(
a: U32 a: U32

View File

@ -1 +0,0 @@
sbt.version=1.6.1

View File

@ -1 +0,0 @@
sbt.version=1.6.1

View File

@ -1 +0,0 @@
sbt.version=1.6.1

View File

@ -22,6 +22,7 @@ enum Phases { setup, teardown }
struct S { x: U32 } struct S { x: U32 }
type T type T
state machine S state machine S
constant t = {seconds=10,useconds=20}
module M { module M {
array A = [3] U32 array A = [3] U32

View File

@ -13,6 +13,7 @@ locate constant product_recv_priority at "defs.fpp"
locate constant queue_size_def at "defs.fpp" locate constant queue_size_def at "defs.fpp"
locate constant record_id at "defs.fpp" locate constant record_id at "defs.fpp"
locate constant stack_size_def at "defs.fpp" locate constant stack_size_def at "defs.fpp"
locate constant t at "defs.fpp"
locate constant tlm_packet_group at "defs.fpp" locate constant tlm_packet_group at "defs.fpp"
locate constant tlm_packet_id at "defs.fpp" locate constant tlm_packet_id at "defs.fpp"
locate instance M.c11 at "defs.fpp" locate instance M.c11 at "defs.fpp"

View File

@ -13,6 +13,7 @@ locate constant product_recv_priority at "defs.fpp"
locate constant queue_size_def at "defs.fpp" locate constant queue_size_def at "defs.fpp"
locate constant record_id at "defs.fpp" locate constant record_id at "defs.fpp"
locate constant stack_size_def at "defs.fpp" locate constant stack_size_def at "defs.fpp"
locate constant t at "defs.fpp"
locate constant tlm_packet_group at "defs.fpp" locate constant tlm_packet_group at "defs.fpp"
locate constant tlm_packet_id at "defs.fpp" locate constant tlm_packet_id at "defs.fpp"
locate instance M.c11 at "defs.fpp" locate instance M.c11 at "defs.fpp"

View File

@ -41,6 +41,7 @@ active component C3 {
state machine instance M_S_use: M.S state machine instance M_S_use: M.S
state machine instance C1_S_use: C1.S state machine instance C1_S_use: C1.S
state machine instance M_C1_S_use: M.C1.S state machine instance M_C1_S_use: M.C1.S
event E(x: M.E) severity activity low id a format "x={}" throttle M.a + 2 every t
} }
active component C4 { active component C4 {

View File

@ -13,6 +13,7 @@ locate constant product_recv_priority at "../defs.fpp"
locate constant queue_size_def at "../defs.fpp" locate constant queue_size_def at "../defs.fpp"
locate constant record_id at "../defs.fpp" locate constant record_id at "../defs.fpp"
locate constant stack_size_def at "../defs.fpp" locate constant stack_size_def at "../defs.fpp"
locate constant t at "../defs.fpp"
locate constant tlm_packet_group at "../defs.fpp" locate constant tlm_packet_group at "../defs.fpp"
locate constant tlm_packet_id at "../defs.fpp" locate constant tlm_packet_id at "../defs.fpp"
locate instance M.c11 at "../defs.fpp" locate instance M.c11 at "../defs.fpp"

View File

@ -1 +0,0 @@
sbt.version=1.6.1

View File

@ -207,6 +207,26 @@ def module
format {} counts format {} counts
throttle literal int 10 throttle literal int 10
@< Event specifier @< Event specifier
@ Event specifier with throttle timeout
spec event
ident ET
formal param
kind value
ident a
type name U32
formal param
kind value
ident b
type name F32
severity activity high
id literal int 0x00
format {} counts
throttle literal int 10
every expr struct
struct member
ident seconds
literal int 10
@< Event specifier
@ Internal port specifier @ Internal port specifier
spec internal port spec internal port
ident I ident I

View File

@ -207,6 +207,26 @@ def module
format {} counts format {} counts
throttle literal int 10 throttle literal int 10
@< Event specifier @< Event specifier
@ Event specifier with throttle timeout
spec event
ident ET
formal param
kind value
ident a
type name U32
formal param
kind value
ident b
type name F32
severity activity high
id literal int 0x00
format {} counts
throttle literal int 10
every expr struct
struct member
ident seconds
literal int 10
@< Event specifier
@ Internal port specifier @ Internal port specifier
spec internal port spec internal port
ident I ident I

View File

@ -207,6 +207,26 @@ def module
format {} counts format {} counts
throttle literal int 10 throttle literal int 10
@< Event specifier @< Event specifier
@ Event specifier with throttle timeout
spec event
ident ET
formal param
kind value
ident a
type name U32
formal param
kind value
ident b
type name F32
severity activity high
id literal int 0x00
format {} counts
throttle literal int 10
every expr struct
struct member
ident seconds
literal int 10
@< Event specifier
@ Internal port specifier @ Internal port specifier
spec internal port spec internal port
ident I ident I

View File

@ -100,6 +100,10 @@ module DefinitionsAndSpecifiers {
event E(a: U32, b: F32) severity activity low id 0x00 format "{} counts" throttle 10 event E(a: U32, b: F32) severity activity low id 0x00 format "{} counts" throttle 10
@< Event specifier @< Event specifier
@ Event specifier with throttle timeout
event ET(a: U32, b: F32) severity activity high id 0x00 format "{} counts" throttle 10 every {seconds=10}
@< Event specifier
@ Internal port specifier @ Internal port specifier
internal port I(a: U32, b: F32) priority 10 assert internal port I(a: U32, b: F32) priority 10 assert
@< Internal port specifier @< Internal port specifier

View File

@ -1 +0,0 @@
sbt.version=1.6.1

View File

@ -15,4 +15,5 @@ default-tests.sh
default-update-ref.sh default-update-ref.sh
!*/include/* !*/include/*
!*.ref.h !*.ref.h
fpp-*.json

View File

@ -78,11 +78,14 @@ std::ostream& operator<<(std::ostream& os, const Abs& obj) {
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
Fw::SerializeStatus Abs :: Fw::SerializeStatus Abs ::
serializeTo(Fw::SerializeBufferBase& buffer) const serializeTo(
Fw::SerializeBufferBase& buffer,
Fw::Endianness mode
) const
{ {
Fw::SerializeStatus status; Fw::SerializeStatus status;
status = buffer.serializeFrom(this->m_A); status = buffer.serializeFrom(this->m_A, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
@ -91,11 +94,14 @@ Fw::SerializeStatus Abs ::
} }
Fw::SerializeStatus Abs :: Fw::SerializeStatus Abs ::
deserializeFrom(Fw::SerializeBufferBase& buffer) deserializeFrom(
Fw::SerializeBufferBase& buffer,
Fw::Endianness mode
)
{ {
Fw::SerializeStatus status; Fw::SerializeStatus status;
status = buffer.deserializeTo(this->m_A); status = buffer.deserializeTo(this->m_A, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }

View File

@ -85,12 +85,14 @@ class Abs :
//! Serialization //! Serialization
Fw::SerializeStatus serializeTo( Fw::SerializeStatus serializeTo(
Fw::SerializeBufferBase& buffer //!< The serial buffer Fw::SerializeBufferBase& buffer, //!< The serial buffer
Fw::Endianness mode = Fw::Endianness::BIG //!< Endianness of serialized buffer
) const; ) const;
//! Deserialization //! Deserialization
Fw::SerializeStatus deserializeFrom( Fw::SerializeStatus deserializeFrom(
Fw::SerializeBufferBase& buffer //!< The serial buffer Fw::SerializeBufferBase& buffer, //!< The serial buffer
Fw::Endianness mode = Fw::Endianness::BIG //!< Endianness of serialized buffer
); );
//! Get the dynamic serialized size of the struct //! Get the dynamic serialized size of the struct

View File

@ -98,23 +98,26 @@ std::ostream& operator<<(std::ostream& os, const Basic& obj) {
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
Fw::SerializeStatus Basic :: Fw::SerializeStatus Basic ::
serializeTo(Fw::SerializeBufferBase& buffer) const serializeTo(
Fw::SerializeBufferBase& buffer,
Fw::Endianness mode
) const
{ {
Fw::SerializeStatus status; Fw::SerializeStatus status;
status = buffer.serializeFrom(this->m_A); status = buffer.serializeFrom(this->m_A, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
status = buffer.serializeFrom(this->m_B); status = buffer.serializeFrom(this->m_B, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
status = buffer.serializeFrom(this->m_C); status = buffer.serializeFrom(this->m_C, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
status = buffer.serializeFrom(this->m_D); status = buffer.serializeFrom(this->m_D, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
@ -123,23 +126,26 @@ Fw::SerializeStatus Basic ::
} }
Fw::SerializeStatus Basic :: Fw::SerializeStatus Basic ::
deserializeFrom(Fw::SerializeBufferBase& buffer) deserializeFrom(
Fw::SerializeBufferBase& buffer,
Fw::Endianness mode
)
{ {
Fw::SerializeStatus status; Fw::SerializeStatus status;
status = buffer.deserializeTo(this->m_A); status = buffer.deserializeTo(this->m_A, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
status = buffer.deserializeTo(this->m_B); status = buffer.deserializeTo(this->m_B, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
status = buffer.deserializeTo(this->m_C); status = buffer.deserializeTo(this->m_C, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
status = buffer.deserializeTo(this->m_D); status = buffer.deserializeTo(this->m_D, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }

View File

@ -96,12 +96,14 @@ class Basic :
//! Serialization //! Serialization
Fw::SerializeStatus serializeTo( Fw::SerializeStatus serializeTo(
Fw::SerializeBufferBase& buffer //!< The serial buffer Fw::SerializeBufferBase& buffer, //!< The serial buffer
Fw::Endianness mode = Fw::Endianness::BIG //!< Endianness of serialized buffer
) const; ) const;
//! Deserialization //! Deserialization
Fw::SerializeStatus deserializeFrom( Fw::SerializeStatus deserializeFrom(
Fw::SerializeBufferBase& buffer //!< The serial buffer Fw::SerializeBufferBase& buffer, //!< The serial buffer
Fw::Endianness mode = Fw::Endianness::BIG //!< Endianness of serialized buffer
); );
//! Get the dynamic serialized size of the struct //! Get the dynamic serialized size of the struct

View File

@ -98,23 +98,26 @@ std::ostream& operator<<(std::ostream& os, const Namespace& obj) {
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
Fw::SerializeStatus Namespace :: Fw::SerializeStatus Namespace ::
serializeTo(Fw::SerializeBufferBase& buffer) const serializeTo(
Fw::SerializeBufferBase& buffer,
Fw::Endianness mode
) const
{ {
Fw::SerializeStatus status; Fw::SerializeStatus status;
status = buffer.serializeFrom(this->m_A); status = buffer.serializeFrom(this->m_A, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
status = buffer.serializeFrom(this->m_B); status = buffer.serializeFrom(this->m_B, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
status = buffer.serializeFrom(this->m_C); status = buffer.serializeFrom(this->m_C, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
status = buffer.serializeFrom(this->m_D); status = buffer.serializeFrom(this->m_D, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
@ -123,23 +126,26 @@ Fw::SerializeStatus Namespace ::
} }
Fw::SerializeStatus Namespace :: Fw::SerializeStatus Namespace ::
deserializeFrom(Fw::SerializeBufferBase& buffer) deserializeFrom(
Fw::SerializeBufferBase& buffer,
Fw::Endianness mode
)
{ {
Fw::SerializeStatus status; Fw::SerializeStatus status;
status = buffer.deserializeTo(this->m_A); status = buffer.deserializeTo(this->m_A, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
status = buffer.deserializeTo(this->m_B); status = buffer.deserializeTo(this->m_B, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
status = buffer.deserializeTo(this->m_C); status = buffer.deserializeTo(this->m_C, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
status = buffer.deserializeTo(this->m_D); status = buffer.deserializeTo(this->m_D, mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }

View File

@ -96,12 +96,14 @@ class Namespace :
//! Serialization //! Serialization
Fw::SerializeStatus serializeTo( Fw::SerializeStatus serializeTo(
Fw::SerializeBufferBase& buffer //!< The serial buffer Fw::SerializeBufferBase& buffer, //!< The serial buffer
Fw::Endianness mode = Fw::Endianness::BIG //!< Endianness of serialized buffer
) const; ) const;
//! Deserialization //! Deserialization
Fw::SerializeStatus deserializeFrom( Fw::SerializeStatus deserializeFrom(
Fw::SerializeBufferBase& buffer //!< The serial buffer Fw::SerializeBufferBase& buffer, //!< The serial buffer
Fw::Endianness mode = Fw::Endianness::BIG //!< Endianness of serialized buffer
); );
//! Get the dynamic serialized size of the struct //! Get the dynamic serialized size of the struct

View File

@ -11,6 +11,7 @@ struct T : public Fw::Serializable { // Extend Fw::Serializable
// Define some shorthand for F Prime types // Define some shorthand for F Prime types
typedef Fw::SerializeStatus SS; typedef Fw::SerializeStatus SS;
typedef Fw::SerializeBufferBase B; typedef Fw::SerializeBufferBase B;
typedef Fw::Endianness E;
// Define the constant SERIALIZED_SIZE // Define the constant SERIALIZED_SIZE
enum Constants { SERIALIZED_SIZE = sizeof(U32) }; enum Constants { SERIALIZED_SIZE = sizeof(U32) };
@ -22,10 +23,10 @@ struct T : public Fw::Serializable { // Extend Fw::Serializable
bool operator==(const T& that) const { return this->x == that.x; } bool operator==(const T& that) const { return this->x == that.x; }
// Define the virtual serializeTo method // Define the virtual serializeTo method
SS serializeTo(B& b) const { return b.serializeFrom(x); } SS serializeTo(B& b, E e) const { return b.serializeFrom(x, e); }
// Define the virtual deserializeFrom method // Define the virtual deserializeFrom method
SS deserializeFrom(B& b) { return b.deserializeTo(x); } SS deserializeFrom(B& b, E e) { return b.deserializeTo(x, e); }
// Provide some data // Provide some data
U32 x; U32 x;

View File

@ -87,8 +87,7 @@ A& A ::
A& A :: A& A ::
operator=(const std::initializer_list<ElementType>& il) operator=(const std::initializer_list<ElementType>& il)
{ {
// Since we are required to use C++11, this has to be a runtime check // Check that the initializer has the expected size
// In C++14, it can be a static check
FW_ASSERT(il.size() == SIZE, static_cast<FwAssertArgType>(il.size()), static_cast<FwAssertArgType>(SIZE)); FW_ASSERT(il.size() == SIZE, static_cast<FwAssertArgType>(il.size()), static_cast<FwAssertArgType>(SIZE));
FwSizeType i = 0; FwSizeType i = 0;
for (const auto& e : il) { for (const auto& e : il) {
@ -141,11 +140,14 @@ std::ostream& operator<<(std::ostream& os, const A& obj) {
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
Fw::SerializeStatus A :: Fw::SerializeStatus A ::
serializeTo(Fw::SerializeBufferBase& buffer) const serializeTo(
Fw::SerializeBufferBase& buffer,
Fw::Endianness mode
) const
{ {
Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK; Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK;
for (FwSizeType index = 0; index < SIZE; index++) { for (FwSizeType index = 0; index < SIZE; index++) {
status = buffer.serializeFrom((*this)[index]); status = buffer.serializeFrom((*this)[index], mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
@ -154,11 +156,14 @@ Fw::SerializeStatus A ::
} }
Fw::SerializeStatus A :: Fw::SerializeStatus A ::
deserializeFrom(Fw::SerializeBufferBase& buffer) deserializeFrom(
Fw::SerializeBufferBase& buffer,
Fw::Endianness mode
)
{ {
Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK; Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK;
for (FwSizeType index = 0; index < SIZE; index++) { for (FwSizeType index = 0; index < SIZE; index++) {
status = buffer.deserializeTo((*this)[index]); status = buffer.deserializeTo((*this)[index], mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }

View File

@ -136,12 +136,14 @@ class A :
//! Serialization //! Serialization
Fw::SerializeStatus serializeTo( Fw::SerializeStatus serializeTo(
Fw::SerializeBufferBase& buffer //!< The serial buffer Fw::SerializeBufferBase& buffer, //!< The serial buffer
Fw::Endianness mode = Fw::Endianness::BIG //!< Endianness of serialized buffer
) const; ) const;
//! Deserialization //! Deserialization
Fw::SerializeStatus deserializeFrom( Fw::SerializeStatus deserializeFrom(
Fw::SerializeBufferBase& buffer //!< The serial buffer Fw::SerializeBufferBase& buffer, //!< The serial buffer
Fw::Endianness mode = Fw::Endianness::BIG //!< Endianness of serialized buffer
); );
//! Get the dynamic serialized size of the array //! Get the dynamic serialized size of the array

View File

@ -87,8 +87,7 @@ AbsType& AbsType ::
AbsType& AbsType :: AbsType& AbsType ::
operator=(const std::initializer_list<ElementType>& il) operator=(const std::initializer_list<ElementType>& il)
{ {
// Since we are required to use C++11, this has to be a runtime check // Check that the initializer has the expected size
// In C++14, it can be a static check
FW_ASSERT(il.size() == SIZE, static_cast<FwAssertArgType>(il.size()), static_cast<FwAssertArgType>(SIZE)); FW_ASSERT(il.size() == SIZE, static_cast<FwAssertArgType>(il.size()), static_cast<FwAssertArgType>(SIZE));
FwSizeType i = 0; FwSizeType i = 0;
for (const auto& e : il) { for (const auto& e : il) {
@ -141,11 +140,14 @@ std::ostream& operator<<(std::ostream& os, const AbsType& obj) {
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
Fw::SerializeStatus AbsType :: Fw::SerializeStatus AbsType ::
serializeTo(Fw::SerializeBufferBase& buffer) const serializeTo(
Fw::SerializeBufferBase& buffer,
Fw::Endianness mode
) const
{ {
Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK; Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK;
for (FwSizeType index = 0; index < SIZE; index++) { for (FwSizeType index = 0; index < SIZE; index++) {
status = buffer.serializeFrom((*this)[index]); status = buffer.serializeFrom((*this)[index], mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
@ -154,11 +156,14 @@ Fw::SerializeStatus AbsType ::
} }
Fw::SerializeStatus AbsType :: Fw::SerializeStatus AbsType ::
deserializeFrom(Fw::SerializeBufferBase& buffer) deserializeFrom(
Fw::SerializeBufferBase& buffer,
Fw::Endianness mode
)
{ {
Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK; Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK;
for (FwSizeType index = 0; index < SIZE; index++) { for (FwSizeType index = 0; index < SIZE; index++) {
status = buffer.deserializeTo((*this)[index]); status = buffer.deserializeTo((*this)[index], mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }

View File

@ -137,12 +137,14 @@ class AbsType :
//! Serialization //! Serialization
Fw::SerializeStatus serializeTo( Fw::SerializeStatus serializeTo(
Fw::SerializeBufferBase& buffer //!< The serial buffer Fw::SerializeBufferBase& buffer, //!< The serial buffer
Fw::Endianness mode = Fw::Endianness::BIG //!< Endianness of serialized buffer
) const; ) const;
//! Deserialization //! Deserialization
Fw::SerializeStatus deserializeFrom( Fw::SerializeStatus deserializeFrom(
Fw::SerializeBufferBase& buffer //!< The serial buffer Fw::SerializeBufferBase& buffer, //!< The serial buffer
Fw::Endianness mode = Fw::Endianness::BIG //!< Endianness of serialized buffer
); );
//! Get the dynamic serialized size of the array //! Get the dynamic serialized size of the array

View File

@ -87,8 +87,7 @@ AliasType& AliasType ::
AliasType& AliasType :: AliasType& AliasType ::
operator=(const std::initializer_list<ElementType>& il) operator=(const std::initializer_list<ElementType>& il)
{ {
// Since we are required to use C++11, this has to be a runtime check // Check that the initializer has the expected size
// In C++14, it can be a static check
FW_ASSERT(il.size() == SIZE, static_cast<FwAssertArgType>(il.size()), static_cast<FwAssertArgType>(SIZE)); FW_ASSERT(il.size() == SIZE, static_cast<FwAssertArgType>(il.size()), static_cast<FwAssertArgType>(SIZE));
FwSizeType i = 0; FwSizeType i = 0;
for (const auto& e : il) { for (const auto& e : il) {
@ -141,11 +140,14 @@ std::ostream& operator<<(std::ostream& os, const AliasType& obj) {
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
Fw::SerializeStatus AliasType :: Fw::SerializeStatus AliasType ::
serializeTo(Fw::SerializeBufferBase& buffer) const serializeTo(
Fw::SerializeBufferBase& buffer,
Fw::Endianness mode
) const
{ {
Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK; Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK;
for (FwSizeType index = 0; index < SIZE; index++) { for (FwSizeType index = 0; index < SIZE; index++) {
status = buffer.serializeFrom((*this)[index]); status = buffer.serializeFrom((*this)[index], mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }
@ -154,11 +156,14 @@ Fw::SerializeStatus AliasType ::
} }
Fw::SerializeStatus AliasType :: Fw::SerializeStatus AliasType ::
deserializeFrom(Fw::SerializeBufferBase& buffer) deserializeFrom(
Fw::SerializeBufferBase& buffer,
Fw::Endianness mode
)
{ {
Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK; Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK;
for (FwSizeType index = 0; index < SIZE; index++) { for (FwSizeType index = 0; index < SIZE; index++) {
status = buffer.deserializeTo((*this)[index]); status = buffer.deserializeTo((*this)[index], mode);
if (status != Fw::FW_SERIALIZE_OK) { if (status != Fw::FW_SERIALIZE_OK) {
return status; return status;
} }

View File

@ -137,12 +137,14 @@ class AliasType :
//! Serialization //! Serialization
Fw::SerializeStatus serializeTo( Fw::SerializeStatus serializeTo(
Fw::SerializeBufferBase& buffer //!< The serial buffer Fw::SerializeBufferBase& buffer, //!< The serial buffer
Fw::Endianness mode = Fw::Endianness::BIG //!< Endianness of serialized buffer
) const; ) const;
//! Deserialization //! Deserialization
Fw::SerializeStatus deserializeFrom( Fw::SerializeStatus deserializeFrom(
Fw::SerializeBufferBase& buffer //!< The serial buffer Fw::SerializeBufferBase& buffer, //!< The serial buffer
Fw::Endianness mode = Fw::Endianness::BIG //!< Endianness of serialized buffer
); );
//! Get the dynamic serialized size of the array //! Get the dynamic serialized size of the array

Some files were not shown because too many files have changed in this diff Show More