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

1
.gitignore vendored
View File

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

View File

@ -29,85 +29,13 @@ lazy val root = (project in file("."))
.settings(settings)
.aggregate(
lib,
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
fpp
)
lazy val lib = project
.settings(settings)
lazy val fpp_check = (project in file("tools/fpp-check"))
.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"))
lazy val fpp = (project in file("tools/fpp"))
.settings(settings)
.dependsOn(lib)
.enablePlugins(AssemblyPlugin)

View File

@ -51,21 +51,7 @@ dir=`cd $dir; pwd`
base=`basename $dest`
dest=$dir/$base
tools="
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
"
tools=`cat ./tools.txt`
if git describe --tags --always > /dev/null 2>&1
then
@ -91,13 +77,18 @@ sed -i.restore.bak -e "s/val v = .*/val v = \"[unknown version]\"/" \
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"
for tool in $tools
do
jar=`find tools/$tool -name "*$name*assembly*.jar" | grep "target/scala-$scala_version"`
echo " $jar"
cp $jar $dest/$tool.jar
echo '#!/bin/sh
'$java' -jar "`dirname $0`/'$tool'.jar" "$@"' > $dest/$tool
chmod +x $dest/$tool
'$java' -jar "`dirname $0`/'fpp'.jar" '$tool' "$@"' > $dest/fpp-$tool
chmod +x $dest/fpp-$tool
done

View File

@ -1,54 +1,6 @@
[
{
"name":"fpp.compiler.FPPFormat",
"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",
"name":"fpp.compiler.tools.FPP",
"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]]) = {
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 data = node1.data
for {
a <- visitList(a, data.params, formalParamNode)
a <- opt(exprNode)(a, data.id)
a <- opt(exprNode)(a, data.throttle)
a <- opt(eventThrottle)(a, data.throttle)
} yield a
}

View File

@ -282,10 +282,27 @@ object CheckExprTypes extends UseAnalyzer {
override def specEventAnnotatedNode(a: Analysis, aNode: Ast.Annotated[AstNode[Ast.SpecEvent]]) = {
val (_, node, _) = aNode
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 {
a <- super.specEventAnnotatedNode(a, aNode)
_ <- convertNodeToNumericOpt(a, data.id)
_ <- convertNodeToNumericOpt(a, data.throttle)
_ <- Result.mapOpt(data.throttle, checkThrottle(a))
}
yield a
}

View File

@ -14,14 +14,29 @@ object CheckInterfaceDefs
a: Analysis,
aNode: Ast.Annotated[AstNode[Ast.DefInterface]]
) = {
val a1 = a.copy(interface = Some(Interface(aNode)))
for {
a <- super.defInterfaceAnnotatedNode(a1, aNode)
}
yield {
val symbol = Symbol.Interface(aNode)
a.copy(interfaceMap = a.interfaceMap + (symbol -> a.interface.get))
val symbol = Symbol.Interface(aNode)
a.interfaceMap.get(symbol) match {
case None =>
// Interface is not in the map: visit it
val a1 = a.copy(interface = Some(Interface(aNode)))
for {
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(
@ -42,8 +57,8 @@ object CheckInterfaceDefs
val node = aNode._2
val ifaceNode = node.data.sym
for {
iface <- a.getInterface(ifaceNode.id)
i <- a.interface.get.addImportedInterface(
iface <- a.getInterfaceSymbol(ifaceNode.id)
i <- a.interface.get.addImportedInterfaceSymbol(
iface,
node.id,
)

View File

@ -49,6 +49,9 @@ object CheckUseDefCycles extends UseAnalyzer {
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) =
visitUse(a, node, use)
@ -71,6 +74,7 @@ object CheckUseDefCycles extends UseAnalyzer {
case Symbol.Constant(node) => defConstantAnnotatedNode(a, node)
case Symbol.Enum(node) => defEnumAnnotatedNode(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.Topology(node) => defTopologyAnnotatedNode(a, node)
case _ => Right(a)

View File

@ -7,7 +7,7 @@ import fpp.compiler.util._
final case class Event(
aNode: Ast.Annotated[AstNode[Ast.SpecEvent]],
format: Format,
throttle: Option[Int]
throttle: Option[Event.Throttle]
) {
/** Gets the name of the event */
@ -20,6 +20,16 @@ final case class Event(
object Event {
case class TimeInterval(
seconds: Long,
useconds: Int,
)
case class Throttle(
count: Int,
every: Option[TimeInterval]
)
type Id = BigInt
/** Creates a event from an event specifier */
@ -35,6 +45,45 @@ object Event {
)
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 {
_ <- checkRefParams(data.params)
_ <- a.checkDisplayableParams(data.params, "type of event is not displayable")
@ -42,7 +91,7 @@ object Event {
data.format,
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)
}

View File

@ -5,8 +5,10 @@ import fpp.compiler.util.*
/** An FPP interface */
case class Interface(
/** The AST node defining the component */
/** The AST node defining the interface */
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 */
portMap: Map[Name.Unqualified, PortInstance] = Map(),
/** The map from special port kinds to special port instances */
@ -19,4 +21,21 @@ case class Interface(
newSpecialPortMap: Map[Ast.SpecPortInstance.SpecialKind, PortInstance.Special]
): 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]]
)
final case class EventThrottle(
count: AstNode[Expr],
every: Option[AstNode[Expr]]
)
/** Event specifier */
final case class SpecEvent(
name: Ident,
@ -524,7 +529,7 @@ object Ast {
severity: SpecEvent.Severity,
id: Option[AstNode[Expr]],
format: AstNode[String],
throttle: Option[AstNode[Expr]]
throttle: Option[AstNode[EventThrottle]]
)
object SpecEvent {
/** Event severity */

View File

@ -428,6 +428,14 @@ object AstWriter extends AstVisitor with LineUtils {
) = {
val (_, node, _) = aNode
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") ++
List.concat(
ident(data.name),
@ -435,7 +443,7 @@ object AstWriter extends AstVisitor with LineUtils {
lines(s"severity ${data.severity.toString}"),
linesOpt(addPrefix("id", exprNode), data.id),
addPrefix("format", string) (data.format.data),
linesOpt(addPrefix("throttle", exprNode), data.throttle),
linesOpt(throttleClause, data.throttle)
).map(indentIn)
}

View File

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

View File

@ -510,21 +510,6 @@ case class ComponentCppWriter (
}
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(
"protected",
@ -541,7 +526,7 @@ case class ComponentCppWriter (
)
),
List(s"Fw::${kindStr}ComponentBase(compName)") :::
(if (hasExternalParameters) List("paramDelegatePtr(NULL)") else Nil) :::
(if (hasExternalParameters) List("paramDelegatePtr(nullptr)") else Nil) :::
smInstancesByName.map { (name, smi) =>
val sm = s.a.stateMachineMap(smi.symbol)
val hasActionsOrGuards = sm.hasActions || sm.hasGuards
@ -554,14 +539,12 @@ case class ComponentCppWriter (
},
intersperseBlankLines(
List(
intersperseBlankLines(
updateOnChangeChannels.map((_, channel) =>
writeChannelInit(channel)
)
),
throttledEvents.map((_, event) => line(
s"this->${eventThrottleCounterName(event.getName)} = 0;"
)),
throttledEventsWithTimeout.map((_, event) => line(
s"this->${eventThrottleTimeName(event.getName)} = Fw::Time();"
)),
sortedParams.flatMap((_, param) => guardedList(!param.isExternal) (
lines(s"this->${paramValidityFlagName(param.getName)} = Fw::ParamValid::UNINIT;")
))
@ -992,7 +975,7 @@ case class ComponentCppWriter (
}
private def getMutexVariableMembers: List[CppDoc.Class.Member] = {
if !(hasGuardedInputPorts || hasGuardedCommands || hasParameters) then Nil
if !(hasGuardedInputPorts || hasGuardedCommands || hasParameters || hasEventsWithTimeout) then Nil
else List(
linesClassMember(
List(
@ -1013,6 +996,13 @@ case class ComponentCppWriter (
|//! Mutex for locking parameters during sets and saves
|Os::Mutex m_paramLock;
|"""
),
if !hasEventsWithTimeout then Nil
else lines(
"""|
|//! Mutex for locking event throttle timeout and counter
|Os::Mutex m_eventLock;
|"""
)
).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 */
val sortedChannels: List[(TlmChannel.Id, TlmChannel)] = component.tlmChannelMap.toList.sortBy(_._1)
@ -319,6 +335,8 @@ abstract class ComponentCppWriterUtils(
val hasContainers: Boolean = containersByName != Nil
val hasEventsWithTimeout: Boolean = throttledEventsWithTimeout.nonEmpty
val hasExternalStateMachineInstances: Boolean =
component.hasStateMachineInstancesOfKind(StateMachine.Kind.External)
@ -815,6 +833,10 @@ abstract class ComponentCppWriterUtils(
def eventThrottleCounterName(name: String) =
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 */
def eventIdConstantName(name: String) =
s"EVENTID_${name.toUpperCase}"
@ -956,6 +978,12 @@ abstract class 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 ) **/
type ParamTypeMapInfo = (String, String, Type)
type CmdParamTypeMap = Map[Command.Opcode, List[ParamTypeMapInfo]]

View File

@ -21,7 +21,7 @@ case class ComponentEvents (
throttledEvents.flatMap((_, event) =>
writeEnumConstant(
eventThrottleConstantName(event.getName),
event.throttle.get,
event.throttle.get.count,
Some(s"Throttle reset count for ${event.getName}")
)
)
@ -60,12 +60,26 @@ case class ComponentEvents (
addAccessTagAndComment(
"private",
"Counter values for event throttling",
throttledEvents.map((_, event) =>
linesClassMember(
Line.blank :: lines(
s"""|//! Throttle for ${event.getName}
|std::atomic<FwIndexType> ${eventThrottleCounterName(event.getName)};
|"""
List.concat(
throttledEventsNoTimeout.map((_, event) =>
linesClassMember(
Line.blank :: lines(
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(
List(
// Hard throttle counter can be checked immediately
// We don't need to get time
event.throttle match {
case None => Nil
case Some(_) => lines(
case Some(Event.Throttle(_, None)) => lines(
s"""|// Check throttle value
|if (this->${eventThrottleCounterName(event.getName)} >= ${eventThrottleConstantName(event.getName)}) {
| return;
|}
|else {
| (void) this->${eventThrottleCounterName(event.getName)}.fetch_add(1);
| this->${eventThrottleCounterName(event.getName)}++;
|}
|"""
)
case _ => Nil
},
lines(
s"""|// Get the time
@ -271,6 +287,37 @@ case class ComponentEvents (
|_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),
writeTextLogBody(event)
)
@ -309,16 +356,40 @@ case class ComponentEvents (
addAccessTagAndComment(
"protected",
"Event throttle reset functions",
throttledEvents.map((_, event) =>
functionClassMember(
Some(s"Reset throttle value for ${event.getName}"),
eventThrottleResetName(event),
Nil,
CppDoc.Type("void"),
lines(
s"""|// Reset throttle counter
|this->${eventThrottleCounterName(event.getName)} = 0;
|"""
List.concat(
throttledEventsNoTimeout.map((_, event) =>
functionClassMember(
Some(s"Reset throttle value for ${event.getName}"),
eventThrottleResetName(event),
Nil,
CppDoc.Type("void"),
List(
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
|_id = ${paramIdConstantName(param.getName)};
|
|FW_ASSERT(this->paramDelegatePtr != NULL);
|FW_ASSERT(this->paramDelegatePtr != nullptr);
|// Call the delegate deserialize function for ${paramVariableName(param.getName)}
|_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
|const FwPrmIdType _localId = ${paramIdConstantName(param.getName)};
|
|FW_ASSERT(this->paramDelegatePtr != NULL);
|FW_ASSERT(this->paramDelegatePtr != nullptr);
|// Get the external parameter from the delegate
|Fw::SerializeStatus _stat = this->paramDelegatePtr->serializeParam(_baseId, _localId, _getBuff);
|if(_stat == Fw::FW_SERIALIZE_OK) {
@ -378,7 +378,7 @@ case class ComponentParameters (
s"""|const FwPrmIdType _localId = ${paramIdConstantName(param.getName)};
|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)}
|const Fw::SerializeStatus _stat = this->paramDelegatePtr->deserializeParam(
| _baseId,
@ -452,7 +452,7 @@ case class ComponentParameters (
|_id = ${paramIdConstantName(param.getName)};
|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);
|"""
)
@ -508,7 +508,7 @@ case class ComponentParameters (
),
CppDoc.Type("void"),
lines(
"""|FW_ASSERT(paramExternalDelegatePtr != NULL);
"""|FW_ASSERT(paramExternalDelegatePtr != nullptr);
|this->paramDelegatePtr = paramExternalDelegatePtr;
|"""
)

View File

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

View File

@ -36,7 +36,7 @@ case class ComponentTelemetry (
}
def getVariableMembers: List[CppDoc.Class.Member] = {
List(
List.concat(
addAccessTagAndComment(
"private",
"First update flags for telemetry channels",
@ -45,7 +45,7 @@ case class ComponentTelemetry (
lines(
s"""|
|//! 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(
s"""|
|//! Records the last emitted value for channel $channelName
|$channelType $channelStoreName;
|$channelType $channelStoreName = {};
|"""
)
)
}),
CppDoc.Lines.Hpp
)
).flatten
)
}
private def getWriteFunctions: List[CppDoc.Class.Member] = {

View File

@ -167,7 +167,7 @@ abstract class ComponentTestUtils(
def outputPortName(name: String) =
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) =
p.getDirection.get match {
case PortInstance.Direction.Input => outputPortName(p.getUnqualifiedName)

View File

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

View File

@ -316,12 +316,19 @@ case class EnumCppWriter(
CppDoc.Type("Fw::SerializeBufferBase&"),
"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"),
lines(
s"""|const Fw::SerializeStatus status = buffer.serializeFrom(
| static_cast<SerialType>(this->e)
| static_cast<SerialType>(this->e),
| mode
|);
|return status;"""
),
@ -336,12 +343,18 @@ case class EnumCppWriter(
CppDoc.Type("Fw::SerializeBufferBase&"),
"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"),
lines(
s"""|SerialType es;
|Fw::SerializeStatus status = buffer.deserializeTo(es);
|Fw::SerializeStatus status = buffer.deserializeTo(es, mode);
|if (status == Fw::FW_SERIALIZE_OK) {
| this->e = static_cast<T>(es);
| if (!this->isValid()) {

View File

@ -466,9 +466,9 @@ case class StructCppWriter(
lines("return status;")
)
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) =
line(s"status = buffer.deserializeTo(this->m_$n);") :: writeSerializeStatusCheck
line(s"status = buffer.deserializeTo(this->m_$n, mode);") :: writeSerializeStatusCheck
List(
List(
@ -487,6 +487,12 @@ case class StructCppWriter(
CppDoc.Type("Fw::SerializeBufferBase&"),
"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"),
@ -511,6 +517,12 @@ case class StructCppWriter(
CppDoc.Type("Fw::SerializeBufferBase&"),
"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"),

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 */
private implicit def channelLimitEncoder: Encoder[TlmChannel.Limits] = new Encoder[TlmChannel.Limits] {
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: Ast.QueueFull => Json.obj(key -> x.toString.asJson).deepMerge(json)
case x: Event.Throttle => Json.obj(key -> x.asJson).deepMerge(json)
}
case None => json
}

View File

@ -483,6 +483,11 @@ object FppWriter extends AstVisitor with LineUtils {
in: In,
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 data = node.data
val severity = data.severity.toString
@ -491,7 +496,7 @@ object FppWriter extends AstVisitor with LineUtils {
joinWithBreak ("severity ") (lines(severity)).
joinOptWithBreak (data.id) ("id ") (exprNode).
joinWithBreak ("format ") (string(data.format.data)).
joinOptWithBreak (data.throttle) ("throttle ") (exprNode)
joinOptWithBreak (data.throttle) ("") (eventThrottle)
}
override def specIncludeAnnotatedNode(

View File

@ -28,6 +28,10 @@ object AstJsonEncoder extends JsonEncoder {
implicit val exprEncoder: Encoder[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
implicit val moduleMemberNodeEncoder: Encoder[Ast.ModuleMember.Node] =
io.circe.generic.semiauto.deriveEncoder[Ast.ModuleMember.Node]

View File

@ -315,7 +315,11 @@ object ComponentXmlFppWriter extends LineUtils {
severity,
id,
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 memberNode = Ast.ComponentMember.SpecEvent(node)

View File

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

View File

@ -620,10 +620,16 @@ object Parser extends Parsers {
failure("severity level expected")
}
def throttleClause = {
(throttle ~>! exprNode) ~! opt(every ~>! exprNode) ^^ {
case throttle ~ duration => Ast.EventThrottle(throttle, duration)
}
}
(event ~> ident) ~! formalParamList ~! (severity ~>! severityLevel) ~!
opt(id ~>! exprNode) ~!
(format ~>! node(literalString)) ~!
opt(throttle ~>! exprNode) ^^ {
opt(node(throttleClause)) ^^ {
case 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 every = accept("every", { case t: Token.EVERY => t })
private def exit = accept("exit", { case t: Token.EXIT => 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 EQUALS() extends Token
final case class EVENT() extends Token
final case class EVERY() extends Token
final case class EXIT() extends Token
final case class EXTERNAL() extends Token
final case class F32() extends Token
@ -186,6 +187,7 @@ enum TokenId {
case ENTRY
case ENUM
case EVENT
case EVERY
case EXIT
case EXTERNAL
case F32

View File

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

View File

@ -16,7 +16,7 @@ object Result {
/** Left fold with a function that returns a result */
@tailrec
def foldLeft[A,B]
def foldLeft[A, B]
(as: List[A])
(b: 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 (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 every {seconds=10,useconds=11}",
)
)
}

View File

@ -25,10 +25,13 @@ evalp()
# Get tool names from a directory
get_tool_names()
{
prefix="fpp-"
dir=$1
for file in $dir/*.jar
for file in $dir/$prefix*
do
basename $file .jar
base=`basename $file`
result="${base#$prefix}"
echo $result
done
}
@ -86,26 +89,30 @@ print_phase "Constructing binary tools in $native_bin"
# Get the tool names from 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
for tool_name in $tool_names
for tool in $tool_names
do
jar_file="bin/$tool_name.jar"
out_file="$native_bin/$tool_name"
echo "Building $out_file"
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
echo '#!/bin/sh
"`dirname $0`/fpp" '$tool' "$@"' > $native_bin/fpp-$tool
chmod +x $native_bin/fpp-$tool
done
sync; sync; sync;

View File

@ -40,7 +40,6 @@ os=`uname`
case "$os" in
Darwin)
os_type=DARWIN
#os_flags='-ferror-limit=1'
;;
Linux)
os_type=LINUX
@ -51,7 +50,7 @@ case "$os" in
;;
esac
g++ --std=c++11 \
g++ --std=c++14 \
$flags \
$os_flags \
-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 {}" \
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="
bad_id
bad_throttle_interval_extra_member
bad_throttle_interval_seconds
bad_throttle_interval_useconds
bad_throttle_interval
bad_throttle_seconds
bad_throttle
duplicate_id_explicit
duplicate_id_implicit
@ -15,4 +20,5 @@ not_displayable
ok
ref_params
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()
interface I1 {
import I2
}
interface I2 {
}
module Fw {
port Cmd
port CmdReg
@ -27,4 +34,9 @@ interface I {
active component C {
import Cmd
import I
import I3
}
interface I3 {
async input port pAsync2: P
}

View File

@ -1,6 +1,8 @@
tests="
async_port_in_passive
conflict_name
cycles
duplicate_import
duplicate_name
empty_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 constant a at "a.fpp"
locate constant b at "b.fpp"
locate constant c at "c.fpp"
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/a.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" \
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 I(
a: U32

View File

@ -124,6 +124,18 @@ module DefinitionsAndSpecifiers {
format "{} counts" \
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 I(
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 }
type T
state machine S
constant t = {seconds=10,useconds=20}
module M {
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 record_id 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_id 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 record_id 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_id 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 C1_S_use: 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 {

View File

@ -13,6 +13,7 @@ locate constant product_recv_priority at "../defs.fpp"
locate constant queue_size_def at "../defs.fpp"
locate constant record_id 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_id 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
throttle literal int 10
@< 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
spec internal port
ident I

View File

@ -207,6 +207,26 @@ def module
format {} counts
throttle literal int 10
@< 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
spec internal port
ident I

View File

@ -207,6 +207,26 @@ def module
format {} counts
throttle literal int 10
@< 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
spec internal port
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 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 I(a: U32, b: F32) priority 10 assert
@< 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
!*/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 ::
serializeTo(Fw::SerializeBufferBase& buffer) const
serializeTo(
Fw::SerializeBufferBase& buffer,
Fw::Endianness mode
) const
{
Fw::SerializeStatus status;
status = buffer.serializeFrom(this->m_A);
status = buffer.serializeFrom(this->m_A, mode);
if (status != Fw::FW_SERIALIZE_OK) {
return status;
}
@ -91,11 +94,14 @@ Fw::SerializeStatus Abs ::
}
Fw::SerializeStatus Abs ::
deserializeFrom(Fw::SerializeBufferBase& buffer)
deserializeFrom(
Fw::SerializeBufferBase& buffer,
Fw::Endianness mode
)
{
Fw::SerializeStatus status;
status = buffer.deserializeTo(this->m_A);
status = buffer.deserializeTo(this->m_A, mode);
if (status != Fw::FW_SERIALIZE_OK) {
return status;
}

View File

@ -85,12 +85,14 @@ class Abs :
//! Serialization
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;
//! Deserialization
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

View File

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

View File

@ -96,12 +96,14 @@ class Basic :
//! Serialization
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;
//! Deserialization
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

View File

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

View File

@ -96,12 +96,14 @@ class Namespace :
//! Serialization
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;
//! Deserialization
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

View File

@ -11,6 +11,7 @@ struct T : public Fw::Serializable { // Extend Fw::Serializable
// Define some shorthand for F Prime types
typedef Fw::SerializeStatus SS;
typedef Fw::SerializeBufferBase B;
typedef Fw::Endianness E;
// Define the constant SERIALIZED_SIZE
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; }
// 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
SS deserializeFrom(B& b) { return b.deserializeTo(x); }
SS deserializeFrom(B& b, E e) { return b.deserializeTo(x, e); }
// Provide some data
U32 x;

View File

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

View File

@ -136,12 +136,14 @@ class A :
//! Serialization
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;
//! Deserialization
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

View File

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

View File

@ -137,12 +137,14 @@ class AbsType :
//! Serialization
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;
//! Deserialization
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

View File

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

View File

@ -137,12 +137,14 @@ class AliasType :
//! Serialization
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;
//! Deserialization
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

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