diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..7ad9489e25 --- /dev/null +++ b/.clang-format @@ -0,0 +1,5 @@ +--- +BasedOnStyle: Chromium +IndentWidth: 4 +ColumnLimit: 120 +AccessModifierOffset: -2 \ No newline at end of file diff --git a/.github/actions/autodoc.bash b/.github/actions/autodoc.bash index 1916638c9d..e5a496e591 100755 --- a/.github/actions/autodoc.bash +++ b/.github/actions/autodoc.bash @@ -11,7 +11,7 @@ git config --local user.name "nasa-fprime[bot]" git fetch "${REMOTE}" release/documentation git fetch "${REMOTE}" devel git checkout release/documentation -git merge "${REMOTE}"/devel +GIT_EDITOR=true git merge "${REMOTE}"/devel ${GITHUB_WORKSPACE}/docs/doxygen/generate_docs.bash git add -Af "${GITHUB_WORKSPACE}/docs" diff --git a/.github/actions/codeql/jpl-standard-pack-1.yml b/.github/actions/codeql/jpl-standard-pack-1.yml new file mode 100644 index 0000000000..bff4722654 --- /dev/null +++ b/.github/actions/codeql/jpl-standard-pack-1.yml @@ -0,0 +1,12 @@ +name: "CodeQL JPL Coding Standard - Errors and Warnings" + +disable-default-queries: true + +packs: + # Source of the query pack is https://github.com/github/codeql/tree/main/cpp/ql/src/JPL_C + - codeql/cpp-queries:JPL_C + +query-filters: + - exclude: + problem.severity: + - recommendation diff --git a/.github/actions/codeql/jpl-standard-pack-2.yml b/.github/actions/codeql/jpl-standard-pack-2.yml new file mode 100644 index 0000000000..61b0e53dc4 --- /dev/null +++ b/.github/actions/codeql/jpl-standard-pack-2.yml @@ -0,0 +1,20 @@ +name: "CodeQL JPL Coding Standard - Recommendations 1 of 2" + +disable-default-queries: true + +packs: + # Source of the query pack is https://github.com/github/codeql/tree/main/cpp/ql/src/JPL_C + - codeql/cpp-queries:JPL_C + +query-filters: + - exclude: + problem.severity: + - error + - warning + # We are excluding the following query because it overflows the limit of + # 5000 results that the SARIF upload can handle + # This sole query is ran in jpl-standard-pack-3.yml + # https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github#uploading-a-code-scanning-analysis-with-github-actions + - exclude: + id: + - cpp/jpl-c/basic-int-types diff --git a/.github/actions/codeql/jpl-standard-pack-3.yml b/.github/actions/codeql/jpl-standard-pack-3.yml new file mode 100644 index 0000000000..2b56eb507d --- /dev/null +++ b/.github/actions/codeql/jpl-standard-pack-3.yml @@ -0,0 +1,13 @@ +name: "CodeQL JPL Coding Standard - Recommendations 2 of 2" + +disable-default-queries: true + +packs: + # Source of the query pack is https://github.com/github/codeql/tree/main/cpp/ql/src/JPL_C + - codeql/cpp-queries:JPL_C + +query-filters: + # This will ONLY include the following query + - include: + id: + - cpp/jpl-c/basic-int-types diff --git a/.github/actions/codeql/security-pack.yml b/.github/actions/codeql/security-pack.yml new file mode 100644 index 0000000000..1c9e6d08f4 --- /dev/null +++ b/.github/actions/codeql/security-pack.yml @@ -0,0 +1,19 @@ +name: "CodeQL security and quality" + +queries: + - uses: security-and-quality + +query-filters: + - include: + id: cpp/incorrect-not-operator-usage + - include: + tags contain: correctness + - include: + tags contain: reliability + +paths-ignore: + - docs/ + - cmake/docs/ + - cmake/test/ + - Autocoders/Python/src/fprime_ac/utils/DiffAndRename.py + - Autocoders/Python/src/fprime_ac/utils/pyparsing.py diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index b2869a0ac3..af35e60fb4 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -9,7 +9,17 @@ runs: steps: - run: git fetch --tags shell: bash - - run: pip3 install setuptools_scm urllib3 + - name: Add Python bin to PATH + run: echo "/Library/Frameworks/Python.framework/Versions/Current/bin" >> $GITHUB_PATH + shell: bash + - run: pip3 install setuptools_scm wheel urllib3 shell: bash - run: pip3 install -r ${{ inputs.location }}/requirements.txt shell: bash + - run: which fprime-util + shell: bash + - run: which fprime-gds + shell: bash + - run: which fpp-check + shell: bash + diff --git a/.github/actions/spelling/README.md b/.github/actions/spelling/README.md index ca5ca67d08..8dd5e9f88d 100644 --- a/.github/actions/spelling/README.md +++ b/.github/actions/spelling/README.md @@ -7,6 +7,7 @@ File | Purpose | Format | Info [excludes.txt](excludes.txt) | Files to ignore entirely | perl regular expression | [excludes](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-excludes) [only.txt](only.txt) | Only check matching files (applied after excludes) | perl regular expression | [only](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-only) [patterns.txt](patterns.txt) | Patterns to ignore from checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns) +[candidate.patterns](candidate.patterns) | Patterns that might be worth adding to [patterns.txt](patterns.txt) | perl regular expression with optional comment block introductions (all matches will be suggested) | [candidates](https://github.com/check-spelling/check-spelling/wiki/Feature:-Suggest-patterns) [line_forbidden.patterns](line_forbidden.patterns) | Patterns to flag in checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns) [expect.txt](expect.txt) | Expected words that aren't in the dictionary | one word per line (sorted, alphabetically) | [expect](https://github.com/check-spelling/check-spelling/wiki/Configuration#expect) [advice.md](advice.md) | Supplement for GitHub comment when unrecognized words are found | GitHub Markdown | [advice](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice) diff --git a/.github/actions/spelling/advice.md b/.github/actions/spelling/advice.md index 54f0c9b5e5..1004eeaa60 100644 --- a/.github/actions/spelling/advice.md +++ b/.github/actions/spelling/advice.md @@ -1,5 +1,5 @@ -
If the flagged items are false positives +
If the flagged items are :exploding_head: false positives If items relate to a ... * binary file (or some other file you wouldn't want to check at all). diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index e69de29bb2..f008fff9df 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -0,0 +1,6 @@ +github +https +ssh +ubuntu +workaround +workarounds diff --git a/.github/actions/spelling/candidate.patterns b/.github/actions/spelling/candidate.patterns new file mode 100644 index 0000000000..91d1e8a8f1 --- /dev/null +++ b/.github/actions/spelling/candidate.patterns @@ -0,0 +1,527 @@ +# marker to ignore all code on line +^.*/\* #no-spell-check-line \*/.*$ +# marker to ignore all code on line +^.*\bno-spell-check(?:-line|)(?:\s.*|)$ + +# https://cspell.org/configuration/document-settings/ +# cspell inline +^.*\b[Cc][Ss][Pp][Ee][Ll]{2}:\s*[Dd][Ii][Ss][Aa][Bb][Ll][Ee]-[Ll][Ii][Nn][Ee]\b + +# patch hunk comments +^\@\@ -\d+(?:,\d+|) \+\d+(?:,\d+|) \@\@ .* +# git index header +index [0-9a-z]{7,40}\.\.[0-9a-z]{7,40} + +# cid urls +(['"])cid:.*?\g{-1} + +# data url in parens +\(data:[^)]*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})[^)]*\) +# data url in quotes +([`'"])data:.*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1} +# data url +data:[-a-zA-Z=;:/0-9+]*,\S* + +# https/http/file urls +#(?:\b(?:https?|ftp|file)://)[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|] + +# mailto urls +mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,} + +# magnet urls +magnet:[?=:\w]+ + +# magnet urls +"magnet:[^"]+" + +# obs: +"obs:[^"]*" + +# The `\b` here means a break, it's the fancy way to handle urls, but it makes things harder to read +# In this examples content, I'm using a number of different ways to match things to show various approaches +# asciinema +\basciinema\.org/a/[0-9a-zA-Z]+ + +# apple +\bdeveloper\.apple\.com/[-\w?=/]+ +# Apple music +\bembed\.music\.apple\.com/fr/playlist/usr-share/[-\w.]+ + +# appveyor api +\bci\.appveyor\.com/api/projects/status/[0-9a-z]+ +# appveyor project +\bci\.appveyor\.com/project/(?:[^/\s"]*/){2}builds?/\d+/job/[0-9a-z]+ + +# Amazon + +# Amazon +\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|) +# AWS S3 +\b\w*\.s3[^.]*\.amazonaws\.com/[-\w/&#%_?:=]* +# AWS execute-api +\b[0-9a-z]{10}\.execute-api\.[-0-9a-z]+\.amazonaws\.com\b +# AWS ELB +\b\w+\.[-0-9a-z]+\.elb\.amazonaws\.com\b +# AWS SNS +\bsns\.[-0-9a-z]+.amazonaws\.com/[-\w/&#%_?:=]* +# AWS VPC +vpc-\w+ + +# While you could try to match `http://` and `https://` by using `s?` in `https?://`, sometimes there +# YouTube url +\b(?:(?:www\.|)youtube\.com|youtu.be)/(?:channel/|embed/|user/|playlist\?list=|watch\?v=|v/|)[-a-zA-Z0-9?&=_%]* +# YouTube music +\bmusic\.youtube\.com/youtubei/v1/browse(?:[?&]\w+=[-a-zA-Z0-9?&=_]*) +# YouTube tag +<\s*youtube\s+id=['"][-a-zA-Z0-9?_]*['"] +# YouTube image +\bimg\.youtube\.com/vi/[-a-zA-Z0-9?&=_]* +# Google Accounts +\baccounts.google.com/[-_/?=.:;+%&0-9a-zA-Z]* +# Google Analytics +\bgoogle-analytics\.com/collect.[-0-9a-zA-Z?%=&_.~]* +# Google APIs +\bgoogleapis\.(?:com|dev)/[a-z]+/(?:v\d+/|)[a-z]+/[-@:./?=\w+|&]+ +# Google Storage +\b[-a-zA-Z0-9.]*\bstorage\d*\.googleapis\.com(?:/\S*|) +# Google Calendar +\bcalendar\.google\.com/calendar(?:/u/\d+|)/embed\?src=[@./?=\w&%]+ +\w+\@group\.calendar\.google\.com\b +# Google DataStudio +\bdatastudio\.google\.com/(?:(?:c/|)u/\d+/|)(?:embed/|)(?:open|reporting|datasources|s)/[-0-9a-zA-Z]+(?:/page/[-0-9a-zA-Z]+|) +# The leading `/` here is as opposed to the `\b` above +# ... a short way to match `https://` or `http://` since most urls have one of those prefixes +# Google Docs +/docs\.google\.com/[a-z]+/(?:ccc\?key=\w+|(?:u/\d+|d/(?:e/|)[0-9a-zA-Z_-]+/)?(?:edit\?[-\w=#.]*|/\?[\w=&]*|)) +# Google Drive +\bdrive\.google\.com/(?:file/d/|open)[-0-9a-zA-Z_?=]* +# Google Groups +\bgroups\.google\.com/(?:(?:forum/#!|d/)(?:msg|topics?|searchin)|a)/[^/\s"]+/[-a-zA-Z0-9$]+(?:/[-a-zA-Z0-9]+)* +# Google Maps +\bmaps\.google\.com/maps\?[\w&;=]* +# Google themes +themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+. +# Google CDN +\bclients2\.google(?:usercontent|)\.com[-0-9a-zA-Z/.]* +# Goo.gl +/goo\.gl/[a-zA-Z0-9]+ +# Google Chrome Store +\bchrome\.google\.com/webstore/detail/[-\w]*(?:/\w*|) +# Google Books +\bgoogle\.(?:\w{2,4})/books(?:/\w+)*\?[-\w\d=&#.]* +# Google Fonts +\bfonts\.(?:googleapis|gstatic)\.com/[-/?=:;+&0-9a-zA-Z]* +# Google Forms +\bforms\.gle/\w+ +# Google Scholar +\bscholar\.google\.com/citations\?user=[A-Za-z0-9_]+ +# Google Colab Research Drive +\bcolab\.research\.google\.com/drive/[-0-9a-zA-Z_?=]* + +# GitHub SHAs (api) +\bapi.github\.com/repos(?:/[^/\s"]+){3}/[0-9a-f]+\b +# GitHub SHAs (markdown) +(?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|) +# GitHub SHAs +\bgithub\.com(?:/[^/\s"]+){2}[@#][0-9a-f]+\b +# GitHub wiki +\bgithub\.com/(?:[^/]+/){2}wiki/(?:(?:[^/]+/|)_history|[^/]+(?:/_compare|)/[0-9a-f.]{40,})\b +# githubusercontent +/[-a-z0-9]+\.githubusercontent\.com/[-a-zA-Z0-9?&=_\/.]* +# githubassets +\bgithubassets.com/[0-9a-f]+(?:[-/\w.]+) +# gist github +\bgist\.github\.com/[^/\s"]+/[0-9a-f]+ +# git.io +\bgit\.io/[0-9a-zA-Z]+ +# GitHub JSON +"node_id": "[-a-zA-Z=;:/0-9+]*" +# Contributor +\[[^\]]+\]\(https://github\.com/[^/\s"]+\) +# GHSA +GHSA(?:-[0-9a-z]{4}){3} + +# GitLab commit +\bgitlab\.[^/\s"]*/\S+/\S+/commit/[0-9a-f]{7,16}#[0-9a-f]{40}\b +# GitLab merge requests +\bgitlab\.[^/\s"]*/\S+/\S+/-/merge_requests/\d+/diffs#[0-9a-f]{40}\b +# GitLab uploads +\bgitlab\.[^/\s"]*/uploads/[-a-zA-Z=;:/0-9+]* +# GitLab commits +\bgitlab\.[^/\s"]*/(?:[^/\s"]+/){2}commits?/[0-9a-f]+\b + +# binanace +accounts.binance.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]* + +# bitbucket diff +\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}diff(?:stat|)(?:/[^/\s"]+){2}:[0-9a-f]+ +# bitbucket repositories commits +\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}commits?/[0-9a-f]+ +# bitbucket commits +\bbitbucket\.org/(?:[^/\s"]+/){2}commits?/[0-9a-f]+ + +# bit.ly +\bbit\.ly/\w+ + +# bitrise +\bapp\.bitrise\.io/app/[0-9a-f]*/[\w.?=&]* + +# bootstrapcdn.com +\bbootstrapcdn\.com/[-./\w]+ + +# cdn.cloudflare.com +\bcdnjs\.cloudflare\.com/[./\w]+ + +# circleci +\bcircleci\.com/gh(?:/[^/\s"]+){1,5}.[a-z]+\?[-0-9a-zA-Z=&]+ + +# gitter +\bgitter\.im(?:/[^/\s"]+){2}\?at=[0-9a-f]+ + +# gravatar +\bgravatar\.com/avatar/[0-9a-f]+ + +# ibm +[a-z.]*ibm\.com/[-_#=:%!?~.\\/\d\w]* + +# imgur +\bimgur\.com/[^.]+ + +# Internet Archive +\barchive\.org/web/\d+/(?:[-\w.?,'/\\+&%$#_:]*) + +# discord +/discord(?:app\.com|\.gg)/(?:invite/)?[a-zA-Z0-9]{7,} + +# Disqus +\bdisqus\.com/[-\w/%.()!?&=_]* + +# medium link +\blink\.medium\.com/[a-zA-Z0-9]+ +# medium +\bmedium\.com/\@?[^/\s"]+/[-\w]+ + +# microsoft +\b(?:https?://|)(?:(?:download\.visualstudio|docs|msdn2?|research)\.microsoft|blogs\.msdn)\.com/[-_a-zA-Z0-9()=./%]* +# powerbi +\bapp\.powerbi\.com/reportEmbed/[^"' ]* +# vs devops +\bvisualstudio.com(?::443|)/[-\w/?=%&.]* +# microsoft store +\bmicrosoft\.com/store/apps/\w+ + +# mvnrepository.com +\bmvnrepository\.com/[-0-9a-z./]+ + +# now.sh +/[0-9a-z-.]+\.now\.sh\b + +# oracle +\bdocs\.oracle\.com/[-0-9a-zA-Z./_?#&=]* + +# chromatic.com +/\S+.chromatic.com\S*[")] + +# codacy +\bapi\.codacy\.com/project/badge/Grade/[0-9a-f]+ + +# compai +\bcompai\.pub/v1/png/[0-9a-f]+ + +# mailgun api +\.api\.mailgun\.net/v3/domains/[0-9a-z]+\.mailgun.org/messages/[0-9a-zA-Z=@]* +# mailgun +\b[0-9a-z]+.mailgun.org + +# /message-id/ +/message-id/[-\w@./%]+ + +# Reddit +\breddit\.com/r/[/\w_]* + +# requestb.in +\brequestb\.in/[0-9a-z]+ + +# sched +\b[a-z0-9]+\.sched\.com\b + +# Slack url +slack://[a-zA-Z0-9?&=]+ +# Slack +\bslack\.com/[-0-9a-zA-Z/_~?&=.]* +# Slack edge +\bslack-edge\.com/[-a-zA-Z0-9?&=%./]+ +# Slack images +\bslack-imgs\.com/[-a-zA-Z0-9?&=%.]+ + +# shields.io +\bshields\.io/[-\w/%?=&.:+;,]* + +# stackexchange -- https://stackexchange.com/feeds/sites +\b(?:askubuntu|serverfault|stack(?:exchange|overflow)|superuser).com/(?:questions/\w+/[-\w]+|a/) + +# Sentry +[0-9a-f]{32}\@o\d+\.ingest\.sentry\.io\b + +# Twitter markdown +\[\@[^[/\]:]*?\]\(https://twitter.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)\) +# Twitter hashtag +\btwitter\.com/hashtag/[\w?_=&]* +# Twitter status +\btwitter\.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|) +# Twitter profile images +\btwimg\.com/profile_images/[_\w./]* +# Twitter media +\btwimg\.com/media/[-_\w./?=]* +# Twitter link shortened +\bt\.co/\w+ + +# facebook +\bfburl\.com/[0-9a-z_]+ +# facebook CDN +\bfbcdn\.net/[\w/.,]* +# facebook watch +\bfb\.watch/[0-9A-Za-z]+ + +# dropbox +\bdropbox\.com/sh?/[^/\s"]+/[-0-9A-Za-z_.%?=&;]+ + +# ipfs protocol +ipfs://[0-9a-z]* +# ipfs url +/ipfs/[0-9a-z]* + +# w3 +\bw3\.org/[-0-9a-zA-Z/#.]+ + +# loom +\bloom\.com/embed/[0-9a-f]+ + +# regex101 +\bregex101\.com/r/[^/\s"]+/\d+ + +# figma +\bfigma\.com/file(?:/[0-9a-zA-Z]+/)+ + +# freecodecamp.org +\bfreecodecamp\.org/[-\w/.]+ + +# image.tmdb.org +\bimage\.tmdb\.org/[/\w.]+ + +# mermaid +\bmermaid\.ink/img/[-\w]+|\bmermaid-js\.github\.io/mermaid-live-editor/#/edit/[-\w]+ + +# Wikipedia +\ben\.wikipedia\.org/wiki/[-\w%.#]+ + +# gitweb +[^"\s]+/gitweb/\S+;h=[0-9a-f]+ + +# HyperKitty lists +/archives/list/[^@/]+\@[^/\s"]*/message/[^/\s"]*/ + +# lists +/thread\.html/[^"\s]+ + +# list-management +\blist-manage\.com/subscribe(?:[?&](?:u|id)=[0-9a-f]+)+ + +# kubectl.kubernetes.io/last-applied-configuration +"kubectl.kubernetes.io/last-applied-configuration": ".*" + +# pgp +\bgnupg\.net/pks/lookup[?&=0-9a-zA-Z]* + +# Spotify +\bopen\.spotify\.com/embed/playlist/\w+ + +# Mastodon +\bmastodon\.[-a-z.]*/(?:media/|\@)[?&=0-9a-zA-Z_]* + +# scastie +\bscastie\.scala-lang\.org/[^/]+/\w+ + +# images.unsplash.com +\bimages\.unsplash\.com/(?:(?:flagged|reserve)/|)[-\w./%?=%&.;]+ + +# pastebin +\bpastebin\.com/[\w/]+ + +# heroku +\b\w+\.heroku\.com/source/archive/\w+ + +# quip +\b\w+\.quip\.com/\w+(?:(?:#|/issues/)\w+)? + +# badgen.net +\bbadgen\.net/badge/[^")\]'\s]+ + +# statuspage.io +\w+\.statuspage\.io\b + +# media.giphy.com +\bmedia\.giphy\.com/media/[^/]+/[\w.?&=]+ + +# tinyurl +\btinyurl\.com/\w+ + +# getopts +\bgetopts\s+(?:"[^"]+"|'[^']+') + +# ANSI color codes +(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m + +# URL escaped characters +\%[0-9A-F][A-F] +# IPv6 +\b(?:[0-9a-fA-F]{0,4}:){3,7}[0-9a-fA-F]{0,4}\b +# c99 hex digits (not the full format, just one I've seen) +0x[0-9a-fA-F](?:\.[0-9a-fA-F]*|)[pP] +# Punycode +\bxn--[-0-9a-z]+ +# sha +sha\d+:[0-9]*[a-f]{3,}[0-9a-f]* +# sha-... -- uses a fancy capture +(['"]|")[0-9a-f]{40,}\g{-1} +# hex runs +\b[0-9a-fA-F]{16,}\b +# hex in url queries +=[0-9a-fA-F]*?(?:[A-F]{3,}|[a-f]{3,})[0-9a-fA-F]*?& +# ssh +(?:ssh-\S+|-nistp256) [-a-zA-Z=;:/0-9+]{12,} + +# PGP +\b(?:[0-9A-F]{4} ){9}[0-9A-F]{4}\b +# GPG keys +\b(?:[0-9A-F]{4} ){5}(?: [0-9A-F]{4}){5}\b +# Well known gpg keys +.well-known/openpgpkey/[\w./]+ + +# uuid: +\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b +# hex digits including css/html color classes: +(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|u\d+)\b +# integrity +integrity="sha\d+-[-a-zA-Z=;:/0-9+]{40,}" + +# https://www.gnu.org/software/groff/manual/groff.html +# man troff content +\\f[BCIPR] +# ' +\\\(aq + +# .desktop mime types +^MimeTypes?=.*$ +# .desktop localized entries +^[A-Z][a-z]+\[[a-z]+\]=.*$ +# Localized .desktop content +Name\[[^\]]+\]=.* + +# IServiceProvider +\bI(?=(?:[A-Z][a-z]{2,})+\b) + +# crypt +"\$2[ayb]\$.{56}" + +# scrypt / argon +\$(?:scrypt|argon\d+[di]*)\$\S+ + +# Input to GitHub JSON +content: "[-a-zA-Z=;:/0-9+]*=" + +# Python stringprefix / binaryprefix +# Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings +(?v# +(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_])) +# Compiler flags (Scala) +(?:^|[\t ,>"'`=(])-J-[DPWXY](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}) +# Compiler flags +(?:^|[\t ,"'`=(])-[DPWXYLlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}) +# Compiler flags (linker) +,-B +# curl arguments +\b(?:\\n|)curl(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)* +# set arguments +\bset(?:\s+-[abefimouxE]{1,2})*\s+-[abefimouxE]{3,}(?:\s+-[abefimouxE]+)* +# tar arguments +\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+ +# tput arguments -- https://man7.org/linux/man-pages/man5/terminfo.5.html -- technically they can be more than 5 chars long... +\btput\s+(?:(?:-[SV]|-T\s*\w+)\s+)*\w{3,5}\b +# macOS temp folders +/var/folders/\w\w/[+\w]+/(?:T|-Caches-)/ diff --git a/.github/actions/spelling/excludes.txt b/.github/actions/spelling/excludes.txt index 1200e9ad0c..d3d2a1a562 100644 --- a/.github/actions/spelling/excludes.txt +++ b/.github/actions/spelling/excludes.txt @@ -1,26 +1,37 @@ # See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-excludes (?:^|/)(?i)COPYRIGHT (?:^|/)(?i)LICEN[CS]E +(?:^|/)3rdparty/ (?:^|/)go\.sum$ (?:^|/)package(?:-lock|)\.json$ +(?:^|/)pyproject.toml +(?:^|/)requirements(?:-dev|-doc|-test|)\.txt$ (?:^|/)vendor/ /doc/xml/ /html/ /third-party/ +/__init__\.py$ ignore$ +\.a$ \.ai$ \.avi$ \.bak$ \.bin$ \.bmp$ \.bz2$ +\.class$ +\.coveragerc$ \.crt$ \.dat$ +\.dll$ \.doc$ \.docx$ +\.drawio$ \.DS_Store$ \.eot$ +\.exe$ \.gif$ +\.git-blame-ignore-revs$ \.gitattributes$ \.graffle$ \.gz$ @@ -28,8 +39,10 @@ ignore$ \.ico$ \.inv$ \.jar$ +\.jks$ \.jpe?g$ \.key$ +\.lib$ \.lock$ \.log$ \.map$ @@ -38,6 +51,7 @@ ignore$ \.min\.. \.mod$ \.mp[34]$ +\.o$ \.ocf$ \.otf$ \.pdf$ @@ -45,17 +59,23 @@ ignore$ \.png$ \.pptx$ \.psd$ +\.pyc$ +\.pylintrc$ \.rtf$ +\.s$ \.ser$ \.sty$ \.svg$ +\.svgz?$ +\.tar$ \.tex$ +\.tiff?$ \.ttf$ \.vm$ \.vsdx$ \.wav$ -\.woff$ -\.woff2$ +\.webm$ +\.webp$ \.woff2?$ \.xls$ \.xlsx$ @@ -77,12 +97,22 @@ ignore$ ^Svc/TlmChan/TlmChan\.hpp$ ^\.github/actions/spelling/ ^\Q.github/workflows/spelling.yml\E$ +^\QAutocoders/Python/doc/tlmLayout/LayoutExampleTlmLayoutAi.csv\E$ +^\QAutocoders/Python/src/fprime_ac/generators/templates/serialize/includes1SerialH.tmpl\E$ +^\QAutocoders/Python/test/command_multi_inst/docs/Test1.md\E$ +^\QAutocoders/Python/test/event_multi_inst/docs/TestLog.md\E$ +^\QAutocoders/Python/test/tlm_multi_inst/docs/TestTlm.md\E$ +^\Qcmake/platform/README.md\E$ +^\Qdocs/Tutorials/FullSystemTutorial/Tutorial.md\E$ ^\QDrv/BlockDriver/BlockDriver.hpp\E$ ^\QDrv/LinuxGpioDriver/LinuxGpioDriver.hpp\E$ ^\QDrv/LinuxSpiDriver/LinuxSpiDriver.hpp\E$ ^\QDrv/TcpClient/TcpClient.hpp\E$ ^\QFw/Types/Linux/StandardTypes.hpp\E$ +^\QRef/SignalGen/check.xml\E$ ^\Qrequirements.txt\E$ +^\QSTest/README.md\E$ +^\QSvc/FileDownlink/check.xml\E$ ^\QSvc/LinuxTime/LinuxTime.hpp\E$ ^\QSvc/PrmDb/PrmDb.hpp\E$ ^\QSvc/TlmChan/TlmChan.hpp\E$ diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 8df0f29c10..951b41dfaa 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -5,7 +5,6 @@ ABCDEF abcdefghijklmnopqrstuvwxyz ablack abspath -ABuffer acconstantsini accurev AClass @@ -43,11 +42,11 @@ APIDOCS aports apos APPENDFILE -apps aps apxs AQuat AQueued +arcsecond arduino argc argcomplete @@ -55,16 +54,12 @@ argcount arglist ARGN argname -argparse -args argtype argv arijitdas arinc -arity arpa asm -aspx ASTRING asyc asynch @@ -81,13 +76,12 @@ autocode autocoded autocoders autocoding -autocomplete autocompletion autodoc +autodocs Autodocumentation autogen Autogenerate -autogenerated autogenerator AUTOLINK autoload @@ -113,6 +107,7 @@ bitmaps bitset ble blog +blogs BLSPSERIALDRIVERCOMPONENTIMPLCFG bocchino bodychars @@ -128,15 +123,14 @@ buf BUFFERALLOCATE BUFFERMANAGERCOMPONENTIMPLCFG BUFFERMGR +BUFFQUEUEIN buffsize BUGLIST bugprone builddir buildroot builtins -bw bysource -bytearray BYTEDRV calcu callee @@ -159,7 +153,7 @@ cdn cerrno cface CFDP -cfg +cff cflag cfsetispeed cfsetospeed @@ -167,15 +161,14 @@ cgi changelog changeme CHANNELID +CHANS chdir -checkbox cheetahtemplate +Chieu CHK -chmod CHNG chr chrono -ci cin cinttypes CIRCULARSTATE @@ -206,6 +199,8 @@ cntx cobj CODEFILE codegen +codeql +coldarm colno COLORSTYLE colorwheel @@ -214,15 +209,21 @@ COMMANDDISPATCHERIMPL COMMANDDISPATCHERIMPLCFG commandline commasepitem +COMBUFFER commonpath COMPACKET COMPONENTTESTERIMPL +COMQUEUE +COMQUEUEIN COMSPLITTER +COMSTUB +COMXBEE Concat config configparser configs configurability +constexpr cookiecutter cooldown coor @@ -237,11 +238,12 @@ Cpkt cplusplus CPOL cpos -cpp +cppcheckxml +cpplint +cppcheck cppreference cprogramming cpuset -cpy CRCAMPCS crcccitt crcdnp @@ -268,7 +270,6 @@ cstdlib CSTOPB cstring csum -csv ctest ctime CTORS @@ -278,16 +279,16 @@ culates curdir curmsgs cuz +ctu cwd -cxx CYCLEOUT cygwin daringfireball Daruwala DASSERT databinding +DATAROOTDIR datastore -datetime dawbarton DBUILD DCMAKE @@ -304,9 +305,9 @@ deframe deframed deframer deframing -delattr delchars delitem +DENABLE deployables DEPRECATEDLIST deps @@ -315,7 +316,6 @@ deregistration deser Deserial deserialization -deserialize deserialized deserializes deserializing @@ -325,13 +325,13 @@ DFL DFPRIME DGRAM dhesikan -DHTML diafile dictgen dicts dictvalue difflib diffs +digitalcommons diles dinkel dirent @@ -346,7 +346,6 @@ dnp DNs docblocks docbook -dockerfile docset docstring doctag @@ -372,7 +371,6 @@ Doxywizard dpi DPRIVATE DPROTECTED -dropdown drv drvipsocket drvsocketreadtask @@ -411,7 +409,6 @@ EHAs EINTR EINVAL EISDIR -elif elist ELOG ELOOP @@ -422,16 +419,13 @@ EMSGSIZE ENAMETOOLONG endcode endcond -endfor endforeach endfunction endian endianness -endif endl endloc endmacro -endswith enduml ENOENT ENOSPC @@ -456,18 +450,16 @@ errornum ert etime ETIMEDOUT -etree eturn -ev EVENTID eventname evr evt EXAMPLECOMPONENTIMPL excinfo -exe executables exitcode +Exoplanets expandtabs expr exprtokens @@ -477,10 +469,10 @@ fadvise FAKELOGGER fallocate fallthrough +fbuild fcheck fclose fcntl -fd fds fdset featuredarticles @@ -490,7 +482,6 @@ fflush Ffs fgetc fgets -fh filecmp filedown FILEDOWNLINK @@ -522,8 +513,10 @@ foodoodiehoo fopen foreach formatline +FPCONFIG fpconfighpp FPGA +fpi fpl fpp fppi @@ -534,11 +527,14 @@ fprofile fptr fputil fpv +freeram Fregoso frontend frox frsize fsanitize +fsanitizers +fsblkcnt fscanf fstream fstrength @@ -550,25 +546,25 @@ func functools fus FWCASSERT -gainsboro Gangianpour gbl gcc gcda gcgandhi +gcno gcov +gcovr +gdb gdiplus gencode genfile GENHUB GENREP genshi -getattr getattribute getbuffer getchildren getcontext -getcwd getdata getdefaultencoding getextern @@ -576,9 +572,9 @@ gethostname getinput getitem getline +getm getopt getoutput -getpass getpid getquaternion getroot @@ -590,14 +586,15 @@ gettime gettimeofday getty getuser -gh ghprb github gjslint glibc globals +gmock gmtime Gnc +Gnd gnd GNUC gnueabihf @@ -619,10 +616,8 @@ gtags gtest gui Guire -gz handcoded hardtoaccess -hasattr hashlib hashvalue Heade @@ -635,7 +630,6 @@ hexid hexnums hexopcode HFiles -hh hhc hhk hhp @@ -646,18 +640,12 @@ hlp HLTH Hofman hostname -hpp -href htags HTH -htm -html htmlfile HTMLHELP htonl htons -http -hu huey Huynh HVisitor @@ -665,7 +653,6 @@ hxx hyperlink hyperlinks hypermail -hz iadd ibd idl @@ -683,7 +670,6 @@ ignorables iif imap ime -img impl imple implgen @@ -691,16 +677,16 @@ importables INADDR iname inbool +INCLUDEDIR inet -ini inin initfiles inits initstate inkscape -inl -ino +inlined inode +INOUT INPCK Inputline installable @@ -708,16 +694,17 @@ instantiator instring instrlen integertypename +interoperate intlimits ints inttype +inttypes invisi ioc ioctl iomanip ior iostream -ip ipc IPCFG IPHELPER @@ -727,22 +714,19 @@ ipriority ipv IRUSR IRWXU -isabs isalpha isdigit -isdir isequal isf isfile isgenerator ishii -isinstance isnan isoschematron isr ISREG +iss isspace -issubclass isupper ITAR itimerspec @@ -750,7 +734,6 @@ itle itr itval itype -iu IWRITE ixor ixx @@ -766,13 +749,11 @@ jenkinsci jishii jobrestrictions joshuaa -jpg jpl jplffs jre jsdelivr JSO -json jsonable keepalive kermit @@ -788,7 +769,6 @@ LBLOCK LCHILD ldl lemstarch -len lestarch levelname lflag @@ -797,31 +777,29 @@ lhash libc libclang libcrc +LIBDIR +LIBEXECDIR libgtest libiconv LIBLOC lic -lifecycle -lightgreen -lightyellow lindent +linelength lineno lineroo lineterm linting linux -LINUXSERIALDRIVER LINUXTIMEIMPL -listdir +LINUXUARTDRIVER Listst LJR -ljust lkml lld llvm loadfile localhost -localtime +LOCALSTATEDIR LOCKGUARDTESTER locs LOGASSERT @@ -836,9 +814,7 @@ lpthread lrt lseek lshift -lstrip ltab -lte LTIME LTIMER LTLT @@ -849,7 +825,6 @@ MACROFILE mailto maincpp mainpage -makedirs makefiles makeindex MAKEVAR @@ -889,12 +864,9 @@ methodname methodstub microcontrollers microsoft -middleware mindepth MINGW -mkdir mkdtemp -mlist mman mmap MMAPALLOCATOR @@ -904,7 +876,6 @@ mname modbus MOSI MOVEFILE -mq mqd mqueue Mrf @@ -918,34 +889,33 @@ msgsize mstarch mstat mstring -MTIME mtype mul -multiline +multiarch multioptionals multirequired multline +multitool munmap mutex mutexattr +Mutexed mutexes mval -MVC mycompany myfile myproject -Mypy mytype -namespace +namespaced nano nanosleep nargs nathan nbits -nbsp ncsl NDELAY ndiffs +neascout Netscape newloc newroot @@ -953,7 +923,6 @@ newself newstring newtio nfds -Nh Nicolich ninjaaron NMEA @@ -968,6 +937,7 @@ nonblock noncomma NONINFRINGEMENT Nop +noparent noreply noreturn normalwidths @@ -983,6 +953,7 @@ NOTYPE Nowicki npm nproc +npx NSHUFF NSPACES nukenewlines @@ -991,15 +962,19 @@ numargs nums nxt objclass +objcopy objdoc +objdump objmodule objs oclc odl odo +ofiles oflag okidocki oldeol +OLDINCLUDEDIR OMG onchange onlinepubs @@ -1015,7 +990,6 @@ optarg optind optparse oran -orangered Orgs orgslist ORhex @@ -1035,7 +1009,6 @@ otherside outbool outdir outout -overridable ovr packetization packetize @@ -1055,14 +1028,10 @@ pbuild pcmake pcomp pdb -pdf pdflatex Peet -perl PERLMOD pexpect -php -phtml pid PINGSEND pinit @@ -1071,12 +1040,15 @@ pkts plainnat plantuml plugin +plugins pname png PNGs +POLLERR pollerr pollfd POLLIN +POLLPRI pollpri POLYDB POLYDBCOMP @@ -1087,7 +1059,6 @@ portlist PORTOUT PORTSELECTOR PORTSOUT -posix ppandian pport PQueue @@ -1113,7 +1084,6 @@ PRMDBLIMPLCFG prmname probs PROGRAMLISTING -proj projectbrief projectlogo projectname @@ -1133,10 +1103,10 @@ ptmcg pton ptr ptype +puml punc pushd pwd -py pycodestyle pydeps pydocstyle @@ -1160,20 +1130,21 @@ QNX qsf qtest qthelpproject +Qualcomm quatchan -quickstart +quoteattr RAbrack radd RAII Ramanan randtbl +rapidscat raspberrypi raspi RATEGROUPDRIVER RATEGROUPDRIVERIMPLTESTER RATEGROUPMEMBEROUT RATELIMITERTESTER -rb RBF Rce RCHILD @@ -1184,7 +1155,6 @@ RDONLY rdwr Readback readdir -readline readme readthedocs realloc @@ -1197,7 +1167,8 @@ reder refactor refactoring refspec -regex +REFTOPOLOGY +REFTOPOLOGYDEFS regexp regexs relaxng @@ -1220,32 +1191,26 @@ RHH ridgerun riverbankcomputing Rizvi -rmdir -rmtree -rng rootdir ror -rp rpaetz rpi RPIDEMO RPIDEMOCOMPONENTIMPLCFG rptr RSend -rstrip rtd rtems -rtf RTOS runcycles runperiod runtest -rx RXD rxor saddr Saikiran Sanchit +sanitizers sats savelist saveop @@ -1253,8 +1218,10 @@ saxutils sbb SBF sbin +SBINDIR sbt scanf +scatterometer sched schem schematron @@ -1264,6 +1231,7 @@ scons scp scrollbars sdd +SDFLIGHT searchdata SEARCHENGINE segfault @@ -1275,7 +1243,6 @@ serafin serializables serializer setaffinity -setattr setbuf setbuffer setdata @@ -1284,7 +1251,9 @@ SETFL setinheritsched setitem SETLOGGING +setm setop +setprecision setprotocol setquaternion setschedparam @@ -1304,10 +1273,10 @@ sface sfregoso sgl SGN +SHAREDSTATEDIR SHELLCOMMAND Shenker showinitializer -shutil sideeffect SIGALRM sighandler @@ -1321,12 +1290,12 @@ SIZ sizeof sloc Smath +smallsat SNDTIMEO snprintf sockaddr SOCKETHELPER SOCKETIPDRIVER -SOCKETIPDRIVERCFG SOCKETREADTASK socklen somechan @@ -1341,25 +1310,27 @@ SOURCEDIR sourceforge Sourcetrail sourcing +spacetech sparc SPHINXBUILD SPHINXOPTS spi spidev -splitext -splitlines sprintf Sqlite srand srandom srange src +srcs +SRCS sre sscanf ssh ssize SSL sss +sstream Ssymbols stacklevel stackoverflow @@ -1367,7 +1338,6 @@ STAMEM standalone standardpipeline startloc -startswith startuml statfs staticmethod @@ -1385,7 +1355,6 @@ strcmp STREQ STREQUAL strerror -strftime strg stri stringbuffer @@ -1393,6 +1362,7 @@ stringchan stringified Stringpacket stringparam +stringstream STRINGUTILS strlen strncat @@ -1403,10 +1373,9 @@ strnlen strs strtol strtoul -structs -stylesheet subdir subfolder +subfolders subgrouping subhist subhistory @@ -1414,17 +1383,18 @@ subpage subseconds subtargets sudo +suppr SVCLOGFILE SVCLOGFILEL -svg svipc swcaegitadmin SYMLINKS synchronicity synopsys -sys +SYSCONFDIR SYSFS sysinfo +sysroot systemd tabbedwidths tabccitt @@ -1448,7 +1418,6 @@ tcpserver TCSANOW tcsetattr tcsh -td tdir tdirection telem @@ -1498,12 +1467,10 @@ TIMERVAL timespec timetag timeval -timezone timothycanham tions tjh TKC -tl tlc tlist tlm @@ -1537,6 +1504,7 @@ toklist TOLOWER toolchain toolchains +toolset tooltip topologyapp Torvalds @@ -1545,6 +1513,7 @@ TOTALFF TOTALISFLOGEVENTMSG TOTALISFTELMMSG TOTALQUEUEFULL +totalram TOUPPER transcoding treeview @@ -1552,22 +1521,21 @@ trimwhitespace trinomials TRUNC truncstring -tt tts ttype Tuszynski TXD -typedef'ed typedef +typedef'ed typeid typeinfo typelist typename typeslist typetoken -tz tzinfo uart +UBSAN ubuntu ucf Uchenik @@ -1594,6 +1562,7 @@ unistd Unithem unittest UNITTESTASSERT +unittests unprintables unsubscribe upcalls @@ -1602,8 +1571,6 @@ upfiles upl upto URI -url -urllib usb usec usecond @@ -1611,15 +1578,13 @@ usepackage usleep usr ustr -utc utdir UTF -utils -uuid valgrind validator vals valud +vbai venv VERSIONED versioning @@ -1629,6 +1594,7 @@ vfs vhd vhdl VID +viewcontent viewforum virt virtualbox @@ -1636,16 +1602,13 @@ virtualization virtualized vla vlist -vm VMIN vmstat vsnprintf VTIME vtype -vue vuejs vwong -vx vxworks VXWORKSLOGASSERT WAITALL @@ -1671,7 +1634,6 @@ WORKDIR workflow worklist Woverloaded -wp writelines WRONLY wrs @@ -1680,20 +1642,17 @@ Wsign WSL Wundef www -wx wxgui Xabcdefx xapian xargs +Xcode +XBee xcode xdf xdffe Xelect xfer -xhtml -xls -xlsx -xml xmlfile xmlns xmls @@ -1702,11 +1661,9 @@ xon xor XPath xsh +xsltproc xxxx XYZZY yacc yacgen -yml yyyymmdd -zsh -zu diff --git a/.github/actions/spelling/line_forbidden.patterns b/.github/actions/spelling/line_forbidden.patterns index 4ca15837cc..760ec9b6ff 100644 --- a/.github/actions/spelling/line_forbidden.patterns +++ b/.github/actions/spelling/line_forbidden.patterns @@ -1,6 +1,11 @@ # reject `m_data` as there's a certain OS which has evil defines that break things if it's used elsewhere # \bm_data\b +# If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test, +# you might not want to check in code where you were debugging w/ `fit()`, in which case, you might want +# to use this: +#\bfit\( + # s.b. GitHub \bGithub\b @@ -19,6 +24,12 @@ # s.b. greater than \bgreater then\b +# s.b. into +#\sin to\s + +# s.b. opt-in +\sopt in\s + # s.b. less than \bless then\b @@ -30,10 +41,22 @@ \b[Nn]o[nt][- ]existent\b # s.b. preexisting -[Pp]re-existing +[Pp]re[- ]existing + +# s.b. preempt +[Pp]re[- ]empt\b # s.b. preemptively -[Pp]re-emptively +[Pp]re[- ]emptively + +# s.b. reentrancy +[Rr]e[- ]entrancy + +# s.b. reentrant +[Rr]e[- ]entrant + +# s.b. workaround(s) +\bwork[- ]arounds?\b # Reject duplicate words \s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s diff --git a/.github/actions/spelling/patterns.txt b/.github/actions/spelling/patterns.txt index 6241a7b50b..edd3969da1 100644 --- a/.github/actions/spelling/patterns.txt +++ b/.github/actions/spelling/patterns.txt @@ -1,5 +1,49 @@ # See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns +# hit-count: 106 file-count: 28 +# Compiler flags +(?:^|[\t ,"'`=(])-[DPWXYLlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}) + +# hit-count: 48 file-count: 18 +# GitHub SHAs (markdown) +(?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|) + +# hit-count: 29 file-count: 13 +# version suffix v# +(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_])) + +# hit-count: 8 file-count: 3 +# Wikipedia +\ben\.wikipedia\.org/wiki/[-\w%.#]+ + +# hit-count: 5 file-count: 2 +# w3 +\bw3\.org/[-0-9a-zA-Z/#.]+ + +# hit-count: 3 file-count: 3 +# Contributor +\[[^\]]+\]\(https://github\.com/[^/\s"]+\) + +# hit-count: 3 file-count: 3 +# stackexchange -- https://stackexchange.com/feeds/sites +\b(?:askubuntu|serverfault|stack(?:exchange|overflow)|superuser).com/(?:questions/\w+/[-\w]+|a/) + +# hit-count: 2 file-count: 1 +# mailto urls +\[([-a-zA-Z=;:/?%&0-9+@.]{3,})]\(mailto:\g{-1}\) + +# hit-count: 2 file-count: 1 +# apple +\bdeveloper\.apple\.com/[-\w?=/]+ + +# hit-count: 2 file-count: 1 +# shields.io +\bshields\.io/[-\w/%?=&.:+;,]* + +# hit-count: 1 file-count: 1 +# hex runs +\b[0-9a-fA-F]{16,}\b + # data urls "data:[^"]*" 'data:[^']*' @@ -47,20 +91,33 @@ value="(?:[0-9a-f]{1,2} )*" # Ignore any text between inline back-ticks `(.*?)` -# Tar archive items +# Tar archive items \b(?:\\n|)tar(?:\s+-[a-zA-Z]+|\s[a-z]+)+ # slashes after spaces are not in paths LaTeX \\.* \\ +# Questionably acceptable forms of `in to` +# Personally, I prefer `log into`, but people object +# https://www.tprteaching.com/log-into-log-in-to-login/ +\b[Ll]og in to\b + # acceptable duplicates # ls directory listings -[-bcdlpsw](?:[-r][-w][-sx]){3}\s+\d+\s+(\S+)\s+\g{-1}\s+\d+\s+ -# C types -\s(expr|long|LONG|Time)(?:\s+\g{-1})+\s +[-bcdlpsw](?:[-r][-w][-Ssx]){3}\s+\d+\s+\S+\s+\S+\s+\d+\s+ +# C types and repeated CSS values +\s(center|div|inherit|expr|long|LONG|none|normal|solid|Time|thin|transparent|very)(?: \g{-1})+\s +# go templates +\s(\w+)\s+\g{-1}\s+\`(?:graphql|json|yaml): # javadoc / .net (?:[\\@](?:groupname|page|param)|(?:public|private)(?:\s+static|\s+readonly)*)\s+(\w+)\s+\g{-1}\s +# Commit message -- Signed-off-by and friends +^\s*(?:(?:Based-on-patch|Co-authored|Helped|Mentored|Reported|Reviewed|Signed-off)-by|Thanks-to): (?:[^<]*<[^>]*>|[^<]*)\s*$ + +# Autogenerated revert commit message +^This reverts commit [0-9a-f]{40}\.$ + # Jenkins library GithubProjectProperty diff --git a/.github/scripts/cppcheck-xml2text.xslt b/.github/scripts/cppcheck-xml2text.xslt new file mode 100644 index 0000000000..808d5ad0a7 --- /dev/null +++ b/.github/scripts/cppcheck-xml2text.xslt @@ -0,0 +1,17 @@ + + + +## CppCheck Summary + +| error | warning | style | performance | portability | information | +| --- | --- | --- | --- | --- | --- | +| | | | | | | + +| severity | location | error id | issue | +| --- | --- | --- | --- | +| | : | | | + + +** error(s) reported** + + diff --git a/.github/scripts/cpplint-xml2text.xslt b/.github/scripts/cpplint-xml2text.xslt new file mode 100644 index 0000000000..626a02d307 --- /dev/null +++ b/.github/scripts/cpplint-xml2text.xslt @@ -0,0 +1,17 @@ + + + +## CppLint Summary + +| error | warning | style | +| --- | --- | --- | +| | | | + +| severity | location | error id | issue | +| --- | --- | --- | --- | +| | : | | | + + +** error(s) reported** + + diff --git a/.github/scripts/cpplint_to_cppcheckxml.py b/.github/scripts/cpplint_to_cppcheckxml.py new file mode 100644 index 0000000000..929726f5d3 --- /dev/null +++ b/.github/scripts/cpplint_to_cppcheckxml.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 + +# Convert output from Google's cpplint to the cppcheck XML format +# Reads from stdin and writes to stderr (to mimic cppcheck) +# https://stackoverflow.com/questions/14172232/how-to-make-cpplint-work-with-jenkins-warnings-plugin + +import re +import sys +import xml.sax.saxutils + +OUTPUT_FILE_XML_HEADER = """ + + + +""" + +OUTPUT_FILE_XML_FOOTER = """ + +""" + +CPPLINT_ERR_REGEX = "([^:]*):([0-9]*): ([^\[]*)\[([^\]]*)\] \[([0-9]*)\].*" +CPPLINT_ERR_REGEX_NB_INFO = 5 + + +def cpplint_score_to_cppcheck_severity(err_score: int) -> str: + if err_score in {1, 2}: + return "style" + if err_score in {3, 4}: + return "warning" + return "error" if err_score == 5 else "" + + +def write_if_relevant_error( + file_name: str, err_severity: str, err_label: str, err_msg: str, err_line: str +) -> None: + if err_severity in {"warning", "error"}: + sys.stderr.write( + f"""\n""" + ) + sys.stderr.write( + f"""\n""" + ) + sys.stderr.write("""\n""") + + +def fmt_report_from_cpplint_to_cppcheck() -> None: + sys.stderr.write(OUTPUT_FILE_XML_HEADER) + compiled_regex = re.compile(CPPLINT_ERR_REGEX) + + for line in sys.stdin.readlines(): + matched_regex = compiled_regex.match(line.strip()) + if not matched_regex: + continue + + matched_subgroups = matched_regex.groups() + if len(matched_subgroups) != CPPLINT_ERR_REGEX_NB_INFO: + continue + + file_name, err_line, raw_err_msg, err_label, err_score = matched_subgroups + # Prepare the data to be used as attribute values + err_msg = xml.sax.saxutils.escape(raw_err_msg) + err_msg = xml.sax.saxutils.quoteattr(err_msg) + + err_severity = cpplint_score_to_cppcheck_severity(int(err_score)) + + write_if_relevant_error(file_name, err_severity, err_label, err_msg, err_line) + + sys.stderr.write(OUTPUT_FILE_XML_FOOTER) + + +if __name__ == "__main__": + fmt_report_from_cpplint_to_cppcheck() diff --git a/.github/workflows/autodocs.yml b/.github/workflows/autodocs.yml index 081ffbe32f..977e7cb8f5 100644 --- a/.github/workflows/autodocs.yml +++ b/.github/workflows/autodocs.yml @@ -10,13 +10,13 @@ jobs: runs-on: ubuntu-latest steps: - name: "Checkout F´ Repository" - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - uses: ./.github/actions/setup - name: Setup Dependencies run: | sudo apt-get update - sudo apt-get install doxygen + sudo apt-get install -y doxygen - name: Autodocs run: .github/actions/autodoc.bash diff --git a/.github/workflows/build-test-macos.yml b/.github/workflows/build-test-macos.yml index 352096ff2d..2de9038f70 100644 --- a/.github/workflows/build-test-macos.yml +++ b/.github/workflows/build-test-macos.yml @@ -16,7 +16,7 @@ jobs: runs-on: macos-latest steps: - name: "Checkout F´ Repository" - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - uses: ./.github/actions/setup @@ -24,7 +24,7 @@ jobs: run: ./ci/tests/Framework.bash # Archive the outputs - name: 'Archive Logs' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: always() with: name: ci-framework-logs @@ -35,7 +35,7 @@ jobs: runs-on: macos-latest steps: - name: "Checkout F´ Repository" - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - uses: ./.github/actions/setup @@ -43,7 +43,7 @@ jobs: run: ./ci/tests/Ref.bash # Archive the outputs - name: 'Archive Logs' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: always() with: name: ci-ref-logs @@ -54,7 +54,7 @@ jobs: runs-on: macos-latest steps: - name: "Checkout F´ Repository" - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - uses: ./.github/actions/setup @@ -64,7 +64,7 @@ jobs: run: ./ci/tests/30-ints.bash # Archive the outputs - name: 'Archive Logs' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: always() with: name: ci-int-logs diff --git a/.github/workflows/build-test-rpi.yml b/.github/workflows/build-test-rpi.yml index 8f02c2e604..dd9d1bba82 100644 --- a/.github/workflows/build-test-rpi.yml +++ b/.github/workflows/build-test-rpi.yml @@ -9,33 +9,35 @@ on: branches: [ master, devel ] pull_request: branches: [ master, devel, release/v3.0.0 ] - +env: + RPI_TOOLCHAIN_DIR: /tmp/rpi-toolchain + DICTIONARY_PATH: build-artifacts/raspberrypi/dict/RPITopologyAppDictionary.xml # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: RPI: runs-on: ubuntu-latest steps: - name: "Checkout F´ Repository" - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - uses: ./.github/actions/setup - - name: Install RPI Toolchain - run: sudo git clone https://github.com/raspberrypi/tools.git /opt/rpi/tools + - name: Setup RPI Toolchain + uses: fprime-community/setup-rpi-sysroot@main - name: F prime CI step run: ./ci/tests/RPI.bash - name: Copy Tests run: mkdir -p artifact/RPI; cp -rp RPI/test RPI/build-artifacts artifact/RPI; cp -rp ci artifact # Build Artifacts - name: 'RPI Build Output' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: rpi-build path: artifact retention-days: 5 # Archive the outputs - name: 'Archive Logs' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: always() with: name: rpi-logs @@ -47,21 +49,17 @@ jobs: needs: RPI steps: - name: RPI Build Download - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: rpi-build - name: RPI Integration Tests run: chmod +x RPI/build-artifacts/raspberrypi/bin/RPI; /bin/bash ci/tests/RPI-Ints.bash # Archive the outputs - name: 'Archive Logs' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: always() with: name: pi-int-logs path: ci-logs.tar.gz retention-days: 5 - - name: Clean-Up - if: always() - run: | - rm -rf $RUNNER_WORKSPACE - sudo /sbin/shutdown -r 1 # Force a shutdown for a clean slate + # Clean-Up moved to post script to prevent collisions diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index cb10277d45..ce0a7f1554 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: "Checkout F´ Repository" - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - uses: ./.github/actions/setup @@ -24,7 +24,7 @@ jobs: run: ./ci/tests/Framework.bash # Archive the outputs - name: 'Archive Logs' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: always() with: name: ci-framework-logs @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest steps: - name: "Checkout F´ Repository" - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - uses: ./.github/actions/setup @@ -43,7 +43,7 @@ jobs: run: ./ci/tests/Ref.bash # Archive the outputs - name: 'Archive Logs' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: always() with: name: ci-ref-logs @@ -54,7 +54,7 @@ jobs: runs-on: ubuntu-latest steps: - name: "Checkout F´ Repository" - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - uses: ./.github/actions/setup @@ -66,7 +66,7 @@ jobs: run: ./ci/tests/30-ints.bash # Archive the outputs - name: 'Archive Logs' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: always() with: name: ci-int-logs @@ -77,7 +77,7 @@ jobs: runs-on: ubuntu-latest steps: - name: "Checkout F´ Repository" - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - uses: ./.github/actions/setup @@ -99,7 +99,7 @@ jobs: runs-on: ubuntu-latest steps: - name: "Checkout F´ Repository" - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - uses: ./.github/actions/setup diff --git a/.github/workflows/codeql-jpl-standard.yml b/.github/workflows/codeql-jpl-standard.yml new file mode 100644 index 0000000000..150ebe1594 --- /dev/null +++ b/.github/workflows/codeql-jpl-standard.yml @@ -0,0 +1,50 @@ +# Semantic code analysis with CodeQL +# see https://github.com/github/codeql-action + +name: "JPL Coding Standard Scan" + +on: + push: + branches: [ master, devel ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master, devel ] + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'cpp' ] + config-file: ['jpl-standard-pack-1.yml', 'jpl-standard-pack-2.yml', 'jpl-standard-pack-3.yml'] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # Run jobs in parallel for each config-file + config-file: ./.github/actions/codeql/${{ matrix.config-file }} + + - name: Build + run: | + python3 -m venv ./fprime-venv + . ./fprime-venv/bin/activate + pip install -U setuptools setuptools_scm wheel pip + pip install -r ./requirements.txt + fprime-util generate + fprime-util build --all + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/codeql-security-scan.yml b/.github/workflows/codeql-security-scan.yml new file mode 100644 index 0000000000..41509f86ae --- /dev/null +++ b/.github/workflows/codeql-security-scan.yml @@ -0,0 +1,50 @@ +# Semantic code analysis with CodeQL +# see https://github.com/github/codeql-action + +name: "CodeQL Security Scan" + +on: + push: + branches: [ master, devel ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master, devel ] + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'cpp', 'python' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + config-file: ./.github/actions/codeql/security-pack.yml + + - if: ${{ matrix.language == 'cpp' }} + name: Build + run: | + python3 -m venv ./fprime-venv + . ./fprime-venv/bin/activate + pip install -U setuptools setuptools_scm wheel pip + pip install -r ./requirements.txt + fprime-util generate + fprime-util build --all + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/cppcheck-scan.yml b/.github/workflows/cppcheck-scan.yml new file mode 100644 index 0000000000..09da2b5b33 --- /dev/null +++ b/.github/workflows/cppcheck-scan.yml @@ -0,0 +1,67 @@ +# Adapted from https://github.com/nasa/cFS/blob/c36aa2c1df0fb47a3838577908af3d0d0ab0ef54/.github/workflows/static-analysis.yml +name: "Cppcheck Scan" + +on: + push: + branches: [ master, devel ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master, devel ] + + +jobs: + cppcheck: + name: Cppcheck + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + steps: + - name: "Checkout F´ Repository" + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - uses: ./.github/actions/setup + + - name: Install cppcheck + run: sudo apt-get install cppcheck xsltproc -y + + - name: Install sarif tool + run: npm i -g @microsoft/sarif-multitool + + # With a CMake-based project, we get the list of files by setting up a build with CMAKE_EXPORT_COMPILE_COMMANDS=ON and + # referencing the compile_commands.json file produced by the tool. This will capture the correct include paths and + # compile definitions based on how the source is actually compiled. See https://cppcheck.sourceforge.io/manual.html + - name: Generate & build F´ + run: | + fprime-util generate -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + fprime-util build --all --jobs "$(nproc || printf '%s\n' 1)" + echo CPPCHECK_OPTS=--project="$GITHUB_WORKSPACE/build-fprime-automatic-native/compile_commands.json" >> $GITHUB_ENV + + - name: Run cppcheck + run: cppcheck --force --relative-paths=$(pwd) --inline-suppr --std=c++11 -j "$(nproc || printf '%s\n' 1)" --max-ctu-depth=16 --enable=warning,performance,portability --suppress=variableScope --inconclusive --xml $CPPCHECK_OPTS 2> cppcheck_err.xml + + - name: Convert cppcheck results to SARIF + run: npx "@microsoft/sarif-multitool" convert "cppcheck_err.xml" --tool "CppCheck" --output "cppcheck_err.sarif" + + - name: Convert cppcheck results to Markdown & Integrate them in the workflow summary + run: xsltproc .github/scripts/cppcheck-xml2text.xslt cppcheck_err.xml | tee $GITHUB_STEP_SUMMARY cppcheck_err.txt + + - name: Upload SARIF file to GitHub Code Scanning Alerts + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: ${{ github.workspace }}/cppcheck_err.sarif + category: "cppcheck" + + - name: Archive static analysis artifacts to download and view + uses: actions/upload-artifact@v3 + with: + name: cppcheck-errors + path: ./*cppcheck_err.* + + # Make the whole step fail if there is an error detected by cppcheck. By default, GitHub Actions enables the set -e. + # See https://stackoverflow.com/questions/73066461/github-actions-why-an-intermediate-command-failure-in-shell-script-would-cause. + - name: Check for reported errors + run: tail -n 1 cppcheck_err.txt | grep -q '^\*\*0 error(s) reported\*\*$' diff --git a/.github/workflows/cpplint-scan.yml b/.github/workflows/cpplint-scan.yml new file mode 100644 index 0000000000..2a90fb54c8 --- /dev/null +++ b/.github/workflows/cpplint-scan.yml @@ -0,0 +1,64 @@ +name: "Cpplint Scan" + +on: + push: + branches: [master, devel] + pull_request: + # The branches below must be a subset of the branches above + branches: [master, devel] + +jobs: + cpplint: + name: Cpplint + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + steps: + - name: "Checkout F´ Repository" + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - uses: ./.github/actions/setup + + - name: Install cpplint + run: pip install cpplint + + - name: Install xsltproc + run: sudo apt-get install xsltproc -y + + - name: Install sarif tool + run: npm i -g @microsoft/sarif-multitool + + - name: Run cpplint & export output to cppcheck format + run: cpplint --counting=detailed --quiet --recursive . 2>&1 | python3 .github/scripts/cpplint_to_cppcheckxml.py &> cpplint_cppcheck_result.xml + + - name: Convert cpplint results to SARIF + run: npx "@microsoft/sarif-multitool" convert "cpplint_cppcheck_result.xml" --tool "CppCheck" --output "cpplint_cppcheck_result.sarif" + + - name: Convert cpplint results to Markdown & Integrate them in the workflow summary + run: xsltproc .github/scripts/cpplint-xml2text.xslt cpplint_cppcheck_result.xml | tee $GITHUB_STEP_SUMMARY cpplint_cppcheck_result.txt + + # See https://github.com/nasa/fprime/pull/1794 for why this is needed + - name: Replace tool name in SARIF file + run: | + sed -i -e 's/\"name\": \"CppCheck\"/\"name\": \"CppLint\"/g' cpplint_cppcheck_result.sarif + + - name: Upload SARIF file to GitHub Code Scanning Alerts + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: ${{ github.workspace }}/cpplint_cppcheck_result.sarif + category: "cpplint" + + - name: Archive static analysis artifacts to download and view + uses: actions/upload-artifact@v3 + with: + name: cpplint-errors + path: ./*cpplint_cppcheck_result.* + + # Make the whole step fail if there is an error detected by cpplint. By default, GitHub Actions enables the set -e. + # See https://stackoverflow.com/questions/73066461/github-actions-why-an-intermediate-command-failure-in-shell-script-would-cause. + # - name: Check for reported errors + # run: tail -n 1 cpplint_cppcheck_result.txt | grep -q '^\*\*0 error(s) reported\*\*$' diff --git a/.github/workflows/pip-check.yml b/.github/workflows/pip-check.yml new file mode 100644 index 0000000000..aa75e2d716 --- /dev/null +++ b/.github/workflows/pip-check.yml @@ -0,0 +1,28 @@ +# This job is to check that the requirements.txt file isn't giving +# any troubles to pip for any of the supported versions of Python + +name: Python Dependency Check + +on: + push: + paths: + - 'requirements.txt' + pull_request: + paths: + - 'requirements.txt' + +jobs: + pip-install: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + pip install -r requirements.txt diff --git a/.github/workflows/python-format.yml b/.github/workflows/python-format.yml index 06ec37189a..742fb3930f 100644 --- a/.github/workflows/python-format.yml +++ b/.github/workflows/python-format.yml @@ -6,7 +6,7 @@ jobs: name: Format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Python 3.7 uses: actions/setup-python@v2 with: diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml index c31e5767e9..178a500a1e 100644 --- a/.github/workflows/spelling.yml +++ b/.github/workflows/spelling.yml @@ -1,4 +1,38 @@ name: Spell checking + +# Comment management is handled through a secondary job, for details see: +# https://github.com/check-spelling/check-spelling/wiki/Feature%3A-Restricted-Permissions +# +# `jobs.comment-push` runs when a push is made to a repository and the `jobs.spelling` job needs to make a comment +# (in odd cases, it might actually run just to collapse a comment, but that's fairly rare) +# it needs `contents: write` in order to add a comment. +# +# `jobs.comment-pr` runs when a pull_request is made to a repository and the `jobs.spelling` job needs to make a comment +# or collapse a comment (in the case where it had previously made a comment and now no longer needs to show a comment) +# it needs `pull-requests: write` in order to manipulate those comments. + +# Updating pull request branches is managed via comment handling. +# For details, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-expect-list +# +# These elements work together to make it happen: +# +# `on.issue_comment` +# This event listens to comments by users asking to update the metadata. +# +# `jobs.update` +# This job runs in response to an issue_comment and will push a new commit +# to update the spelling metadata. +# +# `with.experimental_apply_changes_via_bot` +# Tells the action to support and generate messages that enable it +# to make a commit to update the spelling metadata. +# +# `with.ssh_key` +# In order to trigger workflows when the commit is made, you can provide a +# secret (typically, a write-enabled github deploy key). +# +# For background, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-with-deploy-key + on: push: branches: @@ -10,7 +44,10 @@ on: - "**" tags-ignore: - "**" - types: ['opened', 'reopened', 'synchronize'] + types: + - 'opened' + - 'reopened' + - 'synchronize' jobs: spelling: @@ -30,15 +67,26 @@ jobs: steps: - name: check-spelling id: spelling - uses: check-spelling/check-spelling@v0.0.20 + uses: check-spelling/check-spelling@v0.0.21 with: suppress_push_for_open_pull_request: 1 checkout: true + check_file_names: 1 + spell_check_this: check-spelling/spell-check-this@prerelease post_comment: 0 + use_magic_file: 1 + extra_dictionary_limit: 10 extra_dictionaries: cspell:filetypes/filetypes.txt - cspell:python/python.txt + cspell:python/src/python/python-lib.txt + cspell:python/src/python/python.txt + cspell:python/src/common/extra.txt + cspell:software-terms/src/software-terms.txt + cspell:node/node.txt + cspell:cpp/src/stdlib-c.txt + cspell:cpp/src/stdlib-cpp.txt cspell:django/django.txt cspell:html/html.txt cspell:fullstack/fullstack.txt + cspell:aws/aws.txt check_extra_dictionaries: '' diff --git a/.gitignore b/.gitignore index d17c56549e..1e422e991c 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,5 @@ depend /.idea/ /venv/ + +Packet-Views diff --git a/.lgtm.js b/.lgtm.js deleted file mode 100644 index 41a02371c1..0000000000 --- a/.lgtm.js +++ /dev/null @@ -1 +0,0 @@ -function appease_lgtm() {} diff --git a/.lgtm.yml b/.lgtm.yml deleted file mode 100644 index 08fd0cd122..0000000000 --- a/.lgtm.yml +++ /dev/null @@ -1,43 +0,0 @@ -############## -# Configuration file for LGTM.com -# Currently only needed for cpp code since python and js works by default -# -# @author: Hunter Paulson -# @modified: 2020-07-15 -############## - - -path_classifiers: - docs: - - docs -queries: - - include: cpp/incorrect-not-operator-usage - - include: - tags: - - "correctness" - - include: - tags: - - "reliability" -extraction: - cpp: - prepare: - packages: - - "python3" - - "python3-pip" - - "python3-venv" - after_prepare: - # setup the venv and install packages - - "python3 -m venv ./fprime-venv" - - ". ./fprime-venv/bin/activate" - - "pip install -U setuptools setuptools_scm wheel pip" - - "wget https://github.com/sbt/sbt/releases/download/v1.6.2/sbt-1.6.2.tgz" - - "tar -xzf sbt-1.6.2.tgz" - - "export PATH=$PATH:$LGTM_SRC/sbt/bin" - - "pip install -r ./requirements.txt" - configure: - command: - before_index: - - "fprime-util generate" - index: - build_command: - - "fprime-util build --all" diff --git a/Autocoders/Python/bin/codegen.py b/Autocoders/Python/bin/codegen.py index ac36897c5e..1d24a95a98 100755 --- a/Autocoders/Python/bin/codegen.py +++ b/Autocoders/Python/bin/codegen.py @@ -502,13 +502,6 @@ def generate_component_instance_dictionary( xml_parser_obj = XmlSerializeParser.XmlSerializeParser( serializable_file ) # Telemetry/Params can only use generated serializable types - # check to make sure that the serializables don't have things that channels and parameters can't have - # can't have external non-xml members - if len(xml_parser_obj.get_include_header_files()): - PRINT.info( - f"ERROR: Component include serializables cannot use user-defined types. file: {serializable_file}" - ) - sys.exit(-1) # print xml_parser_obj.get_args() parsed_serializable_xml_list.append(xml_parser_obj) @@ -674,14 +667,6 @@ def generate_component( xml_parser_obj = XmlSerializeParser.XmlSerializeParser( serializable_file ) # Telemetry/Params can only use generated serializable types - # check to make sure that the serializables don't have things that channels and parameters can't have - # can't have external non-xml members - if len(xml_parser_obj.get_include_header_files()): - PRINT.info( - f"ERROR: Component include serializables cannot use user-defined types. file: {serializable_file}" - ) - sys.exit(-1) - # print xml_parser_obj.get_args() parsed_serializable_xml_list.append(xml_parser_obj) del xml_parser_obj @@ -725,6 +710,7 @@ def generate_component( cpp_instance_gtest_name = base + "_GTest_Cpp" h_instance_test_impl_name = base + "_TestImpl_H" cpp_instance_test_impl_name = base + "_TestImpl_Cpp" + cpp_instance_test_impl_helpers_name = base + "_TestImplHelpers_Cpp" test_main_name = base + "_TestMain_Cpp" else: PRINT.info("Missing Ai at end of file name...") @@ -753,6 +739,9 @@ def generate_component( generator.configureVisitor( cpp_instance_test_impl_name, "TestImplCppVisitor", True, True ) + generator.configureVisitor( + cpp_instance_test_impl_helpers_name, "TestImplCppHelpersVisitor", True, True + ) generator.configureVisitor(test_main_name, "TestMainVisitor", True, True) else: generator.configureVisitor(h_instance_name, "ComponentHVisitor", True, True) diff --git a/Autocoders/Python/bin/tlmLayout.py b/Autocoders/Python/bin/tlmLayout.py index 27cc67b476..1f4dd18c02 100644 --- a/Autocoders/Python/bin/tlmLayout.py +++ b/Autocoders/Python/bin/tlmLayout.py @@ -472,9 +472,7 @@ def packet_complete(self): print("") print("Number of items in packet item list: ", len(self.m_item_list)) - i = 0 - for item in self.m_item_list: - i += 1 + for i, item in enumerate(self.m_item_list, start=1): print("Item # ", i) print("\tis_reserve: ", item.m_is_reserve) print("\tis_constant: ", item.m_is_constant) diff --git a/Autocoders/Python/bin/tlm_packet_gen.py b/Autocoders/Python/bin/tlm_packet_gen.py index f2d5d815d2..ec94a0f6b8 100755 --- a/Autocoders/Python/bin/tlm_packet_gen.py +++ b/Autocoders/Python/bin/tlm_packet_gen.py @@ -63,14 +63,14 @@ \#include <${output_header}> \#include -\#include +\#include \#include // Verify packets not too large for ComBuffer // if this macro gives a compile error, that means the packets are too large void check_func(void) { - COMPILE_TIME_ASSERT((${max_size} <= (FW_COM_BUFFER_MAX_SIZE - Fw::Time::SERIALIZED_SIZE - sizeof(FwTlmPacketizeIdType) - sizeof(FwPacketDescriptorType))),PacketsTooBig); + static_assert((${max_size} <= (FW_COM_BUFFER_MAX_SIZE - Fw::Time::SERIALIZED_SIZE - sizeof(FwTlmPacketizeIdType) - sizeof(FwPacketDescriptorType))), "PacketsTooBig"); } namespace ${packet_list_namespace} { @@ -114,6 +114,8 @@ PRINT = logging.getLogger("output") DEBUG = logging.getLogger("debug") +PACKET_VIEW_DIR = "./Packet-Views" + class TlmPacketParseValueError(ValueError): pass @@ -136,8 +138,8 @@ def add_type_size(self, type, size): def get_type_size(self, type_name, size): # switch based on type - if type == "string": - return size + if type_name == "string": + return int(size) + 2 # plus 2 to store the string length elif type_name == "I8": return 1 elif type_name == "I16": @@ -163,28 +165,6 @@ def get_type_size(self, type_name, size): else: return None - # def search_for_file(self,file_type, file_path): - # ''' - # Searches for a given included port or serializable by looking in three places: - # - The specified BUILD_ROOT - # - The F Prime core - # - The exact specified path - # @param file_type: type of file searched for - # @param file_path: path to look for based on offset - # @return: full path of file - # ''' - # core = os.environ.get("FPRIME_CORE_DIR", BUILD_ROOT) - # for possible in [BUILD_ROOT, core, None]: - # if not possible is None: - # checker = os.path.join(possible, file_path) - # else: - # checker = file_path - # if os.path.exists(checker): - # DEBUG.debug("%s xml type description file: %s" % (file_type,file_path)) - # return checker - # else: - # return None - def generate_channel_size_dict(self, the_parsed_topology_xml, xml_filename): """ Generates GDS XML dictionary from parsed topology XML @@ -224,7 +204,7 @@ def generate_channel_size_dict(self, the_parsed_topology_xml, xml_filename): for comp in the_parsed_topology_xml.get_instances(): comp_name = comp.get_name() - comp_id = int(comp.get_base_id()) + comp_id = int(comp.get_base_id(), 0) comp_type = comp.get_type() if self.verbose: PRINT.debug("Processing %s" % comp_name) @@ -246,6 +226,9 @@ def generate_channel_size_dict(self, the_parsed_topology_xml, xml_filename): # if channel is enum if type(chan_type) == type(tuple()): chan_size = 4 + # if channel type is string + # elif chan_type == "string": + # chan_size = int(chan.get_size()) + 2 # FIXME: buffer size storage size magic number - needs to be turned into a constant # if channel is serializable elif chan_type in self.size_dict: chan_size = self.size_dict[chan_type] @@ -266,7 +249,7 @@ def generate_channel_size_dict(self, the_parsed_topology_xml, xml_filename): def gen_packet_file(self, xml_filename): - view_path = "./Views" + view_path = PACKET_VIEW_DIR if not os.path.exists(view_path): os.mkdir(view_path) @@ -275,11 +258,6 @@ def gen_packet_file(self, xml_filename): if not os.path.isfile(xml_filename): raise TlmPacketParseIOError("File %s does not exist!" % xml_filename) - if not "PacketsAi" in xml_filename: - raise IOError( - "ERROR: Missing PacketsAi at end of file name %s" % xml_filename - ) - fd = open(xml_filename, "r") xml_parser = etree.XMLParser(remove_comments=True) element_tree = etree.parse(fd, parser=xml_parser) @@ -315,12 +293,12 @@ def gen_packet_file(self, xml_filename): ht.num_packets = 0 total_packet_size = 0 levels = [] - view_path = "./Views" + view_path = PACKET_VIEW_DIR # find the topology import for entry in element_tree.getroot(): # read in topology file if entry.tag == "import_topology": - top_file = search_for_file("Packet", entry.text) + top_file = search_for_file("Topology", entry.text) if top_file is None: raise TlmPacketParseIOError( "import file %s not found" % entry.text @@ -424,12 +402,9 @@ def gen_packet_file(self, xml_filename): "Invalid xml type %s" % element_tree.getroot().tag ) - output_file_base = os.path.splitext(os.path.basename(xml_filename))[0].replace( - "Ai", "" - ) - file_dir = os.path.dirname(xml_filename).replace( - get_nearest_build_root(xml_filename) + os.sep, "" - ) + output_file_base = os.path.splitext(os.path.basename(xml_filename))[0] + nearest_build_root = get_nearest_build_root(xml_filename) + file_dir = os.path.relpath(os.path.dirname(xml_filename), nearest_build_root) missing_channels = False @@ -499,6 +474,7 @@ def process_serializable_files(self, serializable_file_list): for ( member_name, member_type, + member_array_size, member_size, member_format_specifier, member_comment, @@ -520,6 +496,8 @@ def process_serializable_files(self, serializable_file_list): ) sys.exit(-1) serializable_size += type_size + if member_array_size != None: + serializable_size *= member_array_size self.add_type_size(serializable_type, serializable_size) if self.verbose: print( @@ -616,7 +594,7 @@ def main(): print(f"Usage: {sys.argv[0]} [options] xml_filename") return elif len(args) == 1: - xml_filename = args[0] + xml_filename = os.path.abspath(args[0]) else: print("ERROR: Too many filenames, should only have one") return diff --git a/Autocoders/Python/bin/tlm_packet_gen.sh b/Autocoders/Python/bin/tlm_packet_gen.sh new file mode 100755 index 0000000000..f2d2743588 --- /dev/null +++ b/Autocoders/Python/bin/tlm_packet_gen.sh @@ -0,0 +1,14 @@ +#!/usr/bin/bash + +script_dir=$(dirname $0) + +# $0 = this script +# $1 = packet file +# $2 = deployment build cache (ex. Ref/build-fprime-automatic-native) + +export PYTHONPATH=$script_dir/../src +export BUILD_ROOT=$script_dir/../../../:$2:$2/F-Prime +echo "BUILD_ROOT=$BUILD_ROOT" + +# get python from the path +python3 $script_dir/tlm_packet_gen.py $1 \ No newline at end of file diff --git a/Autocoders/Python/schema/default/interface_schema.rng b/Autocoders/Python/schema/default/interface_schema.rng index 4c9b42c1b4..87d9059ce9 100644 --- a/Autocoders/Python/schema/default/interface_schema.rng +++ b/Autocoders/Python/schema/default/interface_schema.rng @@ -4,7 +4,7 @@ xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> - + diff --git a/Autocoders/Python/schema/default/internal_interface_schema.rng b/Autocoders/Python/schema/default/internal_interface_schema.rng index 87f963dfd7..f29e24c3ee 100644 --- a/Autocoders/Python/schema/default/internal_interface_schema.rng +++ b/Autocoders/Python/schema/default/internal_interface_schema.rng @@ -4,7 +4,7 @@ xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> - + diff --git a/Autocoders/Python/src/fprime_ac/generators/AbstractGenerator.py b/Autocoders/Python/src/fprime_ac/generators/AbstractGenerator.py index dc4e0560ea..de18671938 100644 --- a/Autocoders/Python/src/fprime_ac/generators/AbstractGenerator.py +++ b/Autocoders/Python/src/fprime_ac/generators/AbstractGenerator.py @@ -57,7 +57,7 @@ def __call__(self, args): Main execution point. Calls the accept method on each visitor to generate the code. """ - raise Exception( + raise NotImplementedError( "AbstractGenerator.__call__() - Implementation Error: you must supply your own concrete implementation." ) @@ -65,7 +65,7 @@ def accept(self, visitor): """ Execute the visit call on this object. """ - raise Exception( + raise NotImplementedError( "AbstractFace.accept.accept(v) - Implementation Error: you must supply your own concrete implementation." ) @@ -73,6 +73,6 @@ def addVisitor(self, visitor): """ Method to add the visitor to a list of visitors. """ - raise Exception( + raise NotImplementedError( "AbstractFace.accept.addVisitor(v) - Implementation Error: you must supply your own concrete implementation." ) diff --git a/Autocoders/Python/src/fprime_ac/generators/ChannelBody.py b/Autocoders/Python/src/fprime_ac/generators/ChannelBody.py index c84a65f632..4471c0e78b 100644 --- a/Autocoders/Python/src/fprime_ac/generators/ChannelBody.py +++ b/Autocoders/Python/src/fprime_ac/generators/ChannelBody.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "ChannelBody.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "ChannelBody.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "ChannelBody.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "ChannelBody.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/ChannelHeader.py b/Autocoders/Python/src/fprime_ac/generators/ChannelHeader.py index 73c8b33eac..c2fe6a60e5 100644 --- a/Autocoders/Python/src/fprime_ac/generators/ChannelHeader.py +++ b/Autocoders/Python/src/fprime_ac/generators/ChannelHeader.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "ChannelHeader.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "ChannelHeader.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "ChannelHeader.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "ChannelHeader.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/CommandBody.py b/Autocoders/Python/src/fprime_ac/generators/CommandBody.py index f37b5c57f1..35c81bf8ac 100644 --- a/Autocoders/Python/src/fprime_ac/generators/CommandBody.py +++ b/Autocoders/Python/src/fprime_ac/generators/CommandBody.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "startCommandVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "startCommandVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "startCommandVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "startCommandVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/CommandHeader.py b/Autocoders/Python/src/fprime_ac/generators/CommandHeader.py index cadd440263..66bc1f29c7 100644 --- a/Autocoders/Python/src/fprime_ac/generators/CommandHeader.py +++ b/Autocoders/Python/src/fprime_ac/generators/CommandHeader.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "CommandHeader.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "CommandHeader.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "CommandHeader.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "CommandHeader.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/DictBody.py b/Autocoders/Python/src/fprime_ac/generators/DictBody.py index bc81dc69f4..a9410f7231 100644 --- a/Autocoders/Python/src/fprime_ac/generators/DictBody.py +++ b/Autocoders/Python/src/fprime_ac/generators/DictBody.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "DictBodyVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "DictBodyVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "DictBodyVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "DictBodyVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/DictHeader.py b/Autocoders/Python/src/fprime_ac/generators/DictHeader.py index 1727cb3d74..658a23d3dd 100644 --- a/Autocoders/Python/src/fprime_ac/generators/DictHeader.py +++ b/Autocoders/Python/src/fprime_ac/generators/DictHeader.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "DictHeaderVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "DictHeaderVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "DictHeaderVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "DictHeaderVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/DictStart.py b/Autocoders/Python/src/fprime_ac/generators/DictStart.py index 6cb18a921b..5df92a6bb0 100644 --- a/Autocoders/Python/src/fprime_ac/generators/DictStart.py +++ b/Autocoders/Python/src/fprime_ac/generators/DictStart.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "DictStartVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "DictStartVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "DictStartVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "DictStartVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/EventBody.py b/Autocoders/Python/src/fprime_ac/generators/EventBody.py index 847ffa4547..99eca93ac5 100644 --- a/Autocoders/Python/src/fprime_ac/generators/EventBody.py +++ b/Autocoders/Python/src/fprime_ac/generators/EventBody.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "EventBody.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "EventBody.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "EventBody.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "EventBody.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/EventHeader.py b/Autocoders/Python/src/fprime_ac/generators/EventHeader.py index b431c9ed7d..e54088c2e9 100644 --- a/Autocoders/Python/src/fprime_ac/generators/EventHeader.py +++ b/Autocoders/Python/src/fprime_ac/generators/EventHeader.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "EventHeader.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "EventHeader.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "EventHeader.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "EventHeader.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/FinishSource.py b/Autocoders/Python/src/fprime_ac/generators/FinishSource.py index 352fbe402f..9615967ca7 100644 --- a/Autocoders/Python/src/fprime_ac/generators/FinishSource.py +++ b/Autocoders/Python/src/fprime_ac/generators/FinishSource.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "FinishSource.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "FinishSource.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "FinishSource.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "FinishSource.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/GenFactory.py b/Autocoders/Python/src/fprime_ac/generators/GenFactory.py index 96213e0d35..6aaab7ef9c 100644 --- a/Autocoders/Python/src/fprime_ac/generators/GenFactory.py +++ b/Autocoders/Python/src/fprime_ac/generators/GenFactory.py @@ -71,6 +71,7 @@ SerialHVisitor, SerializableVisitor, TestImplCppVisitor, + TestImplCppHelpersVisitor, TestImplHVisitor, TestMainVisitor, TopologyCppVisitor, @@ -147,6 +148,8 @@ def Instance(self): inst = ImplHVisitor.ImplHVisitor() elif self.__type == "TestImplCppVisitor": inst = TestImplCppVisitor.TestImplCppVisitor() + elif self.__type == "TestImplCppHelpersVisitor": + inst = TestImplCppHelpersVisitor.TestImplCppHelpersVisitor() elif self.__type == "TestImplHVisitor": inst = TestImplHVisitor.TestImplHVisitor() elif self.__type == "TestMainVisitor": diff --git a/Autocoders/Python/src/fprime_ac/generators/HtmlDocPage.py b/Autocoders/Python/src/fprime_ac/generators/HtmlDocPage.py index 943ef39021..a204bc14cf 100644 --- a/Autocoders/Python/src/fprime_ac/generators/HtmlDocPage.py +++ b/Autocoders/Python/src/fprime_ac/generators/HtmlDocPage.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "HtmlDoc.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "HtmlDoc.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "HtmlDoc.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "HtmlDoc.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/HtmlStartPage.py b/Autocoders/Python/src/fprime_ac/generators/HtmlStartPage.py index 081ff24abc..126ec695b3 100644 --- a/Autocoders/Python/src/fprime_ac/generators/HtmlStartPage.py +++ b/Autocoders/Python/src/fprime_ac/generators/HtmlStartPage.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "HtmlStartPage.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "HtmlStartPage.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "HtmlStartPage.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "HtmlStartPage.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/Includes1.py b/Autocoders/Python/src/fprime_ac/generators/Includes1.py index c246ecc4e5..b80ebb040e 100644 --- a/Autocoders/Python/src/fprime_ac/generators/Includes1.py +++ b/Autocoders/Python/src/fprime_ac/generators/Includes1.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "Includes1.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "Includes1.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "Includes1.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "Includes1.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/Includes2.py b/Autocoders/Python/src/fprime_ac/generators/Includes2.py index 7cfda5f929..b22d32c5bb 100644 --- a/Autocoders/Python/src/fprime_ac/generators/Includes2.py +++ b/Autocoders/Python/src/fprime_ac/generators/Includes2.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "Includes2.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "Includes2.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "Includes2.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "Includes2.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/InitFiles.py b/Autocoders/Python/src/fprime_ac/generators/InitFiles.py index 4cc1eadc69..930e72605e 100644 --- a/Autocoders/Python/src/fprime_ac/generators/InitFiles.py +++ b/Autocoders/Python/src/fprime_ac/generators/InitFiles.py @@ -80,7 +80,7 @@ def accept(self, visitor): DEBUG.error( "InitFiles.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "InitFiles.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -95,7 +95,7 @@ def addVisitor(self, visitor): DEBUG.error( "InitFiles.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "InitFiles.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/InstanceDictBody.py b/Autocoders/Python/src/fprime_ac/generators/InstanceDictBody.py index dc12163270..c1a83c250a 100644 --- a/Autocoders/Python/src/fprime_ac/generators/InstanceDictBody.py +++ b/Autocoders/Python/src/fprime_ac/generators/InstanceDictBody.py @@ -79,7 +79,7 @@ def accept(self, visitor, topology_model): DEBUG.error( "InstanceDictBodyVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "InstanceDictBodyVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "InstanceDictBodyVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "InstanceDictBodyVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/InstanceDictHeader.py b/Autocoders/Python/src/fprime_ac/generators/InstanceDictHeader.py index b1098e42c7..91dbe32ba9 100644 --- a/Autocoders/Python/src/fprime_ac/generators/InstanceDictHeader.py +++ b/Autocoders/Python/src/fprime_ac/generators/InstanceDictHeader.py @@ -79,7 +79,7 @@ def accept(self, visitor, topology_model): DEBUG.error( "InstanceDictHeaderVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "InstanceDictHeaderVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "InstanceDictHeaderVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "InstanceDictHeaderVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/InstanceDictStart.py b/Autocoders/Python/src/fprime_ac/generators/InstanceDictStart.py index 1430de5c39..9478f3e198 100644 --- a/Autocoders/Python/src/fprime_ac/generators/InstanceDictStart.py +++ b/Autocoders/Python/src/fprime_ac/generators/InstanceDictStart.py @@ -79,7 +79,7 @@ def accept(self, visitor, topology_model): DEBUG.error( "InstanceDictStartVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "InstanceDictStartVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "InstanceDictStartVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "InstanceDictStartVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/MdDocPage.py b/Autocoders/Python/src/fprime_ac/generators/MdDocPage.py index 3f35ab27db..d24d9c42d8 100644 --- a/Autocoders/Python/src/fprime_ac/generators/MdDocPage.py +++ b/Autocoders/Python/src/fprime_ac/generators/MdDocPage.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "MdDoc.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "MdDoc.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "MdDoc.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "MdDoc.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/MdStartPage.py b/Autocoders/Python/src/fprime_ac/generators/MdStartPage.py index 09a91fd1b2..55502b2806 100644 --- a/Autocoders/Python/src/fprime_ac/generators/MdStartPage.py +++ b/Autocoders/Python/src/fprime_ac/generators/MdStartPage.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "MDStartPage.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "MdStartPage.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "MdStartPage.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "MdStartPage.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/Namespace.py b/Autocoders/Python/src/fprime_ac/generators/Namespace.py index da5c08ded2..6267ddc5c3 100644 --- a/Autocoders/Python/src/fprime_ac/generators/Namespace.py +++ b/Autocoders/Python/src/fprime_ac/generators/Namespace.py @@ -80,7 +80,7 @@ def accept(self, visitor): DEBUG.error( "Namespace.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "Namespace.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -95,7 +95,7 @@ def addVisitor(self, visitor): DEBUG.error( "Namespace.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "Namespace.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/Private.py b/Autocoders/Python/src/fprime_ac/generators/Private.py index 1708128d1f..e4a42ccf2b 100644 --- a/Autocoders/Python/src/fprime_ac/generators/Private.py +++ b/Autocoders/Python/src/fprime_ac/generators/Private.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "Private.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "Private.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "Private.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "Private.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/Protected.py b/Autocoders/Python/src/fprime_ac/generators/Protected.py index d553a52090..af6a1a4112 100644 --- a/Autocoders/Python/src/fprime_ac/generators/Protected.py +++ b/Autocoders/Python/src/fprime_ac/generators/Protected.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "Protected.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "Protected.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "Protected.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "Protected.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/Public.py b/Autocoders/Python/src/fprime_ac/generators/Public.py index 7a03cb02d4..77a7fa51e1 100644 --- a/Autocoders/Python/src/fprime_ac/generators/Public.py +++ b/Autocoders/Python/src/fprime_ac/generators/Public.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "Public.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "Public.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "Public.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "Public.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/StartChannel.py b/Autocoders/Python/src/fprime_ac/generators/StartChannel.py index 5c6939ac79..e2c7dc9249 100644 --- a/Autocoders/Python/src/fprime_ac/generators/StartChannel.py +++ b/Autocoders/Python/src/fprime_ac/generators/StartChannel.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "startChannelVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "startChannelVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "startChannelVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "startChannelVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/StartCommand.py b/Autocoders/Python/src/fprime_ac/generators/StartCommand.py index 53a3a5496c..803d6202d0 100644 --- a/Autocoders/Python/src/fprime_ac/generators/StartCommand.py +++ b/Autocoders/Python/src/fprime_ac/generators/StartCommand.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "startCommandVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "startCommandVisit.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "startCommandVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "startCommandVisit.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/StartEvent.py b/Autocoders/Python/src/fprime_ac/generators/StartEvent.py index fa4c3e3f12..2f9913dd3c 100644 --- a/Autocoders/Python/src/fprime_ac/generators/StartEvent.py +++ b/Autocoders/Python/src/fprime_ac/generators/StartEvent.py @@ -79,7 +79,7 @@ def accept(self, visitor): DEBUG.error( "StartEvent.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "StartEvent.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -94,7 +94,7 @@ def addVisitor(self, visitor): DEBUG.error( "StartEvent.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "StartEvent.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/StartSource.py b/Autocoders/Python/src/fprime_ac/generators/StartSource.py index 88d511a2f0..e1832f7462 100644 --- a/Autocoders/Python/src/fprime_ac/generators/StartSource.py +++ b/Autocoders/Python/src/fprime_ac/generators/StartSource.py @@ -80,7 +80,7 @@ def accept(self, visitor): DEBUG.error( "StartSource.accept() - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "StartSource.accept() - the given visitor is not a subclass of AbstractVisitor!" ) @@ -95,7 +95,7 @@ def addVisitor(self, visitor): DEBUG.error( "StartSource.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) - raise Exception( + raise TypeError( "StartSource.addVisitor(v) - the given visitor is not a subclass of AbstractVisitor!" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/formatters.py b/Autocoders/Python/src/fprime_ac/generators/formatters.py index 80418ec56f..5b75678c24 100644 --- a/Autocoders/Python/src/fprime_ac/generators/formatters.py +++ b/Autocoders/Python/src/fprime_ac/generators/formatters.py @@ -103,14 +103,10 @@ def _getStartExcludingNewlines(self, line_list): Returns -1 if everything is a newline """ - count = 0 - - for item in line_list: + for count, item in enumerate(line_list): item = item.strip() if item != "": return count - count += 1 - return -1 def _getEndsExcludingNewlines(self, line_list): @@ -705,7 +701,7 @@ def opcodeStemName(self, id, name): "ERROR: DETECTED AN INVALID CHARACTER IN COMMAND STEM NAME (%s)." % name_string ) - raise Exception( + raise ValueError( "Fatal error, detected an invalid character in command stem name." ) # All is ok @@ -728,7 +724,7 @@ def opcodeStemNameValidate(self, id, cmd_name_list): for c in cmds: if sum([int(x == c) for x in cmds]) > 1: PRINT.info("ERROR: DETECTED %s COMMAND STEM NAME REPEATED." % c) - raise Exception("Error detected repeated command stem name.") + raise ValueError("Error detected repeated command stem name.") return True def evrNamePrefix(self, name): @@ -1078,15 +1074,13 @@ def formatFunCommentOldVersion(self, name, args, proto=True, indent=0): cpos = apos + type_max + 1 # place args and comments and put together the string. - i = 0 func_arg_list = [] - for a in format_func_list[1:]: + for i, a in enumerate(format_func_list[1:]): pad = (cpos - (apos + len(a.strip()))) * " " str = ( apad + a.strip() + pad + comment_list[i] + "\n" ) # + pad + comment_list[i] func_arg_list.append(str) - i += 1 # # print 'Last arg: ',func_arg_list[-1].replace(') ',');') # TODO: add switch so a ; is inserted - end of last arg after ). @@ -1119,14 +1113,14 @@ def formatFun(self, indent, one_line): "ERROR: No left paren in function name passed to formatFun: %s." % one_line ) - raise Exception("No left paren in function name passed to formatFun.") + raise ValueError("No left paren in function name passed to formatFun.") two_chunks = one_line.split("(") if len(two_chunks) != 2: PRINT.info( "ERROR: Too many left parens in name passed to formatFun: %s" % one_line ) - raise Exception("Too many left parens in name passed to formatFun.") + raise ValueError("Too many left parens in name passed to formatFun.") type_and_name = two_chunks[0] args = two_chunks[1] @@ -1216,11 +1210,9 @@ def argStringAlign(self, type_list, arg_list, pad_spaces=4): max_type_length = max(list(map(len, type_list))) - i = 0 - for type in type_list: + for i, type in enumerate(type_list): pad = (max_type_length + pad_spaces) - len(type) str = type + pad * " " + arg_list[i] - i += 1 str_list.append(str) return str_list @@ -1318,10 +1310,7 @@ def subThreadModuleFirstCap(self, mod_id): and no '_' in string form. """ mod_id_list = mod_id.strip("_").split("_") - if len(mod_id_list) == 1: - mod_id_cap = mod_id[0].upper() + mod_id[1:] - elif len(mod_id_list) == 2: - mod_id_cap = [x[0].upper() + x[1:] for x in mod_id_list] + mod_id_cap = [x[0].upper() + x[1:] for x in mod_id_list] # size of mod_id list error in subThreadDir method. mod_id_cap_str = "".join(mod_id_cap) return mod_id_cap_str diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/arrays/array_cpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/arrays/array_cpp.tmpl index 0883412e23..339443872b 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/arrays/array_cpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/arrays/array_cpp.tmpl @@ -18,8 +18,10 @@ \#include "${name}ArrayAc.hpp" -#if $namespace +#if $namespace_list != None + #for $namespace in $namespace_list namespace ${namespace} { + #end for #end if #if $type == "string": @@ -299,6 +301,8 @@ void ${name}::toString(Fw::StringBase& text) const { return status; } -#if $namespace -} +#if $namespace_list != None + #for $namespace in $reversed($namespace_list) +} // end namespace $namespace + #end for #end if diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/arrays/array_hpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/arrays/array_hpp.tmpl index 96c83429e1..d0adddeee8 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/arrays/array_hpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/arrays/array_hpp.tmpl @@ -11,11 +11,12 @@ // // ====================================================================== -\#ifndef ${namespace}_${name}_HPP -\#define ${namespace}_${name}_HPP + +\#ifndef ${namespace.upper().replace("::", "_")}_${name.upper()}_HPP_ +\#define ${namespace.upper().replace("::", "_")}_${name.upper()}_HPP_ \#include "Fw/Types/String.hpp" -\#include "Fw/Types/BasicTypes.hpp" +\#include \#include "Fw/Types/Serializable.hpp" #for $t in $include_headers: \#include <${t}> @@ -30,8 +31,10 @@ \#include <${t}> #end for -#if $namespace +#if $namespace_list != None + #for $namespace in $namespace_list namespace ${namespace} { + #end for #end if #if $comment //! $re.sub("\n *", "\n //! ", $comment) @@ -214,8 +217,10 @@ namespace ${namespace} { }; -#if $namespace -} +#if $namespace_list != None + #for $namespace in $reversed($namespace_list) +} // end namespace $namespace + #end for #end if #endif diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/component/cpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/component/cpp.tmpl index e475948005..56e4a59f0d 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/component/cpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/component/cpp.tmpl @@ -131,7 +131,7 @@ namespace ${namespace} { #end if get_${instance}_InputPort(NATIVE_INT_TYPE portNum) { - FW_ASSERT(portNum < this->getNum_${instance}_InputPorts(),static_cast(portNum)); + FW_ASSERT(portNum < this->getNum_${instance}_InputPorts(),static_cast(portNum)); return &this->m_${instance}_InputPort[portNum]; } @@ -157,7 +157,7 @@ namespace ${namespace} { #end if ) { - FW_ASSERT(portNum < this->getNum_${instance}_OutputPorts(),static_cast(portNum)); + FW_ASSERT(portNum < this->getNum_${instance}_OutputPorts(),static_cast(portNum)); #if $type == "Serial": this->m_${instance}_OutputPort[portNum].registerSerialPort(port); #else: @@ -189,7 +189,7 @@ namespace ${namespace} { #end if ) { - FW_ASSERT(portNum < this->getNum_${instance}_OutputPorts(),static_cast(portNum)); + FW_ASSERT(portNum < this->getNum_${instance}_OutputPorts(),static_cast(portNum)); return this->m_${instance}_OutputPort[portNum].registerSerialPort(port); } #if $role == "LogTextEvent": @@ -430,8 +430,8 @@ namespace ${namespace} { #for $instance, $type, $sync, $priority, $full, $role, $max_num in $input_ports: // Connect input port $instance for ( - NATIVE_INT_TYPE port = 0; - port < this->getNum_${instance}_InputPorts(); + PlatformIntType port = 0; + port < static_cast(this->getNum_${instance}_InputPorts()); port++ ) { @@ -447,7 +447,7 @@ namespace ${namespace} { (void) snprintf( portName, sizeof(portName), - "%s_${instance}_InputPort[%d]", + "%s_${instance}_InputPort[%" PRI_PlatformIntType "]", this->m_objName, port ); @@ -463,8 +463,8 @@ namespace ${namespace} { \#if FW_ENABLE_TEXT_LOGGING == 1 #end if for ( - NATIVE_INT_TYPE port = 0; - port < this->getNum_${instance}_OutputPorts(); + PlatformIntType port = 0; + port < static_cast(this->getNum_${instance}_OutputPorts()); port++ ) { this->m_${instance}_OutputPort[port].init(); @@ -474,7 +474,7 @@ namespace ${namespace} { (void) snprintf( portName, sizeof(portName), - "%s_${instance}_OutputPort[%d]", + "%s_${instance}_OutputPort[%" PRI_PlatformIntType "]", this->m_objName, port ); @@ -507,7 +507,7 @@ namespace ${namespace} { #end if FW_ASSERT( Os::Queue::QUEUE_OK == qStat, - static_cast(qStat) + static_cast(qStat) ); #end if @@ -538,7 +538,7 @@ namespace ${namespace} { Fw::SerializeBufferBase &Buffer ) { - FW_ASSERT(portNum < this->getNum_${instance}_OutputPorts(),static_cast(portNum)); + FW_ASSERT(portNum < this->getNum_${instance}_OutputPorts(),static_cast(portNum)); return this->m_${instance}_OutputPort[portNum].invokeSerial(Buffer); } #else @@ -552,7 +552,7 @@ namespace ${namespace} { ) { #end if - FW_ASSERT(portNum < this->getNum_${instance}_OutputPorts(),static_cast(portNum)); + FW_ASSERT(portNum < this->getNum_${instance}_OutputPorts(),static_cast(portNum)); #if $void_return: this->m_${instance}_OutputPort[portNum].invoke($args); #else: @@ -596,7 +596,7 @@ namespace ${namespace} { { FW_ASSERT( portNum < this->getNum_${instance}_OutputPorts(), - static_cast(portNum) + static_cast(portNum) ); return this->m_${instance}_OutputPort[portNum].isConnected(); } @@ -813,7 +813,7 @@ namespace ${namespace} { #end if FW_ASSERT ( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); // Fake port number to make message dequeue work @@ -821,25 +821,25 @@ namespace ${namespace} { _status = msg.serialize(port); FW_ASSERT ( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); _status = msg.serialize(opCode); FW_ASSERT ( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); _status = msg.serialize(cmdSeq); FW_ASSERT ( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); _status = msg.serialize(args); FW_ASSERT ( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); // send message @@ -859,7 +859,7 @@ namespace ${namespace} { #end if FW_ASSERT( qStatus == Os::Queue::QUEUE_OK, - static_cast(qStatus) + static_cast(qStatus) ); #end if @@ -925,7 +925,7 @@ namespace ${namespace} { #end if FW_ASSERT( _stat == Fw::FW_SERIALIZE_OK, - static_cast(_stat) + static_cast(_stat) ); FwChanIdType _id; @@ -1206,25 +1206,25 @@ namespace ${namespace} { _status = _logBuff.serialize(static_cast($len($args)+1)); FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); // For FATAL, add stack size of 4 and a dummy entry. No support for stacks yet. _status = _logBuff.serialize(static_cast(4)); FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); _status = _logBuff.serialize(static_cast(0)); FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); #else // Serialize the number of arguments _status = _logBuff.serialize(static_cast($len($args))); FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); #end if \#endif @@ -1235,7 +1235,7 @@ namespace ${namespace} { _zero_status = _logBuff.serialize(static_cast(0)); FW_ASSERT( _zero_status == Fw::FW_SERIALIZE_OK, - static_cast(_zero_status) + static_cast(_zero_status) ); \#endif #end if @@ -1247,7 +1247,7 @@ namespace ${namespace} { _status = _logBuff.serialize(static_cast(sizeof(FwEnumStoreType))); FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); \#endif @@ -1264,14 +1264,14 @@ namespace ${namespace} { ); FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); \#endif _status = _logBuff.serialize($arg_name); #end if FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); #end for @@ -1369,14 +1369,14 @@ namespace ${namespace} { _status = msg.serialize(static_cast(INT_IF_${ifname.upper})); FW_ASSERT ( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); // Fake port number to make message dequeue work _status = msg.serialize(static_cast(0)); FW_ASSERT ( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); #for $argname, $argtype, $comment, $typeinfo in $internal_interface_args[$ifname]: @@ -1385,7 +1385,7 @@ namespace ${namespace} { #else _status = msg.serialize($argname); #end if - FW_ASSERT(_status == Fw::FW_SERIALIZE_OK, static_cast(_status)); + FW_ASSERT(_status == Fw::FW_SERIALIZE_OK, static_cast(_status)); #end for // send message @@ -1405,7 +1405,7 @@ namespace ${namespace} { #end if FW_ASSERT( qStatus == Os::Queue::QUEUE_OK, - static_cast(qStatus) + static_cast(qStatus) ); } @@ -1481,21 +1481,21 @@ namespace ${namespace} { ); FW_ASSERT ( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); // serialize port number _status = msgSerBuff.serialize(portNum); FW_ASSERT ( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); // serialize buffer _status = msgSerBuff.serialize(buffer); FW_ASSERT ( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); // send message @@ -1515,7 +1515,7 @@ namespace ${namespace} { #end if FW_ASSERT( qStatus == Os::Queue::QUEUE_OK, - static_cast(qStatus) + static_cast(qStatus) ); #end if @@ -1583,7 +1583,7 @@ namespace ${namespace} { { // Make sure port number is valid - FW_ASSERT(portNum < this->getNum_${instance}_InputPorts(),static_cast(portNum)); + FW_ASSERT(portNum < this->getNum_${instance}_InputPorts(),static_cast(portNum)); #if not $void_return_type: ${return_type} retVal; #end if @@ -1607,13 +1607,13 @@ namespace ${namespace} { ); FW_ASSERT ( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); _status = msg.serialize(portNum); FW_ASSERT ( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); #set $args = $port_args[$instance] @@ -1628,7 +1628,7 @@ namespace ${namespace} { #end if FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); #end for @@ -1650,7 +1650,7 @@ namespace ${namespace} { #end if FW_ASSERT( qStatus == Os::Queue::QUEUE_OK, - static_cast(qStatus) + static_cast(qStatus) ); #else: @@ -1732,7 +1732,7 @@ namespace ${namespace} { Os::Queue::QueueStatus msgStatus = this->m_queue.receive(msg,priority,Os::Queue::QUEUE_BLOCKING); FW_ASSERT( msgStatus == Os::Queue::QUEUE_OK, - static_cast(msgStatus) + static_cast(msgStatus) ); #else Os::Queue::QueueStatus msgStatus = this->m_queue.receive(msg,priority,Os::Queue::QUEUE_NONBLOCKING); @@ -1741,7 +1741,7 @@ namespace ${namespace} { } else { FW_ASSERT( msgStatus == Os::Queue::QUEUE_OK, - static_cast(msgStatus) + static_cast(msgStatus) ); } #end if @@ -1753,7 +1753,7 @@ namespace ${namespace} { Fw::SerializeStatus deserStatus = msg.deserialize(desMsg); FW_ASSERT( deserStatus == Fw::FW_SERIALIZE_OK, - static_cast(deserStatus) + static_cast(deserStatus) ); MsgTypeEnum msgType = static_cast(desMsg); @@ -1766,7 +1766,7 @@ namespace ${namespace} { deserStatus = msg.deserialize(portNum); FW_ASSERT( deserStatus == Fw::FW_SERIALIZE_OK, - static_cast(deserStatus) + static_cast(deserStatus) ); switch (msgType) { @@ -1795,7 +1795,7 @@ namespace ${namespace} { #end if FW_ASSERT( deserStatus == Fw::FW_SERIALIZE_OK, - static_cast(deserStatus) + static_cast(deserStatus) ); #end for @@ -1806,7 +1806,7 @@ namespace ${namespace} { deserStatus = msg.deserialize(serHandBuff); FW_ASSERT( deserStatus == Fw::FW_SERIALIZE_OK, - static_cast(deserStatus) + static_cast(deserStatus) ); this->${instance}_handler(portNum, serHandBuff); #else: @@ -1846,7 +1846,7 @@ namespace ${namespace} { deserStatus = msg.deserialize(opCode); FW_ASSERT ( deserStatus == Fw::FW_SERIALIZE_OK, - static_cast(deserStatus) + static_cast(deserStatus) ); // Deserialize command sequence @@ -1854,7 +1854,7 @@ namespace ${namespace} { deserStatus = msg.deserialize(cmdSeq); FW_ASSERT ( deserStatus == Fw::FW_SERIALIZE_OK, - static_cast(deserStatus) + static_cast(deserStatus) ); // Deserialize command argument buffer @@ -1862,7 +1862,7 @@ namespace ${namespace} { deserStatus = msg.deserialize(args); FW_ASSERT ( deserStatus == Fw::FW_SERIALIZE_OK, - static_cast(deserStatus) + static_cast(deserStatus) ); // Reset buffer @@ -1939,7 +1939,7 @@ namespace ${namespace} { // Internal interfaces should always deserialize FW_ASSERT( Fw::FW_SERIALIZE_OK == deserStatus, - static_cast(deserStatus) + static_cast(deserStatus) ); #end for @@ -1947,7 +1947,7 @@ namespace ${namespace} { // That means the buffer size was incorrect. FW_ASSERT( msg.getBuffLeft() == 0, - static_cast(msg.getBuffLeft()) + static_cast(msg.getBuffLeft()) ); // Call handler function diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/component/hpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/component/hpp.tmpl index 01de274e1d..9c6ffba64f 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/component/hpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/component/hpp.tmpl @@ -7,8 +7,8 @@ // // ====================================================================== -\#ifndef ${name.upper()}_COMP_HPP_ -\#define ${name.upper()}_COMP_HPP_ +\#ifndef ${namespace.upper().replace("::", "_")}_${name.upper()}_COMP_HPP_ +\#define ${namespace.upper().replace("::", "_")}_${name.upper()}_COMP_HPP_ \#include \#include @@ -244,6 +244,7 @@ namespace ${namespace} { const char* compName = "" $doxygen_post_comment("Component name") ); + public: //! Initialize a ${name}ComponentBase object //! void init( @@ -259,6 +260,7 @@ namespace ${namespace} { #end if ); + PROTECTED: //! Destroy a ${name}ComponentBase object //! virtual ~${name}ComponentBase(); diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/enums/enum_cpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/enums/enum_cpp.tmpl index ac7a752582..6377f6de57 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/enums/enum_cpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/enums/enum_cpp.tmpl @@ -15,8 +15,10 @@ \#include "Fw/Types/Assert.hpp" \#include "${name}EnumAc.hpp" -#if $namespace +#if $namespace_list != None + #for $namespace in $namespace_list namespace ${namespace} { + #end for #end if // ---------------------------------------------------------------------- @@ -186,6 +188,8 @@ a == $item_value#slurp } \#endif -#if $namespace -} +#if $namespace_list != None + #for $namespace in $reversed($namespace_list) +} // end namespace $namespace + #end for #end if diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/enums/enum_hpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/enums/enum_hpp.tmpl index 2d9df6a7c0..3bd76c6aad 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/enums/enum_hpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/enums/enum_hpp.tmpl @@ -11,15 +11,17 @@ // // ====================================================================== -\#ifndef ${namespace}_${name}_HPP -\#define ${namespace}_${name}_HPP +\#ifndef ${namespace.upper().replace("::", "_")}_${name.upper()}_HPP_ +\#define ${namespace.upper().replace("::", "_")}_${name.upper()}_HPP_ \#include "Fw/Types/String.hpp" -\#include "Fw/Types/BasicTypes.hpp" +\#include \#include "Fw/Types/Serializable.hpp" -#if $namespace +#if $namespace_list != None + #for $namespace in $namespace_list namespace ${namespace} { + #end for #end if #if $comment //! $re.sub("\n *", "\n //! ", $comment) @@ -159,7 +161,9 @@ namespace ${namespace} { //! The enumeration value t e; }; -#if $namespace -} +#if $namespace_list != None + #for $namespace in $reversed($namespace_list) +} // end namespace $namespace + #end for #end if #endif diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/impl/cpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/impl/cpp.tmpl index 2fdb13bad1..3886c19e8b 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/impl/cpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/impl/cpp.tmpl @@ -6,7 +6,7 @@ \#include <${include_path}/${name}.hpp> -\#include "Fw/Types/BasicTypes.hpp" +\#include #if $namespace_list != None #for $namespace in $namespace_list @@ -26,20 +26,6 @@ $emit_non_port_params([ $param_compName ]) } - void ${name} :: - init( -$emit_non_port_params($params_init_cpp) - ) - { -#if $kind == "passive" - ${component_base}::init(instance); -#else if $needs_msg_size: - ${component_base}::init(queueDepth, msgSize, instance); -#else - ${component_base}::init(queueDepth, instance); -#end if - } - ${name} :: ~${name}() { diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/impl/hpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/impl/hpp.tmpl index d23277e8cd..3ac8d28a5f 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/impl/hpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/impl/hpp.tmpl @@ -31,12 +31,6 @@ namespace ${namespace} { $emit_non_port_params([ $param_compName ]) ); - //! Initialize object $name - //! - void init( -$emit_non_port_params($params_init_hpp) - ); - //! Destroy object $name //! ~${name}(); diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/port/finishPortCpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/port/finishPortCpp.tmpl index feee95aa01..c0aae49b91 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/port/finishPortCpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/port/finishPortCpp.tmpl @@ -50,11 +50,11 @@ ${return_type}Output${name}Port::invoke(${args_proto_string}) { _status = _buffer.serialize($arg[0]); #end if #set $num = $num + 1 - FW_ASSERT(Fw::FW_SERIALIZE_OK == _status,static_cast(_status)); + FW_ASSERT(Fw::FW_SERIALIZE_OK == _status,static_cast(_status)); #end for _status = this->m_serPort->invokeSerial(_buffer); - FW_ASSERT(Fw::FW_SERIALIZE_OK == _status,static_cast(_status)); + FW_ASSERT(Fw::FW_SERIALIZE_OK == _status,static_cast(_status)); } \#else } diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/port/includes1PortH.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/port/includes1PortH.tmpl index 47a7d3ec3f..c772e94d00 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/port/includes1PortH.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/port/includes1PortH.tmpl @@ -4,6 +4,6 @@ \#include \#include \#include -\#include +\#include \#include \#include diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/port/startPortH.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/port/startPortH.tmpl index eea95aad2a..5753839b16 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/port/startPortH.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/port/startPortH.tmpl @@ -5,6 +5,5 @@ * Author: ${user} * */ -\#ifndef ${name_space.upper().replace(":", "_")}_${name.upper()}_PORT_HPP_ -\#define ${name_space.upper().replace(":", "_")}_${name.upper()}_PORT_HPP_ - +\#ifndef ${name_space.upper().replace("::", "_")}_${name.upper()}_PORT_HPP_ +\#define ${name_space.upper().replace("::", "_")}_${name.upper()}_PORT_HPP_ diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/serialize/includes1SerialCpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/serialize/includes1SerialCpp.tmpl index 0d11c2af0e..02a96490a0 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/serialize/includes1SerialCpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/serialize/includes1SerialCpp.tmpl @@ -1,6 +1,6 @@ \#include <${include_path}/${namespace}${name}SerializableAc.hpp> \#include -\#include +\#include \#include \#if FW_SERIALIZABLE_TO_STRING \#include diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/serialize/includes1SerialH.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/serialize/includes1SerialH.tmpl index 394fb1a265..8593a29087 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/serialize/includes1SerialH.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/serialize/includes1SerialH.tmpl @@ -1,4 +1,4 @@ -\#include +\#include \#include \#if FW_SERIALIZABLE_TO_STRING \#include diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/test/CMakeLists.txt b/Autocoders/Python/src/fprime_ac/generators/templates/test/CMakeLists.txt index 437a242f2e..3994e67161 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/test/CMakeLists.txt +++ b/Autocoders/Python/src/fprime_ac/generators/templates/test/CMakeLists.txt @@ -3,6 +3,7 @@ include(autocoder/ai-shared) set(CHEETAH_TEMPLATES "${CMAKE_CURRENT_LIST_DIR}/cpp.tmpl" "${CMAKE_CURRENT_LIST_DIR}/hpp.tmpl" + "${CMAKE_CURRENT_LIST_DIR}/test_helpers.tmpl" "${CMAKE_CURRENT_LIST_DIR}/test_main.tmpl" ) diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/test/cpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/test/cpp.tmpl index a69e7c5744..6345cfcd2a 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/test/cpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/test/cpp.tmpl @@ -121,8 +121,8 @@ $emit_cpp_params([ $param_instance ]) \#if FW_ENABLE_TEXT_LOGGING == 1 #end if for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_from_${instance}(); + PlatformIntType _port = 0; + _port < static_cast(this->getNum_from_${instance}()); ++_port ) { @@ -139,7 +139,7 @@ $emit_cpp_params([ $param_instance ]) (void) snprintf( _portName, sizeof(_portName), - "%s_${port_name}[%d]", + "%s_${port_name}[%" PRI_PlatformIntType "]", this->m_objName, _port ); @@ -157,8 +157,8 @@ $emit_cpp_params([ $param_instance ]) // Initialize output port $instance for ( - NATIVE_INT_TYPE _port = 0; - _port < this->getNum_to_${instance}(); + PlatformIntType _port = 0; + _port < static_cast(this->getNum_to_${instance}()); ++_port ) { this->m_to_${instance}[_port].init(); @@ -168,7 +168,7 @@ $emit_cpp_params([ $param_instance ]) snprintf( _portName, sizeof(_portName), - "%s_to_${instance}[%d]", + "%s_to_${instance}[%" PRI_PlatformIntType "]", this->m_objName, _port ); @@ -222,7 +222,7 @@ $emit_cpp_params([ $param_instance ]) $emit_cpp_params([ $param_portNum, $param_port ]) ) { - FW_ASSERT(portNum < this->getNum_to_${instance}(),static_cast(portNum)); + FW_ASSERT(portNum < this->getNum_to_${instance}(),static_cast(portNum)); #if $type == "Serial": this->m_to_${instance}[portNum].registerSerialPort($instance); #else: @@ -259,11 +259,11 @@ $emit_cpp_port_params([ $param_portNum ] + $port_params[$instance]) ) #end if { - FW_ASSERT(portNum < this->getNum_to_${instance}(),static_cast(portNum)); + FW_ASSERT(portNum < this->getNum_to_${instance}(),static_cast(portNum)); #if $serial_type: this->m_to_${instance}[portNum].invokeSerial(Buffer); #else - FW_ASSERT(portNum < this->getNum_to_${instance}(),static_cast(portNum)); + FW_ASSERT(portNum < this->getNum_to_${instance}(),static_cast(portNum)); #if $void_return_type this->m_to_${instance}[portNum].invoke( #else: @@ -285,7 +285,7 @@ $emit_cpp_port_params([ $param_portNum ] + $port_params[$instance]) bool ${tester_base} :: isConnected_to_${instance}(const NATIVE_INT_TYPE portNum) { - FW_ASSERT(portNum < this->getNum_to_${instance}(), static_cast(portNum)); + FW_ASSERT(portNum < this->getNum_to_${instance}(), static_cast(portNum)); return this->m_to_${instance}[portNum].isConnected(); } @@ -308,7 +308,7 @@ $emit_cpp_port_params([ $param_portNum ] + $port_params[$instance]) #end if get_from_${instance}(const NATIVE_INT_TYPE portNum) { - FW_ASSERT(portNum < this->getNum_from_${instance}(),static_cast(portNum)); + FW_ASSERT(portNum < this->getNum_from_${instance}(),static_cast(portNum)); return &this->m_from_${instance}[portNum]; } #if $role == "LogTextEvent": @@ -378,7 +378,7 @@ $emit_cpp_port_params([ $param_callComp, $param_portNum] + $params) Fw::SerializeBufferBase &Buffer $doxygen_post_comment("The serialization buffer") ) { - FW_ASSERT(portNum < this->getNum_from_${instance}(),static_cast(portNum)); + FW_ASSERT(portNum < this->getNum_from_${instance}(),static_cast(portNum)); this->from_${instance}_handler( portNum, Buffer @@ -514,7 +514,7 @@ $emit_cpp_port_params([ $param_callComp, $param_portNum] + $params) _ret = _testerBase->m_param_${prm_name}_valid; FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); } break; @@ -559,7 +559,7 @@ $emit_cpp_port_params([ $param_callComp, $param_portNum] + $params) _status = val.deserialize(${prmname}Val); FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); FW_ASSERT( ${prmname}Val == @@ -569,7 +569,7 @@ $emit_cpp_port_params([ $param_callComp, $param_portNum] + $params) Fw::ParamString ${prmname}Val; _status = val.deserialize(${prmname}Val); FW_ASSERT( - _status == Fw::FW_SERIALIZE_OK,static_cast(_status) + _status == Fw::FW_SERIALIZE_OK,static_cast(_status) ); FW_ASSERT( ${prmname}Val == @@ -580,7 +580,7 @@ $emit_cpp_port_params([ $param_callComp, $param_portNum] + $params) _status = val.deserialize(${prmname}Val); FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); FW_ASSERT( ${prmname}Val == @@ -664,7 +664,7 @@ $emit_cpp_port_params([ $param_portNum ] + $port_params[$instance]) #end if ) { - FW_ASSERT(portNum < this->getNum_from_${instance}(),static_cast(portNum)); + FW_ASSERT(portNum < this->getNum_from_${instance}(),static_cast(portNum)); #if $void_params and $void_return_type: this->from_${instance}_handler(portNum); #else if $void_params @@ -725,7 +725,7 @@ $emit_cpp_params([ $param_instance, $param_cmdSeq ] + $get_command_params($mnemo #else _status = buff.serialize($arg_name); #end if - FW_ASSERT(_status == Fw::FW_SERIALIZE_OK,static_cast(_status)); + FW_ASSERT(_status == Fw::FW_SERIALIZE_OK,static_cast(_status)); #end for // Call output command port @@ -950,7 +950,7 @@ $emit_cpp_params([ $param_const_timeTag, $param_val ]) _status = args.deserialize(_numArgs); FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); // verify they match expected. #if $severity == "FATAL" @@ -960,14 +960,14 @@ $emit_cpp_params([ $param_const_timeTag, $param_val ]) _status = args.deserialize(stackArgLen); FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); FW_ASSERT(4 == stackArgLen,stackArgLen); U32 dummyStackArg; _status = args.deserialize(dummyStackArg); FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); FW_ASSERT(0 == dummyStackArg,dummyStackArg); #else @@ -983,7 +983,7 @@ $emit_cpp_params([ $param_const_timeTag, $param_val ]) _zero_status = args.deserialize(_noArgs); FW_ASSERT( _zero_status == Fw::FW_SERIALIZE_OK, - static_cast(_zero_status) + static_cast(_zero_status) ); \#endif #end if @@ -996,7 +996,7 @@ $emit_cpp_params([ $param_const_timeTag, $param_val ]) _status = args.deserialize(_argSize); FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); FW_ASSERT(_argSize == sizeof(FwEnumStoreType),_argSize,sizeof(FwEnumStoreType)); } @@ -1017,7 +1017,7 @@ $emit_cpp_params([ $param_const_timeTag, $param_val ]) _status = args.deserialize(_argSize); FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); FW_ASSERT(_argSize == sizeof(${type}),_argSize,sizeof(${type})); } @@ -1026,7 +1026,7 @@ $emit_cpp_params([ $param_const_timeTag, $param_val ]) #end if FW_ASSERT( _status == Fw::FW_SERIALIZE_OK, - static_cast(_status) + static_cast(_status) ); #end for @@ -1114,11 +1114,11 @@ $emit_cpp_params([ $param_const_timeTag, $param_val ]) fprintf( file, - "EVENT: (%d) (%d:%d,%d) %s: %s\n", + "EVENT: (%" PRI_FwEventIdType ") (%" PRI_FwTimeBaseStoreType ":%" PRIu32 ",%" PRIu32 ") %s: %s\n", e.id, - const_cast(e).timeTag.getTimeBase(), - const_cast(e).timeTag.getSeconds(), - const_cast(e).timeTag.getUSeconds(), + static_cast(e.timeTag.getTimeBase()), + e.timeTag.getSeconds(), + e.timeTag.getUSeconds(), severityString, e.text.toChar() ); diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/test/test_helpers.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/test/test_helpers.tmpl new file mode 100644 index 0000000000..034b5cc15e --- /dev/null +++ b/Autocoders/Python/src/fprime_ac/generators/templates/test/test_helpers.tmpl @@ -0,0 +1,127 @@ +// ====================================================================== +// \title $name/test/ut/TesterHelpers.cpp +// \author Auto-generated +// \brief cpp file for ${name} component test harness base class +// +// NOTE: this file was automatically generated +// +// ====================================================================== +\#include "Tester.hpp" + +#if $namespace_list != None + #for $namespace in $namespace_list +namespace ${namespace} { + #end for +#end if + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + void Tester :: + connectPorts() + { + +#for $instance, $type, $sync, $priority, $full, $role, $max_num in $typed_input_ports: + // $instance + #if $max_num == 1 or $max_num == "1": + this->connect_to_${instance}( + 0, + this->component.get_${instance}_InputPort(0) + ); + #else + #set LT = "<" + for (NATIVE_INT_TYPE i = 0; i $LT $max_num; ++i) { + this->connect_to_${instance}( + i, + this->component.get_${instance}_InputPort(i) + ); + } + #end if + +#end for +#for $instance, $type, $sync, $priority, $role, $max_num in $typed_output_ports: + // $instance + #if $max_num == 1 or $max_num == "1": + this->component.set_${instance}_OutputPort( + 0, + this->get_from_${instance}(0) + ); + #else + #set LT = "<" + for (NATIVE_INT_TYPE i = 0; i $LT $max_num; ++i) { + this->component.set_${instance}_OutputPort( + i, + this->get_from_${instance}(i) + ); + } + #end if + +#end for + +#if len($serial_output_ports) > 0: + // ---------------------------------------------------------------------- + // Connect serial output ports + // ---------------------------------------------------------------------- +#for $instance, $sync, $priority, $max_num in $serial_output_ports: + #if $max_num == 1 or $max_num == "1": + this->component.set_${instance}_OutputPort( + 0, + this->get_from_${instance}(0) + ); + #else + #set LT = "<" + for (NATIVE_INT_TYPE i = 0; i $LT $max_num; ++i) { + this->component.set_${instance}_OutputPort( + i, + this->get_from_${instance}(i) + ); + } + #end if + +#end for +#end if + +#if len($serial_input_ports) > 0: + // ---------------------------------------------------------------------- + // Connect serial input ports + // ---------------------------------------------------------------------- +#for $instance, $sync, $priority, $full, $max_num in $serial_input_ports: + // $instance + #if $max_num == 1 or $max_num == "1": + this->connect_to_${instance}( + 0, + this->component.get_${instance}_InputPort(0) + ); + #else + #set LT = "<" + for (NATIVE_INT_TYPE i = 0; i $LT $max_num; ++i) { + this->connect_to_${instance}( + i, + this->component.get_${instance}_InputPort(i) + ); + } + #end if + +#end for +#end if + + } + + void Tester :: + initComponents() + { + this->init(); + this->component.init( +#if $kind == "passive" + Tester::TEST_INSTANCE_ID +#else + Tester::TEST_INSTANCE_QUEUE_DEPTH, Tester::TEST_INSTANCE_ID +#end if + ); + } + +#if $namespace_list != None + #for $namespace in $reversed($namespace_list) +} // end namespace $namespace + #end for +#end if diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/test/test_main.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/test/test_main.tmpl index 2a31e9affe..00cfb25a6a 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/test/test_main.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/test/test_main.tmpl @@ -6,7 +6,11 @@ #for $test_name, $method_name in $test_cases TEST(Nominal, ${test_name}) { - Ref::Tester tester; + #if $namespace_list != None + #echo "::".join($namespace_list)#::Tester tester; + #else + Tester tester; + #end if tester.${method_name}(); } #end for diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/test_impl/cpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/test_impl/cpp.tmpl index 9cb8634b6a..959cb39386 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/test_impl/cpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/test_impl/cpp.tmpl @@ -6,12 +6,6 @@ \#include "Tester.hpp" -\#define INSTANCE 0 -\#define MAX_HISTORY_SIZE 10 -#if $kind != "passive": -\#define QUEUE_DEPTH 10 -#end if - #if $namespace_list != None #for $namespace in $namespace_list namespace ${namespace} { @@ -24,7 +18,7 @@ namespace ${namespace} { Tester :: Tester() : - ${gtest_base}("Tester", MAX_HISTORY_SIZE), + ${gtest_base}("Tester", Tester::MAX_HISTORY_SIZE), component("${name}") { this->initComponents(); @@ -85,112 +79,6 @@ $emit_port_params([ $param_portNum ] + $port_params[$instance]) #end for #end if - // ---------------------------------------------------------------------- - // Helper methods - // ---------------------------------------------------------------------- - - void Tester :: - connectPorts() - { - -#for $instance, $type, $sync, $priority, $full, $role, $max_num in $typed_input_ports: - // $instance - #if $max_num == 1 or $max_num == "1": - this->connect_to_${instance}( - 0, - this->component.get_${instance}_InputPort(0) - ); - #else - #set LT = "<" - for (NATIVE_INT_TYPE i = 0; i $LT $max_num; ++i) { - this->connect_to_${instance}( - i, - this->component.get_${instance}_InputPort(i) - ); - } - #end if - -#end for -#for $instance, $type, $sync, $priority, $role, $max_num in $typed_output_ports: - // $instance - #if $max_num == 1 or $max_num == "1": - this->component.set_${instance}_OutputPort( - 0, - this->get_from_${instance}(0) - ); - #else - #set LT = "<" - for (NATIVE_INT_TYPE i = 0; i $LT $max_num; ++i) { - this->component.set_${instance}_OutputPort( - i, - this->get_from_${instance}(i) - ); - } - #end if - -#end for - -#if len($serial_output_ports) > 0: - // ---------------------------------------------------------------------- - // Connect serial output ports - // ---------------------------------------------------------------------- -#for $instance, $sync, $priority, $max_num in $serial_output_ports: - #if $max_num == 1 or $max_num == "1": - this->component.set_${instance}_OutputPort( - 0, - this->get_from_${instance}(0) - ); - #else - #set LT = "<" - for (NATIVE_INT_TYPE i = 0; i $LT $max_num; ++i) { - this->component.set_${instance}_OutputPort( - i, - this->get_from_${instance}(i) - ); - } - #end if - -#end for -#end if - -#if len($serial_input_ports) > 0: - // ---------------------------------------------------------------------- - // Connect serial input ports - // ---------------------------------------------------------------------- -#for $instance, $sync, $priority, $full, $max_num in $serial_input_ports: - // $instance - #if $max_num == 1 or $max_num == "1": - this->connect_to_${instance}( - 0, - this->component.get_${instance}_InputPort(0) - ); - #else - #set LT = "<" - for (NATIVE_INT_TYPE i = 0; i $LT $max_num; ++i) { - this->connect_to_${instance}( - i, - this->component.get_${instance}_InputPort(i) - ); - } - #end if - -#end for -#end if - - } - - void Tester :: - initComponents() - { - this->init(); - this->component.init( -#if $kind == "passive" - INSTANCE -#else - QUEUE_DEPTH, INSTANCE -#end if - ); - } #if $namespace_list != None #for $namespace in $reversed($namespace_list) diff --git a/Autocoders/Python/src/fprime_ac/generators/templates/test_impl/hpp.tmpl b/Autocoders/Python/src/fprime_ac/generators/templates/test_impl/hpp.tmpl index 6f36bc8516..1230577320 100644 --- a/Autocoders/Python/src/fprime_ac/generators/templates/test_impl/hpp.tmpl +++ b/Autocoders/Python/src/fprime_ac/generators/templates/test_impl/hpp.tmpl @@ -25,6 +25,14 @@ namespace ${namespace} { // ---------------------------------------------------------------------- public: + // Maximum size of histories storing events, telemetry, and port outputs + static const NATIVE_INT_TYPE MAX_HISTORY_SIZE = 10; + // Instance ID supplied to the component instance under test + static const NATIVE_INT_TYPE TEST_INSTANCE_ID = 0; + #if $kind != "passive": + // Queue depth supplied to component instance under test + static const NATIVE_INT_TYPE TEST_INSTANCE_QUEUE_DEPTH = 10; + #end if //! Construct object Tester //! diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/AbstractVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/AbstractVisitor.py index 320528d6af..4c8b81a625 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/AbstractVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/AbstractVisitor.py @@ -67,7 +67,7 @@ def initFilesVisit(self, obj): Defined to generate files for generated code products. @param args: the instance of the concrete element to operation on. """ - raise Exception( + raise NotImplementedError( "# AbstractVisitor.initFilesVisit() - Implementation Error: you must supply your own concrete implementation." ) @@ -75,7 +75,7 @@ def startSourceFilesVisit(self, obj): """ Defined to generate starting static code within files. """ - raise Exception( + raise NotImplementedError( "# AbstractVisitor.startSourceFilesVisit() - Implementation Error: you must supply your own concrete implementation." ) @@ -85,7 +85,7 @@ def includes1Visit(self, obj): Usually used for the base classes but also for Port types @param args: the instance of the concrete element to operation on. """ - raise Exception( + raise NotImplementedError( "# AbstractVisitor.includesVisit1() - Implementation Error: you must supply your own concrete implementation." ) @@ -95,7 +95,7 @@ def includes2Visit(self, obj): Usually used for data type includes and system includes. @param args: the instance of the concrete element to operation on. """ - raise Exception( + raise NotImplementedError( "# AbstractVisitor.includesVisit2() - Implementation Error: you must supply your own concrete implementation." ) @@ -105,7 +105,7 @@ def namespaceVisit(self, obj): Also any pre-condition code is generated. @param args: the instance of the concrete element to operation on. """ - raise Exception( + raise NotImplementedError( "# AbstractVisitor.namespaceVisit() - Implementation Error: you must supply your own concrete implementation." ) @@ -114,7 +114,7 @@ def publicVisit(self, obj): Defined to generate public stuff within a class. @param args: the instance of the concrete element to operation on. """ - raise Exception( + raise NotImplementedError( "# AbstractVisitor.publicVisit() - Implementation Error: you must supply your own concrete implementation." ) @@ -123,7 +123,7 @@ def protectedVisit(self, obj): Defined to generate protected stuff within a class. @param args: the instance of the concrete element to operation on. """ - raise Exception( + raise NotImplementedError( "# AbstractVisitor.protectedVisit() - Implementation Error: you must supply your own concrete implementation." ) @@ -132,7 +132,7 @@ def privateVisit(self, obj): Defined to generate private stuff within a class. @param args: the instance of the concrete element to operation on. """ - raise Exception( + raise NotImplementedError( "# AbstractVisitor.privateVisit() - Implementation Error: you must supply your own concrete implementation." ) @@ -140,7 +140,7 @@ def finishSourceFilesVisit(self, obj): """ Defined to generate ending static code within files. """ - raise Exception( + raise NotImplementedError( "# AbstractVisitor.endSourceFilesVisit() - Implementation Error: you must supply your own concrete implementation." ) @@ -148,7 +148,7 @@ def DictStartVisit(self, obj): """ Defined to generate start of command Python class. """ - raise Exception( + raise NotImplementedError( "# DictStartVisit.startCommandVisit() - Implementation Error: you must supply your own concrete implementation." ) @@ -156,7 +156,7 @@ def DictHeaderVisit(self, obj): """ Defined to generate header for Python command class. """ - raise Exception( + raise NotImplementedError( "# DictStartVisit.commandHeaderVisit() - Implementation Error: you must supply your own concrete implementation." ) @@ -164,7 +164,7 @@ def DictBodyVisit(self, obj): """ Defined to generate body for Python command class. """ - raise Exception( + raise NotImplementedError( "# DictStartVisit.commandBodyVisit() - Implementation Error: you must supply your own concrete implementation." ) diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/ChannelVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/ChannelVisitor.py index 281e9b9126..4ac4574705 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/ChannelVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/ChannelVisitor.py @@ -99,18 +99,12 @@ def DictStartVisit(self, obj): if len(obj.get_ids()) == 1: pyfile = "{}/{}.py".format(output_dir, obj.get_name()) fd = open(pyfile, "w") - if fd is None: - raise Exception(f"Could not open {pyfile} file.") self.__fp.append(fd) else: - inst = 0 - for id in obj.get_ids(): + for inst, id in enumerate(obj.get_ids()): pyfile = "%s/%s_%d.py" % (output_dir, obj.get_name(), inst) - inst += 1 DEBUG.info(f"Open file: {pyfile}") fd = open(pyfile, "w") - if fd is None: - raise Exception(f"Could not open {pyfile} file.") DEBUG.info(f"Completed {pyfile} open") self.__fp.append(fd) @@ -118,23 +112,20 @@ def DictHeaderVisit(self, obj): """ Defined to generate header for channel python class. """ - inst = 0 - for id in obj.get_ids(): + for inst, id in enumerate(obj.get_ids()): c = ChannelHeader.ChannelHeader() d = datetime.datetime.now() c.date = d.strftime("%A, %d %B %Y") c.user = getuser() c.source = obj.get_xml_filename() self._writeTmpl(c, self.__fp[inst], "channelHeaderVisit") - inst += 1 def DictBodyVisit(self, obj): """ Defined to generate the body of the Python channel class @param obj: the instance of the channel model to operation on. """ - inst = 0 - for id in obj.get_ids(): + for inst, id in enumerate(obj.get_ids()): c = ChannelBody.ChannelBody() if len(obj.get_ids()) > 1: c.name = obj.get_name() + "_%d" % inst @@ -169,4 +160,3 @@ def DictBodyVisit(self, obj): self._writeTmpl(c, self.__fp[inst], "channelBodyVisit") self.__fp[inst].close() - inst += 1 diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/CommandVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/CommandVisitor.py index 8a820e71b7..3d7bffdcd1 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/CommandVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/CommandVisitor.py @@ -108,18 +108,12 @@ def DictStartVisit(self, obj): if len(obj.get_opcodes()) == 1: pyfile = "{}/{}.py".format(output_dir, obj.get_mnemonic()) fd = open(pyfile, "w") - if fd is None: - raise Exception(f"Could not open {pyfile} file.") self.__fp1.append(fd) else: - inst = 0 - for opcode in obj.get_opcodes(): + for inst, opcode in enumerate(obj.get_opcodes()): pyfile = "%s/%s_%d.py" % (output_dir, obj.get_mnemonic(), inst) - inst += 1 DEBUG.info(f"Open file: {pyfile}") fd = open(pyfile, "w") - if fd is None: - raise Exception(f"Could not open {pyfile} file.") DEBUG.info(f"Completed {pyfile} open") self.__fp1.append(fd) elif type(obj) is Parameter.Parameter: @@ -131,36 +125,26 @@ def DictStartVisit(self, obj): if len(obj.get_set_opcodes()) == 1: # set/save opcode numbers had better match if len(obj.get_set_opcodes()) != len(obj.get_save_opcodes()): - raise Exception("set/save opcode quantities do not match!") + raise ValueError("set/save opcode quantities do not match!") pyfile = "{}/{}_PRM_SET.py".format(output_dir, self.__stem) fd = open(pyfile, "w") - if fd is None: - raise Exception(f"Could not open {pyfile} file.") self.__fp1.append(fd) pyfile = "{}/{}_PRM_SAVE.py".format(output_dir, self.__stem) fd = open(pyfile, "w") - if fd is None: - raise Exception(f"Could not open {pyfile} file.") self.__fp2.append(fd) else: - inst = 0 - for opcode in obj.get_set_opcodes(): + for inst, opcode in enumerate(obj.get_set_opcodes()): pyfile = "%s/%s_%d_PRM_SET.py" % (output_dir, self.__stem, inst) DEBUG.info(f"Open file: {pyfile}") fd = open(pyfile, "w") - if fd is None: - raise Exception(f"Could not open {pyfile} file.") self.__fp1.append(fd) DEBUG.info(f"Completed {pyfile} open") pyfile = "%s/%s_%d_PRM_SAVE.py" % (output_dir, self.__stem, inst) DEBUG.info(f"Open file: {pyfile}") fd = open(pyfile, "w") - if fd is None: - raise Exception(f"Could not open {pyfile} file.") self.__fp2.append(fd) - inst += 1 DEBUG.info(f"Completed {pyfile} open") else: @@ -175,38 +159,32 @@ def DictHeaderVisit(self, obj): @param obj: the instance of the command model to visit. """ if type(obj) is Command.Command: - inst = 0 - for opcode in obj.get_opcodes(): + for inst, opcode in enumerate(obj.get_opcodes()): c = CommandHeader.CommandHeader() d = datetime.datetime.now() c.date = d.strftime("%A, %d %B %Y") c.user = getuser() c.source = obj.get_xml_filename() self._writeTmpl(c, self.__fp1[inst], "commandHeaderVisit") - inst += 1 elif type(obj) is Parameter.Parameter: # SET Command header - inst = 0 - for opcode in obj.get_set_opcodes(): + for inst, opcode in enumerate(obj.get_set_opcodes()): c = CommandHeader.CommandHeader() d = datetime.datetime.now() c.date = d.strftime("%A, %d %B %Y") c.user = getuser() c.source = obj.get_xml_filename() self._writeTmpl(c, self.__fp1[inst], "commandHeaderVisit") - inst += 1 # SAVE Command header - inst = 0 - for opcode in obj.get_save_opcodes(): + for inst, opcode in enumerate(obj.get_save_opcodes()): c = CommandHeader.CommandHeader() d = datetime.datetime.now() c.date = d.strftime("%A, %d %B %Y") c.user = getuser() c.source = obj.get_xml_filename() self._writeTmpl(c, self.__fp2[inst], "commandHeaderVisit") - inst += 1 def DictBodyVisit(self, obj): """ @@ -214,8 +192,7 @@ def DictBodyVisit(self, obj): @param obj: the instance of the command model to operation on. """ if type(obj) is Command.Command: - inst = 0 - for opcode in obj.get_opcodes(): + for inst, opcode in enumerate(obj.get_opcodes()): c = CommandBody.CommandBody() # only add the suffix if there is more than one opcode per command if len(obj.get_opcodes()) > 1: @@ -247,10 +224,8 @@ def DictBodyVisit(self, obj): ) self._writeTmpl(c, self.__fp1[inst], "commandBodyVisit") self.__fp1[inst].close() - inst += 1 if type(obj) is Parameter.Parameter: - inst = 0 - for opcode in obj.get_set_opcodes(): + for inst, opcode in enumerate(obj.get_set_opcodes()): # Set Command c = CommandBody.CommandBody() if len(obj.get_set_opcodes()) > 1: @@ -279,10 +254,8 @@ def DictBodyVisit(self, obj): c.arglist.append((obj.get_name(), obj.get_comment(), type_string)) self._writeTmpl(c, self.__fp1[inst], "commandBodyVisit") self.__fp1[inst].close() - inst += 1 - inst = 0 - for opcode in obj.get_save_opcodes(): + for inst, opcode in enumerate(obj.get_save_opcodes()): # Save Command c = CommandBody.CommandBody() if len(obj.get_save_opcodes()) > 1: @@ -298,4 +271,3 @@ def DictBodyVisit(self, obj): self._writeTmpl(c, self.__fp2[inst], "commandBodyVisit") self.__fp2[inst].close() - inst += 1 diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/ComponentVisitorBase.py b/Autocoders/Python/src/fprime_ac/generators/visitors/ComponentVisitorBase.py index d5a8dece3a..c4285a01c5 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/ComponentVisitorBase.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/ComponentVisitorBase.py @@ -379,12 +379,10 @@ def g(xxx_todo_changeme3): if len(opcodes) == 1: return f"CMD_{mnemonic.upper()}" else: - mlist = [] - inst = 0 - for opcode in opcodes: - mlist.append("CMD_" + mnemonic.upper() + "_%d" % inst) - inst += 1 - return mlist + return [ + f"CMD_{mnemonic.upper()}_{inst}" + for inst, opcode in enumerate(opcodes) + ] else: return None @@ -752,8 +750,10 @@ def initPreamble(self, obj, c): c.component_base = c.name() + "ComponentBase" if obj.get_namespace() is None: c.namespace_list = None + c.namespace = "" else: c.namespace_list = obj.get_namespace().split("::") + c.namespace = obj.get_namespace() c.user = getuser() c.args_string = self.argsString c.doxygen_pre_comment = self.doxygenPreComment @@ -865,8 +865,6 @@ def openFile(self, filename): """ DEBUG.info("Open file: %s" % filename) self.__fp = open(filename, "w") - if self.__fp is None: - raise Exception("Could not open file %s") % filename DEBUG.info("Completed") def initFilesVisit(self, obj): diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/EventVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/EventVisitor.py index bf05a074b5..27ee38b47f 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/EventVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/EventVisitor.py @@ -101,8 +101,6 @@ def DictStartVisit(self, obj): if len(obj.get_ids()) == 1: pyfile = "{}/{}.py".format(output_dir, obj.get_name()) fd = open(pyfile, "w") - if fd is None: - raise Exception(f"Could not open {pyfile} file.") self.__fp.append(fd) else: inst = 0 @@ -111,8 +109,6 @@ def DictStartVisit(self, obj): inst += 1 DEBUG.info(f"Open file: {pyfile}") fd = open(pyfile, "w") - if fd is None: - raise Exception(f"Could not open {pyfile} file.") DEBUG.info(f"Completed {pyfile} open") self.__fp.append(fd) @@ -121,23 +117,20 @@ def DictHeaderVisit(self, obj): Defined to generate header for event python class. @param obj: the instance of the event model to operation on. """ - inst = 0 - for id in obj.get_ids(): + for inst, id in enumerate(obj.get_ids()): c = EventHeader.EventHeader() d = datetime.datetime.now() c.date = d.strftime("%A, %d %B %Y") c.user = getuser() c.source = obj.get_xml_filename() self._writeTmpl(c, self.__fp[inst], "eventHeaderVisit") - inst += 1 def DictBodyVisit(self, obj): """ Defined to generate the body of the Python event class @param obj: the instance of the event model to operation on. """ - inst = 0 - for id in obj.get_ids(): + for inst, id in enumerate(obj.get_ids()): c = EventBody.EventBody() if len(obj.get_ids()) > 1: c.name = obj.get_name() + "_%d" % inst @@ -151,9 +144,7 @@ def DictBodyVisit(self, obj): c.arglist = [] c.ser_import_list = [] - arg_num = 0 - - for arg_obj in obj.get_args(): + for arg_num, arg_obj in enumerate(obj.get_args()): n = arg_obj.get_name() t = arg_obj.get_type() s = arg_obj.get_size() @@ -185,7 +176,5 @@ def DictBodyVisit(self, obj): c.format_string = format_string c.arglist.append((n, d, type_string)) - arg_num += 1 self._writeTmpl(c, self.__fp[inst], "eventBodyVisit") self.__fp[inst].close() - inst += 1 diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/GTestCppVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/GTestCppVisitor.py index adf0c382ca..b0a4dac6b7 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/GTestCppVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/GTestCppVisitor.py @@ -40,8 +40,9 @@ def startSourceFilesVisit(self, obj): c = cpp.cpp() self.initGTest(obj, c) c.emit_cpp_params = self.emitCppParams - c.file_message = ' << " File: " << __callSiteFileName << "\\n"\n' - c.line_message = ' << " Line: " << __callSiteLineNumber << "\\n"' - c.failure_message = '<< "\\n"\n' + c.file_message + c.line_message + c.file_and_line_message = ( + ' << __callSiteFileName << ":" << __callSiteLineNumber << "\\n"' + ) + c.failure_message = '<< "\\n"\n' + c.file_and_line_message c.LTLT = "<<" self._writeTmpl(c, "startSourceFilesVisit") diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/GTestHVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/GTestHVisitor.py index 32c19fea35..d584448e2d 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/GTestHVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/GTestHVisitor.py @@ -48,8 +48,7 @@ def startSourceFilesVisit(self, obj): self.initGTest(obj, c) c.emit_hpp_params = self.emitHppParams c.emit_macro_params = self.emitMacroParams - c.file_message = ' << " File: " << __FILE__ << "\\n" \\\n' - c.line_message = ' << " Line: " << __LINE__ << "\\n"' - c.failure_message = '<< "\\n" \\\n' + c.file_message + c.line_message + c.file_and_line_message = ' << __FILE__ << ":" << __LINE__ << "\\n"' + c.failure_message = '<< "\\n" \\\n' + c.file_and_line_message c.LTLT = "<<" self._writeTmpl(c, "startSourceFilesVisit") diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceChannelVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceChannelVisitor.py index 958a91fd61..ed066dcf1b 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceChannelVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceChannelVisitor.py @@ -125,8 +125,6 @@ def DictStartVisit(self, obj, topology_model): pyfile = "{}/{}.py".format(output_dir, fname) DEBUG.info("Open file: {}".format(pyfile)) fd = open(pyfile, "w") - if fd is None: - raise Exception("Could not open {} file.".format(pyfile)) DEBUG.info("Completed {} open".format(pyfile)) self.__fp[fname] = fd @@ -176,7 +174,7 @@ def DictBodyVisit(self, obj, topology_model): c.name = fname if len(obj.get_ids()) > 1: - raise Exception( + raise ValueError( "There is more than one event id when creating dictionaries. Check xml of {} or see if multiple explicit IDs exist in the AcConstants.ini file".format( fname ) diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceCommandVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceCommandVisitor.py index 9e36eaf9ec..55a70fb6b5 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceCommandVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceCommandVisitor.py @@ -138,8 +138,6 @@ def DictStartVisit(self, obj, topology_model): pyfile = "{}/{}.py".format(output_dir, fname) DEBUG.info("Open file: {}".format(pyfile)) fd = open(pyfile, "w") - if fd is None: - raise Exception("Could not open {} file.".format(pyfile)) DEBUG.info("Completed {} open".format(pyfile)) self.__fp1[fname] = fd @@ -164,16 +162,12 @@ def DictStartVisit(self, obj, topology_model): pyfile = "{}/{}_PRM_SET.py".format(output_dir, fname) DEBUG.info("Open file: {}".format(pyfile)) fd = open(pyfile, "w") - if fd is None: - raise Exception("Could not open {} file.".format(pyfile)) self.__fp1[fname] = fd DEBUG.info("Completed {} open".format(pyfile)) pyfile = "{}/{}_PRM_SAVE.py".format(output_dir, fname) DEBUG.info("Open file: {}".format(pyfile)) fd = open(pyfile, "w") - if fd is None: - raise Exception("Could not open {} file.".format(pyfile)) self.__fp2[fname] = fd DEBUG.info("Completed {} open".format(pyfile)) diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceEventVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceEventVisitor.py index 41b82789a0..8c77c2a38e 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceEventVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceEventVisitor.py @@ -127,8 +127,6 @@ def DictStartVisit(self, obj, topology_model): pyfile = "{}/{}.py".format(output_dir, fname) DEBUG.info("Open file: {}".format(pyfile)) fd = open(pyfile, "w") - if fd is None: - raise Exception("Could not open {} file.".format(pyfile)) DEBUG.info("Completed {} open".format(pyfile)) self.__fp[fname] = fd @@ -179,7 +177,7 @@ def DictBodyVisit(self, obj, topology_model): c.name = fname if len(obj.get_ids()) > 1: - raise Exception( + raise ValueError( "There is more than one event id when creating dictionaries. Check xml of {} or see if multiple explicit IDs exist in the AcConstants.ini file".format( fname ) @@ -196,9 +194,7 @@ def DictBodyVisit(self, obj, topology_model): c.arglist = [] c.ser_import_list = [] - arg_num = 0 - - for arg_obj in obj.get_args(): + for arg_num, arg_obj in enumerate(obj.get_args()): n = arg_obj.get_name() t = arg_obj.get_type() s = arg_obj.get_size() @@ -230,6 +226,5 @@ def DictBodyVisit(self, obj, topology_model): c.format_string = format_string c.arglist.append((n, d, type_string)) - arg_num += 1 self._writeTmpl(c, self.__fp[fname], "eventBodyVisit") self.__fp[fname].close() diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceSerializableVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceSerializableVisitor.py index 71ee865989..cd9a5ac663 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceSerializableVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceSerializableVisitor.py @@ -189,8 +189,6 @@ def initFilesVisit(self, obj): # Open file for writing here... DEBUG.info(f"Open file: {pyfile}") self.__fp = open(pyfile, "w") - if self.__fp is None: - raise Exception("Could not open %s file.") % pyfile DEBUG.info("Completed") def startSourceFilesVisit(self, obj): diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceTopologyCppVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceTopologyCppVisitor.py index 56fead0266..060f53c35b 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceTopologyCppVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceTopologyCppVisitor.py @@ -128,8 +128,6 @@ def initFilesVisit(self, obj): # Open file for writing here... DEBUG.info("Open file: %s" % filename) self.__fp = open(filename, "w") - if self.__fp is None: - raise Exception("Could not open %s file.") % filename DEBUG.info("Completed") else: PRINT.info("ERROR: NO COMPONENTS FOUND IN TOPOLOGY XML FILE...") diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceTopologyHVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceTopologyHVisitor.py index e600788a35..97e5a923a2 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceTopologyHVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/InstanceTopologyHVisitor.py @@ -128,8 +128,6 @@ def initFilesVisit(self, obj): # Open file for writing here... DEBUG.info("Open file: %s" % filename) self.__fp = open(filename, "w") - if self.__fp is None: - raise Exception("Could not open %s file.") % filename DEBUG.info("Completed") else: PRINT.info("ERROR: NO COMPONENTS FOUND IN TOPOLOGY XML FILE...") diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/PortCppVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/PortCppVisitor.py index 8344accbaa..dedd5ff0b8 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/PortCppVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/PortCppVisitor.py @@ -195,8 +195,6 @@ def initFilesVisit(self, obj): # Open file for writing here... DEBUG.info("Open file: %s" % filename) self.__fp = open(filename, "w") - if self.__fp is None: - raise Exception("Could not open %s file.") % filename DEBUG.info("Completed") def startSourceFilesVisit(self, obj): diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/PortHVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/PortHVisitor.py index 7ec1f26d56..bb9cd72f24 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/PortHVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/PortHVisitor.py @@ -176,10 +176,18 @@ def _get_args_sum_string(self, obj): "F32", "F64", "bool", - "FwOpcodeType", + "FwBuffSizeType", "FwChanIdType", + "FwEnumStoreType", "FwEventIdType", + "FwIndexType", + "FwOpcodeType", + "FwPacketDescriptorType", "FwPrmIdType", + "FwSizeType", + "FwTimeBaseStoreType", + "FwTimeContextStoreType", + "FwTlmPacketizeIdType", "NATIVE_INT_TYPE", "NATIVE_UINT_TYPE", "POINTER_CAST", @@ -255,8 +263,6 @@ def initFilesVisit(self, obj): # Open file for writing here... DEBUG.info("Open file: %s" % filename) self.__fp = open(filename, "w") - if self.__fp is None: - raise Exception("Could not open %s file.") % filename DEBUG.info("Completed") def startSourceFilesVisit(self, obj): diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/SerialCppVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/SerialCppVisitor.py index d96d1ea0b1..ba45be60e4 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/SerialCppVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/SerialCppVisitor.py @@ -250,8 +250,6 @@ def initFilesVisit(self, obj): # Open file for writing here... DEBUG.info("Open file: %s" % filename) self.__fp = open(filename, "w") - if self.__fp is None: - raise Exception("Could not open %s file.") % filename DEBUG.info("Completed") def startSourceFilesVisit(self, obj): diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/SerialHVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/SerialHVisitor.py index 7cb9fcecc2..586d4fef5d 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/SerialHVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/SerialHVisitor.py @@ -256,8 +256,6 @@ def initFilesVisit(self, obj): # Open file for writing here... DEBUG.info("Open file: %s" % filename) self.__fp = open(filename, "w") - if self.__fp is None: - raise Exception("Could not open %s file.") % filename DEBUG.info("Completed") def startSourceFilesVisit(self, obj): diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/SerializableVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/SerializableVisitor.py index bdedd2a9e8..2880d1773e 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/SerializableVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/SerializableVisitor.py @@ -189,8 +189,6 @@ def initFilesVisit(self, obj): # Open file for writing here... DEBUG.info(f"Open file: {pyfile}") self.__fp = open(pyfile, "w") - if self.__fp is None: - raise Exception("Could not open %s file.") % pyfile DEBUG.info("Completed") def startSourceFilesVisit(self, obj): diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/TestImplCppHelpersVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/TestImplCppHelpersVisitor.py new file mode 100644 index 0000000000..f4fdcfbd77 --- /dev/null +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/TestImplCppHelpersVisitor.py @@ -0,0 +1,47 @@ +# =============================================================================== +# NAME: TestImplCppHelpersVisitor.py +# +# DESCRIPTION: A visitor class for generating test implementation cpp files. +# +# AUTHOR: lestarch +# DATE CREATED: November 28, 2022 +# +# Copyright 2015, California Institute of Technology. +# ALL RIGHTS RESERVED. U.S. Government Sponsorship acknowledged. +# =============================================================================== +import sys + +from fprime_ac.generators.visitors import TestImplVisitorBase + +try: + from fprime_ac.generators.templates.test import test_helpers +except ImportError: + print("ERROR: must generate python templates first.") + sys.exit(-1) + + +class TestImplCppHelpersVisitor(TestImplVisitorBase.TestImplVisitorBase): + """ + A visitor class for generating test implementation cpp files. + """ + + def __init__(self): + super().__init__() + self.initBase("TestImplCpp") + + def emitPortParams(self, params): + return self.emitPortParamsCpp(8, params) + + def emitNonPortParams(self, params): + return self.emitNonPortParamsCpp(8, params) + + def initFilesVisit(self, obj): + self.openFile("TesterHelpers.cpp") + + def startSourceFilesVisit(self, obj): + c = test_helpers.test_helpers() + self.init(obj, c) + self.initTestImpl(obj, c) + c.emit_port_params = self.emitPortParams + c.emit_non_port_params = self.emitNonPortParams + self._writeTmpl(c, "startSourceFilesVisit") diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/TopologyCppVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/TopologyCppVisitor.py index 08040a761c..448523d819 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/TopologyCppVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/TopologyCppVisitor.py @@ -128,8 +128,6 @@ def initFilesVisit(self, obj): # Open file for writing here... DEBUG.info("Open file: %s" % filename) self.__fp = open(filename, "w") - if self.__fp is None: - raise Exception("Could not open %s file.") % filename DEBUG.info("Completed") else: PRINT.info("ERROR: NO COMPONENTS FOUND IN TOPOLOGY XML FILE...") diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/TopologyHVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/TopologyHVisitor.py index ba1f5f9335..2ea6369d80 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/TopologyHVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/TopologyHVisitor.py @@ -128,8 +128,6 @@ def initFilesVisit(self, obj): # Open file for writing here... DEBUG.info("Open file: %s" % filename) self.__fp = open(filename, "w") - if self.__fp is None: - raise Exception("Could not open %s file.") % filename DEBUG.info("Completed") else: PRINT.info("ERROR: NO COMPONENTS FOUND IN TOPOLOGY XML FILE...") diff --git a/Autocoders/Python/src/fprime_ac/generators/visitors/TopologyIDVisitor.py b/Autocoders/Python/src/fprime_ac/generators/visitors/TopologyIDVisitor.py index 31e4d4420a..e0f9178fd1 100644 --- a/Autocoders/Python/src/fprime_ac/generators/visitors/TopologyIDVisitor.py +++ b/Autocoders/Python/src/fprime_ac/generators/visitors/TopologyIDVisitor.py @@ -115,8 +115,6 @@ def initFilesVisit(self, obj): # Open file for writing here... DEBUG.info("Open file: %s" % filename) self.__fp = open(filename, "w") - if self.__fp is None: - raise Exception("Could not open %s file.") % filename DEBUG.info("Completed") else: PRINT.info("ERROR: NO COMPONENTS FOUND IN TOPOLOGY XML FILE...") diff --git a/Autocoders/Python/src/fprime_ac/models/Arg.py b/Autocoders/Python/src/fprime_ac/models/Arg.py index 08447cf7e1..19f6efd9a9 100644 --- a/Autocoders/Python/src/fprime_ac/models/Arg.py +++ b/Autocoders/Python/src/fprime_ac/models/Arg.py @@ -45,7 +45,7 @@ def __init__(self, name, atype, modifier, size=None, comment=None): @param type: Type of arg (must have supporting include xml) @param modifier: Modification of the argument (i.e. pointer or reference) @param size: size of array of type (string or buffer) - @param comment: A single or multline comment + @param comment: A single or multiline comment """ self.__name = name self.__type = atype diff --git a/Autocoders/Python/src/fprime_ac/parsers/XmlComponentParser.py b/Autocoders/Python/src/fprime_ac/parsers/XmlComponentParser.py index fca03ad593..f2b92d5ff5 100644 --- a/Autocoders/Python/src/fprime_ac/parsers/XmlComponentParser.py +++ b/Autocoders/Python/src/fprime_ac/parsers/XmlComponentParser.py @@ -95,8 +95,8 @@ def __init__(self, xml_file=None): else: self.__const_parser = None - xml_parser = etree.XMLParser(remove_comments=True) - element_tree = etree.parse(fd, parser=xml_parser) + self.__xml_parser = etree.XMLParser(remove_comments=True) + element_tree = etree.parse(fd, parser=self.__xml_parser) fd.close() # Close the file, which is only used for the parsing above # Validate against current schema. if more are imported later in the process, they will be reevaluated @@ -159,16 +159,14 @@ def __init__(self, xml_file=None): for comp_tag in component: if comp_tag.tag == "comment": self.__component.set_comment(comp_tag.text.strip()) - elif comp_tag.tag == "include_header": - self.__include_header_files.append(comp_tag.text) - elif comp_tag.tag == "import_port_type": - self.__import_port_type_files.append(comp_tag.text) - elif comp_tag.tag == "import_serializable_type": - self.__import_serializable_type_files.append(comp_tag.text) - elif comp_tag.tag == "import_enum_type": - self.__import_enum_type_files.append(comp_tag.text) - elif comp_tag.tag == "import_array_type": - self.__import_array_type_files.append(comp_tag.text) + elif comp_tag.tag in ( + "include_header", + "import_port_type", + "import_serializable_type", + "import_enum_type", + "import_array_type", + ): + self.__process_import_tag(comp_tag) elif comp_tag.tag == "import_dictionary": try: dict_file = locate_build_root(comp_tag.text) @@ -180,7 +178,7 @@ def __init__(self, xml_file=None): PRINT.info("Reading external dictionary %s" % dict_file) dict_fd = open(dict_file) _ = etree.XMLParser(remove_comments=True) - dict_element_tree = etree.parse(dict_fd, parser=xml_parser) + dict_element_tree = etree.parse(dict_fd, parser=self.__xml_parser) component.append(dict_element_tree.getroot()) @@ -848,7 +846,7 @@ def __init__(self, xml_file=None): else: PRINT.info( "%s: Invalid tag %s in parameter %s" - % (xml_file, comment.tag, n) + % (xml_file, parameter_tag.tag, n) ) sys.exit(-1) self.__parameters.append(parameter_obj) @@ -1129,6 +1127,37 @@ def __init__(self, xml_file=None): # PRINT.info("WARNING: Found namespace qualifier in port type definition (name=%s, type=%s) using namespace specified in XXXPortAi.xml file." % (n,t)) p.set_type(t.split("::")[-1]) + def __recursive_import_process(self, comp_tag): + try: + f = locate_build_root(comp_tag.text) + except (BuildRootMissingException, BuildRootCollisionException) as bre: + stri = "ERROR: Could not find specified dictionary XML file. {}. Error: {}".format( + comp_tag.text, str(bre) + ) + raise OSError(stri) + + fd = open(f) + _ = etree.XMLParser(remove_comments=True) + element_tree = etree.parse(fd, parser=self.__xml_parser) + + for child_tag in element_tree.getroot(): + self.__process_import_tag(child_tag) + + def __process_import_tag(self, comp_tag): + if comp_tag.tag == "include_header": + self.__include_header_files.append(comp_tag.text) + elif comp_tag.tag == "import_port_type": + self.__import_port_type_files.append(comp_tag.text) + self.__recursive_import_process(comp_tag) + elif comp_tag.tag == "import_serializable_type": + self.__import_serializable_type_files.append(comp_tag.text) + self.__recursive_import_process(comp_tag) + elif comp_tag.tag == "import_enum_type": + self.__import_enum_type_files.append(comp_tag.text) + elif comp_tag.tag == "import_array_type": + self.__import_array_type_files.append(comp_tag.text) + self.__recursive_import_process(comp_tag) + def __generate_port_from_role(self, role): special_ports = self.Config._ConfigManager__prop["special_ports"] @@ -1383,8 +1412,8 @@ def __init__( @param name: Name of port (each instance must be unique). @param direction: Direction of data flow (must be input or output) @param type: Type of port (must have supporting include xml) - @param sync: Kind of port (must be one of: asynch, synch, or guarded) - @param comment: A single or multline comment + @param sync: Kind of port (must be one of: async, sync, or guarded) + @param comment: A single or multiline comment """ # TODO: ADD NAMESPACE self.__name = name diff --git a/Autocoders/Python/src/fprime_ac/parsers/XmlPortsParser.py b/Autocoders/Python/src/fprime_ac/parsers/XmlPortsParser.py index 4db40f9e6a..8b09211425 100644 --- a/Autocoders/Python/src/fprime_ac/parsers/XmlPortsParser.py +++ b/Autocoders/Python/src/fprime_ac/parsers/XmlPortsParser.py @@ -304,7 +304,7 @@ def __init__(self, name, atype, modifier, size=None, comment=None): @param type: Type of arg (must have supporting include xml) @param modifier: Whether argument is passed by value, reference, or pointer @param size: size of array for string and buffer - @param comment: A single or multline comment + @param comment: A single or multiline comment """ self.__name = name self.__type = atype diff --git a/Autocoders/Python/src/fprime_ac/parsers/XmlSerializeParser.py b/Autocoders/Python/src/fprime_ac/parsers/XmlSerializeParser.py index 2b78c4a919..a8132f4e3c 100644 --- a/Autocoders/Python/src/fprime_ac/parsers/XmlSerializeParser.py +++ b/Autocoders/Python/src/fprime_ac/parsers/XmlSerializeParser.py @@ -320,6 +320,6 @@ def get_comment(self): def get_members(self): """ - Returns a list of member (name, type, optional size, optional format, optional comment) needed. + Returns a list of member (name, type, optional array size, optional size, optional format, optional comment) needed. """ return self.__members diff --git a/Autocoders/Python/src/fprime_ac/utils/ArrayGenerator.py b/Autocoders/Python/src/fprime_ac/utils/ArrayGenerator.py index 5751c64c31..672b735d11 100644 --- a/Autocoders/Python/src/fprime_ac/utils/ArrayGenerator.py +++ b/Autocoders/Python/src/fprime_ac/utils/ArrayGenerator.py @@ -45,6 +45,7 @@ def write_template( c, name, namespace, + namespace_list, arr_type, arr_typeinfo, arr_size, @@ -64,6 +65,7 @@ def write_template( """ c.name = name c.namespace = namespace + c.namespace_list = namespace_list c.type = arr_type c.typeinfo = arr_typeinfo c.size = arr_size @@ -93,6 +95,9 @@ def generate_array(xml_file): array_xml = XmlArrayParser.XmlArrayParser(xml_file) name = array_xml.get_name() namespace = array_xml.get_namespace() + namespace_list = None + if namespace is not None: + namespace_list = namespace.split("::") arr_type = array_xml.get_type() arr_typeinfo = array_xml.get_typeinfo() arr_size = int(array_xml.get_size()) @@ -136,6 +141,7 @@ def generate_array(xml_file): c, name, namespace, + namespace_list, arr_type, arr_typeinfo, arr_size, @@ -161,6 +167,7 @@ def generate_array(xml_file): c, name, namespace, + namespace_list, arr_type, arr_typeinfo, arr_size, diff --git a/Autocoders/Python/src/fprime_ac/utils/EnumGenerator.py b/Autocoders/Python/src/fprime_ac/utils/EnumGenerator.py index a00156456d..410204ce59 100644 --- a/Autocoders/Python/src/fprime_ac/utils/EnumGenerator.py +++ b/Autocoders/Python/src/fprime_ac/utils/EnumGenerator.py @@ -37,13 +37,23 @@ def open_file(name, type): def write_template( - fp, c, name, namespace, default, serialize_type, items, max_value, comment + fp, + c, + name, + namespace, + namespace_list, + default, + serialize_type, + items, + max_value, + comment, ): """ Set up and write out templates here """ c.name = name c.namespace = namespace + c.namespace_list = namespace_list c.default = default c.serialize_type = serialize_type c.items_list = items @@ -66,6 +76,9 @@ def generate_enum(xml_file): enum_xml = XmlEnumParser.XmlEnumParser(xml_file) name = enum_xml.get_name() namespace = enum_xml.get_namespace() + namespace_list = None + if namespace is not None: + namespace_list = enum_xml.get_namespace().split("::") default = enum_xml.get_default() serialize_type = enum_xml.get_serialize_type() items = enum_xml.get_items() @@ -77,7 +90,16 @@ def generate_enum(xml_file): fp = open_file(name, "hpp") c = enum_hpp.enum_hpp() write_template( - fp, c, name, namespace, default, serialize_type, items, max_value, comment + fp, + c, + name, + namespace, + namespace_list, + default, + serialize_type, + items, + max_value, + comment, ) fp.close() # @@ -86,7 +108,16 @@ def generate_enum(xml_file): fp = open_file(name, "cpp") c = enum_cpp.enum_cpp() write_template( - fp, c, name, namespace, default, serialize_type, items, max_value, comment + fp, + c, + name, + namespace, + namespace_list, + default, + serialize_type, + items, + max_value, + comment, ) fp.close() return True diff --git a/Autocoders/Python/src/fprime_ac/utils/TopDictGenerator.py b/Autocoders/Python/src/fprime_ac/utils/TopDictGenerator.py index 16f8ca1b6b..dfab2fd292 100644 --- a/Autocoders/Python/src/fprime_ac/utils/TopDictGenerator.py +++ b/Autocoders/Python/src/fprime_ac/utils/TopDictGenerator.py @@ -38,11 +38,6 @@ def check_for_serial_xml(self): serializable_model = XmlSerializeParser.XmlSerializeParser( serializable_file ) - if len(serializable_model.get_includes()) != 0: - raise Exception( - "%s: Can only include one level of serializable for dictionaries" - % serializable_file - ) # check for included enum XML in included serializable XML if len(serializable_model.get_include_enums()) != 0: @@ -382,8 +377,8 @@ def check_for_arrays(self): for array_file in array_file_list: array_file = search_for_file("Array", array_file) array_model = XmlArrayParser.XmlArrayParser(array_file) - array_elem = etree.Element("array") + array_elem = etree.Element("array") array_name = array_model.get_namespace() + "::" + array_model.get_name() array_elem.attrib["name"] = array_name diff --git a/Autocoders/Python/src/fprime_ac/utils/TypesList.py b/Autocoders/Python/src/fprime_ac/utils/TypesList.py index d8a58e8208..914dc52399 100644 --- a/Autocoders/Python/src/fprime_ac/utils/TypesList.py +++ b/Autocoders/Python/src/fprime_ac/utils/TypesList.py @@ -16,12 +16,21 @@ # additional types allowed in ports port_types_list = [ - "FwOpcodeType", + "FwBuffSizeType", "FwChanIdType", + "FwEnumStoreType", "FwEventIdType", + "FwIndexType", + "FwOpcodeType", + "FwPacketDescriptorType", "FwPrmIdType", + "FwSizeType", + "FwTimeBaseStoreType", + "FwTimeContextStoreType", + "FwTlmPacketizeIdType", "NATIVE_INT_TYPE", "NATIVE_UINT_TYPE", + "POINTER_CAST", ] diff --git a/Autocoders/Python/src/fprime_ac/utils/buildroot.py b/Autocoders/Python/src/fprime_ac/utils/buildroot.py index 571f9156fe..f26ab569b9 100644 --- a/Autocoders/Python/src/fprime_ac/utils/buildroot.py +++ b/Autocoders/Python/src/fprime_ac/utils/buildroot.py @@ -41,6 +41,7 @@ def get_nearest_build_root(path): :param path: path to find nearest build root to :return: nearest build root """ + path = os.path.abspath(path) parents = filter( lambda build: os.path.commonpath([build, path]) == build, get_build_roots() ) diff --git a/Autocoders/Python/src/fprime_ac/utils/version.py b/Autocoders/Python/src/fprime_ac/utils/version.py index 425ec97d78..b8e8ed567e 100644 --- a/Autocoders/Python/src/fprime_ac/utils/version.py +++ b/Autocoders/Python/src/fprime_ac/utils/version.py @@ -2,7 +2,7 @@ import os import subprocess -FALLBACK_VERSION = "v3.1.1" # Keep up-to-date on release tag +FALLBACK_VERSION = "v3.2.0" # Keep up-to-date on release tag def get_version_str(working_dir, fallback=FALLBACK_VERSION): diff --git a/Autocoders/Python/templates/CMakeLists.txt b/Autocoders/Python/templates/CMakeLists.txt index f9524402d3..4fe4dd16ab 100644 --- a/Autocoders/Python/templates/CMakeLists.txt +++ b/Autocoders/Python/templates/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Autocoders/Python/templates/ExampleType.hpp b/Autocoders/Python/templates/ExampleType.hpp index ecc2762ccd..91883bbbd7 100644 --- a/Autocoders/Python/templates/ExampleType.hpp +++ b/Autocoders/Python/templates/ExampleType.hpp @@ -2,7 +2,7 @@ #define EXAMPLE_TYPE_HPP // A hand-coded serializable -#include +#include #include #if FW_SERIALIZABLE_TO_STRING #include diff --git a/Autocoders/Python/test/array_xml/ArrayTypeArrayAi.xml b/Autocoders/Python/test/array_xml/ArrayTypeArrayAi.xml index edd4e630e2..40b710fcec 100644 --- a/Autocoders/Python/test/array_xml/ArrayTypeArrayAi.xml +++ b/Autocoders/Python/test/array_xml/ArrayTypeArrayAi.xml @@ -1,5 +1,5 @@ - + Autocoders/Python/test/array_xml/InternalTypeArrayAi.xml Example Array Type XML diff --git a/Autocoders/Python/test/array_xml/ExampleArrayImpl.cpp b/Autocoders/Python/test/array_xml/ExampleArrayImpl.cpp index b055302ec4..2ea02be5c2 100644 --- a/Autocoders/Python/test/array_xml/ExampleArrayImpl.cpp +++ b/Autocoders/Python/test/array_xml/ExampleArrayImpl.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -19,7 +19,7 @@ namespace Example { Component1ComponentBase::init(queueDepth); } - void ExampleArrayImpl::ExArrayIn_handler(NATIVE_INT_TYPE portNum, const Example::ArrayType& array1, const Example::ArrSerial& serial1) { + void ExampleArrayImpl::ExArrayIn_handler(NATIVE_INT_TYPE portNum, const Example::SubNameSpace::ArrayType& array1, const Example::ArrSerial& serial1) { Fw::String s; array1.toString(s); @@ -27,7 +27,7 @@ namespace Example { this->ArrayOut_out(0, array1, serial1); } - void ExampleArrayImpl::ArrayIn_handler(NATIVE_INT_TYPE portNum, const Example::ArrayType& array1, const Example::ArrSerial& serial1) { + void ExampleArrayImpl::ArrayIn_handler(NATIVE_INT_TYPE portNum, const Example::SubNameSpace::ArrayType& array1, const Example::ArrSerial& serial1) { Fw::String s; array1.toString(s); diff --git a/Autocoders/Python/test/array_xml/ExampleArrayImpl.hpp b/Autocoders/Python/test/array_xml/ExampleArrayImpl.hpp index 7d907c4211..ba370a8f45 100644 --- a/Autocoders/Python/test/array_xml/ExampleArrayImpl.hpp +++ b/Autocoders/Python/test/array_xml/ExampleArrayImpl.hpp @@ -14,8 +14,8 @@ namespace Example { void init(NATIVE_INT_TYPE queueDepth); private: - void ExArrayIn_handler(NATIVE_INT_TYPE portNum, const Example::ArrayType& array1, const Example::ArrSerial& serial1); - void ArrayIn_handler(NATIVE_INT_TYPE portNum, const Example::ArrayType& array1, const Example::ArrSerial& serial1); + void ExArrayIn_handler(NATIVE_INT_TYPE portNum, const Example::SubNameSpace::ArrayType& array1, const Example::ArrSerial& serial1); + void ArrayIn_handler(NATIVE_INT_TYPE portNum, const Example::SubNameSpace::ArrayType& array1, const Example::ArrSerial& serial1); }; }; diff --git a/Autocoders/Python/test/array_xml/InternalTypeArrayAi.xml b/Autocoders/Python/test/array_xml/InternalTypeArrayAi.xml index 9201a1b441..b376c9213d 100644 --- a/Autocoders/Python/test/array_xml/InternalTypeArrayAi.xml +++ b/Autocoders/Python/test/array_xml/InternalTypeArrayAi.xml @@ -1,5 +1,5 @@ - + U32 4 %u diff --git a/Autocoders/Python/test/array_xml/Port1PortAi.xml b/Autocoders/Python/test/array_xml/Port1PortAi.xml index e784c66cc0..0f6b0f272e 100644 --- a/Autocoders/Python/test/array_xml/Port1PortAi.xml +++ b/Autocoders/Python/test/array_xml/Port1PortAi.xml @@ -8,7 +8,7 @@ Example port with arg - + Example array arg @@ -16,4 +16,3 @@ - diff --git a/Autocoders/Python/test/array_xml/StringArrayArrayAi.xml b/Autocoders/Python/test/array_xml/StringArrayArrayAi.xml index 7b8df96c5a..1628a61c66 100644 --- a/Autocoders/Python/test/array_xml/StringArrayArrayAi.xml +++ b/Autocoders/Python/test/array_xml/StringArrayArrayAi.xml @@ -1,5 +1,5 @@ - + string 3 %s diff --git a/Autocoders/Python/test/array_xml/test/ut/main.cpp b/Autocoders/Python/test/array_xml/test/ut/main.cpp index 6d0cfc6463..c9240419cb 100644 --- a/Autocoders/Python/test/array_xml/test/ut/main.cpp +++ b/Autocoders/Python/test/array_xml/test/ut/main.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include @@ -33,22 +33,17 @@ extern "C" { #endif int main(int argc, char* argv[]) { - // Construct the topology here. - Fw::PortBase::setTrace(true); - Fw::SimpleObjRegistry simpleReg_ptr; - simpleReg_ptr.dump(); - setbuf(stdout, nullptr); cout << "Initialize Arrays" << endl; - InternalType array1 = InternalType(6,7,120,444); - Example::ArrayType array2 = Example::ArrayType(array1); + Example::InternalType array1 = Example::InternalType(6,7,120,444); + Example::SubNameSpace::ArrayType array2 = Example::SubNameSpace::ArrayType(array1); // Create string array for serializable Fw::String mem1 = "Member 1"; Fw::String mem2 = "Member 2"; Fw::String mem3 = "Member 3"; - StringArray array3 = StringArray(mem1, mem2, mem3); + Example::StringArray array3 = Example::StringArray(mem1, mem2, mem3); Example::ArrSerial serial1; // Print toString outputs for each array @@ -89,8 +84,8 @@ int main(int argc, char* argv[]) { // Save copy of arrays to test against post-serialization - InternalType array1Save = array1; - Example::ArrayType array2Save = array2; + Example::InternalType array1Save = array1; + Example::SubNameSpace::ArrayType array2Save = array2; cout << "Deserializing arrays" << endl; if (arraySerial1.deserialize(array1Save) != Fw::FW_SERIALIZE_OK) { diff --git a/Autocoders/Python/test/command2/TestCommandComponentImpl.cpp b/Autocoders/Python/test/command2/TestCommandComponentImpl.cpp index 8c94288e73..3e5ff44765 100644 --- a/Autocoders/Python/test/command2/TestCommandComponentImpl.cpp +++ b/Autocoders/Python/test/command2/TestCommandComponentImpl.cpp @@ -12,7 +12,7 @@ #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace AcTest { diff --git a/Autocoders/Python/test/command_res/Test1ComponentImpl.cpp b/Autocoders/Python/test/command_res/Test1ComponentImpl.cpp index e3b7586c9c..61f8a570fe 100644 --- a/Autocoders/Python/test/command_res/Test1ComponentImpl.cpp +++ b/Autocoders/Python/test/command_res/Test1ComponentImpl.cpp @@ -12,7 +12,7 @@ #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace Cmd { diff --git a/Autocoders/Python/test/enum1port/DrvTimingSignalPort.hpp b/Autocoders/Python/test/enum1port/DrvTimingSignalPort.hpp index 2db34fd0d6..193576f0b8 100644 --- a/Autocoders/Python/test/enum1port/DrvTimingSignalPort.hpp +++ b/Autocoders/Python/test/enum1port/DrvTimingSignalPort.hpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include namespace Drv { diff --git a/Autocoders/Python/test/enum_xml/Component1Impl.cpp b/Autocoders/Python/test/enum_xml/Component1Impl.cpp index c471aab6bb..7f2b84f603 100644 --- a/Autocoders/Python/test/enum_xml/Component1Impl.cpp +++ b/Autocoders/Python/test/enum_xml/Component1Impl.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -18,12 +18,12 @@ namespace Example { Component1ComponentBase::init(queueDepth); } - void ExampleEnumImpl::ExEnumIn_handler(NATIVE_INT_TYPE portNum, const Example::Enum1& enum1, const Example::Serial1& serial1) { + void ExampleEnumImpl::ExEnumIn_handler(NATIVE_INT_TYPE portNum, const Example::SubNamespace::Enum1& enum1, const Example::Serial1& serial1) { printf("%s Invoked ExEnumIn_handler(%d, %d, %d, %d, %d);\n", FW_OPTIONAL_NAME(this->getObjName()), portNum, static_cast(enum1.e), serial1.getMember1(), serial1.getMember2(), static_cast(serial1.getMember3().e)); this->EnumOut_out(0, enum1, serial1); } - void ExampleEnumImpl::EnumIn_handler(NATIVE_INT_TYPE portNum, const Example::Enum1& enum1, const Example::Serial1& serial1) { + void ExampleEnumImpl::EnumIn_handler(NATIVE_INT_TYPE portNum, const Example::SubNamespace::Enum1& enum1, const Example::Serial1& serial1) { printf("%s Invoked EnumIn_handler(%d, %d, %d, %d, %d);\n", FW_OPTIONAL_NAME(this->getObjName()), portNum, static_cast(enum1.e), serial1.getMember1(), serial1.getMember2(), static_cast(serial1.getMember3().e)); } }; diff --git a/Autocoders/Python/test/enum_xml/Component1Impl.hpp b/Autocoders/Python/test/enum_xml/Component1Impl.hpp index 4af083282a..3da68e514e 100644 --- a/Autocoders/Python/test/enum_xml/Component1Impl.hpp +++ b/Autocoders/Python/test/enum_xml/Component1Impl.hpp @@ -14,8 +14,8 @@ namespace Example { void init(NATIVE_INT_TYPE queueDepth); private: - void ExEnumIn_handler(NATIVE_INT_TYPE portNum, const Example::Enum1& enum1, const Example::Serial1& serial1); - void EnumIn_handler(NATIVE_INT_TYPE portNum, const Example::Enum1& enum1, const Example::Serial1& serial1); + void ExEnumIn_handler(NATIVE_INT_TYPE portNum, const Example::SubNamespace::Enum1& enum1, const Example::Serial1& serial1); + void EnumIn_handler(NATIVE_INT_TYPE portNum, const Example::SubNamespace::Enum1& enum1, const Example::Serial1& serial1); }; }; diff --git a/Autocoders/Python/test/enum_xml/Enum1EnumAi.xml b/Autocoders/Python/test/enum_xml/Enum1EnumAi.xml index bcf961e080..36754e92bf 100644 --- a/Autocoders/Python/test/enum_xml/Enum1EnumAi.xml +++ b/Autocoders/Python/test/enum_xml/Enum1EnumAi.xml @@ -1,5 +1,5 @@ - + Test enum_xml example enum diff --git a/Autocoders/Python/test/enum_xml/Port1PortAi.xml b/Autocoders/Python/test/enum_xml/Port1PortAi.xml index 9e6db421b8..01be3db2ae 100644 --- a/Autocoders/Python/test/enum_xml/Port1PortAi.xml +++ b/Autocoders/Python/test/enum_xml/Port1PortAi.xml @@ -6,7 +6,7 @@ Port with example args - + Example enum arg @@ -14,4 +14,3 @@ - diff --git a/Autocoders/Python/test/enum_xml/Serial1SerializableAi.xml b/Autocoders/Python/test/enum_xml/Serial1SerializableAi.xml index f562b9e467..a855210429 100644 --- a/Autocoders/Python/test/enum_xml/Serial1SerializableAi.xml +++ b/Autocoders/Python/test/enum_xml/Serial1SerializableAi.xml @@ -7,7 +7,6 @@ - + - diff --git a/Autocoders/Python/test/enum_xml/main.cpp b/Autocoders/Python/test/enum_xml/main.cpp index 601a18b068..23c32b5930 100644 --- a/Autocoders/Python/test/enum_xml/main.cpp +++ b/Autocoders/Python/test/enum_xml/main.cpp @@ -35,25 +35,25 @@ void constructArchitecture() { } -Example::Enum1::t getEnumConstant() { - Example::Enum1::t c = Example::Enum1::Item1; +Example::SubNamespace::Enum1::t getEnumConstant() { + Example::SubNamespace::Enum1::t c = Example::SubNamespace::Enum1::Item1; const U32 i = STest::Pick::lowerUpper(0, 4); switch(i) { case 0: - c = Example::Enum1::Item1; + c = Example::SubNamespace::Enum1::Item1; break; case 1: - c = Example::Enum1::Item2; + c = Example::SubNamespace::Enum1::Item2; break; case 2: - c = Example::Enum1::Item3; + c = Example::SubNamespace::Enum1::Item3; break; case 3: - c = Example::Enum1::Item4; + c = Example::SubNamespace::Enum1::Item4; break; case 4: - c = Example::Enum1::Item5; + c = Example::SubNamespace::Enum1::Item5; break; default: FW_ASSERT(0, i); @@ -63,19 +63,19 @@ Example::Enum1::t getEnumConstant() { return c; } -Example::Enum1::t getNonnegativeConstant() { - Example::Enum1::t c = Example::Enum1::Item1; +Example::SubNamespace::Enum1::t getNonnegativeConstant() { + Example::SubNamespace::Enum1::t c = Example::SubNamespace::Enum1::Item1; const U32 i = STest::Pick::lowerUpper(0, 2); switch(i) { case 0: - c = Example::Enum1::Item2; + c = Example::SubNamespace::Enum1::Item2; break; case 1: - c = Example::Enum1::Item3; + c = Example::SubNamespace::Enum1::Item3; break; case 2: - c = Example::Enum1::Item4; + c = Example::SubNamespace::Enum1::Item4; break; default: FW_ASSERT(0, i); @@ -85,16 +85,16 @@ Example::Enum1::t getNonnegativeConstant() { return c; } -Example::Enum1::t getNegativeConstant() { - Example::Enum1::t c = Example::Enum1::Item1; +Example::SubNamespace::Enum1::t getNegativeConstant() { + Example::SubNamespace::Enum1::t c = Example::SubNamespace::Enum1::Item1; const U32 i = STest::Pick::lowerUpper(0, 1); switch(i) { case 0: - c = Example::Enum1::Item1; + c = Example::SubNamespace::Enum1::Item1; break; case 1: - c = Example::Enum1::Item5; + c = Example::SubNamespace::Enum1::Item5; break; default: FW_ASSERT(0, i); @@ -104,19 +104,19 @@ Example::Enum1::t getNegativeConstant() { return c; } -Example::Enum1 getEnum() { - const Example::Enum1 e = getEnumConstant(); +Example::SubNamespace::Enum1 getEnum() { + const Example::SubNamespace::Enum1 e = getEnumConstant(); return e; } -Example::Enum1 getEnumFromI32() { - Example::Enum1 e = getEnumConstant(); +Example::SubNamespace::Enum1 getEnumFromI32() { + Example::SubNamespace::Enum1 e = getEnumConstant(); e = static_cast(getEnumConstant()); return e; } -Example::Enum1 getEnumFromU32() { - Example::Enum1 e = getNonnegativeConstant(); +Example::SubNamespace::Enum1 getEnumFromU32() { + Example::SubNamespace::Enum1 e = getNonnegativeConstant(); e = static_cast(getNonnegativeConstant()); return e; } @@ -130,12 +130,12 @@ void checkAssertionFailure( Test::UnitTestAssert::File file = Test::UnitTestAssert::fileInit; NATIVE_UINT_TYPE lineNo = 0; NATIVE_UINT_TYPE numArgs = 0; - AssertArg arg1 = 0; - AssertArg arg2 = 0; - AssertArg arg3 = 0; - AssertArg arg4 = 0; - AssertArg arg5 = 0; - AssertArg arg6 = 0; + FwAssertArgType arg1 = 0; + FwAssertArgType arg2 = 0; + FwAssertArgType arg3 = 0; + FwAssertArgType arg4 = 0; + FwAssertArgType arg5 = 0; + FwAssertArgType arg6 = 0; uta.retrieveAssert(file, lineNo, numArgs, arg1, arg2, arg3, arg4, arg5, arg6); ASSERT_EQ(expectedLineNumber, lineNo); ASSERT_EQ(1U, numArgs); @@ -144,10 +144,10 @@ void checkAssertionFailure( TEST(EnumXML, InvalidNegativeConstant) { ::Test::UnitTestAssert uta; - Example::Enum1 enum1 = getEnum(); + Example::SubNamespace::Enum1 enum1 = getEnum(); // Get a valid negative constant const I32 negativeConstant = getNegativeConstant(); - const U32 expectedLineNumber = 61; + const U32 expectedLineNumber = 62; // Turn it into a U32 const U32 expectedArg1 = negativeConstant; // As a U32, the constant is not valid @@ -158,12 +158,12 @@ TEST(EnumXML, InvalidNegativeConstant) { TEST(EnumXML, InvalidConstant) { ::Test::UnitTestAssert uta; - Example::Enum1 enum1 = getEnum(); + Example::SubNamespace::Enum1 enum1 = getEnum(); // Get an invalid constant const I32 invalidConstant = 42; // This should cause an assertion failure enum1 = invalidConstant; - const U32 expectedLineNumber = 54; + const U32 expectedLineNumber = 55; const U32 expectedArg1 = invalidConstant; checkAssertionFailure(uta, expectedLineNumber, expectedArg1); } @@ -171,9 +171,9 @@ TEST(EnumXML, InvalidConstant) { TEST(EnumXML, OK) { // Explicitly set enum1 to the default value - Example::Enum1 enum1(Example::Enum1::Item4); - Example::Enum1 enum2; - Example::Enum1 enum3; + Example::SubNamespace::Enum1 enum1(Example::SubNamespace::Enum1::Item4); + Example::SubNamespace::Enum1 enum2; + Example::SubNamespace::Enum1 enum3; Example::Enum2 enum4; Example::Enum3 enum5; @@ -187,7 +187,7 @@ TEST(EnumXML, OK) { ASSERT_EQ(enum4.e, 0); // Check that the enum serializable types are set correctly - ASSERT_EQ(Example::Enum1::SERIALIZED_SIZE, sizeof(FwEnumStoreType)); + ASSERT_EQ(Example::SubNamespace::Enum1::SERIALIZED_SIZE, sizeof(FwEnumStoreType)); ASSERT_EQ(Example::Enum2::SERIALIZED_SIZE, sizeof(U64)); ASSERT_EQ(Example::Enum3::SERIALIZED_SIZE, sizeof(U8)); @@ -201,8 +201,8 @@ TEST(EnumXML, OK) { cout << "Created third enum: " << enum3 << endl; // Save copy of enums to test against post-serialization - Example::Enum1 enum1Save = enum1; - Example::Enum1 enum2Save = enum2; + Example::SubNamespace::Enum1 enum1Save = enum1; + Example::SubNamespace::Enum1 enum2Save = enum2; int serial_arg1 = 0; diff --git a/Autocoders/Python/test/ext_dict/ExampleType.hpp b/Autocoders/Python/test/ext_dict/ExampleType.hpp index 1c8f104d06..c67f30aee7 100644 --- a/Autocoders/Python/test/ext_dict/ExampleType.hpp +++ b/Autocoders/Python/test/ext_dict/ExampleType.hpp @@ -2,7 +2,7 @@ #define EXAMPLE_TYPE_HPP // A hand-coded serializable -#include +#include #include #if FW_SERIALIZABLE_TO_STRING #include diff --git a/Autocoders/Python/test/implgen/templates/MathSenderComponentImpl_cpp-template.txt b/Autocoders/Python/test/implgen/templates/MathSenderComponentImpl_cpp-template.txt index 4b5678a73e..7ad49e9d0c 100644 --- a/Autocoders/Python/test/implgen/templates/MathSenderComponentImpl_cpp-template.txt +++ b/Autocoders/Python/test/implgen/templates/MathSenderComponentImpl_cpp-template.txt @@ -1,5 +1,5 @@ #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace Ref { diff --git a/Autocoders/Python/test/interface1/SomeStruct.hpp b/Autocoders/Python/test/interface1/SomeStruct.hpp index 110fc5ff55..df60193f9c 100644 --- a/Autocoders/Python/test/interface1/SomeStruct.hpp +++ b/Autocoders/Python/test/interface1/SomeStruct.hpp @@ -1,7 +1,7 @@ #ifndef SOME_STRUCT_HPP #define SOME_STRUCT_HPP -#include +#include extern "C" { typedef struct { diff --git a/Autocoders/Python/test/interface1/UserSerializer.hpp b/Autocoders/Python/test/interface1/UserSerializer.hpp index b6ea7948f4..c6c730aca0 100644 --- a/Autocoders/Python/test/interface1/UserSerializer.hpp +++ b/Autocoders/Python/test/interface1/UserSerializer.hpp @@ -2,7 +2,7 @@ #define EXAMPLE_TYPE_HPP // A hand-coded serializable -#include +#include #include #include #if FW_SERIALIZABLE_TO_STRING diff --git a/Autocoders/Python/test/noargport/ExampleComponentImpl.cpp b/Autocoders/Python/test/noargport/ExampleComponentImpl.cpp index 4cba2dc177..7c96b21ea6 100644 --- a/Autocoders/Python/test/noargport/ExampleComponentImpl.cpp +++ b/Autocoders/Python/test/noargport/ExampleComponentImpl.cpp @@ -12,7 +12,7 @@ #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace ExampleComponents { diff --git a/Autocoders/Python/test/partition/DuckDuckImpl.cpp b/Autocoders/Python/test/partition/DuckDuckImpl.cpp index 091f9654ce..10145e5d7a 100644 --- a/Autocoders/Python/test/partition/DuckDuckImpl.cpp +++ b/Autocoders/Python/test/partition/DuckDuckImpl.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include diff --git a/Autocoders/Python/test/partition/PartitionImpl.cpp b/Autocoders/Python/test/partition/PartitionImpl.cpp index e43fae07c9..d90c2fd23a 100644 --- a/Autocoders/Python/test/partition/PartitionImpl.cpp +++ b/Autocoders/Python/test/partition/PartitionImpl.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include diff --git a/Autocoders/Python/test/partition/Top.cpp b/Autocoders/Python/test/partition/Top.cpp index f95d9d1c86..9f5a8d002f 100644 --- a/Autocoders/Python/test/partition/Top.cpp +++ b/Autocoders/Python/test/partition/Top.cpp @@ -83,7 +83,7 @@ int main(int argc, char* argv[]) { // Construct the topology here. constructArchitecture(); // Ask for input to huey or duey here. - char in[80]; + char in[80] = {}; U32 cmd; Fw::String *str; char str2[80]; diff --git a/Autocoders/Python/test/pass_by_attrib/Msg1Port.hpp b/Autocoders/Python/test/pass_by_attrib/Msg1Port.hpp index ab2bb158b9..85ab6e77d0 100644 --- a/Autocoders/Python/test/pass_by_attrib/Msg1Port.hpp +++ b/Autocoders/Python/test/pass_by_attrib/Msg1Port.hpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/Autocoders/Python/test/pass_by_kind/Component1.cpp b/Autocoders/Python/test/pass_by_kind/Component1.cpp index a7d5c33e97..5965125c18 100644 --- a/Autocoders/Python/test/pass_by_kind/Component1.cpp +++ b/Autocoders/Python/test/pass_by_kind/Component1.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include diff --git a/Autocoders/Python/test/port_loopback/ExampleComponentImpl.cpp b/Autocoders/Python/test/port_loopback/ExampleComponentImpl.cpp index f9760799ba..ace6e94c1b 100644 --- a/Autocoders/Python/test/port_loopback/ExampleComponentImpl.cpp +++ b/Autocoders/Python/test/port_loopback/ExampleComponentImpl.cpp @@ -12,7 +12,7 @@ #include -#include "Fw/Types/BasicTypes.hpp" +#include #include namespace ExampleComponents { diff --git a/Autocoders/Python/test/port_loopback/ExampleType.hpp b/Autocoders/Python/test/port_loopback/ExampleType.hpp index ecc2762ccd..91883bbbd7 100644 --- a/Autocoders/Python/test/port_loopback/ExampleType.hpp +++ b/Autocoders/Python/test/port_loopback/ExampleType.hpp @@ -2,7 +2,7 @@ #define EXAMPLE_TYPE_HPP // A hand-coded serializable -#include +#include #include #if FW_SERIALIZABLE_TO_STRING #include diff --git a/Autocoders/Python/test/port_nogen/ExampleType.hpp b/Autocoders/Python/test/port_nogen/ExampleType.hpp index 8809099da4..6a60913da9 100644 --- a/Autocoders/Python/test/port_nogen/ExampleType.hpp +++ b/Autocoders/Python/test/port_nogen/ExampleType.hpp @@ -2,7 +2,7 @@ #define EXAMPLE_TYPE_HPP // A hand-coded serializable -#include +#include #include #if FW_SERIALIZABLE_TO_STRING #include diff --git a/Autocoders/Python/test/schematron/test_schematron.py b/Autocoders/Python/test/schematron/test_schematron.py index b2ad1f5a94..f9b5a62132 100644 --- a/Autocoders/Python/test/schematron/test_schematron.py +++ b/Autocoders/Python/test/schematron/test_schematron.py @@ -5,7 +5,7 @@ @author jishii """ - +from pathlib import Path import os import shutil import sys @@ -13,8 +13,9 @@ import pexpect from pexpect import EOF, TIMEOUT -sys.path.append(os.path.join(os.environ["BUILD_ROOT"], "Fw", "Python", "src")) -sys.path.append(os.path.join(os.environ["BUILD_ROOT"], "Gds", "src")) # Add GDS modules +build_root = Path(os.environ["BUILD_ROOT"]) +sys.path.append(build_root / "Fw" / "Python" / "src") +sys.path.append(build_root / "Gds" / "src") # Add GDS modules def test_schematron(): @@ -24,21 +25,14 @@ def test_schematron(): try: # cd into test directory to find test files (code/test/schematron can only find files this way) - testdir = os.path.join( - os.environ["BUILD_ROOT"], - "Autocoders", - "Python", - "test", - "schematron", - "xml", - ) + testdir = build_root / "Autocoders" / "Python" / "test" / "schematron" / "xml" os.chdir(testdir) - bindir = os.path.join(os.environ["BUILD_ROOT"], "Autocoders", "Python", "bin") + bindir = build_root / "Autocoders" / "Python" / "bin" # Autocode enum XML p_enum = pexpect.spawn( - "python " + os.path.join(bindir, "codegen.py") + " -v Enum1EnumAi.xml" + "python " + str(bindir / "codegen.py") + " -v Enum1EnumAi.xml" ) p_enum.expect("(?=.*Enum1 Schematron).*") print("Enum autocoded for test cases") @@ -52,7 +46,7 @@ def test_schematron(): # Successful test case p_test1 = pexpect.spawn( - "python " + os.path.join(bindir, "codegen.py") + " -v TestTopologyAppAi.xml" + "python " + str(bindir / "codegen.py") + " -v TestTopologyAppAi.xml" ) p_test1.expect( "(?=.*Found component XML file)(?=.*Parsing Component TestComponent)(?!.*ERROR)(?!.*is not valid according to schematron).*", @@ -62,9 +56,7 @@ def test_schematron(): # Active component without an async port p_test2 = pexpect.spawn( - "python " - + os.path.join(bindir, "codegen.py") - + " -v Test2TopologyAppAi.xml" + "python " + str(bindir / "codegen.py") + " -v Test2TopologyAppAi.xml" ) p_test2.expect( "(?=.*Found component XML file)(?=.*active_comp_schematron.rng)(?!.*ERROR).*", @@ -76,9 +68,7 @@ def test_schematron(): # Topology with 2 instances of the same ID p_test3 = pexpect.spawn( - "python " - + os.path.join(bindir, "codegen.py") - + " -v BrokenTopologyAppAi.xml" + "python " + str(bindir / "codegen.py") + " -v BrokenTopologyAppAi.xml" ) p_test3.expect("(?=.*top_uniqueness_schematron.rng)(?!.*ERROR).*", timeout=5) print( @@ -91,12 +81,12 @@ def test_schematron(): # Broken imported dict print( "python " - + os.path.join(bindir, "codegen.py") + + str(bindir / "codegen.py") + " -v Test{}DictComponentAi.xml".format(type) ) p_test_dict = pexpect.spawn( "python " - + os.path.join(bindir, "codegen.py") + + str(bindir / "codegen.py") + " -v Test{}DictComponentAi.xml".format(type) ) if type == "Cmd": @@ -129,7 +119,7 @@ def test_schematron(): # Broken component xml p_test_dict = pexpect.spawn( "python " - + os.path.join(bindir, "codegen.py") + + str(bindir / "codegen.py") + " -v Test{}ComponentAi.xml".format(type) ) p_test_dict.expect( diff --git a/Autocoders/Python/test/serial_passive/TestSerialImpl.cpp b/Autocoders/Python/test/serial_passive/TestSerialImpl.cpp index 073e4276c8..657e7a9ad9 100644 --- a/Autocoders/Python/test/serial_passive/TestSerialImpl.cpp +++ b/Autocoders/Python/test/serial_passive/TestSerialImpl.cpp @@ -12,7 +12,7 @@ #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace TestComponents { diff --git a/Autocoders/Python/test/serialize_user/SomeStruct.hpp b/Autocoders/Python/test/serialize_user/SomeStruct.hpp index 110fc5ff55..df60193f9c 100644 --- a/Autocoders/Python/test/serialize_user/SomeStruct.hpp +++ b/Autocoders/Python/test/serialize_user/SomeStruct.hpp @@ -1,7 +1,7 @@ #ifndef SOME_STRUCT_HPP #define SOME_STRUCT_HPP -#include +#include extern "C" { typedef struct { diff --git a/Autocoders/Python/test/serialize_user/UserSerializer.hpp b/Autocoders/Python/test/serialize_user/UserSerializer.hpp index d46584ff18..c460623999 100644 --- a/Autocoders/Python/test/serialize_user/UserSerializer.hpp +++ b/Autocoders/Python/test/serialize_user/UserSerializer.hpp @@ -2,7 +2,7 @@ #define EXAMPLE_TYPE_HPP // A hand-coded serializable -#include +#include #include #include #if FW_SERIALIZABLE_TO_STRING diff --git a/Autocoders/Python/test/testgen/MathSenderComponentImpl.cpp b/Autocoders/Python/test/testgen/MathSenderComponentImpl.cpp index 1e5d4a8ba6..f6b6d9c465 100644 --- a/Autocoders/Python/test/testgen/MathSenderComponentImpl.cpp +++ b/Autocoders/Python/test/testgen/MathSenderComponentImpl.cpp @@ -12,7 +12,7 @@ #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace Ref { diff --git a/CFDP/Checksum/CMakeLists.txt b/CFDP/Checksum/CMakeLists.txt index 0300646cc0..d6f3a11eaa 100644 --- a/CFDP/Checksum/CMakeLists.txt +++ b/CFDP/Checksum/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/CFDP/Checksum/Checksum.hpp b/CFDP/Checksum/Checksum.hpp index 7ccfe2e8fd..7f444a3cf2 100644 --- a/CFDP/Checksum/Checksum.hpp +++ b/CFDP/Checksum/Checksum.hpp @@ -13,7 +13,7 @@ #ifndef CFDP_Checksum_HPP #define CFDP_Checksum_HPP -#include "Fw/Types/BasicTypes.hpp" +#include namespace CFDP { diff --git a/CFDP/Checksum/GTest/CMakeLists.txt b/CFDP/Checksum/GTest/CMakeLists.txt index a778b60118..d2b937e70c 100644 --- a/CFDP/Checksum/GTest/CMakeLists.txt +++ b/CFDP/Checksum/GTest/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index ec5172994b..0000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,125 +0,0 @@ -### Release 3.0: Release and Migration Notes - -Version 3.0.0 of F´ comes with several major enhancements to the framework. This release contains an update to use the FPP modeling language and the C++ standard has been updated to C++11. These are fairly substantial changes and users should consult the version 3 [migration guide](https://nasa.github.io/fprime/UsersGuide/user/v3-migration-guide.html) when adopting F´ version 3. - -### Release 2.1.0: Release Notes - -This is the final release of the F´ version 2 releases. This should be the chosen release for projects unable to upgrade to C++11 and/or adopt FPP. - -### Release 2.0.1: Release Notes - -This is a point release that repaired some compilation issues with VxWorks 6. This will be the last release supporting VxWorks 6. - -### Release 2.0: Release and Migration Notes - -Version 2.0.0 of F´ represents major improvements across the F´ framework. As such, some work may be required to migrate from other versions of F´ to the new -functionality. This section will offer recommendations to migrate to version 2.0.0 of F´. - -Features and Functionality: - -* New ground interface change improves stability and flexibility - * `Svc::Framer` and `Svc::Deframer` components may be used in place of `Svc::GroundInterface` - * `Svc::Framer` and `Svc::Deframer` delegate to a user instantiated framing class allowing use of non-fprime framing protocols -* `Drv::ByteStreamDriverModel` allows implementing drivers reading/writing streams of bytes using a single model -* New IPv4 drivers implement `Drv::ByteStreamDriverModel` allowing choice or combination of uplink and downlink communications - * `Drv::TcpClient` is a tcp client that connects to a remote server - * `Drv::TcpServer` is a tcp server that allows connections from remote clients - * `Drv::Udp` allows UDP communications - * `Drv::SocketIpDriver` may be replaced using a choice of an above component. -* `Svc::FileDownlink` now supports a queue of files to downlink and a port to trigger file downlinks -* `Svc::FileDownlink` may now be configured to turn off certain errors -* `Svc/GenericHub` is a basic instantiation of the hub pattern -* Bug fixes and stability improvements - -Migration considerations: - -* F´ tooling (fprime-util and fprime-gds) should be installed using `pip install fprime-tools fprime-gds` -* `Os::File::open` with the mode CREATE will now properly respect O_EXCL and error if the file exists. Pass in `false` as the final argument to override. -* Revise uses of `Fw::Buffer` to correct usage of member functions using camel case. E.g. `Fw::Buffer::getsize` is now `Fw::Buffer::getSize` -* The ground interface chain has been refactored. Projects may switch to using `Svc::Framer`, `Svc::Deframer`, and any implementor of `Drv::ByteStreamDriverModel` to supply the data. To continue using the old interface with the GDS run `fprime-gds --comm-checksum-type fixed`. -* `Svc::BufferManager` has been reworked to remove errors. When instantiating it please supply a memory allocator as shown in `Ref`. -* Dictionaries, binaries, and other build outputs now are written to a deployments `build_artifacts` folder. - -**Deprecated Functionality:** The following features are or will be deprecated soon and may be removed in future releases. - -* `Svc::GroundInterface` and `Drv::SocketIpDriver` should be replaced by the new ground system components. -* Inline enumerations (enumerations defined inside the definition of a command/event/channel) should be replaced by EnumAi.xml implementations -* `fprime-util generate --ut -DFPRIME_ENABLE_FRAMEWORK_UTS=OFF` will be removed in favor of future `fprime-util check` variants -* `Autocoders/MagicDrawCompPlugin` will be removed in a near-term release - -### Release 1.5 - -* Documentation improvements - * New user's guide containing considerable content: [https://nasa.github.io/fprime/UsersGuide/guide.html](https://nasa.github.io/fprime/UsersGuide/guide.html) - * Auto-generated API documentation - * Rewrites, edits, improvements across the board -* F´ Project restructuring - * Projects may now link to F´ and F´ library packages, without needing to keep the framework code in the same source tree - * Usage of framework can be out-of-source - * `settings.ini` Introduced - * Example: [https://github.com/fprime-community/fprime-arduino](https://github.com/fprime-community/fprime-arduino) -* Refactored `fprime-util` - * Replaced redundant targets with flags e.g. build-ut is now build --ut - * Added `info` command - * Bug and usability fixes -* GDS Improvements - * Prototype GDS CLI tool - * Project custom dashboard support -* Array, Enum type support and examples -* Code linting and bug fixes - -### Release 1.4 - -* Ref app no longer hangs on Linux exit -* GDS improvements: - * File Uplink and Downlink implemented - * GDS supports multiple active windows - * Usability improvements for EVRs and commands -* CMake improvements: - * Baremetal compilation supported - * Random rebuilding fixed - * Missing Cheetah templates properly rebuild - * Separate projects supported without additional tweaks -* Updated MemAllocator to have: - * "recoverable" flag to indicate if memory was recoverable across boots - * size variable is now modifiable by allocator to indicate actual size - * This will break existing code that uses MemAllocator -* Updated CmdSequencer - * Uses new MemAllocator interface - -### Release 1.3 - -* New prototype HTML GUI -* Python packages Fw/Python and Gds -* Refined CMake and fprime-util helper script -* Better ground interface component -* Integration test API -* Baremetal components - -### Release 1.2 - -* Better MagicDraw Plugin -* Prototype CMake build system. See: [CMake Documentation](./docs/UsersGuide/cmake/cmake-intro.md) -* Mars Helicopter Project fixes migrated in -* Python 3 support added -* Gse refactored and renamed to Gds -* Wx frontend to Gds -* UdpSender and UdpReceiver components added -* Purged inaccurate ITAR and Copyright notices -* Misc. bug fixes - -### Release 1.1 - -* Created a Raspberry Pi demo. Read about it [here](RPI/README.md) -* Added a tutorial [here](docs/Tutorials/README.md) -* Updated Svc/BufferManager with bug fix -* Fixed a bunch of shell permissions - -### Release 1.0.1 - -* Updated contributor list. No code changes. - -### Release 1.0 - -* This is the initial release of the software to open source. See the license file for terms of use. - diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000000..0969068080 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,6 @@ +cff-version: 1.2.0 +message: "If you use this software, please cite it as below." +authors: + - name: "The F´ Framework Team" +title: "F´: A Flight-Proven, Multi-Platform, Open-Source Flight Software Framework" +url: "https://github.com/nasa/fprime" diff --git a/CPPLINT.cfg b/CPPLINT.cfg new file mode 100644 index 0000000000..328b30035f --- /dev/null +++ b/CPPLINT.cfg @@ -0,0 +1,70 @@ +# +# Cpplint is a command-line tool to check C/C++ files for style issues following Google's C++ style guide. +# https://github.com/cpplint/cpplint +# +# Type the command below for details about supported options in CPPLINT.cfg. +# > cpplint --help +# + +# Do not look for additional CPPLINT.cfg in the parent directories. +set noparent +root=. +extensions=cpp,hpp,c,h + +# Limit line length. +linelength=120 + +# Adjust the following error categories as specified by the filter: +# (filter parameters are concatenated together) + +# `build` rules +# Enable a warning about C++ features that were not in the original +# C++11 specification (and so might not be well-supported). In the +# case of F´, the minimum supported platforms are potentially not +# new enough to afford to do without this warning. +filter=+build/c++11 + +# F´ uses `#ifndef FOO_H` guard not the `#pragma once`. +filter=-build/pragma_once + +# Do not enforce including header files in both .h and .cpp. +filter=-build/header_guard +filter=-build/include +filter=-build/include_alpha +filter=-build/include_order +filter=-build/include_subdir +filter=-build/include_what_you_use +filter=-build/namespaces + +filter=-legal/copyright + +filter=-readability/braces +filter=-readability/casting +filter=-readability/namespace +filter=-readability/todo + +filter=-runtime/indentation_namespace +filter=-runtime/int +filter=-runtime/references + +filter=-whitespace/blank_line +filter=-whitespace/braces +filter=-whitespace/comma +filter=-whitespace/comments +filter=-whitespace/end_of_line +filter=-whitespace/indent +filter=-whitespace/line_length +filter=-whitespace/newline +filter=-whitespace/operators +filter=-whitespace/parens +filter=-whitespace/tab + +# There is no need for lint-gardening in the documentation. +exclude_files=Autocoders +exclude_files=ci +exclude_files=cmake +exclude_files=docs +exclude_files=Fpp +exclude_files=FppTest +exclude_files=gtest +exclude_files=build-fprime-automatic-* diff --git a/Drv/BlockDriver/BlockDriverImpl.cpp b/Drv/BlockDriver/BlockDriverImpl.cpp index bf8f40fb88..ecd20c2083 100644 --- a/Drv/BlockDriver/BlockDriverImpl.cpp +++ b/Drv/BlockDriver/BlockDriverImpl.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include namespace Drv { diff --git a/Drv/BlockDriver/CMakeLists.txt b/Drv/BlockDriver/CMakeLists.txt index 2789e64813..38bb8281f4 100644 --- a/Drv/BlockDriver/CMakeLists.txt +++ b/Drv/BlockDriver/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Drv/ByteStreamDriverModel/CMakeLists.txt b/Drv/ByteStreamDriverModel/CMakeLists.txt index deb8ca334c..cf19e49396 100644 --- a/Drv/ByteStreamDriverModel/CMakeLists.txt +++ b/Drv/ByteStreamDriverModel/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Drv/ByteStreamDriverModel/docs/sdd.md b/Drv/ByteStreamDriverModel/docs/sdd.md index a4db565059..28353014c2 100644 --- a/Drv/ByteStreamDriverModel/docs/sdd.md +++ b/Drv/ByteStreamDriverModel/docs/sdd.md @@ -41,7 +41,7 @@ The following components implement the byte stream model using a callback format ![Poll](./img/canvas-poll.png) -In the callback formation, The manager component (typically the ground interface) initiates the transfer of received +In the polling formation, the manager component (typically the ground interface) initiates the transfer of received data by calling the "poll" input port. This port fills in the provided `Fw::Buffer` along with a status for the poll. This status is an enumeration whose values are described in the following table: @@ -64,10 +64,3 @@ implementations running on baremetal machines. | BYTEDRV-001 | The ByteStreamDriverModel shall provide the capability to send bytes | inspection | | BYTEDRV-002 | The ByteStreamDriverModel shall provide the capability to poll for bytes | inspection | | BYTEDRV-003 | The ByteStreamDriverModel shall provide the capability to produce bytes | inspection | - -## Change Log - -| Date | Description | -|---|---| -| 2020-12-17 | Initial Draft | -| 2021-01-28 | Updated | diff --git a/Drv/CMakeLists.txt b/Drv/CMakeLists.txt index 70d7471532..a9e30b762e 100644 --- a/Drv/CMakeLists.txt +++ b/Drv/CMakeLists.txt @@ -3,7 +3,6 @@ # Ports add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/DataTypes/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/GpioDriverPorts/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SerialDriverPorts/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SpiDriverPorts/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/I2cDriverPorts/") @@ -11,10 +10,9 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/I2cDriverPorts/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/BlockDriver/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ByteStreamDriverModel/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxGpioDriver/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxSerialDriver/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxUartDriver/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxSpiDriver/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxI2cDriver/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/UartFramer/") # IP Socket is only supported for Linux, Darwin, VxWorks if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR ${CMAKE_SYSTEM_NAME} STREQUAL "VxWorks") diff --git a/Drv/DataTypes/CMakeLists.txt b/Drv/DataTypes/CMakeLists.txt index 3c4e9a733b..fc85603c27 100644 --- a/Drv/DataTypes/CMakeLists.txt +++ b/Drv/DataTypes/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### @@ -10,4 +10,8 @@ set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/DataBuffer.cpp" ) +set(MOD_DEPS + Fw/Port +) + register_fprime_module() diff --git a/Drv/DataTypes/DataBuffer.hpp b/Drv/DataTypes/DataBuffer.hpp index 99215f5006..5530a5bbd0 100644 --- a/Drv/DataTypes/DataBuffer.hpp +++ b/Drv/DataTypes/DataBuffer.hpp @@ -1,7 +1,7 @@ #ifndef _DrvDataBuffer_hpp_ #define _DrvDataBuffer_hpp_ -#include +#include #include namespace Drv { diff --git a/Drv/GpioDriverPorts/CMakeLists.txt b/Drv/GpioDriverPorts/CMakeLists.txt index d0a12854be..8ed47ecc86 100644 --- a/Drv/GpioDriverPorts/CMakeLists.txt +++ b/Drv/GpioDriverPorts/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Drv/GpioDriverPorts/GpioDriverPorts.fpp b/Drv/GpioDriverPorts/GpioDriverPorts.fpp index ae37e09a77..9bb6a2297a 100644 --- a/Drv/GpioDriverPorts/GpioDriverPorts.fpp +++ b/Drv/GpioDriverPorts/GpioDriverPorts.fpp @@ -1,7 +1,7 @@ module Drv { port GpioWrite( - state: bool + state: Fw.Logic ) } @@ -9,7 +9,7 @@ module Drv { module Drv { port GpioRead( - ref state: bool + ref state: Fw.Logic ) } diff --git a/Drv/I2cDriverPorts/CMakeLists.txt b/Drv/I2cDriverPorts/CMakeLists.txt index 3ddc5212cb..c164cb9f43 100644 --- a/Drv/I2cDriverPorts/CMakeLists.txt +++ b/Drv/I2cDriverPorts/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Drv/I2cDriverPorts/I2cDriverPorts.fpp b/Drv/I2cDriverPorts/I2cDriverPorts.fpp index a540e7e1c0..6ceee79157 100644 --- a/Drv/I2cDriverPorts/I2cDriverPorts.fpp +++ b/Drv/I2cDriverPorts/I2cDriverPorts.fpp @@ -16,7 +16,8 @@ module Drv { I2C_ADDRESS_ERR = 1 @< I2C address invalid I2C_WRITE_ERR = 2 @< I2C write failed I2C_READ_ERR = 3 @< I2C read failed - I2C_OTHER_ERR = 4 @< Other errors that don't fit + I2C_OPEN_ERR = 4 @< I2C driver failed to open device + I2C_OTHER_ERR = 5 @< Other errors that don't fit } } diff --git a/Drv/Ip/CMakeLists.txt b/Drv/Ip/CMakeLists.txt index 39388ceb4e..0473c63867 100644 --- a/Drv/Ip/CMakeLists.txt +++ b/Drv/Ip/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Drv/Ip/IpSocket.cpp b/Drv/Ip/IpSocket.cpp index f5cf42d2b6..f7cfb7ecea 100644 --- a/Drv/Ip/IpSocket.cpp +++ b/Drv/Ip/IpSocket.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/Drv/Ip/IpSocket.hpp b/Drv/Ip/IpSocket.hpp index 870ea2e2fe..c0a4b77dd0 100644 --- a/Drv/Ip/IpSocket.hpp +++ b/Drv/Ip/IpSocket.hpp @@ -12,7 +12,7 @@ #ifndef DRV_IP_IPHELPER_HPP_ #define DRV_IP_IPHELPER_HPP_ -#include +#include #include #include @@ -99,7 +99,7 @@ class IpSocket { * \brief send data out the IP socket from the given buffer * * Sends data out of the IpSocket. This outgoing transmission will be retried several times if the transmission - * fails to send all the data. Retries are globally configured in the `SocketIpDriverCfg.hpp` header. Should the + * fails to send all the data. Retries are globally configured in the `IpCfg.hpp` header. Should the * socket be unavailable, SOCK_DISCONNECTED is returned and the socket should be reopened using the `open` call. * This can happen even when the socket has already been opened should a transmission error/closure be detected. * Unless an error is received, all data will have been transmitted. diff --git a/Drv/Ip/SocketReadTask.cpp b/Drv/Ip/SocketReadTask.cpp index 2124ccd92a..6c82289350 100644 --- a/Drv/Ip/SocketReadTask.cpp +++ b/Drv/Ip/SocketReadTask.cpp @@ -19,7 +19,7 @@ namespace Drv { -SocketReadTask::SocketReadTask() : m_stop(false) {} +SocketReadTask::SocketReadTask() : m_reconnect(false), m_stop(false) {} SocketReadTask::~SocketReadTask() {} diff --git a/Drv/Ip/TcpClientSocket.cpp b/Drv/Ip/TcpClientSocket.cpp index 9699b0a6c1..99f7d5017c 100644 --- a/Drv/Ip/TcpClientSocket.cpp +++ b/Drv/Ip/TcpClientSocket.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #ifdef TGT_OS_TYPE_VXWORKS #include diff --git a/Drv/Ip/TcpClientSocket.hpp b/Drv/Ip/TcpClientSocket.hpp index 079be73718..ebe1aa53b2 100644 --- a/Drv/Ip/TcpClientSocket.hpp +++ b/Drv/Ip/TcpClientSocket.hpp @@ -12,7 +12,7 @@ #ifndef DRV_TCPCLIENT_TCPHELPER_HPP_ #define DRV_TCPCLIENT_TCPHELPER_HPP_ -#include +#include #include #include diff --git a/Drv/Ip/TcpServerSocket.cpp b/Drv/Ip/TcpServerSocket.cpp index 10cc355350..ac4be73401 100644 --- a/Drv/Ip/TcpServerSocket.cpp +++ b/Drv/Ip/TcpServerSocket.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include #include -#include +#include #ifdef TGT_OS_TYPE_VXWORKS diff --git a/Drv/Ip/TcpServerSocket.hpp b/Drv/Ip/TcpServerSocket.hpp index 94ea98d3a2..9410d040d2 100644 --- a/Drv/Ip/TcpServerSocket.hpp +++ b/Drv/Ip/TcpServerSocket.hpp @@ -12,7 +12,7 @@ #ifndef DRV_TCPSERVER_TCPHELPER_HPP_ #define DRV_TCPSERVER_TCPHELPER_HPP_ -#include +#include #include #include diff --git a/Drv/Ip/UdpSocket.cpp b/Drv/Ip/UdpSocket.cpp index a748667fc9..6996e52b4b 100644 --- a/Drv/Ip/UdpSocket.cpp +++ b/Drv/Ip/UdpSocket.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #ifdef TGT_OS_TYPE_VXWORKS diff --git a/Drv/Ip/UdpSocket.hpp b/Drv/Ip/UdpSocket.hpp index afdec15378..c73126bd5c 100644 --- a/Drv/Ip/UdpSocket.hpp +++ b/Drv/Ip/UdpSocket.hpp @@ -12,7 +12,7 @@ #ifndef DRV_IP_UDPSOCKET_HPP_ #define DRV_IP_UDPSOCKET_HPP_ -#include +#include #include #include diff --git a/Drv/Ip/test/ut/PortSelector.hpp b/Drv/Ip/test/ut/PortSelector.hpp index fa7f6ef73b..07a1a5de5a 100644 --- a/Drv/Ip/test/ut/PortSelector.hpp +++ b/Drv/Ip/test/ut/PortSelector.hpp @@ -1,7 +1,7 @@ // // Created by mstarch on 12/10/20. // -#include +#include #ifndef DRV_TEST_PORTSELECTOR_HPP #define DRV_TEST_PORTSELECTOR_HPP diff --git a/Drv/Ip/test/ut/SocketTestHelper.hpp b/Drv/Ip/test/ut/SocketTestHelper.hpp index ec02921b63..71f6f12b84 100644 --- a/Drv/Ip/test/ut/SocketTestHelper.hpp +++ b/Drv/Ip/test/ut/SocketTestHelper.hpp @@ -1,7 +1,7 @@ // // Created by mstarch on 12/10/20. // -#include +#include #include #include diff --git a/Drv/LinuxGpioDriver/CMakeLists.txt b/Drv/LinuxGpioDriver/CMakeLists.txt index 8d2567ceae..d8d5692db5 100644 --- a/Drv/LinuxGpioDriver/CMakeLists.txt +++ b/Drv/LinuxGpioDriver/CMakeLists.txt @@ -1,10 +1,14 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### +if (NOT FPRIME_USE_STUBBED_DRIVERS) + restrict_platforms(Linux) +endif() + if(FPRIME_USE_STUBBED_DRIVERS) set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/LinuxGpioDriver.fpp" @@ -19,8 +23,6 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") "${CMAKE_CURRENT_LIST_DIR}/LinuxGpioDriverComponentImpl.cpp" ) register_fprime_module() -else() - message(STATUS "Cannot use ${CMAKE_CURRENT_LIST_DIR} with platform ${CMAKE_SYSTEM_NAME}. Skipping.") endif() diff --git a/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.cpp b/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.cpp index ca87395036..8f1dbab133 100644 --- a/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.cpp +++ b/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.cpp @@ -12,7 +12,7 @@ #include -#include +#include #include // TODO make proper static constants for these @@ -49,7 +49,7 @@ namespace Drv { } // TODO check value of len - len = snprintf(buf, sizeof(buf), "%d", gpio); + len = snprintf(buf, sizeof(buf), "%u", gpio); if(write(fd, buf, len) != len) { (void) close(fd); DEBUG_PRINT("gpio/export error!\n"); @@ -80,7 +80,7 @@ namespace Drv { } // TODO check value of len - len = snprintf(buf, sizeof(buf), "%d", gpio); + len = snprintf(buf, sizeof(buf), "%u", gpio); if(write(fd, buf, len) != len) { (void) close(fd); DEBUG_PRINT("gpio/unexport error!\n"); @@ -104,7 +104,7 @@ namespace Drv { int fd, len; char buf[MAX_BUF]; - len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/direction", gpio); + len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%u/direction", gpio); FW_ASSERT(len > 0, len); fd = open(buf, O_WRONLY); @@ -190,7 +190,7 @@ namespace Drv { FW_ASSERT(edge != nullptr); // TODO check that edge has correct values of "none", "rising", or "falling" - len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/edge", gpio); + len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%u/edge", gpio); FW_ASSERT(len > 0, len); fd = open(buf, O_WRONLY); @@ -219,7 +219,7 @@ namespace Drv { int fd, len; char buf[MAX_BUF]; - len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio); + len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%u/value", gpio); FW_ASSERT(len > 0, len); fd = open(buf, O_RDWR | O_NONBLOCK ); @@ -251,7 +251,7 @@ namespace Drv { void LinuxGpioDriverComponentImpl :: gpioRead_handler( const NATIVE_INT_TYPE portNum, - bool &state + Fw::Logic &state ) { FW_ASSERT(this->m_fd != -1); @@ -262,7 +262,7 @@ namespace Drv { this->log_WARNING_HI_GP_ReadError(this->m_gpio,stat); return; } else { - state = val?true:false; + state = val ? Fw::Logic::HIGH : Fw::Logic::LOW; } } @@ -270,14 +270,14 @@ namespace Drv { void LinuxGpioDriverComponentImpl :: gpioWrite_handler( const NATIVE_INT_TYPE portNum, - bool state + const Fw::Logic& state ) { FW_ASSERT(this->m_fd != -1); NATIVE_INT_TYPE stat; - stat = gpio_set_value(this->m_fd,state?1:0); + stat = gpio_set_value(this->m_fd,(state == Fw::Logic::HIGH) ? 1 : 0); if (0 != stat) { this->log_WARNING_HI_GP_WriteError(this->m_gpio,stat); diff --git a/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.hpp b/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.hpp index 2fbb2a916a..559dfccf2b 100644 --- a/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.hpp +++ b/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImpl.hpp @@ -70,14 +70,14 @@ namespace Drv { //! void gpioRead_handler( const NATIVE_INT_TYPE portNum, /*!< The port number*/ - bool &state + Fw::Logic &state ); //! Handler implementation for gpioWrite //! void gpioWrite_handler( const NATIVE_INT_TYPE portNum, /*!< The port number*/ - bool state + const Fw::Logic& state ); //! keep GPIO ID diff --git a/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImplCommon.cpp b/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImplCommon.cpp index 0df4643e2a..3fc402d806 100644 --- a/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImplCommon.cpp +++ b/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImplCommon.cpp @@ -12,7 +12,7 @@ #include -#include +#include namespace Drv { diff --git a/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImplStub.cpp b/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImplStub.cpp index d439cf095f..41663e8d67 100644 --- a/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImplStub.cpp +++ b/Drv/LinuxGpioDriver/LinuxGpioDriverComponentImplStub.cpp @@ -12,7 +12,7 @@ #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace Drv { @@ -23,7 +23,7 @@ namespace Drv { void LinuxGpioDriverComponentImpl :: gpioRead_handler( const NATIVE_INT_TYPE portNum, - bool &state + Fw::Logic &state ) { // TODO @@ -32,7 +32,7 @@ namespace Drv { void LinuxGpioDriverComponentImpl :: gpioWrite_handler( const NATIVE_INT_TYPE portNum, - bool state + const Fw::Logic& state ) { // TODO diff --git a/Drv/LinuxI2cDriver/CMakeLists.txt b/Drv/LinuxI2cDriver/CMakeLists.txt index 3d89deb124..43a4fff46f 100644 --- a/Drv/LinuxI2cDriver/CMakeLists.txt +++ b/Drv/LinuxI2cDriver/CMakeLists.txt @@ -1,25 +1,27 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### +if (NOT FPRIME_USE_STUBBED_DRIVERS) + restrict_platforms(Linux) +endif() + if(FPRIME_USE_STUBBED_DRIVERS) add_definitions(-DSTUBBED_LINUX_I2C_DRIVER) set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/LinuxI2cDriver.fpp" - "${CMAKE_CURRENT_LIST_DIR}/LinuxI2cDriverComponentImplStub.cpp" + "${CMAKE_CURRENT_LIST_DIR}/LinuxI2cDriverStub.cpp" ) register_fprime_module() elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/LinuxI2cDriver.fpp" - "${CMAKE_CURRENT_LIST_DIR}/LinuxI2cDriverComponentImpl.cpp" + "${CMAKE_CURRENT_LIST_DIR}/LinuxI2cDriver.cpp" ) register_fprime_module() -else() - message(STATUS "Cannot use ${CMAKE_CURRENT_LIST_DIR} with platform ${CMAKE_SYSTEM_NAME}. Skipping.") endif() diff --git a/Drv/LinuxI2cDriver/LinuxI2cDriverComponentImpl.cpp b/Drv/LinuxI2cDriver/LinuxI2cDriver.cpp similarity index 90% rename from Drv/LinuxI2cDriver/LinuxI2cDriverComponentImpl.cpp rename to Drv/LinuxI2cDriver/LinuxI2cDriver.cpp index 8519d4bc1e..9afb610d75 100644 --- a/Drv/LinuxI2cDriver/LinuxI2cDriverComponentImpl.cpp +++ b/Drv/LinuxI2cDriver/LinuxI2cDriver.cpp @@ -10,11 +10,10 @@ // // ====================================================================== - -#include -#include -#include "Fw/Types/BasicTypes.hpp" #include "Fw/Types/Assert.hpp" +#include +#include +#include #include // required for I2C device access #include // required for I2C device configuration @@ -31,8 +30,8 @@ namespace Drv { // Construction, initialization, and destruction // ---------------------------------------------------------------------- - LinuxI2cDriverComponentImpl :: - LinuxI2cDriverComponentImpl( + LinuxI2cDriver :: + LinuxI2cDriver( const char *const compName ) : LinuxI2cDriverComponentBase(compName), m_fd(-1) @@ -40,7 +39,7 @@ namespace Drv { } - void LinuxI2cDriverComponentImpl :: + void LinuxI2cDriver :: init( const NATIVE_INT_TYPE instance ) @@ -48,15 +47,15 @@ namespace Drv { LinuxI2cDriverComponentBase::init(instance); } - LinuxI2cDriverComponentImpl :: - ~LinuxI2cDriverComponentImpl() + LinuxI2cDriver:: + ~LinuxI2cDriver() { if (-1 != this->m_fd) { // check if file is open ::close(this->m_fd); } } - bool LinuxI2cDriverComponentImpl::open(const char* device) { + bool LinuxI2cDriver::open(const char* device) { FW_ASSERT(device); this->m_fd = ::open(device, O_RDWR); return (-1 != this->m_fd); @@ -69,7 +68,7 @@ namespace Drv { // Note this port handler is guarded, so we can make the ioctl call - Drv::I2cStatus LinuxI2cDriverComponentImpl :: + Drv::I2cStatus LinuxI2cDriver :: write_handler( const NATIVE_INT_TYPE portNum, U32 addr, @@ -77,7 +76,9 @@ namespace Drv { ) { // Make sure file has been opened - FW_ASSERT(-1 != this->m_fd); + if (-1 == this->m_fd) { + return I2cStatus::I2C_OPEN_ERR; + } #if DEBUG_PRINT Fw::Logger::logMsg("I2c addr: 0x%02X\n",addr); @@ -108,7 +109,7 @@ namespace Drv { return I2cStatus::I2C_OK; } - Drv::I2cStatus LinuxI2cDriverComponentImpl :: + Drv::I2cStatus LinuxI2cDriver :: read_handler( const NATIVE_INT_TYPE portNum, U32 addr, @@ -116,7 +117,9 @@ namespace Drv { ) { // Make sure file has been opened - FW_ASSERT(-1 != this->m_fd); + if (-1 == this->m_fd) { + return I2cStatus::I2C_OPEN_ERR; + } #if DEBUG_PRINT Fw::Logger::logMsg("I2c addr: 0x%02X\n",addr); @@ -149,7 +152,7 @@ namespace Drv { return I2cStatus::I2C_OK; } - Drv::I2cStatus LinuxI2cDriverComponentImpl :: + Drv::I2cStatus LinuxI2cDriver :: writeRead_handler( const NATIVE_INT_TYPE portNum, /*!< The port number*/ U32 addr, @@ -158,6 +161,9 @@ namespace Drv { ){ // Make sure file has been opened + if (-1 == this->m_fd) { + return I2cStatus::I2C_OPEN_ERR; + } FW_ASSERT(-1 != this->m_fd); // make sure they are not null pointers @@ -196,7 +202,7 @@ namespace Drv { Fw::Logger::logMsg("Status: %d Errno: %d\n", stat, errno); #endif //Because we're using ioctl to perform the transaction we dont know exactly the type of error that occurred - return Drv::I2cStatus::I2C_OTHER_ERR; + return I2cStatus::I2C_OTHER_ERR; } #if DEBUG_PRINT diff --git a/Drv/LinuxI2cDriver/LinuxI2cDriverComponentImpl.hpp b/Drv/LinuxI2cDriver/LinuxI2cDriver.hpp similarity index 90% rename from Drv/LinuxI2cDriver/LinuxI2cDriverComponentImpl.hpp rename to Drv/LinuxI2cDriver/LinuxI2cDriver.hpp index d5d17b2e85..02fdafd9c0 100644 --- a/Drv/LinuxI2cDriver/LinuxI2cDriverComponentImpl.hpp +++ b/Drv/LinuxI2cDriver/LinuxI2cDriver.hpp @@ -1,5 +1,5 @@ // ====================================================================== -// \title LinuxI2cDriverComponentImpl.hpp +// \title LinuxI2cDriver.hpp // \author tcanham // \brief hpp file for LinuxI2cDriver component implementation class // @@ -17,7 +17,7 @@ namespace Drv { - class LinuxI2cDriverComponentImpl : + class LinuxI2cDriver : public LinuxI2cDriverComponentBase { @@ -29,7 +29,7 @@ namespace Drv { //! Construct object LinuxI2cDriver //! - LinuxI2cDriverComponentImpl(const char *const compName); + LinuxI2cDriver(const char *const compName); //! Initialize object LinuxI2cDriver //! @@ -40,7 +40,7 @@ namespace Drv { bool open(const char* device); //! Destroy object LinuxI2cDriver //! - ~LinuxI2cDriverComponentImpl(); + ~LinuxI2cDriver(); PRIVATE: @@ -66,7 +66,7 @@ namespace Drv { //! Handler implementation for writeRead //! - Drv::I2cStatus writeRead_handler( + I2cStatus writeRead_handler( const NATIVE_INT_TYPE portNum, /*!< The port number*/ U32 addr, Fw::Buffer &writeBuffer, diff --git a/Drv/LinuxI2cDriver/LinuxI2cDriverComponentImplStub.cpp b/Drv/LinuxI2cDriver/LinuxI2cDriverStub.cpp similarity index 77% rename from Drv/LinuxI2cDriver/LinuxI2cDriverComponentImplStub.cpp rename to Drv/LinuxI2cDriver/LinuxI2cDriverStub.cpp index 91fdabd58e..b3346aed89 100644 --- a/Drv/LinuxI2cDriver/LinuxI2cDriverComponentImplStub.cpp +++ b/Drv/LinuxI2cDriver/LinuxI2cDriverStub.cpp @@ -1,5 +1,5 @@ // ====================================================================== -// \title LinuxI2cDriverComponentImpl.cpp +// \title LinuxI2cDriver.cpp // \author tcanham // \brief cpp file for LinuxI2cDriver component implementation class // @@ -10,10 +10,9 @@ // // ====================================================================== - -#include -#include "Fw/Types/BasicTypes.hpp" #include "Fw/Types/Assert.hpp" +#include +#include #define DEBUG_PRINT 0 @@ -23,15 +22,14 @@ namespace Drv { // Construction, initialization, and destruction // ---------------------------------------------------------------------- - LinuxI2cDriverComponentImpl :: - LinuxI2cDriverComponentImpl( +LinuxI2cDriver ::LinuxI2cDriver( const char *const compName ) : LinuxI2cDriverComponentBase(compName) { } - void LinuxI2cDriverComponentImpl :: + void LinuxI2cDriver :: init( const NATIVE_INT_TYPE instance ) @@ -39,13 +37,13 @@ namespace Drv { LinuxI2cDriverComponentBase::init(instance); } - LinuxI2cDriverComponentImpl :: - ~LinuxI2cDriverComponentImpl() + LinuxI2cDriver :: + ~LinuxI2cDriver() { } - bool LinuxI2cDriverComponentImpl::open(const char* device) { + bool LinuxI2cDriver::open(const char* device) { return true; } @@ -56,7 +54,7 @@ namespace Drv { // Note this port handler is guarded, so we can make the ioctl call - I2cStatus LinuxI2cDriverComponentImpl :: + I2cStatus LinuxI2cDriver :: write_handler( const NATIVE_INT_TYPE portNum, U32 addr, @@ -66,7 +64,7 @@ namespace Drv { return I2cStatus::I2C_OK; } - Drv::I2cStatus LinuxI2cDriverComponentImpl :: + Drv::I2cStatus LinuxI2cDriver :: read_handler( const NATIVE_INT_TYPE portNum, U32 addr, @@ -76,7 +74,7 @@ namespace Drv { return I2cStatus::I2C_OK; } - Drv::I2cStatus LinuxI2cDriverComponentImpl :: + Drv::I2cStatus LinuxI2cDriver :: writeRead_handler( const NATIVE_INT_TYPE portNum, /*!< The port number*/ U32 addr, diff --git a/Drv/LinuxI2cDriver/test/ut/Tester.hpp b/Drv/LinuxI2cDriver/test/ut/Tester.hpp index 51f8c73a71..b4a42ba83c 100644 --- a/Drv/LinuxI2cDriver/test/ut/Tester.hpp +++ b/Drv/LinuxI2cDriver/test/ut/Tester.hpp @@ -13,8 +13,8 @@ #ifndef TESTER_HPP #define TESTER_HPP +#include "Drv/LinuxI2cDriver/LinuxI2cDriver.hpp" #include "GTestBase.hpp" -#include "Drv/LinuxI2cDriver/LinuxI2cDriverComponentImpl.hpp" namespace Drv { @@ -70,7 +70,7 @@ namespace Drv { //! The component under test //! - LinuxI2cDriverComponentImpl component; + LinuxI2cDriver component; }; diff --git a/Drv/LinuxI2cDriver/test/ut/main.cpp b/Drv/LinuxI2cDriver/test/ut/main.cpp index b58acd8367..e989722b86 100644 --- a/Drv/LinuxI2cDriver/test/ut/main.cpp +++ b/Drv/LinuxI2cDriver/test/ut/main.cpp @@ -1,9 +1,9 @@ -#include #include -#include +#include #include #include #include +#include TEST(TestNominal,Nominal) { diff --git a/Drv/LinuxSerialDriver/CMakeLists.txt b/Drv/LinuxSerialDriver/CMakeLists.txt deleted file mode 100644 index db60b6b2dd..0000000000 --- a/Drv/LinuxSerialDriver/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -#### -# F prime CMakeLists.txt: -# -# SOURCE_FILES: combined list of source and autocoding diles -# MOD_DEPS: (optional) module dependencies -# -#### -set(MOD_DEPS Os) - -if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/LinuxSerialDriver.fpp" - "${CMAKE_CURRENT_LIST_DIR}/LinuxSerialDriverComponentImplCommon.cpp" - "${CMAKE_CURRENT_LIST_DIR}/LinuxSerialDriverComponentImpl.cpp" - ) - register_fprime_module() -else() - message(STATUS "Cannot use ${CMAKE_CURRENT_LIST_DIR} with platform ${CMAKE_SYSTEM_NAME}. Skipping.") -endif() - -### UTs ### -# Note: this UT expects user input -#set(UT_MOD_DEPS -# Os -#) -#set(UT_SOURCE_FILES -# "${CMAKE_CURRENT_LIST_DIR}/LinuxSerialDriverComponentAi.xml" -# "${CMAKE_CURRENT_LIST_DIR}/test/ut/main.cpp" -# "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" -#) -#register_fprime_ut() diff --git a/Drv/LinuxSerialDriver/LinuxSerialDriver.hpp b/Drv/LinuxSerialDriver/LinuxSerialDriver.hpp deleted file mode 100644 index 63bda9ab5c..0000000000 --- a/Drv/LinuxSerialDriver/LinuxSerialDriver.hpp +++ /dev/null @@ -1,17 +0,0 @@ -// ====================================================================== -// LinuxSerialDriver.hpp -// Standardization header for LinuxSerialDriver -// ====================================================================== - -#ifndef Drv_LinuxSerialDriver_HPP -#define Drv_LinuxSerialDriver_HPP - -#include "Drv/LinuxSerialDriver/LinuxSerialDriverComponentImpl.hpp" - -namespace Drv { - - using LinuxSerialDriver = LinuxSerialDriverComponentImpl; - -} - -#endif diff --git a/Drv/LinuxSerialDriver/LinuxSerialDriverComponentImpl.cpp b/Drv/LinuxSerialDriver/LinuxSerialDriverComponentImpl.cpp deleted file mode 100644 index dee01d2731..0000000000 --- a/Drv/LinuxSerialDriver/LinuxSerialDriverComponentImpl.cpp +++ /dev/null @@ -1,415 +0,0 @@ -// ====================================================================== -// \title LinuxSerialDriverImpl.cpp -// \author tcanham -// \brief cpp file for LinuxSerialDriver component implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - - -#include -#include "Fw/Types/BasicTypes.hpp" -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -//#define DEBUG_PRINT(x,...) printf(x,##__VA_ARGS__); fflush(stdout) -#define DEBUG_PRINT(x,...) - -namespace Drv { - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - bool LinuxSerialDriverComponentImpl::open(const char* const device, UartBaudRate baud, UartFlowControl fc, UartParity parity, bool block) { - // TODO remove printf - - NATIVE_INT_TYPE fd; - NATIVE_INT_TYPE stat; - - this->m_device = device; - - DEBUG_PRINT("Opening UART device %s\n", device); - - - // TODO can't use O_NDELAY and block (it is same as O_NONBLOCK), so removing NDELAY for now - /* - The O_NOCTTY flag tells UNIX that this program doesn't want to be the "controlling terminal" for that port. If you don't specify this then any input (such as keyboard abort signals and so forth) will affect your process. Programs like getty(1M/8) use this feature when starting the login process, but normally a user program does not want this behavior. - - The O_NDELAY flag tells UNIX that this program doesn't care what state the DCD signal line is in - whether the other end of the port is up and running. If you do not specify this flag, your process will be put to sleep until the DCD signal line is the space voltage. - */ - fd = ::open(device, O_RDWR | O_NOCTTY); // | O_NDELAY); - //fd = open(device, O_RDWR | O_NONBLOCK | O_SYNC); - - if (fd == -1) { - DEBUG_PRINT("open UART device %s failed.\n", device); - Fw::LogStringArg _arg = device; - Fw::LogStringArg _err = strerror(errno); - this->log_WARNING_HI_DR_OpenError(_arg,this->m_fd,_err); - return false; - } else { - DEBUG_PRINT("Successfully opened UART device %s fd %d\n", device, fd); - } - - this->m_fd = fd; - - // Configure blocking reads - struct termios cfg; - - stat = tcgetattr(fd,&cfg); - if (-1 == stat) { - DEBUG_PRINT("tcgetattr failed: (%d): %s\n",stat,strerror(errno)); - close(fd); - Fw::LogStringArg _arg = device; - Fw::LogStringArg _err = strerror(errno); - this->log_WARNING_HI_DR_OpenError(_arg,fd,_err); - return false; - } else { - DEBUG_PRINT("tcgetattr passed.\n"); - } - - /* - If MIN > 0 and TIME = 0, MIN sets the number of characters to receive before the read is satisfied. As TIME is zero, the timer is not used. - - If MIN = 0 and TIME > 0, TIME serves as a timeout value. The read will be satisfied if a single character is read, or TIME is exceeded (t = TIME *0.1 s). If TIME is exceeded, no character will be returned. - - If MIN > 0 and TIME > 0, TIME serves as an inter-character timer. The read will be satisfied if MIN characters are received, or the time between two characters exceeds TIME. The timer is restarted every time a character is received and only becomes active after the first character has been received. - - If MIN = 0 and TIME = 0, read will be satisfied immediately. The number of characters currently available, or the number of characters requested will be returned. According to Antonino (see contributions), you could issue a fcntl(fd, F_SETFL, FNDELAY); before reading to get the same result. - */ - // wait for at least 1 byte for 1 second - // TODO VMIN should be 0 when using VTIME, and then it would give the timeout behavior Tim wants - cfg.c_cc[VMIN] = 0; // TODO back to 0 - cfg.c_cc[VTIME] = 10; // 1 sec, TODO back to 10 - - stat = tcsetattr(fd,TCSANOW,&cfg); - if (-1 == stat) { - DEBUG_PRINT("tcsetattr failed: (%d): %s\n",stat,strerror(errno)); - close(fd); - Fw::LogStringArg _arg = device; - Fw::LogStringArg _err = strerror(errno); - this->log_WARNING_HI_DR_OpenError(_arg,fd,_err); - return false; - } else { - DEBUG_PRINT("tcsetattr passed.\n"); - } - - // Set flow control - if (fc == HW_FLOW) { - - struct termios t; - - int stat = tcgetattr(fd, &t); - if (-1 == stat) { - DEBUG_PRINT("tcgetattr UART fd %d failed\n", fd); - close(fd); - Fw::LogStringArg _arg = device; - Fw::LogStringArg _err = strerror(errno); - this->log_WARNING_HI_DR_OpenError(_arg,fd,_err); - return false; - } - - // modify flow control flags - t.c_cflag |= CRTSCTS; - - stat = tcsetattr(fd, TCSANOW, &t); - if (-1 == stat) { - DEBUG_PRINT("tcsetattr UART fd %d failed\n", fd); - close(fd); - Fw::LogStringArg _arg = device; - Fw::LogStringArg _err = strerror(errno); - this->log_WARNING_HI_DR_OpenError(_arg,fd,_err); - return false; - } - } - - NATIVE_INT_TYPE relayRate = B0; - switch (baud) { - // TODO add more as needed - case BAUD_9600: - relayRate = B9600; - break; - case BAUD_19200: - relayRate = B19200; - break; - case BAUD_38400: - relayRate = B38400; - break; - case BAUD_57600: - relayRate = B57600; - break; - case BAUD_115K: - relayRate = B115200; - break; - case BAUD_230K: - relayRate = B230400; - break; -#if defined TGT_OS_TYPE_LINUX - case BAUD_460K: - relayRate = B460800; - break; - case BAUD_921K: - relayRate = B921600; - break; -#endif - default: - FW_ASSERT(0,baud); - break; - } - - struct termios newtio; - - stat = tcgetattr(fd, &newtio); - if (-1 == stat) { - DEBUG_PRINT("tcgetattr UART fd %d failed\n", fd); - close(fd); - Fw::LogStringArg _arg = device; - Fw::LogStringArg _err = strerror(errno); - this->log_WARNING_HI_DR_OpenError(_arg,fd,_err); - return false; - } - - // CS8 = 8 data bits, CLOCAL = Local line, CREAD = Enable Receiver - // TODO PARENB for parity bit - /* - Even parity (7E1): - options.c_cflag |= PARENB - options.c_cflag &= ~PARODD - options.c_cflag &= ~CSTOPB - options.c_cflag &= ~CSIZE; - options.c_cflag |= CS7; - Odd parity (7O1): - options.c_cflag |= PARENB - options.c_cflag |= PARODD - options.c_cflag &= ~CSTOPB - options.c_cflag &= ~CSIZE; - options.c_cflag |= CS7; - */ - newtio.c_cflag = CS8 | CLOCAL | CREAD; - - switch (parity) { - case PARITY_ODD: - newtio.c_cflag |= (PARENB | PARODD) ; - break; - case PARITY_EVEN: - newtio.c_cflag |= PARENB ; - break; - case PARITY_NONE: - newtio.c_cflag &= ~PARENB ; - break; - default: - FW_ASSERT(0,parity); - break; - } - - // Set baud rate: - stat = cfsetispeed(&newtio, relayRate); - if (stat) { - DEBUG_PRINT("cfsetispeed failed\n"); - close(fd); - Fw::LogStringArg _arg = device; - Fw::LogStringArg _err = strerror(errno); - this->log_WARNING_HI_DR_OpenError(_arg,fd,_err); - return false; - } - stat = cfsetospeed(&newtio, relayRate); - if (stat) { - DEBUG_PRINT("cfsetospeed failed\n"); - close(fd); - Fw::LogStringArg _arg = device; - Fw::LogStringArg _err = strerror(errno); - this->log_WARNING_HI_DR_OpenError(_arg,fd,_err); - return false; - } - - // Raw output: - newtio.c_oflag = 0; - - // set input mode (non-canonical, no echo,...) - newtio.c_lflag = 0; - - // TODO if parity, then do input parity too - //options.c_iflag |=INPCK; - newtio.c_iflag = INPCK; - - // Flush old data: - (void) tcflush(fd, TCIFLUSH); - - // Set attributes: - stat = tcsetattr(fd,TCSANOW,&newtio); - if (-1 == stat) { - DEBUG_PRINT("tcsetattr UART fd %d failed\n", fd); - close(fd); - Fw::LogStringArg _arg = device; - Fw::LogStringArg _err = strerror(errno); - this->log_WARNING_HI_DR_OpenError(_arg,fd,_err); - return false; - } - - // All done! - Fw::LogStringArg _arg = device; - this->log_ACTIVITY_HI_DR_PortOpened(_arg); - return true; - } - - LinuxSerialDriverComponentImpl :: - ~LinuxSerialDriverComponentImpl() - { - if (this->m_fd != -1) { - DEBUG_PRINT("Closing UART device %d\n", this->m_fd); - - (void) close(this->m_fd); - } - } - - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - void LinuxSerialDriverComponentImpl :: - serialSend_handler( - const NATIVE_INT_TYPE portNum, - Fw::Buffer &serBuffer - ) - { - if (this->m_fd == -1) { - return; - } - - unsigned char* data = serBuffer.getData(); - NATIVE_INT_TYPE xferSize = serBuffer.getSize(); - - NATIVE_INT_TYPE stat = ::write(this->m_fd,data,xferSize); - - // TODO no need to delay for writes b/c the write blocks - // not sure if it will block until everything is transmitted, but seems to - - if (-1 == stat || stat != xferSize) { - Fw::LogStringArg _arg = this->m_device; - this->log_WARNING_HI_DR_WriteError(_arg,stat); - } - } - - void LinuxSerialDriverComponentImpl :: - serialReadTaskEntry(void * ptr) { - - Drv::SerialReadStatus serReadStat; // added by m.chase 03.06.2017 - - LinuxSerialDriverComponentImpl* comp = static_cast(ptr); - - Fw::Buffer buff; - - while (true) { - // wait for data - int sizeRead = 0; - - // find open buffer - - comp->m_readBuffMutex.lock(); - // search for open entry - NATIVE_INT_TYPE entryFound = false; - for (NATIVE_INT_TYPE entry = 0; entry < DR_MAX_NUM_BUFFERS; entry++) { - if (comp->m_buffSet[entry].available) { - comp->m_buffSet[entry].available = false; - buff = comp->m_buffSet[entry].readBuffer; - entryFound = true; - break; - } - } - comp->m_readBuffMutex.unLock(); - - if (not entryFound) { - Fw::LogStringArg _arg = comp->m_device; - comp->log_WARNING_HI_DR_NoBuffers(_arg); - serReadStat = SerialReadStatus::SER_NO_BUFFERS; // added by m.chase 03.06.2017 - comp->serialRecv_out(0,buff,serReadStat); - // to avoid spinning, wait 50 ms - Os::Task::delay(50); - continue; - } - -// timespec stime; -// (void)clock_gettime(CLOCK_REALTIME,&stime); -// DEBUG_PRINT("<<< Calling dsp_relay_uart_relay_read() at %d %d\n", stime.tv_sec, stime.tv_nsec); - - bool waiting = true; - int stat = 0; - - while (waiting) { - if (comp->m_quitReadThread) { - return; - } - - stat = ::read(comp->m_fd, - buff.getData(), - buff.getSize()); - - // Good read: - if (stat > 0) { - sizeRead = stat; - // TODO remove - static int totalSizeRead = 0; - totalSizeRead += sizeRead; - //printf("<<< totalSizeRead: %d, readSize: %d\n", totalSizeRead, sizeRead); - //printf("<<< read size: %d\n", stat); - } - - // check for timeout - if (0 == stat) { - if (comp->m_quitReadThread) { - return; - } - } else { // quit if other error or data - waiting = false; - } - } - - if (comp->m_quitReadThread) { - return; - } - - // check stat, maybe output event - if (stat == -1) { - // TODO(mereweth) - check errno - Fw::LogStringArg _arg = comp->m_device; - comp->log_WARNING_HI_DR_ReadError(_arg,stat); - serReadStat = SerialReadStatus::SER_OTHER_ERR; // added by m.chase 03.06.2017 - //comp->serialRecv_out(0,buff,Drv::SER_OTHER_ERR); - } else { -// (void)clock_gettime(CLOCK_REALTIME,&stime); -// DEBUG_PRINT("serialRecv_out(0,buff,Drv::SER_OK); - } - comp->serialRecv_out(0,buff,serReadStat); // added by m.chase 03.06.2017 - } - } - - void LinuxSerialDriverComponentImpl :: - startReadThread(NATIVE_UINT_TYPE priority, NATIVE_UINT_TYPE stackSize, NATIVE_UINT_TYPE cpuAffinity) { - - Os::TaskString task("SerReader"); - Os::Task::TaskStatus stat = this->m_readTask.start(task, serialReadTaskEntry, this, priority, stackSize, cpuAffinity); - FW_ASSERT(stat == Os::Task::TASK_OK, stat); - } - - void LinuxSerialDriverComponentImpl :: - quitReadThread() { - this->m_quitReadThread = true; - } - -} // end namespace Drv diff --git a/Drv/LinuxSerialDriver/LinuxSerialDriverComponentImpl.hpp b/Drv/LinuxSerialDriver/LinuxSerialDriverComponentImpl.hpp deleted file mode 100644 index dad0418ab8..0000000000 --- a/Drv/LinuxSerialDriver/LinuxSerialDriverComponentImpl.hpp +++ /dev/null @@ -1,124 +0,0 @@ -// ====================================================================== -// \title LinuxSerialDriverImpl.hpp -// \author tcanham -// \brief hpp file for LinuxSerialDriver component implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef LinuxSerialDriver_HPP -#define LinuxSerialDriver_HPP - -#include -#include -#include -#include - -namespace Drv { - - class LinuxSerialDriverComponentImpl : - public LinuxSerialDriverComponentBase - { - - public: - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - //! Construct object LinuxSerialDriver - //! - LinuxSerialDriverComponentImpl( - const char *const compName /*!< The component name*/ - ); - - //! Initialize object LinuxSerialDriver - //! - void init( - const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ - ); - - //! Configure UART parameters - typedef enum BAUD_RATE { - BAUD_9600, - BAUD_19200, - BAUD_38400, - BAUD_57600, - BAUD_115K, - BAUD_230K, - BAUD_460K, - BAUD_921K - } UartBaudRate ; - - typedef enum FLOW_CONTROL { - NO_FLOW, - HW_FLOW - } UartFlowControl; - - typedef enum PARITY { - PARITY_NONE, - PARITY_ODD, - PARITY_EVEN - } UartParity; - - // Open device with specified baud and flow control. - bool open(const char* const device, UartBaudRate baud, UartFlowControl fc, UartParity parity, bool block); - - //! start the serial poll thread. - //! buffSize is the max receive buffer size - //! - void startReadThread(NATIVE_UINT_TYPE priority = Os::Task::TASK_DEFAULT, NATIVE_UINT_TYPE stackSize = Os::Task::TASK_DEFAULT, NATIVE_UINT_TYPE cpuAffinity = Os::Task::TASK_DEFAULT); - - //! Quit thread - void quitReadThread(); - - //! Destroy object LinuxSerialDriver - //! - ~LinuxSerialDriverComponentImpl(); - - PRIVATE: - - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - //! Handler implementation for serialSend - //! - void serialSend_handler( - NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Buffer &serBuffer - ); - - //! Handler implementation for readBufferSend - //! - void readBufferSend_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Buffer& fwBuffer - ); - - NATIVE_INT_TYPE m_fd; //!< file descriptor returned for I/O device - const char* m_device; //!< original device path - - //! This method will be called by the new thread to wait for input on the serial port. - static void serialReadTaskEntry(void * ptr); - - Os::Task m_readTask; //!< task instance for thread to read serial port - - struct BufferSet { - Fw::Buffer readBuffer; //!< buffers for port reads - bool available; //!< is buffer available? - } m_buffSet[DR_MAX_NUM_BUFFERS]; - - Os::Mutex m_readBuffMutex; - - bool m_quitReadThread; //!< flag to quit thread - - }; - -} // end namespace Drv - -#endif diff --git a/Drv/LinuxSerialDriver/LinuxSerialDriverComponentImplCommon.cpp b/Drv/LinuxSerialDriver/LinuxSerialDriverComponentImplCommon.cpp deleted file mode 100644 index dbd2e0b787..0000000000 --- a/Drv/LinuxSerialDriver/LinuxSerialDriverComponentImplCommon.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * LinuxSerialDriverComponentImplCommon.cpp - * - * Created on: Nov 29, 2016 - * Author: tcanham - */ - -#include - -namespace Drv { - - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - LinuxSerialDriverComponentImpl :: - LinuxSerialDriverComponentImpl( - const char *const compName - ) : LinuxSerialDriverComponentBase(compName), - m_fd(-1), - m_device("NOT_EXIST"), - m_quitReadThread(false) - { - // initialize buffer set - for (NATIVE_INT_TYPE entry = 0; entry < DR_MAX_NUM_BUFFERS; entry++) { - this->m_buffSet[entry].available = false; - } - - } - - void LinuxSerialDriverComponentImpl :: - init( - const NATIVE_INT_TYPE instance - ) - { - LinuxSerialDriverComponentBase::init(instance); - } - - void LinuxSerialDriverComponentImpl :: - readBufferSend_handler( - const NATIVE_INT_TYPE portNum, - Fw::Buffer& Buffer - ) - { - this->m_readBuffMutex.lock(); - bool found = false; - - // search for open entry - for (NATIVE_UINT_TYPE entry = 0; entry < DR_MAX_NUM_BUFFERS; entry++) { - // Look for slots to fill. "Available" is from - // the perspective of the driver thread looking for - // buffers to fill, so add the buffer and make it available. - if (not this->m_buffSet[entry].available) { - this->m_buffSet[entry].readBuffer = Buffer; - this->m_buffSet[entry].available = true; - found = true; - break; - } - } - this->m_readBuffMutex.unLock(); - FW_ASSERT(found,Buffer.getContext()); - - } - -} diff --git a/Drv/LinuxSerialDriver/LinuxSerialDriverComponentImplStub.cpp b/Drv/LinuxSerialDriver/LinuxSerialDriverComponentImplStub.cpp deleted file mode 100644 index bd81a71a02..0000000000 --- a/Drv/LinuxSerialDriver/LinuxSerialDriverComponentImplStub.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// ====================================================================== -// \title LinuxSerialDriverImpl.cpp -// \author tcanham -// \brief cpp file for LinuxSerialDriver component implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - - -#include - -namespace Drv { - - LinuxSerialDriverComponentImpl :: - ~LinuxSerialDriverComponentImpl() - { - - } - - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - void LinuxSerialDriverComponentImpl :: - serialSend_handler( - const NATIVE_INT_TYPE portNum, - Fw::Buffer &serBuffer - ) - { - // TODO - } - - void LinuxSerialDriverComponentImpl :: - startReadThread(NATIVE_INT_TYPE priority, NATIVE_INT_TYPE stackSize, NATIVE_INT_TYPE cpuAffinity) { - } - - bool LinuxSerialDriverComponentImpl::open(const char* const device, UartBaudRate baud, UartFlowControl fc, UartParity parity, bool block) { - //TODO - return false; - } - - void LinuxSerialDriverComponentImpl :: - quitReadThread() { - } -} // end namespace Drv diff --git a/Drv/LinuxSerialDriver/LinuxSerialDriverComponentReport.txt b/Drv/LinuxSerialDriver/LinuxSerialDriverComponentReport.txt deleted file mode 100644 index 17f9ba4f81..0000000000 --- a/Drv/LinuxSerialDriver/LinuxSerialDriverComponentReport.txt +++ /dev/null @@ -1,6 +0,0 @@ -Input Ports: 2 -Output Ports: 5 -Channels: 2 - ChanIds: 0,1 -Events: 7 - EventIds: 0,1,2,3,4,5,6 diff --git a/Drv/LinuxSerialDriver/Telemetry.fppi b/Drv/LinuxSerialDriver/Telemetry.fppi deleted file mode 100644 index 1c8289b568..0000000000 --- a/Drv/LinuxSerialDriver/Telemetry.fppi +++ /dev/null @@ -1,5 +0,0 @@ -@ Bytes Sent -telemetry DR_BytesSent: U32 id 0 - -@ Bytes Received -telemetry DR_BytesRecv: U32 id 1 diff --git a/Drv/LinuxSerialDriver/test/ut/Tester.cpp b/Drv/LinuxSerialDriver/test/ut/Tester.cpp deleted file mode 100644 index 3dfd847313..0000000000 --- a/Drv/LinuxSerialDriver/test/ut/Tester.cpp +++ /dev/null @@ -1,223 +0,0 @@ -// ====================================================================== -// \title LinuxSerialDriver.hpp -// \author tcanham -// \brief cpp file for LinuxSerialDriver test harness implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#include "Tester.hpp" -#include -#include - - -#define INSTANCE 0 -#define MAX_HISTORY_SIZE 10 - -namespace Drv { - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - Tester :: - Tester(const char* const device, NATIVE_INT_TYPE numReadBuffers, NATIVE_INT_TYPE bufferSize, - LinuxSerialDriverComponentImpl::UartFlowControl flow, - LinuxSerialDriverComponentImpl::UartParity parity) : - LinuxSerialDriverTesterBase("Tester", MAX_HISTORY_SIZE), - component("LinuxSerialDriver") - ,m_numBuffers(numReadBuffers),m_bufferSize(bufferSize) - { - this->initComponents(); - this->connectPorts(); - - // allocate and configure buffers - for (NATIVE_INT_TYPE buffer = 0; buffer < m_numBuffers; buffer++) { - // initialize buffers - this->m_readData[buffer] = new BYTE[bufferSize]; - FW_ASSERT(this->m_readData[buffer]); - this->m_readBuffer[buffer].setdata(reinterpret_cast(this->m_readData[buffer])); - this->m_readBuffer[buffer].setsize(bufferSize); - this->m_readBuffer[buffer].setbufferID(buffer); - - // push buffers to serial port - this->invoke_to_readBufferSend(0,this->m_readBuffer[buffer]); - } - - // configure port - this->component.open(device,LinuxSerialDriverComponentImpl::BAUD_921K,flow,parity,true); - - // spawn driver thread - this->component.startReadThread(); - - } - - Tester :: - ~Tester() - { - // kill thread - this->component.quitReadThread(); - // free buffers - for (NATIVE_INT_TYPE buffer = 0; buffer < m_numBuffers; buffer++) { - // initialize buffers - delete[] this->m_readData[buffer]; - } - - } - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - void Tester :: - sendSerial(BYTE* data, NATIVE_INT_TYPE size) - { - Fw::Buffer buff; - buff.setdata(reinterpret_cast(data)); - buff.setsize(size); - - this->invoke_to_serialSend(0,buff); - - } - - // ---------------------------------------------------------------------- - // Handlers for typed from ports - // ---------------------------------------------------------------------- - - void Tester :: - from_serialRecv_handler( - const NATIVE_INT_TYPE portNum, - Fw::Buffer &serBuffer, - Drv::SerialReadStatus& status - ) - { -// this->pushFromPortEntry_serialRecv(serBuffer, status); - - static int numPkts = 0.0; - static int numErrs = 0; - //static BYTE expVal = 253; // ramp down, skipping xon and xoff - //static BYTE expVal = 255; // ramp down - static BYTE expVal = 0; // ramp up - - numPkts++; - - BYTE* ptr = (BYTE*) serBuffer.getdata(); - U32 error = 0; - printf("<< size: %d\n",serBuffer.getsize()); - for (NATIVE_UINT_TYPE byte = 0; byte < serBuffer.getsize(); byte++) { - //printf("%d: 0x%02X ",byte,ptr[byte]); - - // For this verification to work, must be sent ramping pattern of size of at least 256 -#if 1 - // ramp down, skipped xon and xoff (17 and 19) when sending - /*if (expVal == 19) expVal -= 1; - if (expVal == 17) expVal -= 1;*/ - - if (ptr[byte] != expVal && error == 0) { - - //error = 1; - printf("ERROR: exp: %d idx: %d got: %d size: %d\n",expVal,byte,ptr[byte],serBuffer.getsize()); - } - //--expVal; // ramp down - ++expVal; // ramp up -#endif - } - - //expVal = ptr[serBuffer.getsize()-1]-1; // ramp down - expVal = ptr[serBuffer.getsize()-1]+1; // ramp up - - if (error) { - numErrs++; - for (NATIVE_UINT_TYPE byte = 0; byte < serBuffer.getsize(); byte++) { - //printf("%d: 0x%02X ",byte,ptr[byte]); - } - - } - printf("\nTOTAL NUMBER OF ERRORS: %d\n",numErrs); - printf("TOTAL ERROR PERCENTAGE: %f\n", ((double)numErrs/(double)numPkts)*100.0); - printf("TOTAL NUMBER OF PACKETS: %d\n",numPkts); - printf("\n"); - printf("\n"); - - // send buffer back - this->m_readBuffer[serBuffer.getbufferID()].setsize(this->m_bufferSize); - this->invoke_to_readBufferSend(0,this->m_readBuffer[serBuffer.getbufferID()]); - } - - // ---------------------------------------------------------------------- - // Helper methods - // ---------------------------------------------------------------------- - - void Tester :: - connectPorts() - { - - // serialSend - this->connect_to_serialSend( - 0, - this->component.get_serialSend_InputPort(0) - ); - - // readBufferSend - this->connect_to_readBufferSend( - 0, - this->component.get_readBufferSend_InputPort(0) - ); - - // serialRecv - this->component.set_serialRecv_OutputPort( - 0, - this->get_from_serialRecv(0) - ); - - // Tlm - this->component.set_Tlm_OutputPort( - 0, - this->get_from_Tlm(0) - ); - - // Time - this->component.set_Time_OutputPort( - 0, - this->get_from_Time(0) - ); - - // Log - this->component.set_Log_OutputPort( - 0, - this->get_from_Log(0) - ); - - // LogText - this->component.set_LogText_OutputPort( - 0, - this->get_from_LogText(0) - ); - - } - - void Tester :: - initComponents() - { - this->init(); - this->component.init( - INSTANCE - ); - } - - void Tester::textLogIn( - const FwEventIdType id, //!< The event ID - Fw::Time& timeTag, //!< The time - const Fw::TextLogSeverity severity, //!< The severity - const Fw::TextLogString& text //!< The event string - ) { - TextLogEntry e = { id, timeTag, severity, text }; - - printTextLogHistoryEntry(e,stdout); - } - -} // end namespace Drv diff --git a/Drv/LinuxSerialDriver/test/ut/Tester.hpp b/Drv/LinuxSerialDriver/test/ut/Tester.hpp deleted file mode 100644 index 29213dd205..0000000000 --- a/Drv/LinuxSerialDriver/test/ut/Tester.hpp +++ /dev/null @@ -1,110 +0,0 @@ -// ====================================================================== -// \title LinuxSerialDriver/test/ut/Tester.hpp -// \author tcanham -// \brief hpp file for LinuxSerialDriver test harness implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef TESTER_HPP -#define TESTER_HPP - -enum { - READ_BUFF_SIZE = 4*1024, // This is large enough for the circular buffer - NUM_READ_BUFFERS = 100 -}; - -#include "TesterBase.hpp" -#include "Drv/LinuxSerialDriver/LinuxSerialDriverComponentImpl.hpp" - -namespace Drv { - - class Tester : - public LinuxSerialDriverTesterBase - { - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - public: - - //! Construct object Tester - //! - Tester(const char* const device, NATIVE_INT_TYPE numReadBuffers, NATIVE_INT_TYPE bufferSize, - LinuxSerialDriverComponentImpl::UartFlowControl flow, - LinuxSerialDriverComponentImpl::UartParity parity); - - //! Destroy object Tester - //! - ~Tester(); - - public: - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - //! Send serial data - //! - void sendSerial(BYTE* data, NATIVE_INT_TYPE size); - - private: - - // ---------------------------------------------------------------------- - // Handlers for typed from ports - // ---------------------------------------------------------------------- - - //! Handler for from_serialRecv - //! - void from_serialRecv_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Buffer &serBuffer, /*!< Buffer containing data*/ - Drv::SerialReadStatus& status /*!< Status of read*/ - ); - - private: - - // ---------------------------------------------------------------------- - // Helper methods - // ---------------------------------------------------------------------- - - //! Connect ports - //! - void connectPorts(); - - //! Initialize components - //! - void initComponents(); - - private: - - // ---------------------------------------------------------------------- - // Variables - // ---------------------------------------------------------------------- - - //! The component under test - //! - LinuxSerialDriverComponentImpl component; - - NATIVE_INT_TYPE m_numBuffers; - NATIVE_INT_TYPE m_bufferSize; - Fw::Buffer m_readBuffer[NUM_READ_BUFFERS]; - BYTE* m_readData[NUM_READ_BUFFERS]; - - void textLogIn( - const FwEventIdType id, //!< The event ID - Fw::Time& timeTag, //!< The time - const Fw::TextLogSeverity severity, //!< The severity - const Fw::TextLogString& text //!< The event string - ); - - }; - -} // end namespace Drv - -#endif diff --git a/Drv/LinuxSerialDriver/test/ut/main.cpp b/Drv/LinuxSerialDriver/test/ut/main.cpp deleted file mode 100644 index d75ddb22ba..0000000000 --- a/Drv/LinuxSerialDriver/test/ut/main.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// ---------------------------------------------------------------------- -// Main.cpp -// ---------------------------------------------------------------------- - -#include "Tester.hpp" -#include -#include "Drv/LinuxSerialDriver/LinuxSerialDriverComponentImpl.hpp" -#include - - -//TEST(Test, NominalTlm) { -// Svc::Tester tester; - // Allocate read buffer -// tester.nominalTlm(); -//} - -void run_simple_test(Drv::Tester& tester) -{ - BYTE pattern[] = {0xA5, 0xA5, 0xA5, 0xA5}; - - tester.sendSerial(pattern,FW_NUM_ARRAY_ELEMENTS(pattern)); - - // delay for 10 sec waiting for some receive data - printf ("Delaying 10 sec for UART input\n"); - Os::Task::delay(1000); -} - -void run_ramping_pattern_test(Drv::Tester& tester) -{ - BYTE pattern[256]; - for (U32 i = 0; i < FW_NUM_ARRAY_ELEMENTS(pattern); ++i) { - pattern[i] = i; - } - - for (NATIVE_INT_TYPE iter = 0; iter < 20*60*100; iter++) { - tester.sendSerial(pattern,FW_NUM_ARRAY_ELEMENTS(pattern)); - Os::Task::delay(1); - } -} - -void run_router_test(Drv::Tester& tester) -{ - - // Fake FcRouter packet: - const int FC_ROUTER_PKT_SIZE = 75; - BYTE pattern[FC_ROUTER_PKT_SIZE]; - memset(pattern,0,sizeof(pattern)); - pattern[0] = 0xa5; - pattern[1] = 0x47; - pattern[2] = 0x1; - pattern[3] = 0x45; - - pattern[FC_ROUTER_PKT_SIZE-2] = 0xe6; - pattern[FC_ROUTER_PKT_SIZE-1] = 0xd5; - - for (NATIVE_INT_TYPE iter = 0; iter < 20*60*100; iter++) { - tester.sendSerial(pattern,FW_NUM_ARRAY_ELEMENTS(pattern)); - Os::Task::delay(1); - } -} - - -int main(int argc, char **argv) { - if ((argc < 1) || (argv[1] == nullptr)) { - printf("Need arg - name of device to open\n"); - return 1; - } - - Drv::Tester tester(argv[1],20,READ_BUFF_SIZE, - Drv::LinuxSerialDriverComponentImpl::NO_FLOW, - Drv::LinuxSerialDriverComponentImpl::PARITY_NONE); - - run_simple_test(tester); -// run_ramping_pattern_test(tester); -// run_router_test(tester); - -} diff --git a/Drv/LinuxSpiDriver/CMakeLists.txt b/Drv/LinuxSpiDriver/CMakeLists.txt index 4d9aa7ecdd..8de2c478bf 100644 --- a/Drv/LinuxSpiDriver/CMakeLists.txt +++ b/Drv/LinuxSpiDriver/CMakeLists.txt @@ -1,10 +1,13 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### +if (NOT FPRIME_USE_STUBBED_DRIVERS) + restrict_platforms(Linux) +endif() if(FPRIME_USE_STUBBED_DRIVERS) set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/LinuxSpiDriver.fpp" @@ -19,7 +22,5 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") "${CMAKE_CURRENT_LIST_DIR}/LinuxSpiDriverComponentImpl.cpp" ) register_fprime_module() -else() - message(STATUS "Cannot use ${CMAKE_CURRENT_LIST_DIR} with platform ${CMAKE_SYSTEM_NAME}. Skipping.") endif() diff --git a/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.cpp b/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.cpp index c84567ccae..180e0103a4 100644 --- a/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.cpp +++ b/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include -#include "Fw/Types/BasicTypes.hpp" +#include #include #include @@ -46,8 +46,8 @@ namespace Drv { spi_ioc_transfer tr; // Zero for unused fields: memset(&tr, 0, sizeof(tr)); - tr.tx_buf = reinterpret_cast(writeBuffer.getData()); - tr.rx_buf = reinterpret_cast(readBuffer.getData()); + tr.tx_buf = reinterpret_cast<__u64>(writeBuffer.getData()); + tr.rx_buf = reinterpret_cast<__u64>(readBuffer.getData()); tr.len = writeBuffer.getSize(); /* .speed_hz = 0, @@ -66,8 +66,6 @@ namespace Drv { } this->m_bytes += readBuffer.getSize(); this->tlmWrite_SPI_Bytes(this->m_bytes); - return; - } bool LinuxSpiDriverComponentImpl::open(NATIVE_INT_TYPE device, diff --git a/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImplCommon.cpp b/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImplCommon.cpp index 9de8bbd5e8..7a8b03f451 100644 --- a/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImplCommon.cpp +++ b/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImplCommon.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace Drv { diff --git a/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImplStub.cpp b/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImplStub.cpp index ab030c8ca2..3b3ebe0aa6 100644 --- a/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImplStub.cpp +++ b/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImplStub.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace Drv { diff --git a/Drv/LinuxUartDriver/CMakeLists.txt b/Drv/LinuxUartDriver/CMakeLists.txt new file mode 100644 index 0000000000..8212f62a5a --- /dev/null +++ b/Drv/LinuxUartDriver/CMakeLists.txt @@ -0,0 +1,15 @@ +#### +# F prime CMakeLists.txt: +# +# SOURCE_FILES: combined list of source and autocoding files +# MOD_DEPS: (optional) module dependencies +# +#### +restrict_platforms(Linux Darwin) + +set(MOD_DEPS Os) +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/LinuxUartDriver.fpp" + "${CMAKE_CURRENT_LIST_DIR}/LinuxUartDriver.cpp" +) +register_fprime_module() diff --git a/Drv/LinuxSerialDriver/Events.fppi b/Drv/LinuxUartDriver/Events.fppi similarity index 92% rename from Drv/LinuxSerialDriver/Events.fppi rename to Drv/LinuxUartDriver/Events.fppi index 899aa1c8b2..cd430d0c72 100644 --- a/Drv/LinuxSerialDriver/Events.fppi +++ b/Drv/LinuxUartDriver/Events.fppi @@ -1,5 +1,5 @@ @ UART open error -event DR_OpenError( +event OpenError( device: string size 40 @< The device error: I32 @< The error code name: string size 40 @< error string @@ -9,7 +9,7 @@ event DR_OpenError( format "Error opening UART device {}: {} {}" @ UART config error -event DR_ConfigError( +event ConfigError( device: string size 40 @< The device error: I32 @< The error code ) \ @@ -18,7 +18,7 @@ event DR_ConfigError( format "Error configuring UART device {}: {}" @ UART write error -event DR_WriteError( +event WriteError( device: string size 40 @< The device error: I32 @< The error code ) \ @@ -28,7 +28,7 @@ event DR_WriteError( throttle 5 @ UART read error -event DR_ReadError( +event ReadError( device: string size 40 @< The device error: I32 @< The error code ) \ @@ -38,7 +38,7 @@ event DR_ReadError( throttle 5 @ UART port opened event -event DR_PortOpened( +event PortOpened( device: string size 40 @< The device ) \ severity activity high \ @@ -46,7 +46,7 @@ event DR_PortOpened( format "UART Device {} configured" @ UART ran out of buffers -event DR_NoBuffers( +event NoBuffers( device: string size 40 @< The device ) \ severity warning high \ @@ -55,7 +55,7 @@ event DR_NoBuffers( throttle 20 @ UART ran out of buffers -event DR_BufferTooSmall( +event BufferTooSmall( device: string size 40 @< The device $size: U32 @< The provided buffer size needed: U32 @< The buffer size needed diff --git a/Drv/LinuxUartDriver/LinuxUartDriver.cpp b/Drv/LinuxUartDriver/LinuxUartDriver.cpp new file mode 100644 index 0000000000..0357c1f0a2 --- /dev/null +++ b/Drv/LinuxUartDriver/LinuxUartDriver.cpp @@ -0,0 +1,377 @@ +// ====================================================================== +// \title LinuxUartDriverImpl.cpp +// \author tcanham +// \brief cpp file for LinuxUartDriver component implementation class +// +// \copyright +// Copyright 2009-2015, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include +#include +#include + +#include "Fw/Types/BasicTypes.hpp" + +#include +#include +#include + +//#include +//#include +//#define DEBUG_PRINT(x,...) printf(x,##__VA_ARGS__); fflush(stdout) +#define DEBUG_PRINT(x, ...) + +namespace Drv { + +// ---------------------------------------------------------------------- +// Construction, initialization, and destruction +// ---------------------------------------------------------------------- + +LinuxUartDriver ::LinuxUartDriver(const char* const compName) + : LinuxUartDriverComponentBase(compName), m_fd(-1), m_allocationSize(-1), m_device("NOT_EXIST"), m_quitReadThread(false) { +} + +void LinuxUartDriver ::init(const NATIVE_INT_TYPE instance) { + LinuxUartDriverComponentBase::init(instance); +} + +bool LinuxUartDriver::open(const char* const device, + UartBaudRate baud, + UartFlowControl fc, + UartParity parity, + NATIVE_INT_TYPE allocationSize) { + FW_ASSERT(device != nullptr); + NATIVE_INT_TYPE fd = -1; + NATIVE_INT_TYPE stat = -1; + this->m_allocationSize = allocationSize; + + this->m_device = device; + + DEBUG_PRINT("Opening UART device %s\n", device); + + /* + The O_NOCTTY flag tells UNIX that this program doesn't want to be the "controlling terminal" for that port. If you + don't specify this then any input (such as keyboard abort signals and so forth) will affect your process. Programs + like getty(1M/8) use this feature when starting the login process, but normally a user program does not want this + behavior. + */ + fd = ::open(device, O_RDWR | O_NOCTTY); + + if (fd == -1) { + DEBUG_PRINT("open UART device %s failed.\n", device); + Fw::LogStringArg _arg = device; + Fw::LogStringArg _err = strerror(errno); + this->log_WARNING_HI_OpenError(_arg, this->m_fd, _err); + return false; + } else { + DEBUG_PRINT("Successfully opened UART device %s fd %d\n", device, fd); + } + + this->m_fd = fd; + + // Configure blocking reads + struct termios cfg; + + stat = tcgetattr(fd, &cfg); + if (-1 == stat) { + DEBUG_PRINT("tcgetattr failed: (%d): %s\n", stat, strerror(errno)); + close(fd); + Fw::LogStringArg _arg = device; + Fw::LogStringArg _err = strerror(errno); + this->log_WARNING_HI_OpenError(_arg, fd, _err); + return false; + } else { + DEBUG_PRINT("tcgetattr passed.\n"); + } + + /* + If MIN > 0 and TIME = 0, MIN sets the number of characters to receive before the read is satisfied. As TIME is + zero, the timer is not used. + + If MIN = 0 and TIME > 0, TIME serves as a timeout value. The read will be satisfied if a single character is read, + or TIME is exceeded (t = TIME *0.1 s). If TIME is exceeded, no character will be returned. + + If MIN > 0 and TIME > 0, TIME serves as an inter-character timer. The read will be satisfied if MIN characters are + received, or the time between two characters exceeds TIME. The timer is restarted every time a character is + received and only becomes active after the first character has been received. + + If MIN = 0 and TIME = 0, read will be satisfied immediately. The number of characters currently available, or the + number of characters requested will be returned. According to Antonino (see contributions), you could issue a + fcntl(fd, F_SETFL, FNDELAY); before reading to get the same result. + */ + cfg.c_cc[VMIN] = 0; + cfg.c_cc[VTIME] = 10; // 1 sec timeout on no-data + + stat = tcsetattr(fd, TCSANOW, &cfg); + if (-1 == stat) { + DEBUG_PRINT("tcsetattr failed: (%d): %s\n", stat, strerror(errno)); + close(fd); + Fw::LogStringArg _arg = device; + Fw::LogStringArg _err = strerror(errno); + this->log_WARNING_HI_OpenError(_arg, fd, _err); + return false; + } else { + DEBUG_PRINT("tcsetattr passed.\n"); + } + + // Set flow control + if (fc == HW_FLOW) { + struct termios t; + + int stat = tcgetattr(fd, &t); + if (-1 == stat) { + DEBUG_PRINT("tcgetattr UART fd %d failed\n", fd); + close(fd); + Fw::LogStringArg _arg = device; + Fw::LogStringArg _err = strerror(errno); + this->log_WARNING_HI_OpenError(_arg, fd, _err); + return false; + } + + // modify flow control flags + t.c_cflag |= CRTSCTS; + + stat = tcsetattr(fd, TCSANOW, &t); + if (-1 == stat) { + DEBUG_PRINT("tcsetattr UART fd %d failed\n", fd); + close(fd); + Fw::LogStringArg _arg = device; + Fw::LogStringArg _err = strerror(errno); + this->log_WARNING_HI_OpenError(_arg, fd, _err); + return false; + } + } + + NATIVE_INT_TYPE relayRate = B0; + switch (baud) { + case BAUD_9600: + relayRate = B9600; + break; + case BAUD_19200: + relayRate = B19200; + break; + case BAUD_38400: + relayRate = B38400; + break; + case BAUD_57600: + relayRate = B57600; + break; + case BAUD_115K: + relayRate = B115200; + break; + case BAUD_230K: + relayRate = B230400; + break; +#if defined TGT_OS_TYPE_LINUX + case BAUD_460K: + relayRate = B460800; + break; + case BAUD_921K: + relayRate = B921600; + break; +#endif + default: + FW_ASSERT(0, baud); + break; + } + + struct termios newtio; + + stat = tcgetattr(fd, &newtio); + if (-1 == stat) { + DEBUG_PRINT("tcgetattr UART fd %d failed\n", fd); + close(fd); + Fw::LogStringArg _arg = device; + Fw::LogStringArg _err = strerror(errno); + this->log_WARNING_HI_OpenError(_arg, fd, _err); + return false; + } + + // CS8 = 8 data bits, CLOCAL = Local line, CREAD = Enable Receiver + /* + Even parity (7E1): + options.c_cflag |= PARENB + options.c_cflag &= ~PARODD + options.c_cflag &= ~CSTOPB + options.c_cflag &= ~CSIZE; + options.c_cflag |= CS7; + Odd parity (7O1): + options.c_cflag |= PARENB + options.c_cflag |= PARODD + options.c_cflag &= ~CSTOPB + options.c_cflag &= ~CSIZE; + options.c_cflag |= CS7; + */ + newtio.c_cflag |= CS8 | CLOCAL | CREAD; + + switch (parity) { + case PARITY_ODD: + newtio.c_cflag |= (PARENB | PARODD); + break; + case PARITY_EVEN: + newtio.c_cflag |= PARENB; + break; + case PARITY_NONE: + newtio.c_cflag &= ~PARENB; + break; + default: + FW_ASSERT(0, parity); + break; + } + + // Set baud rate: + stat = cfsetispeed(&newtio, relayRate); + if (stat) { + DEBUG_PRINT("cfsetispeed failed\n"); + close(fd); + Fw::LogStringArg _arg = device; + Fw::LogStringArg _err = strerror(errno); + this->log_WARNING_HI_OpenError(_arg, fd, _err); + return false; + } + stat = cfsetospeed(&newtio, relayRate); + if (stat) { + DEBUG_PRINT("cfsetospeed failed\n"); + close(fd); + Fw::LogStringArg _arg = device; + Fw::LogStringArg _err = strerror(errno); + this->log_WARNING_HI_OpenError(_arg, fd, _err); + return false; + } + + // Raw output: + newtio.c_oflag = 0; + + // set input mode (non-canonical, no echo,...) + newtio.c_lflag = 0; + + newtio.c_iflag = INPCK; + + // Flush old data: + (void)tcflush(fd, TCIFLUSH); + + // Set attributes: + stat = tcsetattr(fd, TCSANOW, &newtio); + if (-1 == stat) { + DEBUG_PRINT("tcsetattr UART fd %d failed\n", fd); + close(fd); + Fw::LogStringArg _arg = device; + Fw::LogStringArg _err = strerror(errno); + this->log_WARNING_HI_OpenError(_arg, fd, _err); + return false; + } + + // All done! + Fw::LogStringArg _arg = device; + this->log_ACTIVITY_HI_PortOpened(_arg); + if (this->isConnected_ready_OutputPort(0)) { + this->ready_out(0); // Indicate the driver is connected + } + return true; +} + +LinuxUartDriver ::~LinuxUartDriver() { + if (this->m_fd != -1) { + DEBUG_PRINT("Closing UART device %d\n", this->m_fd); + + (void)close(this->m_fd); + } +} + +// ---------------------------------------------------------------------- +// Handler implementations for user-defined typed input ports +// ---------------------------------------------------------------------- + +Drv::SendStatus LinuxUartDriver ::send_handler(const NATIVE_INT_TYPE portNum, Fw::Buffer& serBuffer) { + Drv::SendStatus status = Drv::SendStatus::SEND_OK; + if (this->m_fd == -1 || serBuffer.getData() == nullptr || serBuffer.getSize() == 0) { + status = Drv::SendStatus::SEND_ERROR; + } else { + unsigned char *data = serBuffer.getData(); + NATIVE_INT_TYPE xferSize = serBuffer.getSize(); + + NATIVE_INT_TYPE stat = ::write(this->m_fd, data, xferSize); + + if (-1 == stat || stat != xferSize) { + Fw::LogStringArg _arg = this->m_device; + this->log_WARNING_HI_WriteError(_arg, stat); + status = Drv::SendStatus::SEND_ERROR; + } + } + // Deallocate when necessary + if (isConnected_deallocate_OutputPort(0)) { + deallocate_out(0, serBuffer); + } + return status; +} + +void LinuxUartDriver ::serialReadTaskEntry(void* ptr) { + FW_ASSERT(ptr != nullptr); + Drv::RecvStatus status = RecvStatus::RECV_ERROR; // added by m.chase 03.06.2017 + LinuxUartDriver* comp = reinterpret_cast(ptr); + while (!comp->m_quitReadThread) { + Fw::Buffer buff = comp->allocate_out(0, comp->m_allocationSize); + + // On failed allocation, error and deallocate + if (buff.getData() == nullptr) { + Fw::LogStringArg _arg = comp->m_device; + comp->log_WARNING_HI_NoBuffers(_arg); + status = RecvStatus::RECV_ERROR; + comp->recv_out(0, buff, status); + // to avoid spinning, wait 50 ms + Os::Task::delay(50); + continue; + } + + // timespec stime; + // (void)clock_gettime(CLOCK_REALTIME,&stime); + // DEBUG_PRINT("<<< Calling dsp_relay_uart_relay_read() at %d %d\n", stime.tv_sec, stime.tv_nsec); + + int stat = 0; + + // Read until something is received or an error occurs. Only loop when + // stat == 0 as this is the timeout condition and the read should spin + while ((stat == 0) && !comp->m_quitReadThread) { + stat = ::read(comp->m_fd, buff.getData(), buff.getSize()); + } + buff.setSize(0); + + // On error stat (-1) must mark the read as error + // On normal stat (>0) pass a recv ok + // On timeout stat (0) and m_quitReadThread, error to return the buffer + if (stat == -1) { + Fw::LogStringArg _arg = comp->m_device; + comp->log_WARNING_HI_ReadError(_arg, stat); + status = RecvStatus::RECV_ERROR; + } else if (stat > 0) { + buff.setSize(stat); + status = RecvStatus::RECV_OK; // added by m.chase 03.06.2017 + } else { + status = RecvStatus::RECV_ERROR; // Simply to return the buffer + } + comp->recv_out(0, buff, status); // added by m.chase 03.06.2017 + } +} + +void LinuxUartDriver ::startReadThread(NATIVE_UINT_TYPE priority, + NATIVE_UINT_TYPE stackSize, + NATIVE_UINT_TYPE cpuAffinity) { + Os::TaskString task("SerReader"); + Os::Task::TaskStatus stat = + this->m_readTask.start(task, serialReadTaskEntry, this, priority, stackSize, cpuAffinity); + FW_ASSERT(stat == Os::Task::TASK_OK, stat); +} + +void LinuxUartDriver ::quitReadThread() { + this->m_quitReadThread = true; +} + +Os::Task::TaskStatus LinuxUartDriver ::join(void** value_ptr) { + return m_readTask.join(value_ptr); +} + +} // end namespace Drv diff --git a/Drv/LinuxSerialDriver/LinuxSerialDriver.fpp b/Drv/LinuxUartDriver/LinuxUartDriver.fpp similarity index 61% rename from Drv/LinuxSerialDriver/LinuxSerialDriver.fpp rename to Drv/LinuxUartDriver/LinuxUartDriver.fpp index f41b4b8838..151ef8b825 100644 --- a/Drv/LinuxSerialDriver/LinuxSerialDriver.fpp +++ b/Drv/LinuxUartDriver/LinuxUartDriver.fpp @@ -1,14 +1,25 @@ module Drv { - passive component LinuxSerialDriver { + passive component LinuxUartDriver { # ---------------------------------------------------------------------- # General ports # ---------------------------------------------------------------------- - sync input port readBufferSend: Fw.BufferSend + @ Indicates the driver has connected to the UART device + output port ready: Drv.ByteStreamReady - sync input port serialSend: Drv.SerialWrite + @ Produces data received via the UART device on the receive task + output port $recv: Drv.ByteStreamRecv + + @ Takes data to transmit out the UART device + guarded input port send: Drv.ByteStreamSend + + @ Allocation port used for allocating memory in the receive task + output port allocate: Fw.BufferGet + + @ Deallocates buffers passed to the "send" port + output port deallocate: Fw.BufferSend # ---------------------------------------------------------------------- # Special ports @@ -16,8 +27,6 @@ module Drv { event port Log - output port serialRecv: Drv.SerialRead - telemetry port Tlm text event port LogText diff --git a/Drv/LinuxUartDriver/LinuxUartDriver.hpp b/Drv/LinuxUartDriver/LinuxUartDriver.hpp new file mode 100644 index 0000000000..282ea5f106 --- /dev/null +++ b/Drv/LinuxUartDriver/LinuxUartDriver.hpp @@ -0,0 +1,91 @@ +// ====================================================================== +// \title LinuxUartDriverImpl.hpp +// \author tcanham +// \brief hpp file for LinuxUartDriver component implementation class +// +// \copyright +// Copyright 2009-2015, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#ifndef LinuxUartDriver_HPP +#define LinuxUartDriver_HPP + +#include +#include +#include + +namespace Drv { + +class LinuxUartDriver : public LinuxUartDriverComponentBase { + public: + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + //! Construct object LinuxUartDriver + //! + LinuxUartDriver(const char* const compName /*!< The component name*/ + ); + + //! Initialize object LinuxUartDriver + //! + void init(const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ + ); + + //! Configure UART parameters + enum UartBaudRate { BAUD_9600=9600, BAUD_19200=19200, BAUD_38400=38400, BAUD_57600=57600, BAUD_115K=115200, BAUD_230K=230400, BAUD_460K=460800, BAUD_921K=921600}; + + enum UartFlowControl { NO_FLOW, HW_FLOW }; + + enum UartParity { PARITY_NONE, PARITY_ODD, PARITY_EVEN }; + + // Open device with specified baud and flow control. + bool open(const char* const device, UartBaudRate baud, UartFlowControl fc, UartParity parity, NATIVE_INT_TYPE allocationSize); + + //! start the serial poll thread. + //! buffSize is the max receive buffer size + //! + void startReadThread(NATIVE_UINT_TYPE priority = Os::Task::TASK_DEFAULT, + NATIVE_UINT_TYPE stackSize = Os::Task::TASK_DEFAULT, + NATIVE_UINT_TYPE cpuAffinity = Os::Task::TASK_DEFAULT); + + //! Quit thread + void quitReadThread(); + + //! Join thread + Os::Task::TaskStatus join(void** value_ptr); + + //! Destroy object LinuxUartDriver + //! + ~LinuxUartDriver(); + + PRIVATE: + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for serialSend + //! + Drv::SendStatus send_handler(NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Buffer& serBuffer); + + + NATIVE_INT_TYPE m_fd; //!< file descriptor returned for I/O device + NATIVE_INT_TYPE m_allocationSize; //!< size of allocation request to memory manager + const char* m_device; //!< original device path + + //! This method will be called by the new thread to wait for input on the serial port. + static void serialReadTaskEntry(void* ptr); + + Os::Task m_readTask; //!< task instance for thread to read serial port + + + bool m_quitReadThread; //!< flag to quit thread +}; + +} // end namespace Drv + +#endif diff --git a/Drv/LinuxUartDriver/Telemetry.fppi b/Drv/LinuxUartDriver/Telemetry.fppi new file mode 100644 index 0000000000..ec8fd1ce51 --- /dev/null +++ b/Drv/LinuxUartDriver/Telemetry.fppi @@ -0,0 +1,5 @@ +@ Bytes Sent +telemetry BytesSent: U32 id 0 + +@ Bytes Received +telemetry BytesRecv: U32 id 1 diff --git a/Drv/SerialDriverPorts/CMakeLists.txt b/Drv/SerialDriverPorts/CMakeLists.txt deleted file mode 100644 index f681d9ea94..0000000000 --- a/Drv/SerialDriverPorts/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -#### -# F prime CMakeLists.txt: -# -# SOURCE_FILES: combined list of source and autocoding diles -# MOD_DEPS: (optional) module dependencies -# -#### -set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/SerialDriverPorts.fpp" -) - -register_fprime_module() diff --git a/Drv/SerialDriverPorts/SerialDriverPorts.fpp b/Drv/SerialDriverPorts/SerialDriverPorts.fpp deleted file mode 100644 index 13744b76ce..0000000000 --- a/Drv/SerialDriverPorts/SerialDriverPorts.fpp +++ /dev/null @@ -1,24 +0,0 @@ -module Drv { - - port SerialWrite( - ref serBuffer: Fw.Buffer - ) - -} - -module Drv { - - enum SerialReadStatus { - SER_OK = 0 @< Transaction okay - SER_PARITY_ERR = 1 @< Parity error on data - SER_NO_BUFFERS = 2 @< Serial driver ran out of buffers - SER_BUFFER_TOO_SMALL = 3 @< Target buffer is too small - SER_OTHER_ERR = 4 @< Other errors that don't fit - } - - port SerialRead( - ref serBuffer: Fw.Buffer @< Buffer containing data - ref status: SerialReadStatus @< Status of read - ) - -} diff --git a/Drv/SpiDriverPorts/CMakeLists.txt b/Drv/SpiDriverPorts/CMakeLists.txt index 88d03f874a..1d6bd704f4 100644 --- a/Drv/SpiDriverPorts/CMakeLists.txt +++ b/Drv/SpiDriverPorts/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Drv/TcpClient/CMakeLists.txt b/Drv/TcpClient/CMakeLists.txt index fb2a04b56c..99ae5f1451 100644 --- a/Drv/TcpClient/CMakeLists.txt +++ b/Drv/TcpClient/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Drv/TcpClient/TcpClientComponentImpl.cpp b/Drv/TcpClient/TcpClientComponentImpl.cpp index 8b75d881bd..7da685df0c 100644 --- a/Drv/TcpClient/TcpClientComponentImpl.cpp +++ b/Drv/TcpClient/TcpClientComponentImpl.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include -#include "Fw/Types/BasicTypes.hpp" +#include #include "Fw/Types/Assert.hpp" @@ -68,13 +68,14 @@ void TcpClientComponentImpl::connected() { Drv::SendStatus TcpClientComponentImpl::send_handler(const NATIVE_INT_TYPE portNum, Fw::Buffer& fwBuffer) { Drv::SocketIpStatus status = m_socket.send(fwBuffer.getData(), fwBuffer.getSize()); - // Always return the buffer - deallocate_out(0, fwBuffer); - if ((status == SOCK_DISCONNECTED) || (status == SOCK_INTERRUPTED_TRY_AGAIN)) { + // Only deallocate buffer when the caller is not asked to retry + if (status == SOCK_INTERRUPTED_TRY_AGAIN) { return SendStatus::SEND_RETRY; } else if (status != SOCK_SUCCESS) { + deallocate_out(0, fwBuffer); return SendStatus::SEND_ERROR; } + deallocate_out(0, fwBuffer); return SendStatus::SEND_OK; } diff --git a/Drv/TcpClient/test/ut/Tester.cpp b/Drv/TcpClient/test/ut/Tester.cpp index 453e1ec58d..47ca110795 100644 --- a/Drv/TcpClient/test/ut/Tester.cpp +++ b/Drv/TcpClient/test/ut/Tester.cpp @@ -64,8 +64,8 @@ void Tester ::test_with_loop(U32 iterations, bool recv_thread) { EXPECT_EQ(status2, Drv::SOCK_SUCCESS); // If all the opens worked, then run this - if (Drv::SOCK_SUCCESS == status1 && Drv::SOCK_SUCCESS == status2 && - this->component.getSocketHandler().isOpened()) { + if ((Drv::SOCK_SUCCESS == status1) && (Drv::SOCK_SUCCESS == status2) && + (this->component.getSocketHandler().isOpened())) { // Force the sockets not to hang, if at all possible Drv::Test::force_recv_timeout(this->component.getSocketHandler()); Drv::Test::force_recv_timeout(server); diff --git a/Drv/TcpClient/test/ut/Tester.hpp b/Drv/TcpClient/test/ut/Tester.hpp index 2673a28959..c30c9b438b 100644 --- a/Drv/TcpClient/test/ut/Tester.hpp +++ b/Drv/TcpClient/test/ut/Tester.hpp @@ -115,7 +115,7 @@ namespace Drv { Fw::Buffer m_data_buffer; Fw::Buffer m_data_buffer2; U8 m_data_storage[SEND_DATA_BUFFER_SIZE]; - bool m_spinner; + std::atomic m_spinner; }; diff --git a/Drv/TcpServer/CMakeLists.txt b/Drv/TcpServer/CMakeLists.txt index 59b8e3e41e..80ac3fc867 100644 --- a/Drv/TcpServer/CMakeLists.txt +++ b/Drv/TcpServer/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Drv/TcpServer/TcpServerComponentImpl.cpp b/Drv/TcpServer/TcpServerComponentImpl.cpp index f8115b26e9..773abd2f1c 100644 --- a/Drv/TcpServer/TcpServerComponentImpl.cpp +++ b/Drv/TcpServer/TcpServerComponentImpl.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include -#include "Fw/Types/BasicTypes.hpp" +#include #include "Fw/Types/Assert.hpp" namespace Drv { @@ -75,13 +75,14 @@ void TcpServerComponentImpl::connected() { Drv::SendStatus TcpServerComponentImpl::send_handler(const NATIVE_INT_TYPE portNum, Fw::Buffer& fwBuffer) { Drv::SocketIpStatus status = m_socket.send(fwBuffer.getData(), fwBuffer.getSize()); - // Always return the buffer - deallocate_out(0, fwBuffer); - if ((status == SOCK_DISCONNECTED) || (status == SOCK_INTERRUPTED_TRY_AGAIN)) { + // Only deallocate buffer when the caller is not asked to retry + if (status == SOCK_INTERRUPTED_TRY_AGAIN) { return SendStatus::SEND_RETRY; } else if (status != SOCK_SUCCESS) { + deallocate_out(0, fwBuffer); return SendStatus::SEND_ERROR; } + deallocate_out(0, fwBuffer); return SendStatus::SEND_OK; } diff --git a/Drv/TcpServer/test/ut/Tester.cpp b/Drv/TcpServer/test/ut/Tester.cpp index 6779d75124..3e1d6ed697 100644 --- a/Drv/TcpServer/test/ut/Tester.cpp +++ b/Drv/TcpServer/test/ut/Tester.cpp @@ -66,8 +66,8 @@ void Tester ::test_with_loop(U32 iterations, bool recv_thread) { EXPECT_EQ(status2, Drv::SOCK_SUCCESS); // If all the opens worked, then run this - if (Drv::SOCK_SUCCESS == status1 && Drv::SOCK_SUCCESS == status2 && - this->component.getSocketHandler().isOpened()) { + if ((Drv::SOCK_SUCCESS == status1) && (Drv::SOCK_SUCCESS == status2) && + (this->component.getSocketHandler().isOpened())) { // Force the sockets not to hang, if at all possible Drv::Test::force_recv_timeout(this->component.getSocketHandler()); Drv::Test::force_recv_timeout(client); diff --git a/Drv/TcpServer/test/ut/Tester.hpp b/Drv/TcpServer/test/ut/Tester.hpp index 9ea46a04e6..0f1ec0eb46 100644 --- a/Drv/TcpServer/test/ut/Tester.hpp +++ b/Drv/TcpServer/test/ut/Tester.hpp @@ -125,7 +125,7 @@ namespace Drv { Fw::Buffer m_data_buffer; Fw::Buffer m_data_buffer2; U8 m_data_storage[SEND_DATA_BUFFER_SIZE]; - bool m_spinner; + std::atomic m_spinner; }; diff --git a/Drv/UartFramer/CMakeLists.txt b/Drv/UartFramer/CMakeLists.txt deleted file mode 100644 index a46d3d6b54..0000000000 --- a/Drv/UartFramer/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -#### -# F prime CMakeLists.txt: -# -# SOURCE_FILES: combined list of source and autocoding diles -# MOD_DEPS: (optional) module dependencies -# -#### -set(MOD_DEPS Os) - -set(SOURCE_FILES -"${CMAKE_CURRENT_LIST_DIR}/UartFramer.fpp" -"${CMAKE_CURRENT_LIST_DIR}/UartFramer.cpp" -) -register_fprime_module() - -## UTs ### -# Note: this UT expects user input -set(UT_MOD_DEPS - Os -) -set(UT_SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/UartFramer.fpp" - "${CMAKE_CURRENT_LIST_DIR}/test/ut/TestMain.cpp" - "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" -) -register_fprime_ut() diff --git a/Drv/UartFramer/UartFramer.cpp b/Drv/UartFramer/UartFramer.cpp deleted file mode 100644 index 155e4e5eff..0000000000 --- a/Drv/UartFramer/UartFramer.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// ====================================================================== -// \title UartFramer.cpp -// \author tcanham -// \brief cpp file for UartFramer component implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - - -#include -#include "Fw/Types/BasicTypes.hpp" -#include "Fw/Types/Assert.hpp" - -namespace Drv { - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - UartFramer :: - UartFramer( - const char *const compName - ) : UartFramerComponentBase(compName), m_size(0) - { - - } - - void UartFramer :: - init( - const NATIVE_INT_TYPE instance - ) - { - UartFramerComponentBase::init(instance); - } - - UartFramer :: - ~UartFramer() - { - - } - - void UartFramer::allocate(NATIVE_UINT_TYPE number, NATIVE_UINT_TYPE size) { - - FW_ASSERT(size > 0, size); - this->m_size = size; - - Fw::Buffer buff; - // request a buffer and pass it on to the UART for each requested - for (NATIVE_UINT_TYPE buffNum = 0; buffNum < number; buffNum++) { - buff = this->DeframerAllocate_out(0,this->m_size); - FW_ASSERT(buff.getSize() == size,buff.getSize(),size); - FW_ASSERT(buff.getData()); - this->readBufferSend_out(0,buff); - } - - } - - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - Drv::SendStatus UartFramer :: - Framer_handler( - const NATIVE_INT_TYPE portNum, - Fw::Buffer &sendBuffer - ) - { - this->serialSend_out(0,sendBuffer); - this->FramerDeallocate_out(0,sendBuffer); - // no status from send, so return OK - return Drv::SendStatus::SEND_OK; - } - - void UartFramer :: - serialRecv_handler( - const NATIVE_INT_TYPE portNum, - Fw::Buffer &serBuffer, - Drv::SerialReadStatus &status - ) - { - - Drv::RecvStatus outStat = Drv::RecvStatus::RECV_OK; - // Check the UART status - if (status != Drv::SerialReadStatus::SER_OK) { - outStat = Drv::RecvStatus::RECV_ERROR; - } - - // Forward buffer to deframer - this->Deframer_out(0,serBuffer,outStat); - - // allocate a replacement buffer and send it to - // the UART driver - Fw::Buffer newBuff = this->DeframerAllocate_out(0,this->m_size); - if (newBuff.getSize() != this->m_size) { - this->log_WARNING_HI_BuffErr(); - } else { - this->readBufferSend_out(0,newBuff); - } - - } - -} // end namespace Drv diff --git a/Drv/UartFramer/UartFramer.fpp b/Drv/UartFramer/UartFramer.fpp deleted file mode 100644 index e459c7b75f..0000000000 --- a/Drv/UartFramer/UartFramer.fpp +++ /dev/null @@ -1,62 +0,0 @@ -module Drv { - - passive component UartFramer { - - # ---------------------------------------------------------------------- - # Ports for UART - # ---------------------------------------------------------------------- - - @ port to send a buffer for reads to the UART driver - output port readBufferSend: Fw.BufferSend - - @ send a UART buffer - output port serialSend: Drv.SerialWrite - - @ receive a buffer from the UART - one of the above - sync input port serialRecv: Drv.SerialRead - - # ---------------------------------------------------------------------- - # Ports for Framer/Deframer - # ---------------------------------------------------------------------- - - @ Buffer from Framer - sync input port Framer: Drv.ByteStreamSend - - @ Buffer to Deframer - output port Deframer: Drv.ByteStreamRecv - - # ---------------------------------------------------------------------- - # Ports to get buffers - # ---------------------------------------------------------------------- - - @ Allocation output port - will be sent to Deframer for deallocation - output port DeframerAllocate: Fw.BufferGet - - @ Deallocation output port - deallocation of Framer buffers - output port FramerDeallocate: Fw.BufferSend - - - # ---------------------------------------------------------------------- - # Special F Prime ports - # ---------------------------------------------------------------------- - - event port Log - - text event port LogText - - time get port Time - - # ---------------------------------------------------------------------- - # Events - # ---------------------------------------------------------------------- - - @ UART open error - event BuffErr() \ - severity warning high \ - id 0 \ - format "Couldn't get UART buffer" \ - throttle 5 - - } - -} diff --git a/Drv/UartFramer/UartFramer.hpp b/Drv/UartFramer/UartFramer.hpp deleted file mode 100644 index cea6af3fae..0000000000 --- a/Drv/UartFramer/UartFramer.hpp +++ /dev/null @@ -1,86 +0,0 @@ -// ====================================================================== -// \title UartFramer.hpp -// \author tcanham -// \brief hpp file for UartFramer component implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef UartFramer_HPP -#define UartFramer_HPP - -#include "Drv/UartFramer/UartFramerComponentAc.hpp" - -namespace Drv { - - class UartFramer : - public UartFramerComponentBase - { - - public: - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - //! Construct object UartFramer - //! - UartFramer( - const char *const compName /*!< The component name*/ - ); - - //! Initialize object UartFramer - //! - void init( - const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ - ); - - //! Destroy object UartFramer - //! - ~UartFramer(); - - - //! Allocate pool of buffers for UART receive - BufferManager and UART - // instances must be connected and ready. BufferManager should have at least - // number+1 buffers allocated - void allocate(NATIVE_UINT_TYPE number, NATIVE_UINT_TYPE size); - - PRIVATE: - - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - //! Handler implementation for Framer - //! - Drv::SendStatus Framer_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Buffer &sendBuffer - ); - - //! Handler implementation for serialRecv - //! - void serialRecv_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Buffer &serBuffer, /*!< - Buffer containing data - */ - Drv::SerialReadStatus &status /*!< - Status of read - */ - ); - - // Private data members - - NATIVE_UINT_TYPE m_size; //!< size of UART buffers - - - }; - -} // end namespace Drv - -#endif diff --git a/Drv/UartFramer/docs/UartFramer.vsdx b/Drv/UartFramer/docs/UartFramer.vsdx deleted file mode 100644 index 8fab7e4906..0000000000 Binary files a/Drv/UartFramer/docs/UartFramer.vsdx and /dev/null differ diff --git a/Drv/UartFramer/docs/img/Downlink.svg b/Drv/UartFramer/docs/img/Downlink.svg deleted file mode 100644 index ecd9189b3c..0000000000 --- a/Drv/UartFramer/docs/img/Downlink.svg +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - Downlink - - - - Sheet.1 - - - - Sheet.2 - UART Driver - - - - UART Driver - - Sheet.3 - - - - Sheet.4 - UartFramer - - - - UartFramer - - Sheet.5 - - - - Sheet.6 - Buffer Manager - - - - Buffer Manager - - Sheet.7 - - - - Sheet.8 - Framer - - - - Framer - - Sheet.9 - - - - Sheet.10 - serialSend - - - - serialSend - - Sheet.11 - - - - Sheet.12 - Framer - - - - Framer - - Sheet.13 - - - - Sheet.14 - FramerDeallocate() - - - - FramerDeallocate() - - - - - - - - - - - - - - - - - - Dynamic connector - - - - - - diff --git a/Drv/UartFramer/docs/img/Topo.svg b/Drv/UartFramer/docs/img/Topo.svg deleted file mode 100644 index c82e4aa2a9..0000000000 --- a/Drv/UartFramer/docs/img/Topo.svg +++ /dev/null @@ -1,520 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - Component Connections - - - - Rounded Rectangle - UartFramer - - - - - - - - - - - - - - - - - - - - - - UartFramer - - Square - - - - - - - Sheet.3 - - - - Sheet.4 - - - - Sheet.5 - readBufferSend - - - - readBufferSend - - Square.20 - - - - - - - Sheet.7 - - - - Sheet.8 - serialRecv - - - - serialRecv - - Square.9 - - - - - - - Sheet.10 - - - - Sheet.11 - - - - Sheet.12 - serialSend - - - - serialSend - - Square.27 - - - - - - - Sheet.14 - - - - Sheet.15 - deframerAllocate - - - - deframerAllocate - - Square.37 - - - - - - - Sheet.17 - - - - Sheet.18 - framerDeallocate - - - - framerDeallocate - - Square.40 - - - - - - - Sheet.20 - - - - Sheet.21 - - - - Sheet.22 - Deframer - - - - Deframer - - Square.44 - - - - - - - Sheet.24 - - - - Sheet.25 - Framer - - - - Framer - - Rounded Rectangle.26 - LinuxSerial Driver - - - - - - - - - - - - - - - - - - - - - - LinuxSerialDriver - - Square.27 - - - - - - - Square.28 - - - - - - - Square.29 - - - - - - - Rounded Rectangle.36 - Buffer Manager - - - - - - - - - - - - - - - - - - - - - - BufferManager - - Rounded Rectangle.37 - Static Memory - - - - - - - - - - - - - - - - - - - - - - StaticMemory - - Square.38 - - - - - - - Square.39 - - - - - - - Sheet.40 - bufferGetCallee - - - - bufferGetCallee - - Sheet.41 - readBufferSend - - - - readBufferSend - - Sheet.42 - serialRecv - - - - serialRecv - - Sheet.43 - serialSend - - - - serialSend - - Sheet.44 - bufferDeallocate - - - - bufferDeallocate - - Rounded Rectangle.45 - Deframer - - - - - - - - - - - - - - - - - - - - - - Deframer - - Square.46 - - - - - - - Square.47 - - - - - - - Square.68 - - - - - - - Sheet.71 - - - - Sheet.72 - - - - Sheet.73 - bufferSendIn - - - - bufferSendIn - - Square.74 - - - - - - - Rounded Rectangle.75 - Framer - - - - - - - - - - - - - - - - - - - - - - Framer - - Square.76 - - - - - - - Square.77 - - - - - - - Sheet.79 - - - - Sheet.80 - - - - Sheet.81 - bufferAllocate - - - - bufferAllocate - - Sheet.82 - framedDeallocate - - - - framedDeallocate - - Sheet.83 - framedAllocate - - - - framedAllocate - - Sheet.84 - Framed Out - - - - FramedOut - - Sheet.85 - Framed In - - - - FramedIn - - diff --git a/Drv/UartFramer/docs/img/UartFramer.svg b/Drv/UartFramer/docs/img/UartFramer.svg deleted file mode 100644 index 03bfb074cb..0000000000 --- a/Drv/UartFramer/docs/img/UartFramer.svg +++ /dev/null @@ -1,204 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - Component Diagram - - - - Rounded Rectangle - UartFramer - - - - - - - - - - - - - - - - - - UartFramer - - Square - - - - - - - Sheet.16 - - - - Sheet.18 - - - - Sheet.19 - readBufferSend - - - - readBufferSend - - Square.20 - - - - - - - Sheet.21 - - - - Sheet.22 - serialRecv - - - - serialRecv - - Square.23 - - - - - - - Sheet.24 - - - - Sheet.25 - - - - Sheet.26 - serialSend - - - - serialSend - - Square.27 - - - - - - - Sheet.28 - - - - Sheet.30 - deframerAllocate - - - - deframerAllocate - - Square.37 - - - - - - - Sheet.38 - - - - Sheet.39 - framerDeallocate - - - - framerDeallocate - - Square.40 - - - - - - - Sheet.41 - - - - Sheet.42 - - - - Sheet.43 - Deframer - - - - Deframer - - Square.44 - - - - - - - Sheet.45 - - - - Sheet.46 - Framer - - - - Framer - - diff --git a/Drv/UartFramer/docs/img/UartFramerAllocate.svg b/Drv/UartFramer/docs/img/UartFramerAllocate.svg deleted file mode 100644 index 7c267a5b21..0000000000 --- a/Drv/UartFramer/docs/img/UartFramerAllocate.svg +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - Initialization Scenario Diagram - - - Sheet.1 - - - - Sheet.2 - UART - - - - UART - - Sheet.4 - - - - Sheet.5 - UartFramer - - - - UartFramer - - Sheet.6 - - - - Sheet.7 - BufferManager - - - - BufferManager - - Sheet.8 - - - - Sheet.9 - allocate(number,size) - - - - allocate(number,size) - - Sheet.10 - - - - Sheet.11 - DeframerAllocate(size) - - - - DeframerAllocate(size) - - Sheet.13 - readBufferSend() - - - - readBufferSend() - - Sheet.14 - - - - Sheet.15 - - - - Sheet.16 - - - - Sheet.17 - - - - Sheet.18 - number - - - - number - - diff --git a/Drv/UartFramer/docs/img/Uplink.svg b/Drv/UartFramer/docs/img/Uplink.svg deleted file mode 100644 index 26b0704bb3..0000000000 --- a/Drv/UartFramer/docs/img/Uplink.svg +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - Uplink - - - Sheet.1 - - - - Sheet.2 - UART Driver - - - - UART Driver - - Sheet.3 - - - - Sheet.4 - UART Relay - - - - UART Relay - - Sheet.5 - - - - Sheet.6 - Buffer Manager - - - - Buffer Manager - - Sheet.7 - - - - Sheet.8 - Deframer - - - - Deframer - - Sheet.9 - - - - Sheet.10 - serialRecv() - - - - serialRecv() - - Sheet.11 - - - - Sheet.12 - Deframer() - - - - Deframer() - - Sheet.13 - - - - Sheet.14 - DeframerAllocate() - - - - DeframerAllocate() - - Sheet.15 - - - - Sheet.16 - readBufferSend() - - - - readBufferSend() - - diff --git a/Drv/UartFramer/docs/sdd.md b/Drv/UartFramer/docs/sdd.md deleted file mode 100644 index 09a06df57e..0000000000 --- a/Drv/UartFramer/docs/sdd.md +++ /dev/null @@ -1,174 +0,0 @@ -\page DrvUartFramerComponent Drv::UartFramer Component -# Drv::UartFramer UART Framer Component - -The UART Framer Component is used to bridge the [Framer](../../Svc/Framer/docs/sdd.md) and -[Deframer](../../Svc/Deframer/docs/sdd.md) components to the [Linux Serial Driver](../LinuxSerialDriver/) component. -Another UART driver could be used as long as it supports the same interfaces as the Linux Serial Driver. -This allows a connection to the F Prime [ground system](https://github.com/fprime-community/fprime-gds) via a standard -UART connection. The component is defined as passive, since it acts as a pass-through and doesn't require its own -thread. - -## Design - -### Component Diagram - -![Component Diagram](img/UartFramer.svg) - -### Port List - -|Port Name|Description| -|---|---| -|DeframerAllocate|Allocates buffers for the UART driver to send to the deframer via the UartFramer.| -|FramerDeallocate|Deallocate buffers sent by the framer| -|Framer|Receives packets for downlink| -|Deframer|Sends received packets for uplink| -|readBufferSend|Sends buffers to UART driver receive buffer pool| -|serialRecv|Receives uplink buffers from UART driver| -|serialSend|Sends downlink buffers to UART driver| - -### Initialization - -During initialization, the `UartFramer` component supplies an initial set of buffers to the UART driver to act as a receive pool for received data. - -The initialization call is as follows: - -``` -void allocate(NATIVE_UINT_TYPE number, NATIVE_UINT_TYPE size); -``` - -The arguments are as follows: - -|Argument|Description| -|---|---| -|number|The number of buffers to allocate. This should be defined to cover any anticipated surges in data that could temporarily outpace processing| -|size|The size of each buffer. Should match the size of buffers used for `Framer` and `Deframer`. - -The component invokes the `DeframerAllocate` port enough times to allocate the number of buffers in the `number` parameter, with a requested size of `size`. For each of those invocations, the buffer is passed to the UART driver for the receive pool via the `readBufferSend` port. - -In order for the allocation call to work, all ports should be connected before invoking `allocate()`. - -![Initial Buffer Allocation](img/UartFramerAllocate.svg) - -## Uplink - -When packets arrive via the UART, the UART driver connected to `UartFramer` will get a buffer from the pool of buffers that were initially allocated and fill it with the packet data. The packets are then sent to `UartFramer` via the `serialRecv` port. The buffer is forwarded to the `Deframer` component for processing via the `Deframer` port. -The `Deframer` component will deallocate it when complete. After the packet is forwarded to the `Deframer` component, another packet is allocated via the `DeframerAllocate` port and sent to the UART driver to replenish the pool of receive buffers. - - -![Uplink](img/Uplink.svg) - -## Downlink - -The `Framer` component allocates a packet and fills it with data. The packet gets sent to `UartFramer`, which sends it to the UART driver via the `serialSend` port. When the port call returns (see requirement #4 below), the buffer is deallocated via an invocation of the `FramerDeallocate` port. - -![Downlink](img/Downlink.svg) - -## Error handling - -The `UartFramer` component converts the UART receive error status to the corresponding `Deframer` error status. - -If the `UartFramer` cannot allocate an additional buffer for the serial receive pool, it will issue a `WARNING_HI` event. In this case, the receive pool will permanently lose a buffer. - -## Interconnections - -The following is a diagram of how the `UartFramer` would be connected to the `Framer` and `Deframer` and LinuxSerialDriver components in a typical topology. Note that the types are in the diagram rather than instance names which would be in the actual topology specification. - -![Topology Example](img/Topo.svg) - -## FPP examples - -An example instance of the `LinuxSerialDriver` in the topology is as follows: - -``` -instance gndUart: Drv.LinuxSerialDriver \ - base id 2000 \ - { - - phase Fpp.ToCpp.Phases.configComponents """ - bool openStat = gndUart.open("/dev/ttyUL1", - Drv::LinuxSerialDriverComponentImpl::BAUD_115K, - Drv::LinuxSerialDriverComponentImpl::NO_FLOW, - Drv::LinuxSerialDriverComponentImpl::PARITY_NONE, - true - ); - FW_ASSERT(openStat); - - """ - - phase Fpp.ToCpp.Phases.startTasks """ - gndUart.startReadThread(); - """ - - phase Fpp.ToCpp.Phases.stopTasks """ - gndUart.quitReadThread(); - """ - - } -``` - -The `LinuxSerialDriver` FPP is included as an illustration of how to initialize the UART driver and to relate to the FPP topology code below. - -An example instance of the `UartFramer` in the topology FPP is as follows: - -``` -instance gndUartFramer: Drv.UartFramer \ - base id 2100 \ - { - - phase Fpp.ToCpp.Phases.startTasks """ - gndUartFramer.allocate(10,1024); - """ - - } -``` - -This code pre-allocates 10 1K buffers for the UART driver. It places this call in the initialization phase where component tasks are started, where we know all connections have been completed. - -An example set of connections in the topology FPP is as follows: - -``` - connections SomeDeployment { - - gndUart.serialRecv[0] -> gndUartFramer.serialRecv[0] - gndUartFramer.serialSend[0] -> gndUart.serialSend[0] - gndUartFramer.readBufferSend[0] -> gndUart.readBufferSend[0] - - gndUartFramer.DeframerAllocate[0] -> gndBufferManager.bufferGetCallee[0] - gndUartFramer.FramerDeallocate[0] -> staticMemory.bufferDeallocate[1] - - gndUartFramer.Deframer[0] -> uplink.framedIn[0] - uplink.framedDeallocate[0] -> gndBufferManager.bufferSendIn[0] - - downlink.framedOut[0] -> gndUartFramer.Framer[0] - downlink.framedAllocate[0] -> staticMemory.bufferAllocate[1] - - ... -``` - -This matches the diagram above where instance names are used as opposed to type names in the diagram. - -## Requirements - -| Name | Description | Validation | -|---|---|---| -| UART-FRAMER-COMP-001 | The `UartFramer` component shall pass the `Framer` downlink buffers to UART driver | unit test | -| UART-FRAMER-COMP-002 | The `UartFramer` component shall pass buffers received by the UART to the `Deframer` | unit test | -| UART-FRAMER-COMP-003 | The `UartFramer` component shall supply the UART driver with a specified number of receive buffers at initialization time| unit test | -| UART-FRAMER-COMP-003 | The `UartFramer` component shall pass any receive failure statuses to the `Deframer` | unit test | -| UART-FRAMER-COMP-003 | The `UartFramer` component shall allocate a buffer and pass it back to the UART for every buffer received| unit test | - -## Requirements on other components or topologies - -1\. Packets allocated for the UART receive pool with the `DeframerAllocate` port and sent to the UART driver are the same ones returned in the `serialRecv` port call. - -2\. Packets sent to the `Deframer` component are returned to the same buffer pool that is connected to the `DeframerAllocate` port. - -3\. Packets sent by the `Framer` component are allocated from the same pool as the `FramerDeallocate` port is connected to. - -4\. The UART driver is finished with the transmit buffer after the return of the `serialSend` port invocation so it can be returned to the buffer pool. - -## Change Log - -| Date | Description | -|---|---| -| 2021-02-03 | Initial Release | diff --git a/Drv/UartFramer/test/ut/TestMain.cpp b/Drv/UartFramer/test/ut/TestMain.cpp deleted file mode 100644 index e2642e8d27..0000000000 --- a/Drv/UartFramer/test/ut/TestMain.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// ---------------------------------------------------------------------- -// TestMain.cpp -// ---------------------------------------------------------------------- - -#include "Tester.hpp" - -TEST(Nominal, toDo) { - Drv::Tester tester; - tester.initialization(); -} - -TEST(Nominal, send) { - Drv::Tester tester; - tester.packetSend(); -} - -TEST(Nominal, receive) { - Drv::Tester tester; - tester.packetReceive(); -} - -TEST(Error, receive) { - Drv::Tester tester; - tester.packetReceiveError(); -} - -TEST(Error, allocationError) { - Drv::Tester tester; - tester.packetAllocationError(); -} - -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/Drv/UartFramer/test/ut/Tester.cpp b/Drv/UartFramer/test/ut/Tester.cpp deleted file mode 100644 index 75ef4e86f7..0000000000 --- a/Drv/UartFramer/test/ut/Tester.cpp +++ /dev/null @@ -1,320 +0,0 @@ -// ====================================================================== -// \title UartFramer.hpp -// \author tcanham -// \brief cpp file for UartFramer test harness implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#include "Tester.hpp" - -#define INSTANCE 0 -#define MAX_HISTORY_SIZE 10 - -namespace Drv { - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - Tester :: - Tester() : - UartFramerGTestBase("Tester", MAX_HISTORY_SIZE), - component("UartFramer") - ,m_currBuff(0) - ,m_emptyAlloc(false) - { - this->initComponents(); - this->connectPorts(); - } - - Tester :: - ~Tester() - { - - } - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - void Tester :: - initialization() - { - - this->component.allocate(NUM_INIT_BUFFERS,10); - ASSERT_EQ(NUM_INIT_BUFFERS,this->m_currBuff); - // two port calls; allocate and pass to UART driver - ASSERT_FROM_PORT_HISTORY_SIZE(NUM_INIT_BUFFERS*2); - // allocation calls - ASSERT_from_DeframerAllocate_SIZE(NUM_INIT_BUFFERS); - // UART driver calls - ASSERT_from_readBufferSend_SIZE(NUM_INIT_BUFFERS); - - } - - void Tester :: - packetSend() - { - - // do initialization - this->initialization(); - this->clearHistory(); - - // send a packet - Fw::Buffer sent(reinterpret_cast(1),0); - this->invoke_to_Framer(0,sent); - // verify forwarded to driver - // UART + deallocate - ASSERT_FROM_PORT_HISTORY_SIZE(2); - // Buffer deallocation - ASSERT_from_FramerDeallocate_SIZE(1); - // Send buffer to UART - ASSERT_from_serialSend_SIZE(1); - - } - - void Tester :: - packetReceive() - { - - // do initialization - this->initialization(); - this->clearHistory(); - - // receive a packet - Fw::Buffer received(reinterpret_cast(1),0); - Drv::SerialReadStatus stat = Drv::SerialReadStatus::SER_OK; - this->invoke_to_serialRecv(0,received,stat); - // verify forwarded to driver - // send to deframer + allocate a new packet + send to UART - ASSERT_FROM_PORT_HISTORY_SIZE(3); - // packet sent to deframer - ASSERT_from_Deframer_SIZE(1); - // verify good status to deframer - Drv::RecvStatus retStat = Drv::RecvStatus::RECV_OK; - ASSERT_from_Deframer(0,received,retStat); - // Buffer allocation for UART pool - ASSERT_from_DeframerAllocate_SIZE(1); - // Return buffer to UART for receive pool - ASSERT_from_readBufferSend_SIZE(1); - - } - - void Tester :: - packetReceiveError() - { - - // do initialization - this->initialization(); - this->clearHistory(); - - // receive a packet - Fw::Buffer received(reinterpret_cast(1),0); - Drv::SerialReadStatus stat = Drv::SerialReadStatus::SER_PARITY_ERR; - this->invoke_to_serialRecv(0,received,stat); - // verify forwarded to driver - // send to deframer + allocate a new packet + send to UART - ASSERT_FROM_PORT_HISTORY_SIZE(3); - // packet sent to deframer - ASSERT_from_Deframer_SIZE(1); - // verify good status to deframer - Drv::RecvStatus retStat = Drv::RecvStatus::RECV_ERROR; - ASSERT_from_Deframer(0,received,retStat); - // Buffer allocation for UART pool - ASSERT_from_DeframerAllocate_SIZE(1); - // Return buffer to UART for receive pool - ASSERT_from_readBufferSend_SIZE(1); - - } - - void Tester :: - packetAllocationError() - { - - // do initialization - this->initialization(); - this->clearHistory(); - - // receive a packet - Fw::Buffer received(reinterpret_cast(1),0); - Drv::SerialReadStatus stat = Drv::SerialReadStatus::SER_OK; - // set flag to return empty buffer - this->m_emptyAlloc = true; - this->invoke_to_serialRecv(0,received,stat); - // verify forwarded to driver - // send to deframer + allocate a new packet + send to UART - ASSERT_FROM_PORT_HISTORY_SIZE(2); - // packet sent to deframer - ASSERT_from_Deframer_SIZE(1); - // verify good status to deframer - Drv::RecvStatus retStat = Drv::RecvStatus::RECV_OK; - ASSERT_from_Deframer(0,received,retStat); - // Buffer allocation for UART pool - ASSERT_from_DeframerAllocate_SIZE(1); - // Shouldn't try to give a buffer to the UART if one wasn't allocated - ASSERT_from_readBufferSend_SIZE(0); - // Should have seen error event - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_BuffErr_SIZE(1); - - } - - // ---------------------------------------------------------------------- - // Handlers for typed from ports - // ---------------------------------------------------------------------- - - void Tester :: - from_Deframer_handler( - const NATIVE_INT_TYPE portNum, - Fw::Buffer &recvBuffer, - const Drv::RecvStatus &recvStatus - ) - { - this->pushFromPortEntry_Deframer(recvBuffer, recvStatus); - this->m_currBuff--; - } - - Fw::Buffer Tester :: - from_DeframerAllocate_handler( - const NATIVE_INT_TYPE portNum, - U32 size - ) - { - this->pushFromPortEntry_DeframerAllocate(size); - if (not this->m_emptyAlloc) { - this->m_buffPool[this->m_currBuff].setSize(size); - this->m_buffPool[this->m_currBuff].setData(reinterpret_cast(1)); - this->m_currBuff++; - return this->m_buffPool[this->m_currBuff-1]; - } else { - Fw::Buffer empty(reinterpret_cast(1),0); - return empty; - } - } - - void Tester :: - from_FramerDeallocate_handler( - const NATIVE_INT_TYPE portNum, - Fw::Buffer &fwBuffer - ) - { - this->pushFromPortEntry_FramerDeallocate(fwBuffer); - } - - void Tester :: - from_readBufferSend_handler( - const NATIVE_INT_TYPE portNum, - Fw::Buffer &fwBuffer - ) - { - this->pushFromPortEntry_readBufferSend(fwBuffer); - } - - void Tester :: - from_serialSend_handler( - const NATIVE_INT_TYPE portNum, - Fw::Buffer &serBuffer - ) - { - this->pushFromPortEntry_serialSend(serBuffer); - } - - void Tester::textLogIn(const FwEventIdType id, //!< The event ID - Fw::Time& timeTag, //!< The time - const Fw::LogSeverity severity, //!< The severity - const Fw::TextLogString& text //!< The event string - ) { - TextLogEntry e = { id, timeTag, severity, text }; - - printTextLogHistoryEntry(e, stdout); - } - - - // ---------------------------------------------------------------------- - // Helper methods - // ---------------------------------------------------------------------- - - void Tester :: - connectPorts() - { - - // Framer - this->connect_to_Framer( - 0, - this->component.get_Framer_InputPort(0) - ); - - // serialRecv - this->connect_to_serialRecv( - 0, - this->component.get_serialRecv_InputPort(0) - ); - - // Deframer - this->component.set_Deframer_OutputPort( - 0, - this->get_from_Deframer(0) - ); - - // DeframerAllocate - this->component.set_DeframerAllocate_OutputPort( - 0, - this->get_from_DeframerAllocate(0) - ); - - // FramerDeallocate - this->component.set_FramerDeallocate_OutputPort( - 0, - this->get_from_FramerDeallocate(0) - ); - - // Log - this->component.set_Log_OutputPort( - 0, - this->get_from_Log(0) - ); - - // LogText - this->component.set_LogText_OutputPort( - 0, - this->get_from_LogText(0) - ); - - // Time - this->component.set_Time_OutputPort( - 0, - this->get_from_Time(0) - ); - - // readBufferSend - this->component.set_readBufferSend_OutputPort( - 0, - this->get_from_readBufferSend(0) - ); - - // serialSend - this->component.set_serialSend_OutputPort( - 0, - this->get_from_serialSend(0) - ); - - - - - } - - void Tester :: - initComponents() - { - this->init(); - this->component.init( - INSTANCE - ); - } - -} // end namespace Drv diff --git a/Drv/UartFramer/test/ut/Tester.hpp b/Drv/UartFramer/test/ut/Tester.hpp deleted file mode 100644 index 4368507f5d..0000000000 --- a/Drv/UartFramer/test/ut/Tester.hpp +++ /dev/null @@ -1,150 +0,0 @@ -// ====================================================================== -// \title UartFramer/test/ut/Tester.hpp -// \author tcanham -// \brief hpp file for UartFramer test harness implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef TESTER_HPP -#define TESTER_HPP - -#include "GTestBase.hpp" -#include "Drv/UartFramer/UartFramer.hpp" - -#define NUM_INIT_BUFFERS 5 - -namespace Drv { - - class Tester : - public UartFramerGTestBase - { - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - public: - - //! Construct object Tester - //! - Tester(); - - //! Destroy object Tester - //! - ~Tester(); - - public: - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - //! Initialization - //! - void initialization(); - - //! packet send - //! - void packetSend(); - - //! packet receive - //! - void packetReceive(); - - //! packet receive error - //! - void packetReceiveError(); - - //! error allocating UART receive buffer - //! - void packetAllocationError(); - - - private: - - // ---------------------------------------------------------------------- - // Handlers for typed from ports - // ---------------------------------------------------------------------- - - //! Handler for from_Deframer - //! - void from_Deframer_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Buffer &recvBuffer, - const Drv::RecvStatus &recvStatus - ); - - //! Handler for from_DeframerAllocate - //! - Fw::Buffer from_DeframerAllocate_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - U32 size - ); - - //! Handler for from_FramerDeallocate - //! - void from_FramerDeallocate_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Buffer &fwBuffer - ); - - //! Handler for from_readBufferSend - //! - void from_readBufferSend_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Buffer &fwBuffer - ); - - //! Handler for from_serialSend - //! - void from_serialSend_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Buffer &serBuffer - ); - - void textLogIn( - const FwEventIdType id, //!< The event ID - Fw::Time& timeTag, //!< The time - const Fw::LogSeverity severity, //!< The severity - const Fw::TextLogString& text //!< The event string - ); - - - private: - - // ---------------------------------------------------------------------- - // Helper methods - // ---------------------------------------------------------------------- - - //! Connect ports - //! - void connectPorts(); - - //! Initialize components - //! - void initComponents(); - - private: - - // ---------------------------------------------------------------------- - // Variables - // ---------------------------------------------------------------------- - - //! The component under test - //! - UartFramer component; - - Fw::Buffer m_buffPool[NUM_INIT_BUFFERS]; - NATIVE_UINT_TYPE m_currBuff; - bool m_emptyAlloc; - - }; - -} // end namespace Drv - -#endif diff --git a/Drv/Udp/CMakeLists.txt b/Drv/Udp/CMakeLists.txt index 699dbaab56..203b804904 100644 --- a/Drv/Udp/CMakeLists.txt +++ b/Drv/Udp/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Drv/Udp/UdpComponentImpl.cpp b/Drv/Udp/UdpComponentImpl.cpp index 6072098e1e..e45cd9fd87 100644 --- a/Drv/Udp/UdpComponentImpl.cpp +++ b/Drv/Udp/UdpComponentImpl.cpp @@ -12,7 +12,7 @@ #include #include -#include "Fw/Types/BasicTypes.hpp" +#include #include "Fw/Types/Assert.hpp" diff --git a/Drv/Udp/test/ut/Tester.cpp b/Drv/Udp/test/ut/Tester.cpp index caa1c5005b..d1110216d9 100644 --- a/Drv/Udp/test/ut/Tester.cpp +++ b/Drv/Udp/test/ut/Tester.cpp @@ -69,8 +69,8 @@ void Tester::test_with_loop(U32 iterations, bool recv_thread) { EXPECT_EQ(status2, Drv::SOCK_SUCCESS); // If all the opens worked, then run this - if (Drv::SOCK_SUCCESS == status1 && Drv::SOCK_SUCCESS == status2 && - this->component.getSocketHandler().isOpened()) { + if ((Drv::SOCK_SUCCESS == status1) && (Drv::SOCK_SUCCESS == status2) && + (this->component.getSocketHandler().isOpened())) { // Force the sockets not to hang, if at all possible Drv::Test::force_recv_timeout(this->component.getSocketHandler()); Drv::Test::force_recv_timeout(udp2); diff --git a/Drv/Udp/test/ut/Tester.hpp b/Drv/Udp/test/ut/Tester.hpp index 18323d89dd..aaf438d0ca 100644 --- a/Drv/Udp/test/ut/Tester.hpp +++ b/Drv/Udp/test/ut/Tester.hpp @@ -126,7 +126,7 @@ namespace Drv { Fw::Buffer m_data_buffer; Fw::Buffer m_data_buffer2; U8 m_data_storage[SEND_DATA_BUFFER_SIZE]; - bool m_spinner; + std::atomic m_spinner; }; } // end namespace Drv diff --git a/Drv/locs.fpp b/Drv/locs.fpp deleted file mode 100644 index 1149e2c5a7..0000000000 --- a/Drv/locs.fpp +++ /dev/null @@ -1,11 +0,0 @@ -locate component Drv.BlockDriver at "BlockDriver/BlockDriver.fpp" -locate component Drv.ByteStreamDriverModel at "ByteStreamDriverModel/ByteStreamDriverModel.fpp" -locate port Drv.ByteStreamPoll at "ByteStreamDriverModel/ByteStreamDriverModel.fpp" -locate port Drv.ByteStreamReady at "ByteStreamDriverModel/ByteStreamDriverModel.fpp" -locate port Drv.ByteStreamRecv at "ByteStreamDriverModel/ByteStreamDriverModel.fpp" -locate port Drv.ByteStreamSend at "ByteStreamDriverModel/ByteStreamDriverModel.fpp" -locate port Drv.DataBuffer at "DataTypes/DataTypes.fpp" -locate type Drv.DataBuffer at "DataTypes/DataTypes.fpp" -locate type Drv.PollStatus at "ByteStreamDriverModel/ByteStreamDriverModel.fpp" -locate type Drv.RecvStatus at "ByteStreamDriverModel/ByteStreamDriverModel.fpp" -locate type Drv.SendStatus at "ByteStreamDriverModel/ByteStreamDriverModel.fpp" diff --git a/Drv/subdirs.txt b/Drv/subdirs.txt deleted file mode 100644 index afab5e0325..0000000000 --- a/Drv/subdirs.txt +++ /dev/null @@ -1,3 +0,0 @@ -BlockDriver -ByteStreamDriverModel -DataTypes diff --git a/Drv/update-locs b/Drv/update-locs deleted file mode 100755 index 76583058af..0000000000 --- a/Drv/update-locs +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -fpp-locate-defs `find . -name '*.fpp'` > locs.fpp diff --git a/Drv/update-subdirs b/Drv/update-subdirs deleted file mode 100755 index f86970a7cb..0000000000 --- a/Drv/update-subdirs +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -find . -mindepth 2 -name '*.fpp' | cut -d '/' -f 2 | sort | uniq > subdirs.txt diff --git a/Fpp/locs.fpp b/Fpp/locs.fpp deleted file mode 100644 index 2844f84f24..0000000000 --- a/Fpp/locs.fpp +++ /dev/null @@ -1 +0,0 @@ -locate type Fpp.ToCpp.Phases at "ToCpp.fpp" diff --git a/Fpp/update-locs b/Fpp/update-locs deleted file mode 100755 index 76583058af..0000000000 --- a/Fpp/update-locs +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -fpp-locate-defs `find . -name '*.fpp'` > locs.fpp diff --git a/FppTest/.gitignore b/FppTest/.gitignore new file mode 100644 index 0000000000..404abb2212 --- /dev/null +++ b/FppTest/.gitignore @@ -0,0 +1 @@ +coverage/ diff --git a/FppTest/CMakeLists.txt b/FppTest/CMakeLists.txt new file mode 100644 index 0000000000..56f0f486fc --- /dev/null +++ b/FppTest/CMakeLists.txt @@ -0,0 +1,29 @@ +### +# FPP Test +# +# Builds unit tests for FPP autocoder +### + +cmake_minimum_required(VERSION 3.13) +cmake_policy(SET CMP0048 NEW) +project(FppTest C CXX) + +include("${CMAKE_CURRENT_LIST_DIR}/../cmake/FPrime.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/../cmake/FPrime-Code.cmake") + +if (BUILD_TESTING AND NOT __FPRIME_NO_UT_GEN__) + add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/enum/") + add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/array/") + add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/struct/") + add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/port/") +endif() + +set(SOURCE_FILES "source.cpp") +set(MOD_DEPS + ${PROJECT_NAME}/enum + ${PROJECT_NAME}/array + ${PROJECT_NAME}/struct + ${PROJECT_NAME}/port +) + +register_fprime_deployment() diff --git a/FppTest/README.md b/FppTest/README.md new file mode 100644 index 0000000000..1c966bbe59 --- /dev/null +++ b/FppTest/README.md @@ -0,0 +1,9 @@ +# FppTest + +This project contains unit tests for the FPP autocoder. + +To use this directory, you must have installed F Prime, and you must be inside +the F Prime Python virtual environment. + +* To build the tests, run `fprime-util build --ut`. +* To run the tests, run `fprime-util check`. diff --git a/FppTest/array/ArrayToStringTest.cpp b/FppTest/array/ArrayToStringTest.cpp new file mode 100644 index 0000000000..23ca249e72 --- /dev/null +++ b/FppTest/array/ArrayToStringTest.cpp @@ -0,0 +1,60 @@ +// ====================================================================== +// \title ArrayToStringTest.cpp +// \author T. Chieu +// \brief cpp file for ArrayToStringTest class +// +// \copyright +// Copyright (C) 2009-2022 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "FppTest/array/EnumArrayAc.hpp" +#include "FppTest/array/StringArrayAc.hpp" +#include "FppTest/array/StructArrayAc.hpp" +#include "FppTest/array/Uint32ArrayArrayAc.hpp" + +#include "FppTest/typed_tests/ArrayTest.hpp" + +#include "gtest/gtest.h" + +#include + +// Test array string functions +template +class ArrayToStringTest : public ::testing::Test { +protected: + void SetUp() override { + FppTest::Array::setTestVals(testVals); + } + + typename ArrayType::ElementType testVals[ArrayType::SIZE]; +}; + +using ArrayTypes = ::testing::Types< + Enum, + String, + Struct, + Uint32Array +>; +TYPED_TEST_SUITE(ArrayToStringTest, ArrayTypes); + +// Test array toString() and ostream operator functions +TYPED_TEST(ArrayToStringTest, ToString) { + TypeParam a(this->testVals); + std::stringstream buf1, buf2; + + buf1 << a; + + buf2 << "[ "; + for (U32 i = 0; i < TypeParam::SIZE; i++) { + buf2 << this->testVals[i] << " "; + } + buf2 << "]"; + + ASSERT_STREQ( + buf1.str().c_str(), + buf2.str().c_str() + ); +} diff --git a/FppTest/array/CMakeLists.txt b/FppTest/array/CMakeLists.txt new file mode 100644 index 0000000000..23a286cec7 --- /dev/null +++ b/FppTest/array/CMakeLists.txt @@ -0,0 +1,29 @@ +# ====================================================================== +# CMakeLists.txt +# ====================================================================== + +# We need to declare the XML source files this way to invoke the autocoder. +# However, only the UT build is allowed here. +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/array.fpp" + "${CMAKE_CURRENT_LIST_DIR}/enum.fpp" + "${CMAKE_CURRENT_LIST_DIR}/string.fpp" + "${CMAKE_CURRENT_LIST_DIR}/struct.fpp" + "${CMAKE_CURRENT_LIST_DIR}/format.fpp" +) +register_fprime_module() + +# Declare dependencies on test modules +set(UT_MOD_DEPS + Fw/Test + STest +) + +# List all .cpp files as UT_SOURCE_FILES. Only the UT build is allowed. +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/ArrayToStringTest.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FormatTest.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../utils/Utils.cpp" + "${CMAKE_CURRENT_LIST_DIR}/main.cpp" +) +register_fprime_ut() diff --git a/FppTest/array/FormatTest.cpp b/FppTest/array/FormatTest.cpp new file mode 100644 index 0000000000..59ab523fd5 --- /dev/null +++ b/FppTest/array/FormatTest.cpp @@ -0,0 +1,282 @@ +// ====================================================================== +// \title FormatTest.cpp +// \author T. Chieu +// \brief cpp file for FormatTest class +// +// \copyright +// Copyright (C) 2009-2022 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "FppTest/array/FormatBoolArrayAc.hpp" +#include "FppTest/array/FormatU8ArrayAc.hpp" +#include "FppTest/array/FormatU16DecArrayAc.hpp" +#include "FppTest/array/FormatU32OctArrayAc.hpp" +#include "FppTest/array/FormatU64HexArrayAc.hpp" +#include "FppTest/array/FormatI8ArrayAc.hpp" +#include "FppTest/array/FormatI16DecArrayAc.hpp" +#include "FppTest/array/FormatI32OctArrayAc.hpp" +#include "FppTest/array/FormatI64HexArrayAc.hpp" +#include "FppTest/array/FormatF32eArrayAc.hpp" +#include "FppTest/array/FormatF32fArrayAc.hpp" +#include "FppTest/array/FormatF64gArrayAc.hpp" +#include "FppTest/array/FormatStringArrayAc.hpp" +#include "FppTest/array/FormatCharArrayAc.hpp" +#include "FppTest/utils/Utils.hpp" + +#include "gtest/gtest.h" + +#include +#include + +// Tests FPP format strings +class FormatTest : public ::testing::Test { +protected: + void SetUp() override { + buf2 << "[ "; + } + + std::stringstream buf1, buf2; +}; + +TEST_F(FormatTest, Bool) { + bool testVals[FormatBool::SIZE] = {true, true, false}; + FormatBool a(testVals); + + buf1 << a; + for (U32 i = 0; i < FormatBool::SIZE; i++) { + buf2 << "a " << testVals[i] << " b "; + } + buf2 << "]"; + + ASSERT_STREQ( + buf1.str().c_str(), + buf2.str().c_str() + ); +} + +TEST_F(FormatTest, U8) { + U8 testVals[FormatU8::SIZE] = {0, 100, std::numeric_limits::max()}; + FormatU8 a(testVals); + + buf1 << a; + for (U32 i = 0; i < FormatU8::SIZE; i++) { + buf2 << "a " << (U16) testVals[i] << " b "; + } + buf2 << "]"; + + ASSERT_STREQ( + buf1.str().c_str(), + buf2.str().c_str() + ); +} + +TEST_F(FormatTest, U16Dec) { + U16 testVals[FormatU16Dec::SIZE] = {0, 100, std::numeric_limits::max()}; + FormatU16Dec a(testVals); + + buf1 << a; + for (U32 i = 0; i < FormatU16Dec::SIZE; i++) { + buf2 << "a " << std::dec << testVals[i] << " b "; + } + buf2 << "]"; + + ASSERT_STREQ( + buf1.str().c_str(), + buf2.str().c_str() + ); +} + +TEST_F(FormatTest, U32Oct) { + U32 testVals[FormatU32Oct::SIZE] = {0, 100, std::numeric_limits::max()}; + FormatU32Oct a(testVals); + + buf1 << a; + for (U32 i = 0; i < FormatU32Oct::SIZE; i++) { + buf2 << "a " << std::oct << testVals[i] << " b "; + } + buf2 << "]"; + + ASSERT_STREQ( + buf1.str().c_str(), + buf2.str().c_str() + ); +} + +TEST_F(FormatTest, U64Hex) { + U64 testVals[FormatU64Hex::SIZE] = + {0, 100, std::numeric_limits::max()}; + FormatU64Hex a(testVals); + + buf1 << a; + for (U32 i = 0; i < FormatU64Hex::SIZE; i++) { + buf2 << "a " << std::hex << testVals[i] << " b "; + } + buf2 << "]"; + + ASSERT_STREQ( + buf1.str().c_str(), + buf2.str().c_str() + ); +} + +TEST_F(FormatTest, I8) { + I8 testVals[FormatI8::SIZE] = + {std::numeric_limits::min(), 0, std::numeric_limits::max()}; + FormatI8 a(testVals); + + buf1 << a; + for (U32 i = 0; i < FormatI8::SIZE; i++) { + buf2 << "a " << (I16) testVals[i] << " b "; + } + buf2 << "]"; + + ASSERT_STREQ( + buf1.str().c_str(), + buf2.str().c_str() + ); +} + +TEST_F(FormatTest, I16Dec) { + I16 testVals[FormatI16Dec::SIZE] = + {std::numeric_limits::min(), 0, std::numeric_limits::max()}; + FormatI16Dec a(testVals); + + buf1 << a; + for (U32 i = 0; i < FormatI16Dec::SIZE; i++) { + buf2 << "a " << std::dec << testVals[i] << " b "; + } + buf2 << "]"; + + ASSERT_STREQ( + buf1.str().c_str(), + buf2.str().c_str() + ); +} + +TEST_F(FormatTest, I32Oct) { + I32 testVals[FormatI32Oct::SIZE] = + {std::numeric_limits::min(), 0, std::numeric_limits::max()}; + FormatI32Oct a(testVals); + + buf1 << a; + for (U32 i = 0; i < FormatI32Oct::SIZE; i++) { + buf2 << "a " << std::oct << testVals[i] << " b "; + } + buf2 << "]"; + + ASSERT_STREQ( + buf1.str().c_str(), + buf2.str().c_str() + ); + +} + +TEST_F(FormatTest, I64Hex) { + I64 testVals[FormatI64Hex::SIZE] = + {std::numeric_limits::min(), 0, std::numeric_limits::max()}; + FormatI64Hex a(testVals); + + buf1 << a; + for (U32 i = 0; i < FormatI64Hex::SIZE; i++) { + buf2 << "a " << std::hex << testVals[i] << " b "; + } + buf2 << "]"; + + ASSERT_STREQ( + buf1.str().c_str(), + buf2.str().c_str() + ); +} + +TEST_F(FormatTest, F32E) { + F32 testVals[FormatF32e::SIZE] = + {std::numeric_limits::min(), 0.0, std::numeric_limits::max()}; + FormatF32e a(testVals); + + buf1 << a; + for (U32 i = 0; i < FormatF32e::SIZE; i++) { + buf2 << "a " << std::setprecision(1) << std::scientific << testVals[i] << " b "; + } + buf2 << "]"; + + ASSERT_STREQ( + buf1.str().c_str(), + buf2.str().c_str() + ); +} + +TEST_F(FormatTest, F32F) { + F32 testVals[FormatF32f::SIZE] = + {std::numeric_limits::min(), 0.0, std::numeric_limits::max()}; + FormatF32f a(testVals); + + buf1 << a; + for (U32 i = 0; i < FormatF32f::SIZE; i++) { + buf2 << "a " << std::setprecision(2) << std::fixed << testVals[i] << " b "; + } + buf2 << "]"; + + ASSERT_STREQ( + buf1.str().c_str(), + buf2.str().c_str() + ); +} + +TEST_F(FormatTest, F64G) { + F64 testVals[FormatF64g::SIZE] = + {std::numeric_limits::min(), 0.0, std::numeric_limits::max()}; + FormatF64g a(testVals); + + buf1 << a; + for (U32 i = 0; i < FormatF64g::SIZE; i++) { + buf2 << "a " << std::setprecision(3) << testVals[i] << " b "; + } + buf2 << "]"; + + ASSERT_STREQ( + buf1.str().c_str(), + buf2.str().c_str() + ); +} + +TEST_F(FormatTest, String) { + FormatString::StringSize80 testVals[FormatString::SIZE]; + char buf[80]; + for (U32 i = 0; i < FormatString::SIZE; i++) { + FppTest::Utils::setString(buf, sizeof(buf)); + testVals[i] = buf; + } + + FormatString a(testVals); + + buf1 << a; + for (U32 i = 0; i < FormatString::SIZE; i++) { + buf2 << "% " << testVals[i].toChar() << " "; + } + buf2 << "]"; + + ASSERT_STREQ( + buf1.str().c_str(), + buf2.str().c_str() + ); +} + +TEST_F(FormatTest, Char) { + U8 testVals[FormatChar::SIZE] = + {FppTest::Utils::getU8(), FppTest::Utils::getU8(), FppTest::Utils::getU8()}; + FormatChar a(testVals); + + buf1 << a; + for (U32 i = 0; i < FormatChar::SIZE; i++) { + buf2 << "a " << testVals[i] << " b "; + } + buf2 << "]"; + + ASSERT_STREQ( + buf1.str().c_str(), + buf2.str().c_str() + ); +} diff --git a/FppTest/array/README.md b/FppTest/array/README.md new file mode 100644 index 0000000000..e2b06345e7 --- /dev/null +++ b/FppTest/array/README.md @@ -0,0 +1,12 @@ +# FppTest/array + +This directory contains unit tests for the FPP array code generator. + +* ArrayToStringTest: Tests array toString() and ostream operator functions +* FormatTest: Tests FPP format strings + +To use this directory, you must have installed F Prime, and you must be inside +the F Prime Python virtual environment. + +* To build the tests, run `fprime-util build --ut`. +* To run the tests, run `fprime-util check`. \ No newline at end of file diff --git a/FppTest/array/array.fpp b/FppTest/array/array.fpp new file mode 100644 index 0000000000..a9c17a3c23 --- /dev/null +++ b/FppTest/array/array.fpp @@ -0,0 +1,3 @@ +array Uint32 = [2] U32; + +array Uint32Array = [3] Uint32; diff --git a/FppTest/array/enum.fpp b/FppTest/array/enum.fpp new file mode 100644 index 0000000000..d536e60602 --- /dev/null +++ b/FppTest/array/enum.fpp @@ -0,0 +1,7 @@ +enum E { + A, + B, + C, +} + +array Enum = [3] E default [ E.A, E.B, E.C ] diff --git a/FppTest/array/format.fpp b/FppTest/array/format.fpp new file mode 100644 index 0000000000..241ae68fc0 --- /dev/null +++ b/FppTest/array/format.fpp @@ -0,0 +1,27 @@ +array FormatBool = [3] bool format "a {} b" + +array FormatU8 = [3] U8 format "a {} b" + +array FormatU16Dec = [3] U16 format "a {d} b" + +array FormatU32Oct = [3] U32 format "a {o} b" + +array FormatU64Hex = [3] U64 format "a {x} b" + +array FormatI8 = [3] I8 format "a {} b" + +array FormatI16Dec = [3] I16 format "a {d} b" + +array FormatI32Oct = [3] I32 format "a {o} b" + +array FormatI64Hex = [3] I64 format "a {x} b" + +array FormatF32e = [3] F32 format "a {.1e} b" + +array FormatF32f = [3] F32 format "a {.2f} b" + +array FormatF64g = [3] F64 format "a {.3g} b" + +array FormatString = [3] string format "% {}" + +array FormatChar = [3] U8 format "a {c} b" diff --git a/FppTest/array/main.cpp b/FppTest/array/main.cpp new file mode 100644 index 0000000000..856fcc1f45 --- /dev/null +++ b/FppTest/array/main.cpp @@ -0,0 +1,146 @@ +// ====================================================================== +// \title main.cpp +// \author T. Chieu +// \brief main cpp file for FPP array tests +// +// \copyright +// Copyright (C) 2009-2022 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "FppTest/array/EnumArrayAc.hpp" +#include "FppTest/array/StringArrayAc.hpp" +#include "FppTest/array/StructArrayAc.hpp" +#include "FppTest/array/Uint32ArrayArrayAc.hpp" +#include "FppTest/array/String100ArrayAc.hpp" + +#include "FppTest/typed_tests/ArrayTest.hpp" +#include "FppTest/typed_tests/StringTest.hpp" +#include "FppTest/utils/Utils.hpp" + +#include "STest/Random/Random.hpp" +#include "gtest/gtest.h" + +// Instantiate array tests +using ArrayTestImplementations = ::testing::Types< + Enum, + String, + Struct, + Uint32Array +>; +INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, ArrayTest, ArrayTestImplementations); + +// Specializations for default values +template <> +void FppTest::Array::setDefaultVals(E (&a)[Enum::SIZE]) { + a[0] = E::A; + a[1] = E::B; + a[2] = E::C; +} + +// Specialization for test values +template<> +void FppTest::Array::setTestVals(E (&a)[Enum::SIZE]) { + a[0] = static_cast(STest::Pick::startLength( + E::B, + E::NUM_CONSTANTS - 1 + )); + + for (U32 i = 1; i < Enum::SIZE; i++) { + a[i] = static_cast(STest::Pick::startLength( + E::A, + E::NUM_CONSTANTS - 1 + )); + } +} + +template<> +void FppTest::Array::setTestVals + (::String::StringSize80 (&a)[::String::SIZE]) { + char buf[80]; + for (U32 i = 0; i < ::String::SIZE; i++) { + FppTest::Utils::setString(buf, sizeof(buf)); + a[i] = buf; + } +} + +template<> +void FppTest::Array::setTestVals(S (&a)[Struct::SIZE]) { + U32 b[3]; + for (U32 i = 0; i < Struct::SIZE; i++) { + for (U32 j = 0; j < 3; j++) { + b[j] = FppTest::Utils::getU32(); + } + a[i].set(FppTest::Utils::getU32(), b); + } +} + +template<> +void FppTest::Array::setTestVals(Uint32 (&a)[Uint32Array::SIZE]) { + Uint32 b; + for (U32 i = 0; i < Uint32Array::SIZE; i++) { + for (U32 j = 0; j < Uint32::SIZE; j++) { + b[j] = FppTest::Utils::getU32(); + } + a[i] = b; + } +} + +// Specializations for multi element constructor +template<> +Enum FppTest::Array::getMultiElementConstructedArray + (E (&a)[Enum::SIZE]) { + return Enum(a[0], a[1], a[2]); +} + +template<> +::String FppTest::Array::getMultiElementConstructedArray<::String> + (::String::StringSize80 (&a)[::String::SIZE]) { + return ::String(a[0], a[1], a[2]); +} + +template<> +Struct FppTest::Array::getMultiElementConstructedArray + (S (&a)[Struct::SIZE]) { + return Struct(a[0], a[1], a[2]); +} + +template<> +Uint32Array FppTest::Array::getMultiElementConstructedArray + (Uint32 (&a)[Uint32Array::SIZE]) { + return Uint32Array(a[0], a[1], a[2]); +} + +// Specializations for serialized size +template <> +U32 FppTest::Array::getSerializedSize<::String> + (::String::StringSize80 (&a)[::String::SIZE]) { + U32 serializedSize = 0; + + for (U32 i = 0; i < ::String::SIZE; i++) { + serializedSize += a[i].length() + sizeof(FwBuffSizeType); + } + + return serializedSize; +} + +// Instantiate string tests for arrays +using StringTestImplementations = ::testing::Types< + String::StringSize80, + String100::StringSize100 +>; +INSTANTIATE_TYPED_TEST_SUITE_P(Array, StringTest, StringTestImplementations); + +template<> +U32 FppTest::String::getSize() { + return 100; +} + +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + STest::Random::seed(); + + return RUN_ALL_TESTS(); +} diff --git a/FppTest/array/string.fpp b/FppTest/array/string.fpp new file mode 100644 index 0000000000..fc2c052005 --- /dev/null +++ b/FppTest/array/string.fpp @@ -0,0 +1,3 @@ +array String = [3] string + +array String100 = [3] string size 100 diff --git a/FppTest/array/struct.fpp b/FppTest/array/struct.fpp new file mode 100644 index 0000000000..1c47492abe --- /dev/null +++ b/FppTest/array/struct.fpp @@ -0,0 +1,6 @@ +struct S { + mU32: U32 + mU32Arr: [3] U32 +} + +array Struct = [3] S diff --git a/FppTest/enum/CMakeLists.txt b/FppTest/enum/CMakeLists.txt new file mode 100644 index 0000000000..4dc0819bc7 --- /dev/null +++ b/FppTest/enum/CMakeLists.txt @@ -0,0 +1,27 @@ +# ====================================================================== +# CMakeLists.txt +# ====================================================================== + +# We need to declare the XML source files this way to invoke the autocoder. +# However, only the UT build is allowed here. +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/implicit.fpp" + "${CMAKE_CURRENT_LIST_DIR}/explicit.fpp" + "${CMAKE_CURRENT_LIST_DIR}/default.fpp" + "${CMAKE_CURRENT_LIST_DIR}/interval.fpp" + "${CMAKE_CURRENT_LIST_DIR}/serialize_type.fpp" +) +register_fprime_module() + +# Declare dependencies on test modules +set(UT_MOD_DEPS + Fw/Test + STest +) + +# List all .cpp files as UT_SOURCE_FILES. Only the UT build is allowed. +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/EnumToStringTest.cpp" + "${CMAKE_CURRENT_LIST_DIR}/main.cpp" +) +register_fprime_ut() diff --git a/FppTest/enum/EnumToStringTest.cpp b/FppTest/enum/EnumToStringTest.cpp new file mode 100644 index 0000000000..c533b637f7 --- /dev/null +++ b/FppTest/enum/EnumToStringTest.cpp @@ -0,0 +1,125 @@ +// ====================================================================== +// \title EnumToStringTest.cpp +// \author T. Chieu +// \brief cpp file for EnumToStringTest class +// +// \copyright +// Copyright (C) 2009-2022 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "FppTest/enum/ImplicitEnumAc.hpp" +#include "FppTest/enum/ExplicitEnumAc.hpp" +#include "FppTest/enum/DefaultEnumAc.hpp" +#include "FppTest/enum/IntervalEnumAc.hpp" +#include "FppTest/enum/SerializeTypeU8EnumAc.hpp" +#include "FppTest/enum/SerializeTypeU64EnumAc.hpp" + +#include "gtest/gtest.h" + +#include +#include + +namespace FppTest { + + // Populate an array with enum values + template + void setEnumValArray(typename EnumType::T (&a)[EnumType::NUM_CONSTANTS+1]) { + for (U32 i = 0; i < EnumType::NUM_CONSTANTS + 1; i++) { + a[i] = static_cast(i); + } + } + + template<> + void setEnumValArray(Explicit::T (&a)[Explicit::NUM_CONSTANTS+1]) { + a[0] = Explicit::A; + a[1] = Explicit::B; + a[2] = Explicit::C; + a[3] = static_cast(11); + } + + template<> + void setEnumValArray(Interval::T (&a)[Interval::NUM_CONSTANTS+1]) { + a[0] = Interval::A; + a[1] = Interval::B; + a[2] = Interval::C; + a[3] = Interval::D; + a[4] = Interval::E; + a[5] = Interval::F; + a[6] = Interval::G; + a[7] = static_cast(11); + } + + // Populate an array with strings representing enum values + template + void setEnumStrArray(std::string (&a)[EnumType::NUM_CONSTANTS+1]) { + a[0] = "A (0)"; + a[1] = "B (1)"; + a[2] = "C (2)"; + a[3] = "D (3)"; + a[4] = "E (4)"; + a[5] = "[invalid] (5)"; + } + + template<> + void setEnumStrArray(std::string (&a)[Explicit::NUM_CONSTANTS+1]) { + a[0] = "A (-1952875139)"; + a[1] = "B (2)"; + a[2] = "C (2000999333)"; + a[3] = "[invalid] (11)"; + } + + template <> + void setEnumStrArray(std::string (&a)[Interval::NUM_CONSTANTS+1]) { + a[0] = "A (0)"; + a[1] = "B (3)"; + a[2] = "C (4)"; + a[3] = "D (5)"; + a[4] = "E (10)"; + a[5] = "F (100)"; + a[6] = "G (101)"; + a[7] = "[invalid] (11)"; + } + +} // namespace FppTest + +// Test enum string functions +template +class EnumToStringTest : public ::testing::Test { +protected: + void SetUp() override { + FppTest::setEnumValArray(vals); + FppTest::setEnumStrArray(strs); + }; + + EnumType e; + std::stringstream buf; + + typename EnumType::T vals[EnumType::NUM_CONSTANTS+1]; + std::string strs[EnumType::NUM_CONSTANTS+1]; +}; + +// Specify type parameters for this test suite +using EnumTypes = ::testing::Types< + Implicit, + Explicit, + Default, + Interval, + SerializeTypeU8, + SerializeTypeU64 +>; +TYPED_TEST_SUITE(EnumToStringTest, EnumTypes); + +// Test enum toString() and ostream operator functions +TYPED_TEST(EnumToStringTest, ToString) { + for (U32 i = 0; i < TypeParam::NUM_CONSTANTS + 1; i++) { + this->e = this->vals[i]; + this->buf << this->e; + + ASSERT_STREQ(this->buf.str().c_str(), this->strs[i].c_str()); + + this->buf.str(""); + } +} diff --git a/FppTest/enum/IsValidTest.cpp b/FppTest/enum/IsValidTest.cpp new file mode 100644 index 0000000000..8c1d02d9cd --- /dev/null +++ b/FppTest/enum/IsValidTest.cpp @@ -0,0 +1,54 @@ +// ====================================================================== +// \title IsValidTest.cpp +// \author T. Chieu +// \brief cpp file for IsValidTest class +// +// \copyright +// Copyright (C) 2009-2022 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "FppTest/enum/IntervalEnumAc.hpp" + +#include "gtest/gtest.h" + +// Test boundary values for enum isValid() function +TEST(IsValidTest, IntervalEnum) { + Interval e = static_cast(-1); + ASSERT_FALSE(e.isValid()); + + e = static_cast(0); + ASSERT_TRUE(e.isValid()); + + e = static_cast(1); + ASSERT_FALSE(e.isValid()); + + e = static_cast(2); + ASSERT_FALSE(e.isValid()); + + e = static_cast(3); + ASSERT_TRUE(e.isValid()); + + e = static_cast(5); + ASSERT_TRUE(e.isValid()); + + e = static_cast(6); + ASSERT_FALSE(e.isValid()); + + e = static_cast(10); + ASSERT_TRUE(e.isValid()); + + e = static_cast(99); + ASSERT_FALSE(e.isValid()); + + e = static_cast(100); + ASSERT_TRUE(e.isValid()); + + e = static_cast(101); + ASSERT_TRUE(e.isValid()); + + e = static_cast(102); + ASSERT_FALSE(e.isValid()); +} diff --git a/FppTest/enum/README.md b/FppTest/enum/README.md new file mode 100644 index 0000000000..f984de13d9 --- /dev/null +++ b/FppTest/enum/README.md @@ -0,0 +1,12 @@ +# FppTest/enum + +This directory contains unit tests for the FPP enum code generator. + +* EnumToStringTest: Tests enum toString() and ostream operator functions +* IsValidTest: Additional tests for isValid() function with boundary values + +To use this directory, you must have installed F Prime, and you must be inside +the F Prime Python virtual environment. + +* To build the tests, run `fprime-util build --ut`. +* To run the tests, run `fprime-util check`. diff --git a/FppTest/enum/default.fpp b/FppTest/enum/default.fpp new file mode 100644 index 0000000000..d06a22fc22 --- /dev/null +++ b/FppTest/enum/default.fpp @@ -0,0 +1,8 @@ +@ An enum with specified default values +enum Default { + A, + B, + C, + D, + E, +} default C diff --git a/FppTest/enum/explicit.fpp b/FppTest/enum/explicit.fpp new file mode 100644 index 0000000000..0e3746477c --- /dev/null +++ b/FppTest/enum/explicit.fpp @@ -0,0 +1,6 @@ +@ An enum with explicit constant values +enum Explicit { + A = -1952875139, + B = 2, + C = 2000999333, +} diff --git a/FppTest/enum/implicit.fpp b/FppTest/enum/implicit.fpp new file mode 100644 index 0000000000..617e4ec1f1 --- /dev/null +++ b/FppTest/enum/implicit.fpp @@ -0,0 +1,8 @@ +@ An enum with implicit constant values +enum Implicit { + A, @< Member A + B, + C, + D, + E, +} diff --git a/FppTest/enum/interval.fpp b/FppTest/enum/interval.fpp new file mode 100644 index 0000000000..09e73091e6 --- /dev/null +++ b/FppTest/enum/interval.fpp @@ -0,0 +1,10 @@ +@ An enum with many intervals of values +enum Interval { + A = 0, + B = 3, + C = 4, + D = 5, + E = 10, + F = 100, + G = 101, +} diff --git a/FppTest/enum/main.cpp b/FppTest/enum/main.cpp new file mode 100644 index 0000000000..dd7cb15212 --- /dev/null +++ b/FppTest/enum/main.cpp @@ -0,0 +1,108 @@ +// ====================================================================== +// \title main.cpp +// \author T. Chieu +// \brief main cpp file for FPP enum tests +// +// \copyright +// Copyright (C) 2009-2022 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "FppTest/enum/ImplicitEnumAc.hpp" +#include "FppTest/enum/ExplicitEnumAc.hpp" +#include "FppTest/enum/DefaultEnumAc.hpp" +#include "FppTest/enum/IntervalEnumAc.hpp" +#include "FppTest/enum/SerializeTypeU8EnumAc.hpp" +#include "FppTest/enum/SerializeTypeU64EnumAc.hpp" + +#include "FppTest/typed_tests/EnumTest.hpp" + +#include "STest/Random/Random.hpp" +#include "gtest/gtest.h" + +// Instantiate enum tests +using EnumTestImplementations = ::testing::Types< + Implicit, + Explicit, + Default, + Interval, + SerializeTypeU8, + SerializeTypeU64 +>; +INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, + EnumTest, + EnumTestImplementations); + +// Specializations for default value +template<> +Explicit::T FppTest::Enum::getDefaultValue() { + return Explicit::A; +} + +template<> +Default::T FppTest::Enum::getDefaultValue() { + return Default::C; +} + +// Specializations for valid value +template<> +Explicit::T FppTest::Enum::getValidValue() { + U32 val = STest::Pick::startLength(0, Explicit::NUM_CONSTANTS); + + switch (val) { + case 0: return Explicit::A; + case 1: return Explicit::B; + default: return Explicit::C; + } +} + +template<> +Interval::T FppTest::Enum::getValidValue() { + U32 val = STest::Pick::startLength(0, Interval::NUM_CONSTANTS); + + switch (val) { + case 0: return Interval::A; + case 1: return Interval::B; + case 2: return Interval::C; + case 3: return Interval::D; + case 4: return Interval::E; + case 5: return Interval::F; + default: return Interval::G; + } +} + +// Specializations for invalid value +template <> +Explicit::T FppTest::Enum::getInvalidValue() { + U32 sign = STest::Pick::lowerUpper(0, 1); + + switch (sign) { + case 0: + return static_cast(STest::Pick::lowerUpper( + Explicit::C + 1, + std::numeric_limits::max() + )); + default: + return static_cast(STest::Pick::lowerUpper( + (Explicit::A - 1) * (-1), + std::numeric_limits::max() + ) * (-1)); + } +} + +template<> +Interval::T FppTest::Enum::getInvalidValue() { + return static_cast(STest::Pick::lowerUpper( + Interval::G + 1, + std::numeric_limits::max() + )); +} + +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + STest::Random::seed(); + + return RUN_ALL_TESTS(); +} diff --git a/FppTest/enum/serialize_type.fpp b/FppTest/enum/serialize_type.fpp new file mode 100644 index 0000000000..af8e3d370f --- /dev/null +++ b/FppTest/enum/serialize_type.fpp @@ -0,0 +1,16 @@ +@ An enum with a specified serialize type +enum SerializeTypeU8 : U8 { + A, + B, + C, + D, + E, +} + +enum SerializeTypeU64 : U64 { + A, + B, + C, + D, + E, +} diff --git a/FppTest/port/CMakeLists.txt b/FppTest/port/CMakeLists.txt new file mode 100644 index 0000000000..0c6fab1e8c --- /dev/null +++ b/FppTest/port/CMakeLists.txt @@ -0,0 +1,45 @@ +# ====================================================================== +# CMakeLists.txt +# ====================================================================== + +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/fpp_types.fpp" + "${CMAKE_CURRENT_LIST_DIR}/no_return_ports.fpp" + "${CMAKE_CURRENT_LIST_DIR}/return_ports.fpp" + "${CMAKE_CURRENT_LIST_DIR}/port_index_enums.fpp" + "${CMAKE_CURRENT_LIST_DIR}/example_comp.fpp" + "${CMAKE_CURRENT_LIST_DIR}/Example.cpp" +) + +register_fprime_module() + +# Sets MODULE_NAME to unique name based on path +get_module_name(${CMAKE_CURRENT_LIST_DIR}) + +# Exclude test module from all build +set_target_properties( + ${MODULE_NAME} + PROPERTIES + EXCLUDE_FROM_ALL TRUE +) + +# Declare dependencies on test modules +set(UT_MOD_DEPS + Fw/Test + STest +) + +# Add unit test directory +# UT_SOURCE_FILES: Sources for unit test +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/fpp_types.fpp" + "${CMAKE_CURRENT_LIST_DIR}/no_return_ports.fpp" + "${CMAKE_CURRENT_LIST_DIR}/return_ports.fpp" + "${CMAKE_CURRENT_LIST_DIR}/port_index_enums.fpp" + "${CMAKE_CURRENT_LIST_DIR}/example_comp.fpp" + "${CMAKE_CURRENT_LIST_DIR}/../utils/Utils.cpp" + "${CMAKE_CURRENT_LIST_DIR}/PortTypes.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/TestMain.cpp" +) +register_fprime_ut() diff --git a/FppTest/port/Example.cpp b/FppTest/port/Example.cpp new file mode 100644 index 0000000000..8a679f7a2f --- /dev/null +++ b/FppTest/port/Example.cpp @@ -0,0 +1,192 @@ +// ====================================================================== +// \title Example.cpp +// \author T. Chieu +// \brief cpp file for Example component implementation class +// ====================================================================== + + +#include +#include + + + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + Example :: + Example( + const char *const compName + ) : ExampleComponentBase(compName) + { + + } + + void Example :: + init( + const NATIVE_INT_TYPE instance + ) + { + ExampleComponentBase::init(instance); + } + + Example :: + ~Example() + { + + } + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + void Example :: + arrayArgsIn_handler( + const NATIVE_INT_TYPE portNum, + const PortArray &a, + PortArray &aRef + ) + { + this->arrayArgsOut_out(portNum, a, aRef); + } + + PortArray Example :: + arrayReturnIn_handler( + const NATIVE_INT_TYPE portNum, + const PortArray &a, + PortArray &aRef + ) + { + return this->arrayReturnOut_out(portNum, a, aRef); + } + + void Example :: + enumArgsIn_handler( + const NATIVE_INT_TYPE portNum, + const PortEnum &e, + PortEnum &eRef + ) + { + this->enumArgsOut_out(portNum, e, eRef); + } + + PortEnum Example :: + enumReturnIn_handler( + const NATIVE_INT_TYPE portNum, + const PortEnum &e, + PortEnum &eRef + ) + { + return this->enumReturnOut_out(portNum, e, eRef); + } + + void Example :: + noArgsIn_handler( + const NATIVE_INT_TYPE portNum + ) + { + this->noArgsOut_out(portNum); + } + + bool Example :: + noArgsReturnIn_handler( + const NATIVE_INT_TYPE portNum + ) + { + return this->noArgsReturnOut_out(portNum); + } + + void Example :: + primitiveArgsIn_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + this->primitiveArgsOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + U32 Example :: + primitiveReturnIn_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + return this->primitiveReturnOut_out( + portNum, + u32, + u32Ref, + f32, + f32Ref, + b, + bRef + ); + } + + void Example :: + stringArgsIn_handler( + const NATIVE_INT_TYPE portNum, + const str80String &str80, + str80RefString &str80Ref, + const str100String &str100, + str100RefString &str100Ref + ) + { + this->stringArgsOut_out( + portNum, + str80, + str80Ref, + str100, + str100Ref + ); + } + + void Example :: + structArgsIn_handler( + const NATIVE_INT_TYPE portNum, + const PortStruct &s, + PortStruct &sRef + ) + { + this->structArgsOut_out(portNum, s, sRef); + } + + PortStruct Example :: + structReturnIn_handler( + const NATIVE_INT_TYPE portNum, + const PortStruct &s, + PortStruct &sRef + ) + { + return this->structReturnOut_out(portNum, s, sRef); + } + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined serial input ports + // ---------------------------------------------------------------------- + + void Example :: + serialIn_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + this->serializeStatus = this->serialOut_out(portNum, Buffer); + } + diff --git a/FppTest/port/Example.hpp b/FppTest/port/Example.hpp new file mode 100644 index 0000000000..75510209aa --- /dev/null +++ b/FppTest/port/Example.hpp @@ -0,0 +1,188 @@ +// ====================================================================== +// \title Example.hpp +// \author T. Chieu +// \brief hpp file for Example component implementation class +// ====================================================================== + +#ifndef Example_HPP +#define Example_HPP + +#include "FppTest/port/ExampleComponentAc.hpp" + + + class Example : + public ExampleComponentBase + { + + public: + + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + //! Construct object Example + //! + Example( + const char *const compName /*!< The component name*/ + ); + + //! Initialize object Example + //! + void init( + const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ + ); + + //! Destroy object Example + //! + ~Example(); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for arrayArgsIn + //! + void arrayArgsIn_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const PortArray &a, /*!< + An array + */ + PortArray &aRef /*!< + An array ref + */ + ); + + //! Handler implementation for arrayReturnIn + //! + PortArray arrayReturnIn_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const PortArray &a, /*!< + An array + */ + PortArray &aRef /*!< + An array ref + */ + ); + + //! Handler implementation for enumArgsIn + //! + void enumArgsIn_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const PortEnum &e, /*!< + An enum + */ + PortEnum &eRef /*!< + An enum ref + */ + ); + + //! Handler implementation for enumReturnIn + //! + PortEnum enumReturnIn_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const PortEnum &e, /*!< + An enum + */ + PortEnum &eRef /*!< + An enum ref + */ + ); + + //! Handler implementation for noArgsIn + //! + void noArgsIn_handler( + const NATIVE_INT_TYPE portNum /*!< The port number*/ + ); + + //! Handler implementation for noArgsReturnIn + //! + bool noArgsReturnIn_handler( + const NATIVE_INT_TYPE portNum /*!< The port number*/ + ); + + //! Handler implementation for primitiveArgsIn + //! + void primitiveArgsIn_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ); + + //! Handler implementation for primitiveReturnIn + //! + U32 primitiveReturnIn_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ); + + //! Handler implementation for stringArgsIn + //! + void stringArgsIn_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const str80String &str80, /*!< + A string of size 80 + */ + str80RefString &str80Ref, + const str100String &str100, /*!< + A string of size 100 + */ + str100RefString &str100Ref + ); + + //! Handler implementation for structArgsIn + //! + void structArgsIn_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const PortStruct &s, /*!< + A struct + */ + PortStruct &sRef /*!< + A struct ref + */ + ); + + //! Handler implementation for structReturnIn + //! + PortStruct structReturnIn_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const PortStruct &s, /*!< + A struct + */ + PortStruct &sRef /*!< + A struct ref + */ + ); + + PRIVATE: + + // ---------------------------------------------------------------------- + // Handler implementations for user-defined serial input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for serialIn + //! + void serialIn_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ); + + public: + + //! Enables checking the serialization status of serial port invocations + Fw::SerializeStatus serializeStatus; + + }; + + +#endif diff --git a/FppTest/port/PortTypes.cpp b/FppTest/port/PortTypes.cpp new file mode 100644 index 0000000000..bb774e6b90 --- /dev/null +++ b/FppTest/port/PortTypes.cpp @@ -0,0 +1,138 @@ +// ====================================================================== +// \title PortTypes.cpp +// \author T. Chieu +// \brief cpp file for port types +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "PortTypes.hpp" + +#include "STest/Pick/Pick.hpp" +#include "FppTest/utils/Utils.hpp" + +namespace FppTest { + + namespace Port { + + // ---------------------------------------------------------------------- + // Argument types + // ---------------------------------------------------------------------- + + PrimitiveArgs::PrimitiveArgs() { + u32 = STest::Pick::any(); + u32Ref = STest::Pick::any(); + f32 = static_cast(STest::Pick::any()); + f32Ref = static_cast(STest::Pick::any()); + b = static_cast(STest::Pick::lowerUpper(0, 1)); + bRef = static_cast(STest::Pick::lowerUpper(0, 1)); + } + + StringArgs::StringArgs() { + char buf80[str80.getCapacity()]; + char buf100[str100.getCapacity()]; + + Utils::setString(buf80, sizeof(buf80)); + Utils::setString(buf100, sizeof(buf100)); + + str80 = buf80; + str100 = buf100; + + Utils::setString(buf80, sizeof(buf80)); + Utils::setString(buf100, sizeof(buf100)); + + str80Ref = buf80; + str100Ref = buf100; + } + + EnumArgs::EnumArgs() { + en = getRandomPortEnum(); + enRef = getRandomPortEnum(); + } + + ArrayArgs::ArrayArgs() { + a = getRandomPortArray(); + aRef = getRandomPortArray(); + } + + StructArgs::StructArgs() { + s = getRandomPortStruct(); + sRef = getRandomPortStruct(); + } + + SerialArgs::SerialArgs() : buf(data, sizeof(data)) { + U32 len = STest::Pick::lowerUpper(1, SERIAL_ARGS_BUFFER_CAPACITY); + + for (U32 i = 0; i < len; i++) { + data[i] = Utils::getU8(); + } + } + + // ---------------------------------------------------------------------- + // Return types + // ---------------------------------------------------------------------- + + + BoolReturn::BoolReturn() { + val = static_cast(STest::Pick::lowerUpper(0, 1)); + } + + PrimitiveReturn::PrimitiveReturn() { + val = STest::Pick::any(); + } + + EnumReturn::EnumReturn() { + val = getRandomPortEnum(); + } + + ArrayReturn::ArrayReturn() { + val = getRandomPortArray(); + } + + StructReturn::StructReturn() { + val = getRandomPortStruct(); + } + + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- + + PortEnum getRandomPortEnum() { + PortEnum e; + + e = static_cast(STest::Pick::lowerUpper( + 0, + PortEnum::NUM_CONSTANTS - 1 + )); + + return e; + } + + PortArray getRandomPortArray() { + PortArray a; + + for (U32 i = 0; i < PortArray::SIZE; i++) { + a[i] = STest::Pick::any(); + } + + return a; + } + + PortStruct getRandomPortStruct() { + PortStruct s; + char buf[s.gety().getCapacity()]; + PortStruct::StringSize80 str = buf; + + Utils::setString(buf, sizeof(buf)); + s.set(STest::Pick::any(), str); + + return s; + } + + } // namespace Port + +} // namespace FppTest diff --git a/FppTest/port/PortTypes.hpp b/FppTest/port/PortTypes.hpp new file mode 100644 index 0000000000..0ae7e62c81 --- /dev/null +++ b/FppTest/port/PortTypes.hpp @@ -0,0 +1,154 @@ +// ====================================================================== +// \title PortTypes.hpp +// \author T. Chieu +// \brief hpp file for port types +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#ifndef FPP_TEST_PORT_STRUCTS_HPP +#define FPP_TEST_PORT_STRUCTS_HPP + +#include "Fw/Types/SerialBuffer.hpp" + +#include "FppTest/port/PortEnumEnumAc.hpp" +#include "FppTest/port/PortArrayArrayAc.hpp" +#include "FppTest/port/PortStructSerializableAc.hpp" +#include "FppTest/port/StringArgsPortAc.hpp" + +#define SERIAL_ARGS_BUFFER_CAPACITY 256 + +namespace FppTest { + + namespace Port { + + // PortType template + template + struct PortType { + ArgType args; + }; + + // Empty type + struct Empty {}; + + // ---------------------------------------------------------------------- + // Argument types + // ---------------------------------------------------------------------- + + struct PrimitiveArgs { + PrimitiveArgs(); + + U32 u32; + U32 u32Ref; + F32 f32; + F32 f32Ref; + bool b; + bool bRef; + }; + + struct StringArgs { + StringArgs(); + + StringArgsPortStrings::StringSize80 str80; + StringArgsPortStrings::StringSize80 str80Ref; + StringArgsPortStrings::StringSize100 str100; + StringArgsPortStrings::StringSize100 str100Ref; + }; + + struct EnumArgs { + EnumArgs(); + + PortEnum en; + PortEnum enRef; + }; + + struct ArrayArgs { + ArrayArgs(); + + PortArray a; + PortArray aRef; + }; + + struct StructArgs { + StructArgs(); + + PortStruct s; + PortStruct sRef; + }; + + struct SerialArgs { + SerialArgs(); + + U8 data[SERIAL_ARGS_BUFFER_CAPACITY]; + Fw::SerialBuffer buf; + }; + + // ---------------------------------------------------------------------- + // Return types + // ---------------------------------------------------------------------- + + struct BoolReturn { + BoolReturn(); + + bool val; + }; + + struct PrimitiveReturn { + PrimitiveReturn(); + + U32 val; + }; + + struct EnumReturn { + EnumReturn(); + + PortEnum val; + }; + + struct ArrayReturn { + ArrayReturn(); + + PortArray val; + }; + + struct StructReturn { + StructReturn(); + + PortStruct val; + }; + + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- + + PortEnum getRandomPortEnum(); + PortArray getRandomPortArray(); + PortStruct getRandomPortStruct(); + + // ---------------------------------------------------------------------- + // Typedefs + // ---------------------------------------------------------------------- + + typedef PortType NoArgsPort; + typedef PortType PrimitiveArgsPort; + typedef PortType StringArgsPort; + typedef PortType EnumArgsPort; + typedef PortType ArrayArgsPort; + typedef PortType StructArgsPort; + typedef PortType SerialArgsPort; + + typedef PortType NoArgsReturnPort; + typedef PortType PrimitiveReturnPort; + typedef PortType EnumReturnPort; + typedef PortType ArrayReturnPort; + typedef PortType StructReturnPort; + + } // namespace Port + +} // namespace FppTest + +#endif diff --git a/FppTest/port/README.md b/FppTest/port/README.md new file mode 100644 index 0000000000..452871ab5f --- /dev/null +++ b/FppTest/port/README.md @@ -0,0 +1,33 @@ +# FppTest/port + +This directory contains unit tests for the FPP port code generator. + +* Supports unit tests for typed-to-typed, typed-to-serial, serial-to-typed, and +serial-to-serial port connections + +To use this directory, you must have installed F Prime, and you must be inside +the F Prime Python virtual environment. + +* To build the tests, run `fprime-util build --ut`. +* To run the tests, run `fprime-util check`. + +## Generating Coverage + +Mainline F Prime doesn't generate coverage for autocoded files in a +reliable way. This directory contains some workaround scripts for +generating coverage. To generate coverage, do the following: + +``` +% fprime-util build --ut +% ./build-exe +% ./exe +% ./gen-cov-all +``` + +The output will go to the console and to `.gcov` files. To run the +coverage analysis for one file, replace the last line with `./gen-cov` +followed by the base file name, without `.cpp` or `.hpp`. For example: + +``` +% ./gen-cov NoArgsPortAc +``` diff --git a/FppTest/port/build-exe b/FppTest/port/build-exe new file mode 100755 index 0000000000..c887e28927 --- /dev/null +++ b/FppTest/port/build-exe @@ -0,0 +1,37 @@ +#!/bin/sh + +fprime=../.. +build_cache=$fprime/FppTest/build-fprime-automatic-native-ut +srcs=" +`find . -name '*.cpp'` +`find ../utils -name '*.cpp'` +`find $build_cache/FppTest/port -name '*.cpp' | grep -v Tester.cpp | grep -v TestMain.cpp` +" +srcs=`echo $srcs | tr '\n' ' '` +flags=" +--coverage +--std=c++11 +-DBUILD_UT +-DPRIVATE=public +-DPROTECTED=public +-DTGT_OS_TYPE_DARWIN +-I$build_cache +-I$build_cache/F-Prime +-I$build_cache/FppTest/port +-I$fprime +-I$fprime/STest +-I$fprime/cmake/platform/types +-I$fprime/config +-I$fprime/gtest/googletest-src/googletest +-I$fprime/gtest/googletest-src/googletest/include +-I. +" +cmd="g++ -c $flags $srcs" +echo $cmd +$cmd + +libs=`find $build_cache -name '*.a'` +ofiles=`ls *.o` +cmd="g++ --coverage $ofiles $libs -o exe" +echo $cmd +$cmd diff --git a/FppTest/port/clean b/FppTest/port/clean new file mode 100755 index 0000000000..560e745ee2 --- /dev/null +++ b/FppTest/port/clean @@ -0,0 +1,3 @@ +#!/bin/sh + +rm -f *.o *.gcno *.gcda *.html *.gcov exe diff --git a/FppTest/port/example_comp.fpp b/FppTest/port/example_comp.fpp new file mode 100644 index 0000000000..c436649483 --- /dev/null +++ b/FppTest/port/example_comp.fpp @@ -0,0 +1,62 @@ +@ An example component +passive component Example { + + # Typed input ports with no return types + + sync input port noArgsIn: [2] NoArgs + + sync input port primitiveArgsIn: [2] PrimitiveArgs + + sync input port stringArgsIn: [2] StringArgs + + sync input port enumArgsIn: [2] EnumArgs + + sync input port arrayArgsIn: [2] ArrayArgs + + sync input port structArgsIn: [2] StructArgs + + # Typed output ports with no return types + + output port noArgsOut: [2] NoArgs + + output port primitiveArgsOut: [2] PrimitiveArgs + + output port stringArgsOut: [2] StringArgs + + output port enumArgsOut: [2] EnumArgs + + output port arrayArgsOut: [2] ArrayArgs + + output port structArgsOut: [2] StructArgs + + # Typed input ports with return types + + sync input port noArgsReturnIn: NoArgsReturn + + sync input port primitiveReturnIn: PrimitiveReturn + + sync input port enumReturnIn: EnumReturn + + sync input port arrayReturnIn: ArrayReturn + + sync input port structReturnIn: StructReturn + + # Typed output ports with return types + + output port noArgsReturnOut: NoArgsReturn + + output port primitiveReturnOut: PrimitiveReturn + + output port enumReturnOut: EnumReturn + + output port arrayReturnOut: ArrayReturn + + output port structReturnOut: StructReturn + + # Serial ports + + sync input port serialIn: [7] serial + + output port serialOut: [7] serial + +} diff --git a/FppTest/port/fpp_types.fpp b/FppTest/port/fpp_types.fpp new file mode 100644 index 0000000000..2ee9116103 --- /dev/null +++ b/FppTest/port/fpp_types.fpp @@ -0,0 +1,5 @@ +enum PortEnum { X, Y, Z } + +array PortArray = [3] U32 + +struct PortStruct { x: U32, y: string } diff --git a/FppTest/port/gen-cov b/FppTest/port/gen-cov new file mode 100755 index 0000000000..6cdfbb91a2 --- /dev/null +++ b/FppTest/port/gen-cov @@ -0,0 +1,12 @@ +#!/bin/sh + +if ! test $# -eq 1 +then + echo 'usage: gen-cov file-base' 1>&2 + exit 1 +fi + +base=$1 +fpp_test=../build-fprime-automatic-native-ut/FppTest +src=`find $fpp_test -name $base.cpp` +gcov -o $base.gcno $src diff --git a/FppTest/port/gen-cov-all b/FppTest/port/gen-cov-all new file mode 100755 index 0000000000..71e645e1bd --- /dev/null +++ b/FppTest/port/gen-cov-all @@ -0,0 +1,9 @@ +#!/bin/sh + +for file in `ls *Ac.gcno` +do + base=`basename $file .gcno` + cmd="./gen-cov $base" + echo $cmd + $cmd +done diff --git a/FppTest/port/gen-cov-html b/FppTest/port/gen-cov-html new file mode 100755 index 0000000000..a99389d369 --- /dev/null +++ b/FppTest/port/gen-cov-html @@ -0,0 +1,8 @@ +#!/bin/sh + +if [ ! -d "coverage/" ] +then + mkdir coverage +fi + +gcovr -r .. --html-details -f '(.*)PortAc\.cpp$' -o coverage/coverage.html . diff --git a/FppTest/port/no_return_ports.fpp b/FppTest/port/no_return_ports.fpp new file mode 100644 index 0000000000..b5ae2a8a0f --- /dev/null +++ b/FppTest/port/no_return_ports.fpp @@ -0,0 +1,38 @@ +@ A port with no arguments +port NoArgs + +@ A port with primitive arguments +port PrimitiveArgs( + u32: U32 + ref u32Ref: U32 + f32: F32 + ref f32Ref: F32 + b: bool + ref bRef: bool +) + +@ A port with string arguments +port StringArgs( + str80: string @< A string of size 80 + ref str80Ref: string + str100: string size 100 @< A string of size 100 + ref str100Ref: string size 100 +) + +@ A port with enum arguments +port EnumArgs( + en: PortEnum @< An enum + ref enRef: PortEnum @< An enum ref +) + +@ A port with array arguments +port ArrayArgs( + a: PortArray @< An array + ref aRef: PortArray @< An array ref +) + +@ A port with struct arguments +port StructArgs( + s: PortStruct @< A struct + ref sRef: PortStruct @< A struct ref +) diff --git a/FppTest/port/port_index_enums.fpp b/FppTest/port/port_index_enums.fpp new file mode 100644 index 0000000000..141eb45668 --- /dev/null +++ b/FppTest/port/port_index_enums.fpp @@ -0,0 +1,14 @@ +enum TypedPortIndex { + TYPED + SERIAL +} + +enum SerialPortIndex { + NO_ARGS + PRIMITIVE + STRING + ENUM + ARRAY + STRUCT + SERIAL +} diff --git a/FppTest/port/return_ports.fpp b/FppTest/port/return_ports.fpp new file mode 100644 index 0000000000..3a645589b8 --- /dev/null +++ b/FppTest/port/return_ports.fpp @@ -0,0 +1,40 @@ +@ A port with no arguments +port NoArgsReturn -> bool + +@ A port returning a primitive type +port PrimitiveReturn( + u32: U32 + ref u32Ref: U32 + f32: F32 + ref f32Ref: F32 + b: bool + ref bRef: bool +) -> U32 + +# Commented out because of bug in Python component autocoder +# Will be tested with the FPP component autocoder +# @ A port returning a string type +# port StringReturn( +# str80: string @< A string of size 80 +# ref str80Ref: string +# str100: string size 100 @< A string of size 100 +# ref str100Ref: string size 100 +# ) -> string + +@ A port returning an enum type +port EnumReturn( + en: PortEnum @< An enum + ref enRef: PortEnum @< An enum ref +) -> PortEnum + +@ A port returning an array type +port ArrayReturn( + a: PortArray @< An array + ref aRef: PortArray @< An array ref +) -> PortArray + +@ A port returning a struct type +port StructReturn( + s: PortStruct @< A struct + ref sRef: PortStruct @< A struct ref +) -> PortStruct diff --git a/FppTest/port/test/ut/TestMain.cpp b/FppTest/port/test/ut/TestMain.cpp new file mode 100644 index 0000000000..8d6f703952 --- /dev/null +++ b/FppTest/port/test/ut/TestMain.cpp @@ -0,0 +1,72 @@ +// ====================================================================== +// \title TestMain.cpp +// \author T. Chieu +// \brief main cpp file for FPP port tests +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + + +#include "Tester.hpp" +#include "FppTest/port/PortTypes.hpp" +#include "FppTest/typed_tests/PortTest.hpp" +#include "FppTest/typed_tests/StringTest.hpp" +#include "FppTest/port/StringArgsPortAc.hpp" + +#include "gtest/gtest.h" + +// Typed port tests +using TypedPortTestImplementations = ::testing::Types< + FppTest::Port::NoArgsPort, + FppTest::Port::PrimitiveArgsPort, + FppTest::Port::StringArgsPort, + FppTest::Port::EnumArgsPort, + FppTest::Port::ArrayArgsPort, + FppTest::Port::StructArgsPort, + FppTest::Port::NoArgsReturnPort, + FppTest::Port::PrimitiveReturnPort, + FppTest::Port::EnumReturnPort, + FppTest::Port::ArrayReturnPort, + FppTest::Port::StructReturnPort +>; + +INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, + TypedPortTest, + TypedPortTestImplementations); + +// Serial port tests +using SerialPortTestImplementations = ::testing::Types< + FppTest::Port::NoArgsPort, + FppTest::Port::PrimitiveArgsPort, + FppTest::Port::StringArgsPort, + FppTest::Port::EnumArgsPort, + FppTest::Port::ArrayArgsPort, + FppTest::Port::StructArgsPort +// FppTest::Port::SerialArgsPort +>; + +INSTANTIATE_TYPED_TEST_SUITE_P(FppTest, + SerialPortTest, + SerialPortTestImplementations); + +// String tests +using StringTestImplementations = ::testing::Types< + StringArgsPortStrings::StringSize80, + StringArgsPortStrings::StringSize100 +>; + +INSTANTIATE_TYPED_TEST_SUITE_P(Array, StringTest, StringTestImplementations); + +template<> +U32 FppTest::String::getSize() { + return 100; +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/FppTest/port/test/ut/Tester.cpp b/FppTest/port/test/ut/Tester.cpp new file mode 100644 index 0000000000..2126120dac --- /dev/null +++ b/FppTest/port/test/ut/Tester.cpp @@ -0,0 +1,1409 @@ +// ====================================================================== +// \title Tester.cpp +// \author T. Chieu +// \brief cpp file for Example test harness implementation class +// ====================================================================== + +#include "Tester.hpp" + +#define INSTANCE 0 +#define MAX_HISTORY_SIZE 10 + + + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + Tester :: + Tester() : + ExampleGTestBase("Tester", MAX_HISTORY_SIZE), + component("Example"), + primitiveBuf(primitiveData, sizeof(primitiveData)), + stringBuf(stringData, sizeof(stringData)), + enumBuf(enumData, sizeof(enumData)), + arrayBuf(arrayData, sizeof(arrayData)), + structBuf(structData, sizeof(structData)), + serialBuf(serialData, sizeof(serialData)) + { + this->initComponents(); + this->connectPorts(); + } + + Tester :: + ~Tester() + { + + } + + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + void Tester :: + toDo() + { + // TODO + } + + // ---------------------------------------------------------------------- + // Invoke typed input ports + // ---------------------------------------------------------------------- + + void Tester :: + invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::NoArgsPort& port + ) + { + this->invoke_to_noArgsIn(portNum); + } + + void Tester :: + invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::PrimitiveArgsPort& port + ) + { + this->invoke_to_primitiveArgsIn( + portNum, + port.args.u32, + port.args.u32Ref, + port.args.f32, + port.args.f32Ref, + port.args.b, + port.args.bRef + ); + } + + void Tester :: + invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::StringArgsPort& port + ) + { + this->invoke_to_stringArgsIn( + portNum, + port.args.str80, + port.args.str80Ref, + port.args.str100, + port.args.str100Ref + ); + } + + void Tester :: + invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::EnumArgsPort& port + ) + { + this->invoke_to_enumArgsIn( + portNum, + port.args.en, + port.args.enRef + ); + } + + void Tester :: + invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::ArrayArgsPort& port + ) + { + this->invoke_to_arrayArgsIn( + portNum, + port.args.a, + port.args.aRef + ); + } + + void Tester :: + invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::StructArgsPort& port + ) + { + this->invoke_to_structArgsIn( + portNum, + port.args.s, + port.args.sRef + ); + } + + void Tester :: + invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::SerialArgsPort& port + ) + { + this->invoke_to_serialIn( + portNum, + port.args.buf + ); + } + + void Tester :: + invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::NoArgsReturnPort& port + ) + { + bool returnVal = this->invoke_to_noArgsReturnIn(portNum); + + ASSERT_EQ(returnVal, this->noArgsReturnVal.val); + } + + void Tester :: + invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::PrimitiveReturnPort& port + ) + { + U32 returnVal = this->invoke_to_primitiveReturnIn( + portNum, + port.args.u32, + port.args.u32Ref, + port.args.f32, + port.args.f32Ref, + port.args.b, + port.args.bRef + ); + + ASSERT_EQ(returnVal, this->primitiveReturnVal.val); + } + + void Tester :: + invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::EnumReturnPort& port + ) + { + PortEnum returnVal = this->invoke_to_enumReturnIn( + portNum, + port.args.en, + port.args.enRef + ); + + ASSERT_EQ(returnVal, this->enumReturnVal.val); + } + + void Tester :: + invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::ArrayReturnPort& port + ) + { + PortArray returnVal = this->invoke_to_arrayReturnIn( + portNum, + port.args.a, + port.args.aRef + ); + + ASSERT_EQ(returnVal, this->arrayReturnVal.val); + } + + void Tester :: + invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::StructReturnPort& port + ) + { + PortStruct returnVal = this->invoke_to_structReturnIn( + portNum, + port.args.s, + port.args.sRef + ); + + ASSERT_EQ(returnVal, this->structReturnVal.val); + } + + // ---------------------------------------------------------------------- + // Invoke serial input ports + // ---------------------------------------------------------------------- + + void Tester :: + invoke_serial( + NATIVE_INT_TYPE portNum, + FppTest::Port::NoArgsPort& port + ) + { + U8 data[0]; + Fw::SerialBuffer buf(data, sizeof(data)); + + this->invoke_to_serialIn( + SerialPortIndex::NO_ARGS, + buf + ); + } + + void Tester :: + invoke_serial( + NATIVE_INT_TYPE portNum, + FppTest::Port::PrimitiveArgsPort& port + ) + { + Fw::SerializeStatus status; + + // Check unsuccessful deserialization of first parameter + U8 invalidData1[0]; + Fw::SerialBuffer invalidBuf1(invalidData1, sizeof(invalidData1)); + + this->invoke_to_serialIn( + SerialPortIndex::PRIMITIVE, + invalidBuf1 + ); + + this->checkSerializeStatusBufferEmpty(); + + // Check unsuccessful deserialization of second parameter + U8 invalidData2[sizeof(U32)]; + Fw::SerialBuffer invalidBuf2(invalidData2, sizeof(invalidData2)); + + status = invalidBuf2.serialize(port.args.u32); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::PRIMITIVE, + invalidBuf2 + ); + + this->checkSerializeStatusBufferEmpty(); + + // Check unsuccessful deserialization of third parameter + U8 invalidData3[sizeof(U32) * 2]; + Fw::SerialBuffer invalidBuf3(invalidData3, sizeof(invalidData3)); + + status = invalidBuf3.serialize(port.args.u32); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = invalidBuf3.serialize(port.args.u32Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::PRIMITIVE, + invalidBuf3 + ); + + this->checkSerializeStatusBufferEmpty(); + + // Check unsuccessful deserialization of fourth parameter + U8 invalidData4[ + (sizeof(U32) * 2) + + sizeof(F32) + ]; + Fw::SerialBuffer invalidBuf4(invalidData4, sizeof(invalidData4)); + + status = invalidBuf4.serialize(port.args.u32); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = invalidBuf4.serialize(port.args.u32Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = invalidBuf4.serialize(port.args.f32); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::PRIMITIVE, + invalidBuf4 + ); + + this->checkSerializeStatusBufferEmpty(); + + // Check unsuccessful deserialization of fifth parameter + U8 invalidData5[ + (sizeof(U32) * 2) + + (sizeof(F32) * 2) + ]; + Fw::SerialBuffer invalidBuf5(invalidData5, sizeof(invalidData5)); + + status = invalidBuf5.serialize(port.args.u32); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = invalidBuf5.serialize(port.args.u32Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = invalidBuf5.serialize(port.args.f32); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = invalidBuf5.serialize(port.args.f32Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::PRIMITIVE, + invalidBuf5 + ); + + this->checkSerializeStatusBufferEmpty(); + + // Check unsuccessful deserialization of sixth parameter + U8 invalidData6[ + (sizeof(U32) * 2) + + (sizeof(F32) * 2) + + sizeof(U8) + ]; + Fw::SerialBuffer invalidBuf6(invalidData6, sizeof(invalidData6)); + + status = invalidBuf6.serialize(port.args.u32); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = invalidBuf6.serialize(port.args.u32Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = invalidBuf6.serialize(port.args.f32); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = invalidBuf6.serialize(port.args.f32Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = invalidBuf6.serialize(port.args.b); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::PRIMITIVE, + invalidBuf6 + ); + + this->checkSerializeStatusBufferEmpty(); + + // Check successful serialization + U8 data[InputPrimitiveArgsPort::SERIALIZED_SIZE]; + Fw::SerialBuffer buf(data, sizeof(data)); + + status = buf.serialize(port.args.u32); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = buf.serialize(port.args.u32Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = buf.serialize(port.args.f32); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = buf.serialize(port.args.f32Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = buf.serialize(port.args.b); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = buf.serialize(port.args.bRef); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::PRIMITIVE, + buf + ); + + this->checkSerializeStatusSuccess(); + } + + void Tester :: + invoke_serial( + NATIVE_INT_TYPE portNum, + FppTest::Port::StringArgsPort& port + ) + { + Fw::SerializeStatus status; + + // Check unsuccessful deserialization of first parameter + U8 invalidData1[0]; + Fw::SerialBuffer invalidBuf1(invalidData1, sizeof(invalidData1)); + + this->invoke_to_serialIn( + SerialPortIndex::STRING, + invalidBuf1 + ); + + this->checkSerializeStatusBufferEmpty(); + + // Check unsuccessful deserialization of second parameter + U8 invalidData2[StringArgsPortStrings::StringSize80::SERIALIZED_SIZE]; + Fw::SerialBuffer invalidBuf2(invalidData2, sizeof(invalidData2)); + + status = invalidBuf2.serialize(port.args.str80); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::STRING, + invalidBuf2 + ); + + this->checkSerializeStatusBufferEmpty(); + + // Check unsuccessful deserialization of third parameter + U8 invalidData3[StringArgsPortStrings::StringSize80::SERIALIZED_SIZE * 2]; + Fw::SerialBuffer invalidBuf3(invalidData3, sizeof(invalidData3)); + + status = invalidBuf3.serialize(port.args.str80); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = invalidBuf3.serialize(port.args.str80Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::STRING, + invalidBuf3 + ); + + this->checkSerializeStatusBufferEmpty(); + + // Check unsuccessful deserialization of fourth parameter + U8 invalidData4[ + (StringArgsPortStrings::StringSize80::SERIALIZED_SIZE * 2) + + StringArgsPortStrings::StringSize100::SERIALIZED_SIZE + ]; + Fw::SerialBuffer invalidBuf4(invalidData4, sizeof(invalidData4)); + + status = invalidBuf4.serialize(port.args.str80); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = invalidBuf4.serialize(port.args.str80Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = invalidBuf4.serialize(port.args.str100); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::STRING, + invalidBuf4 + ); + + this->checkSerializeStatusBufferEmpty(); + + // Check successful serialization + U8 data[InputStringArgsPort::SERIALIZED_SIZE]; + Fw::SerialBuffer buf(data, sizeof(data)); + + status = buf.serialize(port.args.str80); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = buf.serialize(port.args.str80Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = buf.serialize(port.args.str100); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = buf.serialize(port.args.str100Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::STRING, + buf + ); + + this->checkSerializeStatusSuccess(); + } + + void Tester :: + invoke_serial( + NATIVE_INT_TYPE portNum, + FppTest::Port::EnumArgsPort& port + ) + { + Fw::SerializeStatus status; + + // Check unsuccessful deserialization of first parameter + U8 invalidData1[0]; + Fw::SerialBuffer invalidBuf1(invalidData1, sizeof(invalidData1)); + + this->invoke_to_serialIn( + SerialPortIndex::ENUM, + invalidBuf1 + ); + + this->checkSerializeStatusBufferEmpty(); + + // Check unsuccessful deserialization of second parameter + U8 invalidData2[PortEnum::SERIALIZED_SIZE]; + Fw::SerialBuffer invalidBuf2(invalidData2, sizeof(invalidData2)); + + status = invalidBuf2.serialize(port.args.en); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::ENUM, + invalidBuf2 + ); + + this->checkSerializeStatusBufferEmpty(); + + // Check successful serialization + U8 data[InputEnumArgsPort::SERIALIZED_SIZE]; + Fw::SerialBuffer buf(data, sizeof(data)); + + status = buf.serialize(port.args.en); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = buf.serialize(port.args.enRef); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::ENUM, + buf + ); + + this->checkSerializeStatusSuccess(); + } + + void Tester :: + invoke_serial( + NATIVE_INT_TYPE portNum, + FppTest::Port::ArrayArgsPort& port + ) + { + Fw::SerializeStatus status; + + // Check unsuccessful deserialization of first parameter + U8 invalidData1[0]; + Fw::SerialBuffer invalidBuf1(invalidData1, sizeof(invalidData1)); + + this->invoke_to_serialIn( + SerialPortIndex::ARRAY, + invalidBuf1 + ); + + this->checkSerializeStatusBufferEmpty(); + + // Check unsuccessful deserialization of second parameter + U8 invalidData2[PortArray::SERIALIZED_SIZE]; + Fw::SerialBuffer invalidBuf2(invalidData2, sizeof(invalidData2)); + + status = invalidBuf2.serialize(port.args.a); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::ARRAY, + invalidBuf2 + ); + + this->checkSerializeStatusBufferEmpty(); + + U8 data[InputArrayArgsPort::SERIALIZED_SIZE]; + Fw::SerialBuffer buf(data, sizeof(data)); + + status = buf.serialize(port.args.a); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = buf.serialize(port.args.aRef); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::ARRAY, + buf + ); + + this->checkSerializeStatusSuccess(); + } + + void Tester :: + invoke_serial( + NATIVE_INT_TYPE portNum, + FppTest::Port::StructArgsPort& port + ) + { + Fw::SerializeStatus status; + + // Check unsuccessful deserialization of first parameter + U8 invalidData1[0]; + Fw::SerialBuffer invalidBuf1(invalidData1, sizeof(invalidData1)); + + this->invoke_to_serialIn( + SerialPortIndex::STRUCT, + invalidBuf1 + ); + + this->checkSerializeStatusBufferEmpty(); + + // Check unsuccessful deserialization of second parameter + U8 invalidData2[PortStruct::SERIALIZED_SIZE]; + Fw::SerialBuffer invalidBuf2(invalidData2, sizeof(invalidData2)); + + status = invalidBuf2.serialize(port.args.s); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::STRUCT, + invalidBuf2 + ); + + this->checkSerializeStatusBufferEmpty(); + + U8 data[InputStructArgsPort::SERIALIZED_SIZE]; + Fw::SerialBuffer buf(data, sizeof(data)); + + status = buf.serialize(port.args.s); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = buf.serialize(port.args.sRef); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + this->invoke_to_serialIn( + SerialPortIndex::STRUCT, + buf + ); + + this->checkSerializeStatusSuccess(); + } + + void Tester :: + invoke_serial( + NATIVE_INT_TYPE portNum, + FppTest::Port::SerialArgsPort& port + ) + { + this->invoke_to_serialIn( + portNum, + port.args.buf + ); + + ASSERT_EQ( + component.serializeStatus, + Fw::FW_SERIALIZE_OK + ); + } + + // ---------------------------------------------------------------------- + // Check history of typed output ports + // ---------------------------------------------------------------------- + + void Tester :: + check_history( + FppTest::Port::NoArgsPort& port + ) + { + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_noArgsOut_SIZE(1); + } + + void Tester :: + check_history( + FppTest::Port::PrimitiveArgsPort& port + ) + { + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_primitiveArgsOut_SIZE(1); + ASSERT_from_primitiveArgsOut( + 0, + port.args.u32, + port.args.u32Ref, + port.args.f32, + port.args.f32Ref, + port.args.b, + port.args.bRef + ); + } + + void Tester :: + check_history( + FppTest::Port::StringArgsPort& port + ) + { + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_stringArgsOut_SIZE(1); + ASSERT_from_stringArgsOut( + 0, + port.args.str80, + port.args.str80Ref, + port.args.str100, + port.args.str100Ref + ); + } + + void Tester :: + check_history( + FppTest::Port::EnumArgsPort& port + ) + { + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_enumArgsOut_SIZE(1); + ASSERT_from_enumArgsOut( + 0, + port.args.en, + port.args.enRef + ); + } + + void Tester :: + check_history( + FppTest::Port::ArrayArgsPort& port + ) + { + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_arrayArgsOut_SIZE(1); + ASSERT_from_arrayArgsOut( + 0, + port.args.a, + port.args.aRef + ); + } + + void Tester :: + check_history( + FppTest::Port::StructArgsPort& port + ) + { + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_structArgsOut_SIZE(1); + ASSERT_from_structArgsOut( + 0, + port.args.s, + port.args.sRef + ); + } + + void Tester :: + check_history( + FppTest::Port::NoArgsReturnPort& port + ) + { + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_noArgsReturnOut_SIZE(1); + } + + void Tester :: + check_history( + FppTest::Port::PrimitiveReturnPort& port + ) + { + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_primitiveReturnOut_SIZE(1); + ASSERT_from_primitiveReturnOut( + 0, + port.args.u32, + port.args.u32Ref, + port.args.f32, + port.args.f32Ref, + port.args.b, + port.args.bRef + ); + } + + void Tester :: + check_history( + FppTest::Port::EnumReturnPort& port + ) + { + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_enumReturnOut_SIZE(1); + ASSERT_from_enumReturnOut( + 0, + port.args.en, + port.args.enRef + ); + } + + void Tester :: + check_history( + FppTest::Port::ArrayReturnPort& port + ) + { + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_arrayReturnOut_SIZE(1); + ASSERT_from_arrayReturnOut( + 0, + port.args.a, + port.args.aRef + ); + } + + void Tester :: + check_history( + FppTest::Port::StructReturnPort& port + ) + { + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_structReturnOut_SIZE(1); + ASSERT_from_structReturnOut( + 0, + port.args.s, + port.args.sRef + ); + } + + // ---------------------------------------------------------------------- + // Check serial output ports + // ---------------------------------------------------------------------- + + void Tester :: + check_serial( + FppTest::Port::NoArgsPort& port + ) + { + } + + void Tester :: + check_serial( + FppTest::Port::PrimitiveArgsPort& port + ) + { + Fw::SerializeStatus status; + U32 u32, u32Ref; + F32 f32, f32Ref; + bool b, bRef; + + status = this->primitiveBuf.deserialize(u32); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = this->primitiveBuf.deserialize(u32Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = this->primitiveBuf.deserialize(f32); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = this->primitiveBuf.deserialize(f32Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = this->primitiveBuf.deserialize(b); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = this->primitiveBuf.deserialize(bRef); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + ASSERT_EQ(u32, port.args.u32); + ASSERT_EQ(u32Ref, port.args.u32Ref); + ASSERT_EQ(f32, port.args.f32); + ASSERT_EQ(f32Ref, port.args.f32Ref); + ASSERT_EQ(b, port.args.b); + ASSERT_EQ(bRef, port.args.bRef); + } + + void Tester :: + check_serial( + FppTest::Port::StringArgsPort& port + ) + { + Fw::SerializeStatus status; + StringArgsPortStrings::StringSize80 str80, str80Ref; + StringArgsPortStrings::StringSize100 str100, str100Ref; + + status = this->stringBuf.deserialize(str80); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = this->stringBuf.deserialize(str80Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = this->stringBuf.deserialize(str100); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = this->stringBuf.deserialize(str100Ref); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + ASSERT_EQ(str80, port.args.str80); + ASSERT_EQ(str80Ref, port.args.str80Ref); + ASSERT_EQ(str100, port.args.str100); + ASSERT_EQ(str100Ref, port.args.str100Ref); + } + + void Tester :: + check_serial( + FppTest::Port::EnumArgsPort& port + ) + { + Fw::SerializeStatus status; + PortEnum en, enRef; + + status = this->enumBuf.deserialize(en); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = this->enumBuf.deserialize(enRef); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + ASSERT_EQ(en, port.args.en); + ASSERT_EQ(enRef, port.args.enRef); + } + + void Tester :: + check_serial( + FppTest::Port::ArrayArgsPort& port + ) + { + Fw::SerializeStatus status; + PortArray a, aRef; + + status = this->arrayBuf.deserialize(a); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = this->arrayBuf.deserialize(aRef); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + ASSERT_EQ(a, port.args.a); + ASSERT_EQ(aRef, port.args.aRef); + } + + void Tester :: + check_serial( + FppTest::Port::StructArgsPort& port + ) + { + Fw::SerializeStatus status; + PortStruct s, sRef; + + status = this->structBuf.deserialize(s); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + status = this->structBuf.deserialize(sRef); + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + + ASSERT_EQ(s, port.args.s); + ASSERT_EQ(sRef, port.args.sRef); + } + + void Tester :: + check_serial( + FppTest::Port::SerialArgsPort& port + ) + { + ASSERT_EQ(this->serialBuf, port.args.buf); + } + + // ---------------------------------------------------------------------- + // Handlers for typed from ports + // ---------------------------------------------------------------------- + + void Tester :: + from_arrayArgsOut_handler( + const NATIVE_INT_TYPE portNum, + const PortArray &a, + PortArray &aRef + ) + { + this->pushFromPortEntry_arrayArgsOut(a, aRef); + } + + PortArray Tester :: + from_arrayReturnOut_handler( + const NATIVE_INT_TYPE portNum, + const PortArray &a, + PortArray &aRef + ) + { + this->pushFromPortEntry_arrayReturnOut(a, aRef); + + return this->arrayReturnVal.val; + } + + void Tester :: + from_enumArgsOut_handler( + const NATIVE_INT_TYPE portNum, + const PortEnum &en, + PortEnum &enRef + ) + { + this->pushFromPortEntry_enumArgsOut(en, enRef); + } + + PortEnum Tester :: + from_enumReturnOut_handler( + const NATIVE_INT_TYPE portNum, + const PortEnum &en, + PortEnum &enRef + ) + { + this->pushFromPortEntry_enumReturnOut(en, enRef); + + return this->enumReturnVal.val; + } + + void Tester :: + from_noArgsOut_handler( + const NATIVE_INT_TYPE portNum + ) + { + this->pushFromPortEntry_noArgsOut(); + } + + bool Tester :: + from_noArgsReturnOut_handler( + const NATIVE_INT_TYPE portNum + ) + { + this->pushFromPortEntry_noArgsReturnOut(); + + return this->noArgsReturnVal.val; + } + + void Tester :: + from_primitiveArgsOut_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + this->pushFromPortEntry_primitiveArgsOut(u32, u32Ref, f32, f32Ref, b, bRef); + } + + U32 Tester :: + from_primitiveReturnOut_handler( + const NATIVE_INT_TYPE portNum, + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ) + { + this->pushFromPortEntry_primitiveReturnOut(u32, u32Ref, f32, f32Ref, b, bRef); + + return this->primitiveReturnVal.val; + } + + void Tester :: + from_stringArgsOut_handler( + const NATIVE_INT_TYPE portNum, + const str80String &str80, + str80RefString &str80Ref, + const str100String &str100, + str100RefString &str100Ref + ) + { + this->pushFromPortEntry_stringArgsOut(str80, str80Ref, str100, str100Ref); + } + + void Tester :: + from_structArgsOut_handler( + const NATIVE_INT_TYPE portNum, + const PortStruct &s, + PortStruct &sRef + ) + { + this->pushFromPortEntry_structArgsOut(s, sRef); + } + + PortStruct Tester :: + from_structReturnOut_handler( + const NATIVE_INT_TYPE portNum, + const PortStruct &s, + PortStruct &sRef + ) + { + this->pushFromPortEntry_structReturnOut(s, sRef); + + return this->structReturnVal.val; + } + + // ---------------------------------------------------------------------- + // Handlers for serial from ports + // ---------------------------------------------------------------------- + + void Tester :: + from_serialOut_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ) + { + Fw::SerializeStatus status; + + switch (portNum) { + case SerialPortIndex::NO_ARGS: + status = Fw::FW_SERIALIZE_OK; + break; + + case SerialPortIndex::PRIMITIVE: + status = Buffer.copyRaw( + this->primitiveBuf, + Buffer.getBuffCapacity() + ); + break; + + case SerialPortIndex::STRING: + status = Buffer.copyRaw( + this->stringBuf, + Buffer.getBuffCapacity() + ); + break; + + case SerialPortIndex::ENUM: + status = Buffer.copyRaw( + this->enumBuf, + Buffer.getBuffCapacity() + ); + break; + + case SerialPortIndex::ARRAY: + status = Buffer.copyRaw( + this->arrayBuf, + Buffer.getBuffCapacity() + ); + break; + + case SerialPortIndex::STRUCT: + status = Buffer.copyRaw( + this->structBuf, + Buffer.getBuffCapacity() + ); + break; + + case SerialPortIndex::SERIAL: + status = Buffer.copyRaw( + this->serialBuf, + Buffer.getBuffCapacity() + ); + break; + } + + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + } + + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + void Tester :: + connectPorts() + { + + // arrayArgsIn + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_arrayArgsIn( + i, + this->component.get_arrayArgsIn_InputPort(i) + ); + } + + // arrayReturnIn + this->connect_to_arrayReturnIn( + 0, + this->component.get_arrayReturnIn_InputPort(0) + ); + + // enumArgsIn + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_enumArgsIn( + i, + this->component.get_enumArgsIn_InputPort(i) + ); + } + + // enumReturnIn + this->connect_to_enumReturnIn( + 0, + this->component.get_enumReturnIn_InputPort(0) + ); + + // noArgsIn + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_noArgsIn( + i, + this->component.get_noArgsIn_InputPort(i) + ); + } + + // noArgsReturnIn + this->connect_to_noArgsReturnIn( + 0, + this->component.get_noArgsReturnIn_InputPort(0) + ); + + // primitiveArgsIn + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_primitiveArgsIn( + i, + this->component.get_primitiveArgsIn_InputPort(i) + ); + } + + // primitiveReturnIn + this->connect_to_primitiveReturnIn( + 0, + this->component.get_primitiveReturnIn_InputPort(0) + ); + + // stringArgsIn + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_stringArgsIn( + i, + this->component.get_stringArgsIn_InputPort(i) + ); + } + + // structArgsIn + for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { + this->connect_to_structArgsIn( + i, + this->component.get_structArgsIn_InputPort(i) + ); + } + + // structReturnIn + this->connect_to_structReturnIn( + 0, + this->component.get_structReturnIn_InputPort(0) + ); + + // arrayArgsOut + this->component.set_arrayArgsOut_OutputPort( + TypedPortIndex::TYPED, + this->get_from_arrayArgsOut(TypedPortIndex::TYPED) + ); + + // arrayReturnOut + this->component.set_arrayReturnOut_OutputPort( + 0, + this->get_from_arrayReturnOut(0) + ); + + // enumArgsOut + this->component.set_enumArgsOut_OutputPort( + TypedPortIndex::TYPED, + this->get_from_enumArgsOut(TypedPortIndex::TYPED) + ); + + // enumReturnOut + this->component.set_enumReturnOut_OutputPort( + 0, + this->get_from_enumReturnOut(0) + ); + + // noArgsOut + this->component.set_noArgsOut_OutputPort( + TypedPortIndex::TYPED, + this->get_from_noArgsOut(TypedPortIndex::TYPED) + ); + + // noArgsReturnOut + this->component.set_noArgsReturnOut_OutputPort( + 0, + this->get_from_noArgsReturnOut(0) + ); + + // primitiveArgsOut + this->component.set_primitiveArgsOut_OutputPort( + TypedPortIndex::TYPED, + this->get_from_primitiveArgsOut(TypedPortIndex::TYPED) + ); + + // primitiveReturnOut + this->component.set_primitiveReturnOut_OutputPort( + 0, + this->get_from_primitiveReturnOut(0) + ); + + // stringArgsOut + this->component.set_stringArgsOut_OutputPort( + TypedPortIndex::TYPED, + this->get_from_stringArgsOut(TypedPortIndex::TYPED) + ); + + // structArgsOut + this->component.set_structArgsOut_OutputPort( + TypedPortIndex::TYPED, + this->get_from_structArgsOut(TypedPortIndex::TYPED) + ); + + // structReturnOut + this->component.set_structReturnOut_OutputPort( + 0, + this->get_from_structReturnOut(0) + ); + + + // ---------------------------------------------------------------------- + // Connect serial output ports + // ---------------------------------------------------------------------- + this->component.set_noArgsOut_OutputPort( + TypedPortIndex::SERIAL, + this->get_from_serialOut(SerialPortIndex::NO_ARGS) + ); + + this->component.set_primitiveArgsOut_OutputPort( + TypedPortIndex::SERIAL, + this->get_from_serialOut(SerialPortIndex::PRIMITIVE) + ); + + this->component.set_stringArgsOut_OutputPort( + TypedPortIndex::SERIAL, + this->get_from_serialOut(SerialPortIndex::STRING) + ); + + this->component.set_enumArgsOut_OutputPort( + TypedPortIndex::SERIAL, + this->get_from_serialOut(SerialPortIndex::ENUM) + ); + + this->component.set_arrayArgsOut_OutputPort( + TypedPortIndex::SERIAL, + this->get_from_serialOut(SerialPortIndex::ARRAY) + ); + + this->component.set_structArgsOut_OutputPort( + TypedPortIndex::SERIAL, + this->get_from_serialOut(SerialPortIndex::STRUCT) + ); + + this->component.set_serialOut_OutputPort( + SerialPortIndex::NO_ARGS, + this->get_from_noArgsOut(TypedPortIndex::SERIAL) + ); + + this->component.set_serialOut_OutputPort( + SerialPortIndex::PRIMITIVE, + this->get_from_primitiveArgsOut(TypedPortIndex::SERIAL) + ); + + this->component.set_serialOut_OutputPort( + SerialPortIndex::STRING, + this->get_from_stringArgsOut(TypedPortIndex::SERIAL) + ); + + this->component.set_serialOut_OutputPort( + SerialPortIndex::ENUM, + this->get_from_enumArgsOut(TypedPortIndex::SERIAL) + ); + + this->component.set_serialOut_OutputPort( + SerialPortIndex::ARRAY, + this->get_from_arrayArgsOut(TypedPortIndex::SERIAL) + ); + + this->component.set_serialOut_OutputPort( + SerialPortIndex::STRUCT, + this->get_from_structArgsOut(TypedPortIndex::SERIAL) + ); + + this->component.set_serialOut_OutputPort( + SerialPortIndex::SERIAL, + this->get_from_serialOut(SerialPortIndex::SERIAL) + ); + + + // ---------------------------------------------------------------------- + // Connect serial input ports + // ---------------------------------------------------------------------- + for (NATIVE_INT_TYPE i = 0; i < 7; ++i) { + this->connect_to_serialIn( + i, + this->component.get_serialIn_InputPort(i) + ); + } + + } + + void Tester :: + initComponents() + { + this->init(); + this->component.init( + INSTANCE + ); + } + + void Tester :: + checkSerializeStatusSuccess() + { + ASSERT_EQ( + component.serializeStatus, + Fw::FW_SERIALIZE_OK + ); + } + + void Tester :: + checkSerializeStatusBufferEmpty() + { + ASSERT_EQ( + component.serializeStatus, + Fw::FW_DESERIALIZE_BUFFER_EMPTY + ); + } + diff --git a/FppTest/port/test/ut/Tester.hpp b/FppTest/port/test/ut/Tester.hpp new file mode 100644 index 0000000000..c4a5d4548e --- /dev/null +++ b/FppTest/port/test/ut/Tester.hpp @@ -0,0 +1,432 @@ +// ====================================================================== +// \title Tester.hpp +// \author T. Chieu +// \brief hpp file for Example test harness implementation class +// ====================================================================== + +#ifndef TESTER_HPP +#define TESTER_HPP + +#include "Fw/Types/SerialBuffer.hpp" + +#include "GTestBase.hpp" +#include "FppTest/port/Example.hpp" +#include "PortTypes.hpp" + +#include "FppTest/port/PrimitiveArgsPortAc.hpp" +#include "FppTest/port/StringArgsPortAc.hpp" +#include "FppTest/port/EnumArgsPortAc.hpp" +#include "FppTest/port/ArrayArgsPortAc.hpp" +#include "FppTest/port/StructArgsPortAc.hpp" +#include "FppTest/port/TypedPortIndexEnumAc.hpp" +#include "FppTest/port/SerialPortIndexEnumAc.hpp" + + class Tester : + public ExampleGTestBase + { + + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + public: + + //! Construct object Tester + //! + Tester(); + + //! Destroy object Tester + //! + ~Tester(); + + public: + + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! To do + //! + void toDo(); + + public: + + // ---------------------------------------------------------------------- + // Invoke typed input ports + // ---------------------------------------------------------------------- + + void invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::NoArgsPort& port + ); + + void invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::PrimitiveArgsPort& port + ); + + void invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::StringArgsPort& port + ); + + void invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::EnumArgsPort& port + ); + + void invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::ArrayArgsPort& port + ); + + void invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::StructArgsPort& port + ); + + void invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::SerialArgsPort& port + ); + + void invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::NoArgsReturnPort& port + ); + + void invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::PrimitiveReturnPort& port + ); + + void invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::EnumReturnPort& port + ); + + void invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::ArrayReturnPort& port + ); + + void invoke( + NATIVE_INT_TYPE portNum, + FppTest::Port::StructReturnPort& port + ); + + // ---------------------------------------------------------------------- + // Invoke serial input ports + // ---------------------------------------------------------------------- + + void invoke_serial( + NATIVE_INT_TYPE portNum, + FppTest::Port::NoArgsPort& port + ); + + void invoke_serial( + NATIVE_INT_TYPE portNum, + FppTest::Port::PrimitiveArgsPort& port + ); + + void invoke_serial( + NATIVE_INT_TYPE portNum, + FppTest::Port::StringArgsPort& port + ); + + void invoke_serial( + NATIVE_INT_TYPE portNum, + FppTest::Port::EnumArgsPort& port + ); + + void invoke_serial( + NATIVE_INT_TYPE portNum, + FppTest::Port::ArrayArgsPort& port + ); + + void invoke_serial( + NATIVE_INT_TYPE portNum, + FppTest::Port::StructArgsPort& port + ); + + void invoke_serial( + NATIVE_INT_TYPE portNum, + FppTest::Port::SerialArgsPort& port + ); + + // ---------------------------------------------------------------------- + // Check history of typed output ports + // ---------------------------------------------------------------------- + + void check_history( + FppTest::Port::NoArgsPort& port + ); + + void check_history( + FppTest::Port::PrimitiveArgsPort& port + ); + + void check_history( + FppTest::Port::StringArgsPort& port + ); + + void check_history( + FppTest::Port::EnumArgsPort& port + ); + + void check_history( + FppTest::Port::ArrayArgsPort& port + ); + + void check_history( + FppTest::Port::StructArgsPort& port + ); + + void check_history( + FppTest::Port::NoArgsReturnPort& port + ); + + void check_history( + FppTest::Port::PrimitiveReturnPort& port + ); + + void check_history( + FppTest::Port::EnumReturnPort& port + ); + + void check_history( + FppTest::Port::ArrayReturnPort& port + ); + + void check_history( + FppTest::Port::StructReturnPort& port + ); + + // ---------------------------------------------------------------------- + // Check serial output ports + // ---------------------------------------------------------------------- + + void check_serial( + FppTest::Port::NoArgsPort& port + ); + + void check_serial( + FppTest::Port::PrimitiveArgsPort& port + ); + + void check_serial( + FppTest::Port::StringArgsPort& port + ); + + void check_serial( + FppTest::Port::EnumArgsPort& port + ); + + void check_serial( + FppTest::Port::ArrayArgsPort& port + ); + + void check_serial( + FppTest::Port::StructArgsPort& port + ); + + void check_serial( + FppTest::Port::SerialArgsPort& port + ); + + private: + + // ---------------------------------------------------------------------- + // Handlers for typed from ports + // ---------------------------------------------------------------------- + + //! Handler for from_arrayArgsOut + //! + void from_arrayArgsOut_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const PortArray &a, /*!< + An array + */ + PortArray &aRef /*!< + An array ref + */ + ); + + //! Handler for from_arrayReturnOut + //! + PortArray from_arrayReturnOut_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const PortArray &a, /*!< + An array + */ + PortArray &aRef /*!< + An array ref + */ + ); + + //! Handler for from_enumArgsOut + //! + void from_enumArgsOut_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const PortEnum &en, /*!< + An enum + */ + PortEnum &enRef /*!< + An enum ref + */ + ); + + //! Handler for from_enumReturnOut + //! + PortEnum from_enumReturnOut_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const PortEnum &en, /*!< + An enum + */ + PortEnum &enRef /*!< + An enum ref + */ + ); + + //! Handler for from_noArgsOut + //! + void from_noArgsOut_handler( + const NATIVE_INT_TYPE portNum /*!< The port number*/ + ); + + //! Handler for from_noArgsReturnOut + //! + bool from_noArgsReturnOut_handler( + const NATIVE_INT_TYPE portNum /*!< The port number*/ + ); + + //! Handler for from_primitiveArgsOut + //! + void from_primitiveArgsOut_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ); + + //! Handler for from_primitiveReturnOut + //! + U32 from_primitiveReturnOut_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + U32 u32, + U32 &u32Ref, + F32 f32, + F32 &f32Ref, + bool b, + bool &bRef + ); + + //! Handler for from_stringArgsOut + //! + void from_stringArgsOut_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const str80String &str80, /*!< + A string of size 80 + */ + str80RefString &str80Ref, + const str100String &str100, /*!< + A string of size 100 + */ + str100RefString &str100Ref + ); + + //! Handler for from_structArgsOut + //! + void from_structArgsOut_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const PortStruct &s, /*!< + A struct + */ + PortStruct &sRef /*!< + A struct ref + */ + ); + + //! Handler for from_structReturnOut + //! + PortStruct from_structReturnOut_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + const PortStruct &s, /*!< + A struct + */ + PortStruct &sRef /*!< + A struct ref + */ + ); + + private: + + // ---------------------------------------------------------------------- + // Handlers for serial from ports + // ---------------------------------------------------------------------- + + //! Handler for from_serialOut + //! + void from_serialOut_handler( + NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ + ); + + private: + + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + //! Connect ports + //! + void connectPorts(); + + //! Initialize components + //! + void initComponents(); + + //! Check successful status of a serial port invocation + void checkSerializeStatusSuccess(); + + //! Check unsuccessful status of a serial port invocation + void checkSerializeStatusBufferEmpty(); + + private: + + // ---------------------------------------------------------------------- + // Variables + // ---------------------------------------------------------------------- + + //! The component under test + //! + Example component; + + // Values returned by typed output ports + FppTest::Port::BoolReturn noArgsReturnVal; + FppTest::Port::PrimitiveReturn primitiveReturnVal; + FppTest::Port::EnumReturn enumReturnVal; + FppTest::Port::ArrayReturn arrayReturnVal; + FppTest::Port::StructReturn structReturnVal; + + // Buffers from serial output ports; + U8 primitiveData[InputPrimitiveArgsPort::SERIALIZED_SIZE]; + U8 stringData[InputStringArgsPort::SERIALIZED_SIZE]; + U8 enumData[InputEnumArgsPort::SERIALIZED_SIZE]; + U8 arrayData[InputArrayArgsPort::SERIALIZED_SIZE]; + U8 structData[InputStructArgsPort::SERIALIZED_SIZE]; + U8 serialData[SERIAL_ARGS_BUFFER_CAPACITY]; + + Fw::SerialBuffer primitiveBuf; + Fw::SerialBuffer stringBuf; + Fw::SerialBuffer enumBuf; + Fw::SerialBuffer arrayBuf; + Fw::SerialBuffer structBuf; + Fw::SerialBuffer serialBuf; + + }; + +#endif diff --git a/FppTest/source.cpp b/FppTest/source.cpp new file mode 100644 index 0000000000..20844df592 --- /dev/null +++ b/FppTest/source.cpp @@ -0,0 +1 @@ +// Empty source file so that SOURCES for target FppTest is not empty diff --git a/FppTest/struct/CMakeLists.txt b/FppTest/struct/CMakeLists.txt new file mode 100644 index 0000000000..8602f311ea --- /dev/null +++ b/FppTest/struct/CMakeLists.txt @@ -0,0 +1,25 @@ +# ====================================================================== +# CMakeLists.txt +# ====================================================================== + +# We need to declare the XML source files this way to invoke the autocoder. +# However, only the UT build is allowed here. +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/struct.fpp" +) +register_fprime_module() + +# Declare dependencies on test modules +set(UT_MOD_DEPS + Fw/Test + STest +) + +# List all .cpp files as UT_SOURCE_FILES. Only the UT build is allowed. +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/PrimitiveStructTest.cpp" + "${CMAKE_CURRENT_LIST_DIR}/NonPrimitiveStructTest.cpp" + "${CMAKE_CURRENT_LIST_DIR}/../utils/Utils.cpp" + "${CMAKE_CURRENT_LIST_DIR}/main.cpp" +) +register_fprime_ut() diff --git a/FppTest/struct/NonPrimitiveStructTest.cpp b/FppTest/struct/NonPrimitiveStructTest.cpp new file mode 100644 index 0000000000..508126b4f1 --- /dev/null +++ b/FppTest/struct/NonPrimitiveStructTest.cpp @@ -0,0 +1,332 @@ +// ====================================================================== +// \title NonPrimitiveStructTest.cpp +// \author T. Chieu +// \brief cpp file for NonPrimitiveStructTest class +// +// \copyright +// Copyright (C) 2009-2022 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "FppTest/struct/NonPrimitiveSerializableAc.hpp" +#include "FppTest/utils/Utils.hpp" + +#include "Fw/Types/SerialBuffer.hpp" +#include "Fw/Types/StringUtils.hpp" +#include "STest/Pick/Pick.hpp" + +#include "gtest/gtest.h" + +#include + +// Test NonPrimitive struct class +class NonPrimitiveStructTest : public ::testing::Test { +protected: + void SetUp() override { + char buf[testString.getCapacity()]; + FppTest::Utils::setString(buf, sizeof(buf)); + testString = buf; + + testEnum = static_cast(STest::Pick::startLength( + StructEnum::A, + StructEnum::B + )); + + for (U32 i = 0; i < StructArray::SIZE; i++) { + testArray[i] = FppTest::Utils::getU32(); + } + + testStruct.set( + true, + FppTest::Utils::getU32(), + static_cast(FppTest::Utils::getU32()), + static_cast(FppTest::Utils::getU32()) + ); + + for (U32 i = 0; i < 3; i++) { + testU32Arr[0] = FppTest::Utils::getU32(); + } + + for (U32 i = 0; i < 3; i++) { + testStructArr[i].set( + true, + FppTest::Utils::getU32(), + static_cast(FppTest::Utils::getU32()), + static_cast(FppTest::Utils::getU32()) + ); + } + } + + void assertStructMembers(const NonPrimitive& s) { + ASSERT_EQ(s.getmString(), testString); + ASSERT_EQ(s.getmEnum(), testEnum); + ASSERT_EQ(s.getmArray(), testArray); + ASSERT_EQ(s.getmStruct(), testStruct); + + for (U32 i = 0; i < 3; i++) { + ASSERT_EQ(s.getmU32Arr()[i], testU32Arr[i]); + } + for (U32 i = 0; i < 3; i++) { + ASSERT_EQ(s.getmStructArr()[i], testStructArr[i]); + } + } + + void assertUnsuccessfulSerialization(NonPrimitive& s, U32 bufSize) { + U8 data[bufSize]; + Fw::SerialBuffer buf(data, sizeof(data)); + Fw::SerializeStatus status; + + // Serialize + status = buf.serialize(s); + ASSERT_NE(status, Fw::FW_SERIALIZE_OK); + + // Deserialize + status = buf.deserialize(s); + ASSERT_NE(status, Fw::FW_SERIALIZE_OK); + } + + NonPrimitive::StringSize80 testString; + StructEnum testEnum; + StructArray testArray; + Primitive testStruct; + U32 testU32Arr[3]; + Primitive testStructArr[3]; +}; + +// Test struct constants and default constructor +TEST_F(NonPrimitiveStructTest, Default) { + NonPrimitive s; + + StructArray defaultArray; + Primitive defaultStruct1(true, 0, 0, 3.14); + Primitive defaultStruct2(true, 0, 0, 1.16); + + // Constants + ASSERT_EQ( + NonPrimitive::SERIALIZED_SIZE, + NonPrimitive::StringSize80::SERIALIZED_SIZE + + StructEnum::SERIALIZED_SIZE + + StructArray::SERIALIZED_SIZE + + Primitive::SERIALIZED_SIZE + + (3 * sizeof(U32)) + + (3 * Primitive::SERIALIZED_SIZE) + ); + + // Default constructor + ASSERT_EQ(s.getmString(), ""); + ASSERT_EQ(s.getmEnum(), StructEnum::C); + ASSERT_EQ(s.getmArray(), defaultArray); + ASSERT_EQ(s.getmStruct(), defaultStruct1); + + for (U32 i = 0; i < 3; i++) { + ASSERT_EQ(s.getmU32Arr()[i], 0); + } + for (U32 i = 0; i < 3; i++) { + ASSERT_EQ(s.getmStructArr()[i], defaultStruct2); + } +} + +// Test struct constructors +TEST_F(NonPrimitiveStructTest, Constructors) { + // Member constructor + NonPrimitive s1(testString, testEnum, testArray, + testStruct, testU32Arr, testStructArr); + assertStructMembers(s1); + + // Scalar member constructor + NonPrimitive s2(testString, testEnum, testArray, + testStruct, testU32Arr[0], testStructArr[0]); + + ASSERT_EQ(s2.getmString(), testString); + ASSERT_EQ(s2.getmEnum(), testEnum); + ASSERT_EQ(s2.getmArray(), testArray); + ASSERT_EQ(s2.getmStruct(), testStruct); + + for (U32 i = 0; i < 3; i++) { + ASSERT_EQ(s2.getmU32Arr()[i], testU32Arr[0]); + } + for (U32 i = 0; i < 3; i++) { + ASSERT_EQ(s2.getmStructArr()[i], testStructArr[0]); + } + + // Copy constructor + NonPrimitive s3(s1); + assertStructMembers(s3); +} + +// Test struct assignment operator +TEST_F(NonPrimitiveStructTest, AssignmentOp) { + NonPrimitive s1; + NonPrimitive s2(testString, testEnum, testArray, + testStruct, testU32Arr, testStructArr); + + // Copy assignment + s1 = s2; + assertStructMembers(s1); + + NonPrimitive& s1Ref = s1; + s1 = s1Ref; + ASSERT_EQ(&s1, &s1Ref); +} + +// Test struct equality and inequality operators +TEST_F(NonPrimitiveStructTest, EqualityOp) { + NonPrimitive s1, s2; + + ASSERT_TRUE(s1 == s2); + ASSERT_FALSE(s1 != s2); + + s1.setmString(testString); + + ASSERT_FALSE(s1 == s2); + ASSERT_TRUE(s1 != s2); + + s2.setmString(testString); + s1.setmEnum(testEnum); + + ASSERT_NE(s1, s2); + ASSERT_FALSE(s1 == s2); + ASSERT_TRUE(s1 != s2); + + s2.setmEnum(testEnum); + s1.setmArray(testArray); + + ASSERT_FALSE(s1 == s2); + ASSERT_TRUE(s1 != s2); + + s2.setmArray(testArray); + s1.setmStruct(testStruct); + + ASSERT_FALSE(s1 == s2); + ASSERT_TRUE(s1 != s2); + + s2.setmStruct(testStruct); + s1.setmU32Arr(testU32Arr); + + ASSERT_FALSE(s1 == s2); + ASSERT_TRUE(s1 != s2); + + s2.setmU32Arr(testU32Arr); + s1.setmStructArr(testStructArr); + + ASSERT_FALSE(s1 == s2); + ASSERT_TRUE(s1 != s2); + + s2.setmStructArr(testStructArr); + + ASSERT_TRUE(s1 == s2); + ASSERT_FALSE(s1 != s2); +} + +// Test struct getter and setter functions +TEST_F(NonPrimitiveStructTest, GetterSetterFunctions) { + NonPrimitive s1, s2; + + // Set all members + s1.set(testString, testEnum, testArray, + testStruct, testU32Arr, testStructArr); + assertStructMembers(s1); + + // Set individual members + s2.setmString(testString); + ASSERT_EQ(s2.getmString(), testString); + + s2.setmEnum(testEnum); + ASSERT_EQ(s2.getmEnum(), testEnum); + + s2.setmArray(testArray); + ASSERT_EQ(s2.getmArray(), testArray); + + s2.setmStruct(testStruct); + ASSERT_EQ(s2.getmStruct(), testStruct); + + s2.setmU32Arr(testU32Arr); + for (U32 i = 0; i < 3; i++) { + ASSERT_EQ(s2.getmU32Arr()[i], testU32Arr[i]); + } + + s2.setmStructArr(testStructArr); + for (U32 i = 0; i < 3; i++) { + ASSERT_EQ(s2.getmStructArr()[i], testStructArr[i]); + } + + // Check non-const getter + s2.getmStruct().setmU32(testU32Arr[0]); + ASSERT_EQ(s2.getmStruct().getmU32(), testU32Arr[0]); +} + +// Test struct serialization and deserialization +TEST_F(NonPrimitiveStructTest, Serialization) { + NonPrimitive s(testString, testEnum, testArray, + testStruct, testU32Arr, testStructArr); + NonPrimitive sCopy; + + U32 stringSerializedSize = testString.length() + sizeof(FwBuffSizeType); + U32 serializedSize = NonPrimitive::SERIALIZED_SIZE + - NonPrimitive::StringSize80::SERIALIZED_SIZE + + stringSerializedSize; + Fw::SerializeStatus status; + + // Test successful serialization + U8 data[NonPrimitive::SERIALIZED_SIZE]; + Fw::SerialBuffer buf(data, sizeof(data)); + + // Serialize + status = buf.serialize(s); + + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buf.getBuffLength(), serializedSize); + + // Deserialize + status = buf.deserialize(sCopy); + + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + ASSERT_EQ(s, sCopy); + + // Test unsuccessful serialization + assertUnsuccessfulSerialization(s, stringSerializedSize - 1); + assertUnsuccessfulSerialization(s, stringSerializedSize + + StructEnum::SERIALIZED_SIZE - 1); + assertUnsuccessfulSerialization(s, stringSerializedSize + + StructEnum::SERIALIZED_SIZE + StructArray::SERIALIZED_SIZE - 1); + assertUnsuccessfulSerialization(s, stringSerializedSize + + StructEnum::SERIALIZED_SIZE + StructArray::SERIALIZED_SIZE + + Primitive::SERIALIZED_SIZE - 1); + assertUnsuccessfulSerialization(s, stringSerializedSize + + StructEnum::SERIALIZED_SIZE + StructArray::SERIALIZED_SIZE + + Primitive::SERIALIZED_SIZE + (3 * sizeof(U32)) - 1); + assertUnsuccessfulSerialization(s, serializedSize - 1); +} + +// Test struct toString() and ostream operator functions +TEST_F(NonPrimitiveStructTest, ToString) { + NonPrimitive s(testString, testEnum, testArray, + testStruct, testU32Arr, testStructArr); + std::stringstream buf1, buf2; + + buf1 << s; + + buf2 << "( " + << "mString = " << testString << ", " + << "mEnum = " << testEnum << ", " + << "mArray = " << testArray << ", " + << "mStruct = " << testStruct << ", " + << "mU32Arr = [ " + << testU32Arr[0] << ", " + << testU32Arr[1] << ", " + << testU32Arr[2] << " ], " + << "mStructArr = [ " + << testStructArr[0] << ", " + << testStructArr[1] << ", " + << testStructArr[2] << " ] " + << " )"; + + // Truncate string output + char buf2Str[FW_SERIALIZABLE_TO_STRING_BUFFER_SIZE]; + Fw::StringUtils::string_copy(buf2Str, buf2.str().c_str(), + FW_SERIALIZABLE_TO_STRING_BUFFER_SIZE); + + ASSERT_STREQ(buf1.str().c_str(), buf2Str); +} diff --git a/FppTest/struct/PrimitiveStructTest.cpp b/FppTest/struct/PrimitiveStructTest.cpp new file mode 100644 index 0000000000..c9e539b8e8 --- /dev/null +++ b/FppTest/struct/PrimitiveStructTest.cpp @@ -0,0 +1,215 @@ +// ====================================================================== +// \title PrimitiveStructTest.cpp +// \author T. Chieu +// \brief cpp file for PrimitiveStructTest class +// +// \copyright +// Copyright (C) 2009-2022 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "FppTest/struct/PrimitiveSerializableAc.hpp" +#include "FppTest/utils/Utils.hpp" + +#include "Fw/Types/SerialBuffer.hpp" +#include "Fw/Types/StringUtils.hpp" +#include "STest/Pick/Pick.hpp" + +#include "gtest/gtest.h" + +#include + +// Test Primitive struct class +class PrimitiveStructTest : public ::testing::Test { +protected: + void SetUp() override { + testBool = true; + testU32 = FppTest::Utils::getU32(); + testI16 = static_cast(FppTest::Utils::getU32()); + testF64 = static_cast(FppTest::Utils::getU32()); + } + + void assertStructMembers(const Primitive& s) { + ASSERT_EQ(s.getmBool(), testBool); + ASSERT_EQ(s.getmU32(), testU32); + ASSERT_EQ(s.getmI16(), testI16); + ASSERT_EQ(s.getmF64(), testF64); + } + + void assertUnsuccessfulSerialization(Primitive& s, U32 bufSize) { + U8 data[bufSize]; + Fw::SerialBuffer buf(data, sizeof(data)); + Fw::SerializeStatus status; + + // Serialize + status = buf.serialize(s); + ASSERT_NE(status, Fw::FW_SERIALIZE_OK); + + // Deserialize + status = buf.deserialize(s); + ASSERT_NE(status, Fw::FW_SERIALIZE_OK); + } + + bool testBool; + U32 testU32; + I16 testI16; + F64 testF64; +}; + +// Test struct constants and default constructor +TEST_F(PrimitiveStructTest, Default) { + Primitive s; + + // Constants + ASSERT_EQ( + Primitive::SERIALIZED_SIZE, + sizeof(U8) + + sizeof(U32) + + sizeof(I16) + + sizeof(F64) + ); + + // Default constructor + ASSERT_EQ(s.getmBool(), false); + ASSERT_EQ(s.getmU32(), 0); + ASSERT_EQ(s.getmI16(), 0); + ASSERT_EQ(s.getmF64(), 0.0); +} + +// Test struct constructors +TEST_F(PrimitiveStructTest, Constructors) { + // Member constructor + Primitive s1(testBool, testU32, testI16, testF64); + assertStructMembers(s1); + + // Copy constructor + Primitive s2(s1); + assertStructMembers(s2); +} + +// Test struct assignment operator +TEST_F(PrimitiveStructTest, AssignmentOp) { + Primitive s1; + Primitive s2(testBool, testU32, testI16, testF64); + + // Copy assignment + s1 = s2; + assertStructMembers(s1); + + Primitive& s1Ref = s1; + s1 = s1Ref; + ASSERT_EQ(&s1, &s1Ref); +} + +// Test struct equality and inequality operators +TEST_F(PrimitiveStructTest, EqualityOp) { + Primitive s1, s2; + + ASSERT_TRUE(s1 == s2); + ASSERT_FALSE(s1 != s2); + + s1.setmBool(testBool); + + ASSERT_FALSE(s1 == s2); + ASSERT_TRUE(s1 != s2); + + s2.setmBool(testBool); + s1.setmU32(testU32); + + ASSERT_FALSE(s1 == s2); + ASSERT_TRUE(s1 != s2); + + s2.setmU32(testU32); + s1.setmI16(testI16); + + ASSERT_FALSE(s1 == s2); + ASSERT_TRUE(s1 != s2); + + s2.setmI16(testI16); + s1.setmF64(testF64); + + ASSERT_FALSE(s1 == s2); + ASSERT_TRUE(s1 != s2); + + s2.setmF64(testF64); + + ASSERT_TRUE(s1 == s2); + ASSERT_FALSE(s1 != s2); +} + +// Test struct getter and setter functions +TEST_F(PrimitiveStructTest, GetterSetterFunctions) { + Primitive s1, s2; + + // Set all members + s1.set(testBool, testU32, testI16, testF64); + assertStructMembers(s1); + + // Set individual members + s2.setmBool(testBool); + ASSERT_EQ(s2.getmBool(), testBool); + + s2.setmU32(testU32); + ASSERT_EQ(s2.getmU32(), testU32); + + s2.setmI16(testI16); + ASSERT_EQ(s2.getmI16(), testI16); + + s2.setmF64(testF64); + ASSERT_EQ(s2.getmF64(), testF64); +} + +// Test struct serialization and deserialization +TEST_F(PrimitiveStructTest, Serialization) { + Primitive s(testBool, testU32, testI16, testF64); + Primitive sCopy; + + Fw::SerializeStatus status; + + // Test successful serialization + U8 data[Primitive::SERIALIZED_SIZE]; + Fw::SerialBuffer buf(data, sizeof(data)); + + // Serialize + status = buf.serialize(s); + + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buf.getBuffLength(), Primitive::SERIALIZED_SIZE); + + // Deserialize + status = buf.deserialize(sCopy); + + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + ASSERT_EQ(s, sCopy); + + // Test unsuccessful serialization + assertUnsuccessfulSerialization(s, sizeof(U8) - 1); + assertUnsuccessfulSerialization(s, sizeof(U8) + sizeof(U32) - 1); + assertUnsuccessfulSerialization(s, sizeof(U8) + sizeof(U32) + + sizeof(I16) - 1); + assertUnsuccessfulSerialization(s, Primitive::SERIALIZED_SIZE - 1); +} + +// Test struct toString() and ostream operator functions +TEST_F(PrimitiveStructTest, ToString) { + Primitive s(testBool, testU32, testI16, testF64); + std::stringstream buf1, buf2; + + buf1 << s; + + buf2 << "( " + << "mBool = " << testBool << ", " + << "mU32 = " << testU32 << ", " + << "mI16 = " << testI16 << ", " + << "mF64 = " << std::fixed << testF64 + << " )"; + + // Truncate string output + char buf2Str[FW_SERIALIZABLE_TO_STRING_BUFFER_SIZE]; + Fw::StringUtils::string_copy(buf2Str, buf2.str().c_str(), + FW_SERIALIZABLE_TO_STRING_BUFFER_SIZE); + + ASSERT_STREQ(buf1.str().c_str(), buf2Str); +} diff --git a/FppTest/struct/README.md b/FppTest/struct/README.md new file mode 100644 index 0000000000..42d4ca4bb9 --- /dev/null +++ b/FppTest/struct/README.md @@ -0,0 +1,9 @@ +# FppTest/struct + +This directory contains unit tests for the FPP struct code generator. + +To use this directory, you must have installed F Prime, and you must be inside +the F Prime Python virtual environment. + +* To build the tests, run `fprime-util build --ut`. +* To run the tests, run `fprime-util check`. diff --git a/FppTest/struct/main.cpp b/FppTest/struct/main.cpp new file mode 100644 index 0000000000..60a72d7d63 --- /dev/null +++ b/FppTest/struct/main.cpp @@ -0,0 +1,44 @@ +// ====================================================================== +// \title main.cpp +// \author T. Chieu +// \brief main cpp file for FPP struct tests +// +// \copyright +// Copyright (C) 2009-2022 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "FppTest/struct/NonPrimitiveSerializableAc.hpp" +#include "FppTest/struct/MultiStringSerializableAc.hpp" +#include "FppTest/typed_tests/StringTest.hpp" + +#include "STest/Random/Random.hpp" +#include "gtest/gtest.h" + +// Instantiate string tests for structs +using StringTestImplementations = ::testing::Types< + NonPrimitive::StringSize80, + MultiString::StringSize50, + MultiString::StringSize60, + MultiString::StringSize80 +>; +INSTANTIATE_TYPED_TEST_SUITE_P(Struct, StringTest, StringTestImplementations); + +template<> +U32 FppTest::String::getSize() { + return 50; +} + +template<> +U32 FppTest::String::getSize() { + return 60; +} + +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + STest::Random::seed(); + + return RUN_ALL_TESTS(); +} diff --git a/FppTest/struct/struct.fpp b/FppTest/struct/struct.fpp new file mode 100644 index 0000000000..e64d927777 --- /dev/null +++ b/FppTest/struct/struct.fpp @@ -0,0 +1,31 @@ +enum StructEnum { A, B, C } +array StructArray = [3] U32 + +struct Primitive { + mBool: bool + mU32: U32 + mI16: I16 + mF64: F64 +} + +struct NonPrimitive { + mString: string + mEnum: StructEnum + mArray: StructArray + mStruct: Primitive + mU32Arr: [3] U32 + mStructArr: [3] Primitive +} default { + mEnum = StructEnum.C + mStruct = { mBool = true, mF64 = 3.14 } + mStructArr = { mBool = true, mF64 = 1.16 } +} + +struct MultiString { + mStr_1: string + mStr_2: string + mStr50_1: string size 50 + mStr50_2: string size 50 + mStrArr_1: [3] string size 60 + mStrArr_2: [3] string size 60 +} diff --git a/FppTest/typed_tests/ArrayTest.hpp b/FppTest/typed_tests/ArrayTest.hpp new file mode 100644 index 0000000000..12cea993ad --- /dev/null +++ b/FppTest/typed_tests/ArrayTest.hpp @@ -0,0 +1,237 @@ +// ====================================================================== +// \title ArrayTest.hpp +// \author T. Chieu +// \brief hpp file for ArrayTest class +// +// \copyright +// Copyright (C) 2009-2022 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#ifndef FPP_TEST_ARRAY_TEST_HPP +#define FPP_TEST_ARRAY_TEST_HPP + +#include "Fw/Types/SerialBuffer.hpp" + +#include "STest/Pick/Pick.hpp" +#include "gtest/gtest.h" + +#include + +namespace FppTest { + + namespace Array { + + // Set default values for an array type + template + void setDefaultVals + (typename ArrayType::ElementType (&a)[ArrayType::SIZE]) {} + + // Set test values for an array type + template + void setTestVals + (typename ArrayType::ElementType (&a)[ArrayType::SIZE]); + + template + ArrayType getMultiElementConstructedArray + (typename ArrayType::ElementType (&a)[ArrayType::SIZE]); + + // Get the serialized size of an array + template + U32 getSerializedSize + (typename ArrayType::ElementType (&a)[ArrayType::SIZE]) { + return ArrayType::SERIALIZED_SIZE; + } + + } // namespace Array + +} // namespace FppTest + +// Test an array class +template +class ArrayTest : public ::testing::Test { +protected: + void SetUp() override { + FppTest::Array::setDefaultVals(defaultVals); + + FppTest::Array::setTestVals(testVals); + ASSERT_FALSE(valsAreEqual()); + }; + + bool valsAreEqual() { + for (U32 i = 0; i < ArrayType::SIZE; i++) { + if (defaultVals[i] != testVals[i]) { + return false; + } + } + + return true; + } + + typename ArrayType::ElementType defaultVals[ArrayType::SIZE]; + typename ArrayType::ElementType testVals[ArrayType::SIZE]; +}; + +TYPED_TEST_SUITE_P(ArrayTest); + +// Test array constants and default constructor +TYPED_TEST_P(ArrayTest, Default) { + TypeParam a; + + // Constants + ASSERT_EQ(TypeParam::SIZE, 3); + ASSERT_EQ( + TypeParam::SERIALIZED_SIZE, + TypeParam::SIZE * TypeParam::ElementType::SERIALIZED_SIZE + ); + + // Default constructor + for (U32 i = 0; i < TypeParam::SIZE; i++) { + ASSERT_EQ(a[i], this->defaultVals[i]); + } +} + +// Test array constructors +TYPED_TEST_P(ArrayTest, Constructors) { + // Array constructor + TypeParam a1(this->testVals); + for (U32 i = 0; i < TypeParam::SIZE; i++) { + ASSERT_EQ(a1[i], this->testVals[i]); + } + + // Single element constructor + TypeParam a2(this->testVals[0]); + for (U32 i = 0; i < TypeParam::SIZE; i++) { + ASSERT_EQ(a2[i], this->testVals[0]); + } + + // Multiple element constructor + TypeParam a3 = FppTest::Array::getMultiElementConstructedArray + (this->testVals); + for (U32 i = 0; i < TypeParam::SIZE; i++) { + ASSERT_EQ(a3[i], this->testVals[i]); + } + + // Copy constructor + TypeParam a4(a1); + for (U32 i = 0; i < TypeParam::SIZE; i++) { + ASSERT_EQ(a4[i], a1[i]); + } +} + +// Test array subscript operator +TYPED_TEST_P(ArrayTest, SubscriptOp) { + TypeParam a; + + for (U32 i = 0; i < TypeParam::SIZE; i++) { + a[i] = this->testVals[0]; + ASSERT_EQ(a[i], this->testVals[0]); + } +} + +// Test array assignment operator +TYPED_TEST_P(ArrayTest, AssignmentOp) { + TypeParam a1, a2; + + // Array assignment + a1 = this->testVals; + for (U32 i = 0; i < TypeParam::SIZE; i++) { + ASSERT_EQ(a1[i], this->testVals[i]); + } + + // Copy assignment + TypeParam& a1Ref = a1; + a1 = a1Ref; + ASSERT_EQ(&a1, &a1Ref); + + a1 = a2; + for (U32 i = 0; i < TypeParam::SIZE; i++) { + ASSERT_EQ(a2[i], a1[i]); + } + + // Single element assignment + a1 = this->testVals[0]; + for (U32 i = 0; i < TypeParam::SIZE; i++) { + ASSERT_EQ(a1[i], this->testVals[0]); + } +} + +// Test array equality and inequality operators +TYPED_TEST_P(ArrayTest, EqualityOp) { + TypeParam a1, a2; + + ASSERT_TRUE(a1 == a2); + ASSERT_FALSE(a1 != a2); + + a2 = this->testVals; + + ASSERT_FALSE(a1 == a2); + ASSERT_TRUE(a1 != a2); + + a1 = a2; + + ASSERT_TRUE(a1 == a2); + ASSERT_FALSE(a1 != a2); +} + +// Test array serialization and deserialization +TYPED_TEST_P(ArrayTest, Serialization) { + TypeParam a(this->testVals); + + U32 serializedSize = + FppTest::Array::getSerializedSize(this->testVals); + Fw::SerializeStatus status; + + // Test successful serialization + TypeParam aCopy; + U8 data[TypeParam::SERIALIZED_SIZE]; + Fw::SerialBuffer buf(data, sizeof(data)); + + // Serialize + status = buf.serialize(a); + + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + ASSERT_EQ( + buf.getBuffLength(), + serializedSize + ); + + // Deserialize + status = buf.deserialize(aCopy); + + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + ASSERT_EQ(a, aCopy); + + // Test unsuccessful serialization + TypeParam aCopy2; + U8 data2[serializedSize-1]; + Fw::SerialBuffer buf2(data2, sizeof(data2)); + + // Serialize + status = buf2.serialize(a); + + ASSERT_NE(status, Fw::FW_SERIALIZE_OK); + ASSERT_NE( + buf2.getBuffLength(), + serializedSize + ); + + // Deserialize + status = buf2.deserialize(aCopy2); + + ASSERT_NE(status, Fw::FW_SERIALIZE_OK); +} + +// Register all test patterns +REGISTER_TYPED_TEST_SUITE_P(ArrayTest, + Default, + Constructors, + SubscriptOp, + AssignmentOp, + EqualityOp, + Serialization +); + +#endif diff --git a/FppTest/typed_tests/EnumTest.hpp b/FppTest/typed_tests/EnumTest.hpp new file mode 100644 index 0000000000..e7b79548de --- /dev/null +++ b/FppTest/typed_tests/EnumTest.hpp @@ -0,0 +1,210 @@ +// ====================================================================== +// \title EnumTest.hpp +// \author T. Chieu +// \brief hpp file for EnumTest class +// +// \copyright +// Copyright (C) 2009-2022 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#ifndef FPP_TEST_ENUM_TEST_HPP +#define FPP_TEST_ENUM_TEST_HPP + +#include "Fw/Types/SerialBuffer.hpp" + +#include "STest/Pick/Pick.hpp" +#include "gtest/gtest.h" + +#include + +namespace FppTest { + + namespace Enum { + + // Get the default value of an enum + template + typename EnumType::T getDefaultValue() { + return static_cast(0); + } + + // Get a valid value of an enum + template + typename EnumType::T getValidValue() { + U32 val = STest::Pick::startLength( + 0, + EnumType::NUM_CONSTANTS + ); + + return static_cast(val); + } + + // Get an invalid value of an enum + template + typename EnumType::T getInvalidValue() { + U8 sign = 0; + if (std::numeric_limits::min() < 0) { + sign = STest::Pick::lowerUpper(0, 1); + } + + switch (sign) { + case 0: + return static_cast(STest::Pick::lowerUpper( + EnumType::NUM_CONSTANTS, + static_cast( + std::numeric_limits::max() + ) + )); + default: + return static_cast(STest::Pick::lowerUpper( + 1, + static_cast((-1) * + (std::numeric_limits::min() + 1) + ) + ) * (-1)); + } + } + + } // namespace Enum + +} // namespace FppTest + +// Test core enum interface +template +class EnumTest : public ::testing::Test {}; + +TYPED_TEST_SUITE_P(EnumTest); + +// Test enum constants and default construction +TYPED_TEST_P(EnumTest, Default) { + TypeParam e; + + // Constants + ASSERT_EQ( + TypeParam::SERIALIZED_SIZE, + sizeof(typename TypeParam::SerialType) + ); + + // Default constructor + ASSERT_EQ(e.e, FppTest::Enum::getDefaultValue()); +} + +// Test enum constructors +TYPED_TEST_P(EnumTest, Constructors) { + typename TypeParam::T validVal = FppTest::Enum::getValidValue(); + + // Raw enum value constructor + TypeParam e1(validVal); + ASSERT_EQ(e1.e, validVal); + + // Copy constructor + TypeParam e2(e1); + ASSERT_EQ(e2.e, validVal); +} + +// Test enum assignment operator +TYPED_TEST_P(EnumTest, AssignmentOp) { + TypeParam e1; + TypeParam e2; + + typename TypeParam::T validVal = FppTest::Enum::getValidValue(); + + // Raw enum value assignment + e1 = validVal; + ASSERT_EQ(e1.e, validVal); + + // Object assignment + e2 = e1; + ASSERT_EQ(e2.e, validVal); +} + +// Test enum equality and inequality operator +TYPED_TEST_P(EnumTest, EqualityOp) { + // Initialize two distinct valid values + typename TypeParam::T validVal1 = FppTest::Enum::getValidValue(); + typename TypeParam::T validVal2 = FppTest::Enum::getValidValue(); + while (validVal1 == validVal2) { + validVal2 = FppTest::Enum::getValidValue(); + } + + TypeParam e1; + TypeParam e2; + TypeParam e3(validVal1); + TypeParam e4(validVal2); + + // operator== + ASSERT_TRUE(e3 == validVal1); + ASSERT_TRUE(e4 == validVal2); + ASSERT_FALSE(e3 == validVal2); + ASSERT_FALSE(e4 == validVal1); + + ASSERT_TRUE(e1 == e2); + ASSERT_FALSE(e3 == e4); + + // operator!= + ASSERT_TRUE(e3 != validVal2); + ASSERT_TRUE(e4 != validVal1); + ASSERT_FALSE(e3 != validVal1); + ASSERT_FALSE(e4 != validVal2); + + ASSERT_TRUE(e3 != e4); + ASSERT_FALSE(e1 != e2); +} + +// Test enum isValid() function +TYPED_TEST_P(EnumTest, IsValidFunction) { + TypeParam validEnum = FppTest::Enum::getValidValue(); + TypeParam invalidEnum = FppTest::Enum::getInvalidValue(); + + ASSERT_TRUE(validEnum.isValid()); + ASSERT_FALSE(invalidEnum.isValid()); +} + +// Test enum serialization and deserialization +TYPED_TEST_P(EnumTest, Serialization) { + TypeParam validEnum = FppTest::Enum::getValidValue(); + TypeParam invalidEnum = FppTest::Enum::getInvalidValue(); + + // Copy of enums to test after serialization + TypeParam validEnumCopy; + TypeParam invalidEnumCopy; + + Fw::SerializeStatus status; + U8 data[TypeParam::SERIALIZED_SIZE * 2]; + Fw::SerialBuffer buf(data, sizeof(data)); + + // Serialize the enums + status = buf.serialize(validEnum); + + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buf.getBuffLength(), sizeof(typename TypeParam::SerialType)); + + status = buf.serialize(invalidEnum); + + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + ASSERT_EQ(buf.getBuffLength(), sizeof(typename TypeParam::SerialType) * 2); + + // Deserialize the enums + status = buf.deserialize(validEnumCopy); + + ASSERT_EQ(status, Fw::FW_SERIALIZE_OK); + ASSERT_EQ(validEnumCopy, validEnum); + + status = buf.deserialize(invalidEnumCopy); + + ASSERT_EQ(status, Fw::FW_DESERIALIZE_FORMAT_ERROR); +} + +// Register all test patterns +REGISTER_TYPED_TEST_SUITE_P(EnumTest, + Default, + Constructors, + AssignmentOp, + EqualityOp, + IsValidFunction, + Serialization +); + +#endif diff --git a/FppTest/typed_tests/PortTest.hpp b/FppTest/typed_tests/PortTest.hpp new file mode 100644 index 0000000000..ddf69ffd6c --- /dev/null +++ b/FppTest/typed_tests/PortTest.hpp @@ -0,0 +1,65 @@ +// ====================================================================== +// \title PortTest.hpp +// \author T. Chieu +// \brief hpp file for PortTest class +// +// \copyright +// Copyright (C) 2009-2023 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#ifndef FPP_TEST_PORT_TEST_HPP +#define FPP_TEST_PORT_TEST_HPP + +#include "test/ut/Tester.hpp" +#include "FppTest/port/TypedPortIndexEnumAc.hpp" + +#include "gtest/gtest.h" + +// Typed port tests +template +class TypedPortTest : public ::testing::Test { +protected: + Tester tester; + PortType port; +}; + +TYPED_TEST_SUITE_P(TypedPortTest); + +TYPED_TEST_P(TypedPortTest, TypedPort) { + this->tester.invoke(TypedPortIndex::TYPED, this->port); + this->tester.check_history(this->port); +} + +REGISTER_TYPED_TEST_SUITE_P(TypedPortTest, + TypedPort +); + +// Serial port tests +template +class SerialPortTest : public ::testing::Test { +protected: + Tester tester; + PortType port; +}; + +TYPED_TEST_SUITE_P(SerialPortTest); + +TYPED_TEST_P(SerialPortTest, ToSerialTest) { + this->tester.invoke(TypedPortIndex::SERIAL, this->port); + this->tester.check_serial(this->port); +} + +TYPED_TEST_P(SerialPortTest, FromSerialTest) { + this->tester.invoke_serial(TypedPortIndex::SERIAL, this->port); + this->tester.check_history(this->port); +} + +REGISTER_TYPED_TEST_SUITE_P(SerialPortTest, + ToSerialTest, + FromSerialTest +); + +#endif diff --git a/FppTest/typed_tests/README.md b/FppTest/typed_tests/README.md new file mode 100644 index 0000000000..ab2062d749 --- /dev/null +++ b/FppTest/typed_tests/README.md @@ -0,0 +1,177 @@ +# FppTest/typed_tests + +This directory contains the following type-parametrized test suites for +C++ code generated by the FPP autocoder. + +* `EnumTest`: Tests an enum class +* `ArrayTest`: Tests an array class +* `StringTest`: Tests a nested string class within an array of struct class +* `PortTest`: Tests typed-to-typed, typed-to-serial, serial-to-typed, and +serial-to-serial port connections + +## Instantiating a Test Suite + +To use a type-parametrized test suite, instantiate it with a list of types: + +```c++ +#include "FppTest/typed_tests/TestSuite.hpp" + +using TestTypes = ::testing::Types< + Type1, + Type2, + Type3 +>; +INSTANTIATE_TYPED_TEST_SUITE_P(InstanceName, + TestSuite, + TestTypes); +``` + +## Implementing Specializations + +In addition to instantiating the test suite, you may also need to implement some +explicit specializations for template functions if the behavior of your class +differs from the provided default implementation. + +### `EnumTest` Suite + +- `getDefaultValue()`: Returns the default value of an enum type. The default +implementation returns 0. + + ```c++ + // Function signature + template + typename EnumType::T FppTest::Enum::getDefaultValue(); + ``` + +- `getValidValue()`: Returns a random valid enum value. The default implementation +assumes the values of the enum have been implicitly defined, i.e. it returns +a value in the interval `[0, EnumType::NUM_CONSTANTS-1]`. + + ```c++ + // Function signature + template + typename EnumType::T FppTest::Enum::getValidValue(); + ``` + +- `getInvalidValue()`: Returns an random invalid enum value. The default +implementation assumes the values of the enum have been implicitly defined, +i.e. it returns a value either in the interval `[min, -1]` (if the serial +representation type is signed) or in the interval +`[EnumType::NUM_CONSTANTS, max]`, where `min` and `max` are the minimum +and maximum values of the serial representation type, respectively. + + ```c++ + // Function signature + template + typename EnumType::T FppTest::Enum::getInvalidValue(); + ``` + +### `ArrayTest` Suite + +The following functions MUST be implemented for your array type! + +- `setTestVals()`: Sets test values for an array. There is no default +implementation, so this function must be implemented for your array type! +In addition, these test values must be different from the default values. + + ```c++ + // Function signature + template + void FppTest::Array::setTestVals + (typename ArrayType::ElementType (&a)[ArrayType::SIZE]); + ``` + +- `getMultiElementConstructedArray()`: Returns an array constructed using its +multiple element constructor. There is no default implementation, so this +function must be implemented for your array type! + + ```c++ + // Function signature + template + ArrayType FppTest::Array::getMultiElementConstructedArray + (typename ArrayType::ElementType (&a)[ArrayType::SIZE]); + ``` + +The following functions may or may not need to be implemented: + +- `setDefaultVals()`: Sets the default values for an array. The default +implementation is empty (i.e. the values are either zero-initialized or +default-initialized). + + ```c++ + // Function signature + template + void FppTest::Array::setDefaultVals + (typename ArrayType::ElementType (&a)[ArrayType::SIZE]); + ``` + +- `getSerializedSize()`: Returns the serialized size of an array. The default +implementation returns the `SERIALIZED_SIZE` of the array type. In particular, +this function will need to be implemented for arrays containing string values. + + ```c++ + // Function signature + template + U32 FppTest::Array::getSerializedSize + (typename ArrayType::ElementType (&a)[ArrayType::SIZE]); + ``` + +### `StringTest` Suite + +- `getSize()`: Returns the size of a string type. The default implementation +returns the default string size of 80. + + ```c++ + // Function signature + template + U32 FppTest::String::getSize(); + ``` + +## Example + +For example, to use the `ArrayTest` suite with array types `U32Array`, an array +of three U32 values, and `F32Array`, an array of four F32 values: + +```c++ +#include "FppTest/typed_tests/ArrayTest.hpp" + +// Instantiate the test suite with a list of types +using ArrayTypes = ::testing::Types< + U32Array, + F32Array +>; +INSTANTIATE_TYPED_TEST_SUITE_P(ExampleInstance, + ArrayTest, + ArrayTypes); + +// Explicit specializations for setTestVals() +template <> +void FppTest::Array::setTestVals + (U32Array::ElementType (&a)[U32Array::SIZE]) { + for (U32 i = 0; i < U32Array::SIZE; i++) { + a[i] = i; + } +} + +template <> +void FppTest::Array::setTestVals + (F32Array::ElementType (&a)[F32Array::SIZE]) { + for (U32 i = 0; i < F32Array::SIZE; i++) { + a[i] = static_cast(i); + } +} + +// Explicit specializations for getMultiElementConstructedArray() +template<> +U32Array FppTest::Array::getMultiElementConstructedArray + (U32Array::ElementType (&a)[U32Array::SIZE]) { + return U32Array(a[0], a[1], a[2]); +} + +template<> +F32Array FppTest::Array::getMultiElementConstructedArray + (F32Array::ElementType (&a)[F32Array::SIZE]) { + return F32Array(a[0], a[1], a[2], a[3]); +} +``` + diff --git a/FppTest/typed_tests/StringTest.hpp b/FppTest/typed_tests/StringTest.hpp new file mode 100644 index 0000000000..ea2008cc46 --- /dev/null +++ b/FppTest/typed_tests/StringTest.hpp @@ -0,0 +1,131 @@ +// ====================================================================== +// \title StringTest.hpp +// \author T. Chieu +// \brief hpp file for StringTest class +// +// \copyright +// Copyright (C) 2009-2022 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#ifndef FPP_TEST_STRING_TEST_HPP +#define FPP_TEST_STRING_TEST_HPP + +#include "FppTest/utils/Utils.hpp" + +#include "Fw/Types/String.hpp" +#include "Fw/Types/StringUtils.hpp" + +#include "gtest/gtest.h" + +namespace FppTest { + + namespace String { + + // Get the size of a string type + template + U32 getSize() { + return 80; + } + + } // namespace String + +} // namespace FppTest + +// Test a nested string class +template +class StringTest : public ::testing::Test { +protected: + void SetUp() override { + size = FppTest::String::getSize(); + + FppTest::Utils::setString(src, size); + + char fwStrBuf1[Fw::String::STRING_SIZE]; + FppTest::Utils::setString(fwStrBuf1, sizeof(fwStrBuf1)); + fwStr = fwStrBuf1; + + // Truncate fwStr for comparison + char fwStrBuf2[size]; + Fw::StringUtils::string_copy(fwStrBuf2, fwStr.toChar(), size); + fwSubstr = fwStrBuf2; + } + + U32 size; + char src[StringType::SERIALIZED_SIZE]; + + Fw::String fwStr; + Fw::String fwSubstr; +}; + +TYPED_TEST_SUITE_P(StringTest); + +// Test string capacity and default constructor +TYPED_TEST_P(StringTest, Default) { + TypeParam str; + + // Capacity + ASSERT_EQ(str.getCapacity(), this->size); + + // Serialized size + ASSERT_EQ( + TypeParam::SERIALIZED_SIZE, + this->size + sizeof(FwBuffSizeType) + ); + + // Default constructors + ASSERT_STREQ(str.toChar(), ""); +} + +// Test string constructors +TYPED_TEST_P(StringTest, Constructors) { + // Char array constructor + TypeParam str1(this->src); + ASSERT_STREQ(str1.toChar(), this->src); + + // Copy constructor + TypeParam str2(str1); + ASSERT_STREQ(str2.toChar(), str1.toChar()); + + // Fw::StringBase constructor + TypeParam str3(this->fwStr); + ASSERT_STREQ(str3.toChar(), this->fwSubstr.toChar()); +} + +// Test string assignment operator +TYPED_TEST_P(StringTest, AssignmentOp) { + TypeParam str1; + TypeParam str2; + TypeParam str3; + + // Char array assignment + str1 = this->src; + ASSERT_STREQ(str1.toChar(), this->src); + + // Copy assignment + TypeParam& strRef = str1; + str1 = strRef; + ASSERT_EQ(&str1, &strRef); + + str2 = str1; + ASSERT_STREQ(str1.toChar(), str1.toChar()); + + // Fw::StringBase assignment + Fw::StringBase& sbRef = str1; + str1 = sbRef; + ASSERT_EQ(&str1, &sbRef); + + str3 = this->fwStr; + ASSERT_STREQ(str3.toChar(), this->fwSubstr.toChar()); +} + +// Register all test patterns +REGISTER_TYPED_TEST_SUITE_P(StringTest, + Default, + Constructors, + AssignmentOp +); + +#endif diff --git a/FppTest/utils/Utils.cpp b/FppTest/utils/Utils.cpp new file mode 100644 index 0000000000..64fdd0b6b8 --- /dev/null +++ b/FppTest/utils/Utils.cpp @@ -0,0 +1,58 @@ +// ====================================================================== +// \title Utils.cpp +// \author T. Chieu +// \brief cpp file for Utils class +// +// \copyright +// Copyright (C) 2009-2022 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include "STest/Pick/Pick.hpp" + +#include +#include +#include + +namespace FppTest { + + namespace Utils { + + U8 getU8() { + return static_cast(STest::Pick::lowerUpper( + 1, + std::numeric_limits::max() + )); + } + + U32 getU32() { + return STest::Pick::lowerUpper( + 1, + std::numeric_limits::max() + ); + } + + char getChar() { + return static_cast(STest::Pick::lowerUpper(1, 127)); + } + + void setString(char* buf, U32 size) { + U32 length = STest::Pick::lowerUpper(1, size); + + if (length == 0) { + buf[0] = 0; + return; + } + + for (U32 i = 0; i < length - 1; i++) { + buf[i] = getChar(); + } + + buf[length-1] = 0; + } + + } // namespace Utils + +} // namespace FppTest diff --git a/FppTest/utils/Utils.hpp b/FppTest/utils/Utils.hpp new file mode 100644 index 0000000000..24308d49a5 --- /dev/null +++ b/FppTest/utils/Utils.hpp @@ -0,0 +1,36 @@ +// ====================================================================== +// \title Utils.hpp +// \author T. Chieu +// \brief hpp file for Utils class +// +// \copyright +// Copyright (C) 2009-2022 California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#ifndef FPP_TEST_UTILS_HPP +#define FPP_TEST_UTILS_HPP + +namespace FppTest { + + namespace Utils { + + // Returns a random nonzero U8 + U8 getU8(); + + // Returns a random nonzero U32 + U32 getU32(); + + // Returns a random non-null char + char getChar(); + + // Populates buf with a random nonempty string of random length with max length size + void setString(char *buf, U32 size); + + } // namespace Utils + +} // namespace FppTest + +#endif diff --git a/Fw/Buffer/Buffer.cpp b/Fw/Buffer/Buffer.cpp index e1a2890d00..010c2dc963 100644 --- a/Fw/Buffer/Buffer.cpp +++ b/Fw/Buffer/Buffer.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include #include -#include +#include #if FW_SERIALIZABLE_TO_STRING #include diff --git a/Fw/Buffer/Buffer.hpp b/Fw/Buffer/Buffer.hpp index 1ac3bc11d8..50d021216b 100644 --- a/Fw/Buffer/Buffer.hpp +++ b/Fw/Buffer/Buffer.hpp @@ -12,7 +12,7 @@ #ifndef BUFFER_HPP_ #define BUFFER_HPP_ -#include +#include #include #if FW_SERIALIZABLE_TO_STRING #include diff --git a/Fw/Buffer/CMakeLists.txt b/Fw/Buffer/CMakeLists.txt index 76ca5f548d..701e233186 100644 --- a/Fw/Buffer/CMakeLists.txt +++ b/Fw/Buffer/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Fw/Buffer/test/ut/TestBuffer.cpp b/Fw/Buffer/test/ut/TestBuffer.cpp index e0bbb514d4..fd2d11aaf5 100644 --- a/Fw/Buffer/test/ut/TestBuffer.cpp +++ b/Fw/Buffer/test/ut/TestBuffer.cpp @@ -2,7 +2,7 @@ // Created by mstarch on 11/13/20. // #include "Fw/Buffer/Buffer.hpp" -#include "Fw/Types/BasicTypes.hpp" +#include #include diff --git a/Fw/CMakeLists.txt b/Fw/CMakeLists.txt index b7be5aa001..8d34393ace 100644 --- a/Fw/CMakeLists.txt +++ b/Fw/CMakeLists.txt @@ -15,6 +15,7 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Cfg/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Comp/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Obj/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Port/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Ports/SuccessCondition") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Types/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FilePacket/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SerializableFile/") diff --git a/Fw/Cfg/CMakeLists.txt b/Fw/Cfg/CMakeLists.txt index ecb0c5a769..b3d675f59a 100644 --- a/Fw/Cfg/CMakeLists.txt +++ b/Fw/Cfg/CMakeLists.txt @@ -1,16 +1,17 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/ConfigCheck.cpp" ) +set(MOD_DEPS config) register_fprime_module() if (FPRIME_USE_BAREMETAL_SCHEDULER) - target_compile_definitions(Fw_Cfg PUBLIC FW_BAREMETAL_SCHEDULER=1) + target_compile_definitions(config PUBLIC FW_BAREMETAL_SCHEDULER=1) else() - target_compile_definitions(Fw_Cfg PUBLIC FW_BAREMETAL_SCHEDULER=0) + target_compile_definitions(config PUBLIC FW_BAREMETAL_SCHEDULER=0) endif() diff --git a/Fw/Cfg/ConfigCheck.cpp b/Fw/Cfg/ConfigCheck.cpp index 43350e05cf..da218bcccf 100644 --- a/Fw/Cfg/ConfigCheck.cpp +++ b/Fw/Cfg/ConfigCheck.cpp @@ -11,7 +11,6 @@ */ #include -#include // Check that command/telemetry strings are not larger than an argument buffer diff --git a/Fw/Cmd/CMakeLists.txt b/Fw/Cmd/CMakeLists.txt index 5cba1e92e2..f87144d8cb 100644 --- a/Fw/Cmd/CMakeLists.txt +++ b/Fw/Cmd/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Fw/Cmd/CmdArgBuffer.hpp b/Fw/Cmd/CmdArgBuffer.hpp index 8e72f220bc..4744c6124c 100644 --- a/Fw/Cmd/CmdArgBuffer.hpp +++ b/Fw/Cmd/CmdArgBuffer.hpp @@ -12,9 +12,8 @@ #ifndef FW_CMD_ARG_BUFFER_HPP #define FW_CMD_ARG_BUFFER_HPP -#include -#include #include +#include #include namespace Fw { diff --git a/Fw/Cmd/CmdString.hpp b/Fw/Cmd/CmdString.hpp index d9d283f188..4e3a9dfe7d 100644 --- a/Fw/Cmd/CmdString.hpp +++ b/Fw/Cmd/CmdString.hpp @@ -1,9 +1,8 @@ #ifndef FW_CMD_STRING_TYPE_HPP #define FW_CMD_STRING_TYPE_HPP -#include -#include #include +#include #include namespace Fw { diff --git a/Fw/Com/CMakeLists.txt b/Fw/Com/CMakeLists.txt index f8139ca4e9..8cfcff21d1 100644 --- a/Fw/Com/CMakeLists.txt +++ b/Fw/Com/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Fw/Com/ComBuffer.hpp b/Fw/Com/ComBuffer.hpp index dc52506566..a9d552a630 100644 --- a/Fw/Com/ComBuffer.hpp +++ b/Fw/Com/ComBuffer.hpp @@ -13,7 +13,6 @@ #define FW_COM_BUFFER_HPP #include -#include #include namespace Fw { diff --git a/Fw/Comp/CMakeLists.txt b/Fw/Comp/CMakeLists.txt index ba18f8b557..6865bdd831 100644 --- a/Fw/Comp/CMakeLists.txt +++ b/Fw/Comp/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Fw/FilePacket/CMakeLists.txt b/Fw/FilePacket/CMakeLists.txt index c92c708c73..c7a1914c2c 100644 --- a/Fw/FilePacket/CMakeLists.txt +++ b/Fw/FilePacket/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Fw/FilePacket/FilePacket.hpp b/Fw/FilePacket/FilePacket.hpp index 8f6cf995dc..09b58cffca 100644 --- a/Fw/FilePacket/FilePacket.hpp +++ b/Fw/FilePacket/FilePacket.hpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include diff --git a/Fw/FilePacket/GTest/CMakeLists.txt b/Fw/FilePacket/GTest/CMakeLists.txt index 6c5b7d3e8d..e9b17fb627 100644 --- a/Fw/FilePacket/GTest/CMakeLists.txt +++ b/Fw/FilePacket/GTest/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Fw/FilePacket/docs/sdd.md b/Fw/FilePacket/docs/sdd.md index 99ca1e1dd2..544333e9f8 100644 --- a/Fw/FilePacket/docs/sdd.md +++ b/Fw/FilePacket/docs/sdd.md @@ -11,7 +11,7 @@ It represents an ISF file packet. The file packet format is similar to the Protocol Data Unit (PDU) format defined in the CCSDS File Delivery Protocol (CFDP). See § 5 of the -[CCSDS File Delivery Protocol (CFDP) Recommended Standard](http://public.ccsds.org/publications/archive/727x0b4.pdf). +[CCSDS File Delivery Protocol (CFDP) Recommended Standard](https://public.ccsds.org/Pubs/727x0b4s.pdf). Each file packet contains the following data: diff --git a/Fw/Log/CMakeLists.txt b/Fw/Log/CMakeLists.txt index ce323f496b..dcd364dd95 100644 --- a/Fw/Log/CMakeLists.txt +++ b/Fw/Log/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Fw/Log/LogBuffer.hpp b/Fw/Log/LogBuffer.hpp index e33fed20a6..8e310f8f3c 100644 --- a/Fw/Log/LogBuffer.hpp +++ b/Fw/Log/LogBuffer.hpp @@ -13,7 +13,6 @@ #define FW_LOG_BUFFER_HPP #include -#include #include #include diff --git a/Fw/Log/LogString.hpp b/Fw/Log/LogString.hpp index 2c3e4e14be..533e2ddf24 100644 --- a/Fw/Log/LogString.hpp +++ b/Fw/Log/LogString.hpp @@ -1,9 +1,8 @@ #ifndef FW_LOG_STRING_TYPE_HPP #define FW_LOG_STRING_TYPE_HPP -#include -#include #include +#include #include namespace Fw { diff --git a/Fw/Log/TextLogString.hpp b/Fw/Log/TextLogString.hpp index 43c0c602b8..e25f7273f2 100644 --- a/Fw/Log/TextLogString.hpp +++ b/Fw/Log/TextLogString.hpp @@ -1,9 +1,8 @@ #ifndef FW_TEXT_LOG_STRING_TYPE_HPP #define FW_TEXT_LOG_STRING_TYPE_HPP -#include -#include #include +#include #include namespace Fw { diff --git a/Fw/Logger/CMakeLists.txt b/Fw/Logger/CMakeLists.txt index 844a9b8d5d..90c41d82a8 100644 --- a/Fw/Logger/CMakeLists.txt +++ b/Fw/Logger/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Fw/Logger/LogAssert.cpp b/Fw/Logger/LogAssert.cpp index 488b17e6b9..4eca41f9b0 100644 --- a/Fw/Logger/LogAssert.cpp +++ b/Fw/Logger/LogAssert.cpp @@ -36,12 +36,12 @@ namespace Fw { FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, NATIVE_UINT_TYPE numArgs, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4, - AssertArg arg5, - AssertArg arg6 + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4, + FwAssertArgType arg5, + FwAssertArgType arg6 ) { // Assumption is that file (when string) goes back to static macro in the code and will persist switch (numArgs) { diff --git a/Fw/Logger/LogAssert.hpp b/Fw/Logger/LogAssert.hpp index 03401e4786..6927b06d90 100644 --- a/Fw/Logger/LogAssert.hpp +++ b/Fw/Logger/LogAssert.hpp @@ -22,12 +22,12 @@ namespace Fw { FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, NATIVE_UINT_TYPE numArgs, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4, - AssertArg arg5, - AssertArg arg6 + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4, + FwAssertArgType arg5, + FwAssertArgType arg6 ); void printAssert(const CHAR* msg); void doAssert(); diff --git a/Fw/Logger/Logger.hpp b/Fw/Logger/Logger.hpp index bca6b273ce..981612b09c 100644 --- a/Fw/Logger/Logger.hpp +++ b/Fw/Logger/Logger.hpp @@ -9,7 +9,7 @@ #ifndef _Fw_Logger_hpp_ #define _Fw_Logger_hpp_ -#include +#include namespace Fw { class Logger { diff --git a/Fw/Logger/test/ut/FakeLogger.cpp b/Fw/Logger/test/ut/FakeLogger.cpp index 866a373392..f4652d4dc1 100644 --- a/Fw/Logger/test/ut/FakeLogger.cpp +++ b/Fw/Logger/test/ut/FakeLogger.cpp @@ -9,9 +9,6 @@ #include #include -extern "C" { - #include -} namespace MockLogging { Fw::Logger* FakeLogger::s_current = nullptr; @@ -85,4 +82,4 @@ namespace MockLogging { m_last.a8 = 0; m_last.a9 = 0; } -} \ No newline at end of file +} diff --git a/Fw/Logger/test/ut/FakeLogger.hpp b/Fw/Logger/test/ut/FakeLogger.hpp index 439b374a97..125023d4b9 100644 --- a/Fw/Logger/test/ut/FakeLogger.hpp +++ b/Fw/Logger/test/ut/FakeLogger.hpp @@ -7,7 +7,7 @@ * @author mstarch */ -#include +#include #include #ifndef FPRIME_FAKELOGGER_HPP diff --git a/Fw/Logger/test/ut/LoggerRules.cpp b/Fw/Logger/test/ut/LoggerRules.cpp index 3e54f3ad79..547f44f181 100644 --- a/Fw/Logger/test/ut/LoggerRules.cpp +++ b/Fw/Logger/test/ut/LoggerRules.cpp @@ -50,60 +50,55 @@ namespace LoggerRules { // Log valid messages void LogGood::action(MockLogging::FakeLogger& truth) { NATIVE_INT_TYPE random = STest::Pick::lowerUpper(0, 10); - NATIVE_INT_TYPE ra1 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra2 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra3 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra4 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra5 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra6 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra7 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra8 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra9 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra10 = STest::Pick::lowerUpper(0, 0xffffffff); + NATIVE_INT_TYPE ra[10]; + for (int i = 0; i < 10; ++i) { + ra[i] = STest::Pick::lowerUpper(0, 0xffffffff); + } + switch (random) { case 0: Fw::Logger::logMsg("No args"); truth.check("No args"); break; case 1: - Fw::Logger::logMsg("One arg: %lu", ra1); - truth.check("One arg: %lu", ra1); + Fw::Logger::logMsg("One arg: %lu", ra[0]); + truth.check("One arg: %lu", ra[0]); break; case 2: - Fw::Logger::logMsg("Two arg: %lu", ra1, ra2); - truth.check("Two arg: %lu", ra1, ra2); + Fw::Logger::logMsg("Two arg: %lu", ra[0], ra[1]); + truth.check("Two arg: %lu", ra[0], ra[1]); break; case 3: - Fw::Logger::logMsg("Three arg: %lu", ra1, ra2, ra3); - truth.check("Three arg: %lu", ra1, ra2, ra3); + Fw::Logger::logMsg("Three arg: %lu", ra[0], ra[1], ra[2]); + truth.check("Three arg: %lu", ra[0], ra[1], ra[2]); break; case 4: - Fw::Logger::logMsg("Four arg: %lu", ra1, ra2, ra3, ra4); - truth.check("Four arg: %lu", ra1, ra2, ra3, ra4); + Fw::Logger::logMsg("Four arg: %lu", ra[0], ra[1], ra[2], ra[3]); + truth.check("Four arg: %lu", ra[0], ra[1], ra[2], ra[3]); break; case 5: - Fw::Logger::logMsg("Five arg: %lu", ra1, ra2, ra3, ra4, ra5); - truth.check("Five arg: %lu", ra1, ra2, ra3, ra4, ra5); + Fw::Logger::logMsg("Five arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4]); + truth.check("Five arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4]); break; case 6: - Fw::Logger::logMsg("Six arg: %lu", ra1, ra2, ra3, ra4, ra5, ra6); - truth.check("Six arg: %lu", ra1, ra2, ra3, ra4, ra5, ra6); + Fw::Logger::logMsg("Six arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5]); + truth.check("Six arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5]); break; case 7: - Fw::Logger::logMsg("Seven arg: %lu", ra1, ra2, ra3, ra4, ra5, ra6, ra7); - truth.check("Seven arg: %lu", ra1, ra2, ra3, ra4, ra5, ra6, ra7); + Fw::Logger::logMsg("Seven arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6]); + truth.check("Seven arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6]); break; case 8: - Fw::Logger::logMsg("Eight arg: %lu", ra1, ra2, ra3, ra4, ra5, ra6, ra7, ra8); - truth.check("Eight arg: %lu", ra1, ra2, ra3, ra4, ra5, ra6, ra7, ra8); + Fw::Logger::logMsg("Eight arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7]); + truth.check("Eight arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7]); break; case 9: - Fw::Logger::logMsg("Nine arg: %lu", ra1, ra2, ra3, ra4, ra5, ra6, ra7, ra8, ra9); - truth.check("Nine arg: %lu", ra1, ra2, ra3, ra4, ra5, ra6, ra7, ra8, ra9); + Fw::Logger::logMsg("Nine arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7], ra[8]); + truth.check("Nine arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7], ra[8]); break; case 10: - Fw::Logger::logMsg("Ten arg: %lu", ra1, ra2, ra3, ra4, ra5, ra6, ra7, ra8, ra9, ra10); - truth.check("Ten arg: %lu", ra1, ra2, ra3, ra4, ra5, ra6, ra7, ra8, ra9, ra10); + Fw::Logger::logMsg("Ten arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7], ra[8], ra[9]); + truth.check("Ten arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7], ra[8], ra[9]); break; default: @@ -123,16 +118,10 @@ namespace LoggerRules { // Log valid messages void LogBad::action(MockLogging::FakeLogger& truth) { NATIVE_INT_TYPE random = STest::Pick::lowerUpper(0, 10); - NATIVE_INT_TYPE ra1 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra2 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra3 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra4 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra5 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra6 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra7 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra8 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra9 = STest::Pick::lowerUpper(0, 0xffffffff); - NATIVE_INT_TYPE ra10 = STest::Pick::lowerUpper(0, 0xffffffff); + NATIVE_INT_TYPE ra[10]; + for (int i = 0; i < 10; ++i) { + ra[i] = STest::Pick::lowerUpper(0, 0xffffffff); + } switch (random) { case 0: @@ -140,43 +129,43 @@ namespace LoggerRules { truth.check(nullptr); break; case 1: - Fw::Logger::logMsg("One arg: %lu", ra1); + Fw::Logger::logMsg("One arg: %lu", ra[0]); truth.check(nullptr); break; case 2: - Fw::Logger::logMsg("Two arg: %lu", ra1, ra2); + Fw::Logger::logMsg("Two arg: %lu", ra[0], ra[1]); truth.check(nullptr); break; case 3: - Fw::Logger::logMsg("Three arg: %lu", ra1, ra2, ra3); + Fw::Logger::logMsg("Three arg: %lu", ra[0], ra[1], ra[2]); truth.check(nullptr); break; case 4: - Fw::Logger::logMsg("Four arg: %lu", ra1, ra2, ra3, ra4); + Fw::Logger::logMsg("Four arg: %lu", ra[0], ra[1], ra[2], ra[3]); truth.check(nullptr); break; case 5: - Fw::Logger::logMsg("Five arg: %lu", ra1, ra2, ra3, ra4, ra5); + Fw::Logger::logMsg("Five arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4]); truth.check(nullptr); break; case 6: - Fw::Logger::logMsg("Six arg: %lu", ra1, ra2, ra3, ra4, ra5, ra6); + Fw::Logger::logMsg("Six arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5]); truth.check(nullptr); break; case 7: - Fw::Logger::logMsg("Six arg: %lu", ra1, ra2, ra3, ra4, ra5, ra6, ra7); + Fw::Logger::logMsg("Seven arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6]); truth.check(nullptr); break; case 8: - Fw::Logger::logMsg("Six arg: %lu", ra1, ra2, ra3, ra4, ra5, ra6, ra7, ra8); + Fw::Logger::logMsg("Eight arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7]); truth.check(nullptr); break; case 9: - Fw::Logger::logMsg("Six arg: %lu", ra1, ra2, ra3, ra4, ra5, ra6, ra7, ra8, ra9); + Fw::Logger::logMsg("Nine arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7], ra[8]); truth.check(nullptr); break; case 10: - Fw::Logger::logMsg("Six arg: %lu", ra1, ra2, ra3, ra4, ra5, ra6, ra7, ra8, ra9, ra10); + Fw::Logger::logMsg("Ten arg: %lu", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5], ra[6], ra[7], ra[8], ra[9]); truth.check(nullptr); break; default: diff --git a/Fw/Logger/test/ut/LoggerRules.hpp b/Fw/Logger/test/ut/LoggerRules.hpp index 0b8405264d..a0f34a4948 100644 --- a/Fw/Logger/test/ut/LoggerRules.hpp +++ b/Fw/Logger/test/ut/LoggerRules.hpp @@ -15,7 +15,7 @@ #ifndef FPRIME_LOGGERRULES_HPP #define FPRIME_LOGGERRULES_HPP -#include +#include #include #include #include diff --git a/Fw/Logger/test/ut/Main.cpp b/Fw/Logger/test/ut/Main.cpp index 7449fcd892..14d52daaf9 100644 --- a/Fw/Logger/test/ut/Main.cpp +++ b/Fw/Logger/test/ut/Main.cpp @@ -49,7 +49,7 @@ TEST(LoggerTests, RandomLoggerTests) { /** * Test that the most basic logging function works. */ -TEST(LoggerTests, BassicGoodLogger) { +TEST(LoggerTests, BasicGoodLogger) { // Setup and register logger MockLogging::FakeLogger logger; Fw::Logger::registerLogger(&logger); @@ -61,7 +61,7 @@ TEST(LoggerTests, BassicGoodLogger) { /** * Test that null-logging function works. */ -TEST(LoggerTests, BassicBadLogger) { +TEST(LoggerTests, BasicBadLogger) { // Basic discard logging MockLogging::FakeLogger logger; Fw::Logger::registerLogger(nullptr); @@ -73,7 +73,7 @@ TEST(LoggerTests, BassicBadLogger) { /** * Test that registration works. Multiple times, as contains randomness. */ -TEST(LoggerTests, BassicRegLogger) { +TEST(LoggerTests, BasicRegLogger) { // Basic discard logging MockLogging::FakeLogger logger; LoggerRules::Register reg("Register"); diff --git a/Fw/Obj/CMakeLists.txt b/Fw/Obj/CMakeLists.txt index 3b6f515497..80a3210321 100644 --- a/Fw/Obj/CMakeLists.txt +++ b/Fw/Obj/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### @@ -12,9 +12,7 @@ set(SOURCE_FILES set(MOD_DEPS Fw/Cfg Fw/Types + Fw/Logger ) -if (BUILD_SHARED_LIBS) - list(APPEND MOD_DEPS "Fw/Logger") -endif() register_fprime_module() diff --git a/Fw/Obj/ObjBase.hpp b/Fw/Obj/ObjBase.hpp index 629fbeb740..ac06088d83 100644 --- a/Fw/Obj/ObjBase.hpp +++ b/Fw/Obj/ObjBase.hpp @@ -13,7 +13,6 @@ #ifndef FW_OBJ_BASE_HPP #define FW_OBJ_BASE_HPP -#include #include namespace Fw { diff --git a/Fw/Obj/SimpleObjRegistry.hpp b/Fw/Obj/SimpleObjRegistry.hpp index b0cd805f86..4d700b698e 100644 --- a/Fw/Obj/SimpleObjRegistry.hpp +++ b/Fw/Obj/SimpleObjRegistry.hpp @@ -21,7 +21,6 @@ #include #include -#include #if FW_OBJECT_REGISTRATION == 1 diff --git a/Fw/Port/CMakeLists.txt b/Fw/Port/CMakeLists.txt index 1308860feb..3747db3fca 100644 --- a/Fw/Port/CMakeLists.txt +++ b/Fw/Port/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Fw/Port/InputPortBase.cpp b/Fw/Port/InputPortBase.cpp index 40168bce71..b82aedcf94 100644 --- a/Fw/Port/InputPortBase.cpp +++ b/Fw/Port/InputPortBase.cpp @@ -1,8 +1,6 @@ #include - #include #include -#include #include namespace Fw { diff --git a/Fw/Port/InputPortBase.hpp b/Fw/Port/InputPortBase.hpp index 1752d47177..5499c7c610 100644 --- a/Fw/Port/InputPortBase.hpp +++ b/Fw/Port/InputPortBase.hpp @@ -2,9 +2,7 @@ #define FW_INPUT_PORT_BASE_HPP #include - #include -#include #include #include #include diff --git a/Fw/Port/OutputPortBase.cpp b/Fw/Port/OutputPortBase.cpp index 44e67034d3..0ac06fd3ae 100644 --- a/Fw/Port/OutputPortBase.cpp +++ b/Fw/Port/OutputPortBase.cpp @@ -1,7 +1,5 @@ #include - #include -#include #include #include #include diff --git a/Fw/Port/OutputPortBase.hpp b/Fw/Port/OutputPortBase.hpp index 1a8d75f154..c64e11fc14 100644 --- a/Fw/Port/OutputPortBase.hpp +++ b/Fw/Port/OutputPortBase.hpp @@ -2,9 +2,7 @@ #define FW_OUTPUT_PORT_BASE_HPP #include - #include -#include #include #include diff --git a/Fw/Port/PortBase.cpp b/Fw/Port/PortBase.cpp index 6d775be222..34b51322a2 100644 --- a/Fw/Port/PortBase.cpp +++ b/Fw/Port/PortBase.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include "Fw/Types/Assert.hpp" diff --git a/Fw/Port/PortBase.hpp b/Fw/Port/PortBase.hpp index 4573d7589b..e9b9a6b8e8 100644 --- a/Fw/Port/PortBase.hpp +++ b/Fw/Port/PortBase.hpp @@ -2,7 +2,7 @@ #define FW_PORT_BASE_HPP #include -#include +#include #include #if FW_PORT_TRACING == 1 diff --git a/Fw/Ports/SuccessCondition/CMakeLists.txt b/Fw/Ports/SuccessCondition/CMakeLists.txt new file mode 100644 index 0000000000..dff861112c --- /dev/null +++ b/Fw/Ports/SuccessCondition/CMakeLists.txt @@ -0,0 +1,9 @@ +#### +# CMakeLists.txt: +# +# Sets up the fprime module build within CMake. +#### +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/SuccessCondition.fpp" +) +register_fprime_module() \ No newline at end of file diff --git a/Fw/Ports/SuccessCondition/SuccessCondition.fpp b/Fw/Ports/SuccessCondition/SuccessCondition.fpp new file mode 100644 index 0000000000..598c4e8250 --- /dev/null +++ b/Fw/Ports/SuccessCondition/SuccessCondition.fpp @@ -0,0 +1,12 @@ +##### +# SuccessCondition: +# +# A port communicating a success or failure condition. +##### + +module Fw { + @ Port communicating success or failure condition + port SuccessCondition( + ref condition: Fw.Success @< Condition success/failure + ) +} \ No newline at end of file diff --git a/Fw/Prm/CMakeLists.txt b/Fw/Prm/CMakeLists.txt index 0aeb62de0a..a468b38f91 100644 --- a/Fw/Prm/CMakeLists.txt +++ b/Fw/Prm/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Fw/Prm/PrmBuffer.hpp b/Fw/Prm/PrmBuffer.hpp index 29739fa846..51b21c94cc 100644 --- a/Fw/Prm/PrmBuffer.hpp +++ b/Fw/Prm/PrmBuffer.hpp @@ -13,7 +13,6 @@ #define FW_PRM_BUFFER_HPP #include -#include #include #include diff --git a/Fw/Prm/PrmString.hpp b/Fw/Prm/PrmString.hpp index deb4fdac48..8972c49a7a 100644 --- a/Fw/Prm/PrmString.hpp +++ b/Fw/Prm/PrmString.hpp @@ -1,9 +1,8 @@ #ifndef FW_PRM_STRING_TYPE_HPP #define FW_PRM_STRING_TYPE_HPP -#include -#include #include +#include #include namespace Fw { diff --git a/Fw/SerializableFile/CMakeLists.txt b/Fw/SerializableFile/CMakeLists.txt index 1b06bb627e..e040d1acba 100644 --- a/Fw/SerializableFile/CMakeLists.txt +++ b/Fw/SerializableFile/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Fw/SerializableFile/test/TestSerializable/CMakeLists.txt b/Fw/SerializableFile/test/TestSerializable/CMakeLists.txt index eab663392b..681efdcf53 100644 --- a/Fw/SerializableFile/test/TestSerializable/CMakeLists.txt +++ b/Fw/SerializableFile/test/TestSerializable/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Fw/SerializableFile/test/ut/Test.cpp b/Fw/SerializableFile/test/ut/Test.cpp index 38d407adda..eb569ede48 100644 --- a/Fw/SerializableFile/test/ut/Test.cpp +++ b/Fw/SerializableFile/test/ut/Test.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include #include diff --git a/Fw/Test/CMakeLists.txt b/Fw/Test/CMakeLists.txt index f18d8ec8a0..dff1941472 100644 --- a/Fw/Test/CMakeLists.txt +++ b/Fw/Test/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Fw/Test/String.hpp b/Fw/Test/String.hpp index 3d293d50b2..ddc525bcd2 100644 --- a/Fw/Test/String.hpp +++ b/Fw/Test/String.hpp @@ -1,7 +1,7 @@ #ifndef TEST_STRING_TYPE_HPP #define TEST_STRING_TYPE_HPP -#include +#include #include #include diff --git a/Fw/Test/UnitTestAssert.cpp b/Fw/Test/UnitTestAssert.cpp index 81ba878087..77a0da89f4 100644 --- a/Fw/Test/UnitTestAssert.cpp +++ b/Fw/Test/UnitTestAssert.cpp @@ -43,9 +43,9 @@ namespace Test { void UnitTestAssert::doAssert() { this->m_assertFailed = true; #if FW_ASSERT_LEVEL == FW_FILEID_ASSERT - (void)fprintf(stderr,"Assert File: 0x%x, Line: %u\n", this->m_file, this->m_lineNo); + (void)fprintf(stderr,"Assert File: 0x%" PRIx32 ", Line: %" PRI_PlatformUIntType "\n", this->m_file, this->m_lineNo); #else - (void)fprintf(stderr,"Assert File: %s, Line: %u\n", this->m_file.toChar(), this->m_lineNo); + (void)fprintf(stderr,"Assert File: %s, Line: %" PRI_PlatformUIntType "\n", this->m_file.toChar(), this->m_lineNo); #endif } @@ -53,12 +53,12 @@ namespace Test { FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, NATIVE_UINT_TYPE numArgs, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4, - AssertArg arg5, - AssertArg arg6 + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4, + FwAssertArgType arg5, + FwAssertArgType arg6 ) { #if FW_ASSERT_LEVEL == FW_FILEID_ASSERT @@ -82,12 +82,12 @@ namespace Test { File& file, NATIVE_UINT_TYPE& lineNo, NATIVE_UINT_TYPE& numArgs, - AssertArg& arg1, - AssertArg& arg2, - AssertArg& arg3, - AssertArg& arg4, - AssertArg& arg5, - AssertArg& arg6 + FwAssertArgType& arg1, + FwAssertArgType& arg2, + FwAssertArgType& arg3, + FwAssertArgType& arg4, + FwAssertArgType& arg5, + FwAssertArgType& arg6 ) const { file = this->m_file; diff --git a/Fw/Test/UnitTestAssert.hpp b/Fw/Test/UnitTestAssert.hpp index 71e7d77266..8e1b5059e3 100644 --- a/Fw/Test/UnitTestAssert.hpp +++ b/Fw/Test/UnitTestAssert.hpp @@ -18,7 +18,7 @@ namespace Test { class UnitTestAssert: public Fw::AssertHook { public: #if FW_ASSERT_LEVEL == FW_FILEID_ASSERT - typedef NATIVE_UINT_TYPE File; + typedef U32 File; #else typedef String File; #endif @@ -34,24 +34,24 @@ namespace Test { FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, NATIVE_UINT_TYPE numArgs, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4, - AssertArg arg5, - AssertArg arg6 + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4, + FwAssertArgType arg5, + FwAssertArgType arg6 ); // retrieves assertion failure values void retrieveAssert( File& file, NATIVE_UINT_TYPE& lineNo, NATIVE_UINT_TYPE& numArgs, - AssertArg& arg1, - AssertArg& arg2, - AssertArg& arg3, - AssertArg& arg4, - AssertArg& arg5, - AssertArg& arg6 + FwAssertArgType& arg1, + FwAssertArgType& arg2, + FwAssertArgType& arg3, + FwAssertArgType& arg4, + FwAssertArgType& arg5, + FwAssertArgType& arg6 ) const; // check whether assertion failure occurred @@ -64,12 +64,12 @@ namespace Test { File m_file; NATIVE_UINT_TYPE m_lineNo; NATIVE_INT_TYPE m_numArgs; - AssertArg m_arg1; - AssertArg m_arg2; - AssertArg m_arg3; - AssertArg m_arg4; - AssertArg m_arg5; - AssertArg m_arg6; + FwAssertArgType m_arg1; + FwAssertArgType m_arg2; + FwAssertArgType m_arg3; + FwAssertArgType m_arg4; + FwAssertArgType m_arg5; + FwAssertArgType m_arg6; // Whether an assertion failed bool m_assertFailed; diff --git a/Fw/Time/CMakeLists.txt b/Fw/Time/CMakeLists.txt index 996a2917fe..fa739f5ad6 100644 --- a/Fw/Time/CMakeLists.txt +++ b/Fw/Time/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Fw/Time/Time.cpp b/Fw/Time/Time.cpp index d75f506e17..5314f29b9d 100644 --- a/Fw/Time/Time.cpp +++ b/Fw/Time/Time.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace Fw { const Time ZERO_TIME = Time(); @@ -144,7 +144,7 @@ namespace Fw { return this->m_timeBase; } - U8 Time::getContext() const { + FwTimeContextStoreType Time::getContext() const { return this->m_timeContext; } diff --git a/Fw/Time/Time.hpp b/Fw/Time/Time.hpp index 249f389137..60591fc1fe 100644 --- a/Fw/Time/Time.hpp +++ b/Fw/Time/Time.hpp @@ -1,10 +1,9 @@ #ifndef FW_TIME_HPP #define FW_TIME_HPP -#include +#include #include #include -#include namespace Fw { class Time: public Serializable { diff --git a/Fw/Time/test/ut/TimeTest.cpp b/Fw/Time/test/ut/TimeTest.cpp index 87ffaa6311..d2b744ce1f 100644 --- a/Fw/Time/test/ut/TimeTest.cpp +++ b/Fw/Time/test/ut/TimeTest.cpp @@ -24,24 +24,41 @@ TEST(TimeTestNominal,MathTest) { Fw::Time time1; Fw::Time time2; - // Try various operations - + // Comparison time1.set(1000,1000); - time2.set(4000,2000); + time2.set(1000,1000); + ASSERT_TRUE(time1 == time2); + ASSERT_TRUE(time1 >= time2); + ASSERT_TRUE(time1 <= time2); - // test add + time1.set(1000,1000); + time2.set(2000,1000); + ASSERT_TRUE(time1 != time2); + ASSERT_TRUE(time1 < time2); + ASSERT_TRUE(time1 <= time2); + time1.set(2000,1000); + time2.set(1000,1000); + ASSERT_TRUE(time1 > time2); + ASSERT_TRUE(time1 >= time2); - // test subtract + // Addition + time1.set(1000,1000); + time2.set(4000,2000); + Fw::Time time_sum = Fw::Time::add(time1,time2); + ASSERT_EQ(time_sum.m_seconds,5000); + ASSERT_EQ(time_sum.m_useconds,3000); - // normal subtract + // Normal subtraction + time1.set(1000,1000); + time2.set(4000,2000); Fw::Time time3 = Fw::Time::sub(time2,time1); ASSERT_EQ(time3.m_timeBase,TB_NONE); ASSERT_EQ(time3.m_timeContext,0); ASSERT_EQ(time3.m_seconds,3000); ASSERT_EQ(time3.m_useconds,1000); - // rollover subtract + // Rollover subtraction time1.set(1,999999); time2.set(2,000001); time3 = Fw::Time::sub(time2,time1); diff --git a/Fw/Tlm/CMakeLists.txt b/Fw/Tlm/CMakeLists.txt index 5d29e9c576..c05d3a179d 100644 --- a/Fw/Tlm/CMakeLists.txt +++ b/Fw/Tlm/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Fw/Tlm/TlmBuffer.hpp b/Fw/Tlm/TlmBuffer.hpp index 9fc9cf6d8c..4de7a67867 100644 --- a/Fw/Tlm/TlmBuffer.hpp +++ b/Fw/Tlm/TlmBuffer.hpp @@ -12,7 +12,6 @@ #define FW_TLM_BUFFER_HPP #include -#include #include #include diff --git a/Fw/Tlm/TlmPacket.cpp b/Fw/Tlm/TlmPacket.cpp index c7806cc863..767e988089 100644 --- a/Fw/Tlm/TlmPacket.cpp +++ b/Fw/Tlm/TlmPacket.cpp @@ -4,97 +4,157 @@ * Created on: May 24, 2014 * Author: Timothy Canham */ - +#include #include #include namespace Fw { - TlmPacket::TlmPacket() : m_id(0) { + TlmPacket::TlmPacket() : m_numEntries(0) { this->m_type = FW_PACKET_TELEM; + this->m_tlmBuffer.resetSer(); } TlmPacket::~TlmPacket() { } - SerializeStatus TlmPacket::serialize(SerializeBufferBase& buffer) const { - SerializeStatus stat; -#if !FW_AMPCS_COMPATIBLE - stat = serializeBase(buffer); - if (stat != FW_SERIALIZE_OK) { + SerializeStatus TlmPacket::resetPktSer() { + this->m_tlmBuffer.resetSer(); + // reset packet count + this->m_numEntries = 0; + // make sure packet type is correct before serializing. It should + // never be anything but FW_PACKET_TELEM, so assert. + FW_ASSERT(FW_PACKET_TELEM == this->m_type,this->m_type); + // serialize descriptor + // The function serializeBase inherited from ComPacket converts this->m_type + // to type FwPacketDescriptorType and serializes the result into this->m_tlmBuffer. + return this->serializeBase(this->m_tlmBuffer); + } + + SerializeStatus TlmPacket::resetPktDeser() { + this->m_tlmBuffer.resetDeser(); + // deserialize descriptor + // The function deserializeBase inherited from ComPacket deserializes a + // value of type FwPacketDescriptorType from this->m_tlmBuffer and stores it + // into this->m_type. + Fw::SerializeStatus stat = this->deserializeBase(this->m_tlmBuffer); + if (stat != Fw::FW_SERIALIZE_OK) { + return stat; + } + // make sure that this->m_tlmBuffer stores a telemetry packet + if (this->m_type != FW_PACKET_TELEM) { + return Fw::FW_DESERIALIZE_TYPE_MISMATCH; + } + + return Fw::FW_SERIALIZE_OK; + } + + NATIVE_UINT_TYPE TlmPacket::getNumEntries() { + return this->m_numEntries; + } + + Fw::ComBuffer& TlmPacket::getBuffer() { + return this->m_tlmBuffer; + } + + void TlmPacket::setBuffer(Fw::ComBuffer& buffer) { + this->m_tlmBuffer = buffer; + } + + SerializeStatus TlmPacket::addValue(FwChanIdType id, Time& timeTag, TlmBuffer& buffer) { + // check to make sure there is room for all the fields + NATIVE_UINT_TYPE left = this->m_tlmBuffer.getBuffCapacity()-this->m_tlmBuffer.getBuffLength(); + if ( + (sizeof(FwChanIdType) + Time::SERIALIZED_SIZE + buffer.getBuffLength()) > left + ) { + return Fw::FW_SERIALIZE_NO_ROOM_LEFT; + } + + // serialize items into buffer + + // id + SerializeStatus stat = this->m_tlmBuffer.serialize(id); + if (stat != Fw::FW_SERIALIZE_OK) { return stat; } -#endif - stat = buffer.serialize(this->m_id); - if (stat != FW_SERIALIZE_OK) { + + // time tag + stat = this->m_tlmBuffer.serialize(timeTag); + if (stat != Fw::FW_SERIALIZE_OK) { return stat; } -#if !FW_AMPCS_COMPATIBLE - stat = buffer.serialize(this->m_timeTag); - if (stat != FW_SERIALIZE_OK) { + // telemetry buffer + stat = this->m_tlmBuffer.serialize(buffer.getBuffAddr(),buffer.getBuffLength(),true); + if (stat != Fw::FW_SERIALIZE_OK) { return stat; } -#endif - return buffer.serialize(this->m_tlmBuffer.getBuffAddr(),m_tlmBuffer.getBuffLength(),true); + // increment number of packets + this->m_numEntries++; + return Fw::FW_SERIALIZE_OK; } - SerializeStatus TlmPacket::deserialize(SerializeBufferBase& buffer) { + // extract telemetry value + SerializeStatus TlmPacket::extractValue(FwChanIdType &id, Time& timeTag, TlmBuffer& buffer, NATIVE_UINT_TYPE bufferSize) { + + // deserialize items out of buffer - SerializeStatus stat; -#if !FW_AMPCS_COMPATIBLE - stat = deserializeBase(buffer); - if (stat != FW_SERIALIZE_OK) { + // id + SerializeStatus stat = this->m_tlmBuffer.deserialize(id); + if (stat != Fw::FW_SERIALIZE_OK) { return stat; } -#endif - stat = buffer.deserialize(this->m_id); - if (stat != FW_SERIALIZE_OK) { + + // time tag + stat = this->m_tlmBuffer.deserialize(timeTag); + if (stat != Fw::FW_SERIALIZE_OK) { return stat; } -#if !FW_AMPCS_COMPATIBLE - stat = buffer.deserialize(this->m_timeTag); - if (stat != FW_SERIALIZE_OK) { + // telemetry buffer + stat = this->m_tlmBuffer.deserialize(buffer.getBuffAddr(),bufferSize,true); + if (stat != Fw::FW_SERIALIZE_OK) { return stat; } -#endif - // remainder of buffer must be telemetry value - NATIVE_UINT_TYPE size = buffer.getBuffLeft(); - stat = buffer.deserialize(this->m_tlmBuffer.getBuffAddr(),size,true); - if (stat == FW_SERIALIZE_OK) { - // Shouldn't fail - stat = this->m_tlmBuffer.setBuffLen(size); - FW_ASSERT(stat == FW_SERIALIZE_OK,static_cast(stat)); + // set buffer size + stat = buffer.setBuffLen(bufferSize); + if (stat != Fw::FW_SERIALIZE_OK) { + return stat; } - return stat; - } - void TlmPacket::setId(FwChanIdType id) { - this->m_id = id; - } - - void TlmPacket::setTlmBuffer(TlmBuffer& buffer) { - this->m_tlmBuffer = buffer; - } + return Fw::FW_SERIALIZE_OK; - void TlmPacket::setTimeTag(Time& timeTag) { - this->m_timeTag = timeTag; } - FwChanIdType TlmPacket::getId() { - return this->m_id; + SerializeStatus TlmPacket::serialize(SerializeBufferBase& buffer) const { + // serialize the number of packets + SerializeStatus stat = buffer.serialize(this->m_numEntries); + if (stat != Fw::FW_SERIALIZE_OK) { + return stat; + } + // Serialize the ComBuffer + return buffer.serialize(this->m_tlmBuffer.getBuffAddr(),m_tlmBuffer.getBuffLength(),true); } - Time& TlmPacket::getTimeTag() { - return this->m_timeTag; - } + SerializeStatus TlmPacket::deserialize(SerializeBufferBase& buffer) { - TlmBuffer& TlmPacket::getTlmBuffer() { - return this->m_tlmBuffer; + // deserialize the number of packets + SerializeStatus stat = buffer.deserialize(this->m_numEntries); + if (stat != Fw::FW_SERIALIZE_OK) { + return stat; + } + // deserialize the channel value entry buffers + NATIVE_UINT_TYPE size = buffer.getBuffLeft(); + stat = buffer.deserialize(this->m_tlmBuffer.getBuffAddr(),size,true); + if (stat == FW_SERIALIZE_OK) { + // Shouldn't fail + stat = this->m_tlmBuffer.setBuffLen(size); + FW_ASSERT(stat == FW_SERIALIZE_OK,static_cast(stat)); + } + return stat; } } /* namespace Fw */ diff --git a/Fw/Tlm/TlmPacket.hpp b/Fw/Tlm/TlmPacket.hpp index cea77730da..3459ef7e7e 100644 --- a/Fw/Tlm/TlmPacket.hpp +++ b/Fw/Tlm/TlmPacket.hpp @@ -10,6 +10,7 @@ #include #include +#include #include namespace Fw { @@ -17,25 +18,35 @@ namespace Fw { class TlmPacket : public ComPacket { public: + //! Constructor TlmPacket(); + //! Destructor virtual ~TlmPacket(); + //! Serialize the packet before sending. For use internally in software. To send to the ground, use getBuffer() below. SerializeStatus serialize(SerializeBufferBase& buffer) const; //!< serialize contents - // Buffer containing value must be remainder of buffer + //! Deserialize the packet. For use internally in software. To extract channels, use setBuffer() and extractValue() below. This is NOT typically used. SerializeStatus deserialize(SerializeBufferBase& buffer); - // setters - void setId(FwChanIdType id); - void setTlmBuffer(TlmBuffer& buffer); - void setTimeTag(Time& timeTag); - // getters - FwChanIdType getId(); - Time& getTimeTag(); - TlmBuffer& getTlmBuffer(); - - PROTECTED: - FwChanIdType m_id; // !< Channel id - Fw::Time m_timeTag; // !< time tag - TlmBuffer m_tlmBuffer; // !< serialized data + //! Add telemetry value to buffer. + SerializeStatus addValue(FwChanIdType id, Time& timeTag, TlmBuffer& buffer); + //! extract telemetry value - since there are potentially multiple channel values in the packet, + //! the size of the entry must be known + SerializeStatus extractValue(FwChanIdType &id, Time& timeTag, TlmBuffer& buffer, NATIVE_UINT_TYPE bufferSize); + + //! Reset serialization of values. This should be done when starting to accumulate a new set of values. + SerializeStatus resetPktSer(); + //! Reset deserialization. This should be done before extracting values. + SerializeStatus resetPktDeser(); + //! get buffer to send to the ground + Fw::ComBuffer& getBuffer(); + //! set the internal buffer for deserializing values + void setBuffer(Fw::ComBuffer& buffer); + //! get the number of packets added via addValue() + NATIVE_UINT_TYPE getNumEntries(); + + PRIVATE: + ComBuffer m_tlmBuffer; //!< serialized data + NATIVE_UINT_TYPE m_numEntries; //!< number of entries stored during addValue() }; } /* namespace Fw */ diff --git a/Fw/Tlm/TlmString.hpp b/Fw/Tlm/TlmString.hpp index 10977deb0b..e9a1a988b8 100644 --- a/Fw/Tlm/TlmString.hpp +++ b/Fw/Tlm/TlmString.hpp @@ -1,9 +1,8 @@ #ifndef FW_TLM_STRING_TYPE_HPP #define FW_TLM_STRING_TYPE_HPP -#include -#include #include +#include #include namespace Fw { diff --git a/Fw/Tlm/docs/sdd.md b/Fw/Tlm/docs/sdd.md index 963ccf91e7..b7e890a3f9 100644 --- a/Fw/Tlm/docs/sdd.md +++ b/Fw/Tlm/docs/sdd.md @@ -17,16 +17,46 @@ The `Fw::Tlm` port has the following port diagram: #### 2.1.2 Serializables -##### 2.1.2.1 Fw::ComPacket +##### 2.1.2.1 Fw::ComBuffer -The `Fw::TlmPacket` class is a packet class derived from [`Fw::ComPacket`](../../Com/docs/sdd.html) that provides methods for encoding a telemetry packet. +The `Fw::TlmBuffer` class contains a buffer that holds the serialized value of a telemetry channel. This buffer is passed as an argument to the `Fw::Tlm` port. -##### 2.1.2.2 Fw::ComBuffer +##### 2.1.2.2 Fw::ComPacket -The `Fw::TlmBuffer` class contains a buffer that holds the serialized value of a telemetry channel. This buffer is passed as an argument to the `Fw::Tlm` port. +The `Fw::TlmPacket` class is a packet class derived from [`Fw::ComPacket`](../../Com/docs/sdd.md) that provides methods for encoding a telemetry packet. It contains an internal `Fw:ComBuffer` that holds serialized channel values. + +To fill a packet with telemetry values, do the following: + +1\. Instantiate an instance of the `TlmPacket` class. + +2\. Invoke the `resetPktSer()` method to start adding telemetry values. This method will empty the buffer and add the channel descriptor to the beginning. + +3\. Call the `addValue()` method with new entries until all entries are added or until the method returns the `Fw::FW_SERIALIZE_NO_ROOM_LEFT` status. That means that the buffer is full and the new entry was not added. + +4\. Extract the `ComBuffer` with the `getBuffer()` method and send it to the ground system. + +5\. Repeat steps 2-4 for additional channel values, not forgetting to include one potentially rejected in step 3. + +The layout of the internal `ComBuffer` is as follows: + +|Telemetry Packet Descriptor|Chan 1 ID|Chan 1 timestamp|Chan 1 Value|....|Chan N ID|Chan N timestamp|Chan N Value|Left over buffer space| +|---|---|---|---|---|---|---|----|---| + +To extract telemetry values from a packet, do the following: + +1\. Instantiate an instance of the `TlmPacket` class. + +2\. Pass it the serialized channel `ComBuffer` data via the `setBuffer()` method. + +3\. Call the `resetPktDeser()` method to start extracting data from the buffer. This will extract the packet descriptor and verify that it matches the one for telemetry. + +4\. For each telemetry entry in the packet, invoke the `extractValue()` method. Note that the users must know the size of the telemetry value (hence the `bufferSize` argument) since the buffer does not contain information on the boundaries of values. + +5\. Repeat steps 2-4 for any additional channels. The `extractValue()` method will return `Fw::FW_DESERIALIZE_BUFFER_EMPTY` when there is no more channel data in the buffer. ## 3. Change Log Date | Description ---- | ----------- 6/23/2015 | Initial Version +6/23/2022 | Updated implementation to hold multiple channel entries diff --git a/Fw/Tlm/test/ut/TlmTest.cpp b/Fw/Tlm/test/ut/TlmTest.cpp index 74cb50901a..6f4da39f9e 100644 --- a/Fw/Tlm/test/ut/TlmTest.cpp +++ b/Fw/Tlm/test/ut/TlmTest.cpp @@ -2,7 +2,7 @@ #include #include -TEST(FwTlmTest,TlmPacketSerialize) { +TEST(FwTlmTest,TlmPacketSerializeSingle) { // Serialize data @@ -10,30 +10,101 @@ TEST(FwTlmTest,TlmPacketSerialize) { Fw::TlmBuffer buffIn; ASSERT_EQ(Fw::FW_SERIALIZE_OK,buffIn.serialize(static_cast(12))); Fw::Time timeIn(TB_WORKSTATION_TIME,10,11); + U32 id = 10; - pktIn.setId(10); - pktIn.setTimeTag(timeIn); - pktIn.setTlmBuffer(buffIn); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,pktIn.resetPktSer()); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,pktIn.addValue(id,timeIn,buffIn)); - Fw::ComBuffer comBuff; - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(pktIn)); + Fw::ComBuffer comBuff = pktIn.getBuffer(); // Deserialize data Fw::TlmPacket pktOut; Fw::TlmBuffer buffOut; Fw::Time timeOut(TB_WORKSTATION_TIME,10,11); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.deserialize(pktOut)); - ASSERT_EQ(pktOut.getId(),10u); - ASSERT_EQ(pktOut.getTimeTag(),timeOut); + pktOut.setBuffer(comBuff); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,pktOut.resetPktDeser()); + // extract values + id = 0; + ASSERT_EQ(Fw::FW_SERIALIZE_OK,pktOut.extractValue(id,timeOut,buffOut,sizeof(U32))); + + ASSERT_EQ(10u,id); U32 valOut = 0; - buffOut = pktOut.getTlmBuffer(); buffOut.resetDeser(); ASSERT_EQ(Fw::FW_SERIALIZE_OK,buffOut.deserialize(valOut)); ASSERT_EQ(valOut,12u); } +TEST(FwTlmTest,TlmPacketSerializeFill) { + + // compute a single entry size assuming for the test that the value of the telemetry channel + // is a U32 + static const NATIVE_UINT_TYPE SIZE_OF_ENTRY = sizeof(FwChanIdType) + Fw::Time::SERIALIZED_SIZE + sizeof(U32); + + // compute the number of entries that should fit - will equal rounded down value of + // ComBuffer size - size of telemetry packet id / size of an entry + static const NATIVE_UINT_TYPE NUM_ENTRIES = (FW_COM_BUFFER_MAX_SIZE - sizeof(FwPacketDescriptorType))/SIZE_OF_ENTRY; + + Fw::TlmPacket pktIn; + ASSERT_EQ(Fw::FW_SERIALIZE_OK,pktIn.resetPktSer()); + + // fill a telemetry packet + + for (NATIVE_UINT_TYPE entry = 0; entry < NUM_ENTRIES; entry++) { + + // Serialize data + + Fw::TlmBuffer buffIn; + ASSERT_EQ(Fw::FW_SERIALIZE_OK,buffIn.serialize(static_cast(entry))); + Fw::Time timeIn(TB_WORKSTATION_TIME,entry+1,entry+2); + U32 id = NUM_ENTRIES-entry; + + ASSERT_EQ(Fw::FW_SERIALIZE_OK,pktIn.addValue(id,timeIn,buffIn)); + } + + // Next one should fail because it's full + { + Fw::TlmBuffer buffIn; + ASSERT_EQ(Fw::FW_SERIALIZE_OK,buffIn.serialize(static_cast(12))); + Fw::Time timeIn(TB_WORKSTATION_TIME,10,11); + U32 id = 10; + + ASSERT_EQ(Fw::FW_SERIALIZE_NO_ROOM_LEFT,pktIn.addValue(id,timeIn,buffIn)); + } + + // Create a new packet from the ComBuffer + + Fw::ComBuffer comBuff = pktIn.getBuffer(); + Fw::TlmPacket pktOut; + pktOut.setBuffer(comBuff); + ASSERT_EQ(Fw::FW_SERIALIZE_OK,pktOut.resetPktDeser()); + + // empty the packet of entries + for (NATIVE_UINT_TYPE entry = 0; entry < NUM_ENTRIES; entry++) { + // Deserialize data + Fw::TlmBuffer buffOut; + Fw::Time timeOut; + U32 id = 0; + ASSERT_EQ(Fw::FW_SERIALIZE_OK,pktOut.extractValue(id,timeOut,buffOut,sizeof(U32))); + ASSERT_EQ(NUM_ENTRIES-entry,id); + Fw::Time expTime(TB_WORKSTATION_TIME,entry+1,entry+2); + ASSERT_EQ(expTime,timeOut); + U32 val = 0; + ASSERT_EQ(Fw::FW_SERIALIZE_OK,buffOut.deserialize(val)); + ASSERT_EQ(entry,val); + } + + // try to extract one more, should fail + { + Fw::TlmBuffer buffOut; + Fw::Time timeOut; + U32 id = 0; + ASSERT_EQ(Fw::FW_DESERIALIZE_BUFFER_EMPTY,pktOut.extractValue(id,timeOut,buffOut,sizeof(U32))); + } + +} + int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/Fw/Trap/TrapHandler.hpp b/Fw/Trap/TrapHandler.hpp index 09ee8bf60e..004b1f0acd 100644 --- a/Fw/Trap/TrapHandler.hpp +++ b/Fw/Trap/TrapHandler.hpp @@ -1,7 +1,6 @@ #ifndef FW_TRAP_HPP #define FW_TRAP_HPP #include -#include namespace Fw { /** diff --git a/Fw/Types/Assert.cpp b/Fw/Types/Assert.cpp index af6deb0327..a9133ff793 100644 --- a/Fw/Types/Assert.cpp +++ b/Fw/Types/Assert.cpp @@ -10,9 +10,9 @@ #else #if FW_ASSERT_LEVEL == FW_FILEID_ASSERT -#define fileIdFs "Assert file ID 0x%08X: Line: %d " +#define fileIdFs "Assert file ID 0x%08" PRIx32 ": Line: %" PRI_PlatformUIntType #else -#define fileIdFs "Assert file \"%s\": Line: %d " +#define fileIdFs "Assert file \"%s\": Line: %" PRI_PlatformUIntType #endif namespace Fw { @@ -26,43 +26,84 @@ namespace Fw { FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, NATIVE_UINT_TYPE numArgs, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4, - AssertArg arg5, - AssertArg arg6, + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4, + FwAssertArgType arg5, + FwAssertArgType arg6, CHAR* destBuffer, NATIVE_INT_TYPE buffSize ) { switch (numArgs) { case 0: - (void)snprintf(destBuffer,buffSize,fileIdFs,file,lineNo); + (void) snprintf(destBuffer, buffSize, fileIdFs, file, lineNo); break; case 1: - (void)snprintf(destBuffer,buffSize,fileIdFs "%d",file,lineNo, - arg1); + (void) snprintf( + destBuffer, + buffSize, + fileIdFs " %" PRI_FwAssertArgType, + file, + lineNo, + arg1 + ); break; case 2: - (void)snprintf(destBuffer,buffSize,fileIdFs "%d %d",file,lineNo, - arg1,arg2); + (void) snprintf( + destBuffer, + buffSize, + fileIdFs " %" PRI_FwAssertArgType " %" PRI_FwAssertArgType, + file, + lineNo, + arg1, arg2 + ); break; case 3: - (void)snprintf(destBuffer,buffSize,fileIdFs "%d %d %d",file,lineNo, - arg1,arg2,arg3); + (void) snprintf( + destBuffer, + buffSize, + fileIdFs " %" PRI_FwAssertArgType " %" PRI_FwAssertArgType + " %" PRI_FwAssertArgType, + file, + lineNo, + arg1, arg2, arg3 + ); break; case 4: - (void)snprintf(destBuffer,buffSize,fileIdFs "%d %d %d %d",file,lineNo, - arg1,arg2,arg3,arg4); + (void) snprintf( + destBuffer, + buffSize, + fileIdFs " %" PRI_FwAssertArgType " %" PRI_FwAssertArgType + " %" PRI_FwAssertArgType " %" PRI_FwAssertArgType, + file, + lineNo, + arg1, arg2, arg3, arg4); break; case 5: - (void)snprintf(destBuffer,buffSize,fileIdFs "%d %d %d %d %d",file,lineNo, - arg1,arg2,arg3,arg4,arg5); + (void) snprintf( + destBuffer, + buffSize, + fileIdFs " %" PRI_FwAssertArgType " %" PRI_FwAssertArgType + " %" PRI_FwAssertArgType " %" PRI_FwAssertArgType + " %" PRI_FwAssertArgType, + file, + lineNo, + arg1, arg2, arg3, arg4, arg5 + ); break; case 6: - (void)snprintf(destBuffer,buffSize,fileIdFs "%d %d %d %d %d %d",file,lineNo, - arg1,arg2,arg3,arg4,arg5,arg6); + (void) snprintf( + destBuffer, + buffSize, + fileIdFs " %" PRI_FwAssertArgType " %" PRI_FwAssertArgType + " %" PRI_FwAssertArgType " %" PRI_FwAssertArgType + " %" PRI_FwAssertArgType " %" PRI_FwAssertArgType, + file, + lineNo, + arg1, arg2, arg3, arg4, arg5, arg6 + ); break; default: // in an assert already, what can we do? break; @@ -82,12 +123,12 @@ namespace Fw { FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, NATIVE_UINT_TYPE numArgs, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4, - AssertArg arg5, - AssertArg arg6 + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4, + FwAssertArgType arg5, + FwAssertArgType arg6 ) { CHAR destBuffer[FW_ASSERT_DFL_MSG_LEN]; @@ -149,7 +190,7 @@ namespace Fw { } NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, - AssertArg arg1) { + FwAssertArgType arg1) { if (nullptr == s_assertHook) { CHAR assertMsg[FW_ASSERT_DFL_MSG_LEN]; defaultReportAssert( @@ -174,8 +215,8 @@ namespace Fw { } NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, - AssertArg arg1, - AssertArg arg2) { + FwAssertArgType arg1, + FwAssertArgType arg2) { if (nullptr == s_assertHook) { CHAR assertMsg[FW_ASSERT_DFL_MSG_LEN]; defaultReportAssert( @@ -199,9 +240,9 @@ namespace Fw { } NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3) { + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3) { if (nullptr == s_assertHook) { CHAR assertMsg[FW_ASSERT_DFL_MSG_LEN]; defaultReportAssert( @@ -225,10 +266,10 @@ namespace Fw { } NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4) { + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4) { if (nullptr == s_assertHook) { CHAR assertMsg[FW_ASSERT_DFL_MSG_LEN]; defaultReportAssert( @@ -252,11 +293,11 @@ namespace Fw { } NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4, - AssertArg arg5) { + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4, + FwAssertArgType arg5) { if (nullptr == s_assertHook) { CHAR assertMsg[FW_ASSERT_DFL_MSG_LEN]; defaultReportAssert( @@ -280,12 +321,12 @@ namespace Fw { } NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4, - AssertArg arg5, - AssertArg arg6) { + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4, + FwAssertArgType arg5, + FwAssertArgType arg6) { if (nullptr == s_assertHook) { CHAR assertMsg[FW_ASSERT_DFL_MSG_LEN]; defaultReportAssert( diff --git a/Fw/Types/Assert.hpp b/Fw/Types/Assert.hpp index 2ccea32f04..bf1d4264ac 100644 --- a/Fw/Types/Assert.hpp +++ b/Fw/Types/Assert.hpp @@ -2,22 +2,27 @@ #define FW_ASSERT_HPP #include -#include #if FW_ASSERT_LEVEL == FW_NO_ASSERT -#define FW_ASSERT(...) + #define FW_ASSERT(...) #else // ASSERT is defined + #if FW_ASSERT_LEVEL == FW_FILEID_ASSERT -#define FILE_NAME_ARG NATIVE_UINT_TYPE -#define FW_ASSERT(cond, ...) \ - ((void) ((cond) ? (0) : \ - (Fw::SwAssert(ASSERT_FILE_ID, __LINE__, ##__VA_ARGS__)))) + #define FILE_NAME_ARG U32 + #define FW_ASSERT(cond, ...) \ + ((void) ((cond) ? (0) : \ + (Fw::SwAssert(ASSERT_FILE_ID, __LINE__, ##__VA_ARGS__)))) +#elif FW_ASSERT_LEVEL == FW_RELATIVE_PATH_ASSERT + #define FILE_NAME_ARG const CHAR* + #define FW_ASSERT(cond, ...) \ + ((void) ((cond) ? (0) : \ + (Fw::SwAssert(ASSERT_RELATIVE_PATH, __LINE__, ##__VA_ARGS__)))) #else -#define FILE_NAME_ARG const CHAR* -#define FW_ASSERT(cond, ...) \ - ((void) ((cond) ? (0) : \ - (Fw::SwAssert(__FILE__, __LINE__, ##__VA_ARGS__)))) + #define FILE_NAME_ARG const CHAR* + #define FW_ASSERT(cond, ...) \ + ((void) ((cond) ? (0) : \ + (Fw::SwAssert(__FILE__, __LINE__, ##__VA_ARGS__)))) #endif // F' Assertion functions can technically return even though the intention is for the assertion to terminate the program. @@ -36,12 +41,12 @@ namespace Fw { NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo) CLANG_ANALYZER_NORETURN; //!< Assert with no arguments - NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, AssertArg arg1) CLANG_ANALYZER_NORETURN; //!< Assert with one argument - NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, AssertArg arg1, AssertArg arg2) CLANG_ANALYZER_NORETURN; //!< Assert with two arguments - NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, AssertArg arg1, AssertArg arg2, AssertArg arg3) CLANG_ANALYZER_NORETURN; //!< Assert with three arguments - NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, AssertArg arg1, AssertArg arg2, AssertArg arg3, AssertArg arg4) CLANG_ANALYZER_NORETURN; //!< Assert with four arguments - NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, AssertArg arg1, AssertArg arg2, AssertArg arg3, AssertArg arg4, AssertArg arg5) CLANG_ANALYZER_NORETURN; //!< Assert with five arguments - NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, AssertArg arg1, AssertArg arg2, AssertArg arg3, AssertArg arg4, AssertArg arg5, AssertArg arg6) CLANG_ANALYZER_NORETURN; //!< Assert with six arguments + NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, FwAssertArgType arg1) CLANG_ANALYZER_NORETURN; //!< Assert with one argument + NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, FwAssertArgType arg1, FwAssertArgType arg2) CLANG_ANALYZER_NORETURN; //!< Assert with two arguments + NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, FwAssertArgType arg1, FwAssertArgType arg2, FwAssertArgType arg3) CLANG_ANALYZER_NORETURN; //!< Assert with three arguments + NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, FwAssertArgType arg1, FwAssertArgType arg2, FwAssertArgType arg3, FwAssertArgType arg4) CLANG_ANALYZER_NORETURN; //!< Assert with four arguments + NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, FwAssertArgType arg1, FwAssertArgType arg2, FwAssertArgType arg3, FwAssertArgType arg4, FwAssertArgType arg5) CLANG_ANALYZER_NORETURN; //!< Assert with five arguments + NATIVE_INT_TYPE SwAssert(FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, FwAssertArgType arg1, FwAssertArgType arg2, FwAssertArgType arg3, FwAssertArgType arg4, FwAssertArgType arg5, FwAssertArgType arg6) CLANG_ANALYZER_NORETURN; //!< Assert with six arguments } // Base class for declaring an assert hook @@ -59,12 +64,12 @@ namespace Fw { FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, NATIVE_UINT_TYPE numArgs, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4, - AssertArg arg5, - AssertArg arg6 + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4, + FwAssertArgType arg5, + FwAssertArgType arg6 ); // default reportAssert() will call this when the message is built // override it to do another kind of print. printf by default @@ -82,8 +87,6 @@ namespace Fw { // the previous assert hook AssertHook *previousHook; }; - - } #endif // if ASSERT is defined diff --git a/Fw/Types/BasicTypes.h b/Fw/Types/BasicTypes.h new file mode 100644 index 0000000000..9a80fa10e7 --- /dev/null +++ b/Fw/Types/BasicTypes.h @@ -0,0 +1,82 @@ +/** + * \file: BasicType.h + * \author mstarch + * \brief Declares fprime basic types for usage within C language files + * + * \copyright + * Copyright 2009-2016, by the California Institute of Technology. + * ALL RIGHTS RESERVED. United States Government Sponsorship + * acknowledged. + * + */ +#include +#ifndef FW_BASIC_TYPES_H +#define FW_BASIC_TYPES_H + +// Compiler checks +#if defined(__GNUC__) || defined(__llvm__) || defined(PLATFORM_OVERRIDE_GCC_CLANG_CHECK) +#else +#error Unsupported compiler! +#endif + +/*----------------------------------------------------------------------------*/ +/* Type definitions: I8, U8, I16, U16, ..., I64, U64, F32, and F64 */ +/*----------------------------------------------------------------------------*/ +typedef int8_t I8; //!< 8-bit signed integer +typedef uint8_t U8; //!< 8-bit unsigned integer +typedef U8 BYTE; //!< byte type +typedef char CHAR; + +#if FW_HAS_16_BIT +typedef int16_t I16; //!< 16-bit signed integer +typedef uint16_t U16; //!< 16-bit unsigned integer +#endif + +#if FW_HAS_32_BIT +typedef uint32_t U32; //!< 32-bit signed integer +typedef int32_t I32; //!< 32-bit unsigned integer +#endif + +#if FW_HAS_64_BIT +typedef int64_t I64; //!< 64-bit signed integer +typedef uint64_t U64; //!< 64-bit unsigned integer +#endif + +typedef float F32; //!< 32-bit floating point +#if FW_HAS_F64 +typedef double F64; //!< 64-bit floating point +#endif + +// Backwards-compatibility definitions +typedef PlatformIntType NATIVE_INT_TYPE; +typedef PlatformUIntType NATIVE_UINT_TYPE; +typedef PlatformPointerCastType POINTER_CAST; + +/*----------------------------------------------------------------------------*/ +/* Useful macro definitions */ +/*----------------------------------------------------------------------------*/ +#define FW_NO_ASSERT 1 //!< Asserts turned off +#define FW_FILEID_ASSERT \ + 2 //!< File ID used - requires -DASSERT_FILE_ID=somevalue to be set on the compile command line +#define FW_FILENAME_ASSERT 3 //!< Uses the file path in the assert - image stores filenames +#define FW_RELATIVE_PATH_ASSERT \ + 4 //!< Uses a relative file path (within fprime/fprime library) for assert. - requires -DASSERT_RELATIVE_PATH=path + //!< to be set on the compile command line + +#define FW_NUM_ARRAY_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) //!< number of elements in an array +#define FW_MAX(a, b) (((a) > (b)) ? (a) : (b)) //!< MAX macro +#define FW_MIN(a, b) (((a) < (b)) ? (a) : (b)) //!< MIN macro + +#ifndef STATIC +#define STATIC static //!< static for non unit-test code +#endif + +#ifndef PROTECTED +#define PROTECTED protected //!< overridable protected for unit testing +#endif + +#ifndef PRIVATE +#define PRIVATE private //!< overridable private for unit testing +#endif + +#endif // FW_BASIC_TYPES_H diff --git a/Fw/Types/BasicTypes.hpp b/Fw/Types/BasicTypes.hpp index 7b01d0e9d5..ec5f578ee9 100644 --- a/Fw/Types/BasicTypes.hpp +++ b/Fw/Types/BasicTypes.hpp @@ -1,124 +1,31 @@ /** - * \file - * \author T. Canham - * \brief Declares ISF basic types + * \file: BasicTypes.hpp + * \author mstarch + * \brief C++ header for working with basic fprime types * * \copyright * Copyright 2009-2016, by the California Institute of Technology. * ALL RIGHTS RESERVED. United States Government Sponsorship * acknowledged. - * */ +#include +// Use C linkage for the basic items +extern "C" { +#include "BasicTypes.h" +}; #ifndef FW_BASIC_TYPES_HPP #define FW_BASIC_TYPES_HPP -#include -#include // This header will be found be include paths by target. This hides different header files for each target. -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -// Define native integer/unsigned integer types -#ifdef _WRS_KERNEL -typedef int32_t NATIVE_INT_TYPE; -typedef uint32_t NATIVE_UINT_TYPE; -#else -// Allow overriding of native types for systems whose stdint.h is malformed -#ifndef FPRIME_OVERRIDE_NATIVE_TYPES -typedef int NATIVE_INT_TYPE; //!< native integer type declaration -typedef unsigned int NATIVE_UINT_TYPE; //!< native unsigned integer type declaration -#endif -#endif - -#if defined __GNUC__ || __llvm__ - -// This is used to cast pointers to integers -// when a pointer needs to be stored generically. -// In order to avoid chopping off bits, -// the integer bit size needs to match -// the pointer bit size. - -#ifdef __SIZEOF_POINTER__ - #if __SIZEOF_POINTER__ == 8 - #define POINTER_CAST U64 - #elif __SIZEOF_POINTER__ == 4 - #define POINTER_CAST U32 - #elif __SIZEOF_POINTER__ == 2 - #define POINTER_CAST U16 - #else - #define POINTER_CAST U8 - #endif -#elif defined (__i386) && __i386 == 1 // GCC 4.1.2 - #define POINTER_CAST U32 -#elif defined (__x86_64) && __x86_64 == 1 // GCC 4.1.2 - #define POINTER_CAST U64 -#elif defined (CPU) && defined (PPC604) && CPU == PPC604 // VxWorks 6.7 RAD750 - #define POINTER_CAST U32 -#elif defined (CPU) && defined(SPARC) && CPU == SPARC - #define POINTER_CAST U32 -#else - #error Cannot get size of pointer cast! -#endif - -#else - #error Unsupported compiler! -#endif - -// compile-time assert -#define COMPILE_TIME_ASSERT( condition, name )\ - do { \ - enum { assert_failed_ ## name = 1/(condition) }; \ - } while(0) - -/*----------------------------------------------------------------------------*/ -typedef int8_t I8; //!< 8-bit signed integer -typedef uint8_t U8; //!< 8-bit unsigned integer -typedef U8 BYTE; //!< byte type - -#if FW_HAS_16_BIT - typedef int16_t I16; //!< 16-bit signed integer - typedef uint16_t U16; //!< 16-bit unsigned integer -#endif - -#if FW_HAS_32_BIT - typedef uint32_t U32; //!< 32-bit signed integer - typedef int32_t I32; //!< 32-bit unsigned integer -#endif - -#if FW_HAS_64_BIT - typedef int64_t I64; //!< 64-bit signed integer - typedef uint64_t U64; //!< 64-bit unsigned integer -#endif - -typedef float F32; //!< 32-bit floating point +// IEEE compliance checks must occur in C++ code +#if !defined(SKIP_FLOAT_IEEE_754_COMPLIANCE) || !SKIP_FLOAT_IEEE_754_COMPLIANCE +static_assert((std::numeric_limits::is_iec559 == true) && (std::numeric_limits::radix == 2) && + (std::numeric_limits::digits == 24) && (std::numeric_limits::max_exponent == 128), + "The 32-bit floating point type does not conform to the IEEE-754 standard."); #if FW_HAS_F64 - typedef double F64; //!< 64-bit floating point -#endif - -typedef char CHAR; - -#define FW_NUM_ARRAY_ELEMENTS(a) (sizeof(a)/sizeof((a)[0])) //!< number of elements in an array - -#define FW_MAX(a,b) (((a) > (b))?(a):(b)) //!< MAX macro -#define FW_MIN(a,b) (((a) < (b))?(a):(b)) //!< MIN macro - -// STATIC for C builds -#ifndef STATIC -#define STATIC static //!< static for non unit-test code -#endif - -#ifndef PROTECTED -#define PROTECTED protected //!< overridable protected for unit testing -#endif - -#ifndef PRIVATE -#define PRIVATE private //!< overridable private for unit testing +static_assert((std::numeric_limits::is_iec559 == true) && (std::numeric_limits::radix == 2) && + (std::numeric_limits::digits == 53) && (std::numeric_limits::max_exponent == 1024), + "The 64-bit floating point type does not conform to the IEEE-754 standard."); #endif - -#ifdef __cplusplus -} // extern "C" - -#endif // __cplusplus - #endif +#endif // End FW_BASIC_TYPES_HPP diff --git a/Fw/Types/ByteArray.hpp b/Fw/Types/ByteArray.hpp index 701bab4395..206dfba66c 100644 --- a/Fw/Types/ByteArray.hpp +++ b/Fw/Types/ByteArray.hpp @@ -13,7 +13,7 @@ #ifndef Fw_ByteArray_HPP #define Fw_ByteArray_HPP -#include "Fw/Types/BasicTypes.hpp" +#include namespace Fw { diff --git a/Fw/Types/CAssert.h b/Fw/Types/CAssert.h new file mode 100644 index 0000000000..857e3ffa69 --- /dev/null +++ b/Fw/Types/CAssert.h @@ -0,0 +1,31 @@ +/* + * FwCAssert.hpp + * + * Created on: Jun 8, 2014 + * Author: tcanham + */ + +#ifndef FWCASSERT_HPP_ +#define FWCASSERT_HPP_ + +#include + +#if FW_ASSERT_LEVEL == FW_NO_ASSERT + +#define FW_CASSERT(...) + +#else // ASSERT is defined + +#if FW_ASSERT_LEVEL == FW_FILEID_ASSERT +#define FILE_NAME_ARG NATIVE_UINT_TYPE +#define FW_CASSERT(cond) ((void)((cond) ? (0) : (CAssert0(ASSERT_FILE_ID, __LINE__)))) +#else +#define FILE_NAME_ARG const U8* +#define FW_CASSERT(cond) ((void)((cond) ? (0) : (CAssert0((FILE_NAME_ARG)(__FILE__), __LINE__)))) +#endif + +I32 CAssert0(FILE_NAME_ARG file, U32 lineNo); //!< C assert function +I32 CAssert1(FILE_NAME_ARG file, U32 lineNo, NATIVE_INT_TYPE arg1); //!< C assert function 1 + +#endif // ASSERT is defined +#endif /* FWCASSERT_HPP_ */ diff --git a/Fw/Types/CAssert.hpp b/Fw/Types/CAssert.hpp deleted file mode 100644 index 83392cfa66..0000000000 --- a/Fw/Types/CAssert.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * FwCAssert.hpp - * - * Created on: Jun 8, 2014 - * Author: tcanham - */ - -#ifndef FWCASSERT_HPP_ -#define FWCASSERT_HPP_ - -#include -#include - -#if FW_ASSERT_LEVEL == FW_NO_ASSERT - -#define FW_CASSERT(...) - -#else // ASSERT is defined - -#if FW_ASSERT_LEVEL == FW_FILEID_ASSERT -#define FILE_NAME_ARG NATIVE_UINT_TYPE -#define FW_CASSERT(cond) \ - ((void) ((cond) ? (0) : \ - (CAssert0(ASSERT_FILE_ID, __LINE__)))) -#else -#define FILE_NAME_ARG const U8* -#define FW_CASSERT(cond) \ - ((void) ((cond) ? (0) : \ - (CAssert0((FILE_NAME_ARG)(__FILE__), __LINE__)))) -#endif - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -I32 CAssert0(FILE_NAME_ARG file, U32 lineNo); //!< C assert function -I32 CAssert1(FILE_NAME_ARG file, U32 lineNo, NATIVE_INT_TYPE arg1); //!< C assert function 1 - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - - - -#endif // ASSERT is defined -#endif /* FWCASSERT_HPP_ */ diff --git a/Fw/Types/CMakeLists.txt b/Fw/Types/CMakeLists.txt index b8d9b020ba..b9105f640c 100644 --- a/Fw/Types/CMakeLists.txt +++ b/Fw/Types/CMakeLists.txt @@ -1,13 +1,14 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME #### -set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Assert.cpp" - "${CMAKE_CURRENT_LIST_DIR}/Types.fpp" + +set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Types.fpp" + "${CMAKE_CURRENT_LIST_DIR}/Assert.cpp" "${CMAKE_CURRENT_LIST_DIR}/String.cpp" "${CMAKE_CURRENT_LIST_DIR}/InternalInterfaceString.cpp" "${CMAKE_CURRENT_LIST_DIR}/MallocAllocator.cpp" diff --git a/Fw/Types/ConstByteArray.hpp b/Fw/Types/ConstByteArray.hpp index 84e13bf33c..d1673d1568 100644 --- a/Fw/Types/ConstByteArray.hpp +++ b/Fw/Types/ConstByteArray.hpp @@ -13,7 +13,7 @@ #ifndef Fw_ConstByteArray_HPP #define Fw_ConstByteArray_HPP -#include "Fw/Types/BasicTypes.hpp" +#include namespace Fw { diff --git a/Fw/Types/EightyCharString.hpp b/Fw/Types/EightyCharString.hpp index f6ad97d5d1..48d4d893d9 100644 --- a/Fw/Types/EightyCharString.hpp +++ b/Fw/Types/EightyCharString.hpp @@ -1,7 +1,7 @@ #ifndef FW_EIGHTY_CHAR_STRING_TYPE_HPP #define FW_EIGHTY_CHAR_STRING_TYPE_HPP -#include +#include #include #include diff --git a/Fw/Types/GTest/Bytes.hpp b/Fw/Types/GTest/Bytes.hpp index 481989e783..0bc64b4273 100644 --- a/Fw/Types/GTest/Bytes.hpp +++ b/Fw/Types/GTest/Bytes.hpp @@ -14,7 +14,7 @@ #define Fw_GTest_Bytes_HPP #include -#include +#include namespace Fw { diff --git a/Fw/Types/GTest/CMakeLists.txt b/Fw/Types/GTest/CMakeLists.txt index 8e864435f6..5b8dfb8ba2 100644 --- a/Fw/Types/GTest/CMakeLists.txt +++ b/Fw/Types/GTest/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Fw/Types/InternalInterfaceString.hpp b/Fw/Types/InternalInterfaceString.hpp index 87505c5ff0..f8b9628100 100644 --- a/Fw/Types/InternalInterfaceString.hpp +++ b/Fw/Types/InternalInterfaceString.hpp @@ -1,10 +1,9 @@ #ifndef FW_INTERNAL_INTERFACE_STRING_TYPE_HPP #define FW_INTERNAL_INTERFACE_STRING_TYPE_HPP -#include +#include #include #include -#include namespace Fw { diff --git a/Fw/Types/Linux/StandardTypes.hpp b/Fw/Types/Linux/StandardTypes.hpp deleted file mode 100644 index 256a908d27..0000000000 --- a/Fw/Types/Linux/StandardTypes.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#include -#include diff --git a/Fw/Types/MemAllocator.hpp b/Fw/Types/MemAllocator.hpp index 0d3fbac60d..d352a4a073 100644 --- a/Fw/Types/MemAllocator.hpp +++ b/Fw/Types/MemAllocator.hpp @@ -16,7 +16,7 @@ #ifndef TYPES_MEMALLOCATOR_HPP_ #define TYPES_MEMALLOCATOR_HPP_ -#include +#include /*! * @@ -27,7 +27,9 @@ * appropriate. * * The identifier can be used to look up a pre-allocated buffer by ID in an - * embedded system. + * embedded system. Identifiers may be used only in a single call to an invocation. + * Some implementations of MemAllocator discard the identifier but components using + * the MemAllocator interface should not depend on the identifier to be discarded. * * The size is the requested size of the memory. If the allocator cannot return the * requested amount, it should return the actual amount and users should check. @@ -45,7 +47,7 @@ namespace Fw { public: //! Allocate memory /*! - * \param identifier the memory segment identifier (if needed) + * \param identifier the memory segment identifier, each identifier is to be used in once single allocation * \param size the requested size - changed to actual if different * \param recoverable - flag to indicate the memory could be recoverable * \return the pointer to memory. Zero if unable to allocate @@ -56,7 +58,7 @@ namespace Fw { bool& recoverable)=0; //! Deallocate memory /*! - * \param identifier the memory segment identifier (if needed) + * \param identifier the memory segment identifier, each identifier is to be used in once single allocation * \param ptr the pointer to memory returned by allocate() */ virtual void deallocate( diff --git a/Fw/Types/PolyType.cpp b/Fw/Types/PolyType.cpp index 0a5492b956..32c2eeb702 100644 --- a/Fw/Types/PolyType.cpp +++ b/Fw/Types/PolyType.cpp @@ -2,7 +2,6 @@ #include #include #define __STDC_FORMAT_MACROS -#include namespace Fw { @@ -411,7 +410,7 @@ namespace Fw { valIsEqual = false; break; default: - FW_ASSERT(0,static_cast(this->m_dataType)); + FW_ASSERT(0,static_cast(this->m_dataType)); return false; // for compiler } return valIsEqual; @@ -474,7 +473,7 @@ namespace Fw { result = false; break; default: - FW_ASSERT(0,static_cast(this->m_dataType)); + FW_ASSERT(0,static_cast(this->m_dataType)); return false; // for compiler } return result; @@ -534,6 +533,8 @@ namespace Fw { case TYPE_I64: stat = buffer.serialize(this->m_val.i64Val); break; +#endif +#if FW_HAS_F64 case TYPE_F64: stat = buffer.serialize(this->m_val.f64Val); break; @@ -587,6 +588,8 @@ namespace Fw { return buffer.deserialize(this->m_val.u64Val); case TYPE_I64: return buffer.deserialize(this->m_val.i64Val); +#endif +#if FW_HAS_F64 case TYPE_F64: return buffer.deserialize(this->m_val.f64Val); #endif diff --git a/Fw/Types/PolyType.hpp b/Fw/Types/PolyType.hpp index 29d616c928..5f24b4813d 100644 --- a/Fw/Types/PolyType.hpp +++ b/Fw/Types/PolyType.hpp @@ -1,10 +1,9 @@ #ifndef FW_POLY_TYPE_HPP #define FW_POLY_TYPE_HPP -#include +#include #include #include -#include #include namespace Fw { @@ -93,7 +92,7 @@ namespace Fw { PolyType(const PolyType &original); //!< copy constructor virtual ~PolyType(); //!< destructor -#if FW_SERIALIZABLE_TO_STRING +#if FW_SERIALIZABLE_TO_STRING || BUILD_UT void toString(StringBase& dest, bool append) const; //!< get string representation void toString(StringBase& dest) const; //!< get string representation #endif @@ -114,14 +113,22 @@ namespace Fw { TYPE_NOTYPE, // !< No type stored yet TYPE_U8, // !< U8 type stored TYPE_I8, // !< I8 type stored +#if FW_HAS_16_BIT TYPE_U16, // !< U16 type stored TYPE_I16, // !< I16 type stored +#endif +#if FW_HAS_32_BIT TYPE_U32, // !< U32 type stored TYPE_I32, // !< I32 type stored +#endif +#if FW_HAS_64_BIT TYPE_U64, // !< U64 type stored TYPE_I64, // !< I64 type stored +#endif TYPE_F32, // !< F32 type stored +#if FW_HAS_F64 TYPE_F64, // !< F64 type stored +#endif TYPE_BOOL, // !< bool type stored TYPE_PTR // !< pointer type stored } Type; diff --git a/Fw/Types/SerialBuffer.hpp b/Fw/Types/SerialBuffer.hpp index 97b935f904..f10b245f9d 100644 --- a/Fw/Types/SerialBuffer.hpp +++ b/Fw/Types/SerialBuffer.hpp @@ -13,7 +13,7 @@ #ifndef Fw_SerialBuffer_HPP #define Fw_SerialBuffer_HPP -#include "Fw/Types/BasicTypes.hpp" +#include #include "Fw/Types/Serializable.hpp" namespace Fw { diff --git a/Fw/Types/Serializable.cpp b/Fw/Types/Serializable.cpp index d2afac76b9..ec67ea618d 100644 --- a/Fw/Types/Serializable.cpp +++ b/Fw/Types/Serializable.cpp @@ -3,7 +3,7 @@ #include #include #include - +#include #ifdef BUILD_UT #include #include @@ -19,7 +19,7 @@ namespace Fw { Serializable::~Serializable() { } -#if FW_SERIALIZABLE_TO_STRING || BUILD_UT +#if FW_SERIALIZABLE_TO_STRING || FW_ENABLE_TEXT_LOGGING || BUILD_UT void Serializable::toString(StringBase& text) const { text = "NOSPEC"; // set to not specified. @@ -186,7 +186,7 @@ namespace Fw { } #endif -#if FW_HAS_F64 +#if FW_HAS_F64 && FW_HAS_64_BIT SerializeStatus SerializeBufferBase::serialize(F64 val) { // floating point values need to be byte-swapped as well, so copy to U64 and use that routine diff --git a/Fw/Types/Serializable.hpp b/Fw/Types/Serializable.hpp index 3a099d2fd6..42048edadc 100644 --- a/Fw/Types/Serializable.hpp +++ b/Fw/Types/Serializable.hpp @@ -5,12 +5,11 @@ #include #endif -#include +#include namespace Fw { class StringBase; //!< forward declaration for string - typedef enum { FW_SERIALIZE_OK, //!< Serialization/Deserialization operation was successful FW_SERIALIZE_FORMAT_ERROR, //!< Data was the wrong format (e.g. wrong packet type) @@ -20,14 +19,13 @@ namespace Fw { FW_DESERIALIZE_SIZE_MISMATCH, //!< Data was left in the buffer, but not enough to deserialize FW_DESERIALIZE_TYPE_MISMATCH //!< Deserialized type ID didn't match } SerializeStatus; - class SerializeBufferBase; //!< forward declaration class Serializable { public: virtual SerializeStatus serialize(SerializeBufferBase& buffer) const = 0; //!< serialize contents virtual SerializeStatus deserialize(SerializeBufferBase& buffer) = 0; //!< deserialize to contents -#if FW_SERIALIZABLE_TO_STRING || BUILD_UT +#if FW_SERIALIZABLE_TO_STRING || FW_ENABLE_TEXT_LOGGING || BUILD_UT virtual void toString(StringBase& text) const; //!< generate text from serializable #endif diff --git a/Fw/Types/String.hpp b/Fw/Types/String.hpp index b9b60064d1..4c829f63a6 100644 --- a/Fw/Types/String.hpp +++ b/Fw/Types/String.hpp @@ -1,7 +1,7 @@ #ifndef FW_FIXED_LENGTH_STRING_TYPE_HPP #define FW_FIXED_LENGTH_STRING_TYPE_HPP -#include +#include #include #include diff --git a/Fw/Types/StringType.hpp b/Fw/Types/StringType.hpp index f411df79d2..4264e3fc96 100644 --- a/Fw/Types/StringType.hpp +++ b/Fw/Types/StringType.hpp @@ -13,7 +13,7 @@ #ifndef FW_STRING_TYPE_HPP #define FW_STRING_TYPE_HPP -#include +#include #include #ifdef BUILD_UT #include diff --git a/Fw/Types/StringUtils.hpp b/Fw/Types/StringUtils.hpp index d0aaba021a..26ecc8fceb 100644 --- a/Fw/Types/StringUtils.hpp +++ b/Fw/Types/StringUtils.hpp @@ -1,6 +1,6 @@ #ifndef FW_STRINGUTILS_HPP #define FW_STRINGUTILS_HPP -#include "Fw/Types/BasicTypes.hpp" +#include namespace Fw { namespace StringUtils { diff --git a/Fw/Types/Types.fpp b/Fw/Types/Types.fpp index bdfcf32a83..560f0e8e30 100644 --- a/Fw/Types/Types.fpp +++ b/Fw/Types/Types.fpp @@ -28,4 +28,47 @@ module Fw { ENABLED @< Enabled state } + @ On and off states + enum On { + OFF @< Off state + ON @< On state + } + + @ Logic states + enum Logic { + LOW @< Logic low state + HIGH @< Logic high state + } + + @ Open and closed states + enum Open { + CLOSED @< Closed state + OPEN @< Open state + } + + @ Direction states + enum Direction { + IN @< In direction + OUT @< Out direction + INOUT @< In/Out direction + } + + @ Active and inactive states + enum Active { + INACTIVE @< Inactive state + ACTIVE @< Active state + } + + @ Health states + enum Health { + HEALTHY @< Healthy state + SICK @< Sick state + FAILED @< Failed state + } + + @ Success/Failure + enum Success { + FAILURE @< Representing failure + SUCCESS @< Representing success + } } diff --git a/Fw/Types/VxWorks/StandardTypes.hpp b/Fw/Types/VxWorks/StandardTypes.hpp deleted file mode 100644 index ce32a75345..0000000000 --- a/Fw/Types/VxWorks/StandardTypes.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef VXWORKS_STD_TYPES_H -#define VXWORKS_STD_TYPES_H - -#include -#include - -// Covert VxWorks OK and ERROR macros to enums -enum { - VXWORKS_OK = OK, - VXWORKS_ERROR = ERROR -}; -#undef OK -#undef ERROR -enum { - OK = VXWORKS_OK, - ERROR = VXWORKS_ERROR -}; - -#endif diff --git a/Fw/Types/default/DefaultTypes.hpp b/Fw/Types/default/DefaultTypes.hpp new file mode 100644 index 0000000000..7815fda0f3 --- /dev/null +++ b/Fw/Types/default/DefaultTypes.hpp @@ -0,0 +1,97 @@ +/** + * \brief DefaultTypes.hpp provides fallback defaults for the platform types + * + * This fill contains default implementations for types typically defined in + * PlatformTypes.hpp. These default implementations are based on x86_64 Linux + * but are often appropriate for most systems. + */ +#include +/** +* Default implementation for deprecated (see note) + */ +#ifndef PLATFORM_INT_TYPE_DEFINED +typedef int PlatformIntType; +extern const PlatformIntType PlatformIntType_MIN; +extern const PlatformIntType PlatformIntType_MAX; +#define PLATFORM_INT_TYPE_DEFINED +#define PRI_PlatformIntType "d" +#endif + + +/** +* Default implementation for deprecated (see note) + */ +#ifndef PLATFORM_UINT_TYPE_DEFINED +typedef unsigned int PlatformUIntType; +extern const PlatformUIntType PlatformUIntType_MIN; +extern const PlatformUIntType PlatformUIntType_MAX; +#define PLATFORM_UINT_TYPE_DEFINED +#define PRI_PlatformUIntType "ud" +#endif + +/** +* Default implementation for ports indices +*/ +#ifndef PLATFORM_INDEX_TYPE_DEFINED +typedef PlatformIntType PlatformIndexType; +extern const PlatformIndexType PlatformIndexType_MIN; +extern const PlatformIndexType PlatformIndexType_MAX; +#define PLATFORM_INDEX_TYPE_DEFINED +#define PRI_PlatformIndexType PRI_PlatformIntType +#endif + +/** +* Default implementation for sizes +*/ +#ifndef PLATFORM_SIZE_TYPE_DEFINED +typedef PlatformUIntType PlatformSizeType; +extern const PlatformSizeType PlatformSizeType_MIN; +extern const PlatformSizeType PlatformSizeType_MAX; +#define PLATFORM_SIZE_TYPE_DEFINED +#define PRI_PlatformSizeType PRI_PlatformUIntType +#endif + +/** +* Default implementation for argument to fw_assert +*/ +#ifndef PLATFORM_ASSERT_ARG_TYPE_DEFINED +typedef PlatformIntType PlatformAssertArgType; +extern const PlatformAssertArgType PlatformAssertArgType_MIN; +extern const PlatformAssertArgType PlatformAssertArgType_MAX; +#define PLATFORM_ASSERT_ARG_TYPE_DEFINED +#define PRI_PlatformAssertArgType PRI_PlatformIntType +#endif + +/** +* Default implementation for pointers stored as integers +*/ +#ifndef PLATFORM_POINTER_CAST_TYPE_DEFINED + // Check for __SIZEOF_POINTER__ or cause error + #ifndef __SIZEOF_POINTER__ + #error "Compiler does not support __SIZEOF_POINTER__, cannot use default for PlatformPointerCastType" + #endif + + // Pointer sizes are determined by size of compiler + #if __SIZEOF_POINTER__ == 8 + typedef uint64_t PlatformPointerCastType; + extern const PlatformPointerCastType PlatformPointerCastType_MIN; + extern const PlatformPointerCastType PlatformPointerCastType_MAX; + #define PRI_PlatformPointerCastType PRIx64 + #elif __SIZEOF_POINTER__ == 4 + typedef uint32_t PlatformPointerCastType; + extern const PlatformPointerCastType PlatformPointerCastType_MIN; + extern const PlatformPointerCastType PlatformPointerCastType_MAX; + #define PRI_PlatformPointerCastType PRIx32 + #elif __SIZEOF_POINTER__ == 2 + typedef uint16_t PlatformPointerCastType; + extern const PlatformPointerCastType PlatformPointerCastType_MIN; + extern const PlatformPointerCastType PlatformPointerCastType_MAX; + #define PRI_PlatformPointerCastType PRIx16 + #else + typedef uint8_t PlatformPointerCastType; + extern const PlatformPointerCastType PlatformPointerCastType_MIN; + extern const PlatformPointerCastType PlatformPointerCastType_MAX; + #define PRI_PlatformPointerCastType PRIx8 + #endif + #define PLATFORM_POINTER_CAST_TYPE_DEFINED +#endif diff --git a/Fw/Types/test/ut/TypesTest.cpp b/Fw/Types/test/ut/TypesTest.cpp index f60a1da0f6..d3af331a47 100644 --- a/Fw/Types/test/ut/TypesTest.cpp +++ b/Fw/Types/test/ut/TypesTest.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -727,12 +727,12 @@ void AssertTest() { FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, NATIVE_UINT_TYPE numArgs, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4, - AssertArg arg5, - AssertArg arg6 + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4, + FwAssertArgType arg5, + FwAssertArgType arg6 ) { this->m_file = file; this->m_lineNo = lineNo; @@ -762,27 +762,27 @@ void AssertTest() { return this->m_numArgs; } - AssertArg getArg1() { + FwAssertArgType getArg1() { return this->m_arg1; } - AssertArg getArg2() { + FwAssertArgType getArg2() { return this->m_arg2; } - AssertArg getArg3() { + FwAssertArgType getArg3() { return this->m_arg3; } - AssertArg getArg4() { + FwAssertArgType getArg4() { return this->m_arg4; } - AssertArg getArg5() { + FwAssertArgType getArg5() { return this->m_arg5; } - AssertArg getArg6() { + FwAssertArgType getArg6() { return this->m_arg6; } @@ -795,15 +795,19 @@ void AssertTest() { private: +#if FW_ASSERT_LEVEL == FW_FILEID_ASSERT + FILE_NAME_ARG m_file = 0; +#else FILE_NAME_ARG m_file = nullptr; +#endif NATIVE_UINT_TYPE m_lineNo = 0; NATIVE_UINT_TYPE m_numArgs = 0; - AssertArg m_arg1 = 0; - AssertArg m_arg2 = 0; - AssertArg m_arg3 = 0; - AssertArg m_arg4 = 0; - AssertArg m_arg5 = 0; - AssertArg m_arg6 = 0; + FwAssertArgType m_arg1 = 0; + FwAssertArgType m_arg2 = 0; + FwAssertArgType m_arg3 = 0; + FwAssertArgType m_arg4 = 0; + FwAssertArgType m_arg5 = 0; + FwAssertArgType m_arg6 = 0; bool m_asserted = false; }; diff --git a/Fw/locs.fpp b/Fw/locs.fpp deleted file mode 100644 index 6c2da0e730..0000000000 --- a/Fw/locs.fpp +++ /dev/null @@ -1,29 +0,0 @@ -locate port Fw.BufferGet at "Buffer/Buffer.fpp" -locate port Fw.BufferSend at "Buffer/Buffer.fpp" -locate port Fw.Cmd at "Cmd/Cmd.fpp" -locate port Fw.CmdReg at "Cmd/Cmd.fpp" -locate port Fw.CmdResponse at "Cmd/Cmd.fpp" -locate port Fw.Com at "Com/Com.fpp" -locate port Fw.Log at "Log/Log.fpp" -locate port Fw.LogText at "Log/Log.fpp" -locate port Fw.PrmGet at "Prm/Prm.fpp" -locate port Fw.PrmSet at "Prm/Prm.fpp" -locate port Fw.Time at "Time/Time.fpp" -locate port Fw.Tlm at "Tlm/Tlm.fpp" -locate port Fw.TlmGet at "Tlm/Tlm.fpp" -locate type Fw.Buffer at "Buffer/Buffer.fpp" -locate type Fw.CmdArgBuffer at "Cmd/Cmd.fpp" -locate type Fw.CmdResponse at "Cmd/Cmd.fpp" -locate type Fw.ComBuffer at "Com/Com.fpp" -locate type Fw.DeserialStatus at "Types/Types.fpp" -locate type Fw.Enabled at "Types/Types.fpp" -locate type Fw.LogBuffer at "Log/Log.fpp" -locate type Fw.LogSeverity at "Log/Log.fpp" -locate type Fw.ParamBuffer at "Prm/Prm.fpp" -locate type Fw.ParamValid at "Prm/Prm.fpp" -locate type Fw.PolyType at "Types/Types.fpp" -locate type Fw.SerialStatus at "Types/Types.fpp" -locate type Fw.String at "Types/Types.fpp" -locate type Fw.TextLogString at "Log/Log.fpp" -locate type Fw.Time at "Time/Time.fpp" -locate type Fw.TlmBuffer at "Tlm/Tlm.fpp" diff --git a/Fw/subdirs.txt b/Fw/subdirs.txt deleted file mode 100644 index 86c3a94524..0000000000 --- a/Fw/subdirs.txt +++ /dev/null @@ -1,8 +0,0 @@ -Buffer -Cmd -Com -Log -Prm -Time -Tlm -Types diff --git a/Fw/update-locs b/Fw/update-locs deleted file mode 100755 index 76583058af..0000000000 --- a/Fw/update-locs +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -fpp-locate-defs `find . -name '*.fpp'` > locs.fpp diff --git a/Fw/update-subdirs b/Fw/update-subdirs deleted file mode 100755 index f86970a7cb..0000000000 --- a/Fw/update-subdirs +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -find . -mindepth 2 -name '*.fpp' | cut -d '/' -f 2 | sort | uniq > subdirs.txt diff --git a/NOTICE.txt b/NOTICE.txt index 8f9b5f74f1..882a0be082 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,27 +1,10 @@ -Copyright (c) 2020 California Institute of Technology (“Caltech”). U.S. Government sponsorship acknowledged. +Copyright (c) 2023 California Institute of Technology (“Caltech”). U.S. Government sponsorship acknowledged. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -following conditions are met: - -• Redistributions of source code must retain the above copyright notice, this list of conditions and the following -disclaimer. - -• Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following -disclaimer in the documentation and/or other materials provided with the distribution. - -• Neither the name of Caltech nor its operating division, the Jet Propulsion Laboratory, nor the names of its +Neither the name of Caltech nor its operating division, the Jet Propulsion Laboratory, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - This product includes cryptographic software written by Eric Young (eay@cryptsoft.com) This product includes pyparsing written by Paul T. McGuire diff --git a/Os/Baremetal/File.cpp b/Os/Baremetal/File.cpp index b516c227b1..fed6dee7b3 100644 --- a/Os/Baremetal/File.cpp +++ b/Os/Baremetal/File.cpp @@ -1,5 +1,4 @@ #include -#include #include #include diff --git a/Os/Baremetal/FileSystem.cpp b/Os/Baremetal/FileSystem.cpp index c2b87d0070..61a6d44614 100644 --- a/Os/Baremetal/FileSystem.cpp +++ b/Os/Baremetal/FileSystem.cpp @@ -1,52 +1,54 @@ #include -#include -#include -#include #include +#include +#include namespace Os { - namespace FileSystem { - Status createDirectory(const char* path) { - return NO_SPACE; - } // end createDirectory - - Status removeDirectory(const char* path) { - return INVALID_PATH; - } // end removeDirectory - - Status readDirectory(const char* path, const U32 maxNum, - Fw::String fileArray[]) - { - return OTHER_ERROR; - } - Status removeFile(const char* path) { - - return OTHER_ERROR; - } // end removeFile - - Status moveFile(const char* originPath, const char* destPath) { - return OTHER_ERROR; - - } // end moveFile - - Status handleFileError(File::Status fileStatus) { - return OTHER_ERROR; - } // end handleFileError - - Status copyFile(const char* originPath, const char* destPath) { - return OTHER_ERROR; - } // end copyFile - - Status getFileSize(const char* path, U64& size) { - return OTHER_ERROR; - } // end getFileSize - - Status changeWorkingDirectory(const char* path) { - return OTHER_ERROR; - } // end changeWorkingDirectory - // Public function to get the file count for a given directory. - Status getFileCount (const char* directory, U32& fileCount) { - return OTHER_ERROR; - } //end getFileCount - } // end FileSystem namespace -} // end Os namespace +namespace FileSystem { +Status createDirectory(const char* path) { + return NO_SPACE; +} // end createDirectory + +Status removeDirectory(const char* path) { + return INVALID_PATH; +} // end removeDirectory + +Status readDirectory(const char* path, const U32 maxNum, Fw::String fileArray[]) { + return OTHER_ERROR; +} +Status removeFile(const char* path) { + return OTHER_ERROR; +} // end removeFile + +Status moveFile(const char* originPath, const char* destPath) { + return OTHER_ERROR; + +} // end moveFile + +Status handleFileError(File::Status fileStatus) { + return OTHER_ERROR; +} // end handleFileError + +Status copyFile(const char* originPath, const char* destPath) { + return OTHER_ERROR; +} // end copyFile + +Status getFileSize(const char* path, FwSizeType& size) { + return OTHER_ERROR; +} // end getFileSize + +Status changeWorkingDirectory(const char* path) { + return OTHER_ERROR; +} // end changeWorkingDirectory +// Public function to get the file count for a given directory. +Status getFileCount(const char* directory, U32& fileCount) { + return OTHER_ERROR; +} // end getFileCount +Status appendFile(const char* originPath, const char* destPath, bool createMissingDest) { + return OTHER_ERROR; +} +Status getFreeSpace(const char* path, FwSizeType& totalBytes, FwSizeType& freeBytes) { + return OTHER_ERROR; +} +} // namespace FileSystem +} // namespace Os diff --git a/Os/Baremetal/Queue.cpp b/Os/Baremetal/Queue.cpp index fca6b74767..bfec97ae1f 100644 --- a/Os/Baremetal/Queue.cpp +++ b/Os/Baremetal/Queue.cpp @@ -5,7 +5,7 @@ // safety is implemented as this intended for baremetal devices. // Based on Os/Pthreads/Queue.cpp from @dinkel // ====================================================================== -#include +#include #include #include #include diff --git a/Os/Baremetal/TaskRunner/BareTaskHandle.hpp b/Os/Baremetal/TaskRunner/BareTaskHandle.hpp index 5b69ef22e6..dbcdea7a44 100644 --- a/Os/Baremetal/TaskRunner/BareTaskHandle.hpp +++ b/Os/Baremetal/TaskRunner/BareTaskHandle.hpp @@ -19,7 +19,7 @@ class BareTaskHandle { bool m_enabled; //!< Save the priority NATIVE_INT_TYPE m_priority; - //!< Function passed in to the task + //!< Function passed into the task Task::taskRoutine m_routine; //!< Argument input pointer void* m_argument; diff --git a/Os/Baremetal/TaskRunner/CMakeLists.txt b/Os/Baremetal/TaskRunner/CMakeLists.txt index e570279c4f..26ab1a5774 100644 --- a/Os/Baremetal/TaskRunner/CMakeLists.txt +++ b/Os/Baremetal/TaskRunner/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Os/Baremetal/TaskRunner/TaskRunner.cpp b/Os/Baremetal/TaskRunner/TaskRunner.cpp index 1b0b2b8610..d60eb97ee0 100644 --- a/Os/Baremetal/TaskRunner/TaskRunner.cpp +++ b/Os/Baremetal/TaskRunner/TaskRunner.cpp @@ -5,7 +5,7 @@ * Author: lestarch */ #include -#include +#include #include #include namespace Os { diff --git a/Os/CMakeLists.txt b/Os/CMakeLists.txt index 3d244349d4..2d5fa8bb3a 100644 --- a/Os/CMakeLists.txt +++ b/Os/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### @@ -81,9 +81,13 @@ if (FPRIME_USE_BAREMETAL_SCHEDULER) list(REMOVE_ITEM SOURCE_FILES "${ITER_ITEM}") endif() endforeach() - list(APPEND SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Baremetal/Task.cpp") + list(APPEND SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Baremetal/File.cpp") + list(APPEND SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Baremetal/FileSystem.cpp") + list(APPEND SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Baremetal/IntervalTimer.cpp") list(APPEND SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Baremetal/Mutex.cpp") + list(APPEND SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Baremetal/Queue.cpp") list(APPEND SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Baremetal/SystemResources.cpp") + list(APPEND SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Baremetal/Task.cpp") endif() register_fprime_module() diff --git a/Os/Directory.hpp b/Os/Directory.hpp index 6d47e277f9..2aec3cf1ce 100644 --- a/Os/Directory.hpp +++ b/Os/Directory.hpp @@ -2,7 +2,6 @@ #define _Directory_hpp_ #include -#include namespace Os { diff --git a/Os/Event.hpp b/Os/Event.hpp index 3f28c22223..e8e41b8a46 100644 --- a/Os/Event.hpp +++ b/Os/Event.hpp @@ -7,7 +7,7 @@ #ifndef EVENT_HPP #define EVENT_HPP -#include +#include #include namespace Os { diff --git a/Os/File.hpp b/Os/File.hpp index 29b2752be4..f0082209fa 100644 --- a/Os/File.hpp +++ b/Os/File.hpp @@ -2,7 +2,6 @@ #define _File_hpp_ #include -#include namespace Os { diff --git a/Os/FileCommon.cpp b/Os/FileCommon.cpp index 6391c7f75e..47189248e9 100644 --- a/Os/FileCommon.cpp +++ b/Os/FileCommon.cpp @@ -1,5 +1,4 @@ #include -#include #include #include diff --git a/Os/FileSystem.hpp b/Os/FileSystem.hpp index c287a532ef..e6b0e2e5f3 100644 --- a/Os/FileSystem.hpp +++ b/Os/FileSystem.hpp @@ -2,7 +2,6 @@ #define _FileSystem_hpp_ #include -#include #include #define FILE_SYSTEM_CHUNK_SIZE (256u) @@ -33,11 +32,10 @@ namespace Os { Status moveFile(const char* originPath, const char* destPath); //! moves a file from origin to destination Status copyFile(const char* originPath, const char* destPath); //! copies a file from origin to destination Status appendFile(const char* originPath, const char* destPath, bool createMissingDest=false); //! append file origin to destination file. If boolean true, creates a brand new file if the destination doesn't exist. - Status getFileSize(const char* path, U64& size); //!< gets the size of the file (in bytes) at location path + Status getFileSize(const char* path, FwSizeType& size); //!< gets the size of the file (in bytes) at location path Status getFileCount(const char* directory, U32& fileCount); //!< counts the number of files in the given directory Status changeWorkingDirectory(const char* path); //!< move current directory to path - - Status getFreeSpace(const char* path, U64& totalBytes, U64& freeBytes); //!< get FS free and total space in bytes on filesystem containing path + Status getFreeSpace(const char* path, FwSizeType& totalBytes, FwSizeType& freeBytes); //!< get FS free and total space in bytes on filesystem containing path } } diff --git a/Os/InterruptLock.hpp b/Os/InterruptLock.hpp index f39dc21e49..924a41e82e 100644 --- a/Os/InterruptLock.hpp +++ b/Os/InterruptLock.hpp @@ -1,7 +1,7 @@ #ifndef _InterruptLock_hpp_ #define _InterruptLock_hpp_ -#include +#include namespace Os { class InterruptLock { diff --git a/Os/IntervalTimer.hpp b/Os/IntervalTimer.hpp index 180fab068a..a606590408 100644 --- a/Os/IntervalTimer.hpp +++ b/Os/IntervalTimer.hpp @@ -7,7 +7,7 @@ #ifndef _IntervalTimer_hpp_ #define _IntervalTimer_hpp_ -#include +#include namespace Os { class IntervalTimer { diff --git a/Os/Linux/Directory.cpp b/Os/Linux/Directory.cpp index a554e1a9d5..6794e56e40 100644 --- a/Os/Linux/Directory.cpp +++ b/Os/Linux/Directory.cpp @@ -1,5 +1,4 @@ #include -#include #include #include diff --git a/Os/Linux/File.cpp b/Os/Linux/File.cpp index 48115784e9..8f63964957 100644 --- a/Os/Linux/File.cpp +++ b/Os/Linux/File.cpp @@ -1,5 +1,4 @@ #include -#include #include #include diff --git a/Os/Linux/FileSystem.cpp b/Os/Linux/FileSystem.cpp index 8cf9935bd0..8f130e658c 100644 --- a/Os/Linux/FileSystem.cpp +++ b/Os/Linux/FileSystem.cpp @@ -1,582 +1,586 @@ #include -#include -#include -#include #include +#include +#include -#include +#include #include +#include #include -#include -#include // Needed for rename +#include +#include // Needed for rename #include #include -#include namespace Os { - namespace FileSystem { - - Status createDirectory(const char* path) { +namespace FileSystem { - Status stat = OP_OK; +Status createDirectory(const char* path) { + Status stat = OP_OK; #ifdef __VXWORKS__ - int mkStat = ::mkdir(path); + int mkStat = ::mkdir(path); #else - int mkStat = ::mkdir(path,S_IRWXU); + int mkStat = ::mkdir(path, S_IRWXU); #endif - if (-1 == mkStat) { - switch (errno) { - case EACCES: - case EPERM: - case EROFS: - case EFAULT: - stat = NO_PERMISSION; - break; - case EEXIST: - stat = ALREADY_EXISTS; - break; - case ELOOP: - case ENOENT: - case ENAMETOOLONG: - stat = INVALID_PATH; - break; - case ENOTDIR: - stat = NOT_DIR; - break; - case ENOSPC: - case EDQUOT: - stat = NO_SPACE; - break; - case EMLINK: - stat = FILE_LIMIT; - break; - default: - stat = OTHER_ERROR; - break; - } - } - - return stat; - } // end createDirectory - - Status removeDirectory(const char* path) { - - Status stat = OP_OK; - - if (::rmdir(path) == -1) { - switch (errno) { - case EACCES: - case EPERM: - case EROFS: - case EFAULT: - stat = NO_PERMISSION; - break; - case ENOTEMPTY: - case EEXIST: - stat = NOT_EMPTY; - break; - case EINVAL: - case ELOOP: - case ENOENT: - case ENAMETOOLONG: - stat = INVALID_PATH; - break; - case ENOTDIR: - stat = NOT_DIR; - break; - case EBUSY: - stat = BUSY; - break; - default: - stat = OTHER_ERROR; - break; - } - } - - return stat; - } // end removeDirectory - - Status readDirectory(const char* path, const U32 maxNum, - Fw::String fileArray[], - U32& numFiles) - { - Status dirStat = OP_OK; - DIR * dirPtr = nullptr; - struct dirent *direntData = nullptr; - - FW_ASSERT(fileArray != nullptr); - FW_ASSERT(path != nullptr); - - // Open directory failed: - if((dirPtr = ::opendir(path)) == nullptr) { - - switch (errno) { - case EACCES: - dirStat = NO_PERMISSION; - break; - case ENOENT: - dirStat = INVALID_PATH; - break; - case ENOTDIR: - dirStat = NOT_DIR; - break; - default: - dirStat = OTHER_ERROR; - break; - } - return dirStat; - } - - // Set errno to 0 so we know why we exited readdir - errno = 0; - U32 arrayIdx = 0; - U32 limitCount = 0; - const U32 loopLimit = std::numeric_limits::max(); - - // Read the directory contents and store in passed in array: - while(arrayIdx < maxNum && limitCount < loopLimit) { - - ++limitCount; - - if((direntData = ::readdir(dirPtr)) != nullptr) { - // We are only care about regular files - if(direntData->d_type == DT_REG) { - - FW_ASSERT(arrayIdx < maxNum, - static_cast(arrayIdx), - static_cast(maxNum)); - - Fw::String str(direntData->d_name); - fileArray[arrayIdx++] = str; - } - } - else { - // readdir failed, did it error or did we run out of files? - if(errno != 0) { - // Only error from readdir is EBADF - dirStat = OTHER_ERROR; - } - break; - } - } - - if(limitCount == loopLimit) { - dirStat = FILE_LIMIT; - } - - if(::closedir(dirPtr) == -1) { - // Only error from closedir is EBADF - dirStat = OTHER_ERROR; - } - - numFiles = arrayIdx; - - return dirStat; - } - - Status removeFile(const char* path) { - - Status stat = OP_OK; - - if(::unlink(path) == -1) { - switch (errno) { - case EACCES: - case EPERM: - case EROFS: - stat = NO_PERMISSION; - break; - case EISDIR: - stat = IS_DIR; - break; - case ELOOP: - case ENOENT: - case ENAMETOOLONG: - stat = INVALID_PATH; - break; - case ENOTDIR: - stat = NOT_DIR; - break; - case EBUSY: - stat = BUSY; - break; - default: - stat = OTHER_ERROR; - break; - } - } - - return stat; - } // end removeFile - - Status moveFile(const char* originPath, const char* destPath) { - - Status stat = OP_OK; - - if(::rename(originPath, destPath) == -1) { - switch (errno) { - case EACCES: - case EPERM: - case EROFS: - case EFAULT: - stat = NO_PERMISSION; - break; - case EDQUOT: - case ENOSPC: - stat = NO_SPACE; - break; - case ELOOP: - case ENAMETOOLONG: - case ENOENT: - case EINVAL: - stat = INVALID_PATH; - break; - case ENOTDIR: - case EISDIR: // Old path is not a dir - stat = NOT_DIR; - break; - case ENOTEMPTY: - case EEXIST: - stat = NOT_EMPTY; - break; - case EMLINK: - stat = FILE_LIMIT; - break; - case EBUSY: - stat = BUSY; - break; - default: - stat = OTHER_ERROR; - break; - } - } - return stat; - - } // end moveFile - - Status handleFileError(File::Status fileStatus) { - Status fileSystemStatus = OTHER_ERROR; - - switch(fileStatus) { - case File::NO_SPACE: - fileSystemStatus = NO_SPACE; - break; - case File::NO_PERMISSION: - fileSystemStatus = NO_PERMISSION; - break; - case File::DOESNT_EXIST: - fileSystemStatus = INVALID_PATH; - break; - default: - fileSystemStatus = OTHER_ERROR; - } - return fileSystemStatus; - } // end handleFileError - - /** - * A helper function that returns an "OP_OK" status if the given file - * exists and can be read from, otherwise returns an error status. - * - * If provided, will also initialize the given stat struct with file - * information. - */ - Status initAndCheckFileStats(const char* filePath, - struct stat* fileInfo=nullptr) { - FileSystem::Status fs_status; - struct stat local_info; - if(!fileInfo) { - // No external struct given, so use the local one - fileInfo = &local_info; - } - - if(::stat(filePath, fileInfo) == -1) { - switch (errno) { - case EACCES: - fs_status = NO_PERMISSION; - break; - case ELOOP: - case ENOENT: - case ENAMETOOLONG: - fs_status = INVALID_PATH; - break; - case ENOTDIR: - fs_status = NOT_DIR; - break; - default: - fs_status = OTHER_ERROR; - break; - } - return fs_status; - } - - // Make sure the origin is a regular file - if(!S_ISREG(fileInfo->st_mode)) { - return INVALID_PATH; - } - - return OP_OK; - } - - /** - * A helper function that writes all the file information in the source - * file to the destination file (replaces/appends to end/etc. depending - * on destination file mode). - * - * Files must already be open and will remain open after this function - * completes. - * - * @param source File to copy data from - * @param destination File to copy data to - * @param size The number of bytes to copy - */ - Status copyFileData(File source, File destination, U64 size) { - U8 fileBuffer[FILE_SYSTEM_CHUNK_SIZE]; - File::Status file_status; - - // Set loop limit - const U64 copyLoopLimit = (size/FILE_SYSTEM_CHUNK_SIZE) + 2; - - U64 loopCounter = 0; - NATIVE_INT_TYPE chunkSize; - while(loopCounter < copyLoopLimit) { - chunkSize = FILE_SYSTEM_CHUNK_SIZE; - file_status = source.read(&fileBuffer, chunkSize, false); - if(file_status != File::OP_OK) { - return handleFileError(file_status); - } - - if(chunkSize == 0) { - //file has been successfully copied - break; - } - - file_status = destination.write(fileBuffer, chunkSize, true); - if(file_status != File::OP_OK) { - return handleFileError(file_status); - } - loopCounter++; - } - FW_ASSERT(loopCounter < copyLoopLimit); - - return FileSystem::OP_OK; - } // end copyFileData - - Status copyFile(const char* originPath, const char* destPath) { - FileSystem::Status fs_status; - File::Status file_status; - - U64 fileSize = 0; - - File source; - File destination; - - fs_status = initAndCheckFileStats(originPath); - if(FileSystem::OP_OK != fs_status) { - return fs_status; - } - - // Get the file size: - fs_status = FileSystem::getFileSize(originPath, fileSize); //!< gets the size of the file (in bytes) at location path - if(FileSystem::OP_OK != fs_status) { - return fs_status; - } - - file_status = source.open(originPath, File::OPEN_READ); - if(file_status != File::OP_OK) { - return handleFileError(file_status); - } - - file_status = destination.open(destPath, File::OPEN_WRITE); - if(file_status != File::OP_OK) { - return handleFileError(file_status); - } - - fs_status = copyFileData(source, destination, fileSize); - - (void) source.close(); - (void) destination.close(); - - return fs_status; - } // end copyFile - - Status appendFile(const char* originPath, const char* destPath, bool createMissingDest) { - FileSystem::Status fs_status; - File::Status file_status; - U64 fileSize = 0; - - File source; - File destination; - - fs_status = initAndCheckFileStats(originPath); - if(FileSystem::OP_OK != fs_status) { - return fs_status; - } - - // Get the file size: - fs_status = FileSystem::getFileSize(originPath, fileSize); //!< gets the size of the file (in bytes) at location path - if(FileSystem::OP_OK != fs_status) { - return fs_status; - } - - file_status = source.open(originPath, File::OPEN_READ); - if(file_status != File::OP_OK) { - return handleFileError(file_status); - } - - // If needed, check if destination file exists (and exit if not) - if(!createMissingDest) { - fs_status = initAndCheckFileStats(destPath); - if(FileSystem::OP_OK != fs_status) { - return fs_status; - } - } - - file_status = destination.open(destPath, File::OPEN_APPEND); - if(file_status != File::OP_OK) { - return handleFileError(file_status); - } - - fs_status = copyFileData(source, destination, fileSize); - - (void) source.close(); - (void) destination.close(); - - return fs_status; - } // end appendFile - - Status getFileSize(const char* path, U64& size) { - - Status fileStat = OP_OK; - struct stat fileStatStruct; - - fileStat = initAndCheckFileStats(path, &fileStatStruct); - if(FileSystem::OP_OK == fileStat) { - // Only check size if struct was initialized successfully - size = fileStatStruct.st_size; - } - - return fileStat; - } // end getFileSize - - Status changeWorkingDirectory(const char* path) { - - Status stat = OP_OK; - - if (::chdir(path) == -1) { - switch (errno) { - case EACCES: - case EFAULT: - stat = NO_PERMISSION; - break; - case ENOTEMPTY: - stat = NOT_EMPTY; - break; - case ENOENT: - case ELOOP: - case ENAMETOOLONG: - stat = INVALID_PATH; - break; - case ENOTDIR: - stat = NOT_DIR; - break; - default: - stat = OTHER_ERROR; - break; - } - } - - return stat; - } // end changeWorkingDirectory - - Status getFreeSpace(const char* path, U64& totalBytes, U64& freeBytes) { - Status stat = OP_OK; - - struct statvfs fsStat; - int ret = statvfs(path, &fsStat); - if (ret) { - switch (errno) { - case EACCES: - stat = NO_PERMISSION; - break; - case ELOOP: - case ENOENT: - case ENAMETOOLONG: - stat = INVALID_PATH; - break; - case ENOTDIR: - stat = NOT_DIR; - break; - default: - stat = OTHER_ERROR; - break; - } - return stat; - } - - totalBytes = static_cast(fsStat.f_blocks) * static_cast(fsStat.f_frsize); - freeBytes = static_cast(fsStat.f_bfree) * static_cast(fsStat.f_frsize); - return stat; - } - - // Public function to get the file count for a given directory. - Status getFileCount (const char* directory, U32& fileCount) { - Status dirStat = OP_OK; - DIR * dirPtr = nullptr; - struct dirent *direntData = nullptr; - U32 limitCount; - const U64 loopLimit = std::numeric_limits::max(); - - fileCount = 0; - if((dirPtr = ::opendir(directory)) == nullptr) { - switch (errno) { - case EACCES: - dirStat = NO_PERMISSION; - break; - case ENOENT: - dirStat = INVALID_PATH; - break; - case ENOTDIR: - dirStat = NOT_DIR; - break; - default: - dirStat = OTHER_ERROR; - break; - } - return dirStat; - } - - // Set errno to 0 so we know why we exited readdir - errno = 0; - for(limitCount = 0; limitCount < loopLimit; limitCount++) { - if((direntData = ::readdir(dirPtr)) != nullptr) { - // We are only counting regular files - if(direntData->d_type == DT_REG) { - fileCount++; - } - } - else { - // readdir failed, did it error or did we run out of files? - if(errno != 0) { - // Only error from readdir is EBADF - dirStat = OTHER_ERROR; - } - break; - } - } - if(limitCount == loopLimit) { - dirStat = FILE_LIMIT; - } - - if(::closedir(dirPtr) == -1) { - // Only error from closedir is EBADF - dirStat = OTHER_ERROR; - } - - return dirStat; - } //end getFileCount - - } // end FileSystem namespace - -} // end Os namespace + if (-1 == mkStat) { + switch (errno) { + case EACCES: + case EPERM: + case EROFS: + case EFAULT: + stat = NO_PERMISSION; + break; + case EEXIST: + stat = ALREADY_EXISTS; + break; + case ELOOP: + case ENOENT: + case ENAMETOOLONG: + stat = INVALID_PATH; + break; + case ENOTDIR: + stat = NOT_DIR; + break; + case ENOSPC: + case EDQUOT: + stat = NO_SPACE; + break; + case EMLINK: + stat = FILE_LIMIT; + break; + default: + stat = OTHER_ERROR; + break; + } + } + + return stat; +} // end createDirectory + +Status removeDirectory(const char* path) { + Status stat = OP_OK; + + if (::rmdir(path) == -1) { + switch (errno) { + case EACCES: + case EPERM: + case EROFS: + case EFAULT: + stat = NO_PERMISSION; + break; + case ENOTEMPTY: + case EEXIST: + stat = NOT_EMPTY; + break; + case EINVAL: + case ELOOP: + case ENOENT: + case ENAMETOOLONG: + stat = INVALID_PATH; + break; + case ENOTDIR: + stat = NOT_DIR; + break; + case EBUSY: + stat = BUSY; + break; + default: + stat = OTHER_ERROR; + break; + } + } + + return stat; +} // end removeDirectory + +Status readDirectory(const char* path, const U32 maxNum, Fw::String fileArray[], U32& numFiles) { + Status dirStat = OP_OK; + DIR* dirPtr = nullptr; + struct dirent* direntData = nullptr; + + FW_ASSERT(fileArray != nullptr); + FW_ASSERT(path != nullptr); + + // Open directory failed: + if ((dirPtr = ::opendir(path)) == nullptr) { + switch (errno) { + case EACCES: + dirStat = NO_PERMISSION; + break; + case ENOENT: + dirStat = INVALID_PATH; + break; + case ENOTDIR: + dirStat = NOT_DIR; + break; + default: + dirStat = OTHER_ERROR; + break; + } + return dirStat; + } + + // Set errno to 0 so we know why we exited readdir + errno = 0; + U32 arrayIdx = 0; + U32 limitCount = 0; + const U32 loopLimit = std::numeric_limits::max(); + + // Read the directory contents and store in passed in array: + while (arrayIdx < maxNum && limitCount < loopLimit) { + ++limitCount; + + if ((direntData = ::readdir(dirPtr)) != nullptr) { + // We are only care about regular files + if (direntData->d_type == DT_REG) { + FW_ASSERT(arrayIdx < maxNum, static_cast(arrayIdx), + static_cast(maxNum)); + + Fw::String str(direntData->d_name); + fileArray[arrayIdx++] = str; + } + } else { + // readdir failed, did it error or did we run out of files? + if (errno != 0) { + // Only error from readdir is EBADF + dirStat = OTHER_ERROR; + } + break; + } + } + + if (limitCount == loopLimit) { + dirStat = FILE_LIMIT; + } + + if (::closedir(dirPtr) == -1) { + // Only error from closedir is EBADF + dirStat = OTHER_ERROR; + } + + numFiles = arrayIdx; + + return dirStat; +} + +Status removeFile(const char* path) { + Status stat = OP_OK; + + if (::unlink(path) == -1) { + switch (errno) { + case EACCES: + case EPERM: + case EROFS: + stat = NO_PERMISSION; + break; + case EISDIR: + stat = IS_DIR; + break; + case ELOOP: + case ENOENT: + case ENAMETOOLONG: + stat = INVALID_PATH; + break; + case ENOTDIR: + stat = NOT_DIR; + break; + case EBUSY: + stat = BUSY; + break; + default: + stat = OTHER_ERROR; + break; + } + } + + return stat; +} // end removeFile + +Status moveFile(const char* originPath, const char* destPath) { + Status stat = OP_OK; + + if (::rename(originPath, destPath) == -1) { + switch (errno) { + case EACCES: + case EPERM: + case EROFS: + case EFAULT: + stat = NO_PERMISSION; + break; + case EDQUOT: + case ENOSPC: + stat = NO_SPACE; + break; + case ELOOP: + case ENAMETOOLONG: + case ENOENT: + case EINVAL: + stat = INVALID_PATH; + break; + case ENOTDIR: + case EISDIR: // Old path is not a dir + stat = NOT_DIR; + break; + case ENOTEMPTY: + case EEXIST: + stat = NOT_EMPTY; + break; + case EMLINK: + stat = FILE_LIMIT; + break; + case EBUSY: + stat = BUSY; + break; + default: + stat = OTHER_ERROR; + break; + } + } + return stat; + +} // end moveFile + +Status handleFileError(File::Status fileStatus) { + Status fileSystemStatus = OTHER_ERROR; + + switch (fileStatus) { + case File::NO_SPACE: + fileSystemStatus = NO_SPACE; + break; + case File::NO_PERMISSION: + fileSystemStatus = NO_PERMISSION; + break; + case File::DOESNT_EXIST: + fileSystemStatus = INVALID_PATH; + break; + default: + fileSystemStatus = OTHER_ERROR; + } + return fileSystemStatus; +} // end handleFileError + +/** + * A helper function that returns an "OP_OK" status if the given file + * exists and can be read from, otherwise returns an error status. + * + * If provided, will also initialize the given stat struct with file + * information. + */ +Status initAndCheckFileStats(const char* filePath, struct stat* fileInfo = nullptr) { + FileSystem::Status fs_status; + struct stat local_info; + if (!fileInfo) { + // No external struct given, so use the local one + fileInfo = &local_info; + } + + if (::stat(filePath, fileInfo) == -1) { + switch (errno) { + case EACCES: + fs_status = NO_PERMISSION; + break; + case ELOOP: + case ENOENT: + case ENAMETOOLONG: + fs_status = INVALID_PATH; + break; + case ENOTDIR: + fs_status = NOT_DIR; + break; + default: + fs_status = OTHER_ERROR; + break; + } + return fs_status; + } + + // Make sure the origin is a regular file + if (!S_ISREG(fileInfo->st_mode)) { + return INVALID_PATH; + } + + return OP_OK; +} + +/** + * A helper function that writes all the file information in the source + * file to the destination file (replaces/appends to end/etc. depending + * on destination file mode). + * + * Files must already be open and will remain open after this function + * completes. + * + * @param source File to copy data from + * @param destination File to copy data to + * @param size The number of bytes to copy + */ +Status copyFileData(File source, File destination, FwSizeType size) { + static_assert(FILE_SYSTEM_CHUNK_SIZE != 0, "FILE_SYSTEM_CHUNK_SIZE must be >0"); + U8 fileBuffer[FILE_SYSTEM_CHUNK_SIZE]; + File::Status file_status; + + // Set loop limit + const FwSizeType copyLoopLimit = (size / FILE_SYSTEM_CHUNK_SIZE) + 2; + + FwSizeType loopCounter = 0; + NATIVE_INT_TYPE chunkSize; + while (loopCounter < copyLoopLimit) { + chunkSize = FILE_SYSTEM_CHUNK_SIZE; + file_status = source.read(&fileBuffer, chunkSize, false); + if (file_status != File::OP_OK) { + return handleFileError(file_status); + } + + if (chunkSize == 0) { + // file has been successfully copied + break; + } + + file_status = destination.write(fileBuffer, chunkSize, true); + if (file_status != File::OP_OK) { + return handleFileError(file_status); + } + loopCounter++; + } + FW_ASSERT(loopCounter < copyLoopLimit); + + return FileSystem::OP_OK; +} // end copyFileData + +Status copyFile(const char* originPath, const char* destPath) { + FileSystem::Status fs_status; + File::Status file_status; + + FwSizeType fileSize = 0; + + File source; + File destination; + + fs_status = initAndCheckFileStats(originPath); + if (FileSystem::OP_OK != fs_status) { + return fs_status; + } + + // Get the file size: + fs_status = + FileSystem::getFileSize(originPath, fileSize); //!< gets the size of the file (in bytes) at location path + if (FileSystem::OP_OK != fs_status) { + return fs_status; + } + + file_status = source.open(originPath, File::OPEN_READ); + if (file_status != File::OP_OK) { + return handleFileError(file_status); + } + + file_status = destination.open(destPath, File::OPEN_WRITE); + if (file_status != File::OP_OK) { + return handleFileError(file_status); + } + + fs_status = copyFileData(source, destination, fileSize); + + (void)source.close(); + (void)destination.close(); + + return fs_status; +} // end copyFile + +Status appendFile(const char* originPath, const char* destPath, bool createMissingDest) { + FileSystem::Status fs_status; + File::Status file_status; + FwSizeType fileSize = 0; + + File source; + File destination; + + fs_status = initAndCheckFileStats(originPath); + if (FileSystem::OP_OK != fs_status) { + return fs_status; + } + + // Get the file size: + fs_status = + FileSystem::getFileSize(originPath, fileSize); //!< gets the size of the file (in bytes) at location path + if (FileSystem::OP_OK != fs_status) { + return fs_status; + } + + file_status = source.open(originPath, File::OPEN_READ); + if (file_status != File::OP_OK) { + return handleFileError(file_status); + } + + // If needed, check if destination file exists (and exit if not) + if (!createMissingDest) { + fs_status = initAndCheckFileStats(destPath); + if (FileSystem::OP_OK != fs_status) { + return fs_status; + } + } + + file_status = destination.open(destPath, File::OPEN_APPEND); + if (file_status != File::OP_OK) { + return handleFileError(file_status); + } + + fs_status = copyFileData(source, destination, fileSize); + + (void)source.close(); + (void)destination.close(); + + return fs_status; +} // end appendFile + +Status getFileSize(const char* path, FwSizeType& size) { + Status fileStat = OP_OK; + struct stat fileStatStruct; + + fileStat = initAndCheckFileStats(path, &fileStatStruct); + if (FileSystem::OP_OK == fileStat) { + // Only check size if struct was initialized successfully + size = fileStatStruct.st_size; + if (static_cast(size) != fileStatStruct.st_size) { + return FileSystem::OTHER_ERROR; + } + } + + return fileStat; +} // end getFileSize + +Status changeWorkingDirectory(const char* path) { + Status stat = OP_OK; + + if (::chdir(path) == -1) { + switch (errno) { + case EACCES: + case EFAULT: + stat = NO_PERMISSION; + break; + case ENOTEMPTY: + stat = NOT_EMPTY; + break; + case ENOENT: + case ELOOP: + case ENAMETOOLONG: + stat = INVALID_PATH; + break; + case ENOTDIR: + stat = NOT_DIR; + break; + default: + stat = OTHER_ERROR; + break; + } + } + + return stat; +} // end changeWorkingDirectory + +Status getFreeSpace(const char* path, FwSizeType& totalBytes, FwSizeType& freeBytes) { + Status stat = OP_OK; + + struct statvfs fsStat; + int ret = statvfs(path, &fsStat); + if (ret) { + switch (errno) { + case EACCES: + stat = NO_PERMISSION; + break; + case ELOOP: + case ENOENT: + case ENAMETOOLONG: + stat = INVALID_PATH; + break; + case ENOTDIR: + stat = NOT_DIR; + break; + default: + stat = OTHER_ERROR; + break; + } + return stat; + } + + const FwSizeType block_size = static_cast(fsStat.f_frsize); + const FwSizeType free_blocks = static_cast(fsStat.f_bfree); + const FwSizeType total_blocks = static_cast(fsStat.f_blocks); + + // Check for casting and type error + if (((block_size <= 0) || (static_cast(block_size) != fsStat.f_frsize)) || + ((free_blocks <= 0) || (static_cast(free_blocks) != fsStat.f_bfree)) || + ((total_blocks <= 0) || (static_cast(block_size) != fsStat.f_blocks))) { + return OTHER_ERROR; + } + // Check for overflow in multiplication + if (free_blocks > (std::numeric_limits::max() / block_size) || + total_blocks > (std::numeric_limits::max() / block_size)) { + return OTHER_ERROR; + } + freeBytes = free_blocks * block_size; + totalBytes = total_blocks * block_size; + return stat; +} + +// Public function to get the file count for a given directory. +Status getFileCount(const char* directory, U32& fileCount) { + Status dirStat = OP_OK; + DIR* dirPtr = nullptr; + struct dirent* direntData = nullptr; + U32 limitCount; + const U32 loopLimit = std::numeric_limits::max(); + + fileCount = 0; + if ((dirPtr = ::opendir(directory)) == nullptr) { + switch (errno) { + case EACCES: + dirStat = NO_PERMISSION; + break; + case ENOENT: + dirStat = INVALID_PATH; + break; + case ENOTDIR: + dirStat = NOT_DIR; + break; + default: + dirStat = OTHER_ERROR; + break; + } + return dirStat; + } + + // Set errno to 0 so we know why we exited readdir + errno = 0; + for (limitCount = 0; limitCount < loopLimit; limitCount++) { + if ((direntData = ::readdir(dirPtr)) != nullptr) { + // We are only counting regular files + if (direntData->d_type == DT_REG) { + fileCount++; + } + } else { + // readdir failed, did it error or did we run out of files? + if (errno != 0) { + // Only error from readdir is EBADF + dirStat = OTHER_ERROR; + } + break; + } + } + if (limitCount == loopLimit) { + dirStat = FILE_LIMIT; + } + + if (::closedir(dirPtr) == -1) { + // Only error from closedir is EBADF + dirStat = OTHER_ERROR; + } + + return dirStat; +} // end getFileCount + +} // namespace FileSystem + +} // namespace Os diff --git a/Os/Linux/SystemResources.cpp b/Os/Linux/SystemResources.cpp index bb7a23661c..90df778fcd 100644 --- a/Os/Linux/SystemResources.cpp +++ b/Os/Linux/SystemResources.cpp @@ -9,104 +9,161 @@ // acknowledged. // // ====================================================================== -#include /* fopen() */ -#include /* scanf */ -#include /* statfs() */ -#include /* get_nprocs() */ +#include #include +#include #include #include +constexpr char PROC_STAT_PATH[] = "/proc/stat"; +constexpr char READ_ONLY[] = "r"; +constexpr int LINE_SIZE = 256; +char proc_stat_line[LINE_SIZE]; + namespace Os { - SystemResources::SystemResourcesStatus SystemResources::getCpuCount(U32 &cpuCount) { + SystemResources::SystemResourcesStatus SystemResources::getCpuCount(U32& cpuCount) { cpuCount = get_nprocs(); return SYSTEM_RESOURCES_OK; } - SystemResources::SystemResourcesStatus SystemResources::getCpuTicks(CpuTicks &cpu_ticks, U32 cpu_index) { - char line[512] = {0}; - FILE *fp = nullptr; - U32 cpu_data[4] = {0}; - U32 cpuCount = 0; - SystemResources::SystemResourcesStatus status = SYSTEM_RESOURCES_ERROR; - U64 cpuUsed = 0; - U64 cpuTotal = 0; + U64 getCpuUsed(U32 cpu_data[4]) { + return cpu_data[0] + cpu_data[1] + cpu_data[2]; + } + U64 getCpuTotal(U32 cpu_data[4]) { + return cpu_data[0] + cpu_data[1] + cpu_data[2] + cpu_data[3]; + } - if ((status = getCpuCount(cpuCount)) != SYSTEM_RESOURCES_OK) { - return status; + SystemResources::SystemResourcesStatus openProcStatFile(FILE*& fp) { + if ((fp = fopen(PROC_STAT_PATH, READ_ONLY)) == nullptr) { + return SystemResources::SYSTEM_RESOURCES_ERROR; } + return SystemResources::SYSTEM_RESOURCES_OK; + } - if (cpu_index >= cpuCount) { - return SYSTEM_RESOURCES_ERROR; + SystemResources::SystemResourcesStatus readProcStatLine(FILE* fp, char proc_stat_line[LINE_SIZE]) { + if (fgets(proc_stat_line, LINE_SIZE, fp) == nullptr) { + return SystemResources::SYSTEM_RESOURCES_ERROR; } + return SystemResources::SYSTEM_RESOURCES_OK; + } - if ((fp = fopen("/proc/stat", "r")) == nullptr) { + SystemResources::SystemResourcesStatus getCpuDataLine(FILE* fp, + U32 cpu_index, + char proc_stat_line[LINE_SIZE]) { + for (U32 i = 0; i < cpu_index + 1; i++) { + if (readProcStatLine(fp, proc_stat_line) != SystemResources::SYSTEM_RESOURCES_OK) { + return SystemResources::SYSTEM_RESOURCES_ERROR; + } + if (i != cpu_index) { + continue; + } + if (strncmp(proc_stat_line, "cpu", 3) != 0) { + return SystemResources::SYSTEM_RESOURCES_ERROR; + } + break; + } + return SystemResources::SYSTEM_RESOURCES_OK; + } - return SYSTEM_RESOURCES_ERROR; + SystemResources::SystemResourcesStatus parseCpuData(char proc_stat_line[LINE_SIZE], + U32 cpu_data[4]) { + if (sscanf(proc_stat_line, "%*s %d %d %d %d", &cpu_data[0], &cpu_data[1], &cpu_data[2], &cpu_data[3]) != + 4) { + return SystemResources::SYSTEM_RESOURCES_ERROR; + } + return SystemResources::SYSTEM_RESOURCES_OK; + } + SystemResources::SystemResourcesStatus getCpuData(U32 cpu_index, U32 cpu_data[4]) { + FILE* fp = nullptr; + if (openProcStatFile(fp) != SystemResources::SYSTEM_RESOURCES_OK) { + return SystemResources::SYSTEM_RESOURCES_ERROR; } - if (fgets(line, sizeof(line), fp) == nullptr) { //1st line. Aggregate cpu line. + if (readProcStatLine(fp, proc_stat_line) != SystemResources::SYSTEM_RESOURCES_OK || + getCpuDataLine(fp, cpu_index, proc_stat_line) != SystemResources::SYSTEM_RESOURCES_OK || + parseCpuData(proc_stat_line, cpu_data) != SystemResources::SYSTEM_RESOURCES_OK) { fclose(fp); - return SYSTEM_RESOURCES_ERROR; + return SystemResources::SYSTEM_RESOURCES_ERROR; } + fclose(fp); + return SystemResources::SYSTEM_RESOURCES_OK; + } - for (U32 i = 0; i < cpu_index + 1; i++) { - if (fgets(line, sizeof(line), fp) == nullptr) { //cpu# line - fclose(fp); - return SYSTEM_RESOURCES_ERROR; - } - if (i != cpu_index) { continue; } - - if (!(line[0] == 'c' && line[1] == 'p' && line[2] == 'u')) { - fclose(fp); - return SYSTEM_RESOURCES_ERROR; - } - // No string concerns, as string is discarded - sscanf(line, "%*s %d %d %d %d", &cpu_data[0], - &cpu_data[1], - &cpu_data[2], - &cpu_data[3]); //cpu#: 4 numbers: usr, nice, sys, idle + SystemResources::SystemResourcesStatus SystemResources::getCpuTicks(CpuTicks& cpu_ticks, U32 cpu_index) { + SystemResources::SystemResourcesStatus status = SYSTEM_RESOURCES_ERROR; + U32 cpu_data[4] = {0}; + U32 cpuCount = 0; - cpuUsed = cpu_data[0] + cpu_data[1] + cpu_data[2]; - cpuTotal = cpu_data[0] + cpu_data[1] + cpu_data[2] + cpu_data[3]; + if ((status = getCpuCount(cpuCount)) != SYSTEM_RESOURCES_OK) { + return status; + } + if (cpu_index >= cpuCount) { + return SYSTEM_RESOURCES_ERROR; + } - break; + if ((status = getCpuData(cpu_index, cpu_data)) != SYSTEM_RESOURCES_OK) { + return status; } - fclose(fp); - cpu_ticks.used = cpuUsed; - cpu_ticks.total = cpuTotal; + cpu_ticks.used = getCpuUsed(cpu_data); + cpu_ticks.total = getCpuTotal(cpu_data); return SYSTEM_RESOURCES_OK; } - SystemResources::SystemResourcesStatus SystemResources::getMemUtil(MemUtil &memory_util) { - FILE *fp = nullptr; - NATIVE_INT_TYPE total = 0; - NATIVE_INT_TYPE free = 0; - // Fallbacks - memory_util.total = 1; - memory_util.used = 1; - fp = fopen("/proc/meminfo", "r"); - if (fp == nullptr) { + U64 getMemoryTotal(FwSizeType total_ram, FwSizeType memory_unit) { + return static_cast(total_ram)*static_cast(memory_unit); + } + U64 getMemoryUsed(FwSizeType total_ram, FwSizeType free_ram, FwSizeType memory_unit) { + return static_cast((total_ram - free_ram)) * static_cast(memory_unit); + } + + bool checkCastingAndTypeErrors(FwSizeType total_ram, + FwSizeType free_ram, + FwSizeType memory_unit, + const struct sysinfo& memory_info) { + return ((total_ram <= 0) || (memory_unit <= 0) || + (static_cast(total_ram) != memory_info.totalram) || + (static_cast(free_ram) != memory_info.freeram) || + (static_cast(memory_unit) != memory_info.mem_unit)); + } + + bool checkInvalidMemoryCalculation(FwSizeType total_ram, FwSizeType free_ram) { + return (total_ram < free_ram); + } + + bool checkMultiplicationOverflow(FwSizeType total_ram, FwSizeType memory_unit) { + return (total_ram > (std::numeric_limits::max() / memory_unit)); + } + + SystemResources::SystemResourcesStatus SystemResources::getMemUtil(MemUtil& memory_util) { + struct sysinfo memory_info; + + if (sysinfo(&memory_info) != 0) { return SYSTEM_RESOURCES_ERROR; } - // No string concerns as strings discarded - if (fscanf(fp, "%*s %d %*s", &total) != 1 || /* 1st line is MemTotal */ - fscanf(fp, "%*s %d", &free) != 1) { /* 2nd line is MemFree */ - fclose(fp); + + const FwSizeType total_ram = static_cast(memory_info.totalram); + const FwSizeType free_ram = static_cast(memory_info.freeram); + const FwSizeType memory_unit = static_cast(memory_info.mem_unit); + + if (checkCastingAndTypeErrors(total_ram, free_ram, memory_unit, memory_info)) { return SYSTEM_RESOURCES_ERROR; } - fclose(fp); - // Check results - if (total < 0 or free < 0 or total < free) { + if (checkInvalidMemoryCalculation(total_ram, free_ram)) { return SYSTEM_RESOURCES_ERROR; } - memory_util.total = static_cast(total) * 1024; // KB to Bytes - memory_util.used = static_cast(total - free) * 1024; + + if (checkMultiplicationOverflow(total_ram, memory_unit)) { + return SYSTEM_RESOURCES_ERROR; + } + + memory_util.used = getMemoryUsed(total_ram, free_ram, memory_unit); + memory_util.total = getMemoryTotal(total_ram, memory_unit); + return SYSTEM_RESOURCES_OK; } } diff --git a/Os/Linux/WatchdogTimer.cpp b/Os/Linux/WatchdogTimer.cpp index 79f7e0f6b7..e1b686ca87 100644 --- a/Os/Linux/WatchdogTimer.cpp +++ b/Os/Linux/WatchdogTimer.cpp @@ -1,4 +1,5 @@ #include +#include namespace Os { @@ -26,6 +27,11 @@ namespace Os { return WATCHDOG_CANCEL_ERROR; } + void WatchdogTimer::expire() { + FW_ASSERT(m_cb != nullptr); + m_cb(m_parameter); + } + } diff --git a/Os/LocklessQueue.hpp b/Os/LocklessQueue.hpp index 9bc686a69d..2eb8f6044b 100644 --- a/Os/LocklessQueue.hpp +++ b/Os/LocklessQueue.hpp @@ -1,7 +1,7 @@ #ifndef _LOCKLESS_QUEUE_H_ #define _LOCKLESS_QUEUE_H_ -#include +#include #include #ifndef BUILD_DARWIN // Allow compiling #include diff --git a/Os/Log.hpp b/Os/Log.hpp index 38e36933a8..0690b19cd4 100644 --- a/Os/Log.hpp +++ b/Os/Log.hpp @@ -6,7 +6,7 @@ #ifndef _Log_hpp_ #define _Log_hpp_ -#include +#include #include namespace Os { diff --git a/Os/MacOs/SystemResources.cpp b/Os/MacOs/SystemResources.cpp index ded252b382..500ba129c7 100644 --- a/Os/MacOs/SystemResources.cpp +++ b/Os/MacOs/SystemResources.cpp @@ -30,7 +30,7 @@ namespace Os { * \param total: total memory in bytes * \return: kern_return_t with success/failure straight from the kernel */ -kern_return_t vm_stat_helper(U64& used, U64& total) { +kern_return_t vm_stat_helper(FwSizeType& used, FwSizeType& total) { mach_msg_type_number_t count = HOST_VM_INFO_COUNT; vm_statistics_data_t vmstat; vm_size_t vmsize; @@ -79,7 +79,7 @@ kern_return_t cpu_data_helper(processor_cpu_load_info_t& cpu_load_info, U32& cpu * * \return success/failure using kern_return_t */ -kern_return_t cpu_by_index(U32 cpu_index, U64& used, U64& total) { +kern_return_t cpu_by_index(U32 cpu_index, FwSizeType& used, FwSizeType& total) { processor_cpu_load_info_t cpu_load_info; U32 cpu_count = 0; kern_return_t stat = cpu_data_helper(cpu_load_info, cpu_count); diff --git a/Os/Mem.hpp b/Os/Mem.hpp index 05207d899b..2ef49c81a2 100644 --- a/Os/Mem.hpp +++ b/Os/Mem.hpp @@ -1,7 +1,7 @@ #ifndef _Mem_hpp_ #define _Mem_hpp_ -#include +#include #include #include diff --git a/Os/Mutex.hpp b/Os/Mutex.hpp index 692daf7ae6..9fc6507ff9 100644 --- a/Os/Mutex.hpp +++ b/Os/Mutex.hpp @@ -1,7 +1,7 @@ #ifndef _Mutex_hpp_ #define _Mutex_hpp_ -#include +#include namespace Os { diff --git a/Os/Posix/TaskId.cpp b/Os/Posix/TaskId.cpp index 33274dfaf5..ad007c224e 100644 --- a/Os/Posix/TaskId.cpp +++ b/Os/Posix/TaskId.cpp @@ -13,9 +13,8 @@ extern "C" { namespace Os { - TaskId::TaskId() + TaskId::TaskId() : id(pthread_self()) { - id = pthread_self(); } TaskId::~TaskId() { diff --git a/Os/Pthreads/BufferQueue.hpp b/Os/Pthreads/BufferQueue.hpp index 222a3dff5e..78b3c73d0c 100644 --- a/Os/Pthreads/BufferQueue.hpp +++ b/Os/Pthreads/BufferQueue.hpp @@ -13,7 +13,7 @@ #ifndef OS_PTHREADS_BUFFER_QUEUE_HPP #define OS_PTHREADS_BUFFER_QUEUE_HPP -#include +#include // This is a generic buffer queue interface. namespace Os { diff --git a/Os/Pthreads/MaxHeap/MaxHeap.cpp b/Os/Pthreads/MaxHeap/MaxHeap.cpp index 5a6dc4e3c6..baa18a8071 100644 --- a/Os/Pthreads/MaxHeap/MaxHeap.cpp +++ b/Os/Pthreads/MaxHeap/MaxHeap.cpp @@ -15,7 +15,7 @@ // ====================================================================== #include "Os/Pthreads/MaxHeap/MaxHeap.hpp" -#include "Fw/Types/BasicTypes.hpp" +#include #include "Fw/Types/Assert.hpp" #include diff --git a/Os/Pthreads/MaxHeap/MaxHeap.hpp b/Os/Pthreads/MaxHeap/MaxHeap.hpp index c897347d77..22066c6d17 100644 --- a/Os/Pthreads/MaxHeap/MaxHeap.hpp +++ b/Os/Pthreads/MaxHeap/MaxHeap.hpp @@ -13,7 +13,7 @@ #ifndef OS_PTHREADS_MAX_HEAP_HPP #define OS_PTHREADS_MAX_HEAP_HPP -#include "Fw/Types/BasicTypes.hpp" +#include namespace Os { diff --git a/Os/Queue.hpp b/Os/Queue.hpp index f0dbf63ca8..56c7804042 100644 --- a/Os/Queue.hpp +++ b/Os/Queue.hpp @@ -12,7 +12,7 @@ #ifndef _Queue_hpp_ #define _Queue_hpp_ -#include +#include #include #include #include @@ -24,7 +24,7 @@ namespace Os { class Queue { public: - typedef enum { + enum QueueStatus { QUEUE_OK, //!< message sent/received okay QUEUE_NO_MORE_MSGS, //!< If non-blocking, all the messages have been drained. QUEUE_UNINITIALIZED, //!< Queue wasn't initialized successfully @@ -35,12 +35,12 @@ namespace Os { QUEUE_EMPTY_BUFFER, //!< supplied buffer is empty QUEUE_FULL, //!< queue was full when attempting to send a message QUEUE_UNKNOWN_ERROR //!< Unexpected error; can't match with returns - } QueueStatus; + }; - typedef enum { + enum QueueBlocking { QUEUE_BLOCKING, //!< Queue receive blocks until a message arrives QUEUE_NONBLOCKING //!< Queue receive always returns even if there is no message - } QueueBlocking; + }; Queue(); virtual ~Queue(); diff --git a/Os/QueueString.hpp b/Os/QueueString.hpp index 16f2f0b6d4..8b590f5ced 100644 --- a/Os/QueueString.hpp +++ b/Os/QueueString.hpp @@ -1,9 +1,8 @@ #ifndef OS_QUEUE_STRING_TYPE_HPP #define OS_QUEUE_STRING_TYPE_HPP -#include -#include #include +#include namespace Os { diff --git a/Os/Stubs/CMakeLists.txt b/Os/Stubs/CMakeLists.txt index a1c4cd3686..2a3ff41f98 100644 --- a/Os/Stubs/CMakeLists.txt +++ b/Os/Stubs/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Os/Stubs/Linux/FileStub.cpp b/Os/Stubs/Linux/FileStub.cpp index 90c8cd4599..8b589cded7 100644 --- a/Os/Stubs/Linux/FileStub.cpp +++ b/Os/Stubs/Linux/FileStub.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/Os/SystemResources.hpp b/Os/SystemResources.hpp index 36f7bc7527..f0b8164063 100644 --- a/Os/SystemResources.hpp +++ b/Os/SystemResources.hpp @@ -12,7 +12,7 @@ #ifndef _SystemResources_hpp_ #define _SystemResources_hpp_ -#include +#include namespace Os { namespace SystemResources { @@ -23,13 +23,13 @@ enum SystemResourcesStatus { }; struct CpuTicks { - U64 used; //!< Filled with non-idle (system, user) CPU ticks - U64 total; //!< Filled with total CPU ticks + FwSizeType used; //!< Filled with non-idle (system, user) CPU ticks + FwSizeType total; //!< Filled with total CPU ticks }; struct MemUtil { - U64 used; //!< Filled with used bytes of volatile memory (permanent, paged-in) - U64 total; //!< Filled with total non-volatile memory + FwSizeType used; //!< Filled with used bytes of volatile memory (permanent, paged-in) + FwSizeType total; //!< Filled with total non-volatile memory }; /** @@ -49,18 +49,15 @@ SystemResourcesStatus getCpuCount(U32& cpu_count); * * \param ticks: (output) filled with the tick information for the given CPU * \param cpu_index: index for CPU to read - * \return: SYSTEM_RESOURCES_OK with valid CPU count, SYSTEM_RESOURCES_ERROR when error occurs + * \return: SYSTEM_RESOURCES_ERROR when error occurs, SYSTEM_RESOURCES_OK otherwise. */ SystemResourcesStatus getCpuTicks(CpuTicks& ticks, U32 cpu_index = 0); /** - * \brief Calculate the across-all-cpu average tick information - * - * See `getCpuTicks`. Operates in a similar capacity, but the aggregation is done across all CPUs not for - * a specific CPU. + * \brief Get system memory usage * - * \param ticks: (output) filled with the tick information for the given CPU - * \return: SYSTEM_RESOURCES_OK with valid CPU count, SYSTEM_RESOURCES_ERROR when error occurs + * \param memory_util: (output) data structure used to store memory usage + * \return: SYSTEM_RESOURCES_ERROR when error occurs, SYSTEM_RESOURCES_OK otherwise. */ SystemResourcesStatus getMemUtil(MemUtil& memory_util); } // namespace SystemResources diff --git a/Os/Task.hpp b/Os/Task.hpp index 2b403cf251..5e9d865195 100644 --- a/Os/Task.hpp +++ b/Os/Task.hpp @@ -2,7 +2,6 @@ #define _Task_hpp_ #include -#include #include #include diff --git a/Os/TaskCommon.cpp b/Os/TaskCommon.cpp index 57f3aa90c3..023bf6f742 100644 --- a/Os/TaskCommon.cpp +++ b/Os/TaskCommon.cpp @@ -1,11 +1,10 @@ #include #include -#include -#include -#include +#include + namespace Os { - const NATIVE_UINT_TYPE Task::TASK_DEFAULT = std::numeric_limits::max(); + const NATIVE_UINT_TYPE Task::TASK_DEFAULT = std::numeric_limits::max(); TaskRegistry* Task::s_taskRegistry = nullptr; NATIVE_INT_TYPE Task::s_numTasks = 0; diff --git a/Os/TaskLock.hpp b/Os/TaskLock.hpp index 957cfa690e..c044206c97 100644 --- a/Os/TaskLock.hpp +++ b/Os/TaskLock.hpp @@ -7,7 +7,7 @@ #ifndef _TaskLock_hpp_ #define _TaskLock_hpp_ -#include +#include namespace Os { class TaskLock { diff --git a/Os/TaskString.hpp b/Os/TaskString.hpp index 9b0befdc7d..1a100ed3ce 100644 --- a/Os/TaskString.hpp +++ b/Os/TaskString.hpp @@ -1,9 +1,8 @@ #ifndef OS_TASK_STRING_TYPE_HPP #define OS_TASK_STRING_TYPE_HPP -#include -#include #include +#include namespace Os { diff --git a/Os/ValidateFileCommon.cpp b/Os/ValidateFileCommon.cpp index c9c8bf3346..39b69b5325 100644 --- a/Os/ValidateFileCommon.cpp +++ b/Os/ValidateFileCommon.cpp @@ -18,9 +18,10 @@ namespace Os { // Get the file size: FileSystem::Status fs_status; - U64 fileSize = 0; + FwSizeType fileSize = 0; fs_status = FileSystem::getFileSize(fileName, fileSize); //!< gets the size of the file (in bytes) at location path - if( FileSystem::OP_OK != fs_status ) { + // fileSize will be used as a NATIVE_INT_TYPE below and thus must cast cleanly to that type + if( FileSystem::OP_OK != fs_status || static_cast(static_cast(fileSize)) != fileSize) { return File::BAD_SIZE; } const NATIVE_INT_TYPE max_itr = static_cast(fileSize/VFILE_HASH_CHUNK_SIZE + 1); diff --git a/Os/ValidatedFile.hpp b/Os/ValidatedFile.hpp index 0f30cd811c..69d19feed7 100644 --- a/Os/ValidatedFile.hpp +++ b/Os/ValidatedFile.hpp @@ -14,7 +14,7 @@ #define OS_ValidatedFile_HPP #include "Fw/Types/String.hpp" -#include "Fw/Types/BasicTypes.hpp" +#include #include "Os/ValidateFile.hpp" namespace Os { diff --git a/Os/WatchdogTimer.hpp b/Os/WatchdogTimer.hpp index 7593b7f2b0..d25c4b7d0f 100644 --- a/Os/WatchdogTimer.hpp +++ b/Os/WatchdogTimer.hpp @@ -1,7 +1,7 @@ #ifndef _WatchdogTimer_hpp_ #define _WatchdogTimer_hpp_ -#include +#include namespace Os { class WatchdogTimer { @@ -31,6 +31,7 @@ namespace Os { WatchdogStatus cancel(); //!< cancel timer + void expire(); //!< Invoke the callback function with m_parameter private: diff --git a/Os/test/ut/OsFileSystemTest.cpp b/Os/test/ut/OsFileSystemTest.cpp index 3ead1c4f3a..54608a4b69 100644 --- a/Os/test/ut/OsFileSystemTest.cpp +++ b/Os/test/ut/OsFileSystemTest.cpp @@ -22,7 +22,7 @@ void testTestFileSystem() { const char up_dir[] = "../"; const char cur_dir[] = "."; struct stat info; - U64 file_size = 42; + FwSizeType file_size = 42; U32 file_count = 0; const char test_string[] = "This is a test file."; NATIVE_INT_TYPE test_string_len = 0; diff --git a/Os/test/ut/OsSystemResourcesTest.cpp b/Os/test/ut/OsSystemResourcesTest.cpp index 1d6219cded..36cb78f2f5 100644 --- a/Os/test/ut/OsSystemResourcesTest.cpp +++ b/Os/test/ut/OsSystemResourcesTest.cpp @@ -7,7 +7,6 @@ void testTestSystemResources() { Os::SystemResources::SystemResourcesStatus sys_res_status; Os::SystemResources::CpuTicks cpuUtil; - Os::SystemResources::MemUtil memUtil; U32 cpuCount; U32 cpuIndex; @@ -22,9 +21,6 @@ void testTestSystemResources() { cpuIndex = 1000; sys_res_status = Os::SystemResources::getCpuTicks(cpuUtil, cpuIndex); ASSERT_EQ(sys_res_status, Os::SystemResources::SystemResourcesStatus::SYSTEM_RESOURCES_ERROR); - - sys_res_status = Os::SystemResources::getMemUtil(memUtil); - ASSERT_EQ(sys_res_status, Os::SystemResources::SystemResourcesStatus::SYSTEM_RESOURCES_OK); } extern "C" { diff --git a/Os/test/ut/OsValidateFileTest.cpp b/Os/test/ut/OsValidateFileTest.cpp index bca810b3b5..db749be20f 100644 --- a/Os/test/ut/OsValidateFileTest.cpp +++ b/Os/test/ut/OsValidateFileTest.cpp @@ -48,7 +48,7 @@ void testValidateFile(const char* fileName) { // Get file size: printf("Checking file size of %s.\n", hashFileName); - U64 fileSize=0; + FwSizeType fileSize=0; fsStatus = Os::FileSystem::getFileSize(hashFileName, fileSize); if( Os::FileSystem::OP_OK != fsStatus ) { printf("\tFailed to get file size of %s\n", hashFileName); diff --git a/README.md b/README.md index 210954c3bc..29fa2022e2 100644 --- a/README.md +++ b/README.md @@ -1,78 +1,69 @@ -# F´: A Flight-Proven, Multi-Platform, Open-Source Flight Software Framework +

+
+

A Flight-Proven, Multi-Platform, Open-Source Flight Software Framework

+

-[![Language grade: C++](https://img.shields.io/lgtm/grade/cpp/g/nasa/fprime.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/nasa/fprime/context:cpp) -[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/nasa/fprime.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/nasa/fprime/context:python) +# +F´ (F Prime) is a component-driven framework that enables rapid development and deployment of spaceflight and other embedded software applications. Originally developed at the [Jet Propulsion Laboratory](https://www.jpl.nasa.gov/), F´ has been successfully deployed on [several space applications](https://nasa.github.io/fprime/projects.html). It is tailored but not limited to small-scale spaceflight systems such as CubeSats, SmallSats, and instruments. -**F´ (F Prime)** is a component-driven framework that enables rapid development and deployment of spaceflight and other embedded software applications. Originally developed at the [Jet Propulsion Laboratory](https://www.jpl.nasa.gov/), F´ has been successfully deployed on several space applications. It is tailored but not limited to small-scale spaceflight systems such as CubeSats, SmallSats, and instruments. +**Please Visit the F´ Website:** [https://nasa.github.io/fprime](https://nasa.github.io/fprime/) for more information. -**Please Visit the F´ Website:** [https://nasa.github.io/fprime/](https://nasa.github.io/fprime/). This website contains project information, user guides, documentation, tutorials, and more! -F´ comprises several elements: +## What does F´ provide -* An architecture that decomposes flight software into discrete components with well-defined interfaces -* A C++ framework that provides core capabilities such as message queues and threads -* Modeling tools for specifying components and connections and automatically generating code -* A growing collection of ready-to-use components -* Testing tools for testing flight software at the unit and integration levels. +- An architecture that decomposes flight software into discrete components with well-defined interfaces +- A C++ framework that provides core capabilities such as message queues and threads +- Modeling tools for specifying components and connections and automatically generating code +- A growing collection of ready-to-use components +- Testing tools for testing flight software at the unit and integration levels. -For installation instructions, including virtual environment creation and installation verification, see [INSTALL.md](./docs/INSTALL.md). +Learn more about F' key features [here](https://nasa.github.io/fprime/features.html). -## Example Deployments -F´ comes with two example deployments. The deployments represent working F´ applications to help you understand F´. You can use these examples for reference, or clone them to start a new project. +## System Requirements -The next section links to more step-by-step tutorials, but it's a good idea to build and run at least the first example deployment to ensure that F´ is installed correctly. +1. Linux, Windows with WSL, or macOS operating system +2. git +3. [CMake 3.16+](https://cmake.org/download/). CLI tool must be available on the system path. +4. CLang or GNU C and C++ compilers (e.g. gcc and g++) +5. [Python 3.7+](https://www.python.org/downloads/), virtual environments, and PIP -**Example one:** [Ref](./Ref/README.md) - The standard reference application demonstrates how most of the system components should be wired together. The reference application can build on Linux or macOS, allowing you to get started immediately without the need for embedded hardware. +## Getting Started -**Example two:** [RPI](./RPI/README.md) +To get started with F´, install the F´ toolset with: +``` +pip install fprime-tools +``` -This Raspberry PI application shows how to run F´ in an embedded context by running on the Raspberry PI (a $35 embedded Linux computer). This application shows you how to get started on embedded projects with cross-compiling, drivers, and more. The Raspberry Pi was chosen because it is commercially available for a low price and runs Linux. +Then, create a new project with: +``` +fprime-util new --project +``` -## Tutorials +See the [HelloWorld Tutorial](https://nasa.github.io/fprime/Tutorials/HelloWorld/Tutorial.html) to guide you through all the steps of developing an F´ project. -F´ provides several tutorials in order to help understand and develop within the framework. These tutorials cover basic component creation, system and topology design, tooling, and more. These tutorials are available at [docs/Tutorials/README.md](./docs/Tutorials/README.md). +New users are encouraged to read through the [User Guide](https://nasa.github.io/fprime/UsersGuide/guide.html) and explore the [other tutorials](https://nasa.github.io/fprime/Tutorials/README.html). -## Getting Help with F´ -As F´ becomes a community centered product line, there are more items available from the community at large. +## Getting Help -To ask questions, discuss improvements, ask for help, please use the project's GitHub Discussions at: [https://github.com/nasa/fprime/discussions](https://github.com/nasa/fprime/discussions). +### Discussions +To ask questions, discuss improvements, and ask for help please use the project's [GitHub Discussions](https://github.com/nasa/fprime/discussions). +### Bug reports +To report bugs and issues, [open an issue here](https://github.com/nasa/fprime/issues). +### Community +The [F´ Community](https://github.com/fprime-community) GitHub Organization contains third party contributions, more documentation of flight software development, and additional resources. -The F´ community GitHub Organization contains third party contributions, more documentation of flight software development, and more! [https://github.com/fprime-community](https://github.com/fprime-community). -You can open issues with this repository at: [https://github.com/nasa/fprime/issues](https://github.com/nasa/fprime/issues) +## Resources +- [User Guide](https://nasa.github.io/fprime/UsersGuide/guide.html) +- [Tutorials](https://nasa.github.io/fprime/Tutorials/README.html) +- [Discussions](https://github.com/nasa/fprime/discussions) +- [Submit an Issue](https://github.com/nasa/fprime/issues) +- [F´ Community](https://github.com/fprime-community) -## F´ Features - -F´ has the following key features that enable robust embedded system design. - -### Reusability - -F´'s component-based architecture enables a high degree of modularity and software reusability. - -### Rapid Deployment - -F´ provides a complete development ecosystem, including modeling tools, testing tools, and a ground data system. Developers use the modeling tools to write high-level specifications, automatically generate implementations in C++, and fill in the implementations with domain-specific code. The framework and the code generators provide all the boilerplate code required in an F´ deployment, including code for thread management, code for communication between components, and code for handling commands, telemetry, and parameters. The testing tools and the ground data system simplify software testing, both on workstations and on flight hardware in the lab. - -### Portability - -F´ runs on a wide range of processors, from microcontrollers to multicore computers, and on several operating systems. Porting F´ to new operating systems is straightforward. - -### High Performance - -F´ utilizes a point-to-point architecture. The architecture minimizes the use of computational resources and is well suited for smaller processors. - -### Adaptability - -F´ is tailored to the level of complexity required for small missions. This makes F´ accessible and easy to use while still supporting a wide variety of missions. - -### Analyzability - -The typed port connections provide strong compile-time guarantees of correctness. ## Release Notes -The version history and artifacts associated with the project can be found at [Releases](https://github.com/nasa/fprime/releases) and [CHANGELOG.md](./CHANGELOG.md). +The version history and artifacts associated with the project can be found at [Releases](https://github.com/nasa/fprime/releases). \ No newline at end of file diff --git a/RPI/README.md b/RPI/README.md index 85593ded52..48fdac77f0 100644 --- a/RPI/README.md +++ b/RPI/README.md @@ -39,13 +39,20 @@ If the UART port is not set up correctly, there will be a file open error. **Install the packages necessary to run the demo.** -Please see [INSTALL.md](../docs/INSTALL.md) to ensure that the F´ application has been installed and tested with the basic Ref. For cross-compiling, clone the cross-compile tools from [here](https://github.com/raspberrypi/tools). This demo has configuration files that assume that the tools have been installed in `/opt/rpi`. If they are installed elsewhere, the user can set the environment variable `RPI_TOOLCHAIN_DIR` to the full tools directory. e.g. in bash the user may run `export RPI_TOOLCHAIN_DIR=/opt/rpi/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/`. +Please see [INSTALL.md](../docs/INSTALL.md) to ensure that the F´ application has been installed and tested with the basic Ref. Additionally, the +cross-compilers need to be installed. This is done by installing the `gcc-arm-linux-gnueabihf` and `g++-arm-linux-gnueabihf` packages on the host +system. This is shown on Ubuntu below. + +**Example: Installing Cross-Compilers for Raspberry PI on Ubuntu** +``` +sudo apt update && sudo apt install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf +``` ### Build the software **Crosscompiling using CMake:** -The following commands are described at length in the getting started [tutorial](../docs/Tutorials/GettingStarted/Tutorial.md). These commands will +The following commands are described at length in the getting started [tutorial](../docs/Tutorials/HelloWorld/Tutorial.md). These commands will go to the RPI directory and generate a build directory for the RPI example. This step generates a CMake Cache, sets the toolchain use to build the code and does an initial scan of the source tree. Since the RPI example sets a default F´ toolchain file in its CMakeLists.txt, we do not need to supply one on the command line when generating the build. This only needs to be done once to prepare for the build because CMake will detect diff --git a/RPI/RpiDemo/CMakeLists.txt b/RPI/RpiDemo/CMakeLists.txt index 6b66fbe00d..ecfb698cf6 100644 --- a/RPI/RpiDemo/CMakeLists.txt +++ b/RPI/RpiDemo/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/RPI/RpiDemo/RpiDemo.fpp b/RPI/RpiDemo/RpiDemo.fpp index c323acfe8c..01bee01e73 100644 --- a/RPI/RpiDemo/RpiDemo.fpp +++ b/RPI/RpiDemo/RpiDemo.fpp @@ -17,11 +17,6 @@ module RPI { PIN_24 = 1 } - enum GpioVal { - CLEAR = 0 - SET = 1 - } - enum LedState { BLINKING = 0 OFF = 1 @@ -35,7 +30,7 @@ module RPI { async input port Run: Svc.Sched @ Input port for receiving UART data - async input port UartRead: Drv.SerialRead + async input port UartRead: Drv.ByteStreamRecv @ Output Port for reading GPIO values output port GpioRead: [2] Drv.GpioRead @@ -47,7 +42,7 @@ module RPI { output port GpioWrite: [3] Drv.GpioWrite @ Output Port for writing UART data - output port UartWrite: Drv.SerialWrite + output port UartWrite: Drv.ByteStreamSend @ Output port for sending UART buffers to use for reading output port UartBuffers: Fw.BufferSend @@ -108,7 +103,7 @@ module RPI { @ Sets a GPIO port value async command RD_SetGpio( $output: GpioOutNum @< Output GPIO - value: GpioVal @< GPIO value + value: Fw.Logic @< GPIO value ) \ opcode 3 @@ -147,7 +142,7 @@ module RPI { @ GPIO set event RD_GpioSetVal( $output: U32 @< The output number - value: GpioVal @< GPIO value + value: Fw.Logic @< GPIO value ) \ severity activity high \ id 2 \ @@ -156,7 +151,7 @@ module RPI { @ GPIO get event RD_GpioGetVal( $output: U32 @< The output number - value: GpioVal @< GPIO value + value: Fw.Logic @< GPIO value ) \ severity activity high \ id 3 \ diff --git a/RPI/RpiDemo/RpiDemoComponentImpl.cpp b/RPI/RpiDemo/RpiDemoComponentImpl.cpp index 901209f30b..aa285559b6 100644 --- a/RPI/RpiDemo/RpiDemoComponentImpl.cpp +++ b/RPI/RpiDemo/RpiDemoComponentImpl.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include -#include "Fw/Types/BasicTypes.hpp" +#include #include namespace RPI { @@ -28,7 +28,7 @@ namespace RPI { ,m_uartWriteBytes(0) ,m_uartReadBytes(0) ,m_spiBytes(0) - ,m_currLedVal(RpiDemo_GpioVal::CLEAR) + ,m_currLedVal(Fw::Logic::LOW) ,m_ledOn(true) ,m_ledDivider(10) // start at 1Hz ,m_1HzTicks(0) @@ -54,13 +54,6 @@ namespace RPI { } void RpiDemoComponentImpl::preamble() { - // send buffers to UART driver - for (NATIVE_INT_TYPE buffer = 0; buffer < NUM_RPI_UART_BUFFERS; buffer++) { - // assign buffers to buffer containers - this->m_recvBuffers[buffer].setData(this->m_uartBuffers[buffer]); - this->m_recvBuffers[buffer].setSize(RPI_UART_READ_BUFF_SIZE); - this->UartBuffers_out(0, this->m_recvBuffers[buffer]); - } // check initial state parameter Fw::ParamValid valid; RpiDemo_LedState initState = paramGet_RD_PrmLedInitState(valid); @@ -106,9 +99,9 @@ namespace RPI { case RG_CONTEXT_10Hz: // Toggle LED value if ( (this->m_10HzTicks++%this->m_ledDivider == 0) and this->m_ledOn) { - this->GpioWrite_out(2, (this->m_currLedVal == RpiDemo_GpioVal::SET)); - this->m_currLedVal = (this->m_currLedVal == RpiDemo_GpioVal::SET) ? - RpiDemo_GpioVal::CLEAR : RpiDemo_GpioVal::SET; + this->GpioWrite_out(2, this->m_currLedVal); + this->m_currLedVal = (this->m_currLedVal == Fw::Logic::HIGH) ? + Fw::Logic::LOW : Fw::Logic::HIGH; } break; default: @@ -122,26 +115,25 @@ namespace RPI { UartRead_handler( const NATIVE_INT_TYPE portNum, Fw::Buffer &serBuffer, - Drv::SerialReadStatus &status + const Drv::RecvStatus &status ) { - // convert incoming data to string. If it is not printable, set character to '*' - char uMsg[serBuffer.getSize()+1]; - char* bPtr = reinterpret_cast(serBuffer.getData()); - - for (NATIVE_UINT_TYPE byte = 0; byte < serBuffer.getSize(); byte++) { - uMsg[byte] = isalpha(bPtr[byte])?bPtr[byte]:'*'; - } - uMsg[sizeof(uMsg)-1] = 0; + if (Drv::RecvStatus::RECV_OK == status.e) { + // convert incoming data to string. If it is not printable, set character to '*' + char uMsg[serBuffer.getSize() + 1]; + char *bPtr = reinterpret_cast(serBuffer.getData()); - Fw::LogStringArg evrMsg(uMsg); - this->log_ACTIVITY_HI_RD_UartMsgIn(evrMsg); - this->m_lastUartMsg = uMsg; - this->m_uartReadBytes += serBuffer.getSize(); + for (NATIVE_UINT_TYPE byte = 0; byte < serBuffer.getSize(); byte++) { + uMsg[byte] = isalpha(bPtr[byte]) ? bPtr[byte] : '*'; + } + uMsg[sizeof(uMsg) - 1] = 0; - // reset buffer size - serBuffer.setSize(RPI_UART_READ_BUFF_SIZE); - // return buffer to driver + Fw::LogStringArg evrMsg(uMsg); + this->log_ACTIVITY_HI_RD_UartMsgIn(evrMsg); + this->m_lastUartMsg = uMsg; + this->m_uartReadBytes += serBuffer.getSize(); + } + // return buffer to buffer manager this->UartBuffers_out(0, serBuffer); } @@ -159,12 +151,13 @@ namespace RPI { Fw::Buffer txt; txt.setSize(text.length()); txt.setData(reinterpret_cast(const_cast(text.toChar()))); - this->UartWrite_out(0, txt); - this->m_uartWriteBytes += text.length(); - - Fw::LogStringArg arg = text; - this->log_ACTIVITY_HI_RD_UartMsgOut(arg); + Drv::SendStatus status = this->UartWrite_out(0, txt); + if (Drv::SendStatus::SEND_OK == status.e) { + this->m_uartWriteBytes += text.length(); + Fw::LogStringArg arg = text; + this->log_ACTIVITY_HI_RD_UartMsgOut(arg); + } this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); } @@ -173,7 +166,7 @@ namespace RPI { const FwOpcodeType opCode, const U32 cmdSeq, RpiDemo_GpioOutNum output, /*!< Output GPIO*/ - RpiDemo_GpioVal value + Fw::Logic value ) { NATIVE_INT_TYPE port; @@ -195,7 +188,7 @@ namespace RPI { return; } // set value of GPIO - this->GpioWrite_out(port, (RpiDemo_GpioVal::SET == value.e)); + this->GpioWrite_out(port, value); this->log_ACTIVITY_HI_RD_GpioSetVal(output.e, value); this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); } @@ -222,12 +215,9 @@ namespace RPI { return; } // get value of GPIO input - bool val; + Fw::Logic val; this->GpioRead_out(port, val); - this->log_ACTIVITY_HI_RD_GpioGetVal( - input.e, - val ? RpiDemo_GpioVal::SET : RpiDemo_GpioVal::CLEAR - ); + this->log_ACTIVITY_HI_RD_GpioGetVal(input.e, val); this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); } diff --git a/RPI/RpiDemo/RpiDemoComponentImpl.hpp b/RPI/RpiDemo/RpiDemoComponentImpl.hpp index da42773048..3b42dda276 100644 --- a/RPI/RpiDemo/RpiDemoComponentImpl.hpp +++ b/RPI/RpiDemo/RpiDemoComponentImpl.hpp @@ -75,7 +75,7 @@ namespace RPI { void UartRead_handler( const NATIVE_INT_TYPE portNum, /*!< The port number*/ Fw::Buffer &serBuffer, /*!< Buffer containing data*/ - Drv::SerialReadStatus &status /*!< Status of read*/ + const Drv::RecvStatus &status /*!< Status of read*/ ) override; PRIVATE: @@ -98,7 +98,7 @@ namespace RPI { const FwOpcodeType opCode, /*!< The opcode*/ const U32 cmdSeq, /*!< The command sequence number*/ RpiDemo_GpioOutNum output, /*!< Output GPIO*/ - RpiDemo_GpioVal value /*!< GPIO value*/ + Fw::Logic value /*!< GPIO value*/ ) override; //! Implementation for RD_GetGpio command handler @@ -142,7 +142,7 @@ namespace RPI { U32 m_uartReadBytes; U32 m_spiBytes; Fw::TlmString m_lastUartMsg; - RpiDemo_GpioVal m_currLedVal; + Fw::Logic m_currLedVal; // serial buffers Fw::Buffer m_recvBuffers[NUM_RPI_UART_BUFFERS]; BYTE m_uartBuffers[NUM_RPI_UART_BUFFERS][RPI_UART_READ_BUFF_SIZE]; diff --git a/RPI/Top/CMakeLists.txt b/RPI/Top/CMakeLists.txt index 598fbfd9ef..8b504f2f06 100644 --- a/RPI/Top/CMakeLists.txt +++ b/RPI/Top/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/RPI/Top/instances.fpp b/RPI/Top/instances.fpp index 39cfec4c38..3ed9f5b002 100644 --- a/RPI/Top/instances.fpp +++ b/RPI/Top/instances.fpp @@ -50,12 +50,8 @@ module RPI { stack size Default.stackSize \ priority 20 \ { - - phase Fpp.ToCpp.Phases.instances """ - Svc::PrmDb prmDb(FW_OPTIONAL_NAME("prmDb"), "PrmDb.dat"); - """ - phase Fpp.ToCpp.Phases.readParameters """ + prmDb.configure("PrmDb.dat"); prmDb.readParamFile(); """ @@ -312,16 +308,16 @@ module RPI { instance textLogger: Svc.PassiveTextLogger base id 1900 - instance uartDrv: Drv.LinuxSerialDriver base id 2000 \ + instance uartDrv: Drv.LinuxUartDriver base id 2000 \ { phase Fpp.ToCpp.Phases.configComponents """ { const bool status = uartDrv.open("/dev/serial0", - Drv::LinuxSerialDriverComponentImpl::BAUD_19200, - Drv::LinuxSerialDriverComponentImpl::NO_FLOW, - Drv::LinuxSerialDriverComponentImpl::PARITY_NONE, - true + Drv::LinuxUartDriver::BAUD_19200, + Drv::LinuxUartDriver::NO_FLOW, + Drv::LinuxUartDriver::PARITY_NONE, + 1024 ); if (!status) { Fw::Logger::logMsg("[ERROR] Could not open UART driver\\n"); @@ -435,4 +431,38 @@ module RPI { } + instance uartBufferManager: Svc.BufferManager base id 2800 \ + { + + phase Fpp.ToCpp.Phases.configConstants """ + enum { + STORE_SIZE = 3000, + QUEUE_SIZE = 30, + MGR_ID = 300 + }; + """ + + phase Fpp.ToCpp.Phases.configComponents """ + { + Svc::BufferManager::BufferBins bufferBins; + memset(&bufferBins, 0, sizeof(bufferBins)); + using namespace ConfigConstants::uartBufferManager; + bufferBins.bins[0].bufferSize = STORE_SIZE; + bufferBins.bins[0].numBuffers = QUEUE_SIZE; + uartBufferManager.setup( + MGR_ID, + 0, + Allocation::mallocator, + // OK to supply a local object here: BufferManager makes a copy + bufferBins + ); + } + """ + + phase Fpp.ToCpp.Phases.tearDownComponents """ + uartBufferManager.cleanup(); + """ + } + + } diff --git a/RPI/Top/topology.fpp b/RPI/Top/topology.fpp index d54e3a1630..ba61be34b7 100644 --- a/RPI/Top/topology.fpp +++ b/RPI/Top/topology.fpp @@ -35,6 +35,7 @@ module RPI { instance textLogger instance uartDrv instance uplink + instance uartBufferManager # ---------------------------------------------------------------------- # Pattern graph specifiers @@ -121,9 +122,10 @@ module RPI { } connections UART { - rpiDemo.UartBuffers -> uartDrv.readBufferSend - rpiDemo.UartWrite -> uartDrv.serialSend - uartDrv.serialRecv -> rpiDemo.UartRead + rpiDemo.UartBuffers -> uartBufferManager.bufferSendIn + rpiDemo.UartWrite -> uartDrv.send + uartDrv.$recv -> rpiDemo.UartRead + uartDrv.allocate -> uartBufferManager.bufferGetCallee } connections Uplink { diff --git a/RPI/test/int/rpi_integration_test.py b/RPI/test/int/rpi_integration_test.py index 3f86c6d610..8ceb43148e 100644 --- a/RPI/test/int/rpi_integration_test.py +++ b/RPI/test/int/rpi_integration_test.py @@ -12,216 +12,166 @@ from fprime_gds.common.utils.event_severity import EventSeverity -class TestRefAppClass(object): - @classmethod - def setup_class(cls): - cls.pipeline = StandardPipeline() - config = ConfigManager() - filename = os.path.dirname(__file__) - path = os.path.join( - filename, - "../../build-artifacts/raspberrypi/dict/RPITopologyAppDictionary.xml", - ) - cls.pipeline.setup(config, path, "/tmp") - cls.pipeline.connect("127.0.0.1", 50050) - logpath = os.path.join(filename, "./logs") - cls.api = IntegrationTestAPI(cls.pipeline, logpath) - cls.case_list = [] # TODO find a better way to do this. - cls.dictionary = path - - @classmethod - def teardown_class(cls): - cls.pipeline.disconnect() - cls.api.teardown() - - def setup_method(self, method): - self.case_list.append(method.__name__) - self.api.start_test_case(method.__name__, len(self.case_list)) - - def test_is_streaming(self): - results = self.api.assert_telemetry_count(5, timeout=10) - for result in results: - msg = "received channel {} update: {}".format( - result.get_id(), result.get_str() - ) - print(msg) - - def assert_command(self, command, args=[], max_delay=None, timeout=5): - """ - This helper will send a command and verify that the command was dispatched and completed - within the F' deployment. This helper can retroactively check that the delay between - dispatch and completion is less than a maximum allowable delay. - - Args: - command: the mnemonic (str) or ID (int) of the command to send - args: a list of command arguments. - max_delay: the maximum allowable delay between dispatch and completion (int/float) - timeout: the number of seconds to wait before terminating the search (int) - Return: - returns a list of the EventData objects found by the search - """ - cmd_id = self.api.translate_command_name(command) - self.api.log( - "Starting assert_command helper for {}({})".format(command, cmd_id) +""" +This enum is includes the values of EventSeverity that can be filtered by the ActiveLogger Component +""" +FilterSeverity = Enum( + "FilterSeverity", + "WARNING_HI WARNING_LO COMMAND ACTIVITY_HI ACTIVITY_LO DIAGNOSTIC", +) + + +def set_event_filter(fprime_test_api, severity, enabled): + """ + This helper will send a command that updates the given severity filter on the ActiveLogger + Component in the Ref App. + Args: + severity: A valid FilterSeverity Enum Value (str) or an instance of FilterSeverity + enabled: a boolean of whether or not to enable the given severity + Return: + boolean of whether the report filter was set successfully. + """ + enabled = "ENABLED" if enabled else "DISABLED" + if isinstance(severity, FilterSeverity): + severity = severity.name + else: + severity = FilterSeverity[severity].name + try: + fprime_test_api.send_command( + "eventLogger.SET_EVENT_FILTER", + [severity, enabled], ) - events = [] - events.append(self.api.get_event_pred("OpCodeDispatched", [cmd_id, None])) - events.append(self.api.get_event_pred("OpCodeCompleted", [cmd_id])) - results = self.api.send_and_assert_event(command, args, events, timeout=timeout) - if max_delay is not None: - delay = results[1].get_time() - results[0].get_time() - msg = "The delay, {}, between the two events should be < {}".format( - delay, max_delay - ) - assert delay < max_delay, msg - self.api.log("assert_command helper completed successfully") - return results + return True + except AssertionError: + return False + +def set_default_filters(fprime_test_api): """ - This enum is includes the values of EventSeverity that can be filtered by the ActiveLogger Component + Sets the default send filters on the ref aps ActiveLogger """ - FilterSeverity = Enum( - "FilterSeverity", - "WARNING_HI WARNING_LO COMMAND ACTIVITY_HI ACTIVITY_LO DIAGNOSTIC", + set_event_filter(fprime_test_api, "COMMAND", True) + set_event_filter(fprime_test_api, "ACTIVITY_LO", True) + set_event_filter(fprime_test_api, "ACTIVITY_HI", True) + set_event_filter(fprime_test_api, "WARNING_LO", True) + set_event_filter(fprime_test_api, "WARNING_HI", True) + set_event_filter(fprime_test_api, "DIAGNOSTIC", False) + + +def test_is_streaming(fprime_test_api): + results = fprime_test_api.assert_telemetry_count(5, timeout=10) + for result in results: + msg = "received channel {} update: {}".format(result.get_id(), result.get_str()) + print(msg) + + +def test_send_command(fprime_test_api): + fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP", max_delay=0.1) + assert fprime_test_api.get_command_test_history().size() == 1 + fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP", max_delay=0.1) + assert fprime_test_api.get_command_test_history().size() == 2 + + +def test_send_and_assert_no_op(fprime_test_api): + length = 100 + failed = 0 + evr_seq = ["OpCodeDispatched", "NoOpReceived", "OpCodeCompleted"] + any_reordered = False + dropped = False + for i in range(0, length): + results = fprime_test_api.send_and_await_event( + "cmdDisp.CMD_NO_OP", events=evr_seq, timeout=25 + ) + msg = "Send and assert NO_OP Trial #{}".format(i) + if not fprime_test_api.test_assert(len(results) == 3, msg, True): + items = fprime_test_api.get_event_test_history().retrieve() + last = None + reordered = False + for item in items: + if last is not None: + if item.get_time() < last.get_time(): + fprime_test_api.log( + "during iteration #{}, a reordered event was detected: {}".format( + i, item + ) + ) + any_reordered = True + reordered = True + break + last = item + if not reordered: + fprime_test_api.log( + "during iteration #{}, a dropped event was detected".format(i) + ) + dropped = True + failed += 1 + fprime_test_api.clear_histories() + + case = True + case &= fprime_test_api.test_assert( + not any_reordered, "Expected no events to be reordered.", True ) + case &= fprime_test_api.test_assert( + not dropped, "Expected no events to be dropped.", True + ) + msg = "{} sequences failed out of {}".format(failed, length) + case &= fprime_test_api.test_assert(failed == 0, msg, True) - def set_event_filter(self, severity, enabled): - """ - This helper will send a command that updates the given severity filter on the ActiveLogger - Component in the Ref App. - Args: - severity: A valid FilterSeverity Enum Value (str) or an instance of FilterSeverity - enabled: a boolean of whether or not to enable the given severity - Return: - boolean of whether the report filter was set successfully. - """ - enabled = "ENABLED" if enabled else "DISABLED" - if isinstance(severity, self.FilterSeverity): - severity = severity.name - else: - severity = self.FilterSeverity[severity].name - try: - self.api.send_command( - "eventLogger.SET_EVENT_FILTER", - [severity, enabled], - ) - return True - except AssertionError: - return False - - def set_default_filters(self): - """ - Sets the default send filters on the ref aps ActiveLogger - """ - self.set_event_filter("COMMAND", True) - self.set_event_filter("ACTIVITY_LO", True) - self.set_event_filter("ACTIVITY_HI", True) - self.set_event_filter("WARNING_LO", True) - self.set_event_filter("WARNING_HI", True) - self.set_event_filter("DIAGNOSTIC", False) - - def test_send_command(self): - self.assert_command("cmdDisp.CMD_NO_OP", max_delay=0.1) - assert self.api.get_command_test_history().size() == 1 - self.assert_command("cmdDisp.CMD_NO_OP", max_delay=0.1) - assert self.api.get_command_test_history().size() == 2 - - def test_send_and_assert_no_op(self): - length = 100 - failed = 0 - evr_seq = ["OpCodeDispatched", "NoOpReceived", "OpCodeCompleted"] - any_reordered = False - dropped = False - for i in range(0, length): - results = self.api.send_and_await_event( - "cmdDisp.CMD_NO_OP", events=evr_seq, timeout=25 - ) - msg = "Send and assert NO_OP Trial #{}".format(i) - if not self.api.test_assert(len(results) == 3, msg, True): - items = self.api.get_event_test_history().retrieve() - last = None - reordered = False - for item in items: - if last is not None: - if item.get_time() < last.get_time(): - self.api.log( - "during iteration #{}, a reordered event was detected: {}".format( - i, item - ) - ) - any_reordered = True - reordered = True - break - last = item - if not reordered: - self.api.log( - "during iteration #{}, a dropped event was detected".format(i) - ) - dropped = True - failed += 1 - self.api.clear_histories() - - case = True - case &= self.api.test_assert( - not any_reordered, "Expected no events to be reordered.", True - ) - case &= self.api.test_assert( - not dropped, "Expected no events to be dropped.", True - ) - msg = "{} sequences failed out of {}".format(failed, length) - case &= self.api.test_assert(failed == 0, msg, True) - - assert ( - case - ), "Expected all checks to pass (reordering, dropped events, all passed). See log." - - def test_active_logger_filter(self): - self.set_default_filters() - try: - cmd_events = self.api.get_event_pred(severity=EventSeverity.COMMAND) - actHI_events = self.api.get_event_pred(severity=EventSeverity.ACTIVITY_HI) - pred = predicates.greater_than(0) - zero = predicates.equal_to(0) - # Drain time for dispatch events - time.sleep(10) - - self.assert_command("cmdDisp.CMD_NO_OP") - self.assert_command("cmdDisp.CMD_NO_OP") - - time.sleep(0.5) - - self.api.assert_event_count(pred, cmd_events) - self.api.assert_event_count(pred, actHI_events) - - self.set_event_filter(self.FilterSeverity.COMMAND, False) - # Drain time for dispatch events - time.sleep(10) - self.api.clear_histories() - self.api.send_command("cmdDisp.CMD_NO_OP") - self.api.send_command("cmdDisp.CMD_NO_OP") - - time.sleep(0.5) - - self.api.assert_event_count(zero, cmd_events) - self.api.assert_event_count(pred, actHI_events) - finally: - self.set_default_filters() - - def test_seqgen(self): - """Tests the seqgen code""" - sequence = os.path.join(os.path.dirname(__file__), "test_seq.seq") - assert ( - subprocess.run( - [ - "fprime-seqgen", - "-d", - self.dictionary, - sequence, - "/tmp/ref_test_int.bin", - ] - ).returncode - == 0 - ), "Failed to run fprime-seqgen" - self.assert_command( - "cmdSeq.CS_RUN", args=["/tmp/ref_test_int.bin", "BLOCK"], max_delay=5 + assert ( + case + ), "Expected all checks to pass (reordering, dropped events, all passed). See log." + + +def test_active_logger_filter(fprime_test_api): + set_default_filters(fprime_test_api) + try: + cmd_events = fprime_test_api.get_event_pred(severity=EventSeverity.COMMAND) + actHI_events = fprime_test_api.get_event_pred( + severity=EventSeverity.ACTIVITY_HI ) + pred = predicates.greater_than(0) + zero = predicates.equal_to(0) + # Drain time for dispatch events + time.sleep(10) + + fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP") + fprime_test_api.send_and_assert_command("cmdDisp.CMD_NO_OP") + + time.sleep(0.5) + + fprime_test_api.assert_event_count(pred, cmd_events) + fprime_test_api.assert_event_count(pred, actHI_events) + + set_event_filter(fprime_test_api, FilterSeverity.COMMAND, False) + # Drain time for dispatch events + time.sleep(10) + fprime_test_api.clear_histories() + fprime_test_api.send_command("cmdDisp.CMD_NO_OP") + fprime_test_api.send_command("cmdDisp.CMD_NO_OP") + + time.sleep(0.5) + + fprime_test_api.assert_event_count(zero, cmd_events) + fprime_test_api.assert_event_count(pred, actHI_events) + finally: + set_default_filters(fprime_test_api) + + +def test_seqgen(fprime_test_api): + """Tests the seqgen code""" + sequence = os.path.join(os.path.dirname(__file__), "test_seq.seq") + assert ( + subprocess.run( + [ + "fprime-seqgen", + "-d", + str(fprime_test_api.pipeline.dictionary_path), + sequence, + "/tmp/ref_test_int.bin", + ] + ).returncode + == 0 + ), "Failed to run fprime-seqgen" + fprime_test_api.send_and_assert_command( + "cmdSeq.CS_RUN", args=["/tmp/ref_test_int.bin", "BLOCK"], max_delay=5 + ) diff --git a/Ref/CMakeLists.txt b/Ref/CMakeLists.txt index 1fc6ca4e41..766689ec3a 100644 --- a/Ref/CMakeLists.txt +++ b/Ref/CMakeLists.txt @@ -43,11 +43,12 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/PingReceiver/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/RecvBuffApp/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SendBuffApp/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/SignalGen/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/TypeDemo/") # Add Topology subdirectory add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Top/") -set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Top/Main.cpp") +set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Main.cpp") set(MOD_DEPS ${PROJECT_NAME}/Top) register_fprime_deployment() diff --git a/Ref/ComponentReport.txt b/Ref/ComponentReport.txt deleted file mode 100644 index 5ae06642df..0000000000 --- a/Ref/ComponentReport.txt +++ /dev/null @@ -1,51 +0,0 @@ - -Component Interface Report: ---------- --------- ------ -Input Ports: 113 -Output Ports: 163 -Commands: 49 -Channels: 39 -Events: 136 -Parameters: 4 - -Use the below to tune the lookup algorithms. - -Command Opcodes: 0,1,2,3,0,1,2,3,10,11,12,13,0x00,1,2,0,0x00,0x00,0x01,0x02,0x03,0,1,2,3,0,1,2,3,4,5,6,0x0,0,1,2,3,4,0,0x0,0x1,0x2,0,1,0x0,0x1,0x2,0x3,0x4 -Telemetry IDs: 0,1,2,3,4,5,0,1,2,3,4,0,0,0,0,0,1,0,1,0,1,2,3,4,0,1,0x0,0,1,2,0,1,2,0x0,0x1,0,0,1,0 -Event IDs: 0,1,2,0,1,2,3,0,0,1,0x00,0x01,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0,1,2,3,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,0,1,2,3,0,1,0x0,0x1,0x2,0x3,0,1,2,0,1,2,3,4,5,6,0,1,2,3,4,5,6,7,0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0,1,2,3,4,5,6,7,0,1,2,3,0,1,2,3,4,5,6,7,0x0,0x1,0x2,0x3,0x4,0x5,0,1,2,3,4,5,6,0,1,2,3,4,5,6,0,1,2,4, -Parameter IDs: 0,1,0,1, - -Stats: - -Component,InputPorts,OutputPorts,Commands,Channels,Events,Parameters - -/Ref/RecvBuffApp/RecvBuff,1,0,4,6,3,2 -/Ref/SendBuffApp/SendBuff,1,1,8,5,4,2 -/Ref/SignalGen/SignalGen,2,6,3,1,1,0 -/Ref/PingReceiver/PingReceiver,1,1,1,1,2,0 -/Svc/BufferAccumulator/BufferAccumulator,5,9,1,1,2,0 -/Svc/BufferLogger/BufferLogger,5,8,4,1,7,0 -/Svc/BufferManager/BufferManager,2,3,0,2,4,0 -/Svc/CmdDispatcher/CommandDispatcher,27,26,4,2,10,0 -/Svc/CmdSequencer/CmdSequencer,5,9,7,5,23,0 -/Svc/GndIf/GndIf,3,7,0,0,4,0 -/Svc/ActiveRateGroup/ActiveRateGroup,2,11,0,2,2,0 -/Svc/RateGroupDriver/RateGroupDriver,1,3,0,0,0,0 -/Svc/ComLogger/ComLogger,3,5,1,0,4,0 -/Svc/BuffGndSockIf/BuffGndSockIf,1,6,0,0,3,0 -/Svc/TlmChan/TlmChan,4,2,0,0,0,0 -/Svc/PassiveTextLogger/PassiveTextLogger,1,0,0,0,0,0 -/Svc/Time/Time,1,0,0,0,0,0 -/Svc/ActiveLogger/ActiveLogger,2,3,5,0,7,0 -/Svc/PolyDb/PolyDb,2,0,0,0,0,0 -/Svc/PrmDb/PrmDb,3,1,1,0,8,0 -/Svc/Health/Health,26,26,3,1,8,0 -/Svc/FileUplink/FileUplink,2,5,0,3,8,0 -/Svc/FileDownlink/FileDownlink,2,8,2,3,4,0 -/Svc/AssertFatalAdapter/AssertFatalAdapter,0,0,0,0,8,0 -/Svc/FatalHandler/FatalHandler,1,0,0,0,0,0 -/Svc/FileManager/FileManager,2,6,5,2,6,0 -/Drv/BlockDriver/BlockDriver,3,3,0,1,0,0 -/Drv/LinuxGpioDriver/LinuxGpioDriver,2,5,0,0,7,0 -/Drv/LinuxSerialDriver/LinuxSerialDriver,2,5,0,2,7,0 -/Drv/LinuxSpiDriver/LinuxSpiDriver,1,4,0,1,4,0 diff --git a/Ref/LINUX_SlocReport.csv b/Ref/LINUX_SlocReport.csv deleted file mode 100644 index b808eb2b11..0000000000 --- a/Ref/LINUX_SlocReport.csv +++ /dev/null @@ -1,67 +0,0 @@ -make[1]: Entering directory '/home/ablack/fprime-sw/Ref' -/usr/bin/gcc -o /home/ablack/fprime-sw/mk/bin/ncsl /home/ablack/fprime-sw/mk/tools/ncsl/ncsl.c -Module, HAND, AC, XML, TOTAL -Ref/Top, 342, 279, 780, 1401 -Ref/RecvBuffApp, 111, 1535, 90, 1736 -Ref/SendBuffApp, 176, 2354, 165, 2695 -Ref/SignalGen, 171, 1290, 32, 1493 -Ref/PingReceiver, 80, 1192, 51, 1323 -Svc/BufferAccumulator, 280, 1757, 33, 2070 -Svc/BufferLogger, 447, 2445, 33, 2925 -Svc/BufferManager, 327, 893, 23, 1243 -Svc/CmdDispatcher, 237, 2910, 232, 3379 -Svc/CmdSequencer, 1820, 4322, 47, 6189 -Svc/Seq, 0, 138, 13, 151 -Svc/GndIf, 0, 1312, 48, 1360 -Svc/ActiveRateGroup, 92, 1121, 61, 1274 -Svc/RateGroupDriver, 69, 231, 25, 325 -Svc/Sched, 0, 137, 12, 149 -Svc/ComLogger, 261, 1462, 30, 1753 -Svc/SocketGndIf, 401, 0, 0, 401 -Svc/BuffGndSockIf, 270, 860, 25, 1155 -Svc/TlmChan, 213, 766, 41, 1020 -Svc/PassiveTextLogger, 0, 152, 19, 171 -Svc/PassiveConsoleTextLogger, 76, 0, 0, 76 -Svc/Time, 0, 140, 13, 153 -Svc/Cycle, 68, 138, 13, 219 -Svc/LinuxTime, 47, 0, 0, 47 -Svc/ActiveLogger, 513, 2358, 254, 3125 -Svc/Fatal, 0, 137, 12, 149 -Svc/PolyIf, 0, 161, 28, 189 -Svc/PolyDb, 66, 255, 18, 339 -Svc/PrmDb, 301, 1921, 155, 2377 -Svc/Ping, 0, 137, 12, 149 -Svc/Health, 201, 2210, 194, 2605 -Svc/WatchDog, 0, 137, 12, 149 -Svc/FileUplink, 389, 1600, 27, 2016 -Svc/FileDownlink, 411, 1626, 44, 2081 -Svc/AssertFatalAdapter, 206, 1406, 6, 1618 -Svc/FatalHandler, 69, 139, 13, 221 -Svc/FileManager, 256, 2117, 24, 2397 -Drv/DataTypes, 55, 138, 13, 206 -Drv/BlockDriver, 73, 1029, 70, 1172 -Drv/GpioDriverPorts, 0, 274, 16, 290 -Drv/LinuxGpioDriver, 317, 1169, 25, 1511 -Drv/LinuxSerialDriver, 352, 1284, 29, 1665 -Drv/LinuxSpiDriver, 163, 924, 23, 1110 -Drv/SerialDriverPorts, 0, 290, 29, 319 -Drv/SpiDriverPorts, 0, 143, 11, 154 -Fw/FilePacket, 632, 0, 0, 632 -Fw/Cfg, 226, 0, 0, 226 -Fw/Buffer, 0, 456, 52, 508 -Fw/Comp, 265, 0, 0, 265 -Fw/Obj, 172, 0, 0, 172 -Fw/Port, 367, 0, 0, 367 -Fw/Cmd, 199, 442, 57, 698 -Fw/Tlm, 275, 149, 20, 444 -Fw/Prm, 143, 267, 40, 450 -Fw/Log, 485, 330, 64, 879 -Fw/Time, 277, 138, 13, 428 -Fw/Com, 95, 143, 16, 254 -Fw/ComFile, 84, 0, 0, 84 -Fw/SerializableFile, 91, 0, 0, 91 -Fw/Types, 2191, 0, 0, 2191 -Os, 2245, 0, 0, 2245 -CFDP/Checksum, 139, 0, 0, 139 -Utils/Hash, 330, 0, 0, 330 -make[1]: Leaving directory '/home/ablack/fprime-sw/Ref' diff --git a/Ref/Main.cpp b/Ref/Main.cpp new file mode 100644 index 0000000000..568ff89682 --- /dev/null +++ b/Ref/Main.cpp @@ -0,0 +1,95 @@ +// ====================================================================== +// \title Main.cpp +// \author mstarch +// \brief main program for reference application. Intended for CLI-based systems (Linux, macOS) +// +// \copyright +// Copyright 2009-2022, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// ====================================================================== +// Used to access topology functions +#include +// Used for signal handling shutdown +#include +// Used for command line argument processing +#include +// Used for printf functions +#include + +/** + * \brief print commandline help message + * + * This will print a command line help message including the available command line arguments. + * + * @param app: name of application + */ +void print_usage(const char* app) { + (void)printf("Usage: ./%s [options]\n-a\thostname/IP address\n-p\tport_number\n", app); +} + +/** + * \brief shutdown topology cycling on signal + * + * The reference topology allows for a simulated cycling of the rate groups. This simulated cycling needs to be stopped + * in order for the program to shutdown. This is done via handling signals such that it is performed via Ctrl-C + * + * @param signum + */ +static void signalHandler(int signum) { + Ref::stopSimulatedCycle(); +} + +/** + * \brief execute the program + * + * This F´ program is designed to run in standard environments (e.g. Linux/macOs running on a laptop). Thus it uses + * command line inputs to specify how to connect. + * + * @param argc: argument count supplied to program + * @param argv: argument values supplied to program + * @return: 0 on success, something else on failure + */ +int main(int argc, char* argv[]) { + U32 port_number = 0; + I32 option = 0; + char* hostname = nullptr; + + // Loop while reading the getopt supplied options + while ((option = getopt(argc, argv, "hp:a:")) != -1) { + switch (option) { + // Handle the -a argument for address/hostname + case 'a': + hostname = optarg; + break; + // Handle the -p port number argument + case 'p': + port_number = static_cast(atoi(optarg)); + break; + // Cascade intended: help output + case 'h': + // Cascade intended: help output + case '?': + // Default case: output help and exit + default: + print_usage(argv[0]); + return (option == 'h') ? 0 : 1; + } + } + // Object for communicating state to the reference topology + Ref::TopologyState inputs; + inputs.hostname = hostname; + inputs.port = port_number; + + // Setup program shutdown via Ctrl-C + signal(SIGINT, signalHandler); + signal(SIGTERM, signalHandler); + (void)printf("Hit Ctrl-C to quit\n"); + + // Setup, cycle, and teardown topology + Ref::setupTopology(inputs); + Ref::startSimulatedCycle(1000); // Program loop cycling rate groups at 1Hz + Ref::teardownTopology(inputs); + (void)printf("Exiting...\n"); + return 0; +} diff --git a/Ref/PingReceiver/CMakeLists.txt b/Ref/PingReceiver/CMakeLists.txt index 20be4c249d..16c15bd70f 100644 --- a/Ref/PingReceiver/CMakeLists.txt +++ b/Ref/PingReceiver/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Ref/PingReceiver/PingReceiverComponentImpl.cpp b/Ref/PingReceiver/PingReceiverComponentImpl.cpp index 6b5ca46d0f..a4c77f7338 100644 --- a/Ref/PingReceiver/PingReceiverComponentImpl.cpp +++ b/Ref/PingReceiver/PingReceiverComponentImpl.cpp @@ -12,7 +12,7 @@ #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace Ref { diff --git a/Ref/README.md b/Ref/README.md index e7b04ccc39..3760603d1e 100644 --- a/Ref/README.md +++ b/Ref/README.md @@ -63,7 +63,7 @@ cd fprime/Ref/build-artifacts//bin/ - The F´ utility's build command can build individual components too. - The 'generate' command can take a toolchain argument for quickly generating a cross-compile `fprime-util generate raspberrypi` for example. -Further work with the F´ utility can be found in the [Getting Started](../docs/Tutorials/GettingStarted/Tutorial.md) tutorial. Other tutorials +Further work with the F´ utility can be found in the [Getting Started](../docs/Tutorials/HelloWorld/Tutorial.md) tutorial. Other tutorials for many aspects of F´ are available [here](../docs/Tutorials/README.md). diff --git a/Ref/RecvBuffApp/CMakeLists.txt b/Ref/RecvBuffApp/CMakeLists.txt index af7f7b9f71..d02e6346c1 100644 --- a/Ref/RecvBuffApp/CMakeLists.txt +++ b/Ref/RecvBuffApp/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Ref/RecvBuffApp/RecvBuffComponentImpl.cpp b/Ref/RecvBuffApp/RecvBuffComponentImpl.cpp index 5abe54d39e..120960814e 100644 --- a/Ref/RecvBuffApp/RecvBuffComponentImpl.cpp +++ b/Ref/RecvBuffApp/RecvBuffComponentImpl.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include diff --git a/Ref/SendBuffApp/CMakeLists.txt b/Ref/SendBuffApp/CMakeLists.txt index beadc881f1..c05f766586 100644 --- a/Ref/SendBuffApp/CMakeLists.txt +++ b/Ref/SendBuffApp/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Ref/SendBuffApp/SendBuffComponentImpl.cpp b/Ref/SendBuffApp/SendBuffComponentImpl.cpp index 5e7dd37d63..8d8865a6dc 100644 --- a/Ref/SendBuffApp/SendBuffComponentImpl.cpp +++ b/Ref/SendBuffApp/SendBuffComponentImpl.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/Ref/SignalGen/CMakeLists.txt b/Ref/SignalGen/CMakeLists.txt index 64eea103d9..142e35fc8a 100644 --- a/Ref/SignalGen/CMakeLists.txt +++ b/Ref/SignalGen/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### @@ -17,4 +17,5 @@ set(UT_SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" "${CMAKE_CURRENT_LIST_DIR}/test/ut/TestMain.cpp" ) +set(UT_AUTO_HELPERS ON) register_fprime_ut() diff --git a/Ref/SignalGen/test/ut/Tester.cpp b/Ref/SignalGen/test/ut/Tester.cpp index 21db548ede..e7fa38f730 100644 --- a/Ref/SignalGen/test/ut/Tester.cpp +++ b/Ref/SignalGen/test/ut/Tester.cpp @@ -12,10 +12,6 @@ #include "Tester.hpp" -#define INSTANCE 0 -#define MAX_HISTORY_SIZE 10 -#define QUEUE_DEPTH 10 - namespace Ref { // ---------------------------------------------------------------------- @@ -51,75 +47,4 @@ namespace Ref { component.doDispatch(); ASSERT_TLM_Output_SIZE(1); } - - // ---------------------------------------------------------------------- - // Helper methods - // ---------------------------------------------------------------------- - - void Tester :: - connectPorts() - { - - // cmdIn - this->connect_to_cmdIn( - 0, - this->component.get_cmdIn_InputPort(0) - ); - - // schedIn - this->connect_to_schedIn( - 0, - this->component.get_schedIn_InputPort(0) - ); - - // timeCaller - this->component.set_timeCaller_OutputPort( - 0, - this->get_from_timeCaller(0) - ); - - // cmdRegOut - this->component.set_cmdRegOut_OutputPort( - 0, - this->get_from_cmdRegOut(0) - ); - - // logTextOut - this->component.set_logTextOut_OutputPort( - 0, - this->get_from_logTextOut(0) - ); - - // logOut - this->component.set_logOut_OutputPort( - 0, - this->get_from_logOut(0) - ); - - // cmdResponseOut - this->component.set_cmdResponseOut_OutputPort( - 0, - this->get_from_cmdResponseOut(0) - ); - - // tlmOut - this->component.set_tlmOut_OutputPort( - 0, - this->get_from_tlmOut(0) - ); - - - - - } - - void Tester :: - initComponents() - { - this->init(); - this->component.init( - QUEUE_DEPTH, INSTANCE - ); - } - } // end namespace Ref diff --git a/Ref/SignalGen/test/ut/Tester.hpp b/Ref/SignalGen/test/ut/Tester.hpp index 17ff6e52b2..c52c2a6808 100644 --- a/Ref/SignalGen/test/ut/Tester.hpp +++ b/Ref/SignalGen/test/ut/Tester.hpp @@ -21,12 +21,17 @@ namespace Ref { class Tester : public SignalGenGTestBase { - // ---------------------------------------------------------------------- // Construction and destruction // ---------------------------------------------------------------------- public: + // Maximum size of histories storing events, telemetry, and port outputs + static const NATIVE_INT_TYPE MAX_HISTORY_SIZE = 10; + // Instance ID supplied to the component instance under test + static const NATIVE_INT_TYPE TEST_INSTANCE_ID = 0; + // Queue depth supplied to component instance under test + static const NATIVE_INT_TYPE TEST_INSTANCE_QUEUE_DEPTH = 10; //! Construct object Tester //! diff --git a/Ref/Top/CMakeLists.txt b/Ref/Top/CMakeLists.txt index 499f256bd4..fce5416991 100644 --- a/Ref/Top/CMakeLists.txt +++ b/Ref/Top/CMakeLists.txt @@ -1,14 +1,15 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies #### set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/instances.fpp" + "${CMAKE_CURRENT_LIST_DIR}/RefPackets.xml" "${CMAKE_CURRENT_LIST_DIR}/topology.fpp" - "${CMAKE_CURRENT_LIST_DIR}/RefTopologyDefs.cpp" + "${CMAKE_CURRENT_LIST_DIR}/RefTopology.cpp" ) set(MOD_DEPS Fw/Logger @@ -18,4 +19,4 @@ set(MOD_DEPS Drv/TcpClient ) -register_fprime_module() \ No newline at end of file +register_fprime_module() diff --git a/Ref/Top/FppConstantsAc.cpp b/Ref/Top/FppConstantsAc.cpp deleted file mode 100644 index 92d79cfe4f..0000000000 --- a/Ref/Top/FppConstantsAc.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// ====================================================================== -// \title FppConstantsAc.cpp -// \author Generated by fpp-to-cpp -// \brief cpp file for FPP constants -// -// \copyright -// Copyright (c) 2021 California Institute of Technology. -// U.S. Government sponsorship acknowledged. -// All rights reserved. -// ====================================================================== - -#include "Ref/Top/FppConstantsAc.hpp" - -namespace Ref { - - namespace Default { - - } - -} diff --git a/Ref/Top/FppConstantsAc.hpp b/Ref/Top/FppConstantsAc.hpp deleted file mode 100644 index 8d665860da..0000000000 --- a/Ref/Top/FppConstantsAc.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// ====================================================================== -// \title FppConstantsAc.hpp -// \author Generated by fpp-to-cpp -// \brief hpp file for FPP constants -// -// \copyright -// Copyright (c) 2021 California Institute of Technology. -// U.S. Government sponsorship acknowledged. -// All rights reserved. -// ====================================================================== - -#ifndef Ref_Top_FppConstantsAc_HPP -#define Ref_Top_FppConstantsAc_HPP - -#include "Fw/Types/BasicTypes.hpp" - -namespace Ref { - - namespace Default { - - enum FppConstant_queueSize { - queueSize = 10 - }; - - enum FppConstant_stackSize { - stackSize = 16384 - }; - - } - -} - -#endif diff --git a/Ref/Top/ISFApp.pdf b/Ref/Top/ISFApp.pdf deleted file mode 100644 index 9b161d0426..0000000000 Binary files a/Ref/Top/ISFApp.pdf and /dev/null differ diff --git a/Ref/Top/Main.cpp b/Ref/Top/Main.cpp deleted file mode 100644 index 0458508b67..0000000000 --- a/Ref/Top/Main.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include -#include -#include - -#include -#include - -void print_usage(const char* app) { - (void) printf("Usage: ./%s [options]\n-p\tport_number\n-a\thostname/IP address\n",app); -} - -#include -#include - -Ref::TopologyState state; -// Enable the console logging provided by Os::Log -Os::Log logger; - -volatile sig_atomic_t terminate = 0; - -static void sighandler(int signum) { - Ref::teardown(state); - terminate = 1; -} - -void run1cycle() { - // call interrupt to emulate a clock - Ref::blockDrv.callIsr(); - Os::Task::delay(1000); //10Hz -} - -void runcycles(NATIVE_INT_TYPE cycles) { - if (cycles == -1) { - while (true) { - run1cycle(); - } - } - - for (NATIVE_INT_TYPE cycle = 0; cycle < cycles; cycle++) { - run1cycle(); - } -} - -int main(int argc, char* argv[]) { - U32 port_number = 0; // Invalid port number forced - I32 option; - char *hostname; - option = 0; - hostname = nullptr; - - while ((option = getopt(argc, argv, "hp:a:")) != -1){ - switch(option) { - case 'h': - print_usage(argv[0]); - return 0; - break; - case 'p': - port_number = static_cast(atoi(optarg)); - break; - case 'a': - hostname = optarg; - break; - case '?': - return 1; - default: - print_usage(argv[0]); - return 1; - } - } - - (void) printf("Hit Ctrl-C to quit\n"); - - state = Ref::TopologyState(hostname, port_number); - Ref::setup(state); - - // register signal handlers to exit program - signal(SIGINT,sighandler); - signal(SIGTERM,sighandler); - - int cycle = 0; - - while (!terminate) { -// (void) printf("Cycle %d\n",cycle); - runcycles(1); - cycle++; - } - - // Give time for threads to exit - (void) printf("Waiting for threads...\n"); - Os::Task::delay(1000); - - (void) printf("Exiting...\n"); - - return 0; -} diff --git a/Ref/Top/RefPacketsAi.xml b/Ref/Top/RefPackets.xml similarity index 62% rename from Ref/Top/RefPacketsAi.xml rename to Ref/Top/RefPackets.xml index 3a9e2bc86e..edd64f2fc8 100644 --- a/Ref/Top/RefPacketsAi.xml +++ b/Ref/Top/RefPackets.xml @@ -18,8 +18,9 @@ - + + @@ -64,56 +65,96 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + + + + + + + + + diff --git a/Ref/Top/RefTopology.cpp b/Ref/Top/RefTopology.cpp new file mode 100644 index 0000000000..4266f97111 --- /dev/null +++ b/Ref/Top/RefTopology.cpp @@ -0,0 +1,188 @@ +// ====================================================================== +// \title Topology.cpp +// \author mstarch +// \brief cpp file containing the topology instantiation code +// +// \copyright +// Copyright 2009-2022, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// ====================================================================== +// Provides access to autocoded functions +#include +#include + +// Necessary project-specified types +#include +#include +#include + +// Used for 1Hz synthetic cycling +#include + +// Allows easy reference to objects in FPP/autocoder required namespaces +using namespace Ref; + +// Instantiate a system logger that will handle Fw::Logger::logMsg calls +Os::Log logger; + +// The reference topology uses a malloc-based allocator for components that need to allocate memory during the +// initialization phase. +Fw::MallocAllocator mallocator; + +// The reference topology uses the F´ packet protocol when communicating with the ground and therefore uses the F´ +// framing and deframing implementations. +Svc::FprimeFraming framing; +Svc::FprimeDeframing deframing; + +// The reference topology divides the incoming clock signal (1Hz) into sub-signals: 1Hz, 1/2Hz, and 1/4Hz +NATIVE_INT_TYPE rateGroupDivisors[Svc::RateGroupDriver::DIVIDER_SIZE] = {1, 2, 4}; + +// Rate groups may supply a context token to each of the attached children whose purpose is set by the project. The +// reference topology sets each token to zero as these contexts are unused in this project. +NATIVE_INT_TYPE rateGroup1Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {}; +NATIVE_INT_TYPE rateGroup2Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {}; +NATIVE_INT_TYPE rateGroup3Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {}; + +// A number of constants are needed for construction of the topology. These are specified here. +enum TopologyConstants { + CMD_SEQ_BUFFER_SIZE = 5 * 1024, + FILE_DOWNLINK_TIMEOUT = 1000, + FILE_DOWNLINK_COOLDOWN = 1000, + FILE_DOWNLINK_CYCLE_TIME = 1000, + FILE_DOWNLINK_FILE_QUEUE_DEPTH = 10, + HEALTH_WATCHDOG_CODE = 0x123, + COMM_PRIORITY = 100, + UPLINK_BUFFER_MANAGER_STORE_SIZE = 3000, + UPLINK_BUFFER_MANAGER_QUEUE_SIZE = 30, + UPLINK_BUFFER_MANAGER_ID = 200 +}; + +// Ping entries are autocoded, however; this code is not properly exported. Thus, it is copied here. +Svc::Health::PingEntry pingEntries[] = { + {PingEntries::blockDrv::WARN, PingEntries::blockDrv::FATAL, "blockDrv"}, + {PingEntries::tlmSend::WARN, PingEntries::tlmSend::FATAL, "chanTlm"}, + {PingEntries::cmdDisp::WARN, PingEntries::cmdDisp::FATAL, "cmdDisp"}, + {PingEntries::cmdSeq::WARN, PingEntries::cmdSeq::FATAL, "cmdSeq"}, + {PingEntries::eventLogger::WARN, PingEntries::eventLogger::FATAL, "eventLogger"}, + {PingEntries::fileDownlink::WARN, PingEntries::fileDownlink::FATAL, "fileDownlink"}, + {PingEntries::fileManager::WARN, PingEntries::fileManager::FATAL, "fileManager"}, + {PingEntries::fileUplink::WARN, PingEntries::fileUplink::FATAL, "fileUplink"}, + {PingEntries::pingRcvr::WARN, PingEntries::pingRcvr::FATAL, "pingRcvr"}, + {PingEntries::prmDb::WARN, PingEntries::prmDb::FATAL, "prmDb"}, + {PingEntries::rateGroup1Comp::WARN, PingEntries::rateGroup1Comp::FATAL, "rateGroup1Comp"}, + {PingEntries::rateGroup2Comp::WARN, PingEntries::rateGroup2Comp::FATAL, "rateGroup2Comp"}, + {PingEntries::rateGroup3Comp::WARN, PingEntries::rateGroup3Comp::FATAL, "rateGroup3Comp"}, +}; + +/** + * \brief configure/setup components in project-specific way + * + * This is a *helper* function which configures/sets up each component requiring project specific input. This includes + * allocating resources, passing-in arguments, etc. This function may be inlined into the topology setup function if + * desired, but is extracted here for clarity. + */ +void configureTopology() { + // Command sequencer needs to allocate memory to hold contents of command sequences + cmdSeq.allocateBuffer(0, mallocator, CMD_SEQ_BUFFER_SIZE); + + // Rate group driver needs a divisor list + rateGroupDriverComp.configure(rateGroupDivisors, FW_NUM_ARRAY_ELEMENTS(rateGroupDivisors)); + + // Rate groups require context arrays. Empty for Reference example. + rateGroup1Comp.configure(rateGroup1Context, FW_NUM_ARRAY_ELEMENTS(rateGroup1Context)); + rateGroup2Comp.configure(rateGroup2Context, FW_NUM_ARRAY_ELEMENTS(rateGroup2Context)); + rateGroup3Comp.configure(rateGroup3Context, FW_NUM_ARRAY_ELEMENTS(rateGroup3Context)); + + // File downlink requires some project-derived properties. + fileDownlink.configure(FILE_DOWNLINK_TIMEOUT, FILE_DOWNLINK_COOLDOWN, FILE_DOWNLINK_CYCLE_TIME, + FILE_DOWNLINK_FILE_QUEUE_DEPTH); + + // Parameter database is configured with a database file name, and that file must be initially read. + prmDb.configure("PrmDb.dat"); + prmDb.readParamFile(); + + // Health is supplied a set of ping entires. + health.setPingEntries(pingEntries, FW_NUM_ARRAY_ELEMENTS(pingEntries), HEALTH_WATCHDOG_CODE); + + // Buffer managers need a configured set of buckets and an allocator used to allocate memory for those buckets. + Svc::BufferManager::BufferBins upBuffMgrBins; + memset(&upBuffMgrBins, 0, sizeof(upBuffMgrBins)); + upBuffMgrBins.bins[0].bufferSize = UPLINK_BUFFER_MANAGER_STORE_SIZE; + upBuffMgrBins.bins[0].numBuffers = UPLINK_BUFFER_MANAGER_QUEUE_SIZE; + fileUplinkBufferManager.setup(UPLINK_BUFFER_MANAGER_ID, 0, mallocator, upBuffMgrBins); + + // Framer and Deframer components need to be passed a protocol handler + downlink.setup(framing); + uplink.setup(deframing); + + // Note: Uncomment when using Svc:TlmPacketizer + //tlmSend.setPacketList(RefPacketsPkts, RefPacketsIgnore, 1); +} + +// Public functions for use in main program are namespaced with deployment name Ref +namespace Ref { +void setupTopology(const TopologyState& state) { + // Autocoded initialization. Function provided by autocoder. + initComponents(state); + // Autocoded id setup. Function provided by autocoder. + setBaseIds(); + // Autocoded connection wiring. Function provided by autocoder. + connectComponents(); + // Autocoded command registration. Function provided by autocoder. + regCommands(); + // Project-specific component configuration. Function provided above. May be inlined, if desired. + configureTopology(); + // Autocoded parameter loading. Function provided by autocoder. + loadParameters(); + // Autocoded task kick-off (active components). Function provided by autocoder. + startTasks(state); + // Initialize socket client communication if and only if there is a valid specification + if (state.hostname != nullptr && state.port != 0) { + Os::TaskString name("ReceiveTask"); + // Uplink is configured for receive so a socket task is started + comm.configure(state.hostname, state.port); + comm.startSocketTask(name, true, COMM_PRIORITY, Default::STACK_SIZE); + } +} + +// Variables used for cycle simulation +Os::Mutex cycleLock; +volatile bool cycleFlag = true; + +void startSimulatedCycle(U32 milliseconds) { + cycleLock.lock(); + bool cycling = cycleFlag; + cycleLock.unLock(); + + // Main loop + while (cycling) { + Ref::blockDrv.callIsr(); + Os::Task::delay(milliseconds); + + cycleLock.lock(); + cycling = cycleFlag; + cycleLock.unLock(); + } +} + +void stopSimulatedCycle() { + cycleLock.lock(); + cycleFlag = false; + cycleLock.unLock(); +} + +void teardownTopology(const TopologyState& state) { + // Autocoded (active component) task clean-up. Functions provided by topology autocoder. + stopTasks(state); + freeThreads(state); + + // Other task clean-up. + comm.stopSocketTask(); + (void)comm.joinSocketTask(nullptr); + + // Resource deallocation + cmdSeq.deallocateBuffer(mallocator); + fileUplinkBufferManager.cleanup(); +} +}; // namespace Ref diff --git a/Ref/Top/RefTopology.hpp b/Ref/Top/RefTopology.hpp new file mode 100644 index 0000000000..b91e477f5f --- /dev/null +++ b/Ref/Top/RefTopology.hpp @@ -0,0 +1,91 @@ +// ====================================================================== +// \title Topology.hpp +// \author mstarch +// \brief header file containing the topology instantiation definitions +// +// \copyright +// Copyright 2009-2022, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// ====================================================================== +#ifndef REF_REFTOPOLOGY_HPP +#define REF_REFTOPOLOGY_HPP +// Included for access to Ref::TopologyState and Ref::ConfigObjects::pingEntries. These definitions are required by the +// autocoder, but are also used in this hand-coded topology. +#include + +// Remove unnecessary Ref:: qualifications +using namespace Ref; +namespace Ref { +/** + * \brief initialize and run the F´ topology + * + * Initializes, configures, and runs the F´ topology. This is performed through a series of steps, some provided via + * autocoded functions, and others provided via the functions implementation. These steps are: + * + * 1. Call the autocoded `initComponents()` function initializing each component via the `component.init` method + * 2. Call the autocoded `setBaseIds()` function to set the base IDs (offset) for each component instance + * 3. Call the autocoded `connectComponents()` function to wire-together the topology of components + * 4. Configure components requiring custom configuration + * 5. Call the autocoded `loadParameters()` function to cause each component to load initial parameter values + * 6. Call the autocoded `startTasks()` function to start the active component tasks + * 7. Start tasks not owned by active components + * + * Step 4 and step 7 are custom and supplied by the project. The ordering of steps 1, 2, 3, 5, and 6 are critical for + * F´ topologies to function. Configuration (step 4) typically assumes a connect but not started topology and is thus + * inserted between step 3 and 5. Step 7 may come before or after the active component initializations. Since these + * custom tasks often start radio communication it is convenient to start them last. + * + * The state argument carries command line inputs used to setup the topology. For an explanation of the required type + * Ref::TopologyState see: RefTopologyDefs.hpp. + * + * \param state: object shuttling CLI arguments (hostname, port) needed to construct the topology + */ +void setupTopology(const TopologyState& state); + +/** + * \brief teardown the F´ topology + * + * Tears down the F´ topology in preparation for shutdown. This is done via a series of steps, some provided by + * autocoded functions, and others provided via the function implementation. These steps are: + * + * 1. Call the autocoded `stopTasks()` function to stop the tasks started by `startTasks()` (active components) + * 2. Call the autocoded `freeThreads()` function to join to the tasks started by `startTasks()` + * 3. Stop the tasks not owned by active components + * 4. Join to the tasks not owned by active components + * 5. Deallocate other resources + * + * Step 1, 2, 3, and 4 must occur in-order as the tasks must be stopped before being joined. These tasks must be stopped + * and joined before any active resources may be deallocated. + * + * For an explanation of the required type Ref::TopologyState see: RefTopologyDefs.hpp. + * + * \param state: state object provided to setupTopology + */ +void teardownTopology(const TopologyState& state); + +/** + * \brief cycle the rate group driver at a crude rate + * + * The reference topology does not have a true 1Hz input clock for the rate group driver because it is designed to + * operate across various computing endpoints (e.g. laptops) where a clear 1Hz source may not be easily and generically + * achieved. This function mimics the cycling via a Task::delay(milliseconds) loop that manually invokes the ISR call + * to the example block driver. + * + * This loop is stopped via a startSimulatedCycle call. + * + * Note: projects should replace this with a component that produces an output port call at the appropriate frequency. + * + * \param milliseconds: milliseconds to delay for each cycle. Default: 1000 or 1Hz. + */ +void startSimulatedCycle(U32 milliseconds = 1000); + +/** + * \brief stop the simulated cycle started by startSimulatedCycle + * + * This stops the cycle started by startSimulatedCycle. + */ +void stopSimulatedCycle(); + +} // namespace Ref +#endif diff --git a/Ref/Top/RefTopologyAc.cpp b/Ref/Top/RefTopologyAc.cpp deleted file mode 100644 index b8455c2146..0000000000 --- a/Ref/Top/RefTopologyAc.cpp +++ /dev/null @@ -1,1349 +0,0 @@ -// ====================================================================== -// \title RefTopologyAc.cpp -// \author Generated by fpp-to-cpp -// \brief cpp file for Ref topology -// -// \copyright -// Copyright (c) 2021 California Institute of Technology. -// U.S. Government sponsorship acknowledged. -// All rights reserved. -// ====================================================================== - -#include "Ref/Top/RefTopologyAc.hpp" - -namespace Ref { - - namespace { - - // ---------------------------------------------------------------------- - // Component configuration objects - // ---------------------------------------------------------------------- - - namespace ConfigObjects { - - namespace downlink { - Svc::FprimeFraming framing; - } - - namespace health { - Svc::HealthImpl::PingEntry pingEntries[] = { - { - PingEntries::blockDrv::WARN, - PingEntries::blockDrv::FATAL, - "blockDrv" - }, - { - PingEntries::chanTlm::WARN, - PingEntries::chanTlm::FATAL, - "chanTlm" - }, - { - PingEntries::cmdDisp::WARN, - PingEntries::cmdDisp::FATAL, - "cmdDisp" - }, - { - PingEntries::cmdSeq::WARN, - PingEntries::cmdSeq::FATAL, - "cmdSeq" - }, - { - PingEntries::eventLogger::WARN, - PingEntries::eventLogger::FATAL, - "eventLogger" - }, - { - PingEntries::fileDownlink::WARN, - PingEntries::fileDownlink::FATAL, - "fileDownlink" - }, - { - PingEntries::fileManager::WARN, - PingEntries::fileManager::FATAL, - "fileManager" - }, - { - PingEntries::fileUplink::WARN, - PingEntries::fileUplink::FATAL, - "fileUplink" - }, - { - PingEntries::pingRcvr::WARN, - PingEntries::pingRcvr::FATAL, - "pingRcvr" - }, - { - PingEntries::prmDb::WARN, - PingEntries::prmDb::FATAL, - "prmDb" - }, - { - PingEntries::rateGroup1Comp::WARN, - PingEntries::rateGroup1Comp::FATAL, - "rateGroup1Comp" - }, - { - PingEntries::rateGroup2Comp::WARN, - PingEntries::rateGroup2Comp::FATAL, - "rateGroup2Comp" - }, - { - PingEntries::rateGroup3Comp::WARN, - PingEntries::rateGroup3Comp::FATAL, - "rateGroup3Comp" - }, - }; - } - - namespace rateGroup1Comp { - NATIVE_UINT_TYPE context[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - } - - namespace rateGroup2Comp { - NATIVE_UINT_TYPE context[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - } - - namespace rateGroup3Comp { - NATIVE_UINT_TYPE context[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - } - - namespace rateGroupDriverComp { - NATIVE_INT_TYPE rgDivs[Svc::RateGroupDriver::DIVIDER_SIZE] = { 1, 2, 4 }; - } - - namespace uplink { - Svc::FprimeDeframing deframing; - } - - } - - // ---------------------------------------------------------------------- - // Component instances - // ---------------------------------------------------------------------- - - // SG1 - SignalGen SG1(FW_OPTIONAL_NAME("SG1")); - - // SG2 - SignalGen SG2(FW_OPTIONAL_NAME("SG2")); - - // SG3 - SignalGen SG3(FW_OPTIONAL_NAME("SG3")); - - // SG4 - SignalGen SG4(FW_OPTIONAL_NAME("SG4")); - - // SG5 - SignalGen SG5(FW_OPTIONAL_NAME("SG5")); - - // blockDrv - // Declared in RefTopologyDefs.cpp - - // chanTlm - Svc::TlmChan chanTlm(FW_OPTIONAL_NAME("chanTlm")); - - // cmdDisp - Svc::CommandDispatcher cmdDisp(FW_OPTIONAL_NAME("cmdDisp")); - - // cmdSeq - Svc::CmdSequencer cmdSeq(FW_OPTIONAL_NAME("cmdSeq")); - - // comm - Drv::TcpClient comm(FW_OPTIONAL_NAME("comm")); - - // downlink - Svc::Framer downlink(FW_OPTIONAL_NAME("downlink")); - - // eventLogger - Svc::ActiveLogger eventLogger(FW_OPTIONAL_NAME("eventLogger")); - - // fatalAdapter - Svc::AssertFatalAdapter fatalAdapter(FW_OPTIONAL_NAME("fatalAdapter")); - - // fatalHandler - Svc::FatalHandler fatalHandler(FW_OPTIONAL_NAME("fatalHandler")); - - // fileDownlink - Svc::FileDownlink fileDownlink(FW_OPTIONAL_NAME("fileDownlink")); - - // fileManager - Svc::FileManager fileManager(FW_OPTIONAL_NAME("fileManager")); - - // fileUplink - Svc::FileUplink fileUplink(FW_OPTIONAL_NAME("fileUplink")); - - // fileUplinkBufferManager - Svc::BufferManager fileUplinkBufferManager(FW_OPTIONAL_NAME("fileUplinkBufferManager")); - - // health - Svc::Health health(FW_OPTIONAL_NAME("health")); - - // linuxTime - Svc::LinuxTime linuxTime(FW_OPTIONAL_NAME("linuxTime")); - - // pingRcvr - PingReceiver pingRcvr(FW_OPTIONAL_NAME("pingRcvr")); - - // prmDb - Svc::PrmDb prmDb(FW_OPTIONAL_NAME("prmDb"), "PrmDb.dat"); - - // rateGroup1Comp - Svc::ActiveRateGroup rateGroup1Comp( - FW_OPTIONAL_NAME("rateGroup1Comp"), - ConfigObjects::rateGroup1Comp::context, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::rateGroup1Comp::context) - ); - - // rateGroup2Comp - Svc::ActiveRateGroup rateGroup2Comp( - FW_OPTIONAL_NAME("rateGroup2Comp"), - ConfigObjects::rateGroup2Comp::context, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::rateGroup2Comp::context) - ); - - // rateGroup3Comp - Svc::ActiveRateGroup rateGroup3Comp( - FW_OPTIONAL_NAME("rateGroup3Comp"), - ConfigObjects::rateGroup3Comp::context, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::rateGroup3Comp::context) - ); - - // rateGroupDriverComp - Svc::RateGroupDriver rateGroupDriverComp( - FW_OPTIONAL_NAME("rateGroupDriverComp"), - ConfigObjects::rateGroupDriverComp::rgDivs, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::rateGroupDriverComp::rgDivs) - ); - - // recvBuffComp - RecvBuff recvBuffComp(FW_OPTIONAL_NAME("recvBuffComp")); - - // sendBuffComp - SendBuff sendBuffComp(FW_OPTIONAL_NAME("sendBuffComp")); - - // staticMemory - Svc::StaticMemory staticMemory(FW_OPTIONAL_NAME("staticMemory")); - - // textLogger - Svc::PassiveTextLogger textLogger(FW_OPTIONAL_NAME("textLogger")); - - // uplink - Svc::Deframer uplink(FW_OPTIONAL_NAME("uplink")); - - // ---------------------------------------------------------------------- - // Private functions - // ---------------------------------------------------------------------- - - // Initialize components - void initComponents(const TopologyState& state) { - SG1.init(QueueSizes::SG1, InstanceIds::SG1); - SG2.init(QueueSizes::SG2, InstanceIds::SG2); - SG3.init(QueueSizes::SG3, InstanceIds::SG3); - SG4.init(QueueSizes::SG4, InstanceIds::SG4); - SG5.init(QueueSizes::SG5, InstanceIds::SG5); - blockDrv.init(QueueSizes::blockDrv, InstanceIds::blockDrv); - chanTlm.init(QueueSizes::chanTlm, InstanceIds::chanTlm); - cmdDisp.init(QueueSizes::cmdDisp, InstanceIds::cmdDisp); - cmdSeq.init(QueueSizes::cmdSeq, InstanceIds::cmdSeq); - comm.init(InstanceIds::comm); - downlink.init(InstanceIds::downlink); - eventLogger.init(QueueSizes::eventLogger, InstanceIds::eventLogger); - fatalAdapter.init(InstanceIds::fatalAdapter); - fatalHandler.init(InstanceIds::fatalHandler); - fileDownlink.init(QueueSizes::fileDownlink, InstanceIds::fileDownlink); - fileManager.init(QueueSizes::fileManager, InstanceIds::fileManager); - fileUplink.init(QueueSizes::fileUplink, InstanceIds::fileUplink); - fileUplinkBufferManager.init(InstanceIds::fileUplinkBufferManager); - health.init(QueueSizes::health, InstanceIds::health); - linuxTime.init(InstanceIds::linuxTime); - pingRcvr.init(QueueSizes::pingRcvr, InstanceIds::pingRcvr); - prmDb.init(QueueSizes::prmDb, InstanceIds::prmDb); - rateGroup1Comp.init(QueueSizes::rateGroup1Comp, InstanceIds::rateGroup1Comp); - rateGroup2Comp.init(QueueSizes::rateGroup2Comp, InstanceIds::rateGroup2Comp); - rateGroup3Comp.init(QueueSizes::rateGroup3Comp, InstanceIds::rateGroup3Comp); - rateGroupDriverComp.init(InstanceIds::rateGroupDriverComp); - recvBuffComp.init(InstanceIds::recvBuffComp); - sendBuffComp.init(QueueSizes::sendBuffComp, InstanceIds::sendBuffComp); - staticMemory.init(InstanceIds::staticMemory); - textLogger.init(InstanceIds::textLogger); - uplink.init(InstanceIds::uplink); - } - - // Configure components - void configComponents(const TopologyState& state) { - cmdSeq.allocateBuffer( - 0, - Allocation::mallocator, - ConfigConstants::cmdSeq::BUFFER_SIZE - ); - downlink.setup(ConfigObjects::downlink::framing); - fileDownlink.configure( - ConfigConstants::fileDownlink::TIMEOUT, - ConfigConstants::fileDownlink::COOLDOWN, - ConfigConstants::fileDownlink::CYCLE_TIME, - ConfigConstants::fileDownlink::FILE_QUEUE_DEPTH - ); - Svc::BufferManager::BufferBins upBuffMgrBins; - memset(&upBuffMgrBins, 0, sizeof(upBuffMgrBins)); - { - using namespace ConfigConstants::fileUplinkBufferManager; - upBuffMgrBins.bins[0].bufferSize = STORE_SIZE; - upBuffMgrBins.bins[0].numBuffers = QUEUE_SIZE; - fileUplinkBufferManager.setup( - MGR_ID, - 0, - Allocation::mallocator, - upBuffMgrBins - ); - } - health.setPingEntries( - ConfigObjects::health::pingEntries, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::health::pingEntries), - ConfigConstants::health::WATCHDOG_CODE - ); - uplink.setup(ConfigObjects::uplink::deframing); - } - - // Set component base Ids - void setBaseIds() { - blockDrv.setIdBase(BaseIds::blockDrv); - rateGroup1Comp.setIdBase(BaseIds::rateGroup1Comp); - rateGroup2Comp.setIdBase(BaseIds::rateGroup2Comp); - rateGroup3Comp.setIdBase(BaseIds::rateGroup3Comp); - cmdDisp.setIdBase(BaseIds::cmdDisp); - cmdSeq.setIdBase(BaseIds::cmdSeq); - fileDownlink.setIdBase(BaseIds::fileDownlink); - fileManager.setIdBase(BaseIds::fileManager); - fileUplink.setIdBase(BaseIds::fileUplink); - pingRcvr.setIdBase(BaseIds::pingRcvr); - eventLogger.setIdBase(BaseIds::eventLogger); - chanTlm.setIdBase(BaseIds::chanTlm); - prmDb.setIdBase(BaseIds::prmDb); - health.setIdBase(BaseIds::health); - SG1.setIdBase(BaseIds::SG1); - SG2.setIdBase(BaseIds::SG2); - SG3.setIdBase(BaseIds::SG3); - SG4.setIdBase(BaseIds::SG4); - SG5.setIdBase(BaseIds::SG5); - sendBuffComp.setIdBase(BaseIds::sendBuffComp); - comm.setIdBase(BaseIds::comm); - downlink.setIdBase(BaseIds::downlink); - fatalAdapter.setIdBase(BaseIds::fatalAdapter); - fatalHandler.setIdBase(BaseIds::fatalHandler); - fileUplinkBufferManager.setIdBase(BaseIds::fileUplinkBufferManager); - linuxTime.setIdBase(BaseIds::linuxTime); - rateGroupDriverComp.setIdBase(BaseIds::rateGroupDriverComp); - recvBuffComp.setIdBase(BaseIds::recvBuffComp); - staticMemory.setIdBase(BaseIds::staticMemory); - textLogger.setIdBase(BaseIds::textLogger); - uplink.setIdBase(BaseIds::uplink); - } - - // Connect components - void connectComponents() { - - // Command - cmdDisp.set_compCmdSend_OutputPort( - 0, - SG1.get_cmdIn_InputPort(0) - ); - cmdDisp.set_compCmdSend_OutputPort( - 1, - SG2.get_cmdIn_InputPort(0) - ); - cmdDisp.set_compCmdSend_OutputPort( - 2, - SG3.get_cmdIn_InputPort(0) - ); - cmdDisp.set_compCmdSend_OutputPort( - 3, - SG4.get_cmdIn_InputPort(0) - ); - cmdDisp.set_compCmdSend_OutputPort( - 4, - SG5.get_cmdIn_InputPort(0) - ); - cmdDisp.set_compCmdSend_OutputPort( - 5, - cmdDisp.get_CmdDisp_InputPort(0) - ); - cmdDisp.set_compCmdSend_OutputPort( - 6, - cmdSeq.get_cmdIn_InputPort(0) - ); - cmdDisp.set_compCmdSend_OutputPort( - 7, - eventLogger.get_CmdDisp_InputPort(0) - ); - cmdDisp.set_compCmdSend_OutputPort( - 8, - fileDownlink.get_cmdIn_InputPort(0) - ); - cmdDisp.set_compCmdSend_OutputPort( - 9, - fileManager.get_cmdIn_InputPort(0) - ); - cmdDisp.set_compCmdSend_OutputPort( - 10, - health.get_CmdDisp_InputPort(0) - ); - cmdDisp.set_compCmdSend_OutputPort( - 11, - pingRcvr.get_CmdDisp_InputPort(0) - ); - cmdDisp.set_compCmdSend_OutputPort( - 12, - prmDb.get_CmdDisp_InputPort(0) - ); - cmdDisp.set_compCmdSend_OutputPort( - 13, - recvBuffComp.get_CmdDisp_InputPort(0) - ); - cmdDisp.set_compCmdSend_OutputPort( - 14, - sendBuffComp.get_CmdDisp_InputPort(0) - ); - - // CommandRegistration - SG1.set_cmdRegOut_OutputPort( - 0, - cmdDisp.get_compCmdReg_InputPort(0) - ); - SG2.set_cmdRegOut_OutputPort( - 0, - cmdDisp.get_compCmdReg_InputPort(1) - ); - SG3.set_cmdRegOut_OutputPort( - 0, - cmdDisp.get_compCmdReg_InputPort(2) - ); - SG4.set_cmdRegOut_OutputPort( - 0, - cmdDisp.get_compCmdReg_InputPort(3) - ); - SG5.set_cmdRegOut_OutputPort( - 0, - cmdDisp.get_compCmdReg_InputPort(4) - ); - cmdDisp.set_CmdReg_OutputPort( - 0, - cmdDisp.get_compCmdReg_InputPort(5) - ); - cmdSeq.set_cmdRegOut_OutputPort( - 0, - cmdDisp.get_compCmdReg_InputPort(6) - ); - eventLogger.set_CmdReg_OutputPort( - 0, - cmdDisp.get_compCmdReg_InputPort(7) - ); - fileDownlink.set_cmdRegOut_OutputPort( - 0, - cmdDisp.get_compCmdReg_InputPort(8) - ); - fileManager.set_cmdRegOut_OutputPort( - 0, - cmdDisp.get_compCmdReg_InputPort(9) - ); - health.set_CmdReg_OutputPort( - 0, - cmdDisp.get_compCmdReg_InputPort(10) - ); - pingRcvr.set_CmdReg_OutputPort( - 0, - cmdDisp.get_compCmdReg_InputPort(11) - ); - prmDb.set_CmdReg_OutputPort( - 0, - cmdDisp.get_compCmdReg_InputPort(12) - ); - recvBuffComp.set_CmdReg_OutputPort( - 0, - cmdDisp.get_compCmdReg_InputPort(13) - ); - sendBuffComp.set_CmdReg_OutputPort( - 0, - cmdDisp.get_compCmdReg_InputPort(14) - ); - - // CommandResponse - SG1.set_cmdResponseOut_OutputPort( - 0, - cmdDisp.get_compCmdStat_InputPort(0) - ); - SG2.set_cmdResponseOut_OutputPort( - 0, - cmdDisp.get_compCmdStat_InputPort(0) - ); - SG3.set_cmdResponseOut_OutputPort( - 0, - cmdDisp.get_compCmdStat_InputPort(0) - ); - SG4.set_cmdResponseOut_OutputPort( - 0, - cmdDisp.get_compCmdStat_InputPort(0) - ); - SG5.set_cmdResponseOut_OutputPort( - 0, - cmdDisp.get_compCmdStat_InputPort(0) - ); - cmdDisp.set_CmdStatus_OutputPort( - 0, - cmdDisp.get_compCmdStat_InputPort(0) - ); - cmdSeq.set_cmdResponseOut_OutputPort( - 0, - cmdDisp.get_compCmdStat_InputPort(0) - ); - eventLogger.set_CmdStatus_OutputPort( - 0, - cmdDisp.get_compCmdStat_InputPort(0) - ); - fileDownlink.set_cmdResponseOut_OutputPort( - 0, - cmdDisp.get_compCmdStat_InputPort(0) - ); - fileManager.set_cmdResponseOut_OutputPort( - 0, - cmdDisp.get_compCmdStat_InputPort(0) - ); - health.set_CmdStatus_OutputPort( - 0, - cmdDisp.get_compCmdStat_InputPort(0) - ); - pingRcvr.set_CmdStatus_OutputPort( - 0, - cmdDisp.get_compCmdStat_InputPort(0) - ); - prmDb.set_CmdStatus_OutputPort( - 0, - cmdDisp.get_compCmdStat_InputPort(0) - ); - recvBuffComp.set_CmdStatus_OutputPort( - 0, - cmdDisp.get_compCmdStat_InputPort(0) - ); - sendBuffComp.set_CmdStatus_OutputPort( - 0, - cmdDisp.get_compCmdStat_InputPort(0) - ); - - // Downlink - chanTlm.set_PktSend_OutputPort( - 0, - downlink.get_comIn_InputPort(0) - ); - comm.set_deallocate_OutputPort( - 0, - staticMemory.get_bufferDeallocate_InputPort(0) - ); - downlink.set_bufferDeallocate_OutputPort( - 0, - fileDownlink.get_bufferReturn_InputPort(0) - ); - downlink.set_framedAllocate_OutputPort( - 0, - staticMemory.get_bufferAllocate_InputPort(0) - ); - downlink.set_framedOut_OutputPort( - 0, - comm.get_send_InputPort(0) - ); - eventLogger.set_PktSend_OutputPort( - 0, - downlink.get_comIn_InputPort(0) - ); - fileDownlink.set_bufferSendOut_OutputPort( - 0, - downlink.get_bufferIn_InputPort(0) - ); - - // Events - SG1.set_logOut_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - SG2.set_logOut_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - SG3.set_logOut_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - SG4.set_logOut_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - SG5.set_logOut_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - cmdDisp.set_Log_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - cmdSeq.set_logOut_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - eventLogger.set_Log_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - fatalAdapter.set_Log_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - fileDownlink.set_eventOut_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - fileManager.set_eventOut_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - fileUplink.set_eventOut_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - fileUplinkBufferManager.set_eventOut_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - health.set_Log_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - pingRcvr.set_Log_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - prmDb.set_Log_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - rateGroup1Comp.set_Log_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - rateGroup2Comp.set_Log_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - rateGroup3Comp.set_Log_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - recvBuffComp.set_Log_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - sendBuffComp.set_Log_OutputPort( - 0, - eventLogger.get_LogRecv_InputPort(0) - ); - - // FaultProtection - eventLogger.set_FatalAnnounce_OutputPort( - 0, - fatalHandler.get_FatalReceive_InputPort(0) - ); - - // Health - blockDrv.set_PingOut_OutputPort( - 0, - health.get_PingReturn_InputPort(0) - ); - chanTlm.set_pingOut_OutputPort( - 0, - health.get_PingReturn_InputPort(1) - ); - cmdDisp.set_pingOut_OutputPort( - 0, - health.get_PingReturn_InputPort(2) - ); - cmdSeq.set_pingOut_OutputPort( - 0, - health.get_PingReturn_InputPort(3) - ); - eventLogger.set_pingOut_OutputPort( - 0, - health.get_PingReturn_InputPort(4) - ); - fileDownlink.set_pingOut_OutputPort( - 0, - health.get_PingReturn_InputPort(5) - ); - fileManager.set_pingOut_OutputPort( - 0, - health.get_PingReturn_InputPort(6) - ); - fileUplink.set_pingOut_OutputPort( - 0, - health.get_PingReturn_InputPort(7) - ); - health.set_PingSend_OutputPort( - 0, - blockDrv.get_PingIn_InputPort(0) - ); - health.set_PingSend_OutputPort( - 1, - chanTlm.get_pingIn_InputPort(0) - ); - health.set_PingSend_OutputPort( - 2, - cmdDisp.get_pingIn_InputPort(0) - ); - health.set_PingSend_OutputPort( - 3, - cmdSeq.get_pingIn_InputPort(0) - ); - health.set_PingSend_OutputPort( - 4, - eventLogger.get_pingIn_InputPort(0) - ); - health.set_PingSend_OutputPort( - 5, - fileDownlink.get_pingIn_InputPort(0) - ); - health.set_PingSend_OutputPort( - 6, - fileManager.get_pingIn_InputPort(0) - ); - health.set_PingSend_OutputPort( - 7, - fileUplink.get_pingIn_InputPort(0) - ); - health.set_PingSend_OutputPort( - 8, - pingRcvr.get_PingIn_InputPort(0) - ); - health.set_PingSend_OutputPort( - 9, - prmDb.get_pingIn_InputPort(0) - ); - health.set_PingSend_OutputPort( - 10, - rateGroup1Comp.get_PingIn_InputPort(0) - ); - health.set_PingSend_OutputPort( - 11, - rateGroup2Comp.get_PingIn_InputPort(0) - ); - health.set_PingSend_OutputPort( - 12, - rateGroup3Comp.get_PingIn_InputPort(0) - ); - pingRcvr.set_PingOut_OutputPort( - 0, - health.get_PingReturn_InputPort(8) - ); - prmDb.set_pingOut_OutputPort( - 0, - health.get_PingReturn_InputPort(9) - ); - rateGroup1Comp.set_PingOut_OutputPort( - 0, - health.get_PingReturn_InputPort(10) - ); - rateGroup2Comp.set_PingOut_OutputPort( - 0, - health.get_PingReturn_InputPort(11) - ); - rateGroup3Comp.set_PingOut_OutputPort( - 0, - health.get_PingReturn_InputPort(12) - ); - - // Parameters - recvBuffComp.set_ParamGet_OutputPort( - 0, - prmDb.get_getPrm_InputPort(0) - ); - recvBuffComp.set_ParamSet_OutputPort( - 0, - prmDb.get_setPrm_InputPort(0) - ); - sendBuffComp.set_ParamGet_OutputPort( - 0, - prmDb.get_getPrm_InputPort(0) - ); - sendBuffComp.set_ParamSet_OutputPort( - 0, - prmDb.get_setPrm_InputPort(0) - ); - - // RateGroups - blockDrv.set_CycleOut_OutputPort( - 0, - rateGroupDriverComp.get_CycleIn_InputPort(0) - ); - rateGroup1Comp.set_RateGroupMemberOut_OutputPort( - 0, - SG1.get_schedIn_InputPort(0) - ); - rateGroup1Comp.set_RateGroupMemberOut_OutputPort( - 1, - SG2.get_schedIn_InputPort(0) - ); - rateGroup1Comp.set_RateGroupMemberOut_OutputPort( - 2, - chanTlm.get_Run_InputPort(0) - ); - rateGroup1Comp.set_RateGroupMemberOut_OutputPort( - 3, - fileDownlink.get_Run_InputPort(0) - ); - rateGroup2Comp.set_RateGroupMemberOut_OutputPort( - 0, - cmdSeq.get_schedIn_InputPort(0) - ); - rateGroup2Comp.set_RateGroupMemberOut_OutputPort( - 1, - sendBuffComp.get_SchedIn_InputPort(0) - ); - rateGroup2Comp.set_RateGroupMemberOut_OutputPort( - 2, - SG3.get_schedIn_InputPort(0) - ); - rateGroup2Comp.set_RateGroupMemberOut_OutputPort( - 3, - SG4.get_schedIn_InputPort(0) - ); - rateGroup3Comp.set_RateGroupMemberOut_OutputPort( - 0, - health.get_Run_InputPort(0) - ); - rateGroup3Comp.set_RateGroupMemberOut_OutputPort( - 1, - SG5.get_schedIn_InputPort(0) - ); - rateGroup3Comp.set_RateGroupMemberOut_OutputPort( - 2, - blockDrv.get_Sched_InputPort(0) - ); - rateGroup3Comp.set_RateGroupMemberOut_OutputPort( - 3, - fileUplinkBufferManager.get_schedIn_InputPort(0) - ); - rateGroupDriverComp.set_CycleOut_OutputPort( - 0, - rateGroup1Comp.get_CycleIn_InputPort(0) - ); - rateGroupDriverComp.set_CycleOut_OutputPort( - 1, - rateGroup2Comp.get_CycleIn_InputPort(0) - ); - rateGroupDriverComp.set_CycleOut_OutputPort( - 2, - rateGroup3Comp.get_CycleIn_InputPort(0) - ); - - // Ref - blockDrv.set_BufferOut_OutputPort( - 0, - recvBuffComp.get_Data_InputPort(0) - ); - sendBuffComp.set_Data_OutputPort( - 0, - blockDrv.get_BufferIn_InputPort(0) - ); - - // Sequencer - cmdDisp.set_seqCmdStatus_OutputPort( - 0, - cmdSeq.get_cmdResponseIn_InputPort(0) - ); - cmdSeq.set_comCmdOut_OutputPort( - 0, - cmdDisp.get_seqCmdBuff_InputPort(0) - ); - - // Telemetry - SG1.set_tlmOut_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - SG2.set_tlmOut_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - SG3.set_tlmOut_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - SG4.set_tlmOut_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - SG5.set_tlmOut_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - blockDrv.set_Tlm_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - cmdDisp.set_Tlm_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - cmdSeq.set_tlmOut_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - fileDownlink.set_tlmOut_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - fileManager.set_tlmOut_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - fileUplink.set_tlmOut_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - fileUplinkBufferManager.set_tlmOut_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - health.set_Tlm_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - pingRcvr.set_Tlm_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - rateGroup1Comp.set_Tlm_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - rateGroup2Comp.set_Tlm_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - rateGroup3Comp.set_Tlm_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - recvBuffComp.set_Tlm_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - sendBuffComp.set_Tlm_OutputPort( - 0, - chanTlm.get_TlmRecv_InputPort(0) - ); - - // TextEvents - SG1.set_logTextOut_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - SG2.set_logTextOut_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - SG3.set_logTextOut_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - SG4.set_logTextOut_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - SG5.set_logTextOut_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - cmdDisp.set_LogText_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - cmdSeq.set_LogText_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - eventLogger.set_LogText_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - fatalAdapter.set_LogText_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - fileDownlink.set_textEventOut_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - fileManager.set_LogText_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - fileUplink.set_LogText_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - fileUplinkBufferManager.set_textEventOut_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - health.set_LogText_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - pingRcvr.set_LogText_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - prmDb.set_LogText_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - rateGroup1Comp.set_LogText_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - rateGroup2Comp.set_LogText_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - rateGroup3Comp.set_LogText_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - recvBuffComp.set_LogText_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - sendBuffComp.set_LogText_OutputPort( - 0, - textLogger.get_TextLogger_InputPort(0) - ); - - // Time - SG1.set_timeCaller_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - SG2.set_timeCaller_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - SG3.set_timeCaller_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - SG4.set_timeCaller_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - SG5.set_timeCaller_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - blockDrv.set_Time_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - cmdDisp.set_Time_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - cmdSeq.set_timeCaller_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - downlink.set_timeGet_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - eventLogger.set_Time_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - fatalAdapter.set_Time_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - fileDownlink.set_timeCaller_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - fileManager.set_timeCaller_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - fileUplink.set_timeCaller_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - fileUplinkBufferManager.set_timeCaller_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - health.set_Time_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - pingRcvr.set_Time_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - prmDb.set_Time_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - rateGroup1Comp.set_Time_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - rateGroup2Comp.set_Time_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - rateGroup3Comp.set_Time_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - recvBuffComp.set_Time_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - sendBuffComp.set_Time_OutputPort( - 0, - linuxTime.get_timeGetPort_InputPort(0) - ); - - // Uplink - cmdDisp.set_seqCmdStatus_OutputPort( - 1, - uplink.get_cmdResponseIn_InputPort(0) - ); - comm.set_allocate_OutputPort( - 0, - staticMemory.get_bufferAllocate_InputPort(1) - ); - comm.set_recv_OutputPort( - 0, - uplink.get_framedIn_InputPort(0) - ); - fileUplink.set_bufferSendOut_OutputPort( - 0, - fileUplinkBufferManager.get_bufferSendIn_InputPort(0) - ); - uplink.set_bufferAllocate_OutputPort( - 0, - fileUplinkBufferManager.get_bufferGetCallee_InputPort(0) - ); - uplink.set_bufferDeallocate_OutputPort( - 0, - fileUplinkBufferManager.get_bufferSendIn_InputPort(0) - ); - uplink.set_bufferOut_OutputPort( - 0, - fileUplink.get_bufferSendIn_InputPort(0) - ); - uplink.set_comOut_OutputPort( - 0, - cmdDisp.get_seqCmdBuff_InputPort(1) - ); - uplink.set_framedDeallocate_OutputPort( - 0, - staticMemory.get_bufferDeallocate_InputPort(1) - ); - - } - - // Register commands - void regCommands() { - SG1.regCommands(); - SG2.regCommands(); - SG3.regCommands(); - SG4.regCommands(); - SG5.regCommands(); - cmdDisp.regCommands(); - cmdSeq.regCommands(); - eventLogger.regCommands(); - fileDownlink.regCommands(); - fileManager.regCommands(); - health.regCommands(); - pingRcvr.regCommands(); - prmDb.regCommands(); - recvBuffComp.regCommands(); - sendBuffComp.regCommands(); - } - - // Read parameters - void readParameters() { - prmDb.readParamFile(); - } - - // Load parameters - void loadParameters() { - recvBuffComp.loadParameters(); - sendBuffComp.loadParameters(); - } - - // Start tasks - void startTasks(const TopologyState& state) { - blockDrv.start( - static_cast(Priorities::blockDrv), - static_cast(StackSizes::blockDrv), - Os::Task::TASK_DEFAULT, // Default CPU - static_cast(TaskIds::blockDrv) - ); - chanTlm.start( - static_cast(Priorities::chanTlm), - static_cast(StackSizes::chanTlm), - Os::Task::TASK_DEFAULT, // Default CPU - static_cast(TaskIds::chanTlm) - ); - cmdDisp.start( - static_cast(Priorities::cmdDisp), - static_cast(StackSizes::cmdDisp), - Os::Task::TASK_DEFAULT, // Default CPU - static_cast(TaskIds::cmdDisp) - ); - cmdSeq.start( - static_cast(Priorities::cmdSeq), - static_cast(StackSizes::cmdSeq), - Os::Task::TASK_DEFAULT, // Default CPU - static_cast(TaskIds::cmdSeq) - ); - // Initialize socket server if and only if there is a valid specification - if (state.hostName != nullptr && state.portNumber != 0) { - Os::TaskString name("ReceiveTask"); - // Uplink is configured for receive so a socket task is started - comm.configure(state.hostName, state.portNumber); - comm.startSocketTask( - name, - ConfigConstants::comm::PRIORITY, - ConfigConstants::comm::STACK_SIZE - ); - } - eventLogger.start( - static_cast(Priorities::eventLogger), - static_cast(StackSizes::eventLogger), - Os::Task::TASK_DEFAULT, // Default CPU - static_cast(TaskIds::eventLogger) - ); - fileDownlink.start( - static_cast(Priorities::fileDownlink), - static_cast(StackSizes::fileDownlink), - Os::Task::TASK_DEFAULT, // Default CPU - static_cast(TaskIds::fileDownlink) - ); - fileManager.start( - static_cast(Priorities::fileManager), - static_cast(StackSizes::fileManager), - Os::Task::TASK_DEFAULT, // Default CPU - static_cast(TaskIds::fileManager) - ); - fileUplink.start( - static_cast(Priorities::fileUplink), - static_cast(StackSizes::fileUplink), - Os::Task::TASK_DEFAULT, // Default CPU - static_cast(TaskIds::fileUplink) - ); - pingRcvr.start( - static_cast(Priorities::pingRcvr), - static_cast(StackSizes::pingRcvr), - Os::Task::TASK_DEFAULT, // Default CPU - static_cast(TaskIds::pingRcvr) - ); - prmDb.start( - static_cast(Priorities::prmDb), - static_cast(StackSizes::prmDb), - Os::Task::TASK_DEFAULT, // Default CPU - static_cast(TaskIds::prmDb) - ); - rateGroup1Comp.start( - static_cast(Priorities::rateGroup1Comp), - static_cast(StackSizes::rateGroup1Comp), - Os::Task::TASK_DEFAULT, // Default CPU - static_cast(TaskIds::rateGroup1Comp) - ); - rateGroup2Comp.start( - static_cast(Priorities::rateGroup2Comp), - static_cast(StackSizes::rateGroup2Comp), - Os::Task::TASK_DEFAULT, // Default CPU - static_cast(TaskIds::rateGroup2Comp) - ); - rateGroup3Comp.start( - static_cast(Priorities::rateGroup3Comp), - static_cast(StackSizes::rateGroup3Comp), - Os::Task::TASK_DEFAULT, // Default CPU - static_cast(TaskIds::rateGroup3Comp) - ); - } - - // Stop tasks - void stopTasks(const TopologyState& state) { - blockDrv.exit(); - chanTlm.exit(); - cmdDisp.exit(); - cmdSeq.exit(); - eventLogger.exit(); - fileDownlink.exit(); - fileManager.exit(); - fileUplink.exit(); - pingRcvr.exit(); - prmDb.exit(); - rateGroup1Comp.exit(); - rateGroup2Comp.exit(); - rateGroup3Comp.exit(); - } - - // Free threads - void freeThreads(const TopologyState& state) { - (void) blockDrv.ActiveComponentBase::join(nullptr); - (void) chanTlm.ActiveComponentBase::join(nullptr); - (void) cmdDisp.ActiveComponentBase::join(nullptr); - (void) cmdSeq.ActiveComponentBase::join(nullptr); - comm.stopSocketTask(); - (void) comm.joinSocketTask(nullptr); - (void) eventLogger.ActiveComponentBase::join(nullptr); - (void) fileDownlink.ActiveComponentBase::join(nullptr); - (void) fileManager.ActiveComponentBase::join(nullptr); - (void) fileUplink.ActiveComponentBase::join(nullptr); - (void) pingRcvr.ActiveComponentBase::join(nullptr); - (void) prmDb.ActiveComponentBase::join(nullptr); - (void) rateGroup1Comp.ActiveComponentBase::join(nullptr); - (void) rateGroup2Comp.ActiveComponentBase::join(nullptr); - (void) rateGroup3Comp.ActiveComponentBase::join(nullptr); - } - - // Tear down components - void tearDownComponents(const TopologyState& state) { - cmdSeq.deallocateBuffer(Allocation::mallocator); - fileUplinkBufferManager.cleanup(); - } - - } - - // ---------------------------------------------------------------------- - // Public interface functions - // ---------------------------------------------------------------------- - - void setup(const TopologyState& state) { - initComponents(state); - configComponents(state); - setBaseIds(); - connectComponents(); - regCommands(); - readParameters(); - loadParameters(); - startTasks(state); - } - - void teardown(const TopologyState& state) { - stopTasks(state); - freeThreads(state); - tearDownComponents(state); - } - -} diff --git a/Ref/Top/RefTopologyAc.hpp b/Ref/Top/RefTopologyAc.hpp deleted file mode 100644 index 5617dff5a2..0000000000 --- a/Ref/Top/RefTopologyAc.hpp +++ /dev/null @@ -1,249 +0,0 @@ -// ====================================================================== -// \title RefTopologyAc.hpp -// \author Generated by fpp-to-cpp -// \brief hpp file for Ref topology -// -// \copyright -// Copyright (c) 2021 California Institute of Technology. -// U.S. Government sponsorship acknowledged. -// All rights reserved. -// ====================================================================== - -#ifndef Ref_RefTopologyAc_HPP -#define Ref_RefTopologyAc_HPP - -#include "Drv/BlockDriver/BlockDriver.hpp" -#include "Drv/TcpClient/TcpClient.hpp" -#include "Ref/PingReceiver/PingReceiver.hpp" -#include "Ref/RecvBuffApp/RecvBuff.hpp" -#include "Ref/SendBuffApp/SendBuff.hpp" -#include "Ref/SignalGen/SignalGen.hpp" -#include "Ref/Top/RefTopologyDefs.hpp" -#include "Svc/ActiveLogger/ActiveLogger.hpp" -#include "Svc/ActiveRateGroup/ActiveRateGroup.hpp" -#include "Svc/AssertFatalAdapter/AssertFatalAdapter.hpp" -#include "Svc/BufferManager/BufferManager.hpp" -#include "Svc/CmdDispatcher/CommandDispatcher.hpp" -#include "Svc/CmdSequencer/CmdSequencer.hpp" -#include "Svc/Deframer/Deframer.hpp" -#include "Svc/FatalHandler/FatalHandler.hpp" -#include "Svc/FileDownlink/FileDownlink.hpp" -#include "Svc/FileManager/FileManager.hpp" -#include "Svc/FileUplink/FileUplink.hpp" -#include "Svc/Framer/Framer.hpp" -#include "Svc/Health/Health.hpp" -#include "Svc/LinuxTime/LinuxTime.hpp" -#include "Svc/PassiveConsoleTextLogger/PassiveTextLogger.hpp" -#include "Svc/PrmDb/PrmDb.hpp" -#include "Svc/RateGroupDriver/RateGroupDriver.hpp" -#include "Svc/StaticMemory/StaticMemory.hpp" -#include "Svc/TlmChan/TlmChan.hpp" - -namespace Ref { - - // ---------------------------------------------------------------------- - // Constants - // ---------------------------------------------------------------------- - - namespace ConfigConstants { - namespace cmdSeq { - enum { - BUFFER_SIZE = 5*1024 - }; - } - namespace comm { - enum { - PRIORITY = 100, - STACK_SIZE = Default::stackSize - }; - } - namespace fileDownlink { - enum { - TIMEOUT = 1000, - COOLDOWN = 1000, - CYCLE_TIME = 1000, - FILE_QUEUE_DEPTH = 10 - }; - } - namespace fileUplinkBufferManager { - enum { - STORE_SIZE = 3000, - QUEUE_SIZE = 30, - MGR_ID = 200 - }; - } - namespace health { - enum { - WATCHDOG_CODE = 0x123 - }; - } - } - - namespace BaseIds { - enum { - blockDrv = 0x100, - rateGroup1Comp = 0x200, - rateGroup2Comp = 0x300, - rateGroup3Comp = 0x400, - cmdDisp = 0x500, - cmdSeq = 0x600, - fileDownlink = 0x700, - fileManager = 0x800, - fileUplink = 0x900, - pingRcvr = 0xA00, - eventLogger = 0xB00, - chanTlm = 0xC00, - prmDb = 0xD00, - health = 0x2000, - SG1 = 0x2100, - SG2 = 0x2200, - SG3 = 0x2300, - SG4 = 0x2400, - SG5 = 0x2500, - sendBuffComp = 0x2600, - comm = 0x4000, - downlink = 0x4100, - fatalAdapter = 0x4200, - fatalHandler = 0x4300, - fileUplinkBufferManager = 0x4400, - linuxTime = 0x4500, - rateGroupDriverComp = 0x4600, - recvBuffComp = 0x4700, - staticMemory = 0x4800, - textLogger = 0x4900, - uplink = 0x4A00, - }; - } - - namespace InstanceIds { - enum { - SG1, - SG2, - SG3, - SG4, - SG5, - blockDrv, - chanTlm, - cmdDisp, - cmdSeq, - comm, - downlink, - eventLogger, - fatalAdapter, - fatalHandler, - fileDownlink, - fileManager, - fileUplink, - fileUplinkBufferManager, - health, - linuxTime, - pingRcvr, - prmDb, - rateGroup1Comp, - rateGroup2Comp, - rateGroup3Comp, - rateGroupDriverComp, - recvBuffComp, - sendBuffComp, - staticMemory, - textLogger, - uplink, - }; - } - - namespace Priorities { - enum { - blockDrv = 140, - chanTlm = 97, - cmdDisp = 101, - cmdSeq = 100, - eventLogger = 98, - fileDownlink = 100, - fileManager = 100, - fileUplink = 100, - pingRcvr = 100, - prmDb = 96, - rateGroup1Comp = 120, - rateGroup2Comp = 119, - rateGroup3Comp = 118, - }; - } - - namespace QueueSizes { - enum { - SG1 = 10, - SG2 = 10, - SG3 = 10, - SG4 = 10, - SG5 = 10, - blockDrv = 10, - chanTlm = 10, - cmdDisp = 20, - cmdSeq = 10, - eventLogger = 10, - fileDownlink = 30, - fileManager = 30, - fileUplink = 30, - health = 25, - pingRcvr = 10, - prmDb = 10, - rateGroup1Comp = 10, - rateGroup2Comp = 10, - rateGroup3Comp = 10, - sendBuffComp = 10, - }; - } - - namespace StackSizes { - enum { - blockDrv = 16384, - chanTlm = 16384, - cmdDisp = 16384, - cmdSeq = 16384, - eventLogger = 16384, - fileDownlink = 16384, - fileManager = 16384, - fileUplink = 16384, - pingRcvr = 16384, - prmDb = 16384, - rateGroup1Comp = 16384, - rateGroup2Comp = 16384, - rateGroup3Comp = 16384, - }; - } - - namespace TaskIds { - enum { - blockDrv, - chanTlm, - cmdDisp, - cmdSeq, - eventLogger, - fileDownlink, - fileManager, - fileUplink, - pingRcvr, - prmDb, - rateGroup1Comp, - rateGroup2Comp, - rateGroup3Comp, - }; - } - - // ---------------------------------------------------------------------- - // Public interface functions - // ---------------------------------------------------------------------- - - //! Set up the topology - void setup( - const TopologyState& state //!< The topology state - ); - - //! Tear down the topology - void teardown( - const TopologyState& state //!< The topology state - ); - -} - -#endif diff --git a/Ref/Top/RefTopologyAppAi.xml b/Ref/Top/RefTopologyAppAi.xml deleted file mode 100644 index a1d06fb439..0000000000 --- a/Ref/Top/RefTopologyAppAi.xml +++ /dev/null @@ -1,896 +0,0 @@ - - - - - - Drv/BlockDriver/BlockDriverComponentAi.xml - Drv/ByteStreamDriverModel/ByteStreamDriverModelComponentAi.xml - Ref/PingReceiver/PingReceiverComponentAi.xml - Ref/RecvBuffApp/RecvBuffComponentAi.xml - Ref/SendBuffApp/SendBuffComponentAi.xml - Ref/SignalGen/SignalGenComponentAi.xml - Svc/ActiveLogger/ActiveLoggerComponentAi.xml - Svc/ActiveRateGroup/ActiveRateGroupComponentAi.xml - Svc/AssertFatalAdapter/AssertFatalAdapterComponentAi.xml - Svc/BufferManager/BufferManagerComponentAi.xml - Svc/CmdDispatcher/CommandDispatcherComponentAi.xml - Svc/CmdSequencer/CmdSequencerComponentAi.xml - Svc/Deframer/DeframerComponentAi.xml - Svc/FatalHandler/FatalHandlerComponentAi.xml - Svc/FileDownlink/FileDownlinkComponentAi.xml - Svc/FileManager/FileManagerComponentAi.xml - Svc/FileUplink/FileUplinkComponentAi.xml - Svc/Framer/FramerComponentAi.xml - Svc/Health/HealthComponentAi.xml - Svc/PassiveConsoleTextLogger/PassiveTextLoggerComponentAi.xml - Svc/PrmDb/PrmDbComponentAi.xml - Svc/RateGroupDriver/RateGroupDriverComponentAi.xml - Svc/StaticMemory/StaticMemoryComponentAi.xml - Svc/Time/TimeComponentAi.xml - Svc/TlmChan/TlmChanComponentAi.xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Ref/Top/RefTopologyDefs.cpp b/Ref/Top/RefTopologyDefs.cpp deleted file mode 100644 index cbd9cd7946..0000000000 --- a/Ref/Top/RefTopologyDefs.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "Ref/Top/RefTopologyDefs.hpp" - -namespace Ref { - - namespace Allocation { - - Fw::MallocAllocator mallocator; - - } - -} diff --git a/Ref/Top/RefTopologyDefs.hpp b/Ref/Top/RefTopologyDefs.hpp index bd91a825b5..6c5b3de729 100644 --- a/Ref/Top/RefTopologyDefs.hpp +++ b/Ref/Top/RefTopologyDefs.hpp @@ -1,58 +1,97 @@ -#ifndef RefTopologyDefs_HPP -#define RefTopologyDefs_HPP +// ====================================================================== +// \title RefTopologyDefs.hpp +// \author mstarch +// \brief required header file containing the required definitions for the topology autocoder +// +// \copyright +// Copyright 2009-2022, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// ====================================================================== +#ifndef REF_REFTOPOLOGYDEFS_HPP +#define REF_REFTOPOLOGYDEFS_HPP #include "Drv/BlockDriver/BlockDriver.hpp" #include "Fw/Types/MallocAllocator.hpp" #include "Ref/Top/FppConstantsAc.hpp" #include "Svc/FramingProtocol/FprimeProtocol.hpp" +#include "Svc/Health/Health.hpp" +// Definitions are placed within a namespace named after the deployment namespace Ref { - namespace Allocation { - - // Malloc allocator for topology construction - extern Fw::MallocAllocator mallocator; - - } - - // State for topology construction - struct TopologyState { - TopologyState() : - hostName(""), - portNumber(0) - { - - } - TopologyState( - const char *hostName, - U32 portNumber - ) : - hostName(hostName), - portNumber(portNumber) - { - - } - const char* hostName; - U32 portNumber; - }; - - // Health ping entries - namespace PingEntries { - namespace blockDrv { enum { WARN = 3, FATAL = 5 }; } - namespace chanTlm { enum { WARN = 3, FATAL = 5 }; } - namespace cmdDisp { enum { WARN = 3, FATAL = 5 }; } - namespace cmdSeq { enum { WARN = 3, FATAL = 5 }; } - namespace eventLogger { enum { WARN = 3, FATAL = 5 }; } - namespace fileDownlink { enum { WARN = 3, FATAL = 5 }; } - namespace fileManager { enum { WARN = 3, FATAL = 5 }; } - namespace fileUplink { enum { WARN = 3, FATAL = 5 }; } - namespace pingRcvr { enum { WARN = 3, FATAL = 5 }; } - namespace prmDb { enum { WARN = 3, FATAL = 5 }; } - namespace rateGroup1Comp { enum { WARN = 3, FATAL = 5 }; } - namespace rateGroup2Comp { enum { WARN = 3, FATAL = 5 }; } - namespace rateGroup3Comp { enum { WARN = 3, FATAL = 5 }; } - } +/** + * \brief required type definition to carry state + * + * The topology autocoder requires an object that carries state with the name `Ref::TopologyState`. Only the type + * definition is required by the autocoder and the contents of this object are otherwise opaque to the autocoder. The + * contents are entirely up to the definition of the project. This reference application specifies hostname and port + * fields, which are derived by command line inputs. + */ +struct TopologyState { + const char* hostname; + U32 port; +}; +/** + * \brief required ping constants + * + * The topology autocoder requires a WARN and FATAL constant definition for each component that supports the health-ping + * interface. These are expressed as enum constants placed in a namespace named for the component instance. These + * are all placed in the PingEntries namespace. + * + * Each constant specifies how many missed pings are allowed before a WARNING_HI/FATAL event is triggered. In the + * following example, the health component will emit a WARNING_HI event if the component instance cmdDisp does not + * respond for 3 pings and will FATAL if responses are not received after a total of 5 pings. + * + * ```c++ + * namespace PingEntries { + * namespace cmdDisp { + * enum { WARN = 3, FATAL = 5 }; + * } + * } + * ``` + */ +namespace PingEntries { +namespace blockDrv { +enum { WARN = 3, FATAL = 5 }; } - +namespace tlmSend { +enum { WARN = 3, FATAL = 5 }; +} +namespace cmdDisp { +enum { WARN = 3, FATAL = 5 }; +} +namespace cmdSeq { +enum { WARN = 3, FATAL = 5 }; +} +namespace eventLogger { +enum { WARN = 3, FATAL = 5 }; +} +namespace fileDownlink { +enum { WARN = 3, FATAL = 5 }; +} +namespace fileManager { +enum { WARN = 3, FATAL = 5 }; +} +namespace fileUplink { +enum { WARN = 3, FATAL = 5 }; +} +namespace pingRcvr { +enum { WARN = 3, FATAL = 5 }; +} +namespace prmDb { +enum { WARN = 3, FATAL = 5 }; +} +namespace rateGroup1Comp { +enum { WARN = 3, FATAL = 5 }; +} +namespace rateGroup2Comp { +enum { WARN = 3, FATAL = 5 }; +} +namespace rateGroup3Comp { +enum { WARN = 3, FATAL = 5 }; +} +} // namespace PingEntries +} // namespace Ref #endif diff --git a/Ref/Top/instances.fpp b/Ref/Top/instances.fpp index 67568eef7a..56edd8ad86 100644 --- a/Ref/Top/instances.fpp +++ b/Ref/Top/instances.fpp @@ -5,11 +5,8 @@ module Ref { # ---------------------------------------------------------------------- module Default { - - constant queueSize = 10 - - constant stackSize = 64 * 1024 - + constant QUEUE_SIZE = 10 + constant STACK_SIZE = 64 * 1024 } # ---------------------------------------------------------------------- @@ -17,206 +14,105 @@ module Ref { # ---------------------------------------------------------------------- instance blockDrv: Drv.BlockDriver base id 0x0100 \ - queue size Default.queueSize \ - stack size Default.stackSize \ + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ priority 140 instance rateGroup1Comp: Svc.ActiveRateGroup base id 0x0200 \ - queue size Default.queueSize \ - stack size Default.stackSize \ - priority 120 \ - { - - phase Fpp.ToCpp.Phases.configObjects """ - NATIVE_INT_TYPE context[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - """ - - phase Fpp.ToCpp.Phases.configComponents """ - rateGroup1Comp.configure( - ConfigObjects::rateGroup1Comp::context, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::rateGroup1Comp::context) - ); - """ - - } + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ + priority 120 instance rateGroup2Comp: Svc.ActiveRateGroup base id 0x0300 \ - queue size Default.queueSize \ - stack size Default.stackSize \ - priority 119 \ - { - - phase Fpp.ToCpp.Phases.configObjects """ - NATIVE_INT_TYPE context[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - """ - - phase Fpp.ToCpp.Phases.configComponents """ - rateGroup2Comp.configure( - ConfigObjects::rateGroup2Comp::context, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::rateGroup2Comp::context) - ); - """ - - } + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ + priority 119 instance rateGroup3Comp: Svc.ActiveRateGroup base id 0x0400 \ - queue size Default.queueSize \ - stack size Default.stackSize \ - priority 118 \ - { - - phase Fpp.ToCpp.Phases.configObjects """ - NATIVE_INT_TYPE context[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - """ - - phase Fpp.ToCpp.Phases.configComponents """ - rateGroup3Comp.configure( - ConfigObjects::rateGroup3Comp::context, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::rateGroup3Comp::context) - ); - """ - - } + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ + priority 118 instance cmdDisp: Svc.CommandDispatcher base id 0x0500 \ queue size 20 \ - stack size Default.stackSize \ + stack size Default.STACK_SIZE \ priority 101 instance cmdSeq: Svc.CmdSequencer base id 0x0600 \ - queue size Default.queueSize \ - stack size Default.stackSize \ - priority 100 \ - { - - phase Fpp.ToCpp.Phases.configConstants """ - enum { - BUFFER_SIZE = 5*1024 - }; - """ - - phase Fpp.ToCpp.Phases.configComponents """ - cmdSeq.allocateBuffer( - 0, - Allocation::mallocator, - ConfigConstants::cmdSeq::BUFFER_SIZE - ); - """ - - phase Fpp.ToCpp.Phases.tearDownComponents """ - cmdSeq.deallocateBuffer(Allocation::mallocator); - """ - - } + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ + priority 100 instance fileDownlink: Svc.FileDownlink base id 0x0700 \ queue size 30 \ - stack size Default.stackSize \ - priority 100 \ - { - - phase Fpp.ToCpp.Phases.configConstants """ - enum { - TIMEOUT = 1000, - COOLDOWN = 1000, - CYCLE_TIME = 1000, - FILE_QUEUE_DEPTH = 10 - }; - """ - - phase Fpp.ToCpp.Phases.configComponents """ - fileDownlink.configure( - ConfigConstants::fileDownlink::TIMEOUT, - ConfigConstants::fileDownlink::COOLDOWN, - ConfigConstants::fileDownlink::CYCLE_TIME, - ConfigConstants::fileDownlink::FILE_QUEUE_DEPTH - ); - """ - - } + stack size Default.STACK_SIZE \ + priority 100 instance fileManager: Svc.FileManager base id 0x0800 \ queue size 30 \ - stack size Default.stackSize \ + stack size Default.STACK_SIZE \ priority 100 instance fileUplink: Svc.FileUplink base id 0x0900 \ queue size 30 \ - stack size Default.stackSize \ + stack size Default.STACK_SIZE \ priority 100 instance pingRcvr: Ref.PingReceiver base id 0x0A00 \ - queue size Default.queueSize \ - stack size Default.stackSize \ + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ priority 100 instance eventLogger: Svc.ActiveLogger base id 0x0B00 \ - queue size Default.queueSize \ - stack size Default.stackSize \ + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ priority 98 - instance chanTlm: Svc.TlmChan base id 0x0C00 \ - queue size Default.queueSize \ - stack size Default.stackSize \ + # comment in Svc.TlmChan or Svc.TlmPacketizer + # depending on which form of telemetry downlink + # you wish to use + + instance tlmSend: Svc.TlmChan base id 0x0C00 \ + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ priority 97 - instance prmDb: Svc.PrmDb base id 0x0D00 \ - queue size Default.queueSize \ - stack size Default.stackSize \ - priority 96 \ - { + #instance tlmSend: Svc.TlmPacketizer base id 0x0C00 \ + # queue size Default.QUEUE_SIZE \ + # stack size Default.STACK_SIZE \ + # priority 97 - phase Fpp.ToCpp.Phases.instances """ - Svc::PrmDb prmDb(FW_OPTIONAL_NAME("prmDb"), "PrmDb.dat"); - """ + instance prmDb: Svc.PrmDb base id 0x0D00 \ + queue size Default.QUEUE_SIZE \ + stack size Default.STACK_SIZE \ + priority 96 - phase Fpp.ToCpp.Phases.readParameters """ - prmDb.readParamFile(); - """ - - } + instance typeDemo: Ref.TypeDemo base id 0x0E00 # ---------------------------------------------------------------------- # Queued component instances # ---------------------------------------------------------------------- instance $health: Svc.Health base id 0x2000 \ - queue size 25 \ - { - - phase Fpp.ToCpp.Phases.configConstants """ - enum { - WATCHDOG_CODE = 0x123 - }; - """ - - phase Fpp.ToCpp.Phases.configComponents """ - health.setPingEntries( - ConfigObjects::health::pingEntries, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::health::pingEntries), - ConfigConstants::health::WATCHDOG_CODE - ); - """ - - } + queue size 25 instance SG1: Ref.SignalGen base id 0x2100 \ - queue size Default.queueSize + queue size Default.QUEUE_SIZE instance SG2: Ref.SignalGen base id 0x2200 \ - queue size Default.queueSize + queue size Default.QUEUE_SIZE instance SG3: Ref.SignalGen base id 0x2300 \ - queue size Default.queueSize + queue size Default.QUEUE_SIZE instance SG4: Ref.SignalGen base id 0x2400 \ - queue size Default.queueSize + queue size Default.QUEUE_SIZE instance SG5: Ref.SignalGen base id 0x2500 \ - queue size Default.queueSize + queue size Default.QUEUE_SIZE instance sendBuffComp: Ref.SendBuff base id 0x2600 \ - queue size Default.queueSize + queue size Default.QUEUE_SIZE # ---------------------------------------------------------------------- # Passive component instances @@ -225,105 +121,22 @@ module Ref { @ Communications driver. May be swapped with other comm drivers like UART @ Note: Here we have TCP reliable uplink and UDP (low latency) downlink instance comm: Drv.ByteStreamDriverModel base id 0x4000 \ - type "Drv::TcpClient" \ - at "../../Drv/TcpClient/TcpClient.hpp" \ - { - - phase Fpp.ToCpp.Phases.configConstants """ - enum { - PRIORITY = 100, - STACK_SIZE = Default::stackSize - }; - """ - - phase Fpp.ToCpp.Phases.startTasks """ - // Initialize socket server if and only if there is a valid specification - if (state.hostName != nullptr && state.portNumber != 0) { - Os::TaskString name("ReceiveTask"); - // Uplink is configured for receive so a socket task is started - comm.configure(state.hostName, state.portNumber); - comm.startSocketTask( - name, - true, - ConfigConstants::comm::PRIORITY, - ConfigConstants::comm::STACK_SIZE - ); - } - """ - - phase Fpp.ToCpp.Phases.freeThreads """ - comm.stopSocketTask(); - (void) comm.joinSocketTask(nullptr); - """ - - } + type "Drv::TcpClient" \ # type specified to select implementor of ByteStreamDriverModel + at "../../Drv/TcpClient/TcpClient.hpp" # location of above implementor must also be specified - instance downlink: Svc.Framer base id 0x4100 { - - phase Fpp.ToCpp.Phases.configObjects """ - Svc::FprimeFraming framing; - """ - - phase Fpp.ToCpp.Phases.configComponents """ - downlink.setup(ConfigObjects::downlink::framing); - """ - - } + instance downlink: Svc.Framer base id 0x4100 instance fatalAdapter: Svc.AssertFatalAdapter base id 0x4200 instance fatalHandler: Svc.FatalHandler base id 0x4300 - instance fileUplinkBufferManager: Svc.BufferManager base id 0x4400 { - - phase Fpp.ToCpp.Phases.configConstants """ - enum { - STORE_SIZE = 3000, - QUEUE_SIZE = 30, - MGR_ID = 200 - }; - """ - - phase Fpp.ToCpp.Phases.configComponents """ - Svc::BufferManager::BufferBins upBuffMgrBins; - memset(&upBuffMgrBins, 0, sizeof(upBuffMgrBins)); - { - using namespace ConfigConstants::fileUplinkBufferManager; - upBuffMgrBins.bins[0].bufferSize = STORE_SIZE; - upBuffMgrBins.bins[0].numBuffers = QUEUE_SIZE; - fileUplinkBufferManager.setup( - MGR_ID, - 0, - Allocation::mallocator, - upBuffMgrBins - ); - } - """ - - phase Fpp.ToCpp.Phases.tearDownComponents """ - fileUplinkBufferManager.cleanup(); - """ - - } + instance fileUplinkBufferManager: Svc.BufferManager base id 0x4400 instance linuxTime: Svc.Time base id 0x4500 \ type "Svc::LinuxTime" \ at "../../Svc/LinuxTime/LinuxTime.hpp" - instance rateGroupDriverComp: Svc.RateGroupDriver base id 0x4600 { - - phase Fpp.ToCpp.Phases.configObjects """ - NATIVE_INT_TYPE rgDivs[Svc::RateGroupDriver::DIVIDER_SIZE] = { 1, 2, 4 }; - """ - - phase Fpp.ToCpp.Phases.configComponents """ - rateGroupDriverComp.configure( - ConfigObjects::rateGroupDriverComp::rgDivs, - FW_NUM_ARRAY_ELEMENTS(ConfigObjects::rateGroupDriverComp::rgDivs) - ); - """ - - } + instance rateGroupDriverComp: Svc.RateGroupDriver base id 0x4600 instance recvBuffComp: Ref.RecvBuff base id 0x4700 @@ -331,17 +144,7 @@ module Ref { instance textLogger: Svc.PassiveTextLogger base id 0x4900 - instance uplink: Svc.Deframer base id 0x4A00 { - - phase Fpp.ToCpp.Phases.configObjects """ - Svc::FprimeDeframing deframing; - """ - - phase Fpp.ToCpp.Phases.configComponents """ - uplink.setup(ConfigObjects::uplink::deframing); - """ - - } + instance uplink: Svc.Deframer base id 0x4A00 instance systemResources: Svc.SystemResources base id 0x4B00 diff --git a/Ref/Top/topology.fpp b/Ref/Top/topology.fpp index bff1a2af1a..6da5dccd55 100644 --- a/Ref/Top/topology.fpp +++ b/Ref/Top/topology.fpp @@ -28,7 +28,7 @@ module Ref { instance SG4 instance SG5 instance blockDrv - instance chanTlm + instance tlmSend instance cmdDisp instance cmdSeq instance comm @@ -51,6 +51,7 @@ module Ref { instance sendBuffComp instance staticMemory instance textLogger + instance typeDemo instance uplink instance systemResources @@ -64,7 +65,7 @@ module Ref { param connections instance prmDb - telemetry connections instance chanTlm + telemetry connections instance tlmSend text event connections instance textLogger @@ -78,7 +79,7 @@ module Ref { connections Downlink { - chanTlm.PktSend -> downlink.comIn + tlmSend.PktSend -> downlink.comIn eventLogger.PktSend -> downlink.comIn fileDownlink.bufferSendOut -> downlink.bufferIn @@ -103,7 +104,7 @@ module Ref { rateGroupDriverComp.CycleOut[Ports_RateGroups.rateGroup1] -> rateGroup1Comp.CycleIn rateGroup1Comp.RateGroupMemberOut[0] -> SG1.schedIn rateGroup1Comp.RateGroupMemberOut[1] -> SG2.schedIn - rateGroup1Comp.RateGroupMemberOut[2] -> chanTlm.Run + rateGroup1Comp.RateGroupMemberOut[2] -> tlmSend.Run rateGroup1Comp.RateGroupMemberOut[3] -> fileDownlink.Run rateGroup1Comp.RateGroupMemberOut[4] -> systemResources.run diff --git a/Ref/TypeDemo/CMakeLists.txt b/Ref/TypeDemo/CMakeLists.txt new file mode 100644 index 0000000000..9a80610286 --- /dev/null +++ b/Ref/TypeDemo/CMakeLists.txt @@ -0,0 +1,13 @@ +#### +# F prime CMakeLists.txt: +# +# SOURCE_FILES: combined list of source and autocoding files +# MOD_DEPS: (optional) module dependencies +# +#### +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/TypeDemo.fpp" + "${CMAKE_CURRENT_LIST_DIR}/TypeDemo.cpp" +) + +register_fprime_module() diff --git a/Ref/TypeDemo/TypeDemo.cpp b/Ref/TypeDemo/TypeDemo.cpp new file mode 100644 index 0000000000..3362a6f58b --- /dev/null +++ b/Ref/TypeDemo/TypeDemo.cpp @@ -0,0 +1,126 @@ +// ====================================================================== +// \title TypeDemo.cpp +// \author mstarch +// \brief cpp file for TypeDemo component implementation class +// ====================================================================== + +#include +#include +#include + +namespace Ref { + +// ---------------------------------------------------------------------- +// Construction, initialization, and destruction +// ---------------------------------------------------------------------- + +TypeDemo ::TypeDemo(const char* const compName) : TypeDemoComponentBase(compName) {} + +void TypeDemo ::init(const NATIVE_INT_TYPE instance) { + TypeDemoComponentBase::init(instance); +} + +// ---------------------------------------------------------------------- +// Command handler implementations +// ---------------------------------------------------------------------- + +void TypeDemo ::CHOICE_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq, Ref::Choice choice) { + this->tlmWrite_ChoiceCh(choice); + this->log_ACTIVITY_HI_ChoiceEv(choice); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +void TypeDemo ::CHOICES_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq, Ref::ManyChoices choices) { + this->tlmWrite_ChoicesCh(choices); + this->log_ACTIVITY_HI_ChoicesEv(choices); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +void TypeDemo ::CHOICES_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, + const U32 cmdSeq, + U8 repeat, + Ref::ManyChoices choices, + U8 repeat_max) { + for (U32 i = 0; (i < repeat) && (i < std::numeric_limits::max()) && (i < repeat_max); i++) { + this->tlmWrite_ChoicesCh(choices); + } + this->log_ACTIVITY_HI_ChoicesEv(choices); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +void TypeDemo ::EXTRA_CHOICES_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq, Ref::TooManyChoices choices) { + this->tlmWrite_ExtraChoicesCh(choices); + this->log_ACTIVITY_HI_ExtraChoicesEv(choices); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +void TypeDemo ::EXTRA_CHOICES_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, + const U32 cmdSeq, + U8 repeat, + Ref::TooManyChoices choices, + U8 repeat_max) { + for (U32 i = 0; (i < repeat) && (i < std::numeric_limits::max()) && (i < repeat_max); i++) { + this->tlmWrite_ExtraChoicesCh(choices); + } + this->log_ACTIVITY_HI_ExtraChoicesEv(choices); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +void TypeDemo ::CHOICE_PAIR_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq, Ref::ChoicePair choices) { + this->tlmWrite_ChoicePairCh(choices); + this->log_ACTIVITY_HI_ChoicePairEv(choices); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +void TypeDemo ::CHOICE_PAIR_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, + const U32 cmdSeq, + U8 repeat, + Ref::ChoicePair choices, + U8 repeat_max) { + for (U32 i = 0; (i < repeat) && (i < std::numeric_limits::max()) && (i < repeat_max); i++) { + this->tlmWrite_ChoicePairCh(choices); + } + this->log_ACTIVITY_HI_ChoicePairEv(choices); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +void TypeDemo ::GLUTTON_OF_CHOICE_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq, Ref::ChoiceSlurry choices) { + this->tlmWrite_ChoiceSlurryCh(choices); + this->log_ACTIVITY_HI_ChoiceSlurryEv(choices); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +void TypeDemo ::GLUTTON_OF_CHOICE_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, + const U32 cmdSeq, + U8 repeat, + Ref::ChoiceSlurry choices, + U8 repeat_max) { + for (U32 i = 0; (i < repeat) && (i < std::numeric_limits::max()) && (i < repeat_max); i++) { + this->tlmWrite_ChoiceSlurryCh(choices); + } + this->log_ACTIVITY_HI_ChoiceSlurryEv(choices); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +void TypeDemo ::DUMP_TYPED_PARAMETERS_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq) { + Fw::ParamValid validity; + + Ref::Choice choice = this->paramGet_CHOICE_PRM(validity); + this->log_ACTIVITY_HI_ChoicePrmEv(choice, validity); + + Ref::ManyChoices choices = this->paramGet_CHOICES_PRM(validity); + this->log_ACTIVITY_HI_ChoicesPrmEv(choices, validity); + + Ref::TooManyChoices tooManyChoices = this->paramGet_EXTRA_CHOICES_PRM(validity); + this->log_ACTIVITY_HI_ExtraChoicesPrmEv(tooManyChoices, validity); + + Ref::ChoicePair choicePair = this->paramGet_CHOICE_PAIR_PRM(validity); + this->log_ACTIVITY_HI_ChoicePairPrmEv(choicePair, validity); + + Ref::ChoiceSlurry choiceSlurry = this->paramGet_GLUTTON_OF_CHOICE_PRM(validity); + this->log_ACTIVITY_HI_ChoiceSlurryPrmEv(choiceSlurry, validity); + + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +} // end namespace Ref diff --git a/Ref/TypeDemo/TypeDemo.fpp b/Ref/TypeDemo/TypeDemo.fpp new file mode 100644 index 0000000000..2c5a6b0c93 --- /dev/null +++ b/Ref/TypeDemo/TypeDemo.fpp @@ -0,0 +1,225 @@ +module Ref { + constant dimension = 2 + + @ Enumeration type for use later + enum Choice { + ONE + TWO + RED + BLUE + } + + @ Enumeration array + array ManyChoices = [dimension] Choice + + @ Array of array + array TooManyChoices = [dimension] ManyChoices + + @ Structure of enums + struct ChoicePair { + @ The first choice to make + firstChoice: Choice, + @ The second choice to make + secondChoice: Choice + } + + @ Structure of enums (with an multi-dimensional array and structure) + struct ChoiceSlurry { + @ A large set of disorganized choices + tooManyChoices: TooManyChoices, + @ A singular choice + separateChoice: Choice + @ A pair of choices + choicePair: ChoicePair + } + + @ Component to demonstrate multiple type configurations + passive component TypeDemo { + ##### + # Variations on a single enumeration input + ##### + @ Single choice command + sync command CHOICE( + @ A single choice + choice: Choice + ) + + @ Single choice channel + telemetry ChoiceCh: Choice + + @ Single choice event + event ChoiceEv(choice: Choice) severity activity high format "Choice: {}" + + @ Single enumeration parameter + param CHOICE_PRM: Choice + + ##### + # Variations on a one-dimensional array of enumeration input + ##### + @ Multiple choice command via Array + sync command CHOICES( + @ A set of choices + choices: ManyChoices + ) + + @ Multiple choice command via Array with a preceding and following argument + sync command CHOICES_WITH_FRIENDS( + @ Number of times to repeat the choices + repeat: U8, + @ A set of choices + choices: ManyChoices, + @ Limit to the number of repetitions + repeat_max: U8 + ) + + @ Multiple choice channel via Array + telemetry ChoicesCh: ManyChoices + + @ Multiple choice event via Array + event ChoicesEv(choices: ManyChoices) severity activity high format "Choices: {}" + + @ Multiple enumeration parameter via Array + param CHOICES_PRM: ManyChoices + + ##### + # Variations on a multi-dimensional array of enumeration input + ##### + @ Too many choice command via Array + sync command EXTRA_CHOICES( + @ Way to many choices to make + choices: TooManyChoices + ) + + @ Too many choices command via Array with a preceding and following argument + sync command EXTRA_CHOICES_WITH_FRIENDS( + @ Number of times to repeat the choices + repeat: U8, + @ Way to many choices to make + choices: TooManyChoices, + @ Limit to the number of repetitions + repeat_max: U8 + ) + + @ Too many choice channel via Array + telemetry ExtraChoicesCh: TooManyChoices + + @ Too many choice event via Array + event ExtraChoicesEv(choices: TooManyChoices) severity activity high format "Choices: {}" + + @ Too many enumeration parameter via Array + param EXTRA_CHOICES_PRM: ManyChoices + + ##### + # Variations on a basic structure + ##### + @ Multiple choice command via Structure + sync command CHOICE_PAIR( + @ A pair of choices + choices: ChoicePair + ) + + @ Multiple choices command via Structure with a preceding and following argument + sync command CHOICE_PAIR_WITH_FRIENDS( + @ Number of times to repeat the choices + repeat: U8, + @ A pair of choices + choices: ChoicePair, + @ Limit to the number of repetitions + repeat_max: U8 + ) + + @ Multiple choice channel via Structure + telemetry ChoicePairCh: ChoicePair + + @ Multiple choice event via Structure + event ChoicePairEv(choices: ChoicePair) severity activity high format "Choices: {}" + + @ Multiple enumeration parameter via Structure + param CHOICE_PAIR_PRM: ChoicePair + + ##### + # Variations on a complex structure + ##### + @ Multiple choice command via Complex Structure + sync command GLUTTON_OF_CHOICE( + @ A phenomenal amount of choice + choices: ChoiceSlurry + ) + + @ Multiple choices command via Complex Structure with a preceding and following argument + sync command GLUTTON_OF_CHOICE_WITH_FRIENDS( + @ Number of times to repeat the choices + repeat: U8, + @ A phenomenal amount of choice + choices: ChoiceSlurry, + @ Limit to the number of repetitions + repeat_max: U8 + ) + + @ Multiple choice channel via Complex Structure + telemetry ChoiceSlurryCh: ChoiceSlurry + + @ Multiple choice event via Complex Structure + event ChoiceSlurryEv(choices: ChoiceSlurry) severity activity high format "Choices: {}" + + @ Multiple enumeration parameter via Complex Structure + param GLUTTON_OF_CHOICE_PRM: ChoiceSlurry + + ##### + # Parameter control: events and a dump command + ##### + + @ Single choice parameter event + event ChoicePrmEv(choice: Choice, validity: Fw.ParamValid) severity activity high \ + format "CHOICE_PRM: {} with validity: {}" + + @ Multiple choice parameter event via Array + event ChoicesPrmEv(choices: ManyChoices, validity: Fw.ParamValid) severity activity high \ + format "CHOICES_PRM: {} with validity: {}" + + @ Too many choice parameter event via Array + event ExtraChoicesPrmEv(choices: TooManyChoices, validity: Fw.ParamValid) severity activity high \ + format "EXTRA_CHOICES_PRM: {} with validity: {}" + + @ Multiple choice parameter event via Structure + event ChoicePairPrmEv(choices: ChoicePair, validity: Fw.ParamValid) severity activity high \ + format "CHOICE_PAIR_PRM: {} with validity: {}" + + @ Multiple choice parameter event via Complex Structure + event ChoiceSlurryPrmEv(choices: ChoiceSlurry, validity: Fw.ParamValid) severity activity high \ + format "GLUTTON_OF_CHOICE_PRM: {} with validity: {}" + + @ Dump the typed parameters + sync command DUMP_TYPED_PARAMETERS() + + # ---------------------------------------------------------------------- + # Special ports + # ---------------------------------------------------------------------- + @ Time get port + time get port timeCaller + + @ Command registration port + command reg port cmdRegOut + + @ Command received port + command recv port cmdIn + + @ Command response port + command resp port cmdResponseOut + + @ Text event port + text event port logTextOut + + @ Event port + event port logOut + + @ Telemetry port + telemetry port tlmOut + + @ Parameter get + param get port prmGetOut + + @ Parameter set + param set port prmSetOut + } +} diff --git a/Ref/TypeDemo/TypeDemo.hpp b/Ref/TypeDemo/TypeDemo.hpp new file mode 100644 index 0000000000..23c251fde3 --- /dev/null +++ b/Ref/TypeDemo/TypeDemo.hpp @@ -0,0 +1,118 @@ +// ====================================================================== +// \title TypeDemo.hpp +// \author mstarch +// \brief hpp file for TypeDemo component implementation class +// ====================================================================== + +#ifndef TypeDemo_HPP +#define TypeDemo_HPP + +#include "Ref/TypeDemo/TypeDemoComponentAc.hpp" + +namespace Ref { + +class TypeDemo : public TypeDemoComponentBase { + public: + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + //! Construct object TypeDemo + //! + TypeDemo(const char* const compName /*!< The component name*/ + ); + + //! Initialize object TypeDemo + //! + void init(const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ + ); + + //! Destroy object TypeDemo + //! + ~TypeDemo() = default; + + PRIVATE: + // ---------------------------------------------------------------------- + // Command handler implementations + // ---------------------------------------------------------------------- + + //! Implementation for CHOICE command handler + //! Single choice command + void CHOICE_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ + const U32 cmdSeq, /*!< The command sequence number*/ + Ref::Choice choice); + + //! Implementation for CHOICES command handler + //! Multiple choice command via Array + void CHOICES_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ + const U32 cmdSeq, /*!< The command sequence number*/ + Ref::ManyChoices choices); + + //! Implementation for CHOICES_WITH_FRIENDS command handler + //! Multiple choice command via Array with a preceding and following argument + void CHOICES_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ + const U32 cmdSeq, /*!< The command sequence number*/ + U8 repeat, + Ref::ManyChoices choices, + U8 repeat_max); + + //! Implementation for EXTRA_CHOICES command handler + //! Multiple choice command via Array + void EXTRA_CHOICES_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ + const U32 cmdSeq, /*!< The command sequence number*/ + Ref::TooManyChoices choices); + + //! Implementation for EXTRA_CHOICES_WITH_FRIENDS command handler + //! Too many choices command via Array with a preceding and following argument + void EXTRA_CHOICES_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ + const U32 cmdSeq, /*!< The command sequence number*/ + U8 repeat, + Ref::TooManyChoices choices, + U8 repeat_max); + //! Implementation for CHOICE_PAIR command handler + //! Multiple choice command via Structure + void CHOICE_PAIR_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ + const U32 cmdSeq, /*!< The command sequence number*/ + Ref::ChoicePair choices); + + //! Implementation for CHOICE_PAIR_WITH_FRIENDS command handler + //! Multiple choices command via Structure with a preceding and following argument + void CHOICE_PAIR_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ + const U32 cmdSeq, /*!< The command sequence number*/ + U8 repeat, + Ref::ChoicePair choices, + U8 repeat_max); + //! Implementation for GLUTTON_OF_CHOICE command handler + //! Multiple choice command via Complex Structure + void GLUTTON_OF_CHOICE_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ + const U32 cmdSeq, /*!< The command sequence number*/ + Ref::ChoiceSlurry choices /*!< + A phenomenal amount of choice + */ + ); + + //! Implementation for GLUTTON_OF_CHOICE_WITH_FRIENDS command handler + //! Multiple choices command via Complex Structure with a preceding and following argument + void GLUTTON_OF_CHOICE_WITH_FRIENDS_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ + const U32 cmdSeq, /*!< The command sequence number*/ + U8 repeat, /*!< + Number of times to repeat the choices + */ + Ref::ChoiceSlurry choices, /*!< + A phenomenal amount of choice + */ + U8 repeat_max /*!< + Limit to the number of repetitions + */ + ); + + //! Implementation for DUMP_TYPED_PARAMETERS command handler + //! Dump the typed parameters + void DUMP_TYPED_PARAMETERS_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ + const U32 cmdSeq /*!< The command sequence number*/ + ); +}; + +} // end namespace Ref + +#endif diff --git a/Ref/locs.fpp b/Ref/locs.fpp deleted file mode 100644 index 8de60b43b4..0000000000 --- a/Ref/locs.fpp +++ /dev/null @@ -1,48 +0,0 @@ -locate component Ref.PingReceiver at "PingReceiver/PingReceiver.fpp" -locate component Ref.RecvBuff at "RecvBuffApp/RecvBuffApp.fpp" -locate component Ref.SendBuff at "SendBuffApp/SendBuffApp.fpp" -locate component Ref.SignalGen at "SignalGen/SignalGen.fpp" -locate constant Ref.Default.queueSize at "Top/instances.fpp" -locate constant Ref.Default.stackSize at "Top/instances.fpp" -locate instance Ref.$health at "Top/instances.fpp" -locate instance Ref.SG1 at "Top/instances.fpp" -locate instance Ref.SG2 at "Top/instances.fpp" -locate instance Ref.SG3 at "Top/instances.fpp" -locate instance Ref.SG4 at "Top/instances.fpp" -locate instance Ref.SG5 at "Top/instances.fpp" -locate instance Ref.blockDrv at "Top/instances.fpp" -locate instance Ref.chanTlm at "Top/instances.fpp" -locate instance Ref.cmdDisp at "Top/instances.fpp" -locate instance Ref.cmdSeq at "Top/instances.fpp" -locate instance Ref.comm at "Top/instances.fpp" -locate instance Ref.downlink at "Top/instances.fpp" -locate instance Ref.eventLogger at "Top/instances.fpp" -locate instance Ref.fatalAdapter at "Top/instances.fpp" -locate instance Ref.fatalHandler at "Top/instances.fpp" -locate instance Ref.fileDownlink at "Top/instances.fpp" -locate instance Ref.fileManager at "Top/instances.fpp" -locate instance Ref.fileUplink at "Top/instances.fpp" -locate instance Ref.fileUplinkBufferManager at "Top/instances.fpp" -locate instance Ref.linuxTime at "Top/instances.fpp" -locate instance Ref.pingRcvr at "Top/instances.fpp" -locate instance Ref.prmDb at "Top/instances.fpp" -locate instance Ref.rateGroup1Comp at "Top/instances.fpp" -locate instance Ref.rateGroup2Comp at "Top/instances.fpp" -locate instance Ref.rateGroup3Comp at "Top/instances.fpp" -locate instance Ref.rateGroupDriverComp at "Top/instances.fpp" -locate instance Ref.recvBuffComp at "Top/instances.fpp" -locate instance Ref.sendBuffComp at "Top/instances.fpp" -locate instance Ref.staticMemory at "Top/instances.fpp" -locate instance Ref.textLogger at "Top/instances.fpp" -locate instance Ref.uplink at "Top/instances.fpp" -locate topology Ref.Ref at "Top/topology.fpp" -locate type Ref.PacketRecvStatus at "RecvBuffApp/RecvBuffApp.fpp" -locate type Ref.PacketStat at "RecvBuffApp/RecvBuffApp.fpp" -locate type Ref.Ports_RateGroups at "Top/topology.fpp" -locate type Ref.Ports_StaticMemory at "Top/topology.fpp" -locate type Ref.SendBuff.ActiveState at "SendBuffApp/SendBuffApp.fpp" -locate type Ref.SignalInfo at "SignalGen/SignalGen.fpp" -locate type Ref.SignalPair at "SignalGen/SignalGen.fpp" -locate type Ref.SignalPairSet at "SignalGen/SignalGen.fpp" -locate type Ref.SignalSet at "SignalGen/SignalGen.fpp" -locate type Ref.SignalType at "SignalGen/SignalGen.fpp" diff --git a/Ref/subdirs.txt b/Ref/subdirs.txt deleted file mode 100644 index 0bc5265b21..0000000000 --- a/Ref/subdirs.txt +++ /dev/null @@ -1,5 +0,0 @@ -PingReceiver -RecvBuffApp -SendBuffApp -SignalGen -Top diff --git a/Ref/update-locs b/Ref/update-locs deleted file mode 100755 index 76583058af..0000000000 --- a/Ref/update-locs +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -fpp-locate-defs `find . -name '*.fpp'` > locs.fpp diff --git a/Ref/update-subdirs b/Ref/update-subdirs deleted file mode 100755 index f86970a7cb..0000000000 --- a/Ref/update-subdirs +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -find . -mindepth 2 -name '*.fpp' | cut -d '/' -f 2 | sort | uniq > subdirs.txt diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..7c4545202c --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,22 @@ +# Security Policy + +The F´ team secures our code base using a combination of code review, dependency review, and static analysis performed during automated pull request +verification. We welcome general bug reports and vulnerability reports from the larger community. + +### Reporting a Vulnerability + +For general defects, please submit a [Bug Report](https://github.com/nasa/fprime/issues/new/choose) + +To report a vulnerability for F´ please use the [vulnerability report form](https://github.com/nasa/fprime/security/advisories/new) or send a detailed +report to [fprime@jpl.nasa.gov](mailto:fprime@jpl.nasa.gov). + +### Static Analysis Checks + +The [GitHub Actions workflows](https://github.com/nasa/fprime/blob/devel/.github/workflows/) are available to the public. To review the results, fork the +repository and run the workflows. + +These checks are run on each pull request submitted to F´. + +### General Support + +For additional support, please open a [Discussion](https://github.com/nasa/fprime/discussions). diff --git a/STest/README.md b/STest/README.md index e69de29bb2..4d2a03fc0c 100644 --- a/STest/README.md +++ b/STest/README.md @@ -0,0 +1,62 @@ +## STest + +STest is a framework for using **rules** and **scenarios** to construct and run unit tests. +The concepts of "rules" and "scenarios" are described below. +Using rules and scenarios provides structure to unit tests. +By automatically generating tests, scenarios can also provide more coverage than is possible +with manually-written tests. + +- [State](#state) +- [Rule](#rule) +- [Scenario](#scenario) +- [Use in F Prime](#use-in-f-prime) + +
+ +### State + +In rule-based testing, **state** refers to the current state of a running test. It usually includes **concrete state** (the actual state of the system under test) and **test state** or **abstract state** (state that abstracts the state of the system under test, to assist with modeling). + +In the STest implementation of rule-based testing, `State` is a user-defined type. The `Rule` and `Scenario` classes discussed below are templates that are parameterized over this type. + +### Rule + +A **rule** is a unit of test code that specifies and checks some behavior of the system under test. +It has two elements: + +1. A **precondition** that specifies when the rule may be applied. +A precondition is a predicate function (i.e., a read-only function that returns a Boolean value) on +the [system state](#state). +For example, consider a rule that exercises the nominal behavior of a buffer allocator. +The precondition for this rule might specify that a buffer is available for allocation. +On the other hand, the precondition for a rule that exercises the error case "buffer not available" +might specify that all buffers have been allocated. + +2. An **action** that (a) causes the system under test to do something and (b) checks that the resulting +behavior is as expected, given the current system state. +For example, a "nominal" or "OK" rule for a buffer allocator might check that a buffer was allocated. +A "buffer not available" rule might check that the appropriate warning is emitted as an F' event. + +When using STest, you specify rules as derived classes of the abstract class [Rule](./STest/Rule/Rule.hpp). +You specify the precondition and action by overriding pure virtual functions specified in the `Rule` interface. + +### Scenario +A **scenario** is a recipe for using a set of rules to construct one or more tests. Examples of scenarios include the following: +- Applying a set of rules in a sequence which is either fixed ([RuleSequenceScenario](./STest/Scenario/RuleSequenceScenario.hpp)) or randomized ([RandomScenario](./STest/Scenario/RandomScenario.hpp)) +- Repeatedly applying a rule within a scenario ([RepeatedRuleScenario](./STest/Scenario/RepeatedRuleScenario.hpp)) +- Running a scenario while a condition holds ([ConditionalScenario](./STest/Scenario/ConditionalScenario.hpp)) +- Creating a sequence of scenarios ([SequenceScenario](./STest/Scenario/SequenceScenario.hpp)) and randomly selecting one of them to run ([SelectedScenario](./STest/Scenario/SelectedScenario.hpp)) +- Randomly interleaving a set of scenarios ([InterleavedScenario](./STest/Scenario/InterleavedScenario.hpp)) +- Iterating over a collection of scenarios ([IteratedScenario](./STest/Scenario/IteratedScenario.hpp)) or over a particular one till a certain condition holds ([ConditionalIteratedScenario](./STest/Scenario/ConditionalIteratedScenario.hpp)) +- Running an iterated scenario with a specific bound on the number of iterations ([BoundedIteratedScenario](./STest/Scenario/BoundedIteratedScenario.hpp)) +- Running a scenario for a certain bound, with the range being either fixed ([BoundedScenario](./STest/Scenario/BoundedScenario.hpp)) or randomly selected ([RandomlyBoundedScenario](./STest/Scenario/RandomlyBoundedScenario.hpp)) + +The iterated and random scenarios allow you to construct complex tests that explore many behaviors, using relatively simple specifications. Typically the tests constructed with these scenarios are not feasible to write by hand (e.g., because they apply thousands or millions of rules). + +### Use in F Prime + +At present, F Prime uses STest for unit testing of components. Examples include [Svc/GroundInterface](https://github.com/nasa/fprime/blob/master/Svc/GroundInterface/test/ut/GroundInterfaceRules.cpp) and [Fw/Logger](https://github.com/nasa/fprime/blob/master/Fw/Logger/test/ut/LoggerRules.cpp). The main scenarios used here are +as follows: + +* Short sequences of rules that set up the system state and then test a particular rule. +* Random scenarios for automatically generating more complex tests. diff --git a/STest/STest/Random/Random.cpp b/STest/STest/Random/Random.cpp index 25af352bc7..7d993f863e 100644 --- a/STest/STest/Random/Random.cpp +++ b/STest/STest/Random/Random.cpp @@ -10,6 +10,7 @@ // ====================================================================== #include +#include #include #include "STest/Random/Random.hpp" @@ -37,7 +38,7 @@ namespace STest { bool result = true; FILE *fp = fopen(fileName, "r"); if (fp != nullptr) { - result = (fscanf(fp, "%u", &value) == 1); + result = (fscanf(fp, "%" PRIu32, &value) == 1); (void) fclose(fp); } else { @@ -59,7 +60,7 @@ namespace STest { if (fp != nullptr) { int status = fprintf( fp, - "%u\n", + "%" PRIu32 "\n", seedValue ); result = (status > 0); @@ -78,11 +79,11 @@ namespace STest { const bool seedValueOK = SeedValue::getFromFile("seed", seedValue); if (seedValueOK) { - printf("[STest::Random] Read seed %u from file\n", seedValue); + printf("[STest::Random] Read seed %" PRIu32 " from file\n", seedValue); } else { seedValue = SeedValue::getFromTime(); - printf("[STest::Random] Generated seed %u from system time\n", seedValue); + printf("[STest::Random] Generated seed %" PRIu32 " from system time\n", seedValue); } (void) SeedValue::appendToFile("seed-history", seedValue); SeedValue::set(seedValue); diff --git a/STest/STest/Random/bsd_random.c b/STest/STest/Random/bsd_random.c index affa2b785e..cdc15cafa6 100644 --- a/STest/STest/Random/bsd_random.c +++ b/STest/STest/Random/bsd_random.c @@ -190,8 +190,7 @@ static uint32_t *end_ptr = &randtbl[DEG_3 + 1]; static inline uint32_t good_rand(int32_t) __attribute__((always_inline)); -static inline uint32_t good_rand (x) - int32_t x; +static inline uint32_t good_rand (int32_t x) { /* * Compute x = (7^5 * x) mod (2^31 - 1) @@ -227,8 +226,7 @@ static inline uint32_t good_rand (x) * for default usage relies on values produced by this routine. */ void -bsd_srandom(x) - unsigned x; +bsd_srandom(unsigned x) { int i, lim; @@ -270,11 +268,11 @@ bsd_srandom(x) * complain about mis-alignment, but you should disregard these messages. */ char * -bsd_initstate(seed, arg_state, n) - unsigned seed; /* seed for R.N.G. */ - char *arg_state; /* pointer to state array */ - size_t n; /* # bytes of state info */ -{ +bsd_initstate( + unsigned seed, /* seed for R.N.G. */ + char *arg_state, /* pointer to state array */ + size_t n /* # bytes of state info */ +) { char *ostate = (char *)(&state[-1]); uint32_t *int_arg_state = (uint32_t *)arg_state; @@ -284,7 +282,7 @@ bsd_initstate(seed, arg_state, n) state[-1] = MAX_TYPES * (rptr - state) + rand_type; if (n < BREAK_0) { (void)fprintf(stderr, - "random: not enough state (%ld bytes); ignored.\n", n); + "random: not enough state (%zd bytes); ignored.\n", n); return(0); } if (n < BREAK_1) { @@ -338,9 +336,9 @@ bsd_initstate(seed, arg_state, n) * complain about mis-alignment, but you should disregard these messages. */ char * -bsd_setstate(arg_state) - const char *arg_state; /* pointer to state array */ -{ +bsd_setstate( + const char *arg_state /* pointer to state array */ +) { uint32_t *new_state = (uint32_t *)arg_state; uint32_t type = new_state[0] % MAX_TYPES; uint32_t rear = new_state[0] / MAX_TYPES; @@ -391,7 +389,7 @@ bsd_setstate(arg_state) * Returns a 31-bit random number. */ long -bsd_random() +bsd_random(void) { uint32_t i; uint32_t *f, *r; diff --git a/STest/STest/Random/bsd_random.h b/STest/STest/Random/bsd_random.h index 1e72d82ece..f776aa5d09 100644 --- a/STest/STest/Random/bsd_random.h +++ b/STest/STest/Random/bsd_random.h @@ -21,4 +21,4 @@ char *bsd_initstate(unsigned seed, char *arg_state, size_t n); char *bsd_setstate(const char *arg_state); -long bsd_random(); +long bsd_random(void); diff --git a/STest/STest/Scenario/ConditionalIteratedScenario.hpp b/STest/STest/Scenario/ConditionalIteratedScenario.hpp index 89823ca2c9..1be1bf1e57 100644 --- a/STest/STest/Scenario/ConditionalIteratedScenario.hpp +++ b/STest/STest/Scenario/ConditionalIteratedScenario.hpp @@ -61,7 +61,7 @@ namespace STest { Scenario* nextScenario_IteratedScenario( State& state //!< The system state ) { - Scenario* scenario = NULL; + Scenario* scenario = nullptr; if (!this->condition_ConditionalIteratedScenario(state)) { this->done = true; } diff --git a/Svc/ActiveLogger/ActiveLoggerImpl.cpp b/Svc/ActiveLogger/ActiveLoggerImpl.cpp index ce9a38b4f8..8bd9ad7711 100644 --- a/Svc/ActiveLogger/ActiveLoggerImpl.cpp +++ b/Svc/ActiveLogger/ActiveLoggerImpl.cpp @@ -127,13 +127,6 @@ namespace Svc { } void ActiveLoggerImpl::SET_EVENT_FILTER_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, FilterSeverity filterLevel, Enabled filterEnable) { - if ( (filterLevel.e > FilterSeverity::DIAGNOSTIC) or - (filterLevel.e < FilterSeverity::WARNING_HI) or - (filterEnable.e < Enabled::ENABLED) or - (filterEnable.e > Enabled::DISABLED)) { - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::VALIDATION_ERROR); - return; - } this->m_filterState[filterLevel.e].enabled = filterEnable; this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); } @@ -145,16 +138,6 @@ namespace Svc { Enabled idEnabled //!< ID filter state ) { - // check parameter - switch (idEnabled.e) { - case Enabled::ENABLED: - case Enabled::DISABLED: - break; - default: - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::VALIDATION_ERROR); - return; - } - if (Enabled::ENABLED == idEnabled.e) { // add ID // search list for existing entry for (NATIVE_INT_TYPE entry = 0; entry < TELEM_ID_FILTER_SIZE; entry++) { diff --git a/Svc/ActiveLogger/CMakeLists.txt b/Svc/ActiveLogger/CMakeLists.txt index 0521ef4012..b31e2a3103 100644 --- a/Svc/ActiveLogger/CMakeLists.txt +++ b/Svc/ActiveLogger/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/ActiveLogger/test/ut/ActiveLoggerImplTester.cpp b/Svc/ActiveLogger/test/ut/ActiveLoggerImplTester.cpp index 85f4862fbb..ff95e840e4 100644 --- a/Svc/ActiveLogger/test/ut/ActiveLoggerImplTester.cpp +++ b/Svc/ActiveLogger/test/ut/ActiveLoggerImplTester.cpp @@ -173,7 +173,7 @@ namespace Svc { 0, ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, cmdSeq, - Fw::CmdResponse::VALIDATION_ERROR + Fw::CmdResponse::FORMAT_ERROR ); this->clearHistory(); reportFilterLevel = FilterSeverity::WARNING_HI; @@ -184,7 +184,7 @@ namespace Svc { 0, ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, cmdSeq, - Fw::CmdResponse::VALIDATION_ERROR + Fw::CmdResponse::FORMAT_ERROR ); FilterSeverity eventLevel; this->clearHistory(); @@ -196,7 +196,7 @@ namespace Svc { 0, ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, cmdSeq, - Fw::CmdResponse::VALIDATION_ERROR + Fw::CmdResponse::FORMAT_ERROR ); this->clearHistory(); @@ -209,7 +209,7 @@ namespace Svc { 0, ActiveLoggerImpl::OPCODE_SET_EVENT_FILTER, cmdSeq, - Fw::CmdResponse::VALIDATION_ERROR + Fw::CmdResponse::FORMAT_ERROR ); } @@ -374,7 +374,7 @@ namespace Svc { 0, ActiveLoggerImpl::OPCODE_SET_ID_FILTER, cmdSeq, - Fw::CmdResponse::VALIDATION_ERROR + Fw::CmdResponse::FORMAT_ERROR ); ASSERT_EVENTS_SIZE(0); diff --git a/Svc/ActiveRateGroup/ActiveRateGroup.cpp b/Svc/ActiveRateGroup/ActiveRateGroup.cpp index 42a9b82b42..772b8ecca6 100644 --- a/Svc/ActiveRateGroup/ActiveRateGroup.cpp +++ b/Svc/ActiveRateGroup/ActiveRateGroup.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/Svc/ActiveRateGroup/ActiveRateGroup.hpp b/Svc/ActiveRateGroup/ActiveRateGroup.hpp index 62fc8f15b9..11e64d8103 100644 --- a/Svc/ActiveRateGroup/ActiveRateGroup.hpp +++ b/Svc/ActiveRateGroup/ActiveRateGroup.hpp @@ -30,6 +30,7 @@ namespace Svc { class ActiveRateGroup : public ActiveRateGroupComponentBase { public: + static constexpr NATIVE_INT_TYPE CONNECTION_COUNT_MAX = NUM_RATEGROUPMEMBEROUT_OUTPUT_PORTS; //! \brief ActiveRateGroup constructor //! @@ -110,7 +111,7 @@ namespace Svc { U32 m_cycles; //!< cycles executed U32 m_maxTime; //!< maximum execution time in microseconds volatile bool m_cycleStarted; //!< indicate that cycle has started. Used to detect overruns. - NATIVE_INT_TYPE m_contexts[NUM_RATEGROUPMEMBEROUT_OUTPUT_PORTS]; //!< Must match number of output ports + NATIVE_INT_TYPE m_contexts[CONNECTION_COUNT_MAX]; //!< Must match number of output ports NATIVE_INT_TYPE m_numContexts; //!< Number of contexts passed in by user NATIVE_INT_TYPE m_overrunThrottle; //!< throttle value for overrun events U32 m_cycleSlips; //!< tracks number of cycle slips diff --git a/Svc/ActiveRateGroup/ActiveRateGroupImpl.cpp b/Svc/ActiveRateGroup/ActiveRateGroupImpl.cpp index 2cbea4117b..75d9d96eb7 100644 --- a/Svc/ActiveRateGroup/ActiveRateGroupImpl.cpp +++ b/Svc/ActiveRateGroup/ActiveRateGroupImpl.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/Svc/ActiveRateGroup/CMakeLists.txt b/Svc/ActiveRateGroup/CMakeLists.txt index ee845c6c64..012ddbb4cb 100644 --- a/Svc/ActiveRateGroup/CMakeLists.txt +++ b/Svc/ActiveRateGroup/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/ActiveRateGroup/docs/img/RateGroupCall.jpg b/Svc/ActiveRateGroup/docs/img/RateGroupCall.jpg deleted file mode 100644 index c783f63892..0000000000 Binary files a/Svc/ActiveRateGroup/docs/img/RateGroupCall.jpg and /dev/null differ diff --git a/Svc/ActiveRateGroup/docs/sdd.md b/Svc/ActiveRateGroup/docs/sdd.md index 235c3df0cd..d7e08f5ec4 100644 --- a/Svc/ActiveRateGroup/docs/sdd.md +++ b/Svc/ActiveRateGroup/docs/sdd.md @@ -63,7 +63,22 @@ event, and increase the cycle slip counters. As described in the Functional Description section, the `Svc::ActiveRateGroup` component accepts calls to the CycleIn and invokes the RateGroupMemberOut ports: -![System Tick Port Call](img/RateGroupCall.jpg) +```mermaid +sequenceDiagram + Caller->>ActiveRateGroup: 1. CycleIn + activate Caller + activate ActiveRateGroup + deactivate ActiveRateGroup + loop for each output port + ActiveRateGroup->>Callee: 2. RateGroupMemberOut[N] + activate Callee + activate ActiveRateGroup + deactivate Callee + deactivate ActiveRateGroup + end + deactivate Caller +``` + ### 3.4 State diff --git a/Svc/ActiveTextLogger/ActiveTextLoggerImpl.cpp b/Svc/ActiveTextLogger/ActiveTextLoggerImpl.cpp index dd6fbd1fdf..5daa9318e0 100644 --- a/Svc/ActiveTextLogger/ActiveTextLoggerImpl.cpp +++ b/Svc/ActiveTextLogger/ActiveTextLoggerImpl.cpp @@ -94,7 +94,7 @@ namespace Svc { (void) snprintf(textStr, FW_INTERNAL_INTERFACE_STRING_MAX_SIZE, - "EVENT: (%d) (%04d-%02d-%02dT%02d:%02d:%02d.%03u) %s: %s\n", + "EVENT: (%" PRI_FwEventIdType ") (%04d-%02d-%02dT%02d:%02d:%02d.%03" PRIu32 ") %s: %s\n", id, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min,tm.tm_sec,timeTag.getUSeconds(), severityString,text.toChar()); @@ -103,8 +103,8 @@ namespace Svc { (void) snprintf(textStr, FW_INTERNAL_INTERFACE_STRING_MAX_SIZE, - "EVENT: (%d) (%d:%d,%d) %s: %s\n", - id,timeTag.getTimeBase(),timeTag.getSeconds(),timeTag.getUSeconds(),severityString,text.toChar()); + "EVENT: (%" PRI_FwEventIdType ") (%" PRI_FwTimeBaseStoreType ":%" PRId32 ",%" PRId32 ") %s: %s\n", + id, static_cast(timeTag.getTimeBase()),timeTag.getSeconds(),timeTag.getUSeconds(),severityString,text.toChar()); } // Call internal interface so that everything else is done on component thread, diff --git a/Svc/ActiveTextLogger/CMakeLists.txt b/Svc/ActiveTextLogger/CMakeLists.txt index 9408619bb5..c9fecef4e5 100644 --- a/Svc/ActiveTextLogger/CMakeLists.txt +++ b/Svc/ActiveTextLogger/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/ActiveTextLogger/LogFile.cpp b/Svc/ActiveTextLogger/LogFile.cpp index 0282e378bf..4b95efd00b 100644 --- a/Svc/ActiveTextLogger/LogFile.cpp +++ b/Svc/ActiveTextLogger/LogFile.cpp @@ -95,7 +95,7 @@ namespace Svc { } U32 suffix = 0; - U64 tmp; + FwSizeType tmp; char fileNameFinal[Fw::String::STRING_SIZE]; (void) strncpy(fileNameFinal,fileName, Fw::String::STRING_SIZE); @@ -119,7 +119,7 @@ namespace Svc { } NATIVE_INT_TYPE stat = snprintf(fileNameFinal,Fw::String::STRING_SIZE, - "%s%d",fileName,suffix); + "%s%" PRIu32,fileName,suffix); // If there was error, then just fail: if (stat <= 0) { diff --git a/Svc/ActiveTextLogger/test/ut/Tester.cpp b/Svc/ActiveTextLogger/test/ut/Tester.cpp index 9826e20682..4c742a9f1b 100644 --- a/Svc/ActiveTextLogger/test/ut/Tester.cpp +++ b/Svc/ActiveTextLogger/test/ut/Tester.cpp @@ -103,7 +103,7 @@ namespace Svc { if (stream1) { std::cout << "readLine: " << buf << std::endl; char textStr[512]; - sprintf(textStr, + snprintf(textStr, sizeof(textStr), "EVENT: (%d) (%d:%d,%d) %s: %s", id,timeTag.getTimeBase(),timeTag.getSeconds(),timeTag.getUSeconds(),severityString,text.toChar()); ASSERT_EQ(0,strcmp(textStr,buf)); @@ -125,7 +125,7 @@ namespace Svc { ASSERT_EQ(512U, this->component.m_log_file.m_maxFileSize); // Test predicted size matches actual: - U64 fileSize = 0; + FwSizeType fileSize = 0; Os::FileSystem::getFileSize("test_file",fileSize); ASSERT_EQ(fileSize,this->component.m_log_file.m_currentFileSize); @@ -144,7 +144,7 @@ namespace Svc { // Verify new printed line else { char textStr[512]; - sprintf(textStr, + snprintf(textStr, sizeof(textStr), "EVENT: (%d) (%d:%d,%d) %s: %s", id,timeTag.getTimeBase(),timeTag.getSeconds(),timeTag.getUSeconds(),severityString,text.toChar()); ASSERT_EQ(0,strcmp(textStr,buf)); @@ -164,7 +164,7 @@ namespace Svc { { // TODO file errors- use the Os/Stubs? - U64 tmp; + FwSizeType tmp; printf("Testing writing text that is larger than FW_INTERNAL_INTERFACE_STRING_MAX_SIZE\n"); // Can't test this b/c max size of TextLogString is 256 and @@ -206,7 +206,7 @@ namespace Svc { if (stream1) { std::cout << "readLine: " << buf << std::endl; char textStr[512]; - sprintf(textStr, + snprintf(textStr, sizeof(textStr), "EVENT: (%d) (%d:%d,%d) %s: %s", id,timeTag.getTimeBase(),timeTag.getSeconds(),timeTag.getUSeconds(),severityString,text.toChar()); ASSERT_EQ(0,strcmp(textStr,buf)); @@ -316,7 +316,7 @@ namespace Svc { stat = this->component.set_log_file(baseName,50); - sprintf(baseNameWithSuffix,"%s%d",baseName,i); + snprintf(baseNameWithSuffix, sizeof(baseNameWithSuffix), "%s%d",baseName,i); ASSERT_TRUE(stat); ASSERT_TRUE(this->component.m_log_file.m_openFile); ASSERT_EQ(0,strcmp(baseNameWithSuffix,this->component.m_log_file.m_fileName.toChar())); @@ -327,7 +327,7 @@ namespace Svc { // Create 11th which will fail and re-use the original: stat = this->component.set_log_file(baseName,50); - sprintf(baseNameWithSuffix,"%s%d",baseName,i); + snprintf(baseNameWithSuffix, sizeof(baseNameWithSuffix), "%s%d",baseName,i); ASSERT_TRUE(stat); ASSERT_TRUE(this->component.m_log_file.m_openFile); printf("<< %s %s\n",baseName,this->component.m_log_file.m_fileName.toChar()); @@ -341,7 +341,7 @@ namespace Svc { remove(longFileNameDup); remove(baseName); for (i = 0; i < 10; ++i) { - sprintf(baseNameWithSuffix,"%s%d",baseName,i); + snprintf(baseNameWithSuffix, sizeof(baseNameWithSuffix), "%s%d",baseName,i); remove(baseNameWithSuffix); } diff --git a/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.cpp b/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.cpp index ff44a64432..1e1ff8d54d 100644 --- a/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.cpp +++ b/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.cpp @@ -12,7 +12,7 @@ #include -#include "Fw/Types/BasicTypes.hpp" +#include #include #include #include @@ -24,12 +24,12 @@ namespace Fw { FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, NATIVE_UINT_TYPE numArgs, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4, - AssertArg arg5, - AssertArg arg6, + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4, + FwAssertArgType arg5, + FwAssertArgType arg6, CHAR* destBuffer, NATIVE_INT_TYPE buffSize ); @@ -72,12 +72,12 @@ namespace Svc { FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, NATIVE_UINT_TYPE numArgs, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4, - AssertArg arg5, - AssertArg arg6 + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4, + FwAssertArgType arg5, + FwAssertArgType arg6 ) { if (m_compPtr) { @@ -108,18 +108,18 @@ namespace Svc { FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, NATIVE_UINT_TYPE numArgs, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4, - AssertArg arg5, - AssertArg arg6 + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4, + FwAssertArgType arg5, + FwAssertArgType arg6 ) { #if FW_ASSERT_LEVEL == FW_FILEID_ASSERT Fw::LogStringArg fileArg; - fileArg.format("0x%08X",file); + fileArg.format("0x%08" PRIX32,file); #else Fw::LogStringArg fileArg(file); #endif @@ -130,6 +130,12 @@ namespace Svc { // and this can conflict with the traditionally smaller stack sizes. printf("%s\n", msg); + // Handle the case where the ports aren't connected yet + if (not this->isConnected_Log_OutputPort(0)) { + assert(0); + return; + } + switch (numArgs) { case 0: this->log_FATAL_AF_ASSERT_0(fileArg,lineNo); diff --git a/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.hpp b/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.hpp index 4de9058e1b..61b3f65541 100644 --- a/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.hpp +++ b/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.hpp @@ -48,12 +48,12 @@ namespace Svc { FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, NATIVE_UINT_TYPE numArgs, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4, - AssertArg arg5, - AssertArg arg6 + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4, + FwAssertArgType arg5, + FwAssertArgType arg6 ); private: @@ -68,12 +68,12 @@ namespace Svc { FILE_NAME_ARG file, NATIVE_UINT_TYPE lineNo, NATIVE_UINT_TYPE numArgs, - AssertArg arg1, - AssertArg arg2, - AssertArg arg3, - AssertArg arg4, - AssertArg arg5, - AssertArg arg6 + FwAssertArgType arg1, + FwAssertArgType arg2, + FwAssertArgType arg3, + FwAssertArgType arg4, + FwAssertArgType arg5, + FwAssertArgType arg6 ); // Prevent actual assert since FATAL handler will deal with it diff --git a/Svc/AssertFatalAdapter/CMakeLists.txt b/Svc/AssertFatalAdapter/CMakeLists.txt index a811de6118..03fd069f3e 100644 --- a/Svc/AssertFatalAdapter/CMakeLists.txt +++ b/Svc/AssertFatalAdapter/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/AssertFatalAdapter/test/ut/Tester.cpp b/Svc/AssertFatalAdapter/test/ut/Tester.cpp index 1991f96652..24eb86b63b 100644 --- a/Svc/AssertFatalAdapter/test/ut/Tester.cpp +++ b/Svc/AssertFatalAdapter/test/ut/Tester.cpp @@ -10,8 +10,9 @@ // // ====================================================================== -#include "Tester.hpp" +#include "Fw/Types/String.hpp" #include "Fw/Types/StringUtils.hpp" +#include "Tester.hpp" #define INSTANCE 0 #define MAX_HISTORY_SIZE 10 @@ -40,7 +41,13 @@ namespace Svc { U32 lineNo; char file[80 + 1]; // Limit to 80 characters in the port call - (void) Fw::StringUtils::string_copy(file, __FILE__, sizeof(file)); + Fw::String fileString; +#if FW_ASSERT_LEVEL == FW_FILEID_ASSERT + fileString.format("0x%08" PRIX32, ASSERT_FILE_ID); +#else + fileString = __FILE__; +#endif + (void) Fw::StringUtils::string_copy(file, fileString.toChar(), sizeof(file)); // FW_ASSERT_0 @@ -85,9 +92,17 @@ namespace Svc { ASSERT_EVENTS_AF_ASSERT_6(0,file,lineNo,1,2,3,4,5,6); // Test unexpected assert - this->component.reportAssert("foo",1000,10,1,2,3,4,5,6); +#if FW_ASSERT_LEVEL == FW_FILEID_ASSERT + U32 unexpectedFile = 0xF00; + const char *const unexpectedFileArg = "0x00000F00"; +#else + const char *const unexpectedFile = "foo"; + const char *const unexpectedFileArg = unexpectedFile; +#endif + + this->component.reportAssert(unexpectedFile,1000,10,1,2,3,4,5,6); ASSERT_EVENTS_AF_UNEXPECTED_ASSERT_SIZE(1); - ASSERT_EVENTS_AF_UNEXPECTED_ASSERT(0,"foo",1000,10); + ASSERT_EVENTS_AF_UNEXPECTED_ASSERT(0,unexpectedFileArg,1000,10); } diff --git a/Svc/BufferAccumulator/ArrayFIFOBuffer.cpp b/Svc/BufferAccumulator/ArrayFIFOBuffer.cpp index 0ef60c8f57..6df0c1a493 100644 --- a/Svc/BufferAccumulator/ArrayFIFOBuffer.cpp +++ b/Svc/BufferAccumulator/ArrayFIFOBuffer.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include "Svc/BufferAccumulator/BufferAccumulator.hpp" -#include "Fw/Types/BasicTypes.hpp" +#include #include "Fw/Types/Assert.hpp" diff --git a/Svc/BufferAccumulator/BufferAccumulator.cpp b/Svc/BufferAccumulator/BufferAccumulator.cpp index 5399518370..ea997b025a 100644 --- a/Svc/BufferAccumulator/BufferAccumulator.cpp +++ b/Svc/BufferAccumulator/BufferAccumulator.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include "Svc/BufferAccumulator/BufferAccumulator.hpp" -#include "Fw/Types/BasicTypes.hpp" +#include namespace Svc { diff --git a/Svc/BufferAccumulator/test/ut/Tester.cpp b/Svc/BufferAccumulator/test/ut/Tester.cpp index 068cb3484d..da253ea686 100644 --- a/Svc/BufferAccumulator/test/ut/Tester.cpp +++ b/Svc/BufferAccumulator/test/ut/Tester.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include "Tester.hpp" -#include "Fw/Types/BasicTypes.hpp" +#include #include "Fw/Types/MallocAllocator.hpp" #define INSTANCE 0 diff --git a/Svc/BufferLogger/CMakeLists.txt b/Svc/BufferLogger/CMakeLists.txt index 87f203baa6..4be8388af7 100644 --- a/Svc/BufferLogger/CMakeLists.txt +++ b/Svc/BufferLogger/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/BufferLogger/test/ut/Tester.cpp b/Svc/BufferLogger/test/ut/Tester.cpp index f32c8a749f..548d03a5a9 100644 --- a/Svc/BufferLogger/test/ut/Tester.cpp +++ b/Svc/BufferLogger/test/ut/Tester.cpp @@ -265,7 +265,7 @@ namespace Svc { { // Make sure the file size is within bounds - U64 actualSize = 0; + FwSizeType actualSize = 0; const Os::FileSystem::Status status = Os::FileSystem::getFileSize(fileName, actualSize); ASSERT_EQ(Os::FileSystem::OP_OK, status); diff --git a/Svc/BufferManager/BufferManagerComponentImpl.cpp b/Svc/BufferManager/BufferManagerComponentImpl.cpp index a1904fbe3c..a256f8c301 100644 --- a/Svc/BufferManager/BufferManagerComponentImpl.cpp +++ b/Svc/BufferManager/BufferManagerComponentImpl.cpp @@ -12,7 +12,7 @@ #include -#include +#include #include #include #include diff --git a/Svc/BufferManager/CMakeLists.txt b/Svc/BufferManager/CMakeLists.txt index b14acdc062..24d060a050 100644 --- a/Svc/BufferManager/CMakeLists.txt +++ b/Svc/BufferManager/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/BufferManager/docs/img/SendingABuffer.jpg b/Svc/BufferManager/docs/img/SendingABuffer.jpg deleted file mode 100644 index f7c1c9ba28..0000000000 Binary files a/Svc/BufferManager/docs/img/SendingABuffer.jpg and /dev/null differ diff --git a/Svc/BufferManager/docs/sdd.md b/Svc/BufferManager/docs/sdd.md index 1ab86cb26b..7eb5e5031f 100644 --- a/Svc/BufferManager/docs/sdd.md +++ b/Svc/BufferManager/docs/sdd.md @@ -106,7 +106,18 @@ component. 3. The receiving component uses the data in *B*. When done, it sends *B* back to the [`bufferSendIn`](#bufferSendIn) port of `BufferManager` for deallocation. -![`BufferManager` Sending a Buffer](img/SendingABuffer.jpg "SequenceDiagram") +```mermaid +sequenceDiagram + Sending Component->>BufferManager: Request buffer + activate Sending Component + activate BufferManager + Sending Component->>Receiving Component: Send buffer + activate Receiving Component + deactivate Sending Component + Receiving Component->>BufferManager: Send buffer + deactivate BufferManager + deactivate Receiving Component +``` ### 3.8 Assertions diff --git a/Svc/BufferRepeater/BufferRepeater.cpp b/Svc/BufferRepeater/BufferRepeater.cpp new file mode 100644 index 0000000000..d081f4bd17 --- /dev/null +++ b/Svc/BufferRepeater/BufferRepeater.cpp @@ -0,0 +1,83 @@ +// ====================================================================== +// \title BufferRepeater.cpp +// \author lestarch +// \brief cpp file for GenericRepeater component implementation class +// +// \copyright +// Copyright 2009-2015, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include +#include + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction, initialization, and destruction +// ---------------------------------------------------------------------- + +BufferRepeater ::BufferRepeater(const char* const compName) + : BufferRepeaterComponentBase(compName), + m_allocation_failure_response(BufferRepeater::NUM_BUFFER_REPEATER_FAILURE_OPTIONS) {} + +void BufferRepeater ::init(const NATIVE_INT_TYPE instance) { + BufferRepeaterComponentBase::init(instance); +} + +BufferRepeater ::~BufferRepeater() {} + +void BufferRepeater ::configure(BufferRepeater::BufferRepeaterFailureOption allocation_failure_response) { + this->m_allocation_failure_response = allocation_failure_response; +} + +bool BufferRepeater ::check_allocation(FwIndexType index, + const Fw::Buffer& new_allocation, + const Fw::Buffer& incoming_buffer) { + FW_ASSERT(index < NUM_PORTOUT_OUTPUT_PORTS, index); + bool is_valid = (new_allocation.getData() != nullptr) && (new_allocation.getSize() >= incoming_buffer.getSize()); + + // Respond to invalid buffer allocation + if (!is_valid) { + switch (this->m_allocation_failure_response) { + case NO_RESPONSE_ON_OUT_OF_MEMORY: + // No response intended + break; + case WARNING_ON_OUT_OF_MEMORY: + this->log_WARNING_HI_AllocationSoftFailure(index, incoming_buffer.getSize()); + break; + case FATAL_ON_OUT_OF_MEMORY: + this->log_FATAL_AllocationHardFailure(index, incoming_buffer.getSize()); + break; + default: + FW_ASSERT(0); + break; + } + } + return is_valid; +} + +// ---------------------------------------------------------------------- +// Handler implementations for user-defined serial input ports +// ---------------------------------------------------------------------- + +void BufferRepeater ::portIn_handler(NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Buffer& buffer /*!< The serialization buffer*/ +) { + FW_ASSERT(this->m_allocation_failure_response < NUM_BUFFER_REPEATER_FAILURE_OPTIONS); + for (FwIndexType i = 0; i < NUM_PORTOUT_OUTPUT_PORTS; i++) { + if (isConnected_portOut_OutputPort(i)) { + Fw::Buffer new_allocation = this->allocate_out(0, buffer.getSize()); + if (this->check_allocation(i, new_allocation, buffer)) { + // Clone the data and send it + ::memcpy(new_allocation.getData(), buffer.getData(), buffer.getSize()); + new_allocation.setSize(buffer.getSize()); + this->portOut_out(i, new_allocation); + } + } + } + this->deallocate_out(0, buffer); +} +} // end namespace Svc diff --git a/Svc/BufferRepeater/BufferRepeater.fpp b/Svc/BufferRepeater/BufferRepeater.fpp new file mode 100644 index 0000000000..133cb918fc --- /dev/null +++ b/Svc/BufferRepeater/BufferRepeater.fpp @@ -0,0 +1,45 @@ +module Svc { + + @ A component for repeating Fw.BufferSend calls to multiple consumers + passive component BufferRepeater { + @ Port to duplicate across the repeater + sync input port portIn: Fw.BufferSend + + @ Duplicated output ports + output port portOut: [BufferRepeaterOutputPorts] Fw.BufferSend + + @ Port to allocate new memory for each buffer output + output port allocate: Fw.BufferGet + + @ Port to deallocate original buffer output + output port deallocate: Fw.BufferSend + + @ Event port + event port Log + + @ Text event port + text event port LogText + + @ Time get port + time get port Time + + @ Soft failure in allocation + event AllocationSoftFailure( + $port: I32 @< The port index that needed an allocation + $size: U32 @< The requested allocation size + ) \ + severity warning high \ + id 0 \ + format "Failed to allocate {} byte buffer for port {}" + + + @ Hard failure in allocation + event AllocationHardFailure( + $port: I32 @< The port index that needed an allocation + $size: U32 @< The requested allocation size + ) \ + severity fatal \ + id 1 \ + format "Failed to allocate {} byte buffer for port {}" + } +} diff --git a/Svc/BufferRepeater/BufferRepeater.hpp b/Svc/BufferRepeater/BufferRepeater.hpp new file mode 100644 index 0000000000..34873565f1 --- /dev/null +++ b/Svc/BufferRepeater/BufferRepeater.hpp @@ -0,0 +1,85 @@ +// ====================================================================== +// \title BufferRepeater.hpp +// \author lestarch +// \brief hpp file for GenericRepeater component implementation class +// +// \copyright +// Copyright 2009-2015, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#ifndef BufferRepeater_HPP +#define BufferRepeater_HPP + +#include "Svc/BufferRepeater/BufferRepeaterComponentAc.hpp" + +namespace Svc { + +class BufferRepeater : public BufferRepeaterComponentBase { + public: + /** + * Set of responses to failures to allocate a buffer when requested + */ + enum BufferRepeaterFailureOption { + NO_RESPONSE_ON_OUT_OF_MEMORY, /*!< The component will continue regardless of allocation failures */ + WARNING_ON_OUT_OF_MEMORY, /*!< The component will produce a warning on allocation failures */ + FATAL_ON_OUT_OF_MEMORY, /*!< The component will produce a FATAL on allocation failures */ + NUM_BUFFER_REPEATER_FAILURE_OPTIONS /*!< Maximum value of this setting. Used to mark as uninitialized. */ + }; + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + //! Construct object BufferRepeater + //! + BufferRepeater(const char* const compName /*!< The component name*/ + ); + + //! Initialize object BufferRepeater + //! + void init(const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ + ); + + //! Destroy object BufferRepeater + //! + ~BufferRepeater(); + + /** + * Set the response used when an allocation request fails to produce a buffer. By default this will assert. + * @param allocation_failure_response: set response + */ + void configure(BufferRepeaterFailureOption allocation_failure_response); + + private: + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- + + /** + * Checks the allocation for viability and reports if it fails. + * @param index: index of the port that needs this allocation + * @param new_allocation: new allocation for a copy of the incoming buffer. + * @param incoming_buffer: buffer that is to be cloned + * @return true when the allocation is valid, false otherwise + */ + bool check_allocation(FwIndexType index, const Fw::Buffer& new_allocation, const Fw::Buffer& incoming_buffer); + + private: + // ---------------------------------------------------------------------- + // Handler implementations for user-defined serial input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for portIn + //! + void portIn_handler(NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Buffer& Buffer /*!< The serialization buffer*/ + ); + + BufferRepeaterFailureOption m_allocation_failure_response; //!< Local storage for configured response +}; + +} // end namespace Svc + +#endif diff --git a/Svc/GenericRepeater/CMakeLists.txt b/Svc/BufferRepeater/CMakeLists.txt similarity index 63% rename from Svc/GenericRepeater/CMakeLists.txt rename to Svc/BufferRepeater/CMakeLists.txt index c8295622fa..23cc894018 100644 --- a/Svc/GenericRepeater/CMakeLists.txt +++ b/Svc/BufferRepeater/CMakeLists.txt @@ -6,20 +6,16 @@ # #### set(SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/GenericRepeater.fpp" - "${CMAKE_CURRENT_LIST_DIR}/GenericRepeaterComponentImpl.cpp" + "${CMAKE_CURRENT_LIST_DIR}/BufferRepeater.fpp" + "${CMAKE_CURRENT_LIST_DIR}/BufferRepeater.cpp" ) register_fprime_module() ### UTs ### set(UT_SOURCE_FILES - "${CMAKE_CURRENT_LIST_DIR}/GenericRepeater.fpp" + "${CMAKE_CURRENT_LIST_DIR}/BufferRepeater.fpp" "${CMAKE_CURRENT_LIST_DIR}/test/ut/TestMain.cpp" "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" ) - -set(UT_MOD_DEPS - Fw/Com -) register_fprime_ut() diff --git a/Svc/BufferRepeater/docs/sdd.md b/Svc/BufferRepeater/docs/sdd.md new file mode 100644 index 0000000000..3e859dcc11 --- /dev/null +++ b/Svc/BufferRepeater/docs/sdd.md @@ -0,0 +1,76 @@ +\page SvcBufferRepeaterComponent Svc::BufferRepeater Component +# Svc::BufferRepeater: Buffer Repeater (Passive Component) + +## 1. Introduction + +The BufferRepeater component is designed to take in an `Fw::buffer` port call and repeat it to multiple output ports. +New memory is allocated from a `Svc::BufferManager` and the data is copied to ensure that each downstream component has +full ownership of its data. The original buffer is deallocated. Users call `configure` to set the response of the +component when allocation requests fail. + +## 2. Requirements + +| Name | Description | Validation | +|--------------------|-------------------------------------------------------------------------------|------------| +| BUFFER_REPEATER_01 | The buffer repeater shall accept incoming `Fw::Buffer` port calls | Unit Test | +| BUFFER_REPEATER_02 | The buffer repeater shall copy the incoming data before each repeated send | Unit Test | +| BUFFER_REPEATER_03 | The buffer repeater shall only send a copy to connected components | Unit Test | +| BUFFER_REPEATER_04 | The buffer repeater shall have a configurable response to allocation failures | Unit Test | + +## 3. Design + +The buffer repeater has a single `portIn` port of type `Fw.BufferSend` and an array of `portOut` ports of the same type. +Each port call received on `portIn` is repeated to each connected `portOut` port. These repetitions emit a copy of the +`Fw::Buffer` data. + +## 3.1 Ports + +`Svc::BufferRepeater` has the following ports: + +| Kind | Name | Port Type | Usage | +|--------------|--------------|---------------------------------------------|---------------------------------------| +| `sync input` | `portIn` | `Fw.BufferSend` | Port for receiving initial Fw::Buffer | +| `output` | `portOut` | `[BufferRepeaterOutputPorts] Fw.BufferSend` | Port array for repeating Fw::Buffers | +| `output` | `deallocate` | `Fw.BufferSend` | Deallocate the original buffer | +| `output` | `allocate` | `Fw.BufferGet` | Port for allocating new memory | +| `event` | `Log` | `Fw.Log` | Port for emitting events | +| `text event` | `LogText` | `Fw.LogText` | Port for emitting text events | +| `time get` | `Time` | `Fw.Time` | Port for getting the time | + +#### 3.1.1 portIn handler + +The `portIn` port handler receives an `Fw::Buffer` data type and a port number. For each connected `portOut` port it +allocates new memory large enough to hold a copy of the `Fw::Buffer` data via the `allocate` port, copies the data to +the new invocation, and sends it to the active `portOut` port. This continues until each `portOut` port has been tried +and at the end it returns the original buffer via `deallocate`. + +Should an allocation fail, `portOut` is not called and an event may be emitted (see below). + +### 3.2 Events + +| Name | Description | +|-----------------------|--------------------------------------------------------------------------------------| +| AllocationSoftFailure | WARNING_HI indicating allocation failure when configured to WARNING_ON_OUT_OF_MEMORY | +| AllocationHardFailure | FATAL indicating allocation failure when configured to FATAL_ON_OUT_OF_MEMORY | + +## 4. Configuration + +Buffer repeater maximum output ports are configured using `AcConstants.fpp` as shown below: + +```ini +constant BufferRepeaterOutputPorts = 10 +``` + +The component's response to allocation failures is configured with a call to the configure method during system +initialization. Possible values include: + +| Setting | Description | +|------------------------------|-------------------------------------------------------------------------------| +| NO_RESPONSE_ON_OUT_OF_MEMORY | The component drops the `portOut` call and otherwise takes no response action | +| WARNING_ON_OUT_OF_MEMORY | The component drops the `portOut` call and emits a WARNING_HI event | +| FATAL_ON_OUT_OF_MEMORY | The component drops the `portOut` call and emits a FATAL event | + +```c++ +bufferRepeater.configure(Svc::BufferRepeater::FATAL_ON_OUT_OF_MEMORY); +``` + diff --git a/Svc/BufferRepeater/test/ut/TestMain.cpp b/Svc/BufferRepeater/test/ut/TestMain.cpp new file mode 100644 index 0000000000..106dc86e96 --- /dev/null +++ b/Svc/BufferRepeater/test/ut/TestMain.cpp @@ -0,0 +1,30 @@ +// ---------------------------------------------------------------------- +// TestMain.cpp +// ---------------------------------------------------------------------- + +#include "Tester.hpp" + +TEST(Nominal, TestRepeater) { + Svc::Tester tester; + tester.testRepeater(); +} + +TEST(OffNominal, NoMemoryResponse) { + Svc::Tester tester; + tester.testFailure(Svc::BufferRepeater::NO_RESPONSE_ON_OUT_OF_MEMORY); +} + +TEST(OffNominal, WarningMemoryResponse) { + Svc::Tester tester; + tester.testFailure(Svc::BufferRepeater::WARNING_ON_OUT_OF_MEMORY); +} + +TEST(OffNominal, FatalMemoryResponse) { + Svc::Tester tester; + tester.testFailure(Svc::BufferRepeater::FATAL_ON_OUT_OF_MEMORY); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/Svc/BufferRepeater/test/ut/Tester.cpp b/Svc/BufferRepeater/test/ut/Tester.cpp new file mode 100644 index 0000000000..a65c8acb01 --- /dev/null +++ b/Svc/BufferRepeater/test/ut/Tester.cpp @@ -0,0 +1,166 @@ +// ====================================================================== +// \title BufferRepeater.hpp +// \author lestarch +// \brief cpp file for BufferRepeater test harness implementation class +// ====================================================================== + +#include "Tester.hpp" + +#define INSTANCE 0 +#define MAX_HISTORY_SIZE 10 + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +Tester ::Tester() + : BufferRepeaterGTestBase("Tester", MAX_HISTORY_SIZE), + component("BufferRepeater"), + m_port_index_history(MAX_HISTORY_SIZE), + m_initial_buffer(), + m_failure(false) { + this->initComponents(); + this->connectPorts(); +} + +Tester ::~Tester() {} + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void Tester ::testRepeater() { + this->component.configure(BufferRepeater::FATAL_ON_OUT_OF_MEMORY); + m_initial_buffer.setSize(1024); + m_initial_buffer.setData(new U8[1024]); + for (U32 i = 0; i < m_initial_buffer.getSize(); i++) { + m_initial_buffer.getData()[i] = static_cast(i); + } + + invoke_to_portIn(0, m_initial_buffer); + ASSERT_EVENTS_AllocationHardFailure_SIZE(0); + ASSERT_EVENTS_AllocationSoftFailure_SIZE(0); + ASSERT_from_portOut_SIZE(this->component.getNum_portOut_OutputPorts()); + ASSERT_EQ(fromPortHistory_portOut->size(), this->m_port_index_history.size()); + for (NATIVE_INT_TYPE i = 0; i < this->component.getNum_portOut_OutputPorts(); i++) { + NATIVE_INT_TYPE port_index = this->m_port_index_history.at(i); + ASSERT_EQ(i, port_index); + Fw::Buffer buffer_under_test = this->fromPortHistory_portOut->at(i).fwBuffer; + ASSERT_EQ(buffer_under_test.getSize(), m_initial_buffer.getSize()); + for (U32 j = 0; j < FW_MIN(buffer_under_test.getSize(), m_initial_buffer.getSize()); j++) { + ASSERT_EQ(buffer_under_test.getData()[j], m_initial_buffer.getData()[j]) + << "Data not copied correctly at offset: " << j; + } + // Deallocate allocated data + if (buffer_under_test.getData() != nullptr) { + delete[] buffer_under_test.getData(); + } + } + // Check proper deallocation + ASSERT_from_deallocate_SIZE(1); + ASSERT_EQ(m_initial_buffer.getData(), fromPortHistory_deallocate->at(0).fwBuffer.getData()); + ASSERT_EQ(m_initial_buffer.getSize(), fromPortHistory_deallocate->at(0).fwBuffer.getSize()); + delete[] m_initial_buffer.getData(); + m_initial_buffer.setData(nullptr); +} + +void Tester ::testFailure(BufferRepeater::BufferRepeaterFailureOption failure_option) { + this->m_failure = true; + this->component.configure(failure_option); + m_initial_buffer.setSize(1024); + m_initial_buffer.setData(new U8[1024]); + + invoke_to_portIn(0, m_initial_buffer); + switch (failure_option) { + case BufferRepeater::WARNING_ON_OUT_OF_MEMORY: + ASSERT_EVENTS_AllocationHardFailure_SIZE(0); + ASSERT_EVENTS_AllocationSoftFailure_SIZE(this->component.getNum_portOut_OutputPorts()); + break; + case BufferRepeater::FATAL_ON_OUT_OF_MEMORY: + ASSERT_EVENTS_AllocationHardFailure_SIZE(this->component.getNum_portOut_OutputPorts()); + ASSERT_EVENTS_AllocationSoftFailure_SIZE(0); + break; + // Cascade intended + case BufferRepeater::NO_RESPONSE_ON_OUT_OF_MEMORY: + case BufferRepeater::NUM_BUFFER_REPEATER_FAILURE_OPTIONS: + ASSERT_EVENTS_AllocationHardFailure_SIZE(0); + ASSERT_EVENTS_AllocationSoftFailure_SIZE(0); + break; + } + + ASSERT_from_portOut_SIZE(0); + + // Check proper deallocation + ASSERT_from_deallocate_SIZE(1); + ASSERT_EQ(m_initial_buffer.getData(), fromPortHistory_deallocate->at(0).fwBuffer.getData()); + ASSERT_EQ(m_initial_buffer.getSize(), fromPortHistory_deallocate->at(0).fwBuffer.getSize()); + delete[] m_initial_buffer.getData(); + m_initial_buffer.setData(nullptr); +} + +// ---------------------------------------------------------------------- +// Handlers for typed from ports +// ---------------------------------------------------------------------- + +Fw::Buffer Tester ::from_allocate_handler(const NATIVE_INT_TYPE portNum, U32 size) { + this->pushFromPortEntry_allocate(size); + Fw::Buffer new_buffer; + + if (m_failure) { + new_buffer.setSize(0); + new_buffer.setData(nullptr); + } else { + new_buffer.setSize(size); + new_buffer.setData(new U8[size]); + } + return new_buffer; +} + +void Tester ::from_deallocate_handler(const NATIVE_INT_TYPE portNum, Fw::Buffer& fwBuffer) { + this->pushFromPortEntry_deallocate(fwBuffer); + EXPECT_EQ(fwBuffer.getData(), m_initial_buffer.getData()) << "Deallocated non-initial buffer"; +} + +void Tester ::from_portOut_handler(const NATIVE_INT_TYPE portNum, Fw::Buffer& fwBuffer) { + this->m_port_index_history.push_back(portNum); + this->pushFromPortEntry_portOut(fwBuffer); + EXPECT_NE(fwBuffer.getData(), nullptr) << "Passed invalid buffer out port"; +} + +// ---------------------------------------------------------------------- +// Helper methods +// ---------------------------------------------------------------------- + +void Tester ::connectPorts() { + // portIn + this->connect_to_portIn(0, this->component.get_portIn_InputPort(0)); + + // Log + this->component.set_Log_OutputPort(0, this->get_from_Log(0)); + + // LogText + this->component.set_LogText_OutputPort(0, this->get_from_LogText(0)); + + // Time + this->component.set_Time_OutputPort(0, this->get_from_Time(0)); + + // allocate + this->component.set_allocate_OutputPort(0, this->get_from_allocate(0)); + + // deallocate + this->component.set_deallocate_OutputPort(0, this->get_from_deallocate(0)); + + // portOut + for (NATIVE_INT_TYPE i = 0; i < this->component.getNum_portOut_OutputPorts(); ++i) { + this->component.set_portOut_OutputPort(i, this->get_from_portOut(i)); + } +} + +void Tester ::initComponents() { + this->init(); + this->component.init(INSTANCE); +} + +} // end namespace Svc diff --git a/Svc/BufferRepeater/test/ut/Tester.hpp b/Svc/BufferRepeater/test/ut/Tester.hpp new file mode 100644 index 0000000000..02b3660bc2 --- /dev/null +++ b/Svc/BufferRepeater/test/ut/Tester.hpp @@ -0,0 +1,96 @@ +// ====================================================================== +// \title BufferRepeater/test/ut/Tester.hpp +// \author lestarch +// \brief hpp file for GenericRepeater test harness implementation class +// +// \copyright +// Copyright 2009-2015, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#ifndef TESTER_HPP +#define TESTER_HPP + +#include "GTestBase.hpp" +#include "Svc/BufferRepeater/BufferRepeater.hpp" + +namespace Svc { + +class Tester : public BufferRepeaterGTestBase { + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + public: + //! Construct object Tester + //! + Tester(); + + //! Destroy object Tester + //! + ~Tester(); + + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! Test the repeating capability of the buffer + //! + void testRepeater(); + + //! Test the repeating capability of the buffer + //! + void testFailure(BufferRepeater::BufferRepeaterFailureOption failure_option); + + private: + // ---------------------------------------------------------------------- + // Handlers for serial from ports + // ---------------------------------------------------------------------- + + //! Handler for from_allocate + //! + Fw::Buffer from_allocate_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + U32 size); + + //! Handler for from_deallocate + //! + void from_deallocate_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Buffer& fwBuffer); + + //! Handler for from_portOut + //! + void from_portOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Buffer& fwBuffer); + + private: + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + //! Connect ports + //! + void connectPorts(); + + //! Initialize components + //! + void initComponents(); + + private: + // ---------------------------------------------------------------------- + // Variables + // ---------------------------------------------------------------------- + + //! The component under test + //! + BufferRepeater component; + History m_port_index_history; + Fw::Buffer m_initial_buffer; + bool m_failure; +}; + +} // end namespace Svc + +#endif diff --git a/Svc/CMakeLists.txt b/Svc/CMakeLists.txt index f3edc204d9..d06bcca1ce 100644 --- a/Svc/CMakeLists.txt +++ b/Svc/CMakeLists.txt @@ -15,8 +15,11 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ActiveRateGroup/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/AssertFatalAdapter/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/BufferManager/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/BufferLogger/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/BufferRepeater/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComLogger/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComQueue/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComSplitter/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ComStub/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CmdDispatcher/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/CmdSequencer/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Deframer/") @@ -26,7 +29,6 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileDownlink/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileManager/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FileUplink/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/GenericHub/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/GenericRepeater/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/GroundInterface/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Framer/") add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/FramingProtocol/") diff --git a/Svc/CmdDispatcher/CMakeLists.txt b/Svc/CmdDispatcher/CMakeLists.txt index bb7efe2fca..6820e752a5 100644 --- a/Svc/CmdDispatcher/CMakeLists.txt +++ b/Svc/CmdDispatcher/CMakeLists.txt @@ -2,7 +2,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/CmdDispatcher/docs/img/CommandDispatch.jpg b/Svc/CmdDispatcher/docs/img/CommandDispatch.jpg deleted file mode 100644 index c530be9891..0000000000 Binary files a/Svc/CmdDispatcher/docs/img/CommandDispatch.jpg and /dev/null differ diff --git a/Svc/CmdDispatcher/docs/img/CommandRegistration.jpg b/Svc/CmdDispatcher/docs/img/CommandRegistration.jpg deleted file mode 100644 index 259e25164e..0000000000 Binary files a/Svc/CmdDispatcher/docs/img/CommandRegistration.jpg and /dev/null differ diff --git a/Svc/CmdDispatcher/docs/sdd.md b/Svc/CmdDispatcher/docs/sdd.md index eee5adbb3c..8147d5d4ba 100644 --- a/Svc/CmdDispatcher/docs/sdd.md +++ b/Svc/CmdDispatcher/docs/sdd.md @@ -56,13 +56,40 @@ When the command dispatcher receives a command buffer, it decodes the opcode. It The `Svc::CmdDispatcher` component accepts command registration from other components: -![Command Registration](img/CommandRegistration.jpg) +```mermaid +sequenceDiagram + Initialization->>Component: get_ComdReg_InputPort() + activate Initialization + deactivate Initialization + activate Component + deactivate Component + Initialization->>Component: regCommands() + activate Initialization + activate Component + loop for each opcode + Component->>CommandDispatcher: cmdReg() + end + deactivate Initialization + deactivate Component +``` #### 3.3.1 Dispatch Commands The `Svc::CmdDispatcher` component dispatches commands to other components: -![Command Dispatch](img/CommandDispatch.jpg) +```mermaid +sequenceDiagram + Command Buffer Source->>CommandDispatcher: cmdBuff() + activate Command Buffer Source + activate CommandDispatcher + CommandDispatcher->>Component: cmdBuff() + activate Component + Component->>CommandDispatcher: comStat() + deactivate Component + CommandDispatcher->>Command Buffer Source: seqStatus() + deactivate CommandDispatcher + deactivate Command Buffer Source +``` ### 3.4 State diff --git a/Svc/CmdSequencer/CMakeLists.txt b/Svc/CmdSequencer/CMakeLists.txt index 697a30b516..24d803b86a 100644 --- a/Svc/CmdSequencer/CMakeLists.txt +++ b/Svc/CmdSequencer/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/CmdSequencer/docs/sdd.md b/Svc/CmdSequencer/docs/sdd.md index ef85342ddf..b7262b74e6 100644 --- a/Svc/CmdSequencer/docs/sdd.md +++ b/Svc/CmdSequencer/docs/sdd.md @@ -43,7 +43,7 @@ pingIn|Svc::Ping|async input|Input ping call pingOut|Svc::Ping|output|Reply for ping schedIn|Svc::Sched|async input|Scheduler input - timed commands will be checked comCmdOut|Fw::Com|output|Sends command buffers for each command in sequence -cmdResponseIn|Fw::CmdResponse|asyc input|Received status of last dispatched command +cmdResponseIn|Fw::CmdResponse|async input|Received status of last dispatched command seqRunIn|Svc::CmdSeqIn|async input|Receives requests for running sequences from other components seqDone|Fw::CmdResponse|output|outputs status of sequence run; meant to be used with `seqRunIn` diff --git a/Svc/CmdSequencer/formats/AMPCSSequence.cpp b/Svc/CmdSequencer/formats/AMPCSSequence.cpp index 31d9e29f92..5b39715501 100644 --- a/Svc/CmdSequencer/formats/AMPCSSequence.cpp +++ b/Svc/CmdSequencer/formats/AMPCSSequence.cpp @@ -80,20 +80,23 @@ namespace Svc { getFileSize(const Fw::CmdStringArg& seqFileName) { bool status = true; - U64 fileSize; + FwSizeType fileSize; this->setFileName(seqFileName); const Os::FileSystem::Status fileStatus = Os::FileSystem::getFileSize(this->m_fileName.toChar(), fileSize); + // fileSize will be used to set a U32 member below, thus we check overflow first + bool overflow = static_cast(static_cast(fileSize)) != fileSize; if ( fileStatus == Os::FileSystem::OP_OK and - fileSize >= sizeof(this->m_sequenceHeader) + fileSize >= sizeof(this->m_sequenceHeader) and + !overflow ) { this->m_header.m_fileSize = static_cast(fileSize - sizeof(this->m_sequenceHeader)); } else { this->m_events.fileInvalid( CmdSequencer_FileReadStage::READ_HEADER_SIZE, - fileStatus + overflow ? Os::FileSystem::OTHER_ERROR : fileStatus ); status = false; } diff --git a/Svc/CmdSequencer/test/ut/SequenceFiles/File.hpp b/Svc/CmdSequencer/test/ut/SequenceFiles/File.hpp index 9d3c9bc365..63b1ddb52e 100644 --- a/Svc/CmdSequencer/test/ut/SequenceFiles/File.hpp +++ b/Svc/CmdSequencer/test/ut/SequenceFiles/File.hpp @@ -75,7 +75,7 @@ namespace Svc { //! Open errors Open open; - //! Heade read errors + //! Header read errors HeaderRead headerRead; //! Data read errors diff --git a/Svc/ComLogger/CMakeLists.txt b/Svc/ComLogger/CMakeLists.txt index f4b10998e1..7bc4413faa 100644 --- a/Svc/ComLogger/CMakeLists.txt +++ b/Svc/ComLogger/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/ComLogger/ComLogger.cpp b/Svc/ComLogger/ComLogger.cpp index dcd94cd244..af1d27f621 100644 --- a/Svc/ComLogger/ComLogger.cpp +++ b/Svc/ComLogger/ComLogger.cpp @@ -5,7 +5,7 @@ // ---------------------------------------------------------------------- #include -#include +#include #include #include #include @@ -31,7 +31,7 @@ namespace Svc { FW_ASSERT(maxFileSize > sizeof(U16), maxFileSize); // must be a positive integer greater than buffer length size } else { - FW_ASSERT(maxFileSize > sizeof(0), maxFileSize); // must be a positive integer + FW_ASSERT(maxFileSize > 0, maxFileSize); // must be a positive integer } FW_ASSERT(Fw::StringUtils::string_length(incomingFilePrefix, sizeof(this->filePrefix)) < sizeof(this->filePrefix), Fw::StringUtils::string_length(incomingFilePrefix, sizeof(this->filePrefix)), sizeof(this->filePrefix)); // ensure that file prefix is not too big @@ -147,16 +147,16 @@ namespace Svc { // Create filename: Fw::Time timestamp = getTime(); memset(this->fileName, 0, sizeof(this->fileName)); - bytesCopied = snprintf(this->fileName, sizeof(this->fileName), "%s_%d_%d_%06d.com", - this->filePrefix, static_cast(timestamp.getTimeBase()), timestamp.getSeconds(), timestamp.getUSeconds()); + bytesCopied = snprintf(this->fileName, sizeof(this->fileName), "%s_%" PRI_FwTimeBaseStoreType "_%" PRIu32 "_%06" PRIu32 ".com", + this->filePrefix, static_cast(timestamp.getTimeBase()), timestamp.getSeconds(), timestamp.getUSeconds()); // "A return value of size or more means that the output was truncated" // See here: http://linux.die.net/man/3/snprintf FW_ASSERT( bytesCopied < sizeof(this->fileName) ); // Create sha filename: - bytesCopied = snprintf(this->hashFileName, sizeof(this->hashFileName), "%s_%d_%d_%06d.com%s", - this->filePrefix, static_cast(timestamp.getTimeBase()), timestamp.getSeconds(), timestamp.getUSeconds(), Utils::Hash::getFileExtensionString()); + bytesCopied = snprintf(this->hashFileName, sizeof(this->hashFileName), "%s_%" PRI_FwTimeBaseStoreType "_%" PRIu32 "_%06" PRIu32 ".com%s", + this->filePrefix, static_cast(timestamp.getTimeBase()), timestamp.getSeconds(), timestamp.getUSeconds(), Utils::Hash::getFileExtensionString()); FW_ASSERT( bytesCopied < sizeof(this->hashFileName) ); Os::File::Status ret = file.open(this->fileName, Os::File::OPEN_WRITE); diff --git a/Svc/ComLogger/ComLogger.hpp b/Svc/ComLogger/ComLogger.hpp index 1f0afc99ba..248efebd47 100644 --- a/Svc/ComLogger/ComLogger.hpp +++ b/Svc/ComLogger/ComLogger.hpp @@ -24,6 +24,13 @@ #define COMLOGGER_PATH_MAX 255 #endif +// some limits.h don't have NAME_MAX +#ifdef NAME_MAX +#define COMLOGGER_NAME_MAX NAME_MAX +#else +#define COMLOGGER_NAME_MAX 255 +#endif + namespace Svc { class ComLogger : @@ -81,7 +88,7 @@ namespace Svc { // ---------------------------------------------------------------------- // The maximum size of a filename enum { - MAX_FILENAME_SIZE = NAME_MAX, // as defined in limits.h + MAX_FILENAME_SIZE = COMLOGGER_NAME_MAX, MAX_PATH_SIZE = COMLOGGER_PATH_MAX }; diff --git a/Svc/ComLogger/test/ut/Tester.cpp b/Svc/ComLogger/test/ut/Tester.cpp index b45a380452..18020874ee 100644 --- a/Svc/ComLogger/test/ut/Tester.cpp +++ b/Svc/ComLogger/test/ut/Tester.cpp @@ -136,7 +136,7 @@ namespace Svc { // Make sure the file size is smaller or equal to the limit: Os::FileSystem::Status fsStat; - U64 fileSize = 0; + FwSizeType fileSize = 0; fsStat = Os::FileSystem::getFileSize(fileName, fileSize); //!< gets the size of the file (in bytes) at location path ASSERT_EQ(fsStat, Os::FileSystem::OP_OK); ASSERT_LE(fileSize, MAX_BYTES_PER_FILE); @@ -259,7 +259,7 @@ namespace Svc { // Make sure the file size is smaller or equal to the limit: Os::FileSystem::Status fsStat; - U64 fileSize = 0; + FwSizeType fileSize = 0; fsStat = Os::FileSystem::getFileSize(fileName, fileSize); //!< gets the size of the file (in bytes) at location path ASSERT_EQ(fsStat, Os::FileSystem::OP_OK); ASSERT_LE(fileSize, MAX_BYTES_PER_FILE); diff --git a/Svc/ComQueue/CMakeLists.txt b/Svc/ComQueue/CMakeLists.txt new file mode 100644 index 0000000000..b6b01756f6 --- /dev/null +++ b/Svc/ComQueue/CMakeLists.txt @@ -0,0 +1,26 @@ +#### +# F prime CMakeLists.txt: +# +# SOURCE_FILES: combined list of source and autocoding diles +# MOD_DEPS: (optional) module dependencies +# +# Note: using PROJECT_NAME as EXECUTABLE_NAME +#### +set(MOD_DEPS + Utils/Types + Fw/Buffer + Fw/Types + ) +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/ComQueue.fpp" + "${CMAKE_CURRENT_LIST_DIR}/ComQueue.cpp" + ) +register_fprime_module() + +### UTs ### +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/ComQueue.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/TestMain.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" + ) +register_fprime_ut() diff --git a/Svc/ComQueue/ComQueue.cpp b/Svc/ComQueue/ComQueue.cpp new file mode 100644 index 0000000000..7ddf34f3a2 --- /dev/null +++ b/Svc/ComQueue/ComQueue.cpp @@ -0,0 +1,259 @@ +// ====================================================================== +// \title ComQueue.cpp +// \author vbai +// \brief cpp file for ComQueue component implementation class +// ====================================================================== + +#include +#include +#include "Fw/Types/BasicTypes.hpp" + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction, initialization, and destruction +// ---------------------------------------------------------------------- + +ComQueue ::QueueConfigurationTable ::QueueConfigurationTable() { + for (NATIVE_UINT_TYPE i = 0; i < FW_NUM_ARRAY_ELEMENTS(this->entries); i++) { + this->entries[i].priority = 0; + this->entries[i].depth = 0; + } +} + +ComQueue ::ComQueue(const char* const compName) + : ComQueueComponentBase(compName), + m_state(WAITING), + m_allocationId(-1), + m_allocator(nullptr), + m_allocation(nullptr) { + // Initialize throttles to "off" + for (NATIVE_UINT_TYPE i = 0; i < TOTAL_PORT_COUNT; i++) { + this->m_throttle[i] = false; + } +} + +ComQueue ::~ComQueue() {} + +void ComQueue ::init(const NATIVE_INT_TYPE queueDepth, const NATIVE_INT_TYPE instance) { + ComQueueComponentBase::init(queueDepth, instance); +} + +void ComQueue ::cleanup() { + // Deallocate memory ignoring error conditions + if ((this->m_allocator != nullptr) && (this->m_allocation != nullptr)) { + this->m_allocator->deallocate(this->m_allocationId, this->m_allocation); + } +} + +void ComQueue::configure(QueueConfigurationTable queueConfig, + NATIVE_UINT_TYPE allocationId, + Fw::MemAllocator& allocator) { + FwIndexType currentPriorityIndex = 0; + NATIVE_UINT_TYPE totalAllocation = 0; + + // Store/initialize allocator members + this->m_allocator = &allocator; + this->m_allocationId = allocationId; + this->m_allocation = nullptr; + + // Initializes the sorted queue metadata list in priority (sorted) order. This is accomplished by walking the + // priority values in priority order from 0 to TOTAL_PORT_COUNT. At each priory value, the supplied queue + // configuration table is walked and any entry matching the current priority values is used to add queue metadata to + // the prioritized list. This results in priority-sorted queue metadata objects that index back into the unsorted + // queue data structures. + // + // The total allocation size is tracked for passing to the allocation call and is a summation of + // (depth * message size) for each prioritized metadata object of (depth * message size) + for (FwIndexType currentPriority = 0; currentPriority < TOTAL_PORT_COUNT; currentPriority++) { + // Walk each queue configuration entry and add them into the prioritized metadata list when matching the current + // priority value + for (NATIVE_UINT_TYPE entryIndex = 0; entryIndex < FW_NUM_ARRAY_ELEMENTS(queueConfig.entries); entryIndex++) { + // Check for valid configuration entry + FW_ASSERT(queueConfig.entries[entryIndex].priority < TOTAL_PORT_COUNT, + queueConfig.entries[entryIndex].priority, TOTAL_PORT_COUNT, entryIndex); + + if (currentPriority == queueConfig.entries[entryIndex].priority) { + // Set up the queue metadata object in order to track priority, depth, index into the queue list of the + // backing queue object, and message size. Both index and message size are calculated where priority and + // depth are copied from the configuration object. + QueueMetadata& entry = this->m_prioritizedList[currentPriorityIndex]; + entry.priority = queueConfig.entries[entryIndex].priority; + entry.depth = queueConfig.entries[entryIndex].depth; + entry.index = entryIndex; + // Message size is determined by the type of object being stored, which in turn is determined by the + // index of the entry. Those lower than COM_PORT_COUNT are Fw::ComBuffers and those larger Fw::Buffer. + entry.msgSize = (entryIndex < COM_PORT_COUNT) ? sizeof(Fw::ComBuffer) : sizeof(Fw::Buffer); + totalAllocation += entry.depth * entry.msgSize; + currentPriorityIndex++; + } + } + } + // Allocate a single chunk of memory from the memory allocator. Memory recover is neither needed nor used. + bool recoverable = false; + this->m_allocation = this->m_allocator->allocate(this->m_allocationId, totalAllocation, recoverable); + + // Each of the backing queue objects must be supplied memory to store the queued messages. These data regions are + // sub-portions of the total allocated data. This memory is passed out by looping through each queue in prioritized + // order and passing out the memory to each queue's setup method. + FwSizeType allocationOffset = 0; + for (FwIndexType i = 0; i < TOTAL_PORT_COUNT; i++) { + // Get current queue's allocation size and safety check the values + FwSizeType allocationSize = this->m_prioritizedList[i].depth * this->m_prioritizedList[i].msgSize; + FW_ASSERT(this->m_prioritizedList[i].index < static_cast(FW_NUM_ARRAY_ELEMENTS(this->m_queues)), + this->m_prioritizedList[i].index); + FW_ASSERT((allocationSize + allocationOffset) <= totalAllocation, allocationSize, allocationOffset, + totalAllocation); + + // Setup queue's memory allocation, depth, and message size. Setup is skipped for a depth 0 queue + if (allocationSize > 0) { + this->m_queues[this->m_prioritizedList[i].index].setup( + reinterpret_cast(this->m_allocation) + allocationOffset, allocationSize, + this->m_prioritizedList[i].depth, this->m_prioritizedList[i].msgSize); + } + allocationOffset += allocationSize; + } + // Safety check that all memory was used as expected + FW_ASSERT(allocationOffset == totalAllocation, allocationOffset, totalAllocation); +} +// ---------------------------------------------------------------------- +// Handler implementations for user-defined typed input ports +// ---------------------------------------------------------------------- + +void ComQueue::comQueueIn_handler(const NATIVE_INT_TYPE portNum, Fw::ComBuffer& data, U32 context) { + // Ensure that the port number of comQueueIn is consistent with the expectation + FW_ASSERT(portNum >= 0 && portNum < COM_PORT_COUNT, portNum); + this->enqueue(portNum, QueueType::COM_QUEUE, reinterpret_cast(&data), sizeof(Fw::ComBuffer)); +} + +void ComQueue::buffQueueIn_handler(const NATIVE_INT_TYPE portNum, Fw::Buffer& fwBuffer) { + const NATIVE_INT_TYPE queueNum = portNum + COM_PORT_COUNT; + // Ensure that the port number of buffQueueIn is consistent with the expectation + FW_ASSERT(portNum >= 0 && portNum < BUFFER_PORT_COUNT, portNum); + FW_ASSERT(queueNum < TOTAL_PORT_COUNT); + this->enqueue(queueNum, QueueType::BUFFER_QUEUE, reinterpret_cast(&fwBuffer), sizeof(Fw::Buffer)); +} + +void ComQueue::comStatusIn_handler(const NATIVE_INT_TYPE portNum, Fw::Success& condition) { + switch (this->m_state) { + // On success, the queue should be processed. On failure, the component should still wait. + case WAITING: + if (condition.e == Fw::Success::SUCCESS) { + this->m_state = READY; + this->processQueue(); + // A message may or may not be sent. Thus, READY or WAITING are acceptable final states. + FW_ASSERT((this->m_state == WAITING || this->m_state == READY), this->m_state); + } else { + this->m_state = WAITING; + } + break; + // Both READY and unknown states should not be possible at this point. To receive a status message we must be + // one of the WAITING or RETRY states. + default: + FW_ASSERT(0, this->m_state); + break; + } +} + +void ComQueue::run_handler(const NATIVE_INT_TYPE portNum, NATIVE_UINT_TYPE context) { + // Downlink the high-water marks for the Fw::ComBuffer array types + ComQueueDepth comQueueDepth; + for (FwSizeType i = 0; i < comQueueDepth.SIZE; i++) { + comQueueDepth[i] = this->m_queues[i].get_high_water_mark(); + this->m_queues[i].clear_high_water_mark(); + } + this->tlmWrite_comQueueDepth(comQueueDepth); + + // Downlink the high-water marks for the Fw::Buffer array types + BuffQueueDepth buffQueueDepth; + for (FwSizeType i = 0; i < buffQueueDepth.SIZE; i++) { + buffQueueDepth[i] = this->m_queues[i + COM_PORT_COUNT].get_high_water_mark(); + this->m_queues[i + COM_PORT_COUNT].clear_high_water_mark(); + } + this->tlmWrite_buffQueueDepth(buffQueueDepth); +} + +// ---------------------------------------------------------------------- +// Private helper methods +// ---------------------------------------------------------------------- + +void ComQueue::enqueue(const FwIndexType queueNum, QueueType queueType, const U8* data, const FwSizeType size) { + // Enqueue the given message onto the matching queue. When no space is available then emit the queue overflow event, + // set the appropriate throttle, and move on. Will assert if passed a message for a depth 0 queue. + const FwSizeType expectedSize = (queueType == QueueType::COM_QUEUE) ? sizeof(Fw::ComBuffer) : sizeof(Fw::Buffer); + const FwIndexType portNum = queueNum - ((queueType == QueueType::COM_QUEUE) ? 0 : COM_PORT_COUNT); + FW_ASSERT(expectedSize == size, size, expectedSize); + FW_ASSERT(portNum >= 0, portNum); + Fw::SerializeStatus status = this->m_queues[queueNum].enqueue(data, size); + if (status == Fw::FW_SERIALIZE_NO_ROOM_LEFT && !this->m_throttle[queueNum]) { + this->log_WARNING_HI_QueueOverflow(queueType, portNum); + this->m_throttle[queueNum] = true; + } + // When the component is already in READY state process the queue to send out the next available message immediately + if (this->m_state == READY) { + this->processQueue(); + } +} + +void ComQueue::sendComBuffer(Fw::ComBuffer& comBuffer) { + FW_ASSERT(this->m_state == READY); + this->comQueueSend_out(0, comBuffer, 0); + this->m_state = WAITING; +} + +void ComQueue::sendBuffer(Fw::Buffer& buffer) { + // Retry buffer expected to be cleared as we are either transferring ownership or have already deallocated it. + FW_ASSERT(this->m_state == READY); + this->buffQueueSend_out(0, buffer); + this->m_state = WAITING; +} + +void ComQueue::processQueue() { + FwIndexType priorityIndex = 0; + FwIndexType sendPriority = 0; + // Check that we are in the appropriate state + FW_ASSERT(this->m_state == READY); + + // Walk all the queues in priority order. Send the first message that is available in priority order. No balancing + // is done within this loop. + for (priorityIndex = 0; priorityIndex < TOTAL_PORT_COUNT; priorityIndex++) { + QueueMetadata& entry = this->m_prioritizedList[priorityIndex]; + Types::Queue& queue = this->m_queues[entry.index]; + + // Continue onto next prioritized queue if there is no items in the current queue + if (queue.getQueueSize() == 0) { + continue; + } + + // Send out the message based on the type + if (entry.index < COM_PORT_COUNT) { + Fw::ComBuffer comBuffer; + queue.dequeue(reinterpret_cast(&comBuffer), sizeof(comBuffer)); + this->sendComBuffer(comBuffer); + } else { + Fw::Buffer buffer; + queue.dequeue(reinterpret_cast(&buffer), sizeof(buffer)); + this->sendBuffer(buffer); + } + + // Update the throttle and the index that was just sent + this->m_throttle[entry.index] = false; + + // Priority used in the next loop + sendPriority = entry.priority; + break; + } + + // Starting on the priority entry after the one dispatched and continuing through the end of the set of entries that + // share the same priority, rotate those entries such that the currently dispatched queue is last and the rest are + // shifted up by one. This effectively round-robins the queues of the same priority. + for (priorityIndex++; + priorityIndex < TOTAL_PORT_COUNT && (this->m_prioritizedList[priorityIndex].priority == sendPriority); + priorityIndex++) { + // Swap the previous entry with this one. + QueueMetadata temp = this->m_prioritizedList[priorityIndex]; + this->m_prioritizedList[priorityIndex] = this->m_prioritizedList[priorityIndex - 1]; + this->m_prioritizedList[priorityIndex - 1] = temp; + } +} +} // end namespace Svc diff --git a/Svc/ComQueue/ComQueue.fpp b/Svc/ComQueue/ComQueue.fpp new file mode 100644 index 0000000000..43cda64368 --- /dev/null +++ b/Svc/ComQueue/ComQueue.fpp @@ -0,0 +1,75 @@ +module Svc { + @ An enumeration of queue data types + enum QueueType { COM_QUEUE, BUFFER_QUEUE } + + @ Array of queue depths for Fw::Com types + array ComQueueDepth = [ComQueueComPorts] U32 + + @ Array of queue depths for Fw::Buffer types + array BuffQueueDepth = [ComQueueBufferPorts] U32 + + + @ Component used to queue buffer types + active component ComQueue { + + # ---------------------------------------------------------------------- + # General ports + # ---------------------------------------------------------------------- + + @ Fw::ComBuffer output port + output port comQueueSend: Fw.Com + + @ Fw::Buffer output port + output port buffQueueSend: Fw.BufferSend + + @ Port for receiving the status signal + async input port comStatusIn: Fw.SuccessCondition + + @ Port array for receiving Fw::ComBuffers + async input port comQueueIn: [ComQueueComPorts] Fw.Com drop + + @ Port array for receiving Fw::Buffers + async input port buffQueueIn: [ComQueueBufferPorts] Fw.BufferSend drop + + @ Port for scheduling telemetry output + async input port run: Svc.Sched drop + + # ---------------------------------------------------------------------- + # Special ports + # ---------------------------------------------------------------------- + + @ Port for emitting events + event port Log + + @ Port for emitting text events + text event port LogText + + @ Port for getting the time + time get port Time + + @ Port for emitting telemetry + telemetry port Tlm + + # ---------------------------------------------------------------------- + # Events + # ---------------------------------------------------------------------- + + @ Queue overflow event + event QueueOverflow( + queueType: QueueType @< The Queue data type + index: U32 @< index of overflowed queue + ) \ + severity warning high \ + format "The {} queue at index {} overflowed" + + # ---------------------------------------------------------------------- + # Telemetry + # ---------------------------------------------------------------------- + + @ Depth of queues of Fw::ComBuffer type + telemetry comQueueDepth: ComQueueDepth id 0 + + @ Depth of queues of Fw::Buffer type + telemetry buffQueueDepth: BuffQueueDepth id 1 + } +} diff --git a/Svc/ComQueue/ComQueue.hpp b/Svc/ComQueue/ComQueue.hpp new file mode 100644 index 0000000000..2888bd1e7e --- /dev/null +++ b/Svc/ComQueue/ComQueue.hpp @@ -0,0 +1,195 @@ +// ====================================================================== +// \title ComQueue.hpp +// \author vbai +// \brief hpp file for ComQueue component implementation class +// ====================================================================== + +#ifndef Svc_ComQueue_HPP +#define Svc_ComQueue_HPP + +#include +#include +#include +#include +#include "Fw/Types/MemAllocator.hpp" +#include "Os/Mutex.hpp" + +namespace Svc { + +// ---------------------------------------------------------------------- +// Types +// ---------------------------------------------------------------------- + +class ComQueue : public ComQueueComponentBase { + public: + //!< Count of Fw::Com input ports and thus Fw::Com queues + static const FwIndexType COM_PORT_COUNT = ComQueueComponentBase::NUM_COMQUEUEIN_INPUT_PORTS; + + //!< Count of Fw::Buffer input ports and thus Fw::Buffer queues + static const FwIndexType BUFFER_PORT_COUNT = ComQueueComponentBase::NUM_BUFFQUEUEIN_INPUT_PORTS; + + //!< Total count of input buffer ports and thus total queues + static const FwIndexType TOTAL_PORT_COUNT = COM_PORT_COUNT + BUFFER_PORT_COUNT; + + /** + * \brief configuration data for each queue + * + * Each queue must be configured to specify the depth of the queue and the priority of the queue. Depth must be a + * non-negative integer indicating the number of messages before overflow. A depth of 0 disables the given queue and + * any message sent to it will overflow. + * + * Priority is an integer between 0 (inclusive) and TOTAL_PORT_COUNT (exclusive). Queues with lower priority values + * will be serviced first. Priorities may be repeated and queues sharing priorities will be serviced in a balanced + * manner. + */ + struct QueueConfigurationEntry { + FwSizeType depth; //!< Depth of the queue [0, infinity) + FwIndexType priority; //!< Priority of the queue [0, TOTAL_PORT_COUNT) + }; + + /** + * \brief configuration table for each queue + * + * This table should be filled-out and passed to the configure method of this component. It represents the + * port-by-port configuration information for the associated queue. Each entry specifies the queue's depth and + * priority. + * + * Entries are specified in-order first addressing Fw::Com ports then Fw::Buffer ports. + */ + struct QueueConfigurationTable { + QueueConfigurationEntry entries[TOTAL_PORT_COUNT]; + /** + * \brief constructs a basic un-prioritized table with depth 0 + */ + QueueConfigurationTable(); + }; + + private: + // ---------------------------------------------------------------------- + // Internal data structures + // ---------------------------------------------------------------------- + + /** + * Storage for internal queue metadata. This is stored in the prioritized list and contains indices to the the + * un-prioritized queue objects. Depth and priority is copied from the configuration supplied by the configure + * method. Index and message size are calculated by the configuration call. + */ + struct QueueMetadata { + FwSizeType depth; //!< Depth of the queue in messages + FwIndexType priority; //!< Priority of the queue + FwIndexType index; //!< Index of this queue in the prioritized list + FwSizeType msgSize; //!< Message size of messages in this queue + }; + + /** + * State of the component. + */ + enum SendState { + READY, //!< Component is ready to send next priority message + WAITING //!< Component is waiting for status of the last sent message + }; + + public: + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + //! Construct object ComQueue + //! + ComQueue(const char* const compName /*!< The component name */ + ); + + //! Initialize object ComQueue + //! + void init(const NATIVE_INT_TYPE queueDepth, /*!< The queue depth */ + const NATIVE_INT_TYPE instance = 0 /*!< The instance number */ + ); + + //! Destroy object ComQueue + //! + ~ComQueue(); + + //! Configure the queue depths, priorities, and memory allocation for the component + //! + //! Takes in the queue depth and priority per-port in order from Fw::Com through Fw::Buffer ports. Calculates the + //! queue metadata stored `m_prioritizedList` and then sorts that list by priority. + void configure(QueueConfigurationTable queueConfig, //!< Table of the configuration properties for the component + NATIVE_UINT_TYPE allocationId, //!< Identifier used when dealing with the Fw::MemAllocator + Fw::MemAllocator& allocator //!< Fw::MemAllocator used to acquire memory + ); + + //! Deallocate resources and cleanup ComQueue + //! + void cleanup(); + + private: + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Receive and queue a Fw::Buffer + //! + void buffQueueIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Buffer& fwBuffer /*!< Buffer containing packet data*/); + + //! Receive and queue a Fw::ComBuffer + //! + void comQueueIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::ComBuffer& data, /*!< Buffer containing packet data*/ + U32 context /*!< Call context value; meaning chosen by user*/ + ); + + //! Handle the status of the last sent message + //! + void comStatusIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Success& condition /*!> +' If/choice check for queue availability +state queue_check <> + +' State definitions to capture self transitions +state WAITING: Buffer Received / Queue Buffer + +[*] -down-> WAITING +' Status In transitions +WAITING -down-> status_check: Status In +status_check -right-> queue_check: [SUCCESS] +status_check -up-> WAITING: [FAILURE] + +queue_check -up-> WAITING: [Buffer Queued] / Send Buffer +queue_check -right-> READY: [No Buffer Queued] +READY -up-> WAITING: Buffer Received / Send Buffer +@enduml + diff --git a/Svc/ComQueue/docs/sdd.md b/Svc/ComQueue/docs/sdd.md new file mode 100644 index 0000000000..8dce9969f2 --- /dev/null +++ b/Svc/ComQueue/docs/sdd.md @@ -0,0 +1,167 @@ +\page SvcComQueueComponent Svc::ComQueue Component +# Svc::ComQueue (Active Component) + +## 1. Introduction + +`Svc::ComQueue` is an F´ active component that functions as a priority queue of buffer types. Messages are dequeued and +forwarded when a `Fw::Success::SUCCESS` signal is received in order of priority. `Fw::Success::FAILURE` signals result +in the queues being paused until a following `Fw::Success::SUCCESS` signal. + +`Svc::ComQueue` is configured with a queue depth and queue priority for each incoming `Fw::Com` and `Fw::Buffer` port by +passing in a configuration table at initialization. Queued messages from the highest priority source port are serviced +first and a round-robin algorithm is used to balance between ports of shared priority. + +`Svc::ComQueue` is designed to act alongside instances of the +[communication adapter interface](https://nasa.github.io/fprime/Design/communication-adapter-interface.html) and +implements the communication queue +[protocol](https://nasa.github.io/fprime/Design/communication-adapter-interface.html#communication-queue-protocol). + +## 2. Assumptions + +1. Incoming buffers to a given port are in priority order +2. Data is considered to be successfully sent when a `Fw::Success::SUCCESS` signal was received +3. The com adapter is responsible for any retransmission of failed data +4. The system includes downstream components implementing the + [communications adapter](https://nasa.github.io/fprime/Design/communication-adapter-interface.html) + + +## 3. Requirements + + +| Requirement | Description | Rationale | Verification Method | +|------------------|-----------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------|---------------------| +| SVC-COMQUEUE-001 | `Svc::ComQueue` shall queue `Fw::Buffer` and `Fw::ComBuffer` received on incoming ports. | The purpose of the queue is to store messages. | Unit Test | +| SVC-COMQUEUE-002 | `Svc::ComQueue` shall output exactly one `Fw::Buffer` or `Fw::ComBuffer` message on a received `Fw::Success::SUCCESS` signal. | `Svc::ComQueue` obeys the communication adapter interface protocol. | Unit Test | +| SVC-COMQUEUE-003 | `Svc::ComQueue` shall pause sending on the `Fw::Success::FAILURE` and restart on the next `Fw::Success::SUCCESS` signal. | `Svc::ComQueue` should not sent to a failing communication adapter. | Unit Test | +| SVC-COMQUEUE-004 | `Svc::ComQueue` shall have a configurable number of `Fw::Com` and `Fw::Buffer` input ports. | `Svc::ComQueue` should be adaptable for a number of projects. | Inspection | +| SVC-COMQUEUE-005 | `Svc::ComQueue` shall select and send the next priority `Fw::Buffer` and `Fw::ComBuffer` message in response to `Fw::Success::SUCCESS`. | `Svc::ComQueue` obeys the communication adapter interface protocol. | Unit test | +| SVC-COMQUEUE-006 | `Svc::ComQueue` shall periodically telemeter the number of queued messages per-port in response to a `run` port invocation. | `Svc::ComQueue` should provide useful telemetry. | Unit Test | +| SVC-COMQUEUE-007 | `Svc::ComQueue` shall emit a queue overflow event for a given port when the configured depth is exceeded. Messages shall be discarded. | `Svc::ComQueue` needs to indicate off-nominal events. | Unit Test | +| SVC-COMQUEUE-008 | `Svc::ComQueue` shall implement a round robin approach to balance between ports of the same priority. | Allows projects to balance between a set of queues of similar priority. | Unit Test | +| SVC-COMQUEUE-009 | `Svc::ComQueue` shall keep track and throttle queue overflow events per port. | Prevents a flood of queue overflow events. | Unit test | + +## 4. Design +The diagram below shows the `Svc::ComQueue` component. + +![Svc::ComQueue](./img/ComQueue.png) + +### 4.1. Ports +`Svc::ComQueue` has the following ports: + +| Kind | Name | Port Type | Usage | +|---------------|-------------------|---------------------------------------|--------------------------------------------------------| +| `output` | `comQueueSend` | `Fw.Com` | Fw::ComBuffer output port | +| `output` | `buffQueueSend` | `Fw.BufferSend` | Fw::Buffer output port | +| `async input` | `comStatusIn` | `Fw.SuccessCondition` | Port for receiving the status signal | +| `async input` | `comQueueIn` | `[ComQueueComPorts] Fw.Com` | Port array for receiving Fw::ComBuffers | +| `async input` | `buffQueueIn` | `[ComQueueBufferPorts] Fw.BufferSend` | Port array for receiving Fw::Buffers | +| `async input` | `run` | `Svc.Sched` | Port for scheduling telemetry output | +| `event` | `Log` | `Fw.Log` | Port for emitting events | +| `text event` | `LogText` | `Fw.LogText` | Port for emitting text events | +| `time get` | `Time` | `Fw.Time` | Port for getting the time | +| `telemetry` | `Tlm` | `Fw.Tlm` | Port for emitting telemetry | + + +### 4.2. State +`Svc::ComQueue` maintains the following state: +1. `m_queues`: An array of `Types::Queue` used to queue per-port messages. +2. `m_prioritizedList`: An instance of `Svc::ComQueue::QueueMetadata` storing the priority-order queue metadata. +3. `m_state`: Instance of `Svc::ComQueue::SendState` representing the state of the component. See: 4.3.1 State Machine +4. `m_throttle`: An array of flags that throttle the per-port queue overflow messages. + +### 4.2.1 State Machine + +The `Svc::ComQueue` component runs the following state machine. It has two states: + +| State | Description | +|---------|-----------------------------------------------------------------------------------------------| +| WAITING | `Svc::ComQueue` is waiting on `SUCCESS` before attempting to send an available buffer | +| READY | `Svc::ComQueue` had no queued buffers and will send the next buffer immediately when received | + +The state machine will transition between states when a status is received and will transition from `READY` when a new +buffer is received. `FAILURE` statuses keep the `Svc::ComQueue` in `WAITING` state whereas a `SUCCESS` status will +either send a buffer and transition to `WAITING` or will have no buffers to send and will transition into `READY` state. +Buffers are queued when in `WAITING` state. + +![`Svc::ComQueue` Functional State Machine](./img/state-machine.png) + +### 4.3 Model Configuration +`Svc::ComQueue` has the following constants, that are configured in `AcConstants.fpp`: +1. `ComQueueComPorts`: number of ports of `Fw.Com` type in the `comQueueIn` port array. +2. `ComQueueBufferPorts`: number of ports of `Fw.BufferSend` type in the `buffQueueIn` port array. + +### 4.4 Runtime Setup +To set up an instance of `ComQueue`, the following needs to be done: +1. Call the constructor and the init method in the usual way for an F Prime active component. +2. Call the `configure` method, passing in an array of `QueueConfiguration` type, the size of the array, +and an allocator of `Fw::MemAllocator`. The `configure` method foes the following: + + 1. Ensures that the total size and config size are the same value + 2. Ensures that priority values range from 0 to the total size value + 3. Ensures that every entry in the queue containing the prioritized order of the com buffer and buffer data have been + initialized. + 4. Ensures that there is enough memory for the com buffer and buffer data we want to process + +### 4.5 Port Handlers + +#### 4.5.1 buffQueueIn +The `buffQueueIn` port handler receives an `Fw::Buffer` data type and a port number. +It does the following: +1. Ensures that the port number is between zero and the value of the buffer size +2. Enqueue the buffer onto the `m_queues` instance +3. Returns a warning if `m_queues` is full + +In the case where the component is already in `READY` state, this will process the queue immediately after the buffer +is added to the queue. + +#### 4.5.2 comQueueIn +The `comQueueIn` port handler receives an `Fw::ComBuffer` data type and a port number. +It does the following: +1. Ensures that the port number is between zero and the value of the com buffer size +2. Enqueue the com buffer onto the `m_queues` instance +3. Returns a warning if `m_queues` is full + +In the case where the component is already in `READY` state, this will process the +queue immediately after the buffer is added to the queue. + +#### 4.5.3 comStatusIn +The `comStatusIn` port handler receives a `Fw::Success` status. This triggers the component's state machine to change +state. For a full description see [4.2.1 State Machine](#4.2.1-State-Machine). + +#### 4.5.4 run +The `run` port handler does the following: +1. Report the high-water mark for each queue since last `run` invocation via telemetry +2. Clear each queue's high-water mark + +### 4.6 Telemetry + +| Name | Type | Description | +|----------------|--------------------|-----------------------------------------------------------| +| comQueueDepth | Svc.ComQueueDepth | High-water mark depths of queues handling `Fw::ComBuffer` | +| buffQueueDepth | Svc.BuffQueueDepth | High-water mark depths of queues handling `Fw::Buffer` | + +### 4.7 Events + +| Name | Description | +|----------------|---------------------------------------------------------------------------------| +| QueueOverflow | WARNING_HI event triggered when a queue can no longer hold the incoming message | + +### 4.8 Helper Functions + +#### 4.8.1 sendComBuffer +Stores the com buffer message, sends the com buffer message on the output port, and then sets the send state to waiting. + +#### 4.8.2 sendBuffer +Stores the buffer message, sends the buffer message on the output port, and then sets the send state to waiting. + +#### 4.8.3 processQueue +In a bounded loop that is constrained by the total size of the queue that contains both +buffer and com buffer data, do: + + 1. Check if there are any items on the queue, and continue with the loop if there are none. + 2. Store the entry point of the queue based on the index of the array that contains the prioritized data. + 3. Compare the entry index with the value of the size of the queue that contains com buffer data. + 1. If it is less than the size value, then invoke the sendComBuffer function. + 2. If it is greater than the size value, then invoke the sendBuffer function. + 4. Break out of the loop, but enter a new loop that starts at the next entry and linearly swap the remaining items in +the prioritized list. diff --git a/Svc/ComQueue/test/ut/TestMain.cpp b/Svc/ComQueue/test/ut/TestMain.cpp new file mode 100644 index 0000000000..eadb4fc105 --- /dev/null +++ b/Svc/ComQueue/test/ut/TestMain.cpp @@ -0,0 +1,35 @@ +// ---------------------------------------------------------------------- +// TestMain.cpp +// ---------------------------------------------------------------------- + +#include "Svc/ComQueue/test/ut/Tester.hpp" + +TEST(Nominal, Send) { + Svc::Tester tester; + tester.testQueueSend(); +} + +TEST(Nominal, Pause) { + Svc::Tester tester; + tester.testQueuePause(); +} + +TEST(Nominal, Priority) { + Svc::Tester tester; + tester.testPrioritySend(); +} + +TEST(Nominal, Full) { + Svc::Tester tester; + tester.testQueueOverflow(); +} + +TEST(Nominal, ReadyFirst) { + Svc::Tester tester; + tester.testReadyFirst(); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/Svc/ComQueue/test/ut/Tester.cpp b/Svc/ComQueue/test/ut/Tester.cpp new file mode 100644 index 0000000000..34d56028a3 --- /dev/null +++ b/Svc/ComQueue/test/ut/Tester.cpp @@ -0,0 +1,327 @@ +// ====================================================================== +// \title ComQueue.hpp +// \author vbai +// \brief cpp file for ComQueue test harness implementation class +// ====================================================================== + +#include "Tester.hpp" +#include "Fw/Types/MallocAllocator.hpp" +using namespace std; + +Fw::MallocAllocator mallocAllocator; +#define INSTANCE 0 +#define MAX_HISTORY_SIZE 100 +#define QUEUE_DEPTH 100 + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +Tester ::Tester() : ComQueueGTestBase("Tester", MAX_HISTORY_SIZE), component("ComQueue") { + this->initComponents(); + this->connectPorts(); +} + +Tester ::~Tester() {} + +void Tester ::dispatchAll() { + while (this->component.m_queue.getNumMsgs() > 0) { + this->component.doDispatch(); + } +} + +void Tester ::configure() { + ComQueue::QueueConfigurationTable configurationTable; + for (NATIVE_UINT_TYPE i = 0; i < ComQueue::TOTAL_PORT_COUNT; i++){ + configurationTable.entries[i].priority = i; + configurationTable.entries[i].depth = 3; + } + component.configure(configurationTable, 0, mallocAllocator); +} + +void Tester ::sendByQueueNumber(NATIVE_INT_TYPE queueNum, NATIVE_INT_TYPE& portNum, QueueType& queueType) { + U8 data[BUFFER_LENGTH] = {0xde, 0xad, 0xbe}; + Fw::ComBuffer comBuffer(&data[0], sizeof(data)); + Fw::Buffer buffer(&data[0], sizeof(data)); + if (queueNum < ComQueue::COM_PORT_COUNT) { + portNum = queueNum; + queueType = QueueType::COM_QUEUE; + invoke_to_comQueueIn(portNum, comBuffer, 0); + } else { + portNum = queueNum - ComQueue::COM_PORT_COUNT; + queueType = QueueType::BUFFER_QUEUE; + invoke_to_buffQueueIn(portNum, buffer); + } +} + +void Tester ::emitOne() { + Fw::Success state = Fw::Success::SUCCESS; + invoke_to_comStatusIn(0, state); + dispatchAll(); +} + +void Tester ::emitOneAndCheck(NATIVE_UINT_TYPE expectedIndex, + QueueType expectedType, + Fw::ComBuffer& expectedCom, + Fw::Buffer& expectedBuff) { + emitOne(); + + if (expectedType == QueueType::COM_QUEUE) { + ASSERT_from_comQueueSend(expectedIndex, expectedCom, 0); + } else { + ASSERT_from_buffQueueSend(expectedIndex, expectedBuff); + } +} + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void Tester ::testQueueSend() { + U8 data[BUFFER_LENGTH] = {0xde, 0xad, 0xbe}; + Fw::ComBuffer comBuffer(&data[0], sizeof(data)); + Fw::Buffer buffer(&data[0], sizeof(data)); + configure(); + + for(NATIVE_INT_TYPE portNum = 0; portNum < ComQueue::COM_PORT_COUNT; portNum++){ + invoke_to_comQueueIn(portNum, comBuffer, 0); + emitOneAndCheck(portNum, QueueType::COM_QUEUE, comBuffer, buffer); + } + clearFromPortHistory(); + + for(NATIVE_INT_TYPE portNum = 0; portNum < ComQueue::BUFFER_PORT_COUNT; portNum++){ + invoke_to_buffQueueIn(portNum, buffer); + emitOneAndCheck(portNum, QueueType::BUFFER_QUEUE, comBuffer, buffer); + } + clearFromPortHistory(); + component.cleanup(); +} + +void Tester ::testQueuePause() { + U8 data[BUFFER_LENGTH] = {0xde, 0xad, 0xbe}; + Fw::ComBuffer comBuffer(&data[0], sizeof(data)); + Fw::Buffer buffer(&data[0], sizeof(data)); + configure(); + + for(NATIVE_INT_TYPE portNum = 0; portNum < ComQueue::COM_PORT_COUNT; portNum++){ + invoke_to_comQueueIn(portNum, comBuffer, 0); + // Send a bunch of failures + Fw::Success state = Fw::Success::FAILURE; + invoke_to_comStatusIn(0, state); + invoke_to_comStatusIn(0, state); + invoke_to_comStatusIn(0, state); + emitOneAndCheck(portNum, QueueType::COM_QUEUE, comBuffer, buffer); + } + clearFromPortHistory(); + + for(NATIVE_INT_TYPE portNum = 0; portNum < ComQueue::BUFFER_PORT_COUNT; portNum++){ + invoke_to_buffQueueIn(portNum, buffer); + // Send a bunch of failures + Fw::Success state = Fw::Success::FAILURE; + invoke_to_comStatusIn(0, state); + invoke_to_comStatusIn(0, state); + invoke_to_comStatusIn(0, state); + emitOneAndCheck(portNum, QueueType::BUFFER_QUEUE, comBuffer, buffer); + } + clearFromPortHistory(); + component.cleanup(); +} + +void Tester ::testPrioritySend() { + U8 data[ComQueue::TOTAL_PORT_COUNT][BUFFER_LENGTH]; + + ComQueue::QueueConfigurationTable configurationTable; + + for (NATIVE_UINT_TYPE i = 0; i < ComQueue::TOTAL_PORT_COUNT; i++) { + configurationTable.entries[i].priority = ComQueue::TOTAL_PORT_COUNT - i - 1; + configurationTable.entries[i].depth = 3; + data[i][0] = ComQueue::TOTAL_PORT_COUNT - i - 1; + } + + // Make the last message have the same priority as the second message + configurationTable.entries[ComQueue::TOTAL_PORT_COUNT - 1].priority = 1; + data[ComQueue::TOTAL_PORT_COUNT - 2][0] = 0; + data[ComQueue::TOTAL_PORT_COUNT - 1][0] = 1; + + component.configure(configurationTable, 0, mallocAllocator); + + for(NATIVE_INT_TYPE portNum = 0; portNum < ComQueue::COM_PORT_COUNT; portNum++){ + Fw::ComBuffer comBuffer(&data[portNum][0], BUFFER_LENGTH); + invoke_to_comQueueIn(portNum, comBuffer, 0); + } + + for (NATIVE_INT_TYPE portNum = 0; portNum < ComQueue::BUFFER_PORT_COUNT; portNum++) { + Fw::Buffer buffer(&data[portNum + ComQueue::COM_PORT_COUNT][0], BUFFER_LENGTH); + invoke_to_buffQueueIn(portNum, buffer); + } + + // Check that nothing has yet been sent + ASSERT_from_buffQueueSend_SIZE(0); + ASSERT_from_comQueueSend_SIZE(0); + + for (NATIVE_INT_TYPE index = 0; index < ComQueue::TOTAL_PORT_COUNT; index++) { + U8 orderKey; + U32 previousComSize = fromPortHistory_comQueueSend->size(); + U32 previousBufSize = fromPortHistory_buffQueueSend->size(); + emitOne(); + ASSERT_EQ(fromPortHistory_comQueueSend->size() + fromPortHistory_buffQueueSend->size(), (index + 1)); + + // Check that the sizes changed by exactly one + ASSERT_TRUE((previousComSize == fromPortHistory_comQueueSend->size()) ^ + (previousBufSize == fromPortHistory_buffQueueSend->size())); + + // Look for which type had arrived + if (fromPortHistory_comQueueSend->size() > previousComSize) { + orderKey = fromPortHistory_comQueueSend->at(fromPortHistory_comQueueSend->size() - 1).data.getBuffAddr()[0]; + } else { + orderKey = + fromPortHistory_buffQueueSend->at(fromPortHistory_buffQueueSend->size() - 1).fwBuffer.getData()[0]; + + } + ASSERT_EQ(orderKey, index); + } + clearFromPortHistory(); + component.cleanup(); +} + +void Tester::testQueueOverflow(){ + ComQueue::QueueConfigurationTable configurationTable; + ComQueueDepth expectedComDepth; + BuffQueueDepth expectedBuffDepth; + + for (NATIVE_UINT_TYPE i = 0; i < ComQueue::TOTAL_PORT_COUNT; i++){ + configurationTable.entries[i].priority = i; + configurationTable.entries[i].depth = 2; + + // Expected depths + if (i < ComQueue::COM_PORT_COUNT) { + expectedComDepth[i] = configurationTable.entries[i].depth; + } else { + expectedBuffDepth[i - ComQueue::COM_PORT_COUNT] = configurationTable.entries[i].depth; + } + } + + component.configure(configurationTable, 0, mallocAllocator); + + for(NATIVE_INT_TYPE queueNum = 0; queueNum < ComQueue::TOTAL_PORT_COUNT; queueNum++) { + QueueType overflow_type; + NATIVE_INT_TYPE portNum; + // queue[portNum].depth + 2 to deliberately cause overflow and check throttle of exactly 1 + for (NATIVE_UINT_TYPE msgCount = 0; msgCount < configurationTable.entries[queueNum].depth + 2; msgCount++) { + sendByQueueNumber(queueNum, portNum, overflow_type); + dispatchAll(); + } + ASSERT_EVENTS_QueueOverflow_SIZE(1); + ASSERT_EVENTS_QueueOverflow(0, overflow_type, portNum); + + // Drain a message, and see if throttle resets + emitOne(); + + // Force another overflow by filling then deliberately overflowing the queue + sendByQueueNumber(queueNum, portNum, overflow_type); + sendByQueueNumber(queueNum, portNum, overflow_type); + dispatchAll(); + + ASSERT_EVENTS_QueueOverflow_SIZE(2); + ASSERT_EVENTS_QueueOverflow(1, overflow_type, portNum); + + // Drain the queue again such that we have a clean slate before the next queue + for (NATIVE_UINT_TYPE msgCount = 0; msgCount < configurationTable.entries[queueNum].depth; msgCount++) { + emitOne(); + } + clearEvents(); + } + // Check max seen queue-depths + invoke_to_run(0, 0); + dispatchAll(); + ASSERT_TLM_comQueueDepth_SIZE(1); + ASSERT_TLM_buffQueueDepth_SIZE(1); + ASSERT_TLM_comQueueDepth(0, expectedComDepth); + ASSERT_TLM_buffQueueDepth(0, expectedBuffDepth); + component.cleanup(); +} + +void Tester ::testReadyFirst() { + U8 data[BUFFER_LENGTH] = {0xde, 0xad, 0xbe}; + Fw::ComBuffer comBuffer(&data[0], sizeof(data)); + Fw::Buffer buffer(&data[0], sizeof(data)); + configure(); + + for(NATIVE_INT_TYPE portNum = 0; portNum < ComQueue::COM_PORT_COUNT; portNum++){ + emitOne(); + invoke_to_comQueueIn(portNum, comBuffer, 0); + dispatchAll(); + ASSERT_from_comQueueSend(portNum, comBuffer, 0); + } + clearFromPortHistory(); + + for(NATIVE_INT_TYPE portNum = 0; portNum < ComQueue::BUFFER_PORT_COUNT; portNum++){ + emitOne(); + invoke_to_buffQueueIn(portNum, buffer); + dispatchAll(); + ASSERT_from_buffQueueSend(portNum, buffer); + } + clearFromPortHistory(); + component.cleanup(); +} + +// ---------------------------------------------------------------------- +// Handlers for typed from ports +// ---------------------------------------------------------------------- + +void Tester ::from_buffQueueSend_handler(const NATIVE_INT_TYPE portNum, Fw::Buffer& fwBuffer) { + this->pushFromPortEntry_buffQueueSend(fwBuffer); +} + +void Tester ::from_comQueueSend_handler(const NATIVE_INT_TYPE portNum, Fw::ComBuffer& data, U32 context) { + this->pushFromPortEntry_comQueueSend(data, context); +} + +// ---------------------------------------------------------------------- +// Helper methods +// ---------------------------------------------------------------------- + +void Tester ::connectPorts() { + // buffQueueIn + for (NATIVE_INT_TYPE i = 0; i < ComQueue::BUFFER_PORT_COUNT; ++i) { + this->connect_to_buffQueueIn(i, this->component.get_buffQueueIn_InputPort(i)); + } + + // comQueueIn + for (NATIVE_INT_TYPE i = 0; i < ComQueue::COM_PORT_COUNT; ++i) { + this->connect_to_comQueueIn(i, this->component.get_comQueueIn_InputPort(i)); + } + + // comStatusIn + this->connect_to_comStatusIn(0, this->component.get_comStatusIn_InputPort(0)); + + // run + this->connect_to_run(0, this->component.get_run_InputPort(0)); + + // Log + this->component.set_Log_OutputPort(0, this->get_from_Log(0)); + + // LogText + this->component.set_LogText_OutputPort(0, this->get_from_LogText(0)); + + // Time + this->component.set_Time_OutputPort(0, this->get_from_Time(0)); + + // Tlm + this->component.set_Tlm_OutputPort(0, this->get_from_Tlm(0)); + + // buffQueueSend + this->component.set_buffQueueSend_OutputPort(0, this->get_from_buffQueueSend(0)); + + // comQueueSend + this->component.set_comQueueSend_OutputPort(0, this->get_from_comQueueSend(0)); +} + +void Tester ::initComponents() { + this->init(); + this->component.init(QUEUE_DEPTH, INSTANCE); +} + +} // end namespace Svc diff --git a/Svc/ComQueue/test/ut/Tester.hpp b/Svc/ComQueue/test/ut/Tester.hpp new file mode 100644 index 0000000000..8b06126396 --- /dev/null +++ b/Svc/ComQueue/test/ut/Tester.hpp @@ -0,0 +1,106 @@ +// ====================================================================== +// \title ComQueue/test/ut/Tester.hpp +// \author vbai +// \brief hpp file for ComQueue test harness implementation class +// ====================================================================== + +#ifndef TESTER_HPP +#define TESTER_HPP + +#include "GTestBase.hpp" +#include "Svc/ComQueue/ComQueue.hpp" +#define BUFFER_LENGTH 3u + +namespace Svc { + +class Tester : public ComQueueGTestBase { + private: + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + public: + //! Construct object Tester + //! + Tester(); + + //! Destroy object Tester + //! + ~Tester(); + + //! Dispatch all component messages + //! + void dispatchAll(); + + public: + // ---------------------------------------------------------------------- + // Helpers + // ---------------------------------------------------------------------- + void configure(); + + void sendByQueueNumber(NATIVE_INT_TYPE queueNumber, NATIVE_INT_TYPE& portNum, QueueType& queueType); + + void emitOne(); + + void emitOneAndCheck(NATIVE_UINT_TYPE expectedIndex, + QueueType expectedType, + Fw::ComBuffer& expectedCom, + Fw::Buffer& expectedBuff); + + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + void testQueueSend(); + + void testQueuePause(); + + void testPrioritySend(); + + void testQueueOverflow(); + + void testReadyFirst(); + + private: + // ---------------------------------------------------------------------- + // Handlers for typed from ports + // ---------------------------------------------------------------------- + + //! Handler for from_buffQueueSend + //! + void from_buffQueueSend_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Buffer& fwBuffer); + + //! Handler for from_comQueueSend + //! + void from_comQueueSend_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::ComBuffer& data, /*!< Buffer containing packet data*/ + U32 context /*!< Call context value; meaning chosen by user*/ + ); + + private: + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + //! Connect ports + //! + void connectPorts(); + + //! Initialize components + //! + void initComponents(); + + private: + // ---------------------------------------------------------------------- + // Variables + // ---------------------------------------------------------------------- + + //! The component under test + //! + ComQueue component; +}; + +} // end namespace Svc + +#endif diff --git a/Svc/ComSplitter/CMakeLists.txt b/Svc/ComSplitter/CMakeLists.txt index 0e9d006698..6602453c53 100644 --- a/Svc/ComSplitter/CMakeLists.txt +++ b/Svc/ComSplitter/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/ComSplitter/ComSplitter.cpp b/Svc/ComSplitter/ComSplitter.cpp index 7a8af5c816..963eb71504 100644 --- a/Svc/ComSplitter/ComSplitter.cpp +++ b/Svc/ComSplitter/ComSplitter.cpp @@ -5,7 +5,7 @@ // ---------------------------------------------------------------------- #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace Svc { diff --git a/Svc/ComStub/CMakeLists.txt b/Svc/ComStub/CMakeLists.txt new file mode 100644 index 0000000000..a22cc74a44 --- /dev/null +++ b/Svc/ComStub/CMakeLists.txt @@ -0,0 +1,23 @@ +#### +# F prime CMakeLists.txt: +# +# SOURCE_FILES: combined list of source and autocoding diles +# MOD_DEPS: (optional) module dependencies +# +# Note: using PROJECT_NAME as EXECUTABLE_NAME +#### +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/ComStub.fpp" + "${CMAKE_CURRENT_LIST_DIR}/ComStub.cpp" +) +register_fprime_module() + +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/ComStub.fpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/TestMain.cpp" +) +set(UT_MOD_DEPS + STest +) +register_fprime_ut() diff --git a/Svc/ComStub/ComStub.cpp b/Svc/ComStub/ComStub.cpp new file mode 100644 index 0000000000..1cf361fcba --- /dev/null +++ b/Svc/ComStub/ComStub.cpp @@ -0,0 +1,58 @@ +// ====================================================================== +// \title ComStub.cpp +// \author mstarch +// \brief cpp file for ComStub component implementation class +// ====================================================================== + +#include +#include "Fw/Types/Assert.hpp" +#include "Fw/Types/BasicTypes.hpp" + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction, initialization, and destruction +// ---------------------------------------------------------------------- + +ComStub::ComStub(const char* const compName) : ComStubComponentBase(compName), m_reinitialize(true) {} + +void ComStub::init(const NATIVE_INT_TYPE instance) { + ComStubComponentBase::init(instance); +} + +ComStub::~ComStub() {} + +// ---------------------------------------------------------------------- +// Handler implementations for user-defined typed input ports +// ---------------------------------------------------------------------- + +Drv::SendStatus ComStub::comDataIn_handler(const NATIVE_INT_TYPE portNum, Fw::Buffer& sendBuffer) { + FW_ASSERT(!this->m_reinitialize || !this->isConnected_comStatus_OutputPort(0)); // A message should never get here if we need to reinitialize is needed + Drv::SendStatus driverStatus = Drv::SendStatus::SEND_RETRY; + for (NATIVE_UINT_TYPE i = 0; driverStatus == Drv::SendStatus::SEND_RETRY && i < RETRY_LIMIT; i++) { + driverStatus = this->drvDataOut_out(0, sendBuffer); + } + FW_ASSERT(driverStatus != Drv::SendStatus::SEND_RETRY); // If it is still in retry state, there is no good answer + Fw::Success comSuccess = (driverStatus.e == Drv::SendStatus::SEND_OK) ? Fw::Success::SUCCESS : Fw::Success::FAILURE; + this->m_reinitialize = driverStatus.e != Drv::SendStatus::SEND_OK; + if (this->isConnected_comStatus_OutputPort(0)) { + this->comStatus_out(0, comSuccess); + } + return Drv::SendStatus::SEND_OK; // Always send ok to deframer as it does not handle this anyway +} + +void ComStub::drvConnected_handler(const NATIVE_INT_TYPE portNum) { + Fw::Success radioSuccess = Fw::Success::SUCCESS; + if (this->isConnected_comStatus_OutputPort(0) && m_reinitialize) { + this->m_reinitialize = false; + this->comStatus_out(0, radioSuccess); + } +} + +void ComStub::drvDataIn_handler(const NATIVE_INT_TYPE portNum, + Fw::Buffer& recvBuffer, + const Drv::RecvStatus& recvStatus) { + this->comDataOut_out(0, recvBuffer, recvStatus); +} + +} // end namespace Svc diff --git a/Svc/ComStub/ComStub.fpp b/Svc/ComStub/ComStub.fpp new file mode 100644 index 0000000000..65576cc854 --- /dev/null +++ b/Svc/ComStub/ComStub.fpp @@ -0,0 +1,31 @@ +module Svc { + @ Communication adapter interface implementing communication adapter interface via a Drv.ByteStreamDriverModel. + passive component ComStub { + + # ---------------------------------------------------------------------- + # Framer, deframer, and queue ports + # ---------------------------------------------------------------------- + + @ Data coming in from the framing component + sync input port comDataIn: Drv.ByteStreamSend + + @ Status of the last radio transmission + output port comStatus: Fw.SuccessCondition + + @ Com data passing back out + output port comDataOut: Drv.ByteStreamRecv + + # ---------------------------------------------------------------------- + # Byte stream model + # ---------------------------------------------------------------------- + + @ Ready signal when driver is connected + sync input port drvConnected: Drv.ByteStreamReady + + @ Data received from driver + sync input port drvDataIn: Drv.ByteStreamRecv + + @ Data going to the underlying driver + output port drvDataOut: Drv.ByteStreamSend + } +} \ No newline at end of file diff --git a/Svc/ComStub/ComStub.hpp b/Svc/ComStub/ComStub.hpp new file mode 100644 index 0000000000..f75b634660 --- /dev/null +++ b/Svc/ComStub/ComStub.hpp @@ -0,0 +1,60 @@ +// ====================================================================== +// \title ComStub.hpp +// \author mstarch +// \brief hpp file for ComStub component implementation class +// ====================================================================== + +#ifndef Svc_ComStub_HPP +#define Svc_ComStub_HPP + +#include "Svc/ComStub/ComStubComponentAc.hpp" + +namespace Svc { + +class ComStub : public ComStubComponentBase { + public: + const NATIVE_UINT_TYPE RETRY_LIMIT = 10; + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + //! Construct object ComStub + //! + ComStub(const char* const compName /*!< The component name*/ + ); + + //! Initialize object ComStub + //! + void init(const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ + ); + + //! Destroy object ComStub + //! + ~ComStub() override; + + private: + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for comDataIn + //! + Drv::SendStatus comDataIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Buffer& sendBuffer) override; + + //! Handler implementation for drvConnected + //! + void drvConnected_handler(const NATIVE_INT_TYPE portNum) override; + + //! Handler implementation for drvDataIn + //! + void drvDataIn_handler(const NATIVE_INT_TYPE portNum, + /*!< The port number*/ Fw::Buffer& recvBuffer, + const Drv::RecvStatus& recvStatus) override; + + bool m_reinitialize; //!< Stores if a ready signal is needed on connection +}; + +} // end namespace Svc + +#endif diff --git a/Svc/ComStub/docs/img/byte-stream.png b/Svc/ComStub/docs/img/byte-stream.png new file mode 100644 index 0000000000..73e31a320d Binary files /dev/null and b/Svc/ComStub/docs/img/byte-stream.png differ diff --git a/Svc/ComStub/docs/img/com-adapter.png b/Svc/ComStub/docs/img/com-adapter.png new file mode 100644 index 0000000000..d831737d38 Binary files /dev/null and b/Svc/ComStub/docs/img/com-adapter.png differ diff --git a/Svc/ComStub/docs/sdd.md b/Svc/ComStub/docs/sdd.md new file mode 100644 index 0000000000..d05fdfc46b --- /dev/null +++ b/Svc/ComStub/docs/sdd.md @@ -0,0 +1,96 @@ +\page SvcComStubComponent Svc::ComStub Component +# Svc::ComStub (Passive Component) + +## 1. Introduction + +`Svc::ComStub` is an example F´ component implementing the +[communication adapter interface](https://nasa.github.io/fprime/Design/communication-adapter-interface.html) required +to work with F´ communication components. Projects and users may choose to replace this with a complete communication +implementation (i.e. a component managing a specific radio) once ready. As long as any communication implementation +implements the communication adapter interface it can drop in and work with the standard F´ uplink and downlink setup. + +`Svc::ComStub` delegates to a `Drv.ByteStreamDriver` in order to send and receive data through the driver interface. + +## 2. Assumptions + +Using `Svc::ComStub` assumes that the driver layer (e.g. `Drv::TcpClient`) provides all capability needed to establish +communications. For example, a project can communicate over raw tcp rather than requiring additional protocol on top of +tcp. + + +## 3. Requirements + +| Requirement | Description | Rationale | Verification Method | +|-----------------|-----------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------|---------------------| +| SVC-COMSTUB-001 | `Svc::ComStub` shall accept `Fw::Buffer` for transmission and pass them to a `Drv::ByteStreamSend` port | The comm interface must send `Fw::Buffer`s through a driver | Unit Test | +| SVC-COMSTUB-002 | `Svc::ComStub` shall send a `Fw::Success:SUCCESS` signal via an `Fw.SuccessCondition` port on `Drv::ByteStreamSend` success | Successful sends must notify any attached `Svc::ComQueue` | Unit Test | +| SVC-COMSTUB-003 | `Svc::ComStub` shall send a `Fw::Success:FAILURE` signal via an `Fw.SuccessCondition` port on `Drv::ByteStreamSend` failure | Failed sends must notify any attached `Svc::ComQueue` | Unit Test | +| SVC-COMSTUB-004 | `Svc::ComStub` shall retry sending to `Drv::ByteStreamSend` on `Drv::ByteStreamSend` retry | Sends indicating `RETRY` should be retried. | Unit Test | +| SVC-COMSTUB-005 | `Svc::ComStub` shall pass-through `Fw::Buffer` from a `Drv::ByteStreamRead` on `Drv::ByteStreamSend` success | A Comm interface must receive `Fw::Buffer`s from a driver | Unit Test | + +## 4. Design + +The diagram below shows the `Svc::ComStub` port interface. `Svc::ComStub` is a basic *Communication Adapter* and can be +used alongside the other F´ communication components (`Svc::Framer`, `Svc::Deframer`, `Svc::ComQueue`). + +**Svc::ComStub Uplink and Downlink Interface** + +![`Svc::ComStub` as Communication Adapter](./img/com-adapter.png) + + +`Svc::ComStub` implements the +[communication adapter interface](https://nasa.github.io/fprime/Design/communication-adapter-interface.html) by +delegation to a `Drv::ByteStreamDriverModel` as a way to transmit data and receive data. Other communication +adapter implementations may follow-suite. + +![`Svc::ComStub` to `Drv::ByteStreamDriverModel`](./img/byte-stream.png) + +### 4.1. Ports + +`ComStub` has the following ports. The first three ports are required for the communication adapter interface, the +second three are because the implementation delegates to a `Drv.ByteStreamDriverModel`. Only the communication adapter +interfaces ports are required for replacements to `Svc::ComStub`, however; a `Drv.ByteStreamDriverModel` ports may still +be useful + +**Communication Adapter Interface Ports** + +| Kind | Name | Port Type | Usage | +|--------------|----------------|-----------------------|-----------------------------------------------------------------------------------| +| `sync input` | `comDataIn` | `Drv.ByteStreamSend` | Port receiving `Fw::Buffer`s for transmission out `drvDataOut` | +| `output` | `comStatus` | `Svc.ComStatus` | Port indicating success or failure to attached `Svc::ComQueue` | +| `output` | `comDataOut` | `Drv.ByteStreamRecv` | Port providing received `Fw::Buffers` to a potential `Svc::Deframer` | + +**Byte Stream Driver Model Ports** + +| Kind | Name | Port Type | Usage | +|--------------|----------------|-----------------------|-----------------------------------------------------------------------------------| +| `sync input` | `drvConnected` | `Drv.ByteStreamReady` | Port called when the underlying driver has connected | +| `sync input` | `drvDataIn` | `Drv.ByteStreamRecv` | Port receiving `Fw::Buffers` from underlying communications bus driver | +| `output` | `drvDataOut` | `Drv.ByteStreamSend` | Port providing received `Fw::Buffers` to the underlying communications bus driver | + + +### 4.2. State, Configuration, and Runtime Setup + +`Svc::ComStub` has only stores a boolean `m_reinitialize` indicating when it should send `Fw::Success::SUCCESS` in +response to a driver reconnection event. This is to implement the Communication Adapter Protocol of a +[communication adapter interface](https://nasa.github.io/fprime/Design/communication-adapter-interface.html#Communication_Adapter_Protocol). + +### 4.3. Port Handlers + +#### 4.3.1 comDataIn + +The `comDataIn` port handler receives an `Fw::Buffer` from the F´ system for transmission to the ground. Typically, it +is connected to the output of the `Svc::Framer` component. In this `Svc::ComStub` implementation, it passes this +`Fw::Buffer` directly to the `drvDataOut` port. It will retry when that port responds with a `RETRY` request. Otherwise, + the `comStatus` port will be invoked to indicate success or failure. Retries attempts are limited before the port +asserts. + +#### 4.3.1 drvConnected + +This port receives the connected signal from the driver and responds with exactly one `READY` invocation to the +`comStatus` port. This starts downlink. This occurs each time the driver reconnects. + +#### 4.3.1 drvDataIn + +The `drvDataIn` handler receives data read from the driver and supplies it out the `comDataOut` port. It is usually +connected to the `Svc::Deframer` component diff --git a/Svc/GenericRepeater/test/ut/TestMain.cpp b/Svc/ComStub/test/ut/TestMain.cpp similarity index 53% rename from Svc/GenericRepeater/test/ut/TestMain.cpp rename to Svc/ComStub/test/ut/TestMain.cpp index 8017863c5f..c156b08acb 100644 --- a/Svc/GenericRepeater/test/ut/TestMain.cpp +++ b/Svc/ComStub/test/ut/TestMain.cpp @@ -4,9 +4,25 @@ #include "Tester.hpp" -TEST(Nominal, TestRepeater) { +TEST(Nominal, Initial) { Svc::Tester tester; - tester.testRepeater(); + tester.test_initial(); +} + +TEST(Nominal, BasicIo) { + Svc::Tester tester; + tester.test_basic(); +} + + +TEST(Nominal, Fail) { + Svc::Tester tester; + tester.test_fail(); +} + +TEST(OffNominal, Retry) { + Svc::Tester tester; + tester.test_retry(); } int main(int argc, char **argv) { diff --git a/Svc/ComStub/test/ut/Tester.cpp b/Svc/ComStub/test/ut/Tester.cpp new file mode 100644 index 0000000000..59788e8585 --- /dev/null +++ b/Svc/ComStub/test/ut/Tester.cpp @@ -0,0 +1,172 @@ +// ====================================================================== +// \title ComStub.hpp +// \author mstarch +// \brief cpp file for ComStub test harness implementation class +// ====================================================================== + +#include "Tester.hpp" +#include + +#define INSTANCE 0 +#define MAX_HISTORY_SIZE 100 +#define RETRIES 3 + +U8 storage[RETRIES][10240]; + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +Tester ::Tester() + : ComStubGTestBase("Tester", MAX_HISTORY_SIZE), + m_component("ComStub"), + m_send_mode(Drv::SendStatus::SEND_OK), + m_retries(0) { + this->initComponents(); + this->connectPorts(); +} + +Tester ::~Tester() {} + +// ---------------------------------------------------------------------- +// Helpers +// ---------------------------------------------------------------------- +void Tester ::fill(Fw::Buffer& buffer_to_fill) { + U8 size = STest::Pick::lowerUpper(1, sizeof(buffer_to_fill.getSize())); + for (U32 i = 0; i < size; i++) { + buffer_to_fill.getData()[i] = STest::Pick::any(); + } + buffer_to_fill.setSize(size); +} + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- +void Tester ::test_initial() { + Fw::Success condition = Fw::Success::SUCCESS; + invoke_to_drvConnected(0); + ASSERT_from_comStatus_SIZE(1); + ASSERT_from_comStatus(0, condition); + this->fromPortHistory_comStatus->clear(); +} + +void Tester ::test_basic() { + this->test_initial(); + Fw::Buffer buffer(storage[0], sizeof(storage[0])); + Fw::Success condition = Fw::Success::SUCCESS; + this->fill(buffer); + + // Downlink + ASSERT_EQ(invoke_to_comDataIn(0, buffer), Drv::SendStatus::SEND_OK); + ASSERT_from_drvDataOut_SIZE(1); + ASSERT_from_drvDataOut(0, buffer); + ASSERT_from_comStatus(0, condition); + + // Uplink + Drv::RecvStatus status = Drv::RecvStatus::RECV_OK; + invoke_to_drvDataIn(0, buffer, status); + ASSERT_from_comDataOut_SIZE(1); + ASSERT_from_comDataOut(0, buffer, status); +} + +void Tester ::test_fail() { + this->test_initial(); + Fw::Buffer buffer(storage[0], sizeof(storage[0])); + this->fill(buffer); + Fw::Success condition = Fw::Success::FAILURE; + m_send_mode = Drv::SendStatus::SEND_ERROR; + + // Downlink + ASSERT_EQ(invoke_to_comDataIn(0, buffer), Drv::SendStatus::SEND_OK); + ASSERT_from_drvDataOut_SIZE(1); + ASSERT_from_drvDataOut(0, buffer); + ASSERT_from_drvDataOut_SIZE(1); + ASSERT_from_comStatus(0, condition); + + // Uplink + Drv::RecvStatus status = Drv::RecvStatus::RECV_ERROR; + invoke_to_drvDataIn(0, buffer, status); + ASSERT_from_comDataOut_SIZE(1); + ASSERT_from_comDataOut(0, buffer, status); +} + +void Tester ::test_retry() { + this->test_initial(); + Fw::Buffer buffers[RETRIES]; + Fw::Success condition = Fw::Success::SUCCESS; + m_send_mode = Drv::SendStatus::SEND_RETRY; + + for (U32 i = 0; i < RETRIES; i++) { + buffers[i].setData(storage[i]); + buffers[i].setSize(sizeof(storage[i])); + buffers[i].setContext(i); + this->fill(buffers[i]); + invoke_to_comDataIn(0, buffers[i]); + ASSERT_from_drvDataOut_SIZE((i + 1) * RETRIES); + m_retries = 0; + } + ASSERT_from_drvDataOut_SIZE(RETRIES * RETRIES); + ASSERT_from_comStatus_SIZE(3); + for (U32 i = 0; i < RETRIES; i++) { + for (U32 j = 0; j < RETRIES; j++) { + ASSERT_from_drvDataOut((i * RETRIES) + j, buffers[i]); + } + ASSERT_from_comStatus(i, condition); + } +} + +// ---------------------------------------------------------------------- +// Handlers for typed from ports +// ---------------------------------------------------------------------- + +void Tester ::from_comDataOut_handler(const NATIVE_INT_TYPE portNum, + Fw::Buffer& recvBuffer, + const Drv::RecvStatus& recvStatus) { + this->pushFromPortEntry_comDataOut(recvBuffer, recvStatus); +} + +void Tester ::from_comStatus_handler(const NATIVE_INT_TYPE portNum, Fw::Success& condition) { + this->pushFromPortEntry_comStatus(condition); +} + +Drv::SendStatus Tester ::from_drvDataOut_handler(const NATIVE_INT_TYPE portNum, Fw::Buffer& sendBuffer) { + this->pushFromPortEntry_drvDataOut(sendBuffer); + m_retries = (m_send_mode == Drv::SendStatus::SEND_RETRY) ? (m_retries + 1) : m_retries; + if (m_retries < RETRIES) { + return m_send_mode; + } + return Drv::SendStatus::SEND_OK; +} + +// ---------------------------------------------------------------------- +// Helper methods +// ---------------------------------------------------------------------- + +void Tester ::connectPorts() { + // comDataIn + this->connect_to_comDataIn(0, this->m_component.get_comDataIn_InputPort(0)); + + // drvConnected + this->connect_to_drvConnected(0, this->m_component.get_drvConnected_InputPort(0)); + + // drvDataIn + this->connect_to_drvDataIn(0, this->m_component.get_drvDataIn_InputPort(0)); + + // comDataOut + this->m_component.set_comDataOut_OutputPort(0, this->get_from_comDataOut(0)); + + // comStatus + this->m_component.set_comStatus_OutputPort(0, this->get_from_comStatus(0)); + + // drvDataOut + this->m_component.set_drvDataOut_OutputPort(0, this->get_from_drvDataOut(0)); +} + +void Tester ::initComponents() { + this->init(); + this->m_component.init(INSTANCE); +} + +} // end namespace Svc diff --git a/Svc/ComStub/test/ut/Tester.hpp b/Svc/ComStub/test/ut/Tester.hpp new file mode 100644 index 0000000000..6f794d6354 --- /dev/null +++ b/Svc/ComStub/test/ut/Tester.hpp @@ -0,0 +1,104 @@ +// ====================================================================== +// \title ComStub/test/ut/Tester.hpp +// \author mstarch +// \brief hpp file for ComStub test harness implementation class +// ====================================================================== + +#ifndef TESTER_HPP +#define TESTER_HPP + +#include "GTestBase.hpp" +#include "Svc/ComStub/ComStub.hpp" + +namespace Svc { + +class Tester : public ComStubGTestBase { + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + public: + //! Construct object Tester + //! + Tester(); + + //! Destroy object Tester + //! + ~Tester(); + + public: + //! Buffer to fill with data + //! + void fill(Fw::Buffer& buffer_to_fill); + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! Test initial READY setup + //! + void test_initial(); + + //! Tests the basic input and output of the component + //! + void test_basic(); + + //! Tests the basic failure case for the component + //! + void test_fail(); + + //! Tests the basic failure retry component + //! + void test_retry(); + + private: + // ---------------------------------------------------------------------- + // Handlers for typed from ports + // ---------------------------------------------------------------------- + + //! Handler for from_comDataOut + //! + void from_comDataOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Buffer& recvBuffer, + const Drv::RecvStatus& recvStatus); + + //! Handler for from_comStatus + //! + void from_comStatus_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Success& condition /*!< + Status of communication state + */ + ); + + //! Handler for from_drvDataOut + //! + Drv::SendStatus from_drvDataOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Buffer& sendBuffer); + + private: + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + //! Connect ports + //! + void connectPorts(); + + //! Initialize components + //! + void initComponents(); + + private: + // ---------------------------------------------------------------------- + // Variables + // ---------------------------------------------------------------------- + + //! The component under test + //! + ComStub m_component; + Drv::SendStatus m_send_mode; //! Send mode + U32 m_retries; //! Number of retries to test +}; + +} // end namespace Svc + +#endif diff --git a/Svc/Cycle/CMakeLists.txt b/Svc/Cycle/CMakeLists.txt index 2ae14a6b94..32dcbfa8c6 100644 --- a/Svc/Cycle/CMakeLists.txt +++ b/Svc/Cycle/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME @@ -12,5 +12,6 @@ set(SOURCE_FILES ) set(MOD_DEPS Os + Fw/Port ) register_fprime_module() diff --git a/Svc/Deframer/CMakeLists.txt b/Svc/Deframer/CMakeLists.txt index f9fd350047..c90079e115 100644 --- a/Svc/Deframer/CMakeLists.txt +++ b/Svc/Deframer/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/Deframer/Deframer.cpp b/Svc/Deframer/Deframer.cpp index 5d9f1686d3..00a259a8c3 100644 --- a/Svc/Deframer/Deframer.cpp +++ b/Svc/Deframer/Deframer.cpp @@ -14,7 +14,7 @@ #include "Fw/Com/ComPacket.hpp" #include "Fw/Logger/Logger.hpp" -#include "Fw/Types/BasicTypes.hpp" +#include #include "Svc/Deframer/Deframer.hpp" namespace Svc { diff --git a/Svc/Deframer/docs/img/top/file.json b/Svc/Deframer/docs/img/top/deframer-file.json similarity index 100% rename from Svc/Deframer/docs/img/top/file.json rename to Svc/Deframer/docs/img/top/deframer-file.json diff --git a/Svc/Deframer/docs/img/top/file.png b/Svc/Deframer/docs/img/top/deframer-file.png similarity index 100% rename from Svc/Deframer/docs/img/top/file.png rename to Svc/Deframer/docs/img/top/deframer-file.png diff --git a/Svc/Deframer/docs/img/top/file.txt b/Svc/Deframer/docs/img/top/deframer-file.txt similarity index 100% rename from Svc/Deframer/docs/img/top/file.txt rename to Svc/Deframer/docs/img/top/deframer-file.txt diff --git a/Svc/Deframer/docs/sdd.md b/Svc/Deframer/docs/sdd.md index 0807465438..a7612e5d68 100644 --- a/Svc/Deframer/docs/sdd.md +++ b/Svc/Deframer/docs/sdd.md @@ -376,7 +376,7 @@ assign these numbers. **Topology 3: Buffers containing packet data:**
- +
### 6.2. Sequence Diagrams diff --git a/Svc/Deframer/test/ut-fprime-protocol/GenerateFrames.hpp b/Svc/Deframer/test/ut-fprime-protocol/GenerateFrames.hpp index f1e6e1a41a..1e2487388b 100644 --- a/Svc/Deframer/test/ut-fprime-protocol/GenerateFrames.hpp +++ b/Svc/Deframer/test/ut-fprime-protocol/GenerateFrames.hpp @@ -7,7 +7,7 @@ #ifndef SVC_GENERATE_FRAMES_HPP #define SVC_GENERATE_FRAMES_HPP -#include "Fw/Types/BasicTypes.hpp" +#include #include "Fw/Types/StringType.hpp" #include "STest/STest/Pick/Pick.hpp" #include "STest/STest/Rule/Rule.hpp" diff --git a/Svc/Deframer/test/ut-fprime-protocol/SendBuffer.hpp b/Svc/Deframer/test/ut-fprime-protocol/SendBuffer.hpp index d642366917..0f21758709 100644 --- a/Svc/Deframer/test/ut-fprime-protocol/SendBuffer.hpp +++ b/Svc/Deframer/test/ut-fprime-protocol/SendBuffer.hpp @@ -7,7 +7,7 @@ #ifndef SVC_SEND_BUFFER_HPP #define SVC_SEND_BUFFER_HPP -#include "Fw/Types/BasicTypes.hpp" +#include #include "Fw/Types/StringType.hpp" #include "STest/STest/Pick/Pick.hpp" #include "STest/STest/Rule/Rule.hpp" diff --git a/Svc/Fatal/CMakeLists.txt b/Svc/Fatal/CMakeLists.txt index 9dccaa9e26..53c0e656f1 100644 --- a/Svc/Fatal/CMakeLists.txt +++ b/Svc/Fatal/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME @@ -10,4 +10,8 @@ set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Fatal.fpp" ) +set(MOD_DEPS + Fw/Port +) + register_fprime_module() diff --git a/Svc/FatalHandler/CMakeLists.txt b/Svc/FatalHandler/CMakeLists.txt index 27ae77a898..6b82bb5bfa 100644 --- a/Svc/FatalHandler/CMakeLists.txt +++ b/Svc/FatalHandler/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/FatalHandler/FatalHandlerComponentBaremetalImpl.cpp b/Svc/FatalHandler/FatalHandlerComponentBaremetalImpl.cpp index de7dbbef27..e62f4535ec 100644 --- a/Svc/FatalHandler/FatalHandlerComponentBaremetalImpl.cpp +++ b/Svc/FatalHandler/FatalHandlerComponentBaremetalImpl.cpp @@ -7,7 +7,7 @@ #include #include #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace Svc { diff --git a/Svc/FatalHandler/FatalHandlerComponentCommonImpl.cpp b/Svc/FatalHandler/FatalHandlerComponentCommonImpl.cpp index be76416c7b..42bd6ec9e4 100644 --- a/Svc/FatalHandler/FatalHandlerComponentCommonImpl.cpp +++ b/Svc/FatalHandler/FatalHandlerComponentCommonImpl.cpp @@ -12,7 +12,7 @@ #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace Svc { diff --git a/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp b/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp index 9cb3a02d63..2805682255 100644 --- a/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp +++ b/Svc/FatalHandler/FatalHandlerComponentLinuxImpl.cpp @@ -14,7 +14,7 @@ #include #include #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace Svc { @@ -28,8 +28,8 @@ namespace Svc { // for **nix, delay then exit with error code Fw::Logger::logMsg("FATAL %d handled.\n",Id,0,0,0,0,0); (void)Os::Task::delay(1000); - Fw::Logger::logMsg("Exiting with segfault and core dump file.\n",0,0,0,0,0,0); - (void)raise( SIGSEGV ); + Fw::Logger::logMsg("Exiting with abort signal and core dump file.\n",0,0,0,0,0,0); + (void)raise( SIGABRT ); exit(1); } diff --git a/Svc/FatalHandler/FatalHandlerComponentVxWorksImpl.cpp b/Svc/FatalHandler/FatalHandlerComponentVxWorksImpl.cpp index 86f4a17922..25a8e689b1 100644 --- a/Svc/FatalHandler/FatalHandlerComponentVxWorksImpl.cpp +++ b/Svc/FatalHandler/FatalHandlerComponentVxWorksImpl.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include -#include "Fw/Types/BasicTypes.hpp" +#include #include #include diff --git a/Svc/FileDownlink/CMakeLists.txt b/Svc/FileDownlink/CMakeLists.txt index 19497b0002..74e0fd9be6 100644 --- a/Svc/FileDownlink/CMakeLists.txt +++ b/Svc/FileDownlink/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/FileDownlink/File.cpp b/Svc/FileDownlink/File.cpp index bb701afaf8..2b6caa09be 100644 --- a/Svc/FileDownlink/File.cpp +++ b/Svc/FileDownlink/File.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include namespace Svc { @@ -33,11 +33,15 @@ namespace Svc { this->destName = destLogStringArg; // Set size - U64 size; + FwSizeType size; const Os::FileSystem::Status status = Os::FileSystem::getFileSize(sourceFileName, size); if (status != Os::FileSystem::OP_OK) return Os::File::BAD_SIZE; + // If the size does not cast cleanly to the desired U32 type, return size error + if (static_cast(static_cast(size)) != size) { + return Os::File::BAD_SIZE; + } this->size = static_cast(size); // Initialize checksum @@ -66,8 +70,10 @@ namespace Svc { status = this->osFile.read(data, intSize); if (status != Os::File::OP_OK) return status; - FW_ASSERT(static_cast(intSize) == size); - + // Force a bad size error when the U32 carrying size is bad + if (static_cast(intSize) != size) { + return Os::File::BAD_SIZE; + } this->checksum.update(data, byteOffset, size); return Os::File::OP_OK; diff --git a/Svc/FileDownlink/FileDownlink.cpp b/Svc/FileDownlink/FileDownlink.cpp index ce1fff0121..40080d320a 100644 --- a/Svc/FileDownlink/FileDownlink.cpp +++ b/Svc/FileDownlink/FileDownlink.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include diff --git a/Svc/FileDownlink/docs/sdd.md b/Svc/FileDownlink/docs/sdd.md index dff4c312d0..0e44c68ea4 100644 --- a/Svc/FileDownlink/docs/sdd.md +++ b/Svc/FileDownlink/docs/sdd.md @@ -12,6 +12,9 @@ has completed. To prevent a continuous stream of file downlink traffic from satu communication link, a cooldown can be configured to add a delay between the completion of a file downlink and starting on the next file in the queue. +**Note:** file downlink is limited to processing files with a maximum file size of 4GiB. Larger files will result in a +bad size error. + ## 2 Requirements Requirement | Description | Rationale | Verification Method diff --git a/Svc/FileDownlinkPorts/CMakeLists.txt b/Svc/FileDownlinkPorts/CMakeLists.txt index 88c1974e35..c4216dd5ab 100644 --- a/Svc/FileDownlinkPorts/CMakeLists.txt +++ b/Svc/FileDownlinkPorts/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME @@ -9,4 +9,10 @@ set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/FileDownlinkPorts.fpp" ) + +set(MOD_DEPS + Fw/Types + Fw/Port +) + register_fprime_module() diff --git a/Svc/FileManager/CMakeLists.txt b/Svc/FileManager/CMakeLists.txt index c50de22066..ef30c5d810 100644 --- a/Svc/FileManager/CMakeLists.txt +++ b/Svc/FileManager/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/FileManager/Commands.fppi b/Svc/FileManager/Commands.fppi index 62ef875083..07da27a7f0 100644 --- a/Svc/FileManager/Commands.fppi +++ b/Svc/FileManager/Commands.fppi @@ -20,6 +20,7 @@ async command RemoveDirectory( @ Remove a file async command RemoveFile( fileName: string size 256 @< The file to remove + ignoreErrors: bool @< Ignore non-existent files ) \ opcode 0x03 @@ -36,3 +37,8 @@ async command AppendFile( target: string size 256 @< The name of the file to append to ) \ opcode 0x05 + +async command FileSize( + fileName: string size 256 @< The file to get the size of + ) \ + opcode 0x06 diff --git a/Svc/FileManager/Events.fppi b/Svc/FileManager/Events.fppi index 296cc5a1f5..835465a1c9 100644 --- a/Svc/FileManager/Events.fppi +++ b/Svc/FileManager/Events.fppi @@ -153,3 +153,29 @@ event RemoveFileStarted( severity activity high \ id 0x11 \ format "Removing file {}..." + +@ File size response +event FileSizeSucceeded( + fileName: string size 256 @< The name of the file + $size: U64 @< The size of the file in bytes + ) \ + severity activity high \ + id 0x12 \ + format "The size of file {} is {} B" + +@ Failed to get file size +event FileSizeError( + fileName: string size 256 @< The name of the file + status: U32 @< The error status + ) \ + severity warning high \ + id 0x13 \ + format "Failed to get the size of file {}, returned status {}" + +@ Checking file size +event FileSizeStarted( + fileName: string size 256 @< The name of the file + ) \ + severity activity high \ + id 0x14 \ + format "Checking size of file {}..." diff --git a/Svc/FileManager/FileManager.cpp b/Svc/FileManager/FileManager.cpp index 9fb0564bef..eabc57480f 100644 --- a/Svc/FileManager/FileManager.cpp +++ b/Svc/FileManager/FileManager.cpp @@ -15,7 +15,7 @@ #include "Svc/FileManager/FileManager.hpp" #include "Fw/Types/Assert.hpp" -#include "Fw/Types/BasicTypes.hpp" +#include namespace Svc { @@ -80,7 +80,8 @@ namespace Svc { RemoveFile_cmdHandler( const FwOpcodeType opCode, const U32 cmdSeq, - const Fw::CmdStringArg& fileName + const Fw::CmdStringArg& fileName, + const bool ignoreErrors ) { Fw::LogStringArg logStringFileName(fileName.toChar()); @@ -92,6 +93,16 @@ namespace Svc { logStringFileName, status ); + if (ignoreErrors == true) { + ++this->errorCount; + this->tlmWrite_Errors(this->errorCount); + this->cmdResponse_out( + opCode, + cmdSeq, + Fw::CmdResponse::OK + ); + return; + } } else { this->log_ACTIVITY_HI_RemoveFileSucceeded(logStringFileName); } @@ -213,6 +224,32 @@ namespace Svc { this->sendCommandResponse(opCode, cmdSeq, status); } + void FileManager :: + FileSize_cmdHandler( + const FwOpcodeType opCode, + const U32 cmdSeq, + const Fw::CmdStringArg& fileName + ) + { + Fw::LogStringArg logStringFileName(fileName.toChar()); + this->log_ACTIVITY_HI_FileSizeStarted(logStringFileName); + + FwSizeType size_arg; + const Os::FileSystem::Status status = + Os::FileSystem::getFileSize(fileName.toChar(), size_arg); + if (status != Os::FileSystem::OP_OK) { + this->log_WARNING_HI_FileSizeError( + logStringFileName, + status + ); + } else { + U64 size = static_cast(size_arg); + this->log_ACTIVITY_HI_FileSizeSucceeded(logStringFileName, size); + } + this->emitTelemetry(status); + this->sendCommandResponse(opCode, cmdSeq, status); + } + void FileManager :: pingIn_handler( const NATIVE_INT_TYPE portNum, diff --git a/Svc/FileManager/FileManager.hpp b/Svc/FileManager/FileManager.hpp index 09482aca06..69baf655f5 100644 --- a/Svc/FileManager/FileManager.hpp +++ b/Svc/FileManager/FileManager.hpp @@ -64,7 +64,8 @@ namespace Svc { void RemoveFile_cmdHandler( const FwOpcodeType opCode, //!< The opcode const U32 cmdSeq, //!< The command sequence number - const Fw::CmdStringArg& fileName //!< The file to remove + const Fw::CmdStringArg& fileName, //!< The file to remove + const bool ignoreErrors //!< Ignore missing files ); //! Implementation for MoveFile command handler @@ -102,6 +103,14 @@ namespace Svc { const Fw::CmdStringArg& target //! The name of the file to append to ); + //! Implementation for FileSize command handler + //! + void FileSize_cmdHandler( + const FwOpcodeType opCode, //!< The opcode + const U32 cmdSeq, //!< The command sequence number + const Fw::CmdStringArg& fileName //!< The file to get the size of + ); + //! Handler implementation for pingIn //! void pingIn_handler( diff --git a/Svc/FileManager/test/ut/Main.cpp b/Svc/FileManager/test/ut/Main.cpp index a3a09bb74e..70e690dbec 100644 --- a/Svc/FileManager/test/ut/Main.cpp +++ b/Svc/FileManager/test/ut/Main.cpp @@ -69,6 +69,16 @@ TEST(Test, appendFileFail) { tester.appendFileFail(); } +TEST(Test, fileSizeSucceed) { + Svc::Tester tester; + tester.fileSizeSucceed(); +} + +TEST(Test, fileSizeFail) { + Svc::Tester tester; + tester.fileSizeFail(); +} + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/Svc/FileManager/test/ut/Tester.cpp b/Svc/FileManager/test/ut/Tester.cpp index b24720b6ef..5927898012 100644 --- a/Svc/FileManager/test/ut/Tester.cpp +++ b/Svc/FileManager/test/ut/Tester.cpp @@ -233,7 +233,7 @@ namespace Svc { #endif // Remove test_file - this->removeFile("test_file"); + this->removeFile("test_file", false); // Assert success this->assertSuccess( @@ -259,7 +259,7 @@ namespace Svc { #endif // Attempt to remove test_file (should fail) - this->removeFile("test_file"); + this->removeFile("test_file", false); // Assert failure this->assertFailure( @@ -419,6 +419,50 @@ namespace Svc { ); } + void Tester :: + fileSizeSucceed() { +#if defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN + // Remove testing files, if they exist + this->system("rm -rf file1"); + + this->system("echo 'file1 text' > file1"); +#else + FAIL(); // Commands not implemented for this OS +#endif + Fw::CmdStringArg cmdStringFile("file1"); + this->sendCmd_FileSize( + INSTANCE, + CMD_SEQ, + cmdStringFile + ); + this->component.doDispatch(); + + this->assertSuccess(FileManager::OPCODE_FILESIZE, 2); + ASSERT_EVENTS_FileSizeSucceeded(0, "file1", 11); + } + + void Tester :: + fileSizeFail() { +#if defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN + // Remove testing files, if they exist + this->system("rm -rf file1"); +#else + FAIL(); // Commands not implemented for this OS +#endif + + Fw::CmdStringArg cmdStringFile("file1"); + this->sendCmd_FileSize( + INSTANCE, + CMD_SEQ, + cmdStringFile + ); + this->component.doDispatch(); + + this->assertFailure( + FileManager::OPCODE_FILESIZE + ); + } + // ---------------------------------------------------------------------- // Helper methods // ---------------------------------------------------------------------- @@ -530,13 +574,14 @@ namespace Svc { } void Tester :: - removeFile(const char *const fileName) + removeFile(const char *const fileName, bool ignoreErrors) { Fw::CmdStringArg cmdStringFile(fileName); this->sendCmd_RemoveFile( INSTANCE, CMD_SEQ, - cmdStringFile + cmdStringFile, + ignoreErrors ); this->component.doDispatch(); } diff --git a/Svc/FileManager/test/ut/Tester.hpp b/Svc/FileManager/test/ut/Tester.hpp index 7da9db9f02..4c231788a1 100644 --- a/Svc/FileManager/test/ut/Tester.hpp +++ b/Svc/FileManager/test/ut/Tester.hpp @@ -94,6 +94,14 @@ namespace Svc { //! void appendFileFail(); + //! File size (succeed) + //! + void fileSizeSucceed(); + + //! File size (fail) + //! + void fileSizeFail(); + private: // ---------------------------------------------------------------------- @@ -130,7 +138,8 @@ namespace Svc { //! Remove a file void removeFile( - const char *const fileName + const char *const fileName, + bool ignoreErrors ); //! Perform a shell command diff --git a/Svc/FileUplink/CMakeLists.txt b/Svc/FileUplink/CMakeLists.txt index c8ef18f404..abcc81addc 100644 --- a/Svc/FileUplink/CMakeLists.txt +++ b/Svc/FileUplink/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/FileUplink/FileUplink.cpp b/Svc/FileUplink/FileUplink.cpp index ca3aecc7a6..bff997fc6d 100644 --- a/Svc/FileUplink/FileUplink.cpp +++ b/Svc/FileUplink/FileUplink.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include namespace Svc { diff --git a/Svc/FileUplink/docs/sdd.md b/Svc/FileUplink/docs/sdd.md index c7185e452b..bef295dba0 100644 --- a/Svc/FileUplink/docs/sdd.md +++ b/Svc/FileUplink/docs/sdd.md @@ -137,7 +137,7 @@ then issue a *PacketOutOfOrder* warning reporting b. Use *writeFileDescriptor* to do the following: 1. Use the method described in § 4.1.2 of the -[CCSDS File Delivery Protocol (CFDP) Recommended Standard](http://public.ccsds.org/publications/archive/727x0b4.pdf) +[CCSDS File Delivery Protocol (CFDP) Recommended Standard](https://public.ccsds.org/Pubs/727x0b4s.pdf) to compute the checksum value for the file. 2. Compare the value computed in the previous step against the diff --git a/Svc/Framer/CMakeLists.txt b/Svc/Framer/CMakeLists.txt index fb689c4fb0..8de1326a00 100644 --- a/Svc/Framer/CMakeLists.txt +++ b/Svc/Framer/CMakeLists.txt @@ -1,14 +1,14 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME #### set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Framer.fpp" - "${CMAKE_CURRENT_LIST_DIR}/FramerComponentImpl.cpp" + "${CMAKE_CURRENT_LIST_DIR}/Framer.cpp" ) set(MOD_DEPS diff --git a/Svc/Framer/Framer.cpp b/Svc/Framer/Framer.cpp new file mode 100644 index 0000000000..3ec1cf8f1e --- /dev/null +++ b/Svc/Framer/Framer.cpp @@ -0,0 +1,90 @@ +// ====================================================================== +// \title Framer.cpp +// \author mstarch +// \brief cpp file for Framer component implementation class +// +// \copyright +// Copyright 2009-2022, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// +// ====================================================================== + +#include +#include +#include "Fw/Logger/Logger.hpp" +#include "Utils/Hash/Hash.hpp" + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction, initialization, and destruction +// ---------------------------------------------------------------------- + +Framer ::Framer(const char* const compName) + : FramerComponentBase(compName), FramingProtocolInterface(), m_protocol(nullptr), m_frame_sent(false) {} + +void Framer ::init(const NATIVE_INT_TYPE instance) { + FramerComponentBase::init(instance); +} + +Framer ::~Framer() {} + +void Framer ::setup(FramingProtocol& protocol) { + FW_ASSERT(this->m_protocol == nullptr); + this->m_protocol = &protocol; + protocol.setup(*this); +} + +void Framer ::handle_framing(const U8* const data, const U32 size, Fw::ComPacket::ComPacketType packet_type) { + FW_ASSERT(this->m_protocol != nullptr); + this->m_frame_sent = false; // Clear the flag to detect if frame was sent + this->m_protocol->frame(data, size, packet_type); + // If no frame was sent, Framer has the obligation to report success + if (this->isConnected_comStatusOut_OutputPort(0) && (!this->m_frame_sent)) { + Fw::Success status = Fw::Success::SUCCESS; + this->comStatusOut_out(0, status); + } +} + +// ---------------------------------------------------------------------- +// Handler implementations for user-defined typed input ports +// ---------------------------------------------------------------------- + +void Framer ::comIn_handler(const NATIVE_INT_TYPE portNum, Fw::ComBuffer& data, U32 context) { + this->handle_framing(data.getBuffAddr(), data.getBuffLength(), Fw::ComPacket::FW_PACKET_UNKNOWN); +} + +void Framer ::bufferIn_handler(const NATIVE_INT_TYPE portNum, Fw::Buffer& fwBuffer) { + this->handle_framing(fwBuffer.getData(), fwBuffer.getSize(), Fw::ComPacket::FW_PACKET_FILE); + // Deallocate the buffer after it was processed by the framing protocol + this->bufferDeallocate_out(0, fwBuffer); +} + +void Framer ::comStatusIn_handler(const NATIVE_INT_TYPE portNum, Fw::Success& condition) { + if (this->isConnected_comStatusOut_OutputPort(portNum)) { + this->comStatusOut_out(portNum, condition); + } +} + +// ---------------------------------------------------------------------- +// Framing protocol implementations +// ---------------------------------------------------------------------- + +void Framer ::send(Fw::Buffer& outgoing) { + FW_ASSERT(!this->m_frame_sent); // Prevent multiple sends per-packet + const Drv::SendStatus sendStatus = this->framedOut_out(0, outgoing); + if (sendStatus.e != Drv::SendStatus::SEND_OK) { + // Note: if there is a data sending problem, an EVR likely wouldn't + // make it down. Log the issue in hopes that + // someone will see it. + Fw::Logger::logMsg("[ERROR] Failed to send framed data: %d\n", sendStatus.e); + } + this->m_frame_sent = true; // A frame was sent +} + +Fw::Buffer Framer ::allocate(const U32 size) { + return this->framedAllocate_out(0, size); +} + +} // end namespace Svc diff --git a/Svc/Framer/Framer.fpp b/Svc/Framer/Framer.fpp index d5576eda33..3017d2380f 100644 --- a/Svc/Framer/Framer.fpp +++ b/Svc/Framer/Framer.fpp @@ -1,25 +1,49 @@ module Svc { - @ A component for framing unframed input + @ A component for framing input for transmission to the ground passive component Framer { - @ Mutexed input communication port + # ---------------------------------------------------------------------- + # Receiving packets + # ---------------------------------------------------------------------- + + @ Port for receiving data packets of any type stored in statically-sized + @ Fw::Com buffers guarded input port comIn: Fw.Com - @ Mutexed input Buffer send port + @ Port for receiving file packets stored in dynamically-sized + @ Fw::Buffer objects guarded input port bufferIn: Fw.BufferSend - @ Buffer send output port + # ---------------------------------------------------------------------- + # Allocation and deallocation of buffers + # ---------------------------------------------------------------------- + + @ Port for deallocating buffers received on bufferIn, after + @ copying packet data to the frame buffer output port bufferDeallocate: Fw.BufferSend - @ Framed allocate output port + @ Port for allocating buffers to hold framed data output port framedAllocate: Fw.BufferGet - @ Framed output port + # ---------------------------------------------------------------------- + # Sending frame data + # ---------------------------------------------------------------------- + + @ Port for sending buffers containing framed data. Ownership of the + @ buffer passes to the receiver. output port framedOut: Drv.ByteStreamSend - @ Time get port - time get port timeGet + # ---------------------------------------------------------------------- + # Handling of of ready signals + # ---------------------------------------------------------------------- + + @ Port receiving the general status from the downstream component + @ indicating it is ready or not-ready for more input + guarded input port comStatusIn: Fw.SuccessCondition + + @ Port receiving indicating the status of framer for receiving more data + output port comStatusOut: Fw.SuccessCondition } diff --git a/Svc/Framer/Framer.hpp b/Svc/Framer/Framer.hpp index 0b488e53e6..88f09af8c9 100644 --- a/Svc/Framer/Framer.hpp +++ b/Svc/Framer/Framer.hpp @@ -1,17 +1,118 @@ // ====================================================================== -// Framer.hpp -// Standardization header for Framer +// \title Framer.hpp +// \author mstarch, bocchino +// \brief hpp file for Framer component implementation class +// +// \copyright +// Copyright 2009-2022, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. +// // ====================================================================== #ifndef Svc_Framer_HPP #define Svc_Framer_HPP -#include "Svc/Framer/FramerComponentImpl.hpp" +#include "Svc/Framer/FramerComponentAc.hpp" +#include "Svc/FramingProtocol/FramingProtocol.hpp" +#include "Svc/FramingProtocol/FramingProtocolInterface.hpp" namespace Svc { +/** + * \brief Generic framing component using FramingProtocol implementation for actual framing + * + * Framing component used to take Com and File packets and frame serialize them using a + * framing protocol specified in a FramingProtocol instance. The instance must be supplied + * using the `setup` method. + * + * Using this component, projects can implement and supply a fresh FramingProtocol implementation + * without changing the reference topology. + */ +class Framer : public FramerComponentBase, public FramingProtocolInterface { + public: + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- - typedef FramerComponentImpl Framer; + //! Construct object Framer + //! + Framer(const char* const compName /*!< The component name*/ + ); -} + //! Initialize object Framer + //! + void init(const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ + ); + + //! \brief Setup this component with a supplied framing protocol + //! + void setup(FramingProtocol& protocol /*!< Protocol used in framing */); + + //! Destroy object Framer + //! + ~Framer(); + + PRIVATE: + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for comIn + //! + void comIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::ComBuffer& data, /*!< Buffer containing packet data*/ + U32 context /*!< Call context value; meaning chosen by user*/ + ); + + //! Handler implementation for bufferIn + //! + void bufferIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Buffer& fwBuffer /*!< The buffer*/ + ); + + //! Handler implementation for comStatusIn + //! + void comStatusIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Success& condition /*!< The condition*/); + + // ---------------------------------------------------------------------- + // Implementation of FramingProtocolInterface + // ---------------------------------------------------------------------- + + //! \brief Allocation callback used to request memory for the framer + //! + //! Method used by the FramingProtocol to allocate memory for the framed buffer. Framing + //! typically adds tokens on the beginning and end of the raw data so it must allocate new space + //! to place those and a copy of the data in. + //! + //! \param size: size of allocation + //! \return Fw::Buffer containing allocation to write into + Fw::Buffer allocate(const U32 size); + + //! Send implementation + //! + void send(Fw::Buffer& outgoing //!< The buffer to send + ); + + // ---------------------------------------------------------------------- + // Helper functions + // ---------------------------------------------------------------------- + + //! \brief helper function to handle framing of the raw data + //! + void handle_framing(const U8* const data, const U32 size, Fw::ComPacket::ComPacketType packet_type); + + // ---------------------------------------------------------------------- + // Member variables + // ---------------------------------------------------------------------- + + //! The FramingProtocol implementation + FramingProtocol* m_protocol; + + //! Flag determining if at least one frame was sent during framing + bool m_frame_sent; +}; + +} // end namespace Svc #endif diff --git a/Svc/Framer/FramerComponentImpl.cpp b/Svc/Framer/FramerComponentImpl.cpp deleted file mode 100644 index 576de36aa0..0000000000 --- a/Svc/Framer/FramerComponentImpl.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// ====================================================================== -// \title FramerComponentImpl.cpp -// \author mstarch -// \brief cpp file for Framer component implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#include -#include "Fw/Logger/Logger.hpp" -#include "Fw/Types/BasicTypes.hpp" -#include "Utils/Hash/Hash.hpp" - -namespace Svc { - - - -// ---------------------------------------------------------------------- -// Construction, initialization, and destruction -// ---------------------------------------------------------------------- - -FramerComponentImpl ::FramerComponentImpl(const char* const compName) : FramerComponentBase(compName), FramingProtocolInterface(), -m_protocol(nullptr) {} - -void FramerComponentImpl ::init(const NATIVE_INT_TYPE instance) { - FramerComponentBase::init(instance); -} - -FramerComponentImpl ::~FramerComponentImpl() {} - -void FramerComponentImpl ::setup(FramingProtocol& protocol) { - FW_ASSERT(m_protocol == nullptr); - m_protocol = &protocol; - protocol.setup(*this); -} - -// ---------------------------------------------------------------------- -// Handler implementations for user-defined typed input ports -// ---------------------------------------------------------------------- - -void FramerComponentImpl ::comIn_handler(const NATIVE_INT_TYPE portNum, Fw::ComBuffer& data, U32 context) { - FW_ASSERT(m_protocol != nullptr); - m_protocol->frame(data.getBuffAddr(), data.getBuffLength(), Fw::ComPacket::FW_PACKET_UNKNOWN); -} - -void FramerComponentImpl ::bufferIn_handler(const NATIVE_INT_TYPE portNum, Fw::Buffer& fwBuffer) { - FW_ASSERT(m_protocol != nullptr); - m_protocol->frame(fwBuffer.getData(), fwBuffer.getSize(), Fw::ComPacket::FW_PACKET_FILE); - bufferDeallocate_out(0, fwBuffer); -} - -void FramerComponentImpl ::send(Fw::Buffer& outgoing) { - Drv::SendStatus sendStatus = framedOut_out(0, outgoing); - if (sendStatus.e != Drv::SendStatus::SEND_OK) { - // Note: if there is a data sending problem, an EVR likely wouldn't make it down. Log the issue in hopes that - // someone will see it. - Fw::Logger::logMsg("[ERROR] Failed to send framed data: %d\n", sendStatus.e); - } -} - -Fw::Buffer FramerComponentImpl ::allocate(const U32 size) { - this->getTime(); - return framedAllocate_out(0, size); -} - -} // end namespace Svc diff --git a/Svc/Framer/FramerComponentImpl.hpp b/Svc/Framer/FramerComponentImpl.hpp deleted file mode 100644 index f95cfa699e..0000000000 --- a/Svc/Framer/FramerComponentImpl.hpp +++ /dev/null @@ -1,91 +0,0 @@ -// ====================================================================== -// \title FramerComponentImpl.hpp -// \author mstarch -// \brief hpp file for Framer component implementation class -// -// \copyright -// Copyright 2009-2021, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef Framer_HPP -#define Framer_HPP - -#include "Svc/Framer/FramerComponentAc.hpp" -#include "Svc/FramingProtocol/FramingProtocol.hpp" -#include "Svc/FramingProtocol/FramingProtocolInterface.hpp" - -namespace Svc { -/** - * \brief Generic framing component using FramingProtocol implementation for actual framing - * - * Framing component used to take Com and File packets and frame serialize them using a - * framing protocol specified in a FramingProtocol instance. The instance must be supplied - * using the `setup` method. - * - * Using this component, projects can implement and supply a fresh FramingProtocol implementation - * without changing the reference topology. - */ -class FramerComponentImpl : public FramerComponentBase, public FramingProtocolInterface { - public: - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - //! Construct object Framer - //! - FramerComponentImpl(const char* const compName /*!< The component name*/ - ); - - //! Initialize object Framer - //! - void init(const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ - ); - - //! \brief Setup this component with a supplied framing protocol - //! - void setup(FramingProtocol& protocol /*!< Protocol used in framing */); - - //! Destroy object Framer - //! - ~FramerComponentImpl(); - - //! \brief Allocation callback used to request memory for the framer - //! - //! Method used by the FramingProtocol to allocate memory for the framed buffer. Framing - //! typically adds tokens on the beginning and end of the raw data so it must allocate new space - //! to place those and a copy of the data in. - //! - //! \param size: size of allocation - //! \return Fw::Buffer containing allocation to write into - Fw::Buffer allocate(const U32 size); - - PRIVATE: - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - //! Handler implementation for comIn - //! - void comIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::ComBuffer& data, /*!< Buffer containing packet data*/ - U32 context /*!< Call context value; meaning chosen by user*/ - ); - - //! Handler implementation for bufferIn - //! - void bufferIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Buffer& fwBuffer); - - //! Send helper implementation - //! - void send(Fw::Buffer& outgoing); - - FramingProtocol* m_protocol; -}; - -} // end namespace Svc - -#endif diff --git a/Svc/Framer/docs/img/.fpv-env b/Svc/Framer/docs/img/.fpv-env new file mode 100644 index 0000000000..ff60caacf4 --- /dev/null +++ b/Svc/Framer/docs/img/.fpv-env @@ -0,0 +1 @@ +DATA_FOLDER=top/ diff --git a/Svc/Framer/docs/img/Framer.png b/Svc/Framer/docs/img/Framer.png new file mode 100644 index 0000000000..bf86d6b493 Binary files /dev/null and b/Svc/Framer/docs/img/Framer.png differ diff --git a/Svc/Framer/docs/img/class_diagram_framer.png b/Svc/Framer/docs/img/class_diagram_framer.png deleted file mode 100644 index a598c9b1ea..0000000000 Binary files a/Svc/Framer/docs/img/class_diagram_framer.png and /dev/null differ diff --git a/Svc/Framer/docs/img/framer_example_1.png b/Svc/Framer/docs/img/framer_example_1.png deleted file mode 100644 index 96c5499bea..0000000000 Binary files a/Svc/Framer/docs/img/framer_example_1.png and /dev/null differ diff --git a/Svc/Framer/docs/img/framer_example_2.png b/Svc/Framer/docs/img/framer_example_2.png deleted file mode 100644 index 9de8e3a279..0000000000 Binary files a/Svc/Framer/docs/img/framer_example_2.png and /dev/null differ diff --git a/Svc/Framer/docs/img/top/event.json b/Svc/Framer/docs/img/top/event.json new file mode 100644 index 0000000000..5267fe8c9f --- /dev/null +++ b/Svc/Framer/docs/img/top/event.json @@ -0,0 +1,48 @@ +{ + "columns" : [ + [ + { + "instanceName" : "eventLogger", + "inputPorts" : [], + "outputPorts" : [ + { + "name" : "PktSend", + "portNumbers" : [ + 0 + ] + } + ] + } + ], + [ + { + "instanceName" : "framer", + "inputPorts" : [ + { + "name" : "comIn", + "portNumbers" : [ + 0 + ] + } + ], + "outputPorts" : [] + } + ] + ], + "connections" : [ + [ + [ + 0, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0 + ] + ] + ] +} diff --git a/Svc/Framer/docs/img/top/event.png b/Svc/Framer/docs/img/top/event.png new file mode 100644 index 0000000000..f585289878 Binary files /dev/null and b/Svc/Framer/docs/img/top/event.png differ diff --git a/Svc/Framer/docs/img/top/event.txt b/Svc/Framer/docs/img/top/event.txt new file mode 100644 index 0000000000..01cc5916c8 --- /dev/null +++ b/Svc/Framer/docs/img/top/event.txt @@ -0,0 +1,6 @@ +eventLogger +PktSend +0 +framer +comIn +0 diff --git a/Svc/Framer/docs/img/top/framed.json b/Svc/Framer/docs/img/top/framed.json new file mode 100644 index 0000000000..300491b337 --- /dev/null +++ b/Svc/Framer/docs/img/top/framed.json @@ -0,0 +1,109 @@ +{ + "columns" : [ + [ + { + "instanceName" : "framer", + "inputPorts" : [], + "outputPorts" : [ + { + "name" : "framedOut", + "portNumbers" : [ + 0 + ] + }, + { + "name" : "framedAllocate", + "portNumbers" : [ + 0 + ] + } + ] + } + ], + [ + { + "instanceName" : "comm", + "inputPorts" : [ + { + "name" : "send", + "portNumbers" : [ + 0 + ] + } + ], + "outputPorts" : [ + { + "name" : "deallocate", + "portNumbers" : [ + 0 + ] + } + ] + } + ], + [ + { + "instanceName" : "buffMgr", + "inputPorts" : [ + { + "name" : "bufferSendIn", + "portNumbers" : [ + 0 + ] + }, + { + "name" : "bufferGetCallee", + "portNumbers" : [ + 0 + ] + } + ], + "outputPorts" : [] + } + ] + ], + "connections" : [ + [ + [ + 0, + 0, + 1, + 0 + ], + [ + 2, + 0, + 1, + 0 + ] + ], + [ + [ + 1, + 0, + 0, + 0 + ], + [ + 2, + 0, + 0, + 0 + ] + ], + [ + [ + 0, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0 + ] + ] + ] +} diff --git a/Svc/Framer/docs/img/top/framed.png b/Svc/Framer/docs/img/top/framed.png new file mode 100644 index 0000000000..7813c271fb Binary files /dev/null and b/Svc/Framer/docs/img/top/framed.png differ diff --git a/Svc/Framer/docs/img/top/framed.txt b/Svc/Framer/docs/img/top/framed.txt new file mode 100644 index 0000000000..3dabc9a9f3 --- /dev/null +++ b/Svc/Framer/docs/img/top/framed.txt @@ -0,0 +1,20 @@ +framer +framedAllocate +0 +buffMgr +bufferGetCallee +0 + +comm +deallocate +0 +buffMgr +bufferSendIn +0 + +framer +framedOut +0 +comm +send +0 diff --git a/Svc/Framer/docs/img/top/framer-file.json b/Svc/Framer/docs/img/top/framer-file.json new file mode 100644 index 0000000000..1c35a02fbd --- /dev/null +++ b/Svc/Framer/docs/img/top/framer-file.json @@ -0,0 +1,76 @@ +{ + "columns" : [ + [ + { + "instanceName" : "fileDownlink", + "inputPorts" : [ + { + "name" : "bufferReturn", + "portNumbers" : [ + 0 + ] + } + ], + "outputPorts" : [ + { + "name" : "bufferSendOut", + "portNumbers" : [ + 0 + ] + } + ] + } + ], + [ + { + "instanceName" : "framer", + "inputPorts" : [ + { + "name" : "bufferIn", + "portNumbers" : [ + 0 + ] + } + ], + "outputPorts" : [ + { + "name" : "bufferDeallocate", + "portNumbers" : [ + 0 + ] + } + ] + } + ] + ], + "connections" : [ + [ + [ + 0, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0 + ] + ], + [ + [ + 1, + 0, + 0, + 0 + ], + [ + 0, + 0, + 0, + 0 + ] + ] + ] +} diff --git a/Svc/Framer/docs/img/top/framer-file.png b/Svc/Framer/docs/img/top/framer-file.png new file mode 100644 index 0000000000..7d284aa0d8 Binary files /dev/null and b/Svc/Framer/docs/img/top/framer-file.png differ diff --git a/Svc/Framer/docs/img/top/framer-file.txt b/Svc/Framer/docs/img/top/framer-file.txt new file mode 100644 index 0000000000..400fc3049f --- /dev/null +++ b/Svc/Framer/docs/img/top/framer-file.txt @@ -0,0 +1,13 @@ +fileDownlink +bufferSendOut +0 +framer +bufferIn +0 + +framer +bufferDeallocate +0 +fileDownlink +bufferReturn +0 diff --git a/Svc/Framer/docs/img/top/hub.json b/Svc/Framer/docs/img/top/hub.json new file mode 100644 index 0000000000..17d0fec967 --- /dev/null +++ b/Svc/Framer/docs/img/top/hub.json @@ -0,0 +1,63 @@ +{ + "columns" : [ + [ + { + "instanceName" : "hub", + "inputPorts" : [], + "outputPorts" : [ + { + "name" : "portOut", + "portNumbers" : [ + 0, + 1 + ] + } + ] + } + ], + [ + { + "instanceName" : "framer", + "inputPorts" : [ + { + "name" : "comIn", + "portNumbers" : [ + 0 + ] + } + ], + "outputPorts" : [] + } + ] + ], + "connections" : [ + [ + [ + 0, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0 + ] + ], + [ + [ + 0, + 0, + 0, + 1 + ], + [ + 1, + 0, + 0, + 0 + ] + ] + ] +} diff --git a/Svc/Framer/docs/img/top/hub.png b/Svc/Framer/docs/img/top/hub.png new file mode 100644 index 0000000000..510126bc9d Binary files /dev/null and b/Svc/Framer/docs/img/top/hub.png differ diff --git a/Svc/Framer/docs/img/top/hub.txt b/Svc/Framer/docs/img/top/hub.txt new file mode 100644 index 0000000000..87a7c7d508 --- /dev/null +++ b/Svc/Framer/docs/img/top/hub.txt @@ -0,0 +1,13 @@ +hub +portOut +0 +framer +comIn +0 + +hub +portOut +1 +framer +comIn +0 diff --git a/Svc/Framer/docs/img/top/tlm.json b/Svc/Framer/docs/img/top/tlm.json new file mode 100644 index 0000000000..2a172d5de5 --- /dev/null +++ b/Svc/Framer/docs/img/top/tlm.json @@ -0,0 +1,48 @@ +{ + "columns" : [ + [ + { + "instanceName" : "chanTlm", + "inputPorts" : [], + "outputPorts" : [ + { + "name" : "PktSend", + "portNumbers" : [ + 0 + ] + } + ] + } + ], + [ + { + "instanceName" : "framer", + "inputPorts" : [ + { + "name" : "comIn", + "portNumbers" : [ + 0 + ] + } + ], + "outputPorts" : [] + } + ] + ], + "connections" : [ + [ + [ + 0, + 0, + 0, + 0 + ], + [ + 1, + 0, + 0, + 0 + ] + ] + ] +} diff --git a/Svc/Framer/docs/img/top/tlm.png b/Svc/Framer/docs/img/top/tlm.png new file mode 100644 index 0000000000..66e234a24e Binary files /dev/null and b/Svc/Framer/docs/img/top/tlm.png differ diff --git a/Svc/Framer/docs/img/top/tlm.txt b/Svc/Framer/docs/img/top/tlm.txt new file mode 100644 index 0000000000..11ed0e9ff0 --- /dev/null +++ b/Svc/Framer/docs/img/top/tlm.txt @@ -0,0 +1,6 @@ +chanTlm +PktSend +0 +framer +comIn +0 diff --git a/Svc/Framer/docs/sdd.md b/Svc/Framer/docs/sdd.md index 128ac8e56c..229c601e7e 100644 --- a/Svc/Framer/docs/sdd.md +++ b/Svc/Framer/docs/sdd.md @@ -1,46 +1,322 @@ \page SvcFramerComponent Svc::Framer Component -# Svc::Framer Framer Component +# Svc::Framer (Passive Component) -The Framer component is used to frame packets for downlink. It translates between the service layer (typically TlmChan, ActiveLogger, and FileDownlink) and the driver layer (Drv), where service typically deals with F´ types and the driver layer deals in streams of bytes. Framer serializes the F´ types into a stream of bytes and adds header/footer information to ensure transmission integrity. As an argument to `setup()` function Framer accepts a reference to a `FramingProtocol` to do the actual header/data/footer serialization. Users may substitute the framing protocol without changing the F´ topology hook-ups. +## 1. Introduction -## Usage Examples -When using Framer component, the manager component (typically a service layer or a generic hub) initiates the transfer of data by calling bufferIn port. The Framer component will perform the serialization per `FramingProtocol` and will transfer the stream via bufferOut port. +`Svc::Framer` is a passive component. +It is part of the standard path for F Prime data downlink. +It accepts data packets from service layer components, for example +instances of [`Svc::TlmChan`](../../TlmChan/docs/sdd.md), +[`Svc::ActiveLogger`](../../ActiveLogger/docs/sdd.md), +or [`Svc::FileDownlink`](../../FileDownlink/docs/sdd.md). +For each packet _P_ received, it wraps _P_ in a frame _F_ +and sends _F_ to a byte stream driver that downlinks frames, +for example, [`Drv::TcpClient`](../../../Drv/TcpClient/docs/sdd.md). -The following diagram is an example of framer usage with chanTlm and eventLogger: +When instantiating `Framer`, you must provide an implementation +of [`Svc::FramingProtocol`](../../FramingProtocol/docs/sdd.md). +This implementation specifies exactly what is +in each frame; typically it is a frame header, a data packet, and a hash value. +You can use the standard F Prime downlink protocol implementation. +This implementation works with the F Prime ground data system (GDS). -![framer_example](./img/framer_example_1.png) +`Svc::Framer` is designed to act alongside instances of the +[communication adapter interface](https://nasa.github.io/fprime/Design/communication-adapter-interface.html). In order +to work well with communication adapters, `Svc::Framer` implements the framer status +[protocol](https://nasa.github.io/fprime/Design/communication-adapter-interface.html#framer-status-protocol). -The following diagram is an example of framer usage with a generic hub and TcpClient: +## 2. Assumptions -![framer_example](./img/framer_example_2.png) +1. For any deployment _D_ that uses an instance _I_ of `Framer`, the + framing protocol used with _I_ matches the downlink protocol of + any ground system that receives frames from _I_. -The following is a typical example of Framer usage: +## 3. Requirements -```c++ -Svc::FprimeFraming framing_obj; // Framing protocol obj; -Svc::FramerComponentImpl downlink_obj("Framer"); // Framer obj +| Requirement | Description | Rationale | Verification Method | +|------------------|----------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------| +| SVC-FRAMER-001 | `Svc::Framer` shall accept data packets of any type stored in `Fw::Com` buffers. | `Svc::ActiveLogger` and `Svc::ChanTlm` emit packets as `Fw::Com` buffers. | Unit test | +| SVC-FRAMER-002 | `Svc::Framer` shall accept file packets stored in `Fw::Buffer` objects. | `Svc::FileDownlink` emits packets as `Fw::Buffer` objects. | Unit test | +| SVC-FRAMER-003 | `Svc::Framer` shall use an instance of `Svc::FramingProtocol`, supplied when the component is instantiated, to wrap packets in frames. | The purpose of `Svc::Framer` is to frame data packets. Using the `Svc::FramingProtocol` interface allows the same Framer component to operate with different protocols. | Unit test | +| SVC-FRAMER-004 | `Svc::Framer` shall emit a status of `Fw::Success::SUCCESS` when no framed packets were sent in response to incoming buffer. | `Svc::Framer` implements the framer status protocol. | Unit Test | +| SVC-FRAMER-005 | `Svc::Framer` shall forward `Fw::Success` status messages received | `Svc::Framer` implements the framer status protocol. | Unit Test | -downlink_obj.init(0); -downlink_obj.setup(framing_obj); +## 4. Design -... +### 4.1. Component Diagram -Fw::Buffer buf; // This could be data from bufferIn port -downlink_obj.send(buf); // Send framed buffer to a port connected to bufferOut +The diagram below shows the `Framer` component. + +![Framer Component](./img/Framer.png) + +### 4.2. Ports + +| Kind | Name | Port Type | Usage | +|-----------------|--------------------|-----------------------|---------------------------------------------------------------------------------------------------| +| `guarded input` | `comIn` | `Fw.Com` | Port for receiving data packets of any type stored in statically-sized Fw::Com buffers | +| `guarded input` | `bufferIn` | `Fw.BufferSend` | Port for receiving file packets stored in dynamically-sized Fw::Buffer objects | +| `guarded input` | `comStatusIn` | `Fw.SuccessCondition` | Port for receiving status of last send for implementing communication adapter interface protocol | +| `output` | `bufferDeallocate` | `Fw.BufferSend` | Port for deallocating buffers received on bufferIn, after copying packet data to the frame buffer | +| `output` | `framedAllocate` | `Fw.BufferGet` | Port for allocating buffers to hold framed data | +| `output` | `framedOut` | `Drv.ByteStreamSend` | Port for sending buffers containing framed data. Ownership of the buffer passes to the receiver. | +| `output` | `comStatusOut` | `Fw.SuccessCondition` | Port for sending communication adapter interface protocol status messages | + + +### 4.3. Derived Classes + +`Framer` is derived from `FramerComponentBase` as usual. +It is also derived (via C++ multiple inheritance) from +[`Svc::FramingProtocolInterface`](../../FramingProtocol/docs/sdd.md). +The multiple inheritance makes the `Framer` instance into the +instance of `Svc::FramingProtocolInterface` that is required +to use `Svc::FramingProtocol`. +See below for a description of how `Framer` implements +`FramingProtocolInterface`. + +Here is a class diagram for `Framer`: + +```mermaid +classDiagram + ObjBase <|-- PassiveComponentBase + PassiveComponentBase <|-- FramerComponentBase + FramerComponentBase <|-- Framer + FramingProtocolInterface <|-- Framer ``` -## Class Diagram +### 4.4. State + +`Framer` maintains the following state: + +1. `m_protocol`: A pointer to the implementation of `FramingProtocol` + used for framing. + +### 4.5. Header File Configuration + +None. + + +### 4.6. Runtime Setup + +To set up an instance of `Framer`, you do the following: + +1. Call the constructor and the `init` method in the usual way +for an F Prime passive component. + +1. Call the `setup` method, passing in an instance _P_ of `Svc::FramingProtocol`. +The `setup` method does the following: + + 1. Store a pointer to _P_ in `m_protocol`. + + 1. Pass `*this` into the setup method for _P_. + As noted above, `*this` + is the instance of `Svc::FramingProtocolInterface` + used by _P_. + +For an example of setting up a `Framer` instance, see the +`downlink` instance in [`Ref/Top/instances.fpp`](../../../Ref/Top/instances.fpp). + +### 4.7. Port Handlers + +#### 4.7.1. comIn + +The `comIn` port handler receive a reference to an `Fw::Com` buffer _B_ +and an integer context value. +It calls the `frame` method of `m_protocol`, passing in the +address and length of _B_ and the packet type +`Fw::ComPacket::FW_PACKET_UNKNOWN`. + +#### 4.7.2. bufferIn + +The `bufferIn` port handler receives a reference to an `Fw::Buffer` +object _B_. +It calls the `frame` method of `m_protocol`, passing in the +data address and size of _B_ and the packet type +`Fw::ComPacket::FW_PACKET_FILE`. + +#### 4.7.2. comStatusIn + +The `comStatusIn` port handler receives com status messages and forwards them out `comStatusOut`. + + +### 4.8. Implementation of Svc::FramingProtocolInterface + + +#### 4.8.1. allocate + +The implementation of `allocate` invokes `framedAllocate`. + + +#### 4.8.2. send + +The implementation of `send` takes a reference to an `Fw::Buffer` +_B_ representing framed data and does the following: + +1. Invoke `framedOut`, passing in _B_ as the argument. + +1. Check the return status of the invocation. +If the return status is not `Drv::SendStatus::SEND_OK`, then +use `Fw::Logger::logMsg` to log an error message. +Don't send an event report in this case, because downlink is +apparently not working. + +## 5. Ground Interface + +None. + +If an error occurs, `Framer` writes to the system log. +The rationale is that if something is wrong with the framing, then +downlink of events is unlikely to work. + +## 6. Example Uses -![classdiagram](./img/class_diagram_framer.png) + +### 6.1. Topology Diagrams -## Requirements +The following topology diagrams show how to connect `Svc::Framer` +to a telemetry database, an event collector, a file downlink component, +and a byte stream driver. +The diagrams use the following instances: -| Name | Description | Validation | -|---|---|---| -| TBD | TBD | TBD | +* `comm`: An instance of +[`Drv::ByteStreamDriverModel`](../../../Drv/ByteStreamDriverModel/docs/sdd.md), for example +[`Drv::TcpClient`](../../../Drv/TcpClient/docs/sdd.md). -## Change Log +* `buffMgr`: An instance of [`Svc::BufferManager`](../../BufferManager/docs/sdd.md) + +* `fileDownlink`: An instance of [`Svc::FileDownlink`](../../FileDownlink/docs/sdd.md). + +* `framer`: An instance of `Svc::Framer`. + +* `chanTlm`: An instance of [`Svc::TlmChan`](../../TlmChan/docs/sdd.md). + +* `eventLogger`: An instance of [`Svc::ActiveLogger`](../../ActiveLogger/docs/sdd.md). + +**Topology 1: Telemetry packets:** + +
+ +
+ +The `chanTlm` instance sends telemetry packets to the `framer` instance. + +**Topology 2: Event packets:** + +
+ +
+ +The `eventLogger` instance sends event packets to the `framer` instance. + +**Topology 3: File packets:** + +
+ +
+ +The `fileDownlink` instance sends a sequence of file packets, +representing a complete file, to the `framer` instance. +The sending happens in the following sequence: + +1. `fileDownlink` sends a buffer _PB_ containing a file packet. + +1. `framer` receives and processes _PB_. +When it is done, it returns _PB_ to `fileDownlink`. + +1. Upon receipt of _PB_, if another file packet is available, +`fileDownlink` sends it. + +Exchanging the buffer controls the rate at which +`fileDownlink` sends file packets. +It ensures that the rate does not exceed the rate at which `framer` +can handle the packets. + +**Topology 4: Framed data:** + +
+ +
+ +`framer` allocates frame buffers from `buffMgr`. +It sends buffers containing frames to `comm`. +`comm` processes the buffers and sends them to +`buffMgr` for deallocation. + +### 6.2. Sequence Diagrams + +In the following diagrams, open vertical rectangles represent threads. +Vertical dashed lines represent component code. +Solid horizontal arrows represent synchronous port invocations, and open +horizontal arrows represent asynchronous port invocations. + +These diagrams assume that, in the +implementation of `Svc::FramingProtocol` +passed in at initialization, +each downlink frame contains a single packet. +This is a common use case; for example, the F Prime standard downlink protocol +is implemented this way. + +#### 6.2.1. Sending a Telemetry Packet + +The following diagram shows what happens when `chanTlm` +sends a telemetry packet to `framer`. + +```mermaid +sequenceDiagram + activate chanTlm + chanTlm->>framer: Send telemetry packet P [comIn] + framer->>buffMgr: Allocate frame buffer B [framedAllocate] + buffMgr-->>framer: Return B + framer->>framer: Frame P into B + framer-)comm: Send B [framedOut] + comm->>comm: Downlink frame + comm->>buffMgr: Deallocate B + buffMgr-->>comm: + comm-->>framer: + framer-->>chanTlm: + deactivate chanTlm +``` + +#### 6.2.2. Sending an Event Packet + +The following diagram shows what happens when `eventLogger` +sends an event packet to `framer`. + +```mermaid +sequenceDiagram + activate eventLogger + eventLogger->>framer: Send event packet P [comIn] + framer->>buffMgr: Allocate frame buffer B [framedAllocate] + buffMgr-->>framer: Return B + framer->>framer: Frame P into B + framer-)comm: Send B [framedOut] + comm->>comm: Downlink frame + comm->>buffMgr: Deallocate B + buffMgr-->>comm: + comm-->>framer: + framer-->>eventLogger: + deactivate eventLogger +``` + +#### 6.2.3. Sending a File Packet + +The following diagram shows what happens when `fileDownlink` +sends a file packet to `framer`. + +```mermaid +sequenceDiagram + activate fileDownlink + fileDownlink->>framer: Send file packet buffer PB [bufferIn] + framer->>buffMgr: Allocate frame buffer B [framedAllocate] + buffMgr-->>framer: Return B + framer->>framer: Frame P into B + framer-)comm: Send B [framedOut] + comm->>comm: Downlink frame + comm->>buffMgr: Deallocate B + buffMgr-->>comm: + comm-->>framer: + framer->>fileDownlink: Return PB [bufferDeallocate] + fileDownlink-->>framer: + framer-->>fileDownlink: + deactivate fileDownlink +``` -| Date | Description | -|---|---| -| 2021-01-29 | Initial Draft | \ No newline at end of file diff --git a/Svc/Framer/test/ut/TestMain.cpp b/Svc/Framer/test/ut/TestMain.cpp index f86598850d..8e2297a7a1 100644 --- a/Svc/Framer/test/ut/TestMain.cpp +++ b/Svc/Framer/test/ut/TestMain.cpp @@ -2,27 +2,74 @@ // TestMain.cpp // ---------------------------------------------------------------------- +#include "Fw/Test/UnitTest.hpp" +#include "Os/Log.hpp" #include "Tester.hpp" +// Enable the console logging provided by Os::Log +Os::Log logger; + TEST(Nominal, Com) { + COMMENT("Send one Fw::Com buffer to the framer (nominal behavior)"); + REQUIREMENT("SVC-FRAMER-001"); + REQUIREMENT("SVC-FRAMER-003"); Svc::Tester tester; - tester.test_incoming(); + tester.test_com(); } TEST(Nominal, Buffer) { + COMMENT("Send one Fw::Buffer to the framer (nominal behavior)"); + REQUIREMENT("SVC-FRAMER-002"); + REQUIREMENT("SVC-FRAMER-003"); Svc::Tester tester; tester.test_buffer(); } TEST(Nominal, ManySends) { + COMMENT("Send several buffers"); + REQUIREMENT("SVC-FRAMER-001"); + REQUIREMENT("SVC-FRAMER-002"); + REQUIREMENT("SVC-FRAMER-003"); Svc::Tester tester; - tester.test_incoming(27); + tester.test_com(27); tester.test_buffer(27); - tester.test_incoming(31); + tester.test_com(31); tester.test_buffer(31); } -int main(int argc, char **argv) { +TEST(Nominal, StatusPassThrough) { + COMMENT("Ensure status pass-through"); + REQUIREMENT("SVC-FRAMER-004"); + Svc::Tester tester; + tester.test_status_pass_through(); +} + +TEST(Nominal, NoSendStatus) { + COMMENT("Ensure status on no-send"); + REQUIREMENT("SVC-FRAMER-003"); + Svc::Tester tester; + tester.test_no_send_status(); +} + +TEST(SendError, Buffer) { + COMMENT("Send one Fw::Buffer to the framer (send error)"); + REQUIREMENT("SVC-FRAMER-002"); + REQUIREMENT("SVC-FRAMER-003"); + Svc::Tester tester; + tester.setSendStatus(Drv::SendStatus::SEND_ERROR); + tester.test_buffer(); +} + +TEST(SendError, Com) { + COMMENT("Send one Fw::Com buffer to the framer (send error)"); + REQUIREMENT("SVC-FRAMER-001"); + REQUIREMENT("SVC-FRAMER-003"); + Svc::Tester tester; + tester.setSendStatus(Drv::SendStatus::SEND_ERROR); + tester.test_com(); +} + +int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/Svc/Framer/test/ut/Tester.cpp b/Svc/Framer/test/ut/Tester.cpp index e03f6aa2b1..05f14c7d5f 100644 --- a/Svc/Framer/test/ut/Tester.cpp +++ b/Svc/Framer/test/ut/Tester.cpp @@ -1,10 +1,10 @@ // ====================================================================== // \title Framer.hpp -// \author mstarch +// \author mstarch, bocchino // \brief cpp file for Framer test harness implementation class // // \copyright -// Copyright 2009-2015, by the California Institute of Technology. +// Copyright 2009-2022, by the California Institute of Technology. // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. // @@ -17,13 +17,16 @@ namespace Svc { -Tester::MockFramer::MockFramer(Tester& parent) : m_parent(parent) {} +Tester::MockFramer::MockFramer(Tester& parent) : m_parent(parent), m_do_not_send(false) {} void Tester::MockFramer::frame(const U8* const data, const U32 size, Fw::ComPacket::ComPacketType packet_type) { - Fw::Buffer buffer(const_cast(data), size); - m_parent.check_last_buffer(buffer); - Fw::Buffer allocated = m_interface->allocate(size); - m_interface->send(allocated); + // When testing without the send case, disable all mock functions + if (!m_do_not_send) { + Fw::Buffer buffer(const_cast(data), size); + m_parent.check_last_buffer(buffer); + Fw::Buffer allocated = m_interface->allocate(size); + m_interface->send(allocated); + } } // ---------------------------------------------------------------------- @@ -31,12 +34,13 @@ void Tester::MockFramer::frame(const U8* const data, const U32 size, Fw::ComPack // ---------------------------------------------------------------------- Tester ::Tester() - : - FramerGTestBase("Tester", MAX_HISTORY_SIZE), + : FramerGTestBase("Tester", MAX_HISTORY_SIZE), component("Framer"), m_mock(*this), m_framed(false), - m_returned(false) + m_sent(false), + m_returned(false), + m_sendStatus(Drv::SendStatus::SEND_OK) { this->initComponents(); @@ -50,13 +54,21 @@ Tester ::~Tester() {} // Tests // ---------------------------------------------------------------------- -void Tester ::test_incoming(U32 iterations) { +void Tester ::test_com(U32 iterations) { for (U32 i = 0; i < iterations; i++) { Fw::ComBuffer com; m_buffer.set(com.getBuffAddr(), com.getBuffLength()); m_framed = false; + m_sent = false; + m_returned = false; invoke_to_comIn(0, com, 0); ASSERT_TRUE(m_framed); + if (m_sendStatus == Drv::SendStatus::SEND_OK) { + ASSERT_TRUE(m_sent); + } else { + ASSERT_FALSE(m_sent); + } + ASSERT_FALSE(m_returned); } } @@ -64,20 +76,53 @@ void Tester ::test_buffer(U32 iterations) { for (U32 i = 0; i < iterations; i++) { Fw::Buffer buffer(new U8[3412], 3412); m_framed = false; + m_sent = false; m_returned = false; m_buffer = buffer; invoke_to_bufferIn(0, buffer); ASSERT_TRUE(m_framed); + if (m_sendStatus == Drv::SendStatus::SEND_OK) { + ASSERT_TRUE(m_sent); + } else { + ASSERT_FALSE(m_sent); + } ASSERT_TRUE(m_returned); } } -void Tester ::check_last_buffer(Fw::Buffer buffer) { - ASSERT_EQ(buffer, m_buffer); +void Tester ::test_status_pass_through() { + // Check not always success + Fw::Success status = Fw::Success::FAILURE; + invoke_to_comStatusIn(0, status); + ASSERT_from_comStatusOut(0, status); + + // Check a success + status = Fw::Success::SUCCESS; + invoke_to_comStatusIn(0, status); + ASSERT_from_comStatusOut(1, status); } -void Tester ::check_not_freed() { - ASSERT_FALSE(m_returned); +void Tester ::test_no_send_status() { + Fw::Success status = Fw::Success::SUCCESS; + m_mock.m_do_not_send = true; + // Send com buffer and check no send and a status + Fw::ComBuffer com; + invoke_to_comIn(0, com, 0); + ASSERT_from_framedOut_SIZE(0); + ASSERT_from_comStatusOut(0, status); + + Fw::Buffer buffer(new U8[3412], 3412); + invoke_to_bufferIn(0, buffer); + ASSERT_from_framedOut_SIZE(0); + ASSERT_from_comStatusOut(0, status); + clearFromPortHistory(); + + // Make sure it still does pass-through + test_status_pass_through(); +} + +void Tester ::check_last_buffer(Fw::Buffer buffer) { + ASSERT_EQ(buffer, m_buffer); } // ---------------------------------------------------------------------- @@ -102,7 +147,14 @@ Drv::SendStatus Tester ::from_framedOut_handler(const NATIVE_INT_TYPE portNum, F this->check_last_buffer(sendBuffer); delete[] sendBuffer.getData(); m_framed = true; - return Drv::SendStatus::SEND_OK; + if (m_sendStatus == Drv::SendStatus::SEND_OK) { + m_sent = true; + } + return m_sendStatus; +} + +void Tester ::from_comStatusOut_handler(const NATIVE_INT_TYPE portNum, Fw::Success& condition) { + this->pushFromPortEntry_comStatusOut(condition); } // ---------------------------------------------------------------------- @@ -125,8 +177,11 @@ void Tester ::connectPorts() { // framedOut this->component.set_framedOut_OutputPort(0, this->get_from_framedOut(0)); - // timeGet - this->component.set_timeGet_OutputPort(0, this->get_from_timeGet(0)); + // comStatusIn + this->connect_to_comStatusIn(0, this->component.get_comStatusIn_InputPort(0)); + + // comStatusOut + this->component.set_comStatusOut_OutputPort(0, this->get_from_comStatusOut(0)); } void Tester ::initComponents() { @@ -134,4 +189,8 @@ void Tester ::initComponents() { this->component.init(INSTANCE); } +void Tester ::setSendStatus(Drv::SendStatus sendStatus) { + m_sendStatus = sendStatus; +} + } // end namespace Svc diff --git a/Svc/Framer/test/ut/Tester.hpp b/Svc/Framer/test/ut/Tester.hpp index 446edf6656..29e1661546 100644 --- a/Svc/Framer/test/ut/Tester.hpp +++ b/Svc/Framer/test/ut/Tester.hpp @@ -1,10 +1,10 @@ // ====================================================================== // \title Framer/test/ut/Tester.hpp -// \author mstarch +// \author mstarch, bocchino // \brief hpp file for Framer test harness implementation class // // \copyright -// Copyright 2009-2015, by the California Institute of Technology. +// Copyright 2009-2022, by the California Institute of Technology. // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. // @@ -14,93 +14,142 @@ #define TESTER_HPP #include "GTestBase.hpp" -#include "Svc/Framer/FramerComponentImpl.hpp" +#include "Svc/Framer/Framer.hpp" namespace Svc { class Tester : public FramerGTestBase { + public: + // ---------------------------------------------------------------------- - // Construction and destruction + // Types // ---------------------------------------------------------------------- + + //! Mock framing protocol class MockFramer : public FramingProtocol { public: MockFramer(Tester& parent); - void frame(const U8* const data, const U32 size, Fw::ComPacket::ComPacketType packet_type); + void frame( + const U8* const data, + const U32 size, + Fw::ComPacket::ComPacketType packet_type + ); Tester& m_parent; + bool m_do_not_send; }; + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + public: + //! Construct object Tester - //! Tester(); //! Destroy object Tester - //! ~Tester(); public: + // ---------------------------------------------------------------------- // Tests // ---------------------------------------------------------------------- - //! Test incoming data to the framer - //! - void test_incoming(U32 iterations = 1); + //! Test incoming Fw::Com data to the framer + void test_com(U32 iterations = 1); - //! Test incoming data to the framer - //! + //! Test incoming Fw::Buffer data to the framer void test_buffer(U32 iterations = 1); + //! Tests statuses pass-through + void test_status_pass_through(); + + //! Tests statuses on no-send + void test_no_send_status(); + + //! Check that buffer is equal to the last buffer allocated void check_last_buffer(Fw::Buffer buffer); - void check_not_freed(); private: + // ---------------------------------------------------------------------- // Handlers for typed from ports // ---------------------------------------------------------------------- //! Handler for from_bufferDeallocate - //! - void from_bufferDeallocate_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Buffer& fwBuffer); + void from_bufferDeallocate_handler( + const NATIVE_INT_TYPE portNum, //!< The port number + Fw::Buffer& fwBuffer //!< The buffer + ); //! Handler for from_framedAllocate - //! - Fw::Buffer from_framedAllocate_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ - U32 size); + Fw::Buffer from_framedAllocate_handler( + const NATIVE_INT_TYPE portNum, //!< The port number + U32 size //!< The size + ); //! Handler for from_framedOut + Drv::SendStatus from_framedOut_handler( + const NATIVE_INT_TYPE portNum, //!< The port number + Fw::Buffer& sendBuffer //!< The buffer containing framed data + ); + + //! Handler for from_comStatusOut //! - Drv::SendStatus from_framedOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Buffer& sendBuffer); + void from_comStatusOut_handler( + const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Success &condition /*!< Condition success/failure */ + ); + + public: + + // ---------------------------------------------------------------------- + // Public instance methods + // ---------------------------------------------------------------------- + + //! Set the send status + void setSendStatus(Drv::SendStatus sendStatus); private: + // ---------------------------------------------------------------------- - // Helper methods + // Private instance methods // ---------------------------------------------------------------------- //! Connect ports - //! void connectPorts(); //! Initialize components - //! void initComponents(); private: + // ---------------------------------------------------------------------- // Variables // ---------------------------------------------------------------------- //! The component under test - //! - FramerComponentImpl component; + Framer component; + //! Buffer for sending unframed data Fw::Buffer m_buffer; + + //! Mock framing protocol MockFramer m_mock; + + //! Whether framing succeeded bool m_framed; + + //! Whether sending succeeded + bool m_sent; + + //! Whether the frame buffer was deallocated bool m_returned; + + //! Send status for error injection + Drv::SendStatus m_sendStatus; }; } // end namespace Svc diff --git a/Svc/FramingProtocol/CMakeLists.txt b/Svc/FramingProtocol/CMakeLists.txt index 3182586cde..22bbe72408 100644 --- a/Svc/FramingProtocol/CMakeLists.txt +++ b/Svc/FramingProtocol/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME @@ -21,3 +21,10 @@ set(MOD_DEPS register_fprime_module() +set(UT_SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/test/ut/DeframingTester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/FramingTester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/main.cpp" +) +set(UT_MOD_DEPS STest) +register_fprime_ut() diff --git a/Svc/FramingProtocol/FprimeProtocol.cpp b/Svc/FramingProtocol/FprimeProtocol.cpp index 8be912cb73..f7d162a910 100644 --- a/Svc/FramingProtocol/FprimeProtocol.cpp +++ b/Svc/FramingProtocol/FprimeProtocol.cpp @@ -9,10 +9,8 @@ // acknowledged. // // ====================================================================== - -#include - #include "FprimeProtocol.hpp" +#include "FpConfig.hpp" #include "Utils/Hash/Hash.hpp" namespace Svc { @@ -65,7 +63,8 @@ bool FprimeDeframing::validate(Types::CircularBuffer& ring, U32 size) { hash.init(); for (U32 i = 0; i < size; i++) { char byte; - ring.peek(byte, i); + const Fw::SerializeStatus status = ring.peek(byte, i); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); hash.update(&byte, 1); } hash.final(hashBuffer); @@ -73,7 +72,8 @@ bool FprimeDeframing::validate(Types::CircularBuffer& ring, U32 size) { for (U32 i = 0; i < HASH_DIGEST_LENGTH; i++) { char calc = static_cast(hashBuffer.getBuffAddr()[i]); char sent = 0; - ring.peek(sent, size + i); + const Fw::SerializeStatus status = ring.peek(sent, size + i); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); if (calc != sent) { return false; } @@ -126,7 +126,8 @@ DeframingProtocol::DeframingStatus FprimeDeframing::deframe(Types::CircularBuffe // That causes issues in routing; adjust size. FW_ASSERT(buffer.getSize() >= size); buffer.setSize(size); - ring.peek(buffer.getData(), size, FpFrameHeader::SIZE); + status = ring.peek(buffer.getData(), size, FpFrameHeader::SIZE); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); m_interface->route(buffer); return DeframingProtocol::DEFRAMING_STATUS_SUCCESS; } diff --git a/Svc/FramingProtocol/docs/sdd.md b/Svc/FramingProtocol/docs/sdd.md index 67183c18ad..eb6014a126 100644 --- a/Svc/FramingProtocol/docs/sdd.md +++ b/Svc/FramingProtocol/docs/sdd.md @@ -26,11 +26,11 @@ defined in the `FramingProtocol` library. ## 1. Requirements -Requirement | Description | Verification Method ------------ | ----------- | ------------------- -FramingProtocol-001 | `Svc::FramingProtocol` shall provide the interface to a protocol for wrapping data in frames for transmission to the ground|Inspection -FramingProtocol-002 | `Svc::FramingProtocol` shall provide the interface to a protocol for extracting data from frames received from the ground|Inspection -FramingProtocol-003 | `Svc::FramingProtocol` shall implement the framing and deframing protocols used by the F Prime GDS|Inspection +| Requirement | Description | Verification Method | +|-------------------------|-----------------------------------------------------------------------------------------------------------------------------|---------------------| +| Svc-FramingProtocol-001 | `Svc::FramingProtocol` shall provide the interface to a protocol for wrapping data in frames for transmission to the ground | Unit test | +| Svc-FramingProtocol-002 | `Svc::FramingProtocol` shall provide the interface to a protocol for extracting data from frames received from the ground | Unit test | +| Svc-FramingProtocol-003 | `Svc::FramingProtocol` shall implement the framing and deframing protocols used by the F Prime GDS | Unit test | ## 2. Using the Interface @@ -103,9 +103,13 @@ To implement a framing protocol, do the following: 1. Implement the abstract class `FramingProtocolInterface`. -1. Use the implementation in step 1 to implement the abstract class +2. Use the implementation in step 1 to implement the abstract class `FramingProtocol`. +Implementations of the framing protocol are allowed to produce zero or one frame +for each incoming packet. Producing zero packets is useful when aggregating packets +into a larger frame. Producing more than one packet is not permitted. + #### 3.1.1. Implementing `FramingProtocolInterface` `FramingProtocolInterface` defines helper methods for framing data. @@ -161,9 +165,11 @@ Your implementation of `frame` should do the following: 1. Use `m_interface->allocate` to allocate a buffer to hold the framed data. -1. Frame the data into the buffer allocated in step 1. +2. Frame the data into the buffer allocated in step 1. -1. Use `m_interface->send` to send the buffer. +3. Use `m_interface->send` to send the buffer. `m_interface->send` should be called at most once in any +single invocation of `frame`. Aggregating protocols may only call `m_interface->send` for occasional +invocations of `frame`. ### 3.2. Deframing diff --git a/Svc/FramingProtocol/test/ut/DeframingTester.cpp b/Svc/FramingProtocol/test/ut/DeframingTester.cpp new file mode 100644 index 0000000000..1020a992f7 --- /dev/null +++ b/Svc/FramingProtocol/test/ut/DeframingTester.cpp @@ -0,0 +1,166 @@ +// ====================================================================== +// \title DeframingTester.cpp +// \author bocchino +// \brief cpp file for DeframingTester class +// ====================================================================== + +#include + +#include "Fw/Types/SerialBuffer.hpp" +#include "STest/Pick/Pick.hpp" +#include "Svc/FramingProtocol/test/ut/DeframingTester.hpp" +#include "Utils/Hash/Hash.hpp" +#include "gtest/gtest.h" + +namespace Svc { + + // ---------------------------------------------------------------------- + // Construction + // ---------------------------------------------------------------------- + + DeframingTester :: + DeframingTester(U32 cbStoreSize) : + frameSize(0), + cbStorage(new U8[cbStoreSize]), + circularBuffer(this->cbStorage, cbStoreSize), + interface(*this) + { + this->fprimeDeframing.setup(this->interface); + memset(this->bufferStorage, 0, sizeof this->bufferStorage); + memset(this->frameData, 0, sizeof this->frameData); + memset(this->cbStorage, 0, cbStoreSize); + } + + DeframingTester :: + ~DeframingTester() + { + delete[](this->cbStorage); + } + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + DeframingProtocol::DeframingStatus DeframingTester :: + deframe(U32& needed) + { + return this->fprimeDeframing.deframe(this->circularBuffer, needed); + } + + void DeframingTester :: + serializeTokenType(FpFrameHeader::TokenType v) + { + U8 buffer[sizeof v]; + Fw::SerialBuffer sb(buffer, sizeof buffer); + { + const Fw::SerializeStatus status = sb.serialize(v); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + } + { + const Fw::SerializeStatus status = + this->circularBuffer.serialize(buffer, sizeof buffer); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + } + } + + Fw::ByteArray DeframingTester :: + constructRandomFrame(U32 packetSize) + { + FW_ASSERT(packetSize <= MAX_PACKET_SIZE, packetSize, MAX_PACKET_SIZE); + Fw::SerialBuffer sb(this->frameData, sizeof this->frameData); + Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK; + // Serialize the start word + status = sb.serialize(Svc::FpFrameHeader::START_WORD); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + // Serialize the packet size + status = sb.serialize(static_cast(packetSize)); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + // Construct the packet data + for (U32 i = 0; i < packetSize; ++i) { + const U8 byte = static_cast(STest::Pick::lowerUpper(0, 0xFF)); + status = sb.serialize(byte); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + } + const U32 buffLength = sb.getBuffLength(); + const U32 dataSize = FpFrameHeader::SIZE + packetSize; + FW_ASSERT(buffLength == dataSize, buffLength, dataSize); + // Compute the hash value + Utils::Hash hash; + Utils::HashBuffer hashBuffer; + hash.init(); + hash.update(&this->frameData, dataSize); + hash.final(hashBuffer); + // Copy the hash value into place + const U8 *const buffAddr = hashBuffer.getBuffAddr(); + this->frameSize = dataSize + HASH_DIGEST_LENGTH; + FW_ASSERT(this->frameSize <= MAX_FRAME_SIZE); + memcpy(&this->frameData[dataSize], buffAddr, HASH_DIGEST_LENGTH); + // Return the byte array + return Fw::ByteArray(this->frameData, this->frameSize); + } + + void DeframingTester :: + pushFrameOntoCB(Fw::ByteArray frame) + { + const Fw::SerializeStatus status = + this->circularBuffer.serialize(frame.bytes, frame.size); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK); + } + + Fw::ByteArray DeframingTester :: + getFrame() + { + return Fw::ByteArray(this->frameData, this->frameSize); + } + + void DeframingTester :: + checkPacketData() + { + FW_ASSERT( + this->frameSize <= MAX_FRAME_SIZE, + this->frameSize, + MAX_FRAME_SIZE + ); + FW_ASSERT( + this->frameSize >= NON_PACKET_DATA_SIZE, + this->frameSize, + NON_PACKET_DATA_SIZE + ); + const U32 packetSize = this->frameSize - NON_PACKET_DATA_SIZE; + Fw::Buffer buffer = this->interface.getRoutedBuffer(); + ASSERT_EQ(buffer.getSize(), packetSize); + const int result = memcmp( + &this->frameData[FpFrameHeader::SIZE], + buffer.getData(), + packetSize + ); + ASSERT_EQ(result, 0); + } + + void DeframingTester :: + testNominalDeframing(U32 packetSize) + { + const Fw::ByteArray frame = this->constructRandomFrame(packetSize); + this->pushFrameOntoCB(frame); + U32 needed; + const Svc::DeframingProtocol::DeframingStatus status = + this->deframe(needed); + ASSERT_EQ(status, Svc::DeframingProtocol::DEFRAMING_STATUS_SUCCESS); + ASSERT_EQ(needed, frame.size); + this->checkPacketData(); + } + + void DeframingTester :: + testBadChecksum(U32 packetSize) + { + const Fw::ByteArray frame = this->constructRandomFrame(packetSize); + const U32 hashOffset = FpFrameHeader::SIZE + packetSize; + ++frame.bytes[hashOffset]; + this->pushFrameOntoCB(frame); + U32 needed; + const Svc::DeframingProtocol::DeframingStatus status = + this->deframe(needed); + ASSERT_EQ(status, Svc::DeframingProtocol::DEFRAMING_INVALID_CHECKSUM); + } + +} diff --git a/Svc/FramingProtocol/test/ut/DeframingTester.hpp b/Svc/FramingProtocol/test/ut/DeframingTester.hpp new file mode 100644 index 0000000000..44b17f07ab --- /dev/null +++ b/Svc/FramingProtocol/test/ut/DeframingTester.hpp @@ -0,0 +1,174 @@ +// ====================================================================== +// \title DeframingTester.hpp +// \author bocchino +// \brief hpp file for DeframingTester class +// ====================================================================== + +#include "Fw/Types/Assert.hpp" +#include "Fw/Types/ByteArray.hpp" +#include "Fw/Types/SerialBuffer.hpp" +#include "Svc/FramingProtocol/FprimeProtocol.hpp" +#include "Svc/FramingProtocol/DeframingProtocol.hpp" +#include "Utils/Hash/Hash.hpp" +#include "Utils/Types/CircularBuffer.hpp" + +namespace Svc { + + //! A harness for checking deframing + class DeframingTester { + + public: + + // ---------------------------------------------------------------------- + // Constants and types + // ---------------------------------------------------------------------- + + //! Constants + enum Constants { + //! The maximum frame size + MAX_FRAME_SIZE = 1024, + //! The size of non-packet data in a frame + NON_PACKET_DATA_SIZE = FpFrameHeader::SIZE + HASH_DIGEST_LENGTH, + //! The maximum allowed packet size + MAX_PACKET_SIZE = MAX_FRAME_SIZE - NON_PACKET_DATA_SIZE, + //! The offset of the start word in an F Prime protocol frame + START_WORD_OFFSET = 0, + //! The offset of the packet size in an F Prime protocol frame + PACKET_SIZE_OFFSET = START_WORD_OFFSET + + sizeof FpFrameHeader::START_WORD, + }; + + //! The deframing protocol interface + class Interface : + public DeframingProtocolInterface + { + + public: + + //! Construct an Interface + Interface( + DeframingTester& deframingTester //!< The enclosing DeframingTester + ) : + deframingTester(deframingTester) + { + + } + + public: + + //! Allocate the buffer + Fw::Buffer allocate(const U32 size) { + FW_ASSERT(size <= MAX_FRAME_SIZE); + Fw::Buffer buffer(this->deframingTester.bufferStorage, size); + return buffer; + } + + //! Route the buffer + void route(Fw::Buffer& data) { + this->routedBuffer = data; + } + + //! Get the routed buffer + Fw::Buffer getRoutedBuffer() { + return this->routedBuffer; + } + + private: + + //! The enclosing DeframingTester + DeframingTester& deframingTester; + + //! The routed buffer + Fw::Buffer routedBuffer; + + }; + + public: + + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + //! Construct a DeframingTester + DeframingTester( + U32 cbStoreSize = MAX_FRAME_SIZE //!< The circular buffer store size + ); + + //! Destroy a DeframingTester + ~DeframingTester(); + + public: + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Call the deframe function of the deframer + DeframingProtocol::DeframingStatus deframe( + U32& needed //!< The number of bytes needed (output) + ); + + //! Serialize a value of token type into the circular buffer + void serializeTokenType( + FpFrameHeader::TokenType v //!< The value + ); + + //! Construct a random frame + //! \return An array pointing to frame data owned by DeframingTester. + Fw::ByteArray constructRandomFrame( + U32 packetSize //!< The packet size + ); + + //! Push a frame onto the circular buffer + void pushFrameOntoCB( + Fw::ByteArray frame //!< The frame + ); + + //! Get the stored frame + //! \return The frame + Fw::ByteArray getFrame(); + + //! Check the packet data + void checkPacketData(); + + //! Test nominal deframing with a valid frame containing random + //! packet data + void testNominalDeframing( + U32 packetSize //!< The packet size + ); + + //! Test deframing with a frame containing a bad checksum + void testBadChecksum( + U32 packetSize //!< The packet size + ); + + private: + + // ---------------------------------------------------------------------- + // Private member variables + // ---------------------------------------------------------------------- + + //! Storage for the buffer + U8 bufferStorage[MAX_FRAME_SIZE]; + + //! The frame data + U8 frameData[MAX_FRAME_SIZE]; + + //! The frame size + U32 frameSize; + + //! Storage for the circular buffer + U8* cbStorage; + + //! The circular buffer + Types::CircularBuffer circularBuffer; + + //! The framing protocol interface + Interface interface; + + //! The F Prime framing protocol + FprimeDeframing fprimeDeframing; + + }; + +} diff --git a/Svc/FramingProtocol/test/ut/FramingTester.cpp b/Svc/FramingProtocol/test/ut/FramingTester.cpp new file mode 100644 index 0000000000..8b25340139 --- /dev/null +++ b/Svc/FramingProtocol/test/ut/FramingTester.cpp @@ -0,0 +1,157 @@ +// ====================================================================== +// \title FramingTester.cpp +// \author bocchino +// \brief cpp file for FramingTester class +// ====================================================================== + +#include "STest/Pick/Pick.hpp" +#include "Svc/FramingProtocol/test/ut/FramingTester.hpp" +#include "gtest/gtest.h" + +namespace Svc { + + // ---------------------------------------------------------------------- + // Construction + // ---------------------------------------------------------------------- + + FramingTester :: + FramingTester(Fw::ComPacket::ComPacketType packetType) : + // Pick a random data size + dataSize(STest::Pick::lowerUpper(1, MAX_DATA_SIZE)), + packetType(packetType), + interface(*this) + { + FW_ASSERT(this->dataSize <= MAX_DATA_SIZE); + this->fprimeFraming.setup(this->interface); + // Fill in random data + for (U32 i = 0; i < sizeof(this->data); ++i) { + this->data[i] = STest::Pick::lowerUpper(0, 0xFF); + } + memset(this->bufferStorage, 0, sizeof this->bufferStorage); + } + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + void FramingTester :: + check() + { + this->fprimeFraming.frame( + this->data, + this->dataSize, + this->packetType + ); + // Check that we received a buffer + Fw::Buffer *const sentBuffer = this->interface.getSentBuffer(); + ASSERT_NE(sentBuffer, nullptr); + if (sentBuffer != nullptr) { + // Check the start word + this->checkStartWord(); + // Check the packet size + const U32 packetSize = this->getPacketSize(); + this->checkPacketSize(packetSize); + // Check the packet type + if (this->packetType != Fw::ComPacket::FW_PACKET_UNKNOWN) { + this->checkPacketType(); + } + // Check the data + this->checkData(); + // Check the hash value + this->checkHash(packetSize); + } + } + + // ---------------------------------------------------------------------- + // Private member functions + // ---------------------------------------------------------------------- + + FpFrameHeader::TokenType FramingTester :: + getPacketSize() + { + FpFrameHeader::TokenType packetSize = 0; + Fw::SerialBuffer sb( + &this->bufferStorage[PACKET_SIZE_OFFSET], + sizeof packetSize + ); + sb.fill(); + const Fw::SerializeStatus status = sb.deserialize(packetSize); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); + return packetSize; + } + + void FramingTester :: + checkPacketSize(FpFrameHeader::TokenType packetSize) + { + U32 expectedPacketSize = this->dataSize; + if (this->packetType != Fw::ComPacket::FW_PACKET_UNKNOWN) { + // Packet type is stored in header + expectedPacketSize += sizeof(SerialPacketType); + } + ASSERT_EQ(packetSize, expectedPacketSize); + } + + void FramingTester :: + checkPacketType() + { + SerialPacketType serialPacketType = 0; + Fw::SerialBuffer sb( + &this->bufferStorage[PACKET_TYPE_OFFSET], + sizeof serialPacketType + ); + sb.fill(); + const Fw::SerializeStatus status = sb.deserialize(serialPacketType); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); + typedef Fw::ComPacket::ComPacketType PacketType; + const PacketType pt = static_cast(serialPacketType); + ASSERT_EQ(pt, this->packetType); + } + + void FramingTester :: + checkStartWord() + { + FpFrameHeader::TokenType startWord = 0; + Fw::SerialBuffer sb( + &this->bufferStorage[START_WORD_OFFSET], + sizeof startWord + ); + sb.fill(); + const Fw::SerializeStatus status = sb.deserialize(startWord); + FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status); + ASSERT_EQ(startWord, FpFrameHeader::START_WORD); + } + + void FramingTester :: + checkData() + { + U32 dataOffset = PACKET_TYPE_OFFSET; + if (this->packetType != Fw::ComPacket::FW_PACKET_UNKNOWN) { + // Packet type is stored in header + dataOffset += sizeof(SerialPacketType); + } + const I32 result = memcmp( + this->data, + &this->bufferStorage[dataOffset], + this->dataSize + ); + ASSERT_EQ(result, 0); + } + + void FramingTester :: + checkHash(FpFrameHeader::TokenType packetSize) + { + Utils::Hash hash; + Utils::HashBuffer hashBuffer; + const U32 dataSize = FpFrameHeader::SIZE + packetSize; + hash.update(this->bufferStorage, dataSize); + hash.final(hashBuffer); + const U8 *const hashAddr = hashBuffer.getBuffAddr(); + const I32 result = memcmp( + &this->bufferStorage[dataSize], + hashAddr, + HASH_DIGEST_LENGTH + ); + ASSERT_EQ(result, 0); + } + +} diff --git a/Svc/FramingProtocol/test/ut/FramingTester.hpp b/Svc/FramingProtocol/test/ut/FramingTester.hpp new file mode 100644 index 0000000000..99215c74ec --- /dev/null +++ b/Svc/FramingProtocol/test/ut/FramingTester.hpp @@ -0,0 +1,165 @@ +// ====================================================================== +// \title FramingTester.hpp +// \author bocchino +// \brief hpp file for FramingTester class +// ====================================================================== + +#include "Fw/Types/Assert.hpp" +#include "Fw/Types/SerialBuffer.hpp" +#include "Svc/FramingProtocol/FprimeProtocol.hpp" +#include "Svc/FramingProtocol/FramingProtocol.hpp" +#include "Utils/Hash/Hash.hpp" + +namespace Svc { + + //! A harness for checking framing + class FramingTester { + + private: + + // ---------------------------------------------------------------------- + // Constants and types + // ---------------------------------------------------------------------- + + //! The serialized packet type + typedef I32 SerialPacketType; + + //! Constants + enum Constants { + //! The maximum buffer size + MAX_BUFFER_SIZE = 1024, + //! The maximum allowed data size + MAX_DATA_SIZE = MAX_BUFFER_SIZE - + FpFrameHeader::SIZE - + sizeof(SerialPacketType) - + HASH_DIGEST_LENGTH, + //! The offset of the start word in an F Prime protocol frame + START_WORD_OFFSET = 0, + //! The offset of the packet size in an F Prime protocol frame + PACKET_SIZE_OFFSET = START_WORD_OFFSET + + sizeof FpFrameHeader::START_WORD, + //! The offset of the packet type in an F Prime protocol frame + PACKET_TYPE_OFFSET = FpFrameHeader::SIZE, + }; + + //! The framing protocol interface + class Interface : + public FramingProtocolInterface + { + + public: + + //! Construct an Interface + Interface( + FramingTester& framingTester //!< The enclosing FramingTester + ) : + framingTester(framingTester), + sentBuffer(nullptr) + { + + } + + public: + + //! Allocate the buffer + Fw::Buffer allocate(const U32 size) { + FW_ASSERT(size <= MAX_BUFFER_SIZE, size, MAX_BUFFER_SIZE); + Fw::Buffer buffer(this->framingTester.bufferStorage, size); + return buffer; + } + + //! Send the buffer + void send(Fw::Buffer& outgoing) { + this->sentBuffer = &outgoing; + } + + //! Get the sent buffer + Fw::Buffer *getSentBuffer() { + return this->sentBuffer; + } + + private: + + //! The enclosing FramingTester + FramingTester& framingTester; + + //! The sent buffer + Fw::Buffer *sentBuffer; + + }; + + public: + + // ---------------------------------------------------------------------- + // Construction + // ---------------------------------------------------------------------- + + //! Construct a FramingTester + FramingTester( + Fw::ComPacket::ComPacketType packetType //!< The packet type + ); + + public: + + // ---------------------------------------------------------------------- + // Public member functions + // ---------------------------------------------------------------------- + + //! Check framing + void check(); + + // ---------------------------------------------------------------------- + // Private member functions + // ---------------------------------------------------------------------- + + private: + + //! Get the packet size from the buffer + FpFrameHeader::TokenType getPacketSize(); + + //! Check the packet size in the buffer + void checkPacketSize( + FpFrameHeader::TokenType packetSize //!< The packet size + ); + + //! Check the packet type in the buffer + void checkPacketType(); + + //! Check the start word in the buffer + void checkStartWord(); + + //! Check the data in the buffer + void checkData(); + + //! Check the hash value in the buffer + void checkHash( + FpFrameHeader::TokenType packetSize //!< The packet size + ); + + private: + + // ---------------------------------------------------------------------- + // Private member variables + // ---------------------------------------------------------------------- + + //! The data to frame + U8 data[MAX_DATA_SIZE]; + + //! The data size in bytes + const U32 dataSize; + + //! The packet type + Fw::ComPacket::ComPacketType packetType; + + //! Storage for the buffer + U8 bufferStorage[MAX_BUFFER_SIZE]; + + //! The framing protocol interface + Interface interface; + + //! The F Prime framing protocol + FprimeFraming fprimeFraming; + + }; + +} diff --git a/Svc/FramingProtocol/test/ut/main.cpp b/Svc/FramingProtocol/test/ut/main.cpp new file mode 100644 index 0000000000..a8a9f548e3 --- /dev/null +++ b/Svc/FramingProtocol/test/ut/main.cpp @@ -0,0 +1,175 @@ +#include + +#include "Fw/Test/UnitTest.hpp" +#include "STest/Pick/Pick.hpp" +#include "STest/Random/Random.hpp" +#include "Svc/FramingProtocol/test/ut/DeframingTester.hpp" +#include "Svc/FramingProtocol/test/ut/FramingTester.hpp" +#include "gtest/gtest.h" + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +TEST(Deframing, IncompleteHeader) { + COMMENT("Apply deframing to a frame with an incomplete header"); + REQUIREMENT("Svc-FramingProtocol-002"); + REQUIREMENT("Svc-FramingProtocol-003"); + Svc::DeframingTester tester; + // Start word + tester.serializeTokenType(Svc::FpFrameHeader::START_WORD); + U32 needed = 0; + const Svc::DeframingProtocol::DeframingStatus status = + tester.deframe(needed); + ASSERT_EQ(status, Svc::DeframingProtocol::DEFRAMING_MORE_NEEDED); +} + +TEST(Deframing, InvalidStartWord) { + COMMENT("Apply deframing to a frame with an invalid start word"); + REQUIREMENT("Svc-FramingProtocol-002"); + REQUIREMENT("Svc-FramingProtocol-003"); + Svc::DeframingTester tester; + // Start word + tester.serializeTokenType(Svc::FpFrameHeader::START_WORD + 1); + // Packet size + tester.serializeTokenType(0); + U32 needed = 0; + const Svc::DeframingProtocol::DeframingStatus status = + tester.deframe(needed); + ASSERT_EQ(status, Svc::DeframingProtocol::DEFRAMING_INVALID_FORMAT); +} + +TEST(Deframing, InvalidSizeIntegerOverflow) { + COMMENT("Apply deframing to a frame with an invalid packet size due to integer overflow"); + REQUIREMENT("Svc-FramingProtocol-002"); + REQUIREMENT("Svc-FramingProtocol-003"); + Svc::DeframingTester tester; + // Start word + tester.serializeTokenType(Svc::FpFrameHeader::START_WORD); + // Packet size + const U32 maxU32 = std::numeric_limits::max(); + const U32 maxSize = maxU32 - (Svc::FpFrameHeader::SIZE + HASH_DIGEST_LENGTH); + // Make size too big + tester.serializeTokenType(maxSize + 1); + U32 needed = 0; + const Svc::DeframingProtocol::DeframingStatus status = + tester.deframe(needed); + ASSERT_EQ(status, Svc::DeframingProtocol::DEFRAMING_INVALID_SIZE); +} + +TEST(Deframing, InvalidSizeBufferOverflow) { + COMMENT("Apply deframing to a frame with an invalid packet size due to buffer overflow"); + REQUIREMENT("Svc-FramingProtocol-002"); + REQUIREMENT("Svc-FramingProtocol-003"); + const Svc::FpFrameHeader::TokenType packetSize = 10; + const U32 frameSize = + Svc::FpFrameHeader::SIZE + packetSize + HASH_DIGEST_LENGTH; + // Make the circular buffer too small to hold the frame + Svc::DeframingTester tester(frameSize - 1); + // Start word + tester.serializeTokenType(Svc::FpFrameHeader::START_WORD); + // Packet size + tester.serializeTokenType(packetSize); + U32 needed = 0; + const Svc::DeframingProtocol::DeframingStatus status = + tester.deframe(needed); + ASSERT_EQ(status, Svc::DeframingProtocol::DEFRAMING_INVALID_SIZE); + ASSERT_EQ(needed, frameSize); +} + +TEST(Deframing, IncompleteFrame) { + COMMENT("Apply deframing to an incomplete frame"); + REQUIREMENT("Svc-FramingProtocol-002"); + REQUIREMENT("Svc-FramingProtocol-003"); + const Svc::FpFrameHeader::TokenType packetSize = 1; + Svc::DeframingTester tester; + // Start word + tester.serializeTokenType(Svc::FpFrameHeader::START_WORD); + // Packet size + tester.serializeTokenType(packetSize); + U32 needed = 0; + // Deframe + const Svc::DeframingProtocol::DeframingStatus status = + tester.deframe(needed); + // Check results + ASSERT_EQ(status, Svc::DeframingProtocol::DEFRAMING_MORE_NEEDED); + const U32 expectedFrameSize = + Svc::FpFrameHeader::SIZE + packetSize + HASH_DIGEST_LENGTH; + ASSERT_EQ(needed, expectedFrameSize); +} + +TEST(Deframing, ZeroPacketSize) { + COMMENT("Apply deframing to a valid frame with packet size zero"); + REQUIREMENT("Svc-FramingProtocol-002"); + REQUIREMENT("Svc-FramingProtocol-003"); + Svc::DeframingTester tester; + const U32 packetSize = 0; + tester.testNominalDeframing(packetSize); +} + +TEST(Deframing, RandomPacketSize) { + COMMENT("Apply deframing to a valid frame with a random packet size"); + REQUIREMENT("Svc-FramingProtocol-002"); + REQUIREMENT("Svc-FramingProtocol-003"); + Svc::DeframingTester tester; + const U32 packetSize = STest::Pick::lowerUpper( + 0, + Svc::DeframingTester::MAX_PACKET_SIZE + ); + tester.testNominalDeframing(packetSize); +} + +TEST(Deframing, MaxPacketSize) { + COMMENT("Apply deframing to a valid frame with maximum packet size for the test buffer"); + REQUIREMENT("Svc-FramingProtocol-002"); + REQUIREMENT("Svc-FramingProtocol-003"); + Svc::DeframingTester tester; + const U32 packetSize = Svc::DeframingTester::MAX_PACKET_SIZE; + tester.testNominalDeframing(packetSize); +} + +TEST(Deframing, BadChecksum) { + COMMENT("Apply deframing to a frame with a bad checksum"); + REQUIREMENT("Svc-FramingProtocol-002"); + REQUIREMENT("Svc-FramingProtocol-003"); + Svc::DeframingTester tester; + const U32 packetSize = STest::Pick::lowerUpper( + 0, + Svc::DeframingTester::MAX_PACKET_SIZE + ); + tester.testBadChecksum(packetSize); +} + +TEST(Framing, CommandPacket) { + COMMENT("Apply framing to a command packet"); + REQUIREMENT("Svc-FramingProtocol-001"); + REQUIREMENT("Svc-FramingProtocol-003"); + Svc::FramingTester tester(Fw::ComPacket::FW_PACKET_COMMAND); + tester.check(); +} + +TEST(Framing, FilePacket) { + COMMENT("Apply framing to a file packet"); + REQUIREMENT("Svc-FramingProtocol-001"); + REQUIREMENT("Svc-FramingProtocol-003"); + Svc::FramingTester tester(Fw::ComPacket::FW_PACKET_FILE); + tester.check(); +} + +TEST(Framing, UnknownPacket) { + COMMENT("Apply framing to a packet of unknown type"); + REQUIREMENT("Svc-FramingProtocol-001"); + REQUIREMENT("Svc-FramingProtocol-003"); + Svc::FramingTester tester(Fw::ComPacket::FW_PACKET_UNKNOWN); + tester.check(); +} + +// ---------------------------------------------------------------------- +// Main function +// ---------------------------------------------------------------------- + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + STest::Random::seed(); + return RUN_ALL_TESTS(); +} diff --git a/Svc/GenericHub/CMakeLists.txt b/Svc/GenericHub/CMakeLists.txt index a9d80fd76b..c540994354 100644 --- a/Svc/GenericHub/CMakeLists.txt +++ b/Svc/GenericHub/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Svc/GenericHub/GenericHubComponentImpl.cpp b/Svc/GenericHub/GenericHubComponentImpl.cpp index 3757abf20c..0b6623fd12 100644 --- a/Svc/GenericHub/GenericHubComponentImpl.cpp +++ b/Svc/GenericHub/GenericHubComponentImpl.cpp @@ -13,7 +13,7 @@ #include #include "Fw/Logger/Logger.hpp" #include "Fw/Types/Assert.hpp" -#include "Fw/Types/BasicTypes.hpp" +#include // Required port serialization or the hub cannot work static_assert(FW_PORT_SERIALIZATION, "FW_PORT_SERIALIZATION must be enabled to use GenericHub"); diff --git a/Svc/GenericHub/docs/GenricHubExampleAppAi.xml b/Svc/GenericHub/docs/GenericHubExampleAppAi.xml similarity index 100% rename from Svc/GenericHub/docs/GenricHubExampleAppAi.xml rename to Svc/GenericHub/docs/GenericHubExampleAppAi.xml diff --git a/Svc/GenericRepeater/GenericRepeater.fpp b/Svc/GenericRepeater/GenericRepeater.fpp deleted file mode 100644 index 2ee2934fb7..0000000000 --- a/Svc/GenericRepeater/GenericRepeater.fpp +++ /dev/null @@ -1,14 +0,0 @@ -module Svc { - - @ A generic component for repeating input - passive component GenericRepeater { - - @ Port to duplicate across the repeater - sync input port portIn: serial - - @ Duplicated output port - output port portOut: [GenericRepeaterOutputPorts] serial - - } - -} diff --git a/Svc/GenericRepeater/GenericRepeaterComponentImpl.cpp b/Svc/GenericRepeater/GenericRepeaterComponentImpl.cpp deleted file mode 100644 index e4c4d0d39d..0000000000 --- a/Svc/GenericRepeater/GenericRepeaterComponentImpl.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// ====================================================================== -// \title GenericRepeaterComponentImpl.cpp -// \author joshuaa -// \brief cpp file for GenericRepeater component implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#include -#include "Fw/Types/BasicTypes.hpp" - -namespace Svc { - -// ---------------------------------------------------------------------- -// Construction, initialization, and destruction -// ---------------------------------------------------------------------- - -GenericRepeaterComponentImpl ::GenericRepeaterComponentImpl(const char* const compName) - : GenericRepeaterComponentBase(compName) {} - -void GenericRepeaterComponentImpl ::init(const NATIVE_INT_TYPE instance) { - GenericRepeaterComponentBase::init(instance); -} - -GenericRepeaterComponentImpl ::~GenericRepeaterComponentImpl() {} - -// ---------------------------------------------------------------------- -// Handler implementations for user-defined serial input ports -// ---------------------------------------------------------------------- - -void GenericRepeaterComponentImpl ::portIn_handler(NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::SerializeBufferBase& Buffer /*!< The serialization buffer*/ -) { - for (NATIVE_INT_TYPE i = 0; i < NUM_PORTOUT_OUTPUT_PORTS; i++) { - if (!isConnected_portOut_OutputPort(i)) { - continue; - } - - portOut_out(i, Buffer); - } -} - -} // end namespace Svc diff --git a/Svc/GenericRepeater/GenericRepeaterComponentImpl.hpp b/Svc/GenericRepeater/GenericRepeaterComponentImpl.hpp deleted file mode 100644 index 612ec3b718..0000000000 --- a/Svc/GenericRepeater/GenericRepeaterComponentImpl.hpp +++ /dev/null @@ -1,54 +0,0 @@ -// ====================================================================== -// \title GenericRepeaterComponentImpl.hpp -// \author joshuaa -// \brief hpp file for GenericRepeater component implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef GenericRepeater_HPP -#define GenericRepeater_HPP - -#include "Svc/GenericRepeater/GenericRepeaterComponentAc.hpp" - -namespace Svc { - -class GenericRepeaterComponentImpl : public GenericRepeaterComponentBase { - public: - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - //! Construct object GenericRepeater - //! - GenericRepeaterComponentImpl(const char* const compName /*!< The component name*/ - ); - - //! Initialize object GenericRepeater - //! - void init(const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ - ); - - //! Destroy object GenericRepeater - //! - ~GenericRepeaterComponentImpl(); - - PRIVATE: - // ---------------------------------------------------------------------- - // Handler implementations for user-defined serial input ports - // ---------------------------------------------------------------------- - - //! Handler implementation for portIn - //! - void portIn_handler(NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::SerializeBufferBase& Buffer /*!< The serialization buffer*/ - ); -}; - -} // end namespace Svc - -#endif diff --git a/Svc/GenericRepeater/docs/GenricRepeaterAppAi.xml b/Svc/GenericRepeater/docs/GenricRepeaterAppAi.xml deleted file mode 100644 index f9fcc0e2ea..0000000000 --- a/Svc/GenericRepeater/docs/GenricRepeaterAppAi.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Svc/GenericRepeater/docs/img/repeater.png b/Svc/GenericRepeater/docs/img/repeater.png deleted file mode 100644 index e9f0072265..0000000000 Binary files a/Svc/GenericRepeater/docs/img/repeater.png and /dev/null differ diff --git a/Svc/GenericRepeater/docs/sdd.md b/Svc/GenericRepeater/docs/sdd.md deleted file mode 100644 index fe7106bb52..0000000000 --- a/Svc/GenericRepeater/docs/sdd.md +++ /dev/null @@ -1,42 +0,0 @@ -\page SvcGenericRepeaterComponent Svc::GenericRepeater Component -# Svc::GenericRepeater Generic Repeater Component - -The GenericRepeater component is designed to take in a port and repeat it to the output multiple times. GenericRepeater is -typically used to take in `Fw::ComBuffer` and log the buffer to a file and send it to the ground interface. - -## Design - -The generic component has an input port and an array of output ports that receive the repeated calls. A typical logging -use case is shown below. - -![Generic Repeater](./img/repeater.png) - -## Configuration - -Generic repeater maximum output ports are configured using `AcConstants.ini` as shown below: - -```ini -GenericRepeaterOutputPorts = 2 -``` - -Here the repeater will bifurcate the incoming port calls. - -## Idiosyncrasies - -The generic repeater does not copy data, and thus reference port calls will not clone references. Care should be taken -when passing pointers and references through the repeater. Special care must be taken with items that need to be -deallocated, like `Svc::BufferManager` allocations. - - -## Requirements - -| Name | Description | Validation | -|---|---|---| -| GENREP-001 | The generic repeater shall repeat calls from input to output | unit test | - -## Change Log - -| Date | Description | -|---|---| -| 2020-12-21 | Initial Draft | -| 2021-01-29 | Updated | \ No newline at end of file diff --git a/Svc/GenericRepeater/test/ut/Tester.cpp b/Svc/GenericRepeater/test/ut/Tester.cpp deleted file mode 100644 index 77fcbfa0d7..0000000000 --- a/Svc/GenericRepeater/test/ut/Tester.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// ====================================================================== -// \title GenericRepeater.hpp -// \author joshuaa -// \brief cpp file for GenericRepeater test harness implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#include "Tester.hpp" - - -#define INSTANCE 0 -#define MAX_HISTORY_SIZE 10 - -namespace Svc { - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - Tester :: - Tester() : - GenericRepeaterGTestBase("Tester", MAX_HISTORY_SIZE), - component("GenericRepeater"), - m_num_msg_per_port() - { - this->initComponents(); - this->connectPorts(); - } - - Tester :: - ~Tester() - { - - } - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - void Tester :: - testRepeater() - { - m_msg.resetSer(); - for(U8 i = 0; i < 32; i++) { - m_msg.serialize(i); - } - - invoke_to_portIn(0, m_msg); - - ASSERT_EQ(m_num_msg_per_port[0], 1); - ASSERT_EQ(m_num_msg_per_port[1], 1); - } - - // ---------------------------------------------------------------------- - // Handlers for serial from ports - // ---------------------------------------------------------------------- - - void Tester :: - from_portOut_handler( - NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ - ) - { - ASSERT_LT(portNum, 2); - m_num_msg_per_port[portNum]++; - - ASSERT_TRUE(Buffer == m_msg); - } - - // ---------------------------------------------------------------------- - // Helper methods - // ---------------------------------------------------------------------- - - void Tester::connectPorts() - { - // Only connecting 2/4 ports to verify that repeater doesn't send to disconnected ports - for (NATIVE_INT_TYPE i = 0; i < 2; ++i) { - this->component.set_portOut_OutputPort( - i, - this->get_from_portOut(i) - ); - } - - - // ---------------------------------------------------------------------- - // Connect serial input ports - // ---------------------------------------------------------------------- - // portIn - this->connect_to_portIn( - 0, - this->component.get_portIn_InputPort(0) - ); - - - } - - void Tester :: - initComponents() - { - this->init(); - this->component.init( - INSTANCE - ); - } - -} // end namespace Svc diff --git a/Svc/GenericRepeater/test/ut/Tester.hpp b/Svc/GenericRepeater/test/ut/Tester.hpp deleted file mode 100644 index faf4daad32..0000000000 --- a/Svc/GenericRepeater/test/ut/Tester.hpp +++ /dev/null @@ -1,92 +0,0 @@ -// ====================================================================== -// \title GenericRepeater/test/ut/Tester.hpp -// \author joshuaa -// \brief hpp file for GenericRepeater test harness implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef TESTER_HPP -#define TESTER_HPP - -#include "GTestBase.hpp" -#include -#include "Svc/GenericRepeater/GenericRepeaterComponentImpl.hpp" - -namespace Svc { - - class Tester : - public GenericRepeaterGTestBase - { - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - public: - - //! Construct object Tester - //! - Tester(); - - //! Destroy object Tester - //! - ~Tester(); - - public: - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - //! To do - //! - void testRepeater(); - - private: - - // ---------------------------------------------------------------------- - // Handlers for serial from ports - // ---------------------------------------------------------------------- - - //! Handler for from_portOut - //! - void from_portOut_handler( - NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::SerializeBufferBase &Buffer /*!< The serialization buffer*/ - ); - - private: - - // ---------------------------------------------------------------------- - // Helper methods - // ---------------------------------------------------------------------- - - //! Connect ports - //! - void connectPorts(); - - //! Initialize components - //! - void initComponents(); - - private: - - // ---------------------------------------------------------------------- - // Variables - // ---------------------------------------------------------------------- - - //! The component under test - //! - GenericRepeaterComponentImpl component; - U8 m_num_msg_per_port[2]; - Fw::ComBuffer m_msg; - }; - -} // end namespace Svc - -#endif diff --git a/Svc/GroundInterface/CMakeLists.txt b/Svc/GroundInterface/CMakeLists.txt index 7a13de6dc7..9ac1f9d0c4 100644 --- a/Svc/GroundInterface/CMakeLists.txt +++ b/Svc/GroundInterface/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/GroundInterface/GroundInterface.cpp b/Svc/GroundInterface/GroundInterface.cpp index 0fe5b1343e..b400fc3476 100644 --- a/Svc/GroundInterface/GroundInterface.cpp +++ b/Svc/GroundInterface/GroundInterface.cpp @@ -6,7 +6,7 @@ #include #include -#include "Fw/Types/BasicTypes.hpp" +#include #include namespace Svc { diff --git a/Svc/GroundInterface/test/ut/DeframerRules.hpp b/Svc/GroundInterface/test/ut/DeframerRules.hpp index 647e5dd7bf..09d1f72cbf 100644 --- a/Svc/GroundInterface/test/ut/DeframerRules.hpp +++ b/Svc/GroundInterface/test/ut/DeframerRules.hpp @@ -15,7 +15,7 @@ #ifndef FPRIME_SVC_GROUND_INTERFACE_HPP #define FPRIME_SVC_GROUND_INTERFACE_HPP -#include +#include #include #include #include diff --git a/Svc/GroundInterface/test/ut/GroundInterfaceRules.hpp b/Svc/GroundInterface/test/ut/GroundInterfaceRules.hpp index ed3029691e..2808d677cb 100644 --- a/Svc/GroundInterface/test/ut/GroundInterfaceRules.hpp +++ b/Svc/GroundInterface/test/ut/GroundInterfaceRules.hpp @@ -15,7 +15,7 @@ #ifndef FPRIME_SVC_GROUND_INTERFACE_HPP #define FPRIME_SVC_GROUND_INTERFACE_HPP -#include +#include #include #include #include diff --git a/Svc/Health/CMakeLists.txt b/Svc/Health/CMakeLists.txt index cb38505b8a..85bb36c76b 100644 --- a/Svc/Health/CMakeLists.txt +++ b/Svc/Health/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/Health/HealthComponentImpl.cpp b/Svc/Health/HealthComponentImpl.cpp index 22dec74b72..adc9934f0a 100644 --- a/Svc/Health/HealthComponentImpl.cpp +++ b/Svc/Health/HealthComponentImpl.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include -#include "Fw/Types/BasicTypes.hpp" +#include #include namespace Svc { @@ -165,12 +165,6 @@ namespace Svc { return; } - // check enable value - if (enable != Fw::Enabled::DISABLED && enable != Fw::Enabled::ENABLED) { - this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::VALIDATION_ERROR); - return; - } - this->m_pingTrackerEntries[entryIndex].enabled = enable.e; Fw::Enabled isEnabled(Fw::Enabled::DISABLED); if (enable == Fw::Enabled::ENABLED) { @@ -206,7 +200,7 @@ namespace Svc { this->cmdResponse_out(opCode,cmdSeq,Fw::CmdResponse::OK); } - NATIVE_INT_TYPE HealthImpl::findEntry(Fw::CmdStringArg entry) { + NATIVE_INT_TYPE HealthImpl::findEntry(const Fw::CmdStringArg& entry) { // walk through entries for (NATIVE_UINT_TYPE tableEntry = 0; tableEntry < NUM_PINGSEND_OUTPUT_PORTS; tableEntry++) { diff --git a/Svc/Health/HealthComponentImpl.hpp b/Svc/Health/HealthComponentImpl.hpp index f8f94c7ae7..7ecbd20f01 100644 --- a/Svc/Health/HealthComponentImpl.hpp +++ b/Svc/Health/HealthComponentImpl.hpp @@ -142,7 +142,7 @@ namespace Svc { Fw::Enabled::t enabled; //!< if current ping result is checked } m_pingTrackerEntries[NUM_PINGSEND_OUTPUT_PORTS]; - NATIVE_INT_TYPE findEntry(Fw::CmdStringArg entry); + NATIVE_INT_TYPE findEntry(const Fw::CmdStringArg& entry); //! Private member data U32 m_numPingEntries; //!< stores number of entries passed to constructor diff --git a/Svc/Health/Stub/HealthComponentStubChecks.cpp b/Svc/Health/Stub/HealthComponentStubChecks.cpp index 6510e8141e..051ba4e591 100644 --- a/Svc/Health/Stub/HealthComponentStubChecks.cpp +++ b/Svc/Health/Stub/HealthComponentStubChecks.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include -#include "Fw/Types/BasicTypes.hpp" +#include #include #include diff --git a/Svc/Health/VxWorks/HealthComponentVxWorksChecks.cpp b/Svc/Health/VxWorks/HealthComponentVxWorksChecks.cpp index 6510e8141e..051ba4e591 100644 --- a/Svc/Health/VxWorks/HealthComponentVxWorksChecks.cpp +++ b/Svc/Health/VxWorks/HealthComponentVxWorksChecks.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include -#include "Fw/Types/BasicTypes.hpp" +#include #include #include diff --git a/Svc/Health/test/ut/Tester.cpp b/Svc/Health/test/ut/Tester.cpp index 56caea055f..f7006db7c9 100644 --- a/Svc/Health/test/ut/Tester.cpp +++ b/Svc/Health/test/ut/Tester.cpp @@ -260,7 +260,7 @@ namespace Svc { for (NATIVE_UINT_TYPE port = 0; port < Svc::HealthComponentBase::NUM_PINGSEND_OUTPUT_PORTS; port++) { char name[80]; - sprintf(name,"task%d",port); + snprintf(name, sizeof(name), "task%d",port); ASSERT_EVENTS_HLTH_PING_WARN(port,name); } @@ -294,7 +294,7 @@ namespace Svc { for (NATIVE_UINT_TYPE port = 0; port < Svc::HealthComponentBase::NUM_PINGSEND_OUTPUT_PORTS; port++) { char name[80]; - sprintf(name,"task%d",port); + snprintf(name, sizeof(name), "task%d",port); ASSERT_EVENTS_HLTH_PING_WARN(port,name); } @@ -316,7 +316,7 @@ namespace Svc { for (NATIVE_UINT_TYPE port = 0; port < Svc::HealthComponentBase::NUM_PINGSEND_OUTPUT_PORTS; port++) { char name[80]; - sprintf(name,"task%d",port); + snprintf(name, sizeof(name), "task%d",port); ASSERT_EVENTS_HLTH_PING_LATE(port,name); } @@ -346,7 +346,7 @@ namespace Svc { ASSERT_EVENTS_HLTH_PING_WARN_SIZE(Svc::HealthComponentBase::NUM_PINGSEND_OUTPUT_PORTS); for (NATIVE_INT_TYPE entry = 0; entry < Svc::HealthComponentBase::NUM_PINGSEND_OUTPUT_PORTS; entry++) { char name[80]; - sprintf(name,"task%d",entry); + snprintf(name, sizeof(name), "task%d",entry); ASSERT_EVENTS_HLTH_PING_WARN(entry, name); } @@ -406,7 +406,7 @@ namespace Svc { ASSERT_EVENTS_HLTH_PING_LATE_SIZE(Svc::HealthComponentBase::NUM_PINGSEND_OUTPUT_PORTS); for (NATIVE_INT_TYPE entry = 0; entry < Svc::HealthComponentBase::NUM_PINGSEND_OUTPUT_PORTS; entry++) { char name[80]; - sprintf(name,"task%d",entry); + snprintf(name,sizeof(name), "task%d",entry); ASSERT_EVENTS_HLTH_PING_LATE(entry,name); } @@ -435,7 +435,7 @@ namespace Svc { } // disable entry char name[80]; - sprintf(name,"task%d",entry); + snprintf(name, sizeof(name), "task%d",entry); Fw::CmdStringArg task(name); this->sendCmd_HLTH_PING_ENABLE(0,10,name,Fw::Enabled::DISABLED); this->dispatchAll(); @@ -495,7 +495,7 @@ namespace Svc { ASSERT_EQ(this->pingEntries[entry].warnCycles,Svc::HealthComponentBase::NUM_PINGSEND_OUTPUT_PORTS+entry); ASSERT_EQ(this->pingEntries[entry].fatalCycles,Svc::HealthComponentBase::NUM_PINGSEND_OUTPUT_PORTS*2+entry+1); char name[80]; - sprintf(name,"task%d",entry); + snprintf(name, sizeof(name), "task%d",entry); Fw::CmdStringArg task(name); this->sendCmd_HLTH_CHNG_PING(0,10,task, Svc::HealthComponentBase::NUM_PINGSEND_OUTPUT_PORTS*4+entry, @@ -656,7 +656,7 @@ namespace Svc { ASSERT_EVENTS_HLTH_PING_WRONG_KEY_SIZE(Svc::HealthComponentBase::NUM_PINGSEND_OUTPUT_PORTS); for (NATIVE_INT_TYPE port = 0; port < Svc::HealthComponentBase::NUM_PINGSEND_OUTPUT_PORTS; port++) { char name[80]; - sprintf(name,"task%d",port); + snprintf(name, sizeof(name), "task%d",port); ASSERT_EVENTS_HLTH_PING_WRONG_KEY(port,name,FLAG_KEY_VALUE); } @@ -675,7 +675,7 @@ namespace Svc { this->dispatchAll(); ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE(0,HealthComponentBase::OPCODE_HLTH_PING_ENABLE,0,Fw::CmdResponse::VALIDATION_ERROR); + ASSERT_CMD_RESPONSE(0,HealthComponentBase::OPCODE_HLTH_PING_ENABLE,0,Fw::CmdResponse::FORMAT_ERROR); //send command with bad ping entry sendCmd_HLTH_PING_ENABLE(0,0,"notask",Fw::Enabled::ENABLED); @@ -748,7 +748,7 @@ namespace Svc { ASSERT_EVENTS_SIZE(1); ASSERT_EVENTS_HLTH_PING_WARN_SIZE(1); char name[80]; - sprintf(name,"task%d",Svc::HealthComponentBase::NUM_PINGSEND_OUTPUT_PORTS-1); + snprintf(name, sizeof(name), "task%d",Svc::HealthComponentBase::NUM_PINGSEND_OUTPUT_PORTS-1); ASSERT_EVENTS_HLTH_PING_WARN(0,name); ASSERT_TLM_SIZE(1); ASSERT_TLM_PingLateWarnings_SIZE(1); diff --git a/Svc/LinuxTime/CMakeLists.txt b/Svc/LinuxTime/CMakeLists.txt index 8683ede979..e278ae6ff8 100644 --- a/Svc/LinuxTime/CMakeLists.txt +++ b/Svc/LinuxTime/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/LinuxTimer/CMakeLists.txt b/Svc/LinuxTimer/CMakeLists.txt index 0482ff7500..0b505cfaca 100644 --- a/Svc/LinuxTimer/CMakeLists.txt +++ b/Svc/LinuxTimer/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Svc/LinuxTimer/LinuxTimerComponentImplCommon.cpp b/Svc/LinuxTimer/LinuxTimerComponentImplCommon.cpp index 2f78012335..ec9158262b 100644 --- a/Svc/LinuxTimer/LinuxTimerComponentImplCommon.cpp +++ b/Svc/LinuxTimer/LinuxTimerComponentImplCommon.cpp @@ -12,7 +12,7 @@ #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace Svc { diff --git a/Svc/LinuxTimer/LinuxTimerComponentImplTaskDelay.cpp b/Svc/LinuxTimer/LinuxTimerComponentImplTaskDelay.cpp index 2278b2aba3..c0cc750674 100644 --- a/Svc/LinuxTimer/LinuxTimerComponentImplTaskDelay.cpp +++ b/Svc/LinuxTimer/LinuxTimerComponentImplTaskDelay.cpp @@ -12,7 +12,7 @@ #include -#include "Fw/Types/BasicTypes.hpp" +#include #include namespace Svc { diff --git a/Svc/LinuxTimer/LinuxTimerComponentImplTimerFd.cpp b/Svc/LinuxTimer/LinuxTimerComponentImplTimerFd.cpp index f113b17135..acf3b58efa 100644 --- a/Svc/LinuxTimer/LinuxTimerComponentImplTimerFd.cpp +++ b/Svc/LinuxTimer/LinuxTimerComponentImplTimerFd.cpp @@ -12,7 +12,7 @@ #include #include -#include "Fw/Types/BasicTypes.hpp" +#include #include #include #include diff --git a/Svc/PassiveConsoleTextLogger/CMakeLists.txt b/Svc/PassiveConsoleTextLogger/CMakeLists.txt index 5a26b4ca69..34587220d7 100644 --- a/Svc/PassiveConsoleTextLogger/CMakeLists.txt +++ b/Svc/PassiveConsoleTextLogger/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/PassiveConsoleTextLogger/ConsoleTextLoggerImplCommon.cpp b/Svc/PassiveConsoleTextLogger/ConsoleTextLoggerImplCommon.cpp index ac49b26cbf..bb27536235 100644 --- a/Svc/PassiveConsoleTextLogger/ConsoleTextLoggerImplCommon.cpp +++ b/Svc/PassiveConsoleTextLogger/ConsoleTextLoggerImplCommon.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -43,8 +43,8 @@ namespace Svc { severityString = "SEVERITY ERROR"; break; } - Fw::Logger::logMsg("EVENT: (%d) (%d:%d,%d) %s: %s\n", - id, timeTag.getTimeBase(), timeTag.getSeconds(), timeTag.getUSeconds(), - reinterpret_cast(severityString), reinterpret_cast(text.toChar())); + Fw::Logger::logMsg("EVENT: (%" PRI_FwEventIdType ") (%" PRI_FwTimeBaseStoreType ":%" PRIu32 ",%" PRIu32 ") %s: %s\n", + id, static_cast(timeTag.getTimeBase()), timeTag.getSeconds(), timeTag.getUSeconds(), + reinterpret_cast(severityString), reinterpret_cast(text.toChar())); } } diff --git a/Svc/Ping/CMakeLists.txt b/Svc/Ping/CMakeLists.txt index 214a69daa7..04567a4eaa 100644 --- a/Svc/Ping/CMakeLists.txt +++ b/Svc/Ping/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME @@ -10,4 +10,8 @@ set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Ping.fpp" ) +set(MOD_DEPS + Fw/Port +) + register_fprime_module() diff --git a/Svc/PolyDb/CMakeLists.txt b/Svc/PolyDb/CMakeLists.txt index 74fe77f9c6..baf5524e08 100644 --- a/Svc/PolyDb/CMakeLists.txt +++ b/Svc/PolyDb/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/PolyDb/PolyDb.hpp b/Svc/PolyDb/PolyDb.hpp new file mode 100644 index 0000000000..8e085c34fd --- /dev/null +++ b/Svc/PolyDb/PolyDb.hpp @@ -0,0 +1,17 @@ +// ====================================================================== +// PolyDb.hpp +// Standardization header for PolyDb +// ====================================================================== + +#ifndef Svc_PolyDb_HPP +#define Svc_PolyDb_HPP + +#include "Svc/PolyDb/PolyDbImpl.hpp" + +namespace Svc { + + typedef PolyDbImpl PolyDb; + +} + +#endif diff --git a/Svc/PolyDb/PolyDbImpl.cpp b/Svc/PolyDb/PolyDbImpl.cpp index 03310344a0..48e4e4c1e3 100644 --- a/Svc/PolyDb/PolyDbImpl.cpp +++ b/Svc/PolyDb/PolyDbImpl.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include namespace Svc { PolyDbImpl::PolyDbImpl(const char* name) : PolyDbComponentBase(name) { diff --git a/Svc/PolyIf/CMakeLists.txt b/Svc/PolyIf/CMakeLists.txt index 3f80a337ef..aa3ea93781 100644 --- a/Svc/PolyIf/CMakeLists.txt +++ b/Svc/PolyIf/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/PrmDb/CMakeLists.txt b/Svc/PrmDb/CMakeLists.txt index 42c616cc3d..2aa37c969c 100644 --- a/Svc/PrmDb/CMakeLists.txt +++ b/Svc/PrmDb/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/PrmDb/PrmDbImpl.cpp b/Svc/PrmDb/PrmDbImpl.cpp index 6fb74adc39..540ce5b162 100644 --- a/Svc/PrmDb/PrmDbImpl.cpp +++ b/Svc/PrmDb/PrmDbImpl.cpp @@ -41,8 +41,12 @@ namespace Svc { }; } - PrmDbImpl::PrmDbImpl(const char* name, const char* file) : PrmDbComponentBase(name) { + PrmDbImpl::PrmDbImpl(const char* name) : PrmDbComponentBase(name) { this->clearDb(); + } + + void PrmDbImpl::configure(const char* file) { + FW_ASSERT(file != nullptr); this->m_fileName = file; } @@ -125,7 +129,7 @@ namespace Svc { } void PrmDbImpl::PRM_SAVE_FILE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { - + FW_ASSERT(this->m_fileName.length() > 0); Os::File paramFile; WorkingBuffer buff; @@ -240,6 +244,7 @@ namespace Svc { } void PrmDbImpl::readParamFile() { + FW_ASSERT(this->m_fileName.length() > 0); // load file. FIXME: Put more robust file checking, such as a CRC. Os::File paramFile; diff --git a/Svc/PrmDb/PrmDbImpl.hpp b/Svc/PrmDb/PrmDbImpl.hpp index 53ccfd90bb..3016849558 100644 --- a/Svc/PrmDb/PrmDbImpl.hpp +++ b/Svc/PrmDb/PrmDbImpl.hpp @@ -39,8 +39,7 @@ namespace Svc { //! the file name for opening later. //! //! \param name component instance name - //! \param file file where parameters are stored. - PrmDbImpl(const char* name, const char* file); + PrmDbImpl(const char* name); //! \brief PrmDb initialization function //! @@ -52,6 +51,14 @@ namespace Svc { void init(NATIVE_INT_TYPE queueDepth, NATIVE_INT_TYPE instance); + //! \brief PrmDb configure method + //! + //! The configure method stores the file name for opening later. + //! + //! \param file file where parameters are stored. + void configure(const char* file); + + //! \brief PrmDb file read function //! //! The readFile function reads the set of parameters from the file passed in to diff --git a/Svc/PrmDb/test/ut/PrmDbTester.cpp b/Svc/PrmDb/test/ut/PrmDbTester.cpp index 8c41e92d72..cfff113f04 100644 --- a/Svc/PrmDb/test/ut/PrmDbTester.cpp +++ b/Svc/PrmDb/test/ut/PrmDbTester.cpp @@ -44,10 +44,10 @@ TEST(ParameterDbTest,NominalPopulateTest) { TEST_CASE(105.1.1,"Nominal populate test"); COMMENT("Write values to the parameter database and verify that they were written correctly"); - Svc::PrmDbImpl impl("PrmDbImpl","TestFile.prm"); + Svc::PrmDbImpl impl("PrmDbImpl"); impl.init(10,0); - + impl.configure("TestFile.prm"); Svc::PrmDbImplTester tester(impl); tester.init(); @@ -65,9 +65,10 @@ TEST(ParameterDbTest,NominalFileSaveTest) { TEST_CASE(105.1.2,"Nominal file save test"); COMMENT("Write values to the parameter database and save them to a file."); - Svc::PrmDbImpl impl("PrmDbImpl","TestFile.prm"); + Svc::PrmDbImpl impl("PrmDbImpl"); impl.init(10,0); + impl.configure("TestFile.prm"); Svc::PrmDbImplTester tester(impl); @@ -86,9 +87,10 @@ TEST(ParameterDbTest,NominalFileLoadTest) { TEST_CASE(105.1.3,"Nominal file load test"); COMMENT("Read values from the created file and verify they are correct."); - Svc::PrmDbImpl impl("PrmDbImpl","TestFile.prm"); + Svc::PrmDbImpl impl("PrmDbImpl"); impl.init(10,0); + impl.configure("TestFile.prm"); Svc::PrmDbImplTester tester(impl); @@ -104,7 +106,7 @@ TEST(ParameterDbTest,NominalFileLoadTest) { //TEST(ParameterDbTest,RefPrmFile) { // -// Svc::PrmDbImpl impl("PrmDbImpl","TestFile.prm"); +// Svc::PrmDbImpl impl("PrmDbImpl"); // // impl.init(10); // @@ -125,9 +127,10 @@ TEST(ParameterDbTest,PrmMissingExtraParamsTest) { TEST_CASE(105.2.1,"Missing and too many parameters test"); COMMENT("Attempt to read a nonexistent parameter and write too many parameters"); - Svc::PrmDbImpl impl("PrmDbImpl","TestFile.prm"); + Svc::PrmDbImpl impl("PrmDbImpl"); impl.init(10,0); + impl.configure("TestFile.prm"); Svc::PrmDbImplTester tester(impl); @@ -146,9 +149,10 @@ TEST(ParameterDbTest,PrmFileReadError) { TEST_CASE(105.2.2,"File read errors"); COMMENT("Induce errors at various stages of reading the file"); - Svc::PrmDbImpl impl("PrmDbImpl","TestFile.prm"); + Svc::PrmDbImpl impl("PrmDbImpl"); impl.init(10,0); + impl.configure("TestFile.prm"); Svc::PrmDbImplTester tester(impl); @@ -167,9 +171,10 @@ TEST(ParameterDbTest,PrmFileWriteError) { TEST_CASE(105.2.3,"File write errors"); COMMENT("Induce errors at various stages of writing the file"); - Svc::PrmDbImpl impl("PrmDbImpl","TestFile.prm"); + Svc::PrmDbImpl impl("PrmDbImpl"); impl.init(10,0); + impl.configure("TestFile.prm"); Svc::PrmDbImplTester tester(impl); diff --git a/Svc/RateGroupDriver/CMakeLists.txt b/Svc/RateGroupDriver/CMakeLists.txt index 16a0130e57..d3e4d2eecd 100644 --- a/Svc/RateGroupDriver/CMakeLists.txt +++ b/Svc/RateGroupDriver/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/RateGroupDriver/RateGroupDriver.cpp b/Svc/RateGroupDriver/RateGroupDriver.cpp index f3bfe29a70..082a10f0eb 100644 --- a/Svc/RateGroupDriver/RateGroupDriver.cpp +++ b/Svc/RateGroupDriver/RateGroupDriver.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/Svc/RateGroupDriver/RateGroupDriver.hpp b/Svc/RateGroupDriver/RateGroupDriver.hpp index 3320d99257..57a3b18062 100644 --- a/Svc/RateGroupDriver/RateGroupDriver.hpp +++ b/Svc/RateGroupDriver/RateGroupDriver.hpp @@ -19,7 +19,7 @@ #define SVC_RATEGROUPDRIVER_HPP #include -#include +#include namespace Svc { diff --git a/Svc/Sched/CMakeLists.txt b/Svc/Sched/CMakeLists.txt index d949af19c3..ead9650f1d 100644 --- a/Svc/Sched/CMakeLists.txt +++ b/Svc/Sched/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME @@ -10,4 +10,8 @@ set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Sched.fpp" ) +set(MOD_DEPS + Fw/Port +) + register_fprime_module() diff --git a/Svc/Seq/CMakeLists.txt b/Svc/Seq/CMakeLists.txt index 33edc7fb87..f887794fc1 100644 --- a/Svc/Seq/CMakeLists.txt +++ b/Svc/Seq/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME @@ -10,4 +10,8 @@ set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/Seq.fpp" ) +set(MOD_DEPS + Fw/Port +) + register_fprime_module() diff --git a/Svc/StaticMemory/CMakeLists.txt b/Svc/StaticMemory/CMakeLists.txt index 0838dfbd76..8b80148bf3 100644 --- a/Svc/StaticMemory/CMakeLists.txt +++ b/Svc/StaticMemory/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/StaticMemory/StaticMemoryComponentImpl.cpp b/Svc/StaticMemory/StaticMemoryComponentImpl.cpp index cdf48881b3..a50b8de30b 100644 --- a/Svc/StaticMemory/StaticMemoryComponentImpl.cpp +++ b/Svc/StaticMemory/StaticMemoryComponentImpl.cpp @@ -11,7 +11,7 @@ // ====================================================================== #include -#include "Fw/Types/BasicTypes.hpp" +#include #include "Fw/Types/Assert.hpp" namespace Svc { diff --git a/Svc/SystemResources/CMakeLists.txt b/Svc/SystemResources/CMakeLists.txt index f7b2e5a07b..f5d65b1c6e 100644 --- a/Svc/SystemResources/CMakeLists.txt +++ b/Svc/SystemResources/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/SystemResources/SystemResources.cpp b/Svc/SystemResources/SystemResources.cpp index 9e34edf5d0..7de8f3b36f 100644 --- a/Svc/SystemResources/SystemResources.cpp +++ b/Svc/SystemResources/SystemResources.cpp @@ -13,7 +13,7 @@ #include //isnan() #include #include -#include "Fw/Types/BasicTypes.hpp" +#include namespace Svc { @@ -39,10 +39,6 @@ SystemResources ::SystemResources(const char* const compName) } m_cpu_count = (m_cpu_count >= CPU_COUNT) ? CPU_COUNT : m_cpu_count; -} - -void SystemResources ::init(const NATIVE_INT_TYPE instance) { - SystemResourcesComponentBase::init(instance); m_cpu_tlm_functions[0] = &Svc::SystemResources::tlmWrite_CPU_00; m_cpu_tlm_functions[1] = &Svc::SystemResources::tlmWrite_CPU_01; @@ -62,6 +58,10 @@ void SystemResources ::init(const NATIVE_INT_TYPE instance) { m_cpu_tlm_functions[15] = &Svc::SystemResources::tlmWrite_CPU_15; } +void SystemResources ::init(const NATIVE_INT_TYPE instance) { + SystemResourcesComponentBase::init(instance); +} + SystemResources ::~SystemResources() {} // ---------------------------------------------------------------------- @@ -142,8 +142,8 @@ void SystemResources::Mem() { } void SystemResources::PhysMem() { - U64 total = 0; - U64 free = 0; + FwSizeType total = 0; + FwSizeType free = 0; if (Os::FileSystem::getFreeSpace("/", total, free) == Os::FileSystem::OP_OK) { this->tlmWrite_NON_VOLATILE_FREE(free / 1024); diff --git a/Svc/SystemResources/docs/sdd.md b/Svc/SystemResources/docs/sdd.md new file mode 100644 index 0000000000..c89a5f269d --- /dev/null +++ b/Svc/SystemResources/docs/sdd.md @@ -0,0 +1,12 @@ +# System Resources Component + +The system resources component downlinks information about the running F´ system. This information includes: + +1. System and Software version +2. Free Memory +3. CPU load +4. Disk space + +These items are downlinked as telemetry channels in response to a rate group port invocation. + +**Note:** system resources requires `U64` types to be available on the target architecture. \ No newline at end of file diff --git a/Svc/SystemResources/test/ut/Tester.cpp b/Svc/SystemResources/test/ut/Tester.cpp index 19f5dbbfda..94d32ecdd4 100644 --- a/Svc/SystemResources/test/ut/Tester.cpp +++ b/Svc/SystemResources/test/ut/Tester.cpp @@ -88,19 +88,36 @@ void Tester ::test_tlm(bool enabled) { ASSERT_TLM_CPU_00_SIZE((enabled) ? 1 : 0); // Cascade expected default: + FwSizeType free = 0; + FwSizeType total = 0; + Os::SystemResources::MemUtil memory_info; ASSERT_TLM_CPU_SIZE((enabled) ? 1 : 0); - ASSERT_TLM_MEMORY_USED_SIZE((enabled) ? 1 : 0); - ASSERT_TLM_MEMORY_TOTAL_SIZE((enabled) ? 1 : 0); - ASSERT_TLM_NON_VOLATILE_FREE_SIZE((enabled) ? 1 : 0); - ASSERT_TLM_NON_VOLATILE_TOTAL_SIZE((enabled) ? 1 : 0); + // Check that the filesystem reads well before asserting telemetry + if (enabled && Os::SystemResources::getMemUtil(memory_info) == Os::SystemResources::SYSTEM_RESOURCES_OK) { + ASSERT_TLM_MEMORY_USED_SIZE(1); + ASSERT_TLM_MEMORY_TOTAL_SIZE(1); + count += 2; + } else { + ASSERT_TLM_MEMORY_USED_SIZE(0); + ASSERT_TLM_MEMORY_TOTAL_SIZE(0); + } + // Check that the filesystem reads well before asserting telemetry + if (enabled && Os::FileSystem::getFreeSpace("/", free, total ) == Os::FileSystem::OP_OK) { + ASSERT_TLM_NON_VOLATILE_FREE_SIZE(1); + ASSERT_TLM_NON_VOLATILE_TOTAL_SIZE(1); + count += 2; + } else { + ASSERT_TLM_NON_VOLATILE_FREE_SIZE(0); + ASSERT_TLM_NON_VOLATILE_TOTAL_SIZE(0); + } ASSERT_TLM_FRAMEWORK_VERSION_SIZE((enabled) ? 1 : 0); ASSERT_TLM_PROJECT_VERSION_SIZE((enabled) ? 1 : 0); if (enabled) { ASSERT_TLM_FRAMEWORK_VERSION(0, FRAMEWORK_VERSION); ASSERT_TLM_PROJECT_VERSION(0, PROJECT_VERSION); } - ASSERT_TLM_SIZE((enabled) ? (count + 7) : 0); // CPU count channels + avg + 2 mem + 2 non-volatile + 2 ver + ASSERT_TLM_SIZE((enabled) ? (count + 3) : 0); // CPU count channels + avg + 2 ver break; } } diff --git a/Svc/Time/CMakeLists.txt b/Svc/Time/CMakeLists.txt index f90de3eb46..0241f89c63 100644 --- a/Svc/Time/CMakeLists.txt +++ b/Svc/Time/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/TlmChan/CMakeLists.txt b/Svc/TlmChan/CMakeLists.txt index 09f6fc3bbe..c489718876 100644 --- a/Svc/TlmChan/CMakeLists.txt +++ b/Svc/TlmChan/CMakeLists.txt @@ -1,27 +1,23 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME #### set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/TlmChan.fpp" - "${CMAKE_CURRENT_LIST_DIR}/TlmChanImpl.cpp" - "${CMAKE_CURRENT_LIST_DIR}/TlmChanImplGet.cpp" - "${CMAKE_CURRENT_LIST_DIR}/TlmChanImplRecv.cpp" - "${CMAKE_CURRENT_LIST_DIR}/TlmChanImplTask.cpp" + "${CMAKE_CURRENT_LIST_DIR}/TlmChan.cpp" ) register_fprime_module() - ### UTs ### set(UT_SOURCE_FILES "${FPRIME_FRAMEWORK_PATH}/Svc/TlmChan/TlmChan.fpp" - "${CMAKE_CURRENT_LIST_DIR}/test/ut/TlmChanTester.cpp" - "${CMAKE_CURRENT_LIST_DIR}/test/ut/TlmChanImplTester.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Main.cpp" + "${CMAKE_CURRENT_LIST_DIR}/test/ut/Tester.cpp" ) register_fprime_ut() diff --git a/Svc/TlmChan/README b/Svc/TlmChan/README deleted file mode 100644 index 2547e93318..0000000000 --- a/Svc/TlmChan/README +++ /dev/null @@ -1,10 +0,0 @@ -This directory defines an implementation class for the Tlm component base class. It implements telemetry storage as a table accessed by the telemetry ID. -It has two alternate implementations. One does a linear lookup to find the telemetry entry in the table based on the telemetry ID. This is more space efficient, -but has slower performance because the table is traversed each time. The second uses the telemetry ID as an index into the table. It is faster but can be space -inefficient if there are disjoint telemetry IDs. Which version is used can be done by putting the desired file in the mod.mk file. - -TelemChannelImpl.hpp(.cpp) - implementation of the common functions of the telemetry storage -TelemChannelImpIndex.cpp - implements lookup by using the telemetry ID as an array index -TelemChannelLookup.cpp - implements lookup by traversing the table and looking for the ID -TelemChanTask.cpp - implements the rate group handler to write the telemetry to the downlink -TlmChanImplCfg.hpp - Contains configuration values for the component diff --git a/Svc/TlmChan/TlmChan.cpp b/Svc/TlmChan/TlmChan.cpp new file mode 100644 index 0000000000..2ecc2650c5 --- /dev/null +++ b/Svc/TlmChan/TlmChan.cpp @@ -0,0 +1,189 @@ +/** + * \file + * \author T. Canham + * \brief Implementation file for channelized telemetry storage component + * + * \copyright + * Copyright 2009-2015, by the California Institute of Technology. + * ALL RIGHTS RESERVED. United States Government Sponsorship + * acknowledged. + *

+ */ +#include +#include +#include +#include + +namespace Svc { + +TlmChan::TlmChan(const char* name) : TlmChanComponentBase(name), m_activeBuffer(0) { + // clear slot pointers + for (NATIVE_UINT_TYPE entry = 0; entry < TLMCHAN_NUM_TLM_HASH_SLOTS; entry++) { + this->m_tlmEntries[0].slots[entry] = nullptr; + this->m_tlmEntries[1].slots[entry] = nullptr; + } + // clear buckets + for (NATIVE_UINT_TYPE entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) { + this->m_tlmEntries[0].buckets[entry].used = false; + this->m_tlmEntries[0].buckets[entry].updated = false; + this->m_tlmEntries[0].buckets[entry].bucketNo = entry; + this->m_tlmEntries[0].buckets[entry].next = nullptr; + this->m_tlmEntries[0].buckets[entry].id = 0; + this->m_tlmEntries[1].buckets[entry].used = false; + this->m_tlmEntries[1].buckets[entry].updated = false; + this->m_tlmEntries[1].buckets[entry].bucketNo = entry; + this->m_tlmEntries[1].buckets[entry].next = nullptr; + this->m_tlmEntries[1].buckets[entry].id = 0; + } + // clear free index + this->m_tlmEntries[0].free = 0; + this->m_tlmEntries[1].free = 0; +} + +TlmChan::~TlmChan() {} + +void TlmChan::init(NATIVE_INT_TYPE queueDepth, /*!< The queue depth*/ + NATIVE_INT_TYPE instance /*!< The instance number*/ +) { + TlmChanComponentBase::init(queueDepth, instance); +} + +NATIVE_UINT_TYPE TlmChan::doHash(FwChanIdType id) { + return (id % TLMCHAN_HASH_MOD_VALUE) % TLMCHAN_NUM_TLM_HASH_SLOTS; +} + +void TlmChan::pingIn_handler(const NATIVE_INT_TYPE portNum, U32 key) { + // return key + this->pingOut_out(0, key); +} + +void TlmChan::TlmGet_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val) { + // Compute index for entry + + NATIVE_UINT_TYPE index = this->doHash(id); + + // Search to see if channel has been stored + TlmEntry* entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index]; + for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { + if (entryToUse) { // If bucket exists, check id + if (entryToUse->id == id) { + break; + } else { // otherwise go to next bucket + entryToUse = entryToUse->next; + } + } else { // no buckets left to search + break; + } + } + + if (entryToUse) { + val = entryToUse->buffer; + timeTag = entryToUse->lastUpdate; + } else { // requested entry may not be written yet; empty buffer + val.resetSer(); + } +} + +void TlmChan::TlmRecv_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val) { + // Compute index for entry + + NATIVE_UINT_TYPE index = this->doHash(id); + TlmEntry* entryToUse = nullptr; + TlmEntry* prevEntry = nullptr; + + // Search to see if channel has already been stored or a bucket needs to be added + if (this->m_tlmEntries[this->m_activeBuffer].slots[index]) { + entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index]; + for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { + if (entryToUse) { + if (entryToUse->id == id) { // found the matching entry + break; + } else { // try next entry + prevEntry = entryToUse; + entryToUse = entryToUse->next; + } + } else { + // Make sure that we haven't run out of buckets + FW_ASSERT(this->m_tlmEntries[this->m_activeBuffer].free < TLMCHAN_HASH_BUCKETS); + // add new bucket from free list + entryToUse = + &this->m_tlmEntries[this->m_activeBuffer].buckets[this->m_tlmEntries[this->m_activeBuffer].free++]; + FW_ASSERT(prevEntry); + prevEntry->next = entryToUse; + // clear next pointer + entryToUse->next = nullptr; + break; + } + } + } else { + // Make sure that we haven't run out of buckets + FW_ASSERT(this->m_tlmEntries[this->m_activeBuffer].free < TLMCHAN_HASH_BUCKETS); + // create new entry at slot head + this->m_tlmEntries[this->m_activeBuffer].slots[index] = + &this->m_tlmEntries[this->m_activeBuffer].buckets[this->m_tlmEntries[this->m_activeBuffer].free++]; + entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index]; + entryToUse->next = nullptr; + } + + // copy into entry + FW_ASSERT(entryToUse); + entryToUse->used = true; + entryToUse->id = id; + entryToUse->updated = true; + entryToUse->lastUpdate = timeTag; + entryToUse->buffer = val; +} + +void TlmChan::Run_handler(NATIVE_INT_TYPE portNum, NATIVE_UINT_TYPE context) { + // Only write packets if connected + if (not this->isConnected_PktSend_OutputPort(0)) { + return; + } + + // lock mutex long enough to modify active telemetry buffer + // so the data can be read without worrying about updates + this->lock(); + this->m_activeBuffer = 1 - this->m_activeBuffer; + // set activeBuffer to not updated + for (U32 entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) { + this->m_tlmEntries[this->m_activeBuffer].buckets[entry].updated = false; + } + this->unLock(); + + // go through each entry and send a packet if it has been updated + Fw::TlmPacket pkt; + pkt.resetPktSer(); + + for (U32 entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) { + TlmEntry* p_entry = &this->m_tlmEntries[1 - this->m_activeBuffer].buckets[entry]; + if ((p_entry->updated) && (p_entry->used)) { + Fw::SerializeStatus stat = pkt.addValue(p_entry->id, p_entry->lastUpdate, p_entry->buffer); + + // check to see if this packet is full, if so, send it + if (Fw::FW_SERIALIZE_NO_ROOM_LEFT == stat) { + this->PktSend_out(0, pkt.getBuffer(), 0); + // reset packet for more entries + pkt.resetPktSer(); + // add entry to new packet + Fw::SerializeStatus stat = pkt.addValue(p_entry->id, p_entry->lastUpdate, p_entry->buffer); + // if this doesn't work, that means packet isn't big enough for + // even one channel, so assert + FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, static_cast(stat)); + } else if (Fw::FW_SERIALIZE_OK == stat) { + // if there was still room, do nothing move on to the next channel in the packet + } else // any other status is an assert, since it shouldn't happen + { + FW_ASSERT(0, static_cast(stat)); + } + // flag as updated + p_entry->updated = false; + } // end if entry was updated + } // end for each entry + + // send remnant entries + if (pkt.getNumEntries() > 0) { + this->PktSend_out(0, pkt.getBuffer(), 0); + } +} // end run handler + +} // namespace Svc diff --git a/Svc/TlmChan/TlmChan.hpp b/Svc/TlmChan/TlmChan.hpp index 2b88093c1d..cbd30b1d67 100644 --- a/Svc/TlmChan/TlmChan.hpp +++ b/Svc/TlmChan/TlmChan.hpp @@ -1,17 +1,66 @@ -// ====================================================================== -// TlmChan.hpp -// Standardization header for TlmChan -// ====================================================================== +/** + * \file + * \author T. Canham + * \brief Component that stores telemetry channel values + * + * \copyright + * Copyright 2009-2015, by the California Institute of Technology. + * ALL RIGHTS RESERVED. United States Government Sponsorship + * acknowledged. + *

+ */ -#ifndef Svc_TlmChan_HPP -#define Svc_TlmChan_HPP +#ifndef TELEMCHANIMPL_HPP_ +#define TELEMCHANIMPL_HPP_ -#include "Svc/TlmChan/TlmChanImpl.hpp" +#include +#include +#include namespace Svc { - typedef TlmChanImpl TlmChan; +class TlmChan : public TlmChanComponentBase { + public: + TlmChan(const char* compName); + virtual ~TlmChan(); + void init(NATIVE_INT_TYPE queueDepth, /*!< The queue depth*/ + NATIVE_INT_TYPE instance /*!< The instance number*/ + ); -} + PROTECTED: + // can be overridden for alternate algorithms + virtual NATIVE_UINT_TYPE doHash(FwChanIdType id); -#endif + PRIVATE: + // Port functions + void TlmRecv_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val); + void TlmGet_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time& timeTag, Fw::TlmBuffer& val); + void Run_handler(NATIVE_INT_TYPE portNum, NATIVE_UINT_TYPE context); + //! Handler implementation for pingIn + //! + void pingIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + U32 key /*!< Value to return to pinger*/ + ); + + typedef struct tlmEntry { + FwChanIdType id; //!< telemetry id stored in slot + bool updated; //!< set whenever a value has been written. Used to skip if writing out values for downlinking + Fw::Time lastUpdate; //!< last updated time + Fw::TlmBuffer buffer; //!< buffer to store serialized telemetry + tlmEntry* next; //!< pointer to next bucket in table + bool used; //!< if entry has been used + NATIVE_UINT_TYPE bucketNo; //!< for testing + } TlmEntry; + + struct TlmSet { + TlmEntry* slots[TLMCHAN_NUM_TLM_HASH_SLOTS]; //!< set of hash slots in hash table + TlmEntry buckets[TLMCHAN_HASH_BUCKETS]; //!< set of buckets used in hash table + NATIVE_INT_TYPE free; //!< next free bucket + } m_tlmEntries[2]; + + U32 m_activeBuffer; // !< which buffer is active for storing telemetry +}; + +} // namespace Svc + +#endif /* TELEMCHANIMPL_HPP_ */ diff --git a/Svc/TlmChan/TlmChanImpl.cpp b/Svc/TlmChan/TlmChanImpl.cpp deleted file mode 100644 index 69f16727ae..0000000000 --- a/Svc/TlmChan/TlmChanImpl.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/** - * \file - * \author T. Canham - * \brief Implementation file for channelized telemetry storage component - * - * \copyright - * Copyright 2009-2015, by the California Institute of Technology. - * ALL RIGHTS RESERVED. United States Government Sponsorship - * acknowledged. - *

- */ -#include -#include -#include -#include -#include - -#include - -namespace Svc { - - TlmChanImpl::TlmChanImpl(const char* name) : TlmChanComponentBase(name) - { - // clear data - this->m_activeBuffer = 0; - // clear slot pointers - for (NATIVE_UINT_TYPE entry = 0; entry < TLMCHAN_NUM_TLM_HASH_SLOTS; entry++) { - this->m_tlmEntries[0].slots[entry] = nullptr; - this->m_tlmEntries[1].slots[entry] = nullptr; - } - // clear buckets - for (NATIVE_UINT_TYPE entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) { - this->m_tlmEntries[0].buckets[entry].used = false; - this->m_tlmEntries[0].buckets[entry].updated = false; - this->m_tlmEntries[0].buckets[entry].bucketNo = entry; - this->m_tlmEntries[0].buckets[entry].next = nullptr; - this->m_tlmEntries[0].buckets[entry].id = 0; - this->m_tlmEntries[1].buckets[entry].used = false; - this->m_tlmEntries[1].buckets[entry].updated = false; - this->m_tlmEntries[1].buckets[entry].bucketNo = entry; - this->m_tlmEntries[1].buckets[entry].next = nullptr; - this->m_tlmEntries[1].buckets[entry].id = 0; - } - // clear free index - this->m_tlmEntries[0].free = 0; - this->m_tlmEntries[1].free = 0; - - - } - - TlmChanImpl::~TlmChanImpl() { - } - - void TlmChanImpl::init( - NATIVE_INT_TYPE queueDepth, /*!< The queue depth*/ - NATIVE_INT_TYPE instance /*!< The instance number*/ - ) { - TlmChanComponentBase::init(queueDepth,instance); - } - - NATIVE_UINT_TYPE TlmChanImpl::doHash(FwChanIdType id) { - return (id % TLMCHAN_HASH_MOD_VALUE)%TLMCHAN_NUM_TLM_HASH_SLOTS; - } - - void TlmChanImpl::pingIn_handler( - const NATIVE_INT_TYPE portNum, - U32 key - ) - { - // return key - this->pingOut_out(0,key); - } - - -} diff --git a/Svc/TlmChan/TlmChanImpl.hpp b/Svc/TlmChan/TlmChanImpl.hpp deleted file mode 100644 index 3a7f801cb9..0000000000 --- a/Svc/TlmChan/TlmChanImpl.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/** - * \file - * \author T. Canham - * \brief Component that stores telemetry channel values - * - * \copyright - * Copyright 2009-2015, by the California Institute of Technology. - * ALL RIGHTS RESERVED. United States Government Sponsorship - * acknowledged. - *

- */ - -#ifndef TELEMCHANIMPL_HPP_ -#define TELEMCHANIMPL_HPP_ - -#include -#include -#include -#include - -namespace Svc { - - class TlmChanImpl: public TlmChanComponentBase { - public: - friend class TlmChanImplTester; - TlmChanImpl(const char* compName); - virtual ~TlmChanImpl(); - void init( - NATIVE_INT_TYPE queueDepth, /*!< The queue depth*/ - NATIVE_INT_TYPE instance /*!< The instance number*/ - ); - PROTECTED: - - // can be overridden for alternate algorithms - virtual NATIVE_UINT_TYPE doHash(FwChanIdType id); - - PRIVATE: - - // Port functions - void TlmRecv_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time &timeTag, Fw::TlmBuffer &val); - void TlmGet_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time &timeTag, Fw::TlmBuffer &val); - void Run_handler(NATIVE_INT_TYPE portNum, NATIVE_UINT_TYPE context); - //! Handler implementation for pingIn - //! - void pingIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - U32 key /*!< Value to return to pinger*/ - ); - - typedef struct tlmEntry { - FwChanIdType id; //!< telemetry id stored in slot - bool updated; //!< set whenever a value has been written. Used to skip if writing out values for downlinking - Fw::Time lastUpdate; //!< last updated time - Fw::TlmBuffer buffer; //!< buffer to store serialized telemetry - tlmEntry* next; //!< pointer to next bucket in table - bool used; //!< if entry has been used - NATIVE_UINT_TYPE bucketNo; //!< for testing - } TlmEntry; - - struct TlmSet { - TlmEntry* slots[TLMCHAN_NUM_TLM_HASH_SLOTS]; //!< set of hash slots in hash table - TlmEntry buckets[TLMCHAN_HASH_BUCKETS]; //!< set of buckets used in hash table - NATIVE_INT_TYPE free; //!< next free bucket - } m_tlmEntries[2]; - - U32 m_activeBuffer; // !< which buffer is active for storing telemetry - - // work variables - Fw::ComBuffer m_comBuffer; - Fw::TlmPacket m_tlmPacket; - - }; - -} - -#endif /* TELEMCHANIMPL_HPP_ */ diff --git a/Svc/TlmChan/TlmChanImplGet.cpp b/Svc/TlmChan/TlmChanImplGet.cpp deleted file mode 100644 index a5f54c7bce..0000000000 --- a/Svc/TlmChan/TlmChanImplGet.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * TelemChanImpl.cpp - * - * Created on: Mar 28, 2014 - * Author: tcanham - */ - -#include -#include -#include -#include - -#include - -namespace Svc { - - void TlmChanImpl::TlmGet_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time &timeTag, Fw::TlmBuffer &val) { - - // Compute index for entry - - NATIVE_UINT_TYPE index = this->doHash(id); - - // Search to see if channel has been stored - TlmEntry *entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index]; - for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { - if (entryToUse) { // If bucket exists, check id - if (entryToUse->id == id) { - break; - } else { // otherwise go to next bucket - entryToUse = entryToUse->next; - } - } else { // no buckets left to search - break; - } - } - - if (entryToUse) { - val = entryToUse->buffer; - timeTag = entryToUse->lastUpdate; - } else { // requested entry may not be written yet; empty buffer - val.resetSer(); - } - - } -} diff --git a/Svc/TlmChan/TlmChanImplRecv.cpp b/Svc/TlmChan/TlmChanImplRecv.cpp deleted file mode 100644 index 4ea477b8ef..0000000000 --- a/Svc/TlmChan/TlmChanImplRecv.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * TelemChanImpl.cpp - * - * Created on: Mar 28, 2014 - * Author: tcanham - */ - -#include -#include -#include -#include - -#include - -namespace Svc { - - void TlmChanImpl::TlmRecv_handler(NATIVE_INT_TYPE portNum, FwChanIdType id, Fw::Time &timeTag, Fw::TlmBuffer &val) { - - // Compute index for entry - - NATIVE_UINT_TYPE index = this->doHash(id); - TlmEntry* entryToUse = nullptr; - TlmEntry* prevEntry = nullptr; - - // Search to see if channel has already been stored or a bucket needs to be added - if (this->m_tlmEntries[this->m_activeBuffer].slots[index]) { - entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index]; - for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { - if (entryToUse) { - if (entryToUse->id == id) { // found the matching entry - break; - } else { // try next entry - prevEntry = entryToUse; - entryToUse = entryToUse->next; - } - } else { - // Make sure that we haven't run out of buckets - FW_ASSERT(this->m_tlmEntries[this->m_activeBuffer].free < TLMCHAN_HASH_BUCKETS); - // add new bucket from free list - entryToUse = &this->m_tlmEntries[this->m_activeBuffer].buckets[this->m_tlmEntries[this->m_activeBuffer].free++]; - FW_ASSERT(prevEntry); - prevEntry->next = entryToUse; - // clear next pointer - entryToUse->next = nullptr; - break; - } - } - } else { - // Make sure that we haven't run out of buckets - FW_ASSERT(this->m_tlmEntries[this->m_activeBuffer].free < TLMCHAN_HASH_BUCKETS); - // create new entry at slot head - this->m_tlmEntries[this->m_activeBuffer].slots[index] = &this->m_tlmEntries[this->m_activeBuffer].buckets[this->m_tlmEntries[this->m_activeBuffer].free++]; - entryToUse = this->m_tlmEntries[this->m_activeBuffer].slots[index]; - entryToUse->next = nullptr; - } - - // copy into entry - FW_ASSERT(entryToUse); - entryToUse->used = true; - entryToUse->id = id; - entryToUse->updated = true; - entryToUse->lastUpdate = timeTag; - entryToUse->buffer = val; - - } -} diff --git a/Svc/TlmChan/TlmChanImplTask.cpp b/Svc/TlmChan/TlmChanImplTask.cpp deleted file mode 100644 index d44b9a1488..0000000000 --- a/Svc/TlmChan/TlmChanImplTask.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/** - * \file - * \author T. Canham - * \brief Implementation for telemetry channel component thread. - * - * \copyright - * Copyright 2009-2015, by the California Institute of Technology. - * ALL RIGHTS RESERVED. United States Government Sponsorship - * acknowledged. - *

- */ - -#include -#include -#include -#include -#include -#include - -#include - -namespace Svc { - - void TlmChanImpl::Run_handler(NATIVE_INT_TYPE portNum, NATIVE_UINT_TYPE context) { - // Only write packets if connected - if (not this->isConnected_PktSend_OutputPort(0)) { - return; - } - - // lock mutex long enough to modify active telemetry buffer - // so the data can be read without worrying about updates - this->lock(); - this->m_activeBuffer = 1 - this->m_activeBuffer; - // set activeBuffer to not updated - for (U32 entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) { - this->m_tlmEntries[this->m_activeBuffer].buckets[entry].updated = false; - } - this->unLock(); - - // go through each entry and send a packet if it has been updated - - for (U32 entry = 0; entry < TLMCHAN_HASH_BUCKETS; entry++) { - TlmEntry* p_entry = &this->m_tlmEntries[1-this->m_activeBuffer].buckets[entry]; - if ((p_entry->updated) && (p_entry->used)) { - this->m_tlmPacket.setId(p_entry->id); - this->m_tlmPacket.setTimeTag(p_entry->lastUpdate); - this->m_tlmPacket.setTlmBuffer(p_entry->buffer); - this->m_comBuffer.resetSer(); - Fw::SerializeStatus stat = this->m_tlmPacket.serialize(this->m_comBuffer); - FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,static_cast(stat)); - p_entry->updated = false; - this->PktSend_out(0,this->m_comBuffer,0); - } - } - } - -} diff --git a/Svc/TlmChan/docs/sdd.md b/Svc/TlmChan/docs/sdd.md index 31c612a0f4..6cd8086d92 100644 --- a/Svc/TlmChan/docs/sdd.md +++ b/Svc/TlmChan/docs/sdd.md @@ -44,7 +44,7 @@ Port Data Type | Name | Direction | Kind | Usage The `Svc::TlmChan` component has an input port `TlmRecv` that receives channel updates from other components in the system. These calls from the other components are made by the component implementation classes, but the generated code in the base classes takes the type specific channel value and serializes it, then makes the call to the output port. The `Svc::TlmChan` component can then store the channel value as generic data. The channel values are stored in an internal double-buffered table, and a flag is set when a new value is written to the channel entry. -When a request is made for a nonexistent channel, the call will return with an empty buffer in the Fw::TlmBuffer value argument. This is to cover the case where a channel is defined in the system, but has not been written yet. If the channel has not ever been defined, there is no way to programmatically determine that from the TlmGet port call. +When a request is made for a nonexistent channel, the call will return with an empty buffer in the Fw::TlmBuffer value argument. This is to cover the case where a channel is defined in the system, but has not been written yet. If the channel has not ever been defined, there is no way to programmatically determine that from the TlmGet port call. The implementation uses a hashing function that is tuned in the configuration file `TlmChanImplCfg.hpp`. See section 3.5 for description. diff --git a/Svc/TlmChan/run.txt b/Svc/TlmChan/run.txt deleted file mode 100644 index e675f2ec9c..0000000000 --- a/Svc/TlmChan/run.txt +++ /dev/null @@ -1,4342 +0,0 @@ -Compiling ut_CYGWIN unit test for SvcTlmChan -make[1]: Entering directory '/home/tcanham/source/isf/Svc/TlmChan' -mkdir -p /home/tcanham/source/isf/Svc/TlmChan/test/ut/linux-cygwin-x86-ut-gnu-bin -/usr/bin/g++ -DASSERT_FILE_ID=314589494 -MMD -MP -MF/home/tcanham/source/isf/Svc/TlmChan/test/ut/linux-cygwin-x86-ut-gnu-bin/TelemChanTester.d -g3 -DTGT_OS_TYPE_LINUX -DISF -DBUILD_CYGWIN -Wall -Wextra -fno-builtin -fno-asm -fstrength-reduce -Wno-unused-parameter -Wno-long-long -fcheck-new -Wnon-virtual-dtor -m32 -I/home/tcanham/source/isf/Fw/Types/Linux -I/home/tcanham/source/isf -I/home/tcanham/source/isf/gtest/include -I/home/tcanham/source/isf/gtest -fprofile-arcs -ftest-coverage -DSTATIC= -DBUILD_UT -DPROTECTED=public -DPRIVATE=public -I/home/tcanham/source/isf/Svc/TlmChan/test/ut/ -c -o /home/tcanham/source/isf/Svc/TlmChan/test/ut/linux-cygwin-x86-ut-gnu-bin/TelemChanTester.o /home/tcanham/source/isf/Svc/TlmChan/test/ut/TelemChanTester.cpp -mkdir -p /home/tcanham/source/isf/Svc/TlmChan/test/ut/linux-cygwin-x86-ut-gnu-bin -/usr/bin/ar rcs /home/tcanham/source/isf/Svc/TlmChan/test/ut/linux-cygwin-x86-ut-gnu-bin/test_ut_test_lib.a /home/tcanham/source/isf/Svc/TlmChan/test/ut/linux-cygwin-x86-ut-gnu-bin/TelemStoreComponentTestAc.o /home/tcanham/source/isf/Svc/TlmChan/test/ut/linux-cygwin-x86-ut-gnu-bin/TelemChanTester.o /home/tcanham/source/isf/Svc/TlmChan/test/ut/linux-cygwin-x86-ut-gnu-bin/TelemChanImplTester.o -/usr/bin/g++ -m32 -fprofile-arcs -ftest-coverage -o /home/tcanham/source/isf/Svc/TlmChan/test/ut/linux-cygwin-x86-ut-gnu-bin/test_ut /home/tcanham/source/isf/Svc/TlmChan/test/ut/linux-cygwin-x86-ut-gnu-bin/test_ut_test_lib.a /home/tcanham/source/isf/Svc/Tlm/linux-cygwin-x86-ut-gnu-bin/libSvcTlm.a /home/tcanham/source/isf/Svc/TlmChan/linux-cygwin-x86-ut-gnu-bin/libSvcTlmChan.a /home/tcanham/source/isf/Fw/Tlm/linux-cygwin-x86-ut-gnu-bin/libFwTlm.a /home/tcanham/source/isf/Fw/Com/linux-cygwin-x86-ut-gnu-bin/libFwCom.a /home/tcanham/source/isf/Fw/Comp/linux-cygwin-x86-ut-gnu-bin/libFwComp.a /home/tcanham/source/isf/Fw/Log/linux-cygwin-x86-ut-gnu-bin/libFwLog.a /home/tcanham/source/isf/Fw/Obj/linux-cygwin-x86-ut-gnu-bin/libFwObj.a /home/tcanham/source/isf/Fw/Port/linux-cygwin-x86-ut-gnu-bin/libFwPort.a /home/tcanham/source/isf/Fw/Time/linux-cygwin-x86-ut-gnu-bin/libFwTime.a /home/tcanham/source/isf/Fw/Types/linux-cygwin-x86-ut-gnu-bin/libFwTypes.a /home/tcanham/source/isf/Svc/Sched/linux-cygwin-x86-ut-gnu-bin/libSvcSched.a /home/tcanham/source/isf/Os/linux-cygwin-x86-ut-gnu-bin/libOs.a /home/tcanham/source/isf/gtest/linux-cygwin-x86-ut-gnu-bin/libgtest.a -ldl -lpthread -lm -lrt -make[1]: Leaving directory '/home/tcanham/source/isf/Svc/TlmChan' -Running unit test for SvcTlmChan -make[1]: Entering directory '/home/tcanham/source/isf/Svc/TlmChan' -Running test/ut/runtest_CYGWIN with output dir linux-cygwin-x86-ut-gnu-bin -test/ut/runtest_CYGWIN linux-cygwin-x86-ut-gnu-bin -Running /home/tcanham/source/isf/Svc/TlmChan/test/ut/linux-cygwin-x86-ut-gnu-bin/test_ut -[==========] Running 3 tests from 1 test case. -[----------] Global test environment set-up. -[----------] 3 tests from TlmChanTest -[ RUN ] TlmChanTest.NominalChannelTest - -*************************************** -Nominal Channel Test -*************************************** -**Buffer 0 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -Entry Ptr: 0x29aee4 id: 27 bucket: 0 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 27 bucket: 0 next: 0x0 -Bucket: 1 Entry Ptr: 0x29af54 id: 0 bucket: 1 next: 0x0 -Bucket: 2 Entry Ptr: 0x29afc4 id: 0 bucket: 2 next: 0x0 -Bucket: 3 Entry Ptr: 0x29b034 id: 0 bucket: 3 next: 0x0 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 Entry Ptr: 0x29b114 id: 0 bucket: 5 next: 0x0 -Bucket: 6 Entry Ptr: 0x29b184 id: 0 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 0 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 0 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 0 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 0 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 0 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -Entry Ptr: 0x29aee4 id: 27 bucket: 0 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 27 bucket: 0 next: 0x0 -Bucket: 1 Entry Ptr: 0x29af54 id: 0 bucket: 1 next: 0x0 -Bucket: 2 Entry Ptr: 0x29afc4 id: 0 bucket: 2 next: 0x0 -Bucket: 3 Entry Ptr: 0x29b034 id: 0 bucket: 3 next: 0x0 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 Entry Ptr: 0x29b114 id: 0 bucket: 5 next: 0x0 -Bucket: 6 Entry Ptr: 0x29b184 id: 0 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 0 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 0 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 0 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 0 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 0 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -Entry Ptr: 0x29bc24 id: 27 bucket: 0 next: 0x0 - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 27 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -Entry Ptr: 0x29aee4 id: 27 bucket: 0 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 27 bucket: 0 next: 0x0 -Bucket: 1 Entry Ptr: 0x29af54 id: 0 bucket: 1 next: 0x0 -Bucket: 2 Entry Ptr: 0x29afc4 id: 0 bucket: 2 next: 0x0 -Bucket: 3 Entry Ptr: 0x29b034 id: 0 bucket: 3 next: 0x0 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 Entry Ptr: 0x29b114 id: 0 bucket: 5 next: 0x0 -Bucket: 6 Entry Ptr: 0x29b184 id: 0 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 0 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 0 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 0 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 0 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 0 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -Entry Ptr: 0x29bc24 id: 27 bucket: 0 next: 0x0 - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 27 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -[ OK ] TlmChanTest.NominalChannelTest (3 ms) -[ RUN ] TlmChanTest.MultiChannelTest - -*************************************** -Multiple Channel Test -*************************************** -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x0 -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x0 -Bucket: 1 Entry Ptr: 0x29af54 id: 0 bucket: 1 next: 0x0 -Bucket: 2 Entry Ptr: 0x29afc4 id: 0 bucket: 2 next: 0x0 -Bucket: 3 Entry Ptr: 0x29b034 id: 0 bucket: 3 next: 0x0 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 Entry Ptr: 0x29b114 id: 0 bucket: 5 next: 0x0 -Bucket: 6 Entry Ptr: 0x29b184 id: 0 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 0 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 0 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 0 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 0 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 0 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x0 -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x0 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x0 -Bucket: 2 Entry Ptr: 0x29afc4 id: 0 bucket: 2 next: 0x0 -Bucket: 3 Entry Ptr: 0x29b034 id: 0 bucket: 3 next: 0x0 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 Entry Ptr: 0x29b114 id: 0 bucket: 5 next: 0x0 -Bucket: 6 Entry Ptr: 0x29b184 id: 0 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 0 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 0 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 0 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 0 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 0 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x0 -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x0 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x0 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x0 -Bucket: 3 Entry Ptr: 0x29b034 id: 0 bucket: 3 next: 0x0 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 Entry Ptr: 0x29b114 id: 0 bucket: 5 next: 0x0 -Bucket: 6 Entry Ptr: 0x29b184 id: 0 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 0 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 0 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 0 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 0 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 0 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x0 -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x0 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x0 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x0 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x0 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 Entry Ptr: 0x29b114 id: 0 bucket: 5 next: 0x0 -Bucket: 6 Entry Ptr: 0x29b184 id: 0 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 0 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 0 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 0 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 0 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 0 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x0 -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x0 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x0 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x0 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x0 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x0 -Bucket: 5 Entry Ptr: 0x29b114 id: 0 bucket: 5 next: 0x0 -Bucket: 6 Entry Ptr: 0x29b184 id: 0 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 0 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 0 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 0 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 0 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 0 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x0 -Slot: 6 -EMPTY - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x0 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x0 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x0 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x0 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x0 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x0 -Bucket: 6 Entry Ptr: 0x29b184 id: 0 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 0 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 0 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 0 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 0 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 0 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x0 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x0 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x0 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x0 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x0 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x0 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 0 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 0 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 0 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 0 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 0 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x0 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x0 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x0 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x0 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x0 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 0 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 0 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 0 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 0 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x0 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x0 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x0 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x0 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 0 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 0 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 0 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x0 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x0 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x0 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 0 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 0 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x0 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x0 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 0 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x0 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 0 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x0 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 0 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x0 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 0 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x0 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 0 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x0 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 0 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x0 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 0 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x0 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 0 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x0 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 0 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x0 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x0 -Bucket: 15 Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 0 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Bucket: 15 Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x0 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 0 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Bucket: 15 Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x0 -Bucket: 17 Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 0 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x29b8f4 -Entry Ptr: 0x29b8f4 id: 123 bucket: 23 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Bucket: 15 Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x29b8f4 -Bucket: 17 Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x0 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 123 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 0 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x29b8f4 -Entry Ptr: 0x29b8f4 id: 123 bucket: 23 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x29b964 -Entry Ptr: 0x29b964 id: 124 bucket: 24 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Bucket: 15 Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x29b8f4 -Bucket: 17 Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x29b964 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x0 -Bucket: 19 Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 123 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 124 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 0 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x29b8f4 -Entry Ptr: 0x29b8f4 id: 123 bucket: 23 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x29b964 -Entry Ptr: 0x29b964 id: 124 bucket: 24 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x29b9d4 -Entry Ptr: 0x29b9d4 id: 125 bucket: 25 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Bucket: 15 Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x29b8f4 -Bucket: 17 Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x29b964 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x29b9d4 -Bucket: 19 Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x0 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 123 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 124 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 125 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 0 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x29b8f4 -Entry Ptr: 0x29b8f4 id: 123 bucket: 23 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x29b964 -Entry Ptr: 0x29b964 id: 124 bucket: 24 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x29b9d4 -Entry Ptr: 0x29b9d4 id: 125 bucket: 25 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x29ba44 -Entry Ptr: 0x29ba44 id: 126 bucket: 26 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Bucket: 15 Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x29b8f4 -Bucket: 17 Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x29b964 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x29b9d4 -Bucket: 19 Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x29ba44 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x0 -Bucket: 21 Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 123 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 124 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 125 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 126 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x29b8f4 -Entry Ptr: 0x29b8f4 id: 123 bucket: 23 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x29b964 -Entry Ptr: 0x29b964 id: 124 bucket: 24 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x29b9d4 -Entry Ptr: 0x29b9d4 id: 125 bucket: 25 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x29ba44 -Entry Ptr: 0x29ba44 id: 126 bucket: 26 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x29bab4 -Entry Ptr: 0x29bab4 id: 127 bucket: 27 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Bucket: 15 Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x29b8f4 -Bucket: 17 Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x29b964 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x29b9d4 -Bucket: 19 Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x29ba44 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x29bab4 -Bucket: 21 Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x0 -Bucket: 22 Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 123 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 124 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 125 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 126 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 127 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 0 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x29bb24 -Entry Ptr: 0x29bb24 id: 128 bucket: 28 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x29b8f4 -Entry Ptr: 0x29b8f4 id: 123 bucket: 23 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x29b964 -Entry Ptr: 0x29b964 id: 124 bucket: 24 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x29b9d4 -Entry Ptr: 0x29b9d4 id: 125 bucket: 25 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x29ba44 -Entry Ptr: 0x29ba44 id: 126 bucket: 26 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x29bab4 -Entry Ptr: 0x29bab4 id: 127 bucket: 27 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Bucket: 15 Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x29b8f4 -Bucket: 17 Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x29b964 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x29b9d4 -Bucket: 19 Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x29ba44 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x29bab4 -Bucket: 21 Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x29bb24 -Bucket: 22 Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x0 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 123 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 124 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 125 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 126 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 127 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 128 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 0 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -**Buffer 0 -Slot: 0 -Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x29bb24 -Entry Ptr: 0x29bb24 id: 128 bucket: 28 next: 0x0 -Slot: 1 -Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x29bb94 -Entry Ptr: 0x29bb94 id: 129 bucket: 29 next: 0x0 -Slot: 2 -Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x29b8f4 -Entry Ptr: 0x29b8f4 id: 123 bucket: 23 next: 0x0 -Slot: 3 -Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x29b964 -Entry Ptr: 0x29b964 id: 124 bucket: 24 next: 0x0 -Slot: 4 -Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x29b9d4 -Entry Ptr: 0x29b9d4 id: 125 bucket: 25 next: 0x0 -Slot: 5 -Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x29ba44 -Entry Ptr: 0x29ba44 id: 126 bucket: 26 next: 0x0 -Slot: 6 -Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x29bab4 -Entry Ptr: 0x29bab4 id: 127 bucket: 27 next: 0x0 - -Bucket: 0 Entry Ptr: 0x29aee4 id: 100 bucket: 0 next: 0x29b1f4 -Bucket: 1 Entry Ptr: 0x29af54 id: 101 bucket: 1 next: 0x29b264 -Bucket: 2 Entry Ptr: 0x29afc4 id: 102 bucket: 2 next: 0x29b2d4 -Bucket: 3 Entry Ptr: 0x29b034 id: 103 bucket: 3 next: 0x29b344 -Bucket: 4 Entry Ptr: 0x29b0a4 id: 104 bucket: 4 next: 0x29b3b4 -Bucket: 5 Entry Ptr: 0x29b114 id: 105 bucket: 5 next: 0x29b424 -Bucket: 6 Entry Ptr: 0x29b184 id: 106 bucket: 6 next: 0x29b494 -Bucket: 7 Entry Ptr: 0x29b1f4 id: 107 bucket: 7 next: 0x29b504 -Bucket: 8 Entry Ptr: 0x29b264 id: 108 bucket: 8 next: 0x29b574 -Bucket: 9 Entry Ptr: 0x29b2d4 id: 109 bucket: 9 next: 0x29b5e4 -Bucket: 10 Entry Ptr: 0x29b344 id: 110 bucket: 10 next: 0x29b654 -Bucket: 11 Entry Ptr: 0x29b3b4 id: 111 bucket: 11 next: 0x29b6c4 -Bucket: 12 Entry Ptr: 0x29b424 id: 112 bucket: 12 next: 0x29b734 -Bucket: 13 Entry Ptr: 0x29b494 id: 113 bucket: 13 next: 0x29b7a4 -Bucket: 14 Entry Ptr: 0x29b504 id: 114 bucket: 14 next: 0x29b814 -Bucket: 15 Entry Ptr: 0x29b574 id: 115 bucket: 15 next: 0x29b884 -Bucket: 16 Entry Ptr: 0x29b5e4 id: 116 bucket: 16 next: 0x29b8f4 -Bucket: 17 Entry Ptr: 0x29b654 id: 117 bucket: 17 next: 0x29b964 -Bucket: 18 Entry Ptr: 0x29b6c4 id: 118 bucket: 18 next: 0x29b9d4 -Bucket: 19 Entry Ptr: 0x29b734 id: 119 bucket: 19 next: 0x29ba44 -Bucket: 20 Entry Ptr: 0x29b7a4 id: 120 bucket: 20 next: 0x29bab4 -Bucket: 21 Entry Ptr: 0x29b814 id: 121 bucket: 21 next: 0x29bb24 -Bucket: 22 Entry Ptr: 0x29b884 id: 122 bucket: 22 next: 0x29bb94 -Bucket: 23 Entry Ptr: 0x29b8f4 id: 123 bucket: 23 next: 0x0 -Bucket: 24 Entry Ptr: 0x29b964 id: 124 bucket: 24 next: 0x0 -Bucket: 25 Entry Ptr: 0x29b9d4 id: 125 bucket: 25 next: 0x0 -Bucket: 26 Entry Ptr: 0x29ba44 id: 126 bucket: 26 next: 0x0 -Bucket: 27 Entry Ptr: 0x29bab4 id: 127 bucket: 27 next: 0x0 -Bucket: 28 Entry Ptr: 0x29bb24 id: 128 bucket: 28 next: 0x0 -Bucket: 29 Entry Ptr: 0x29bb94 id: 129 bucket: 29 next: 0x0 -**Buffer 1 -Slot: 0 -EMPTY -Slot: 1 -EMPTY -Slot: 2 -EMPTY -Slot: 3 -EMPTY -Slot: 4 -EMPTY -Slot: 5 -EMPTY -Slot: 6 -EMPTY - -Bucket: 0 -Entry Ptr: 0x29bc24 id: 0 bucket: 0 next: 0x0 -Bucket: 1 -Entry Ptr: 0x29bc94 id: 0 bucket: 1 next: 0x0 -Bucket: 2 -Entry Ptr: 0x29bd04 id: 0 bucket: 2 next: 0x0 -Bucket: 3 -Entry Ptr: 0x29bd74 id: 0 bucket: 3 next: 0x0 -Bucket: 4 -Entry Ptr: 0x29bde4 id: 0 bucket: 4 next: 0x0 -Bucket: 5 -Entry Ptr: 0x29be54 id: 0 bucket: 5 next: 0x0 -Bucket: 6 -Entry Ptr: 0x29bec4 id: 0 bucket: 6 next: 0x0 -Bucket: 7 -Entry Ptr: 0x29bf34 id: 0 bucket: 7 next: 0x0 -Bucket: 8 -Entry Ptr: 0x29bfa4 id: 0 bucket: 8 next: 0x0 -Bucket: 9 -Entry Ptr: 0x29c014 id: 0 bucket: 9 next: 0x0 -Bucket: 10 -Entry Ptr: 0x29c084 id: 0 bucket: 10 next: 0x0 -Bucket: 11 -Entry Ptr: 0x29c0f4 id: 0 bucket: 11 next: 0x0 -Bucket: 12 -Entry Ptr: 0x29c164 id: 0 bucket: 12 next: 0x0 -Bucket: 13 -Entry Ptr: 0x29c1d4 id: 0 bucket: 13 next: 0x0 -Bucket: 14 -Entry Ptr: 0x29c244 id: 0 bucket: 14 next: 0x0 -Bucket: 15 -Entry Ptr: 0x29c2b4 id: 0 bucket: 15 next: 0x0 -Bucket: 16 -Entry Ptr: 0x29c324 id: 0 bucket: 16 next: 0x0 -Bucket: 17 -Entry Ptr: 0x29c394 id: 0 bucket: 17 next: 0x0 -Bucket: 18 -Entry Ptr: 0x29c404 id: 0 bucket: 18 next: 0x0 -Bucket: 19 -Entry Ptr: 0x29c474 id: 0 bucket: 19 next: 0x0 -Bucket: 20 -Entry Ptr: 0x29c4e4 id: 0 bucket: 20 next: 0x0 -Bucket: 21 -Entry Ptr: 0x29c554 id: 0 bucket: 21 next: 0x0 -Bucket: 22 -Entry Ptr: 0x29c5c4 id: 0 bucket: 22 next: 0x0 -Bucket: 23 -Entry Ptr: 0x29c634 id: 0 bucket: 23 next: 0x0 -Bucket: 24 -Entry Ptr: 0x29c6a4 id: 0 bucket: 24 next: 0x0 -Bucket: 25 -Entry Ptr: 0x29c714 id: 0 bucket: 25 next: 0x0 -Bucket: 26 -Entry Ptr: 0x29c784 id: 0 bucket: 26 next: 0x0 -Bucket: 27 -Entry Ptr: 0x29c7f4 id: 0 bucket: 27 next: 0x0 -Bucket: 28 -Entry Ptr: 0x29c864 id: 0 bucket: 28 next: 0x0 -Bucket: 29 -Entry Ptr: 0x29c8d4 id: 0 bucket: 29 next: 0x0 -[ OK ] TlmChanTest.MultiChannelTest (6 ms) -[ RUN ] TlmChanTest.OffNominal - -*************************************** -Off-nominal Channel Test -*************************************** -[ OK ] TlmChanTest.OffNominal (2 ms) -[----------] 3 tests from TlmChanTest (11 ms total) - -[----------] Global test environment tear-down -[==========] 3 tests from 1 test case ran. (11 ms total) -[ PASSED ] 3 tests. -make[1]: Leaving directory '/home/tcanham/source/isf/Svc/TlmChan' diff --git a/Svc/TlmChan/test/perf/TelemChanImplTester.cpp b/Svc/TlmChan/test/perf/TelemChanImplTester.cpp deleted file mode 100644 index 2e67813115..0000000000 --- a/Svc/TlmChan/test/perf/TelemChanImplTester.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * PrmDbImplTester.cpp - * - * Created on: Mar 18, 2015 - * Author: tcanham - */ - -#include -#include -#include -#include - -#include - - -namespace Svc { - - TelemStoreComponentBaseFriend::TelemStoreComponentBaseFriend(Svc::TelemStoreComponentBase& inst) : m_baseInst(inst) { - } - - Fw::QueuedComponentBase::MsgDispatchStatus TelemStoreComponentBaseFriend::doDispatch() { - return this->m_baseInst.doDispatch(); - } - - void TelemChanImplTester::init(NATIVE_INT_TYPE instance) { - Svc::TelemStoreComponentTesterBase::init(); - } - - void TelemChanImplTester::pktSend_handler(NATIVE_INT_TYPE portNum, Fw::ComBuffer &data) { - - } - - TelemChanImplTester::TelemChanImplTester(Svc::TelemChanImpl& inst) : Svc::TelemStoreComponentTesterBase("testerbase"),m_impl(inst), m_baseFriend(inst) { - - } - - TelemChanImplTester::~TelemChanImplTester() { - } - - void TelemChanImplTester::doPerfTest(U32 iterations) { - - Os::IntervalTimer timer; - Fw::TlmBuffer buff; - Fw::TlmBuffer readBack; - Fw::SerializeStatus stat; - Fw::Time timeTag; - - U32 testVal = 10; - U32 retestVal = 0; - - // prefill telemetry to force a linear search to the end - - for (U32 entry = 0; entry < TelemChanImpl::NUM_TLM_ENTRIES - 1; entry++) { - Fw::TlmBuffer fakeBuff; - this->tlmRecv_out(0,entry,timeTag,buff); - } - - timer.start(); - - for (U32 iter = 0; iter < iterations; iter++) { - // create telemetry item - buff.resetSer(); - stat = buff.serialize(testVal); - this->tlmRecv_out(0,TelemChanImpl::NUM_TLM_ENTRIES - 1,timeTag,buff); - // Read back value - this->tlmGet_out(0,TelemChanImpl::NUM_TLM_ENTRIES - 1,timeTag,readBack); - // deserialize value - retestVal = 0; - buff.deserialize(retestVal); - if (retestVal != testVal) { - printf("Mismatch: %d %d\n",testVal,retestVal); - break; - } - } - - timer.stop(); - printf("Write total: %d ave: %d\n",timer.getDiffUsec(),timer.getDiffUsec()/iterations); - - } - -} /* namespace SvcTest */ diff --git a/Svc/TlmChan/test/perf/TelemChanImplTester.hpp b/Svc/TlmChan/test/perf/TelemChanImplTester.hpp deleted file mode 100644 index 15df672e97..0000000000 --- a/Svc/TlmChan/test/perf/TelemChanImplTester.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * TelemStoreImplTester.hpp - * - * Created on: Mar 18, 2015 - * Author: tcanham - */ - -#ifndef TLMCHAN_TEST_UT_TLMCHANIMPLTESTER_HPP_ -#define TLMCHAN_TEST_UT_TLMCHANIMPLTESTER_HPP_ - -#include -#include - -namespace Svc { - - // access to base class data - class TelemStoreComponentBaseFriend { - public: - TelemStoreComponentBaseFriend(Svc::TelemStoreComponentBase& inst); - Fw::QueuedComponentBase::MsgDispatchStatus doDispatch(); - private: - Svc::TelemStoreComponentBase& m_baseInst; - }; - - class TelemChanImplTester: public Svc::TelemStoreComponentTesterBase { - public: - TelemChanImplTester(Svc::TelemChanImpl& inst); - virtual ~TelemChanImplTester(); - - void init(NATIVE_INT_TYPE instance = 0); - - void doPerfTest(U32 iterations); - - private: - Svc::TelemChanImpl& m_impl; - TelemStoreComponentBaseFriend m_baseFriend; - - void pktSend_handler(NATIVE_INT_TYPE portNum, Fw::ComBuffer &data); - - - }; - -} /* namespace Svc */ - -#endif /* TLMCHAN_TEST_UT_TLMCHANIMPLTESTER_HPP_ */ diff --git a/Svc/TlmChan/test/perf/TelemChanTester.cpp b/Svc/TlmChan/test/perf/TelemChanTester.cpp deleted file mode 100644 index e03c4722ca..0000000000 --- a/Svc/TlmChan/test/perf/TelemChanTester.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * PrmDbTester.cpp - * - * Created on: Mar 18, 2015 - * Author: tcanham - */ - -#include -#include -#include - -#if FW_OBJECT_REGISTRATION == 1 -static Fw::SimpleObjRegistry simpleReg; -#endif - -void connectPorts(Svc::TelemChanImpl& impl, Svc::TelemChanImplTester& tester) { - - // parameter ports - tester.set_tlmRecv_OutputPort(0,impl.get_tlmRecv_InputPort(0)); - tester.set_tlmGet_OutputPort(0,impl.get_tlmGet_InputPort(0)); - -#if FW_PORT_TRACING - //Fw::PortBase::setTrace(true); -#endif - - //simpleReg.dump(); -} - -void runTimingTest(U32 iterations) { - - Svc::TelemChanImpl impl("TlmChanImpl"); - - impl.init(10); - - Svc::TelemChanImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - // run timing test - tester.doPerfTest(iterations); - -} - -extern "C" { - void runTest(); -} - -void runTest(U32 iterations) { - runTimingTest(iterations); -} - -#ifdef TGT_OS_TYPE_LINUX -int main(int argc, char* argv[]) { - runTest(1000000); -} - -#endif - diff --git a/Svc/TlmChan/test/perf/TelemStoreComponentTestAc.cpp b/Svc/TlmChan/test/perf/TelemStoreComponentTestAc.cpp deleted file mode 100644 index f7210a6675..0000000000 --- a/Svc/TlmChan/test/perf/TelemStoreComponentTestAc.cpp +++ /dev/null @@ -1,149 +0,0 @@ -#include -#include -// The following header will need to be modified when test code is moved -// If the component tester is regenerated, this will need to be modified again. -// Make the compile fail to make sure it is changed -#include -#include - -namespace Svc { -// public methods - Fw::InputComPort *TelemStoreComponentTesterBase::get_pktSend_InputPort(NATIVE_INT_TYPE portNum) { - FW_ASSERT(portNum < this->getNum_pktSend_InputPorts()); - return &this->m_pktSend_InputPort[portNum]; - } - - void TelemStoreComponentTesterBase::set_tlmRecv_OutputPort(NATIVE_INT_TYPE portNum, Fw::InputTlmPort* port) { - FW_ASSERT(portNum < this->getNum_tlmRecv_OutputPorts()); - this->m_tlmRecv_OutputPort[portNum].addCallPort(port); - } - - void TelemStoreComponentTesterBase::set_tlmGet_OutputPort(NATIVE_INT_TYPE portNum, Fw::InputTlmPort* port) { - FW_ASSERT(portNum < this->getNum_tlmGet_OutputPorts()); - this->m_tlmGet_OutputPort[portNum].addCallPort(port); - } - - void TelemStoreComponentTesterBase::set_run_OutputPort(NATIVE_INT_TYPE portNum, Svc::InputSchedPort* port) { - FW_ASSERT(portNum < this->getNum_run_OutputPorts()); - this->m_run_OutputPort[portNum].addCallPort(port); - } - -// protected methods - TelemStoreComponentTesterBase::TelemStoreComponentTesterBase(const char* compName) : Fw::PassiveComponentBase(compName) { - } - - TelemStoreComponentTesterBase::~TelemStoreComponentTesterBase(void) { - } - - void TelemStoreComponentTesterBase::init(NATIVE_INT_TYPE instance) { - - - // initialize base class - Fw::PassiveComponentBase::init(instance); - // Input ports attached to component here with external component interfaces - for (NATIVE_INT_TYPE port = 0; port < this->getNum_pktSend_InputPorts(); port++) { - this->m_pktSend_InputPort[port].init(); - this->m_pktSend_InputPort[port].addCallComp(this, m_p_pktSend_in); - this->m_pktSend_InputPort[port].setPortNum(port); -#if FW_OBJECT_NAMES == 1 - char portName[80]; - snprintf(portName, sizeof(portName), "%s_pktSend_InputPort[%d]", this->m_objName, port); - this->m_pktSend_InputPort[port].setObjName(portName); -#endif - } - - // Set output ports - for (NATIVE_INT_TYPE port = 0; port < this->getNum_tlmRecv_OutputPorts(); port++) { - this->m_tlmRecv_OutputPort[port].init(); -#if FW_OBJECT_NAMES == 1 - char portName[80]; - snprintf(portName, sizeof(portName), "%s_tlmRecv_OutputPort[%d]", this->m_objName, port); - this->m_tlmRecv_OutputPort[port].setObjName(portName); -#endif - } - - for (NATIVE_INT_TYPE port = 0; port < this->getNum_tlmGet_OutputPorts(); port++) { - this->m_tlmGet_OutputPort[port].init(); -#if FW_OBJECT_NAMES == 1 - char portName[80]; - snprintf(portName, sizeof(portName), "%s_tlmGet_OutputPort[%d]", this->m_objName, port); - this->m_tlmGet_OutputPort[port].setObjName(portName); -#endif - } - - for (NATIVE_INT_TYPE port = 0; port < this->getNum_run_OutputPorts(); port++) { - this->m_run_OutputPort[port].init(); -#if FW_OBJECT_NAMES == 1 - char portName[80]; - snprintf(portName, sizeof(portName), "%s_run_OutputPort[%d]", this->m_objName, port); - this->m_run_OutputPort[port].setObjName(portName); -#endif - } - - - } - - // Up-calls, calls for output ports - void TelemStoreComponentTesterBase::tlmRecv_out(NATIVE_INT_TYPE portNum, U32 id, Fw::Time &timeTag, Fw::TlmBuffer &val) { - FW_ASSERT(portNum < this->getNum_tlmRecv_OutputPorts()); - m_tlmRecv_OutputPort[portNum].invoke(id, timeTag, val); - } - - void TelemStoreComponentTesterBase::tlmGet_out(NATIVE_INT_TYPE portNum, U32 id, Fw::Time &timeTag, Fw::TlmBuffer &val) { - FW_ASSERT(portNum < this->getNum_tlmGet_OutputPorts()); - m_tlmGet_OutputPort[portNum].invoke(id, timeTag, val); - } - - void TelemStoreComponentTesterBase::run_out(NATIVE_INT_TYPE portNum, I32 order) { - FW_ASSERT(portNum < this->getNum_run_OutputPorts()); - m_run_OutputPort[portNum].invoke(order); - } - - NATIVE_INT_TYPE TelemStoreComponentTesterBase::getNum_tlmRecv_OutputPorts(void) { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_tlmRecv_OutputPort); - } - NATIVE_INT_TYPE TelemStoreComponentTesterBase::getNum_tlmGet_OutputPorts(void) { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_tlmGet_OutputPort); - } - NATIVE_INT_TYPE TelemStoreComponentTesterBase::getNum_run_OutputPorts(void) { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_run_OutputPort); - } - NATIVE_INT_TYPE TelemStoreComponentTesterBase::getNum_pktSend_InputPorts(void) { - return (NATIVE_INT_TYPE) FW_NUM_ARRAY_ELEMENTS(this->m_pktSend_InputPort); - } - bool TelemStoreComponentTesterBase::isConnected_tlmRecv_OutputPort(NATIVE_INT_TYPE portNum) { - FW_ASSERT(portNum < this->getNum_tlmRecv_OutputPorts(),portNum); - return this->m_tlmRecv_OutputPort[portNum].isConnected(); - } - bool TelemStoreComponentTesterBase::isConnected_tlmGet_OutputPort(NATIVE_INT_TYPE portNum) { - FW_ASSERT(portNum < this->getNum_tlmGet_OutputPorts(),portNum); - return this->m_tlmGet_OutputPort[portNum].isConnected(); - } - bool TelemStoreComponentTesterBase::isConnected_run_OutputPort(NATIVE_INT_TYPE portNum) { - FW_ASSERT(portNum < this->getNum_run_OutputPorts(),portNum); - return this->m_run_OutputPort[portNum].isConnected(); - } - - -// private methods - - // call for incoming port pktSend - void TelemStoreComponentTesterBase::m_p_pktSend_in(Fw::PassiveComponentBase* callComp, NATIVE_INT_TYPE portNum, Fw::ComBuffer &data) { - FW_ASSERT(callComp); - TelemStoreComponentTesterBase* compPtr = (TelemStoreComponentTesterBase*)callComp; - compPtr->pktSend_handlerBase(portNum, data); - } - - void TelemStoreComponentTesterBase::pktSend_handlerBase(NATIVE_INT_TYPE portNum, Fw::ComBuffer &data) { - - // make sure port number is valid - FW_ASSERT(portNum < this->getNum_pktSend_InputPorts()); - - // Down call to pure virtual handler method implemented in Impl class - this->pktSend_handler(portNum, data); - - } - - -} - diff --git a/Svc/TlmChan/test/perf/TelemStoreComponentTestAc.hpp b/Svc/TlmChan/test/perf/TelemStoreComponentTestAc.hpp deleted file mode 100644 index bd506b0d40..0000000000 --- a/Svc/TlmChan/test/perf/TelemStoreComponentTestAc.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * TelemStoreComponentComponentTestAc.hpp - * - * Created on: Monday, 13 April 2015 - * Author: tcanham - * - */ -#ifndef TELEMSTORECOMPONENTCOMP_TESTER_HPP_ -#define TELEMSTORECOMPONENTCOMP_TESTER_HPP_ -#include -#include - -// type includes -#include -#include -#include - -// port includes -#include -#include -#include - -// serializable includes - -namespace Svc { - - class TelemStoreComponentTesterBase : public Fw::PassiveComponentBase { - - public: - - void set_tlmRecv_OutputPort(NATIVE_INT_TYPE portNum, Fw::InputTlmPort *port); - void set_tlmGet_OutputPort(NATIVE_INT_TYPE portNum, Fw::InputTlmPort *port); - void set_run_OutputPort(NATIVE_INT_TYPE portNum, Svc::InputSchedPort *port); - Fw::InputComPort* get_pktSend_InputPort(NATIVE_INT_TYPE portNum); - protected: - // Only called by derived class - TelemStoreComponentTesterBase(const char* compName); - - virtual ~TelemStoreComponentTesterBase(void); - virtual void init(NATIVE_INT_TYPE instance = 0); - // downcalls for input ports - virtual void pktSend_handler(NATIVE_INT_TYPE portNum, Fw::ComBuffer &data) = 0; - // base class function (can be called by derived classes to bypass port) - void pktSend_handlerBase(NATIVE_INT_TYPE portNum, Fw::ComBuffer &data); - // upcalls for output ports - void tlmRecv_out(NATIVE_INT_TYPE portNum, U32 id, Fw::Time &timeTag, Fw::TlmBuffer &val); - void tlmGet_out(NATIVE_INT_TYPE portNum, U32 id, Fw::Time &timeTag, Fw::TlmBuffer &val); - void run_out(NATIVE_INT_TYPE portNum, I32 order); - NATIVE_INT_TYPE getNum_tlmRecv_OutputPorts(void); - NATIVE_INT_TYPE getNum_tlmGet_OutputPorts(void); - NATIVE_INT_TYPE getNum_run_OutputPorts(void); - NATIVE_INT_TYPE getNum_pktSend_InputPorts(void); - - // check to see if output port is connected - - bool isConnected_tlmRecv_OutputPort(NATIVE_INT_TYPE portNum); - - bool isConnected_tlmGet_OutputPort(NATIVE_INT_TYPE portNum); - - bool isConnected_run_OutputPort(NATIVE_INT_TYPE portNum); - - - private: - // output ports - Fw::OutputTlmPort m_tlmRecv_OutputPort[1]; - Fw::OutputTlmPort m_tlmGet_OutputPort[1]; - Svc::OutputSchedPort m_run_OutputPort[1]; - - // input ports - Fw::InputComPort m_pktSend_InputPort[1]; - - // calls for incoming ports - static void m_p_pktSend_in(Fw::PassiveComponentBase* callComp, NATIVE_INT_TYPE portNum, Fw::ComBuffer &data); - }; -}; - -#endif /* TELEMSTORECOMPONENTCOMP_TEST_HPP_ */ - - diff --git a/Svc/TlmChan/test/ut/Main.cpp b/Svc/TlmChan/test/ut/Main.cpp new file mode 100644 index 0000000000..a18350e3cf --- /dev/null +++ b/Svc/TlmChan/test/ut/Main.cpp @@ -0,0 +1,65 @@ +/* + * Main.cpp + * + * Created on: Mar 18, 2015 + * Updated: 6/22/2022 + * Author: tcanham + */ + +#include +#include +#include +#include + +TEST(TlmChanTest, InitTest) { + Svc::Tester tester; +} + +TEST(TlmChanTest, NominalChannelTest) { + TEST_CASE(107.1.1, "Nominal channelized telemetry"); + COMMENT("Write a single channel and verify it is read back and pushed correctly."); + + Svc::Tester tester; + // run test + tester.runNominalChannel(); +} + +TEST(TlmChanTest, MultiChannelTest) { + TEST_CASE(107.1.2, "Nominal Multi-channel channelized telemetry"); + COMMENT("Write multiple channels and verify they are read back and pushed correctly."); + + Svc::Tester tester; + + // run test + tester.runMultiChannel(); +} + +TEST(TlmChanTest, OffNominal) { + TEST_CASE(107.2.1, "Off-nominal channelized telemetry"); + COMMENT("Attempt to read a channel that hasn't been written."); + + Svc::Tester tester; + + // run test + tester.runOffNominal(); +} + +// TEST(TlmChanTest,TooManyChannels) { + +// COMMENT("Too Many Channel Test"); + +// Svc::TlmChanImpl impl("TlmChanImpl"); + +// impl.init(10,0); + +// Svc::TlmChanImplTester tester(impl); + +// tester.init(); + +// // connect ports +// connectPorts(impl,tester); + +// // run test +// tester.runTooManyChannels(); + +// } diff --git a/Svc/TlmChan/test/ut/Readme.txt b/Svc/TlmChan/test/ut/Readme.txt deleted file mode 100644 index c4c9711c65..0000000000 --- a/Svc/TlmChan/test/ut/Readme.txt +++ /dev/null @@ -1,9 +0,0 @@ -This test can be run by executing the following: - -From Svc/TlmChan: - -"make ut run_ut" - -Note that the Ref application needs to be built first. -The test will return a pass/fail error code depending on the -success of the test. \ No newline at end of file diff --git a/Svc/TlmChan/test/ut/Tester.cpp b/Svc/TlmChan/test/ut/Tester.cpp new file mode 100644 index 0000000000..8f7e5642a5 --- /dev/null +++ b/Svc/TlmChan/test/ut/Tester.cpp @@ -0,0 +1,345 @@ +// ====================================================================== +// \title TlmChan.hpp +// \author tcanham +// \brief cpp file for TlmChan test harness implementation class +// ====================================================================== + +#include "Tester.hpp" +#include + +#define INSTANCE 0 +#define MAX_HISTORY_SIZE 10 +#define QUEUE_DEPTH 10 + +static const NATIVE_UINT_TYPE TEST_CHAN_SIZE = sizeof(FwChanIdType) + Fw::Time::SERIALIZED_SIZE + sizeof(U32); +static const NATIVE_UINT_TYPE CHANS_PER_COMBUFFER = + (FW_COM_BUFFER_MAX_SIZE - sizeof(FwPacketDescriptorType)) / TEST_CHAN_SIZE; + +namespace Svc { + +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +Tester ::Tester() + : TlmChanGTestBase("Tester", MAX_HISTORY_SIZE), component("TlmChan"), m_numBuffs(0), m_bufferRecv(false) { + this->initComponents(); + this->connectPorts(); +} + +Tester ::~Tester() {} + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +void Tester::runNominalChannel() { + this->clearBuffs(); + // send first buffer + this->sendBuff(27, 10); + this->doRun(true); + this->checkBuff(0, 1, 27, 10); + + this->clearBuffs(); + // send again to other buffer + this->sendBuff(27, 10); + + static bool tlc003 = false; + + if (not tlc003) { + REQUIREMENT("TLC-003"); + tlc003 = true; + } + + this->doRun(true); + this->checkBuff(0, 1, 27, 10); + + // do an update to make sure it gets updated and returned correctly + this->clearBuffs(); + this->sendBuff(27, 20); +} + +void Tester::runMultiChannel() { + FwChanIdType ID_0[] = {// Test channel IDs + 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1100, 0x1101, 0x1102, 0x1103, 0x300, + 0x301, 0x400, 0x401, 0x402, 0x100, 0x101, 0x102, 0x103, 0x104, 0x105}; + + this->clearBuffs(); + // send all updates + for (NATIVE_UINT_TYPE n = 0; n < FW_NUM_ARRAY_ELEMENTS(ID_0); n++) { + this->sendBuff(ID_0[n], n); + } + + ASSERT_EQ(0, this->component.m_activeBuffer); + + // do a run, and all the packets should be sent + this->doRun(true); + ASSERT_TRUE(this->m_bufferRecv); + ASSERT_EQ((FW_NUM_ARRAY_ELEMENTS(ID_0) / CHANS_PER_COMBUFFER) + 1, this->m_numBuffs); + ASSERT_EQ(1, this->component.m_activeBuffer); + + // verify packets + for (NATIVE_UINT_TYPE n = 0; n < FW_NUM_ARRAY_ELEMENTS(ID_0); n++) { + // printf("#: %d\n",n); + this->checkBuff(n, FW_NUM_ARRAY_ELEMENTS(ID_0), ID_0[n], n); + } + + // send another set + + FwChanIdType ID_1[] = {// Test channel IDs + 0x5000, 0x5001, 0x5002, 0x5003, 0x5004, 0x5005, 0x5100, 0x5101, 0x5102, + 0x5103, 0x6300, 0x6301, 0x6400, 0x6401, 0x6402, 0x6100, 0x6101, 0x6102, + 0x6103, 0x6104, 0x6105, 0x8101, 0x8102, 0x8103, 0x8104, 0x8105}; + + this->clearBuffs(); + // send all updates + for (NATIVE_UINT_TYPE n = 0; n < FW_NUM_ARRAY_ELEMENTS(ID_1); n++) { + this->sendBuff(ID_1[n], n); + } + + ASSERT_EQ(1, this->component.m_activeBuffer); + + // do a run, and all the packets should be sent + this->doRun(true); + ASSERT_TRUE(this->m_bufferRecv); + ASSERT_EQ((FW_NUM_ARRAY_ELEMENTS(ID_1) / CHANS_PER_COMBUFFER) + 1, this->m_numBuffs); + ASSERT_EQ(0, this->component.m_activeBuffer); + + // verify packets + for (NATIVE_UINT_TYPE n = 0; n < FW_NUM_ARRAY_ELEMENTS(ID_1); n++) { + // printf("#: %d\n",n); + this->checkBuff(n, FW_NUM_ARRAY_ELEMENTS(ID_1), ID_1[n], n); + } +} + +void Tester::runOffNominal() { + // Ask for a packet that isn't written yet + Fw::TlmBuffer buff; + Fw::SerializeStatus stat; + Fw::Time timeTag; + U32 val = 10; + + // create Telemetry item and put dummy data in to make sure it gets erased + buff.resetSer(); + stat = buff.serialize(val); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); + + // Read back value + this->invoke_to_TlmGet(0, 10, timeTag, buff); + ASSERT_EQ(0u, buff.getBuffLength()); +} + +// ---------------------------------------------------------------------- +// Handlers for typed from ports +// ---------------------------------------------------------------------- + +void Tester ::from_PktSend_handler(const NATIVE_INT_TYPE portNum, Fw::ComBuffer& data, U32 context) { + this->pushFromPortEntry_PktSend(data, context); + this->m_bufferRecv = true; + this->m_rcvdBuffer[this->m_numBuffs] = data; + this->m_numBuffs++; +} + +void Tester ::from_pingOut_handler(const NATIVE_INT_TYPE portNum, U32 key) { + this->pushFromPortEntry_pingOut(key); +} + +// ---------------------------------------------------------------------- +// Helper methods +// ---------------------------------------------------------------------- + +bool Tester::doRun(bool check) { + // execute run port to send packet + this->invoke_to_Run(0, 0); + // dispatch run message + this->m_bufferRecv = false; + this->component.doDispatch(); + if (check) { + EXPECT_TRUE(this->m_bufferRecv); + } + return this->m_bufferRecv; +} + +void Tester::checkBuff(NATIVE_UINT_TYPE chanNum, NATIVE_UINT_TYPE totalChan, FwChanIdType id, U32 val) { + Fw::Time timeTag; + // deserialize packet + Fw::SerializeStatus stat; + + static bool tlc004 = false; + + if (not tlc004) { + REQUIREMENT("TLC-004"); + tlc004 = true; + } + + NATIVE_UINT_TYPE currentChan = 0; + + // Search for channel ID + for (NATIVE_UINT_TYPE packet = 0; packet < this->m_numBuffs; packet++) { + // Look at packet descriptor for current packet + this->m_rcvdBuffer[packet].resetDeser(); + // first piece should be tlm packet descriptor + FwPacketDescriptorType desc; + stat = this->m_rcvdBuffer[packet].deserialize(desc); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); + ASSERT_EQ(desc, static_cast(Fw::ComPacket::FW_PACKET_TELEM)); + + for (NATIVE_UINT_TYPE chan = 0; chan < CHANS_PER_COMBUFFER; chan++) { + // decode channel ID + FwEventIdType sentId; + stat = this->m_rcvdBuffer[packet].deserialize(sentId); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); + + // next piece is time tag + Fw::Time recTimeTag(TB_NONE, 0, 0); + stat = this->m_rcvdBuffer[packet].deserialize(recTimeTag); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); + ASSERT_TRUE(timeTag == recTimeTag); + // next piece is event argument + U32 readVal; + stat = this->m_rcvdBuffer[packet].deserialize(readVal); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); + + if (chanNum == currentChan) { + ASSERT_EQ(id, sentId); + ASSERT_EQ(val, readVal); + } + + // quit if we are at max channel entry + if (currentChan == (totalChan - 1)) { + break; + } + + currentChan++; + } + + // packet should be empty + ASSERT_EQ(0, this->m_rcvdBuffer[packet].getBuffLeft()); + } +} + +void Tester::sendBuff(FwChanIdType id, U32 val) { + Fw::TlmBuffer buff; + Fw::TlmBuffer readBack; + Fw::SerializeStatus stat; + Fw::Time timeTag; + U32 retestVal; + + // create telemetry item + buff.resetSer(); + stat = buff.serialize(val); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, stat); + + static bool tlc001 = false; + + if (not tlc001) { + REQUIREMENT("TLC-001"); + tlc001 = true; + } + + this->invoke_to_TlmRecv(0, id, timeTag, buff); + // Read back value + static bool tlc002 = false; + + if (not tlc002) { + REQUIREMENT("TLC-002"); + tlc002 = true; + } + + this->invoke_to_TlmGet(0, id, timeTag, readBack); + // deserialize value + retestVal = 0; + readBack.deserialize(retestVal); + ASSERT_EQ(retestVal, val); +} + +void Tester::clearBuffs() { + this->m_numBuffs = 0; + for (NATIVE_INT_TYPE n = 0; n < TLMCHAN_HASH_BUCKETS; n++) { + this->m_rcvdBuffer[n].resetSer(); + } +} + +void Tester::dumpTlmEntry(TlmChan::TlmEntry* entry) { + printf( + "Entry " + " Ptr: %p" + " id: 0x%08X" + " bucket: %d" + " next: %p\n", + static_cast(entry), entry->id, entry->bucketNo, static_cast(entry->next)); +} + +void Tester::dumpHash() { + // printf("**Buffer 0\n"); + for (NATIVE_INT_TYPE slot = 0; slot < TLMCHAN_NUM_TLM_HASH_SLOTS; slot++) { + printf("Slot: %d\n", slot); + if (this->component.m_tlmEntries[0].slots[slot]) { + TlmChan::TlmEntry* entry = component.m_tlmEntries[0].slots[slot]; + for (NATIVE_INT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { + dumpTlmEntry(entry); + if (entry->next == nullptr) { + break; + } else { + entry = entry->next; + } + } + } else { + printf("EMPTY\n"); + } + } + printf("\n"); + // for (NATIVE_INT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { + // printf("Bucket: %d ",bucket); + // dumpTlmEntry(&m_impl.m_tlmEntries[0].buckets[bucket]); + // } + // printf("**Buffer 1\n"); + // for (NATIVE_INT_TYPE slot = 0; slot < TLMCHAN_NUM_TLM_HASH_SLOTS; slot++) { + // printf("Slot: %d\n",slot); + // if (m_impl.m_tlmEntries[1].slots[slot]) { + // TlmChanImpl::TlmEntry* entry = m_impl.m_tlmEntries[1].slots[slot]; + // for (NATIVE_INT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { + // dumpTlmEntry(entry); + // if (entry->next == 0) { + // break; + // } else { + // entry = entry->next; + // } + // } + // } else { + // printf("EMPTY\n"); + // } + // } + // printf("\n"); + // for (NATIVE_INT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { + // printf("Bucket: %d\n",bucket); + // dumpTlmEntry(&m_impl.m_tlmEntries[1].buckets[bucket]); + // } +} + +void Tester ::connectPorts() { + // Run + this->connect_to_Run(0, this->component.get_Run_InputPort(0)); + + // TlmGet + this->connect_to_TlmGet(0, this->component.get_TlmGet_InputPort(0)); + + // TlmRecv + this->connect_to_TlmRecv(0, this->component.get_TlmRecv_InputPort(0)); + + // pingIn + this->connect_to_pingIn(0, this->component.get_pingIn_InputPort(0)); + + // PktSend + this->component.set_PktSend_OutputPort(0, this->get_from_PktSend(0)); + + // pingOut + this->component.set_pingOut_OutputPort(0, this->get_from_pingOut(0)); +} + +void Tester ::initComponents() { + this->init(); + this->component.init(QUEUE_DEPTH, INSTANCE); +} + +} // end namespace Svc diff --git a/Svc/TlmChan/test/ut/Tester.hpp b/Svc/TlmChan/test/ut/Tester.hpp new file mode 100644 index 0000000000..6b61ec2ce7 --- /dev/null +++ b/Svc/TlmChan/test/ut/Tester.hpp @@ -0,0 +1,101 @@ +// ====================================================================== +// \title TlmChan/test/ut/Tester.hpp +// \author tcanham +// \brief hpp file for TlmChan test harness implementation class +// ====================================================================== + +#ifndef TESTER_HPP +#define TESTER_HPP + +#include "GTestBase.hpp" +#include "Svc/TlmChan/TlmChan.hpp" + +namespace Svc { + +class Tester : public TlmChanGTestBase { + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + public: + //! Construct object Tester + //! + Tester(); + + //! Destroy object Tester + //! + ~Tester(); + + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + void runNominalChannel(); + void runMultiChannel(); + void runOffNominal(); + + private: + // ---------------------------------------------------------------------- + // Handlers for typed from ports + // ---------------------------------------------------------------------- + + //! Handler for from_PktSend + //! + void from_PktSend_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::ComBuffer& data, /*!< + Buffer containing packet data + */ + U32 context /*!< + Call context value; meaning chosen by user + */ + ); + + //! Handler for from_pingOut + //! + void from_pingOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + U32 key /*!< + Value to return to pinger + */ + ); + + private: + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + //! Connect ports + //! + void connectPorts(); + + //! Initialize components + //! + void initComponents(); + + void sendBuff(FwChanIdType id, U32 val); + bool doRun(bool check); + void checkBuff(NATIVE_UINT_TYPE chanNum, NATIVE_UINT_TYPE totalChan, FwChanIdType id, U32 val); + + void clearBuffs(); + + // dump functions + void dumpHash(); + static void dumpTlmEntry(TlmChan::TlmEntry* entry); + + private: + // ---------------------------------------------------------------------- + // Variables + // ---------------------------------------------------------------------- + + //! The component under test + //! + TlmChan component; + // Keep a history + NATIVE_UINT_TYPE m_numBuffs; + Fw::ComBuffer m_rcvdBuffer[TLMCHAN_HASH_BUCKETS]; + bool m_bufferRecv; +}; + +} // end namespace Svc + +#endif diff --git a/Svc/TlmChan/test/ut/TlmChanImplTester.cpp b/Svc/TlmChan/test/ut/TlmChanImplTester.cpp deleted file mode 100644 index 45377997c7..0000000000 --- a/Svc/TlmChan/test/ut/TlmChanImplTester.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/* - * PrmDbImplTester.cpp - * - * Created on: Mar 18, 2015 - * Author: tcanham - */ - -#include -#include -#include -#include -#include - -#include - -#include - - -namespace Svc { - - void TlmChanImplTester::init(NATIVE_INT_TYPE instance) { - TlmChanGTestBase::init(); - } - - void TlmChanImplTester::from_PktSend_handler(NATIVE_INT_TYPE portNum, Fw::ComBuffer &data, U32 context) { - this->m_bufferRecv = true; - this->m_rcvdBuffer[this->m_numBuffs] = data; - this->m_numBuffs++; - } - - TlmChanImplTester::TlmChanImplTester(Svc::TlmChanImpl& inst) : - TlmChanGTestBase("testerbase",100), - m_impl(inst), - m_numBuffs(0), - m_bufferRecv(false) { - } - - TlmChanImplTester::~TlmChanImplTester() { - } - - bool TlmChanImplTester::doRun(bool check) { - // execute run port to send packet - this->invoke_to_Run(0,0); - // dispatch run message - this->m_bufferRecv = false; - this->m_impl.doDispatch(); - if (check) { - EXPECT_TRUE(this->m_bufferRecv); - } - return this->m_bufferRecv; - } - - void TlmChanImplTester::checkBuff(FwChanIdType id, U32 val, NATIVE_INT_TYPE instance) { - Fw::Time timeTag; - // deserialize packet - Fw::SerializeStatus stat; - bool packetFound = false; - - static bool tlc004 = false; - - if (not tlc004) { - REQUIREMENT("TLC-004"); - tlc004 = true; - } - - // Search for channel ID - for (NATIVE_UINT_TYPE packet = 0; packet < this->m_numBuffs; packet++) { - this->m_rcvdBuffer[packet].resetDeser(); - // first piece should be tlm packet descriptor - FwPacketDescriptorType desc; - stat = this->m_rcvdBuffer[packet].deserialize(desc); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_EQ(desc, static_cast(Fw::ComPacket::FW_PACKET_TELEM)); - // next piece should be event ID - FwEventIdType sentId; - stat = this->m_rcvdBuffer[packet].deserialize(sentId); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - - // this is the packet you are looking for.. - if (sentId != id) { - this->m_rcvdBuffer[packet].resetDeser(); - continue; - } - packetFound = true; - // next piece is time tag - Fw::Time recTimeTag(TB_NONE,0,0); - stat = this->m_rcvdBuffer[packet].deserialize(recTimeTag); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_TRUE(timeTag == recTimeTag); - // next piece is event argument - U32 readVal; - stat = this->m_rcvdBuffer[packet].deserialize(readVal); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - ASSERT_EQ(readVal, val); - // packet should be empty - ASSERT_EQ(this->m_rcvdBuffer[packet].getBuffLeft(),0u); - } - - ASSERT_TRUE(packetFound); - } - - void TlmChanImplTester::sendBuff(FwChanIdType id, U32 val, NATIVE_INT_TYPE instance) { - - Fw::TlmBuffer buff; - Fw::TlmBuffer readBack; - Fw::SerializeStatus stat; - Fw::Time timeTag; - U32 retestVal; - - // create telemetry item - buff.resetSer(); - stat = buff.serialize(val); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - - static bool tlc001 = false; - - if (not tlc001) { - REQUIREMENT("TLC-001"); - tlc001 = true; - } - - this->invoke_to_TlmRecv(0,id,timeTag,buff); - // Read back value - static bool tlc002 = false; - - if (not tlc002) { - REQUIREMENT("TLC-002"); - tlc002 = true; - } - - this->invoke_to_TlmGet(0,id,timeTag,readBack); - // deserialize value - retestVal = 0; - readBack.deserialize(retestVal); - ASSERT_EQ(retestVal, val); - - - } - - void TlmChanImplTester::runNominalChannel() { - - this->clearBuffs(); - // send first buffer - this->sendBuff(27,10,0); - this->doRun(true); - this->checkBuff(27,10,0); - - this->clearBuffs(); - // send again to other buffer - this->sendBuff(27,10,0); - - static bool tlc003 = false; - - if (not tlc003) { - REQUIREMENT("TLC-003"); - tlc003 = true; - } - - this->doRun(true); - this->checkBuff(27,10,0); - - // do an update to make sure it gets updated and returned correctly - this->clearBuffs(); - this->sendBuff(27,20,0); - - - } - - void TlmChanImplTester::runMultiChannel() { - - - FwChanIdType IDs[] = { - // From Ref ComponentReport.txt - 0x1000,0x1001,0x1002,0x1003,0x1004,0x1005,0x1100,0x1101,0x1102,0x1103,0x300,0x301,0x400,0x401,0x402,0x100,0x101,0x102,0x103,0x104,0x105 - }; - - this->clearBuffs(); - // send all updates - for (NATIVE_UINT_TYPE n=0; n < FW_NUM_ARRAY_ELEMENTS(IDs); n++) { - this->sendBuff(IDs[n],n,0); - } - - // dump hash table - this->dumpHash(); - - // do a run, and all the packets should be sent - this->doRun(true); - ASSERT_TRUE(this->m_bufferRecv); - ASSERT_EQ(this->m_numBuffs,FW_NUM_ARRAY_ELEMENTS(IDs)); - - // verify packets - - for (NATIVE_UINT_TYPE n=0; n < FW_NUM_ARRAY_ELEMENTS(IDs); n++) { - //printf("#: %d\n",n); - this->checkBuff(IDs[n],n,0); - } - - } - - void TlmChanImplTester::runTooManyChannels() { - - // This will assert, so disable after testing - - this->clearBuffs(); - // send all updates -// for (NATIVE_UINT_TYPE n=0; n <= TLMCHAN_HASH_BUCKETS; n++) { - for (NATIVE_UINT_TYPE n=0; n < TLMCHAN_HASH_BUCKETS; n++) { - this->sendBuff(n,n,0); - } - - - } - - void TlmChanImplTester::runOffNominal() { - - // Ask for a packet that isn't written yet - Fw::TlmBuffer buff; - Fw::SerializeStatus stat; - Fw::Time timeTag; - U32 val = 10; - - // create Telemetry item and put dummy data in to make sure it gets erased - buff.resetSer(); - stat = buff.serialize(val); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,stat); - - // Read back value - this->invoke_to_TlmGet(0,10,timeTag,buff); - ASSERT_EQ(0u,buff.getBuffLength()); - - } - - void TlmChanImplTester::clearBuffs() { - this->m_numBuffs = 0; - for (NATIVE_INT_TYPE n = 0; n < TLMCHAN_HASH_BUCKETS; n++) { - this->m_rcvdBuffer[n].resetSer(); - } - } - - void TlmChanImplTester::dumpTlmEntry(TlmChanImpl::TlmEntry* entry) { - printf( - "Entry " - " Ptr: %p" - " id: 0x%08X" - " bucket: %d" - " next: %p\n", - static_cast(entry),entry->id,entry->bucketNo,static_cast(entry->next) - ); - } - - void TlmChanImplTester::dumpHash() { -// printf("**Buffer 0\n"); - for (NATIVE_INT_TYPE slot = 0; slot < TLMCHAN_NUM_TLM_HASH_SLOTS; slot++) { - printf("Slot: %d\n",slot); - if (m_impl.m_tlmEntries[0].slots[slot]) { - TlmChanImpl::TlmEntry* entry = m_impl.m_tlmEntries[0].slots[slot]; - for (NATIVE_INT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { - dumpTlmEntry(entry); - if (entry->next == nullptr) { - break; - } else { - entry = entry->next; - } - } - } else { - printf("EMPTY\n"); - } - } - printf("\n"); -// for (NATIVE_INT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { -// printf("Bucket: %d ",bucket); -// dumpTlmEntry(&m_impl.m_tlmEntries[0].buckets[bucket]); -// } -// printf("**Buffer 1\n"); -// for (NATIVE_INT_TYPE slot = 0; slot < TLMCHAN_NUM_TLM_HASH_SLOTS; slot++) { -// printf("Slot: %d\n",slot); -// if (m_impl.m_tlmEntries[1].slots[slot]) { -// TlmChanImpl::TlmEntry* entry = m_impl.m_tlmEntries[1].slots[slot]; -// for (NATIVE_INT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { -// dumpTlmEntry(entry); -// if (entry->next == 0) { -// break; -// } else { -// entry = entry->next; -// } -// } -// } else { -// printf("EMPTY\n"); -// } -// } -// printf("\n"); -// for (NATIVE_INT_TYPE bucket = 0; bucket < TLMCHAN_HASH_BUCKETS; bucket++) { -// printf("Bucket: %d\n",bucket); -// dumpTlmEntry(&m_impl.m_tlmEntries[1].buckets[bucket]); -// } - } - void TlmChanImplTester :: - from_pingOut_handler( - const NATIVE_INT_TYPE portNum, - U32 key - ) - { - this->pushFromPortEntry_pingOut(key); - } -} /* namespace SvcTest */ diff --git a/Svc/TlmChan/test/ut/TlmChanImplTester.hpp b/Svc/TlmChan/test/ut/TlmChanImplTester.hpp deleted file mode 100644 index 5c06eb1424..0000000000 --- a/Svc/TlmChan/test/ut/TlmChanImplTester.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * TlmStoreImplTester.hpp - * - * Created on: Mar 18, 2015 - * Author: tcanham - */ - -#ifndef TLMCHAN_TEST_UT_TLMCHANIMPLTESTER_HPP_ -#define TLMCHAN_TEST_UT_TLMCHANIMPLTESTER_HPP_ - -#include -#include - -namespace Svc { - - class TlmChanImplTester: public TlmChanGTestBase { - public: - TlmChanImplTester(Svc::TlmChanImpl& inst); - virtual ~TlmChanImplTester(); - - void init(NATIVE_INT_TYPE instance = 0); - - void runNominalChannel(); - void runMultiChannel(); - void runOffNominal(); - void runTooManyChannels(); - - private: - Svc::TlmChanImpl& m_impl; - - void from_PktSend_handler(NATIVE_INT_TYPE portNum, Fw::ComBuffer &data, U32 context); - - // helper - void sendBuff(FwChanIdType id, U32 val, NATIVE_INT_TYPE instance); - bool doRun(bool check); - void checkBuff(FwChanIdType id, U32 val, NATIVE_INT_TYPE instance); - - // Keep a history - NATIVE_UINT_TYPE m_numBuffs; - Fw::ComBuffer m_rcvdBuffer[TLMCHAN_HASH_BUCKETS]; - bool m_bufferRecv; - void clearBuffs(); - - // dump functions - void dumpHash(); - static void dumpTlmEntry(TlmChanImpl::TlmEntry* entry); - //! Handler for from_pingOut - //! - void from_pingOut_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - U32 key /*!< Value to return to pinger*/ - ); - - }; - -} /* namespace Svc */ - -#endif /* TLMCHAN_TEST_UT_TLMCHANIMPLTESTER_HPP_ */ diff --git a/Svc/TlmChan/test/ut/TlmChanTester.cpp b/Svc/TlmChan/test/ut/TlmChanTester.cpp deleted file mode 100644 index 6b99154b53..0000000000 --- a/Svc/TlmChan/test/ut/TlmChanTester.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * PrmDbTester.cpp - * - * Created on: Mar 18, 2015 - * Author: tcanham - */ - -#include -#include -#include -#include -#include - -#if FW_OBJECT_REGISTRATION == 1 -static Fw::SimpleObjRegistry simpleReg; -#endif - -void connectPorts(Svc::TlmChanImpl& impl, Svc::TlmChanImplTester& tester) { - - // connect ports - tester.connect_to_TlmRecv(0,impl.get_TlmRecv_InputPort(0)); - tester.connect_to_TlmGet(0,impl.get_TlmGet_InputPort(0)); - tester.connect_to_Run(0,impl.get_Run_InputPort(0)); - impl.set_PktSend_OutputPort(0,tester.get_from_PktSend(0)); - -#if FW_PORT_TRACING - //Fw::PortBase::setTrace(true); -#endif - - //simpleReg.dump(); -} - - -TEST(TlmChanTest,NominalChannelTest) { - - TEST_CASE(107.1.1,"Nominal channelized telemetry"); - COMMENT("Write a single channel and verify it is read back and pushed correctly."); - - Svc::TlmChanImpl impl("TlmChanImpl"); - - impl.init(10,0); - - Svc::TlmChanImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - // run test - tester.runNominalChannel(); - -} - -TEST(TlmChanTest,MultiChannelTest) { - - TEST_CASE(107.1.2,"Nominal Multi-channel channelized telemetry"); - COMMENT("Write multiple channels and verify they are read back and pushed correctly."); - - Svc::TlmChanImpl impl("TlmChanImpl"); - - impl.init(10,0); - - Svc::TlmChanImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - // run test - tester.runMultiChannel(); - -} - - -TEST(TlmChanTest,OffNominal) { - - TEST_CASE(107.2.1,"Off-nominal channelized telemetry"); - COMMENT("Attempt to read a channel that hasn't been written."); - - Svc::TlmChanImpl impl("TlmChanImpl"); - - impl.init(10,0); - - Svc::TlmChanImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - // run test - tester.runOffNominal(); - -} - -TEST(TlmChanTest,TooManyChannels) { - - COMMENT("Too Many Channel Test"); - - Svc::TlmChanImpl impl("TlmChanImpl"); - - impl.init(10,0); - - Svc::TlmChanImplTester tester(impl); - - tester.init(); - - // connect ports - connectPorts(impl,tester); - - // run test - tester.runTooManyChannels(); - -} - -#ifndef TGT_OS_TYPE_VXWORKS -int main(int argc, char* argv[]) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} - -#endif - diff --git a/Svc/TlmPacketizer/CMakeLists.txt b/Svc/TlmPacketizer/CMakeLists.txt index 722637c07e..b4162cebd2 100644 --- a/Svc/TlmPacketizer/CMakeLists.txt +++ b/Svc/TlmPacketizer/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME diff --git a/Svc/TlmPacketizer/TlmPacketizer.cpp b/Svc/TlmPacketizer/TlmPacketizer.cpp index 32731b2b24..e35990b9ea 100644 --- a/Svc/TlmPacketizer/TlmPacketizer.cpp +++ b/Svc/TlmPacketizer/TlmPacketizer.cpp @@ -8,391 +8,342 @@ // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. -#include -#include +#include #include +#include namespace Svc { - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - TlmPacketizer :: - TlmPacketizer( - const char *const compName - ) : - TlmPacketizerComponentBase(compName) - ,m_numPackets(0) - ,m_configured(false) - ,m_startLevel(0) - ,m_maxLevel(0) - { - // clear slot pointers - for (NATIVE_UINT_TYPE entry = 0; entry < TLMPACKETIZER_NUM_TLM_HASH_SLOTS; entry++) { - this->m_tlmEntries.slots[entry] = nullptr; - } - // clear buckets - for (NATIVE_UINT_TYPE entry = 0; entry < TLMPACKETIZER_HASH_BUCKETS; entry++) { - this->m_tlmEntries.buckets[entry].used = false; - this->m_tlmEntries.buckets[entry].bucketNo = entry; - this->m_tlmEntries.buckets[entry].next = nullptr; - this->m_tlmEntries.buckets[entry].id = 0; - } - // clear free index - this->m_tlmEntries.free = 0; - // clear missing tlm channel check - for (NATIVE_UINT_TYPE entry = 0; entry < TLMPACKETIZER_MAX_MISSING_TLM_CHECK; entry++) { - this->m_missTlmCheck[entry].checked = false; - this->m_missTlmCheck[entry].id = 0; - } - - // clear packet buffers - for (NATIVE_UINT_TYPE buffer = 0; buffer < MAX_PACKETIZER_PACKETS; buffer++) { - this->m_fillBuffers[buffer].updated = false; - this->m_fillBuffers[buffer].requested = false; - this->m_sendBuffers[buffer].updated = false; - } - } - - void TlmPacketizer :: - init( - const NATIVE_INT_TYPE queueDepth, - const NATIVE_INT_TYPE instance - ) - { +// ---------------------------------------------------------------------- +// Construction, initialization, and destruction +// ---------------------------------------------------------------------- + +TlmPacketizer ::TlmPacketizer(const char* const compName) + : TlmPacketizerComponentBase(compName), m_numPackets(0), m_configured(false), m_startLevel(0), m_maxLevel(0) { + // clear slot pointers + for (NATIVE_UINT_TYPE entry = 0; entry < TLMPACKETIZER_NUM_TLM_HASH_SLOTS; entry++) { + this->m_tlmEntries.slots[entry] = nullptr; + } + // clear buckets + for (NATIVE_UINT_TYPE entry = 0; entry < TLMPACKETIZER_HASH_BUCKETS; entry++) { + this->m_tlmEntries.buckets[entry].used = false; + this->m_tlmEntries.buckets[entry].bucketNo = entry; + this->m_tlmEntries.buckets[entry].next = nullptr; + this->m_tlmEntries.buckets[entry].id = 0; + } + // clear free index + this->m_tlmEntries.free = 0; + // clear missing tlm channel check + for (NATIVE_UINT_TYPE entry = 0; entry < TLMPACKETIZER_MAX_MISSING_TLM_CHECK; entry++) { + this->m_missTlmCheck[entry].checked = false; + this->m_missTlmCheck[entry].id = 0; + } + + // clear packet buffers + for (NATIVE_UINT_TYPE buffer = 0; buffer < MAX_PACKETIZER_PACKETS; buffer++) { + this->m_fillBuffers[buffer].updated = false; + this->m_fillBuffers[buffer].requested = false; + this->m_sendBuffers[buffer].updated = false; + } +} + +void TlmPacketizer ::init(const NATIVE_INT_TYPE queueDepth, const NATIVE_INT_TYPE instance) { TlmPacketizerComponentBase::init(queueDepth, instance); - } - - TlmPacketizer :: - ~TlmPacketizer() - { - - } - - void TlmPacketizer::setPacketList( - const TlmPacketizerPacketList& packetList, - const Svc::TlmPacketizerPacket& ignoreList, - const NATIVE_UINT_TYPE startLevel) { - - FW_ASSERT(packetList.list); - FW_ASSERT(ignoreList.list); - FW_ASSERT(packetList.numEntries <= MAX_PACKETIZER_PACKETS,packetList.numEntries); - // validate packet sizes against maximum com buffer size and populate hash - // table - for (NATIVE_UINT_TYPE pktEntry = 0; pktEntry < packetList.numEntries; pktEntry++) { - // Initial size is packetized telemetry descriptor + size of time tag + sizeof packet ID - NATIVE_UINT_TYPE packetLen = sizeof(FwPacketDescriptorType) + Fw::Time::SERIALIZED_SIZE + sizeof(FwTlmPacketizeIdType); - FW_ASSERT(packetList.list[pktEntry]->list,pktEntry); - // add up entries for each defined packet - for (NATIVE_UINT_TYPE tlmEntry = 0; tlmEntry < packetList.list[pktEntry]->numEntries; tlmEntry++) { - // get hash value for id - FwChanIdType id = packetList.list[pktEntry]->list[tlmEntry].id; - TlmEntry *entryToUse = this->findBucket(id); - // copy into entry - FW_ASSERT(entryToUse); - entryToUse->used = true; - // not ignored channel - entryToUse->ignored = false; - entryToUse->id = id; - // the offset into the buffer will be the current packet length - entryToUse->packetOffset[pktEntry] = packetLen; - - packetLen += packetList.list[pktEntry]->list[tlmEntry].size; - - } // end channel in packet - FW_ASSERT(packetLen <= FW_COM_BUFFER_MAX_SIZE,packetLen,pktEntry); - // clear contents - memset(this->m_fillBuffers[pktEntry].buffer.getBuffAddr(),0,packetLen); - // serialize packet descriptor and packet ID now since it will always be the same - Fw::SerializeStatus stat = this->m_fillBuffers[pktEntry].buffer.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM)); - FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,stat); - stat = this->m_fillBuffers[pktEntry].buffer.serialize(packetList.list[pktEntry]->id); - FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,stat); - // set packet buffer length - stat = this->m_fillBuffers[pktEntry].buffer.setBuffLen(packetLen); - FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,stat); - // save ID - this->m_fillBuffers[pktEntry].id = packetList.list[pktEntry]->id; - // save level - this->m_fillBuffers[pktEntry].level = packetList.list[pktEntry]->level; - // store max level - if (packetList.list[pktEntry]->level > this->m_maxLevel) { - this->m_maxLevel = packetList.list[pktEntry]->level; - } - // save start level - this->m_startLevel = startLevel; - - } // end packet list - - // populate hash table with ignore list - for (NATIVE_UINT_TYPE channelEntry = 0; channelEntry < ignoreList.numEntries; channelEntry++) { - // get hash value for id - FwChanIdType id = ignoreList.list[channelEntry].id; - - TlmEntry *entryToUse = this->findBucket(id); - - // copy into entry - FW_ASSERT(entryToUse); - entryToUse->used = true; - // is ignored channel - entryToUse->ignored = true; - entryToUse->id = id; - } // end ignore list - - // store number of packets - this->m_numPackets = packetList.numEntries; - - // indicate configured - this->m_configured = true; - } - - TlmPacketizer::TlmEntry* TlmPacketizer::findBucket(FwChanIdType id) { - NATIVE_UINT_TYPE index = this->doHash(id); - FW_ASSERT(index < TLMPACKETIZER_HASH_BUCKETS); - TlmEntry* entryToUse = nullptr; - TlmEntry* prevEntry = nullptr; - - // Search to see if channel has already been stored or a bucket needs to be added - if (this->m_tlmEntries.slots[index]) { - entryToUse = this->m_tlmEntries.slots[index]; - for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMPACKETIZER_HASH_BUCKETS; bucket++) { - if (entryToUse) { - if (entryToUse->id == id) { // found the matching entry - break; - } else { // try next entry - prevEntry = entryToUse; - entryToUse = entryToUse->next; - } - } else { - // Make sure that we haven't run out of buckets - FW_ASSERT(this->m_tlmEntries.free < TLMPACKETIZER_HASH_BUCKETS,this->m_tlmEntries.free); - // add new bucket from free list - entryToUse = &this->m_tlmEntries.buckets[this->m_tlmEntries.free++]; - // Coverity warning about null dereference - see if it happens - FW_ASSERT(prevEntry); - prevEntry->next = entryToUse; - // clear next pointer - entryToUse->next = nullptr; - // set all packet offsets to -1 for new entry - for (NATIVE_UINT_TYPE pktOffsetEntry = 0; pktOffsetEntry < MAX_PACKETIZER_PACKETS; pktOffsetEntry++) { - entryToUse->packetOffset[pktOffsetEntry] = -1; - } - break; - } - } - } else { - // Make sure that we haven't run out of buckets - FW_ASSERT(this->m_tlmEntries.free < TLMPACKETIZER_HASH_BUCKETS,this->m_tlmEntries.free); - // create new entry at slot head - this->m_tlmEntries.slots[index] = &this->m_tlmEntries.buckets[this->m_tlmEntries.free++]; - entryToUse = this->m_tlmEntries.slots[index]; - entryToUse->next = nullptr; - // set all packet offsets to -1 for new entry - for (NATIVE_UINT_TYPE pktOffsetEntry = 0; pktOffsetEntry < MAX_PACKETIZER_PACKETS; pktOffsetEntry++) { - entryToUse->packetOffset[pktOffsetEntry] = -1; - } - - } - - return entryToUse; - } - - - - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - void TlmPacketizer :: - TlmRecv_handler( - const NATIVE_INT_TYPE portNum, - FwChanIdType id, - Fw::Time &timeTag, - Fw::TlmBuffer &val - ) - { - FW_ASSERT(this->m_configured); - // get hash value for id - NATIVE_UINT_TYPE index = this->doHash(id); - TlmEntry* entryToUse = nullptr; - - // Search to see if the channel is being sent - entryToUse = this->m_tlmEntries.slots[index]; - - // if no entries at hash, channel not part of a packet or is not ignored - if (not entryToUse) { - this->missingChannel(id); - return; - } - - for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMPACKETIZER_HASH_BUCKETS; bucket++) { - if (entryToUse) { - if (entryToUse->id == id) { // found the matching entry - // check to see if the channel is ignored. If so, just return. - if (entryToUse->ignored) { - return; - } - break; - } else { // try next entry - entryToUse = entryToUse->next; - } - } else { - // telemetry channel not in any packets - this->missingChannel(id); - return; - } - } - - // copy telemetry value into active buffers - for (NATIVE_UINT_TYPE pkt = 0; pkt < MAX_PACKETIZER_PACKETS; pkt++) { - // check if current packet has this channel - if (entryToUse->packetOffset[pkt] != -1) { - // get destination address - // printf("PK %d CH: %d\n",this->m_fillBuffers[pkt].id,id); - this->m_lock.lock(); - this->m_fillBuffers[pkt].updated = true; - this->m_fillBuffers[pkt].latestTime = timeTag; - U8* ptr = &this->m_fillBuffers[pkt].buffer.getBuffAddr()[entryToUse->packetOffset[pkt]]; - memcpy(ptr,val.getBuffAddr(),val.getBuffLength()); - this->m_lock.unLock(); - } - } - - } - - void TlmPacketizer :: - Run_handler( - const NATIVE_INT_TYPE portNum, - NATIVE_UINT_TYPE context - ) - { - FW_ASSERT(this->m_configured); - - // Only write packets if connected - if (not this->isConnected_PktSend_OutputPort(0)) { - return; - } - - // lock mutex long enough to modify active telemetry buffer - // so the data can be read without worrying about updates - this->m_lock.lock(); - // copy buffers from fill side to send side - for (NATIVE_UINT_TYPE pkt = 0; pkt < this->m_numPackets; pkt++) { - if ((this->m_fillBuffers[pkt].updated) and - ((this->m_fillBuffers[pkt].level <= this->m_startLevel) or - (this->m_fillBuffers[pkt].requested))) { - - this->m_sendBuffers[pkt] = this->m_fillBuffers[pkt]; - if (PACKET_UPDATE_ON_CHANGE == PACKET_UPDATE_MODE) { - this->m_fillBuffers[pkt].updated = false; - } - this->m_fillBuffers[pkt].requested = false; - // PACKET_UPDATE_AFTER_FIRST_CHANGE will be this case - updated flag will not be cleared - } else if ((PACKET_UPDATE_ALWAYS == PACKET_UPDATE_MODE) and (this->m_fillBuffers[pkt].level <= this->m_startLevel)) { - this->m_sendBuffers[pkt] = this->m_fillBuffers[pkt]; - this->m_sendBuffers[pkt].updated = true; - } else { - this->m_sendBuffers[pkt].updated = false; - } - } - this->m_lock.unLock(); - - // push all updated packet buffers - for (NATIVE_UINT_TYPE pkt = 0; pkt < this->m_numPackets; pkt++) { - if (this->m_sendBuffers[pkt].updated) { - // serialize time into time offset in packet - Fw::ExternalSerializeBuffer buff(&this->m_sendBuffers[pkt].buffer.getBuffAddr() - [sizeof(FwPacketDescriptorType)+ sizeof(FwTlmPacketizeIdType)],Fw::Time::SERIALIZED_SIZE); - Fw::SerializeStatus stat = buff.serialize(this->m_sendBuffers[pkt].latestTime); - FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat); - this->PktSend_out(0,this->m_sendBuffers[pkt].buffer,0); - } - } - } - - void TlmPacketizer :: - pingIn_handler( - const NATIVE_INT_TYPE portNum, - U32 key - ) - { - // return key - this->pingOut_out(0,key); - } - - // ---------------------------------------------------------------------- - // Command handler implementations - // ---------------------------------------------------------------------- - - void TlmPacketizer :: - SET_LEVEL_cmdHandler( - const FwOpcodeType opCode, - const U32 cmdSeq, - U32 level - ) - { - this->m_startLevel = level; - if (level > this->m_maxLevel) { - this->log_WARNING_LO_MaxLevelExceed(level,this->m_maxLevel); - } - this->tlmWrite_SendLevel(level); - this->log_ACTIVITY_HI_LevelSet(level); - this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); - } - - void TlmPacketizer :: - SEND_PKT_cmdHandler( - const FwOpcodeType opCode, - const U32 cmdSeq, - U32 id - ) - { - NATIVE_UINT_TYPE pkt = 0; - for (pkt = 0; pkt < this->m_numPackets; pkt++) { - if (this->m_fillBuffers[pkt].id == id) { - - this->m_lock.lock(); - this->m_fillBuffers[pkt].updated = true; - this->m_fillBuffers[pkt].latestTime = this->getTime(); - this->m_fillBuffers[pkt].requested = true; - this->m_lock.unLock(); - - this->log_ACTIVITY_LO_PacketSent(id); - break; - } - } - - // couldn't find it - if (pkt == this->m_numPackets) { - log_WARNING_LO_PacketNotFound(id); - this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR); - return; - } - - this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); - } - - - NATIVE_UINT_TYPE TlmPacketizer::doHash(FwChanIdType id) { - return (id % TLMPACKETIZER_HASH_MOD_VALUE)%TLMPACKETIZER_NUM_TLM_HASH_SLOTS; - } - - void TlmPacketizer::missingChannel(FwChanIdType id) { - // search to see if missing channel has already been sent - for (NATIVE_UINT_TYPE slot = 0; slot < TLMPACKETIZER_MAX_MISSING_TLM_CHECK; slot++) { - // if it's been checked, return - if (this->m_missTlmCheck[slot].checked and (this->m_missTlmCheck[slot].id == id)) { - return; - } else if (not this->m_missTlmCheck[slot].checked) { - this->m_missTlmCheck[slot].checked = true; - this->m_missTlmCheck[slot].id = id; - this->log_WARNING_LO_NoChan(id); - return; - } - } - - } - - -} // end namespace Svc +} + +TlmPacketizer ::~TlmPacketizer() {} + +void TlmPacketizer::setPacketList(const TlmPacketizerPacketList& packetList, + const Svc::TlmPacketizerPacket& ignoreList, + const NATIVE_UINT_TYPE startLevel) { + FW_ASSERT(packetList.list); + FW_ASSERT(ignoreList.list); + FW_ASSERT(packetList.numEntries <= MAX_PACKETIZER_PACKETS, packetList.numEntries); + // validate packet sizes against maximum com buffer size and populate hash + // table + for (NATIVE_UINT_TYPE pktEntry = 0; pktEntry < packetList.numEntries; pktEntry++) { + // Initial size is packetized telemetry descriptor + size of time tag + sizeof packet ID + NATIVE_UINT_TYPE packetLen = + sizeof(FwPacketDescriptorType) + Fw::Time::SERIALIZED_SIZE + sizeof(FwTlmPacketizeIdType); + FW_ASSERT(packetList.list[pktEntry]->list, pktEntry); + // add up entries for each defined packet + for (NATIVE_UINT_TYPE tlmEntry = 0; tlmEntry < packetList.list[pktEntry]->numEntries; tlmEntry++) { + // get hash value for id + FwChanIdType id = packetList.list[pktEntry]->list[tlmEntry].id; + TlmEntry* entryToUse = this->findBucket(id); + // copy into entry + FW_ASSERT(entryToUse); + entryToUse->used = true; + // not ignored channel + entryToUse->ignored = false; + entryToUse->id = id; + // the offset into the buffer will be the current packet length + entryToUse->packetOffset[pktEntry] = packetLen; + + packetLen += packetList.list[pktEntry]->list[tlmEntry].size; + + } // end channel in packet + FW_ASSERT(packetLen <= FW_COM_BUFFER_MAX_SIZE, packetLen, pktEntry); + // clear contents + memset(this->m_fillBuffers[pktEntry].buffer.getBuffAddr(), 0, packetLen); + // serialize packet descriptor and packet ID now since it will always be the same + Fw::SerializeStatus stat = this->m_fillBuffers[pktEntry].buffer.serialize( + static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM)); + FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat); + stat = this->m_fillBuffers[pktEntry].buffer.serialize(packetList.list[pktEntry]->id); + FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat); + // set packet buffer length + stat = this->m_fillBuffers[pktEntry].buffer.setBuffLen(packetLen); + FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat); + // save ID + this->m_fillBuffers[pktEntry].id = packetList.list[pktEntry]->id; + // save level + this->m_fillBuffers[pktEntry].level = packetList.list[pktEntry]->level; + // store max level + if (packetList.list[pktEntry]->level > this->m_maxLevel) { + this->m_maxLevel = packetList.list[pktEntry]->level; + } + // save start level + this->m_startLevel = startLevel; + + } // end packet list + + // populate hash table with ignore list + for (NATIVE_UINT_TYPE channelEntry = 0; channelEntry < ignoreList.numEntries; channelEntry++) { + // get hash value for id + FwChanIdType id = ignoreList.list[channelEntry].id; + + TlmEntry* entryToUse = this->findBucket(id); + + // copy into entry + FW_ASSERT(entryToUse); + entryToUse->used = true; + // is ignored channel + entryToUse->ignored = true; + entryToUse->id = id; + } // end ignore list + + // store number of packets + this->m_numPackets = packetList.numEntries; + + // indicate configured + this->m_configured = true; +} + +TlmPacketizer::TlmEntry* TlmPacketizer::findBucket(FwChanIdType id) { + NATIVE_UINT_TYPE index = this->doHash(id); + FW_ASSERT(index < TLMPACKETIZER_HASH_BUCKETS); + TlmEntry* entryToUse = nullptr; + TlmEntry* prevEntry = nullptr; + + // Search to see if channel has already been stored or a bucket needs to be added + if (this->m_tlmEntries.slots[index]) { + entryToUse = this->m_tlmEntries.slots[index]; + for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMPACKETIZER_HASH_BUCKETS; bucket++) { + if (entryToUse) { + if (entryToUse->id == id) { // found the matching entry + break; + } else { // try next entry + prevEntry = entryToUse; + entryToUse = entryToUse->next; + } + } else { + // Make sure that we haven't run out of buckets + FW_ASSERT(this->m_tlmEntries.free < TLMPACKETIZER_HASH_BUCKETS, this->m_tlmEntries.free); + // add new bucket from free list + entryToUse = &this->m_tlmEntries.buckets[this->m_tlmEntries.free++]; + // Coverity warning about null dereference - see if it happens + FW_ASSERT(prevEntry); + prevEntry->next = entryToUse; + // clear next pointer + entryToUse->next = nullptr; + // set all packet offsets to -1 for new entry + for (NATIVE_UINT_TYPE pktOffsetEntry = 0; pktOffsetEntry < MAX_PACKETIZER_PACKETS; pktOffsetEntry++) { + entryToUse->packetOffset[pktOffsetEntry] = -1; + } + break; + } + } + } else { + // Make sure that we haven't run out of buckets + FW_ASSERT(this->m_tlmEntries.free < TLMPACKETIZER_HASH_BUCKETS, this->m_tlmEntries.free); + // create new entry at slot head + this->m_tlmEntries.slots[index] = &this->m_tlmEntries.buckets[this->m_tlmEntries.free++]; + entryToUse = this->m_tlmEntries.slots[index]; + entryToUse->next = nullptr; + // set all packet offsets to -1 for new entry + for (NATIVE_UINT_TYPE pktOffsetEntry = 0; pktOffsetEntry < MAX_PACKETIZER_PACKETS; pktOffsetEntry++) { + entryToUse->packetOffset[pktOffsetEntry] = -1; + } + } + + return entryToUse; +} + +// ---------------------------------------------------------------------- +// Handler implementations for user-defined typed input ports +// ---------------------------------------------------------------------- + +void TlmPacketizer ::TlmRecv_handler(const NATIVE_INT_TYPE portNum, + FwChanIdType id, + Fw::Time& timeTag, + Fw::TlmBuffer& val) { + FW_ASSERT(this->m_configured); + // get hash value for id + NATIVE_UINT_TYPE index = this->doHash(id); + TlmEntry* entryToUse = nullptr; + + // Search to see if the channel is being sent + entryToUse = this->m_tlmEntries.slots[index]; + + // if no entries at hash, channel not part of a packet or is not ignored + if (not entryToUse) { + this->missingChannel(id); + return; + } + + for (NATIVE_UINT_TYPE bucket = 0; bucket < TLMPACKETIZER_HASH_BUCKETS; bucket++) { + if (entryToUse) { + if (entryToUse->id == id) { // found the matching entry + // check to see if the channel is ignored. If so, just return. + if (entryToUse->ignored) { + return; + } + break; + } else { // try next entry + entryToUse = entryToUse->next; + } + } else { + // telemetry channel not in any packets + this->missingChannel(id); + return; + } + } + + // copy telemetry value into active buffers + for (NATIVE_UINT_TYPE pkt = 0; pkt < MAX_PACKETIZER_PACKETS; pkt++) { + // check if current packet has this channel + if (entryToUse->packetOffset[pkt] != -1) { + // get destination address + // printf("PK %d CH: %d\n",this->m_fillBuffers[pkt].id,id); + this->m_lock.lock(); + this->m_fillBuffers[pkt].updated = true; + this->m_fillBuffers[pkt].latestTime = timeTag; + U8* ptr = &this->m_fillBuffers[pkt].buffer.getBuffAddr()[entryToUse->packetOffset[pkt]]; + memcpy(ptr, val.getBuffAddr(), val.getBuffLength()); + this->m_lock.unLock(); + } + } +} + +void TlmPacketizer ::Run_handler(const NATIVE_INT_TYPE portNum, NATIVE_UINT_TYPE context) { + FW_ASSERT(this->m_configured); + + // Only write packets if connected + if (not this->isConnected_PktSend_OutputPort(0)) { + return; + } + + // lock mutex long enough to modify active telemetry buffer + // so the data can be read without worrying about updates + this->m_lock.lock(); + // copy buffers from fill side to send side + for (NATIVE_UINT_TYPE pkt = 0; pkt < this->m_numPackets; pkt++) { + if ((this->m_fillBuffers[pkt].updated) and + ((this->m_fillBuffers[pkt].level <= this->m_startLevel) or (this->m_fillBuffers[pkt].requested))) { + this->m_sendBuffers[pkt] = this->m_fillBuffers[pkt]; + if (PACKET_UPDATE_ON_CHANGE == PACKET_UPDATE_MODE) { + this->m_fillBuffers[pkt].updated = false; + } + this->m_fillBuffers[pkt].requested = false; + // PACKET_UPDATE_AFTER_FIRST_CHANGE will be this case - updated flag will not be cleared + } else if ((PACKET_UPDATE_ALWAYS == PACKET_UPDATE_MODE) and + (this->m_fillBuffers[pkt].level <= this->m_startLevel)) { + this->m_sendBuffers[pkt] = this->m_fillBuffers[pkt]; + this->m_sendBuffers[pkt].updated = true; + } else { + this->m_sendBuffers[pkt].updated = false; + } + } + this->m_lock.unLock(); + + // push all updated packet buffers + for (NATIVE_UINT_TYPE pkt = 0; pkt < this->m_numPackets; pkt++) { + if (this->m_sendBuffers[pkt].updated) { + // serialize time into time offset in packet + Fw::ExternalSerializeBuffer buff( + &this->m_sendBuffers[pkt] + .buffer.getBuffAddr()[sizeof(FwPacketDescriptorType) + sizeof(FwTlmPacketizeIdType)], + Fw::Time::SERIALIZED_SIZE); + Fw::SerializeStatus stat = buff.serialize(this->m_sendBuffers[pkt].latestTime); + FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, stat); + + this->PktSend_out(0, this->m_sendBuffers[pkt].buffer, 0); + } + } +} + +void TlmPacketizer ::pingIn_handler(const NATIVE_INT_TYPE portNum, U32 key) { + // return key + this->pingOut_out(0, key); +} + +// ---------------------------------------------------------------------- +// Command handler implementations +// ---------------------------------------------------------------------- + +void TlmPacketizer ::SET_LEVEL_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq, U32 level) { + this->m_startLevel = level; + if (level > this->m_maxLevel) { + this->log_WARNING_LO_MaxLevelExceed(level, this->m_maxLevel); + } + this->tlmWrite_SendLevel(level); + this->log_ACTIVITY_HI_LevelSet(level); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +void TlmPacketizer ::SEND_PKT_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq, U32 id) { + NATIVE_UINT_TYPE pkt = 0; + for (pkt = 0; pkt < this->m_numPackets; pkt++) { + if (this->m_fillBuffers[pkt].id == id) { + this->m_lock.lock(); + this->m_fillBuffers[pkt].updated = true; + this->m_fillBuffers[pkt].latestTime = this->getTime(); + this->m_fillBuffers[pkt].requested = true; + this->m_lock.unLock(); + + this->log_ACTIVITY_LO_PacketSent(id); + break; + } + } + + // couldn't find it + if (pkt == this->m_numPackets) { + log_WARNING_LO_PacketNotFound(id); + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR); + return; + } + + this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); +} + +NATIVE_UINT_TYPE TlmPacketizer::doHash(FwChanIdType id) { + return (id % TLMPACKETIZER_HASH_MOD_VALUE) % TLMPACKETIZER_NUM_TLM_HASH_SLOTS; +} + +void TlmPacketizer::missingChannel(FwChanIdType id) { + // search to see if missing channel has already been sent + for (NATIVE_UINT_TYPE slot = 0; slot < TLMPACKETIZER_MAX_MISSING_TLM_CHECK; slot++) { + // if it's been checked, return + if (this->m_missTlmCheck[slot].checked and (this->m_missTlmCheck[slot].id == id)) { + return; + } else if (not this->m_missTlmCheck[slot].checked) { + this->m_missTlmCheck[slot].checked = true; + this->m_missTlmCheck[slot].id = id; + this->log_WARNING_LO_NoChan(id); + return; + } + } +} + +} // end namespace Svc diff --git a/Svc/TlmPacketizer/TlmPacketizer.hpp b/Svc/TlmPacketizer/TlmPacketizer.hpp index d8492946be..4957bb3cd9 100644 --- a/Svc/TlmPacketizer/TlmPacketizer.hpp +++ b/Svc/TlmPacketizer/TlmPacketizer.hpp @@ -1,4 +1,4 @@ -// ====================================================================== +// ====================================================================== // \title TlmPacketizerImpl.hpp // \author tcanham // \brief hpp file for TlmPacketizer component implementation class @@ -11,147 +11,134 @@ #ifndef TlmPacketizer_HPP #define TlmPacketizer_HPP +#include "Os/Mutex.hpp" #include "Svc/TlmPacketizer/TlmPacketizerComponentAc.hpp" #include "Svc/TlmPacketizer/TlmPacketizerTypes.hpp" -#include "Svc/TlmPacketizer/TlmPacketizerComponentImplCfg.hpp" -#include "Os/Mutex.hpp" +#include "TlmPacketizerCfg.hpp" namespace Svc { - class TlmPacketizer : - public TlmPacketizerComponentBase - { - - public: - - // ---------------------------------------------------------------------- - // Construction, initialization, and destruction - // ---------------------------------------------------------------------- - - //! Construct object TlmPacketizer - //! - TlmPacketizer( - const char *const compName /*!< The component name*/ - ); - - //! Initialize object TlmPacketizer - //! - void init( - const NATIVE_INT_TYPE queueDepth, /*!< The queue depth*/ - const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ - ); - - void setPacketList( - const TlmPacketizerPacketList& packetList, // channels to packetize - const Svc::TlmPacketizerPacket& ignoreList, // channels to ignore (i.e. no warning event if not packetized) - const NATIVE_UINT_TYPE startLevel); // starting level of packets to send - - //! Destroy object TlmPacketizer - //! - ~TlmPacketizer(void); - - PRIVATE: - - // ---------------------------------------------------------------------- - // Handler implementations for user-defined typed input ports - // ---------------------------------------------------------------------- - - //! Handler implementation for TlmRecv - //! - void TlmRecv_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - FwChanIdType id, /*!< Telemetry Channel ID*/ - Fw::Time &timeTag, /*!< Time Tag*/ - Fw::TlmBuffer &val /*!< Buffer containing serialized telemetry value*/ - ); - - //! Handler implementation for Run - //! - void Run_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - NATIVE_UINT_TYPE context /*!< The call order*/ - ); - - //! Handler implementation for pingIn - //! - void pingIn_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - U32 key /*!< Value to return to pinger*/ - ); - - //! Implementation for SET_LEVEL command handler - //! Set telemetry send leve - void SET_LEVEL_cmdHandler( - const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ - U32 level /*!< The I32 command argument*/ - ); - - //! Implementation for SEND_PKT command handler - //! Force a packet to be sent - void SEND_PKT_cmdHandler( - const FwOpcodeType opCode, /*!< The opcode*/ - const U32 cmdSeq, /*!< The command sequence number*/ - U32 id /*!< The packet ID*/ - ); - - // number of packets to fill - NATIVE_UINT_TYPE m_numPackets; - // Array of packet buffers to send - // Double-buffered to fill one while sending one - - struct BufferEntry { - Fw::ComBuffer buffer; //!< buffer for packetized channels - Fw::Time latestTime; //!< latest update time - NATIVE_UINT_TYPE id; //!< channel id - NATIVE_UINT_TYPE level; //!< channel level - bool updated; //!< if packet had any updates during last cycle - bool requested; //!< if the packet was requested with SEND_PKT in the last cycle - }; - - // buffers for filling with telemetry - BufferEntry m_fillBuffers[MAX_PACKETIZER_PACKETS]; - // buffers for sending - will be copied from fill buffers - BufferEntry m_sendBuffers[MAX_PACKETIZER_PACKETS]; - - struct TlmEntry { - FwChanIdType id; //!< telemetry id stored in slot - // Offsets into packet buffers. - // -1 means that channel is not in that packet - NATIVE_INT_TYPE packetOffset[MAX_PACKETIZER_PACKETS]; - TlmEntry* next; //!< pointer to next bucket in table - bool used; //!< if entry has been used - bool ignored; //!< ignored packet id - NATIVE_UINT_TYPE bucketNo; //!< for testing - }; - - struct TlmSet { - TlmEntry* slots[TLMPACKETIZER_NUM_TLM_HASH_SLOTS]; //!< set of hash slots in hash table - TlmEntry buckets[TLMPACKETIZER_HASH_BUCKETS]; //!< set of buckets used in hash table - NATIVE_UINT_TYPE free; //!< next free bucket - } m_tlmEntries; - - // hash function for looking up telemetry channel - NATIVE_UINT_TYPE doHash(FwChanIdType id); - - Os::Mutex m_lock; //!< used to lock access to packet buffers - - bool m_configured; //!< indicates a table has been passed and packets configured - - struct MissingTlmChan { - FwChanIdType id; - bool checked; - } m_missTlmCheck[TLMPACKETIZER_MAX_MISSING_TLM_CHECK]; - - void missingChannel(FwChanIdType id); //!< Helper to check to see if missing channel warning was sent - - TlmEntry* findBucket(FwChanIdType id); - - NATIVE_UINT_TYPE m_startLevel; //!< initial level for sending packets - NATIVE_UINT_TYPE m_maxLevel; //!< maximum level in all packets +class TlmPacketizer : public TlmPacketizerComponentBase { + public: + // ---------------------------------------------------------------------- + // Construction, initialization, and destruction + // ---------------------------------------------------------------------- + + //! Construct object TlmPacketizer + //! + TlmPacketizer(const char* const compName /*!< The component name*/ + ); + + //! Initialize object TlmPacketizer + //! + void init(const NATIVE_INT_TYPE queueDepth, /*!< The queue depth*/ + const NATIVE_INT_TYPE instance = 0 /*!< The instance number*/ + ); + + void setPacketList( + const TlmPacketizerPacketList& packetList, // channels to packetize + const Svc::TlmPacketizerPacket& ignoreList, // channels to ignore (i.e. no warning event if not packetized) + const NATIVE_UINT_TYPE startLevel); // starting level of packets to send + + //! Destroy object TlmPacketizer + //! + ~TlmPacketizer(void); + + PRIVATE: + // ---------------------------------------------------------------------- + // Handler implementations for user-defined typed input ports + // ---------------------------------------------------------------------- + + //! Handler implementation for TlmRecv + //! + void TlmRecv_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + FwChanIdType id, /*!< Telemetry Channel ID*/ + Fw::Time& timeTag, /*!< Time Tag*/ + Fw::TlmBuffer& val /*!< Buffer containing serialized telemetry value*/ + ); + + //! Handler implementation for Run + //! + void Run_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + NATIVE_UINT_TYPE context /*!< The call order*/ + ); + + //! Handler implementation for pingIn + //! + void pingIn_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + U32 key /*!< Value to return to pinger*/ + ); + + //! Implementation for SET_LEVEL command handler + //! Set telemetry send leve + void SET_LEVEL_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ + const U32 cmdSeq, /*!< The command sequence number*/ + U32 level /*!< The I32 command argument*/ + ); + + //! Implementation for SEND_PKT command handler + //! Force a packet to be sent + void SEND_PKT_cmdHandler(const FwOpcodeType opCode, /*!< The opcode*/ + const U32 cmdSeq, /*!< The command sequence number*/ + U32 id /*!< The packet ID*/ + ); + + // number of packets to fill + NATIVE_UINT_TYPE m_numPackets; + // Array of packet buffers to send + // Double-buffered to fill one while sending one + + struct BufferEntry { + Fw::ComBuffer buffer; //!< buffer for packetized channels + Fw::Time latestTime; //!< latest update time + NATIVE_UINT_TYPE id; //!< channel id + NATIVE_UINT_TYPE level; //!< channel level + bool updated; //!< if packet had any updates during last cycle + bool requested; //!< if the packet was requested with SEND_PKT in the last cycle + }; + // buffers for filling with telemetry + BufferEntry m_fillBuffers[MAX_PACKETIZER_PACKETS]; + // buffers for sending - will be copied from fill buffers + BufferEntry m_sendBuffers[MAX_PACKETIZER_PACKETS]; + + struct TlmEntry { + FwChanIdType id; //!< telemetry id stored in slot + // Offsets into packet buffers. + // -1 means that channel is not in that packet + NATIVE_INT_TYPE packetOffset[MAX_PACKETIZER_PACKETS]; + TlmEntry* next; //!< pointer to next bucket in table + bool used; //!< if entry has been used + bool ignored; //!< ignored packet id + NATIVE_UINT_TYPE bucketNo; //!< for testing }; -} // end namespace Svc + struct TlmSet { + TlmEntry* slots[TLMPACKETIZER_NUM_TLM_HASH_SLOTS]; //!< set of hash slots in hash table + TlmEntry buckets[TLMPACKETIZER_HASH_BUCKETS]; //!< set of buckets used in hash table + NATIVE_UINT_TYPE free; //!< next free bucket + } m_tlmEntries; + + // hash function for looking up telemetry channel + NATIVE_UINT_TYPE doHash(FwChanIdType id); + + Os::Mutex m_lock; //!< used to lock access to packet buffers + + bool m_configured; //!< indicates a table has been passed and packets configured + + struct MissingTlmChan { + FwChanIdType id; + bool checked; + } m_missTlmCheck[TLMPACKETIZER_MAX_MISSING_TLM_CHECK]; + + void missingChannel(FwChanIdType id); //!< Helper to check to see if missing channel warning was sent + + TlmEntry* findBucket(FwChanIdType id); + + NATIVE_UINT_TYPE m_startLevel; //!< initial level for sending packets + NATIVE_UINT_TYPE m_maxLevel; //!< maximum level in all packets +}; + +} // end namespace Svc #endif diff --git a/Svc/TlmPacketizer/TlmPacketizerComponentImplCfg.hpp b/Svc/TlmPacketizer/TlmPacketizerComponentImplCfg.hpp deleted file mode 100644 index 0e7405c2cc..0000000000 --- a/Svc/TlmPacketizer/TlmPacketizerComponentImplCfg.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * TlmPacketizerComponentImplCfg.hpp - * - * Created on: Dec 10, 2017 - * Author: tim - */ - -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. - - -#ifndef SVC_TLMPACKETIZER_TLMPACKETIZERCOMPONENTIMPLCFG_HPP_ -#define SVC_TLMPACKETIZER_TLMPACKETIZERCOMPONENTIMPLCFG_HPP_ - -#include - -namespace Svc { - static const NATIVE_UINT_TYPE MAX_PACKETIZER_PACKETS = 200; - static const NATIVE_UINT_TYPE TLMPACKETIZER_NUM_TLM_HASH_SLOTS = 15; // !< Number of slots in the hash table. - // Works best when set to about twice the number of components producing telemetry - static const NATIVE_UINT_TYPE TLMPACKETIZER_HASH_MOD_VALUE = 99; // !< The modulo value of the hashing function. - // Should be set to a little below the ID gaps to spread the entries around - - static const NATIVE_UINT_TYPE TLMPACKETIZER_HASH_BUCKETS = 1000; // !< Buckets assignable to a hash slot. - // Buckets must be >= number of telemetry channels in system - static const NATIVE_UINT_TYPE TLMPACKETIZER_MAX_MISSING_TLM_CHECK = 25; // !< Maximum number of missing telemetry channel checks - - // packet update mode - enum PacketUpdateMode { - PACKET_UPDATE_ALWAYS, // Always send packets, even if no changes to channel data - PACKET_UPDATE_ON_CHANGE, // Only send packets if any of the channels updates - PACKET_UPDATE_AFTER_FIRST_CHANGE, // Always send packets, but only after first channel has been updated - }; - - static const PacketUpdateMode PACKET_UPDATE_MODE = PACKET_UPDATE_ON_CHANGE; -} - - - -#endif /* SVC_TLMPACKETIZER_TLMPACKETIZERCOMPONENTIMPLCFG_HPP_ */ diff --git a/Svc/TlmPacketizer/TlmPacketizerTypes.hpp b/Svc/TlmPacketizer/TlmPacketizerTypes.hpp index 1a0e9efd38..0ef7c38a62 100644 --- a/Svc/TlmPacketizer/TlmPacketizerTypes.hpp +++ b/Svc/TlmPacketizer/TlmPacketizerTypes.hpp @@ -10,31 +10,30 @@ // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. - #ifndef SVC_TLMPACKETIZER_TLMPACKETIZERTYPES_HPP_ #define SVC_TLMPACKETIZER_TLMPACKETIZERTYPES_HPP_ #include -#include +#include namespace Svc { - struct TlmPacketizerChannelEntry { - FwChanIdType id; //!< Id of channel - NATIVE_UINT_TYPE size; //!< serialized size of channel in bytes - }; - - struct TlmPacketizerPacket { - const TlmPacketizerChannelEntry* list; //!< pointer to a channel entry - FwTlmPacketizeIdType id; //!< packet ID - NATIVE_UINT_TYPE level; //!< packet level - used to select set of packets to send - NATIVE_UINT_TYPE numEntries; //!< number of channels in packet - }; - - struct TlmPacketizerPacketList { - const TlmPacketizerPacket* list[MAX_PACKETIZER_PACKETS]; //!< - NATIVE_UINT_TYPE numEntries; - }; -} +struct TlmPacketizerChannelEntry { + FwChanIdType id; //!< Id of channel + NATIVE_UINT_TYPE size; //!< serialized size of channel in bytes +}; + +struct TlmPacketizerPacket { + const TlmPacketizerChannelEntry* list; //!< pointer to a channel entry + FwTlmPacketizeIdType id; //!< packet ID + NATIVE_UINT_TYPE level; //!< packet level - used to select set of packets to send + NATIVE_UINT_TYPE numEntries; //!< number of channels in packet +}; + +struct TlmPacketizerPacketList { + const TlmPacketizerPacket* list[MAX_PACKETIZER_PACKETS]; //!< + NATIVE_UINT_TYPE numEntries; +}; +} // namespace Svc #endif /* SVC_TLMPACKETIZER_TLMPACKETIZERTYPES_HPP_ */ diff --git a/Svc/TlmPacketizer/test/ut/Tester.cpp b/Svc/TlmPacketizer/test/ut/Tester.cpp index ff3be6a8de..f72ef3feab 100644 --- a/Svc/TlmPacketizer/test/ut/Tester.cpp +++ b/Svc/TlmPacketizer/test/ut/Tester.cpp @@ -18,1051 +18,960 @@ namespace Svc { - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - Tester :: - Tester() : - TlmPacketizerGTestBase("Tester", MAX_HISTORY_SIZE), - component("TlmPacketizer") - ,m_timeSent(false) - { +// ---------------------------------------------------------------------- +// Construction and destruction +// ---------------------------------------------------------------------- + +Tester ::Tester() : TlmPacketizerGTestBase("Tester", MAX_HISTORY_SIZE), component("TlmPacketizer"), m_timeSent(false) { this->initComponents(); this->connectPorts(); - } +} + +Tester ::~Tester() {} + +// ---------------------------------------------------------------------- +// Tests +// ---------------------------------------------------------------------- + +// Some Test tables + +TlmPacketizerChannelEntry packet1List[] = {{10, 4}, {100, 2}, {333, 1}}; + +TlmPacketizerChannelEntry packet2List[] = {{10, 4}, {13, 8}, {250, 2}, {22, 1}}; + +TlmPacketizerPacket packet1 = {packet1List, 4, 1, FW_NUM_ARRAY_ELEMENTS(packet1List)}; + +TlmPacketizerPacket packet2 = {packet2List, 8, 2, FW_NUM_ARRAY_ELEMENTS(packet2List)}; + +TlmPacketizerPacketList packetList = {{&packet1, &packet2}, 2}; - Tester :: - ~Tester() - { +TlmPacketizerChannelEntry ignoreList[] = {{25, 0}, {50, 0}}; - } +TlmPacketizerPacket ignore = {ignoreList, 0, 0, FW_NUM_ARRAY_ELEMENTS(ignoreList)}; - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- +void Tester ::initTest() { + this->component.setPacketList(packetList, ignore, 2); +} - // Some Test tables +void Tester ::pushTlmTest() { + this->component.setPacketList(packetList, ignore, 2); + Fw::Time ts; + Fw::TlmBuffer buff; - TlmPacketizerChannelEntry packet1List[] = { - {10, 4}, - {100, 2}, - {333, 1} - }; + // first channel + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(20))); + this->invoke_to_TlmRecv(0, 10, ts, buff); - TlmPacketizerChannelEntry packet2List[] = { - {10, 4}, - {13, 8}, - {250, 2}, - {22,1} - }; + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(15))); + this->invoke_to_TlmRecv(0, 100, ts, buff); - TlmPacketizerPacket packet1 = {packet1List, 4, 1, FW_NUM_ARRAY_ELEMENTS(packet1List)}; + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(14))); + this->invoke_to_TlmRecv(0, 333, ts, buff); - TlmPacketizerPacket packet2 = {packet2List, 8, 2, FW_NUM_ARRAY_ELEMENTS(packet2List)}; + // second channel + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(50))); + this->invoke_to_TlmRecv(0, 10, ts, buff); - TlmPacketizerPacketList packetList = { - {&packet1, &packet2}, - 2 - }; + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(1000000))); + this->invoke_to_TlmRecv(0, 13, ts, buff); - TlmPacketizerChannelEntry ignoreList[] = { - {25, 0}, - {50, 0} - }; - - TlmPacketizerPacket ignore = {ignoreList, 0, 0, FW_NUM_ARRAY_ELEMENTS(ignoreList)}; + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(1010))); + this->invoke_to_TlmRecv(0, 250, ts, buff); - void Tester :: - initTest() - { - this->component.setPacketList(packetList,ignore,2); - - } - - void Tester :: - pushTlmTest() - { - this->component.setPacketList(packetList,ignore,2); - Fw::Time ts; - Fw::TlmBuffer buff; + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(15))); + this->invoke_to_TlmRecv(0, 22, ts, buff); +} - // first channel - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(20))); - this->invoke_to_TlmRecv(0,10,ts,buff); - - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(15))); - this->invoke_to_TlmRecv(0,100,ts,buff); - - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(14))); - this->invoke_to_TlmRecv(0,333,ts,buff); - - // second channel - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(50))); - this->invoke_to_TlmRecv(0,10,ts,buff); - - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(1000000))); - this->invoke_to_TlmRecv(0,13,ts,buff); - - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(1010))); - this->invoke_to_TlmRecv(0,250,ts,buff); - - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(15))); - this->invoke_to_TlmRecv(0,22,ts,buff); - - } - - - void Tester :: - sendPacketsTest() - { - this->component.setPacketList(packetList,ignore,2); - Fw::Time ts; - Fw::TlmBuffer buff; - - // first channel - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(20))); - this->invoke_to_TlmRecv(0,10,ts,buff); - - // second channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(15))); - this->invoke_to_TlmRecv(0,100,ts,buff); - - // third channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(14))); - this->invoke_to_TlmRecv(0,333,ts,buff); - - // fifth channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(1000000))); - this->invoke_to_TlmRecv(0,13,ts,buff); - - // sixth channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(1010))); - this->invoke_to_TlmRecv(0,250,ts,buff); - - // seventh channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(15))); - this->invoke_to_TlmRecv(0,22,ts,buff); - - this->setTestTime(this->m_testTime); - // run scheduler port to send packets - this->invoke_to_Run(0,0); - this->component.doDispatch(); - - ASSERT_FROM_PORT_HISTORY_SIZE(2); - ASSERT_from_PktSend_SIZE(2); - - // construct the packet buffers and make sure they are correct - - Fw::ComBuffer comBuff; - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(4))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(this->m_testTime)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(15))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(14))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(8))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(this->m_testTime)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1000000))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1010))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(15))); - - ASSERT_from_PktSend(1,comBuff,static_cast(0)); - - } - - void Tester :: - sendPacketLevelsTest() - { - this->component.setPacketList(packetList,ignore,1); - Fw::Time ts; - Fw::TlmBuffer buff; - - // first channel - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(20))); - this->invoke_to_TlmRecv(0,10,ts,buff); - - // second channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(15))); - this->invoke_to_TlmRecv(0,100,ts,buff); - - // third channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(14))); - this->invoke_to_TlmRecv(0,333,ts,buff); - - // fifth channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(1000000))); - this->invoke_to_TlmRecv(0,13,ts,buff); - - // sixth channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(1010))); - this->invoke_to_TlmRecv(0,250,ts,buff); - - // seventh channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(15))); - this->invoke_to_TlmRecv(0,22,ts,buff); - - this->setTestTime(this->m_testTime); - // run scheduler port to send packets - this->invoke_to_Run(0,0); - this->component.doDispatch(); - - ASSERT_FROM_PORT_HISTORY_SIZE(2); - ASSERT_from_PktSend_SIZE(2); - - // construct the packet buffers and make sure they are correct - - Fw::ComBuffer comBuff; - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(4))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(this->m_testTime)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(15))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(14))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(8))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(this->m_testTime)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1000000))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1010))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(15))); - - ASSERT_from_PktSend(1,comBuff,static_cast(0)); - - } - - void Tester :: - updatePacketsTest() - { - this->component.setPacketList(packetList,ignore,2); - Fw::Time ts; - Fw::TlmBuffer buff; - - Fw::ComBuffer comBuff; - - // Initially no packets should be pushed - this->invoke_to_Run(0,0); - this->component.doDispatch(); - - // Should be no packets pushed - ASSERT_from_PktSend_SIZE(0); - - // first channel - ts.set(100,1000); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(20))); - this->invoke_to_TlmRecv(0,10,ts,buff); - - this->m_testTime.add(1,0); - this->setTestTime(this->m_testTime); - this->clearFromPortHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - ASSERT_from_PktSend_SIZE(2); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(4))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(0))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(0))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(8))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(0))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(0))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(0))); - - ASSERT_from_PktSend(1,comBuff,static_cast(0)); - - // second channel - - buff.resetSer(); - ts.add(1,0); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(15))); - this->invoke_to_TlmRecv(0,100,ts,buff); - - this->m_testTime.add(1,0); - this->setTestTime(this->m_testTime); - this->clearFromPortHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - - // only one should be pushed - ASSERT_from_PktSend_SIZE(1); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(4))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(15))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(0))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - buff.resetSer(); - ts.add(1,0); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(14))); - this->invoke_to_TlmRecv(0,333,ts,buff); - - this->clearFromPortHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - // only one should be pushed - ASSERT_from_PktSend_SIZE(1); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(4))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(15))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(14))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - buff.resetSer(); - ts.add(1,0); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(1000000))); - this->invoke_to_TlmRecv(0,13,ts,buff); - - this->clearFromPortHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - ASSERT_from_PktSend_SIZE(1); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(8))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1000000))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(0))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(0))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - buff.resetSer(); - ts.add(1,0); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(1010))); - this->invoke_to_TlmRecv(0,250,ts,buff); - - this->clearFromPortHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - ASSERT_from_PktSend_SIZE(1); - - comBuff.resetSer(); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(8))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1000000))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1010))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(0))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - buff.resetSer(); - ts.add(1,0); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(15))); - this->invoke_to_TlmRecv(0,22,ts,buff); - - this->clearFromPortHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - ASSERT_from_PktSend_SIZE(1); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(8))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1000000))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1010))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(15))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - //** Update all the packets again with new values - - // first channel - buff.resetSer(); - ts.add(1,0); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(1000))); - this->invoke_to_TlmRecv(0,10,ts,buff); - - this->clearFromPortHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - ASSERT_from_PktSend_SIZE(2); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(4))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1000))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(15))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(14))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(8))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1000))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1000000))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1010))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(15))); - - ASSERT_from_PktSend(1,comBuff,static_cast(0)); - - // second channel - - buff.resetSer(); - ts.add(1,0); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(550))); - this->invoke_to_TlmRecv(0,100,ts,buff); - - this->clearFromPortHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - ASSERT_from_PktSend_SIZE(1); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(4))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1000))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(550))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(14))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - buff.resetSer(); - ts.add(1,0); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(211))); - this->invoke_to_TlmRecv(0,333,ts,buff); - - this->clearFromPortHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - ASSERT_from_PktSend_SIZE(1); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(4))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1000))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(550))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(211))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - buff.resetSer(); - ts.add(1,0); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(34441))); - this->invoke_to_TlmRecv(0,13,ts,buff); - - this->clearFromPortHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - ASSERT_from_PktSend_SIZE(1); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(8))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1000))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(34441))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1010))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(15))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - buff.resetSer(); - ts.add(1,0); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(8649))); - this->invoke_to_TlmRecv(0,250,ts,buff); - - this->clearFromPortHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - ASSERT_from_PktSend_SIZE(1); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(8))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1000))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(34441))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(8649))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(15))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - buff.resetSer(); - ts.add(1,0); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(65))); - this->invoke_to_TlmRecv(0,22,ts,buff); - - this->clearFromPortHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - ASSERT_from_PktSend_SIZE(1); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(8))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1000))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(34441))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(8649))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(65))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - } - - void Tester :: - ignoreTest() - { - this->component.setPacketList(packetList,ignore,2); - Fw::Time ts; - Fw::TlmBuffer buff; - - Fw::ComBuffer comBuff; - - // Initially no packets should be pushed - this->invoke_to_Run(0,0); - this->component.doDispatch(); - - // Should be no packets pushed - ASSERT_from_PktSend_SIZE(0); - - // first channel - ts.set(100,1000); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(20))); - this->invoke_to_TlmRecv(0,10,ts,buff); - - this->m_testTime.add(1,0); - this->setTestTime(this->m_testTime); - this->clearFromPortHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - ASSERT_from_PktSend_SIZE(2); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(4))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(0))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(0))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(8))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(ts)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(0))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(0))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(0))); - - ASSERT_from_PktSend(1,comBuff,static_cast(0)); - - // ignored channel - - buff.resetSer(); - ts.add(1,0); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(20))); - this->invoke_to_TlmRecv(0,25,ts,buff); - - this->m_testTime.add(1,0); - this->setTestTime(this->m_testTime); - this->clearFromPortHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - - // no packets should be pushed - ASSERT_from_PktSend_SIZE(0); - - } - - void Tester :: - sendManualPacketTest() - { - this->component.setPacketList(packetList,ignore,2); - Fw::Time ts; - Fw::TlmBuffer buff; - - // first channel - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(20))); - this->invoke_to_TlmRecv(0,10,ts,buff); - - // second channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(15))); - this->invoke_to_TlmRecv(0,100,ts,buff); - - // third channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(14))); - this->invoke_to_TlmRecv(0,333,ts,buff); - - // fifth channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(1000000))); - this->invoke_to_TlmRecv(0,13,ts,buff); - - // sixth channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(1010))); - this->invoke_to_TlmRecv(0,250,ts,buff); - - // seventh channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(15))); - this->invoke_to_TlmRecv(0,22,ts,buff); - - this->setTestTime(this->m_testTime); - // run scheduler port to send packets - this->invoke_to_Run(0,0); - this->component.doDispatch(); - - ASSERT_FROM_PORT_HISTORY_SIZE(2); - ASSERT_from_PktSend_SIZE(2); - - // construct the packet buffers and make sure they are correct - - Fw::ComBuffer comBuff1; - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff1.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff1.serialize(static_cast(4))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff1.serialize(this->m_testTime)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff1.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff1.serialize(static_cast(15))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff1.serialize(static_cast(14))); - - ASSERT_from_PktSend(0,comBuff1,static_cast(0)); - - Fw::ComBuffer comBuff2; - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff2.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff2.serialize(static_cast(8))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff2.serialize(this->m_testTime)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff2.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff2.serialize(static_cast(1000000))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff2.serialize(static_cast(1010))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff2.serialize(static_cast(15))); - - ASSERT_from_PktSend(1,comBuff2,static_cast(0)); - - // should not be any new packets - this->clearHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - - ASSERT_FROM_PORT_HISTORY_SIZE(0); - ASSERT_from_PktSend_SIZE(0); - - // send command to manually send a packet - this->sendCmd_SEND_PKT(0,12,4); - this->component.doDispatch(); - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_PacketSent(0,4); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE(0,TlmPacketizerComponentBase::OPCODE_SEND_PKT,12,Fw::CmdResponse::OK); - // dispatch run call to send packet - this->invoke_to_Run(0,0); - this->component.doDispatch(); - ASSERT_from_PktSend_SIZE(1); - ASSERT_from_PktSend(0,comBuff1,static_cast(0)); - - // another packet - this->clearHistory(); - this->invoke_to_Run(0,0); - this->component.doDispatch(); - - ASSERT_FROM_PORT_HISTORY_SIZE(0); - ASSERT_from_PktSend_SIZE(0); - - // send command to manually send a packet - this->clearHistory(); - this->sendCmd_SEND_PKT(0,12,8); - this->component.doDispatch(); - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_PacketSent(0,8); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE(0,TlmPacketizerComponentBase::OPCODE_SEND_PKT,12,Fw::CmdResponse::OK); - // dispatch run call to send packet - this->invoke_to_Run(0,0); - this->component.doDispatch(); - ASSERT_from_PktSend_SIZE(1); - ASSERT_from_PktSend(0,comBuff2,static_cast(0)); - - // Try to send invalid packet - // send command to manually send a packet - this->clearHistory(); - this->sendCmd_SEND_PKT(0,12,20); - this->component.doDispatch(); - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_PacketNotFound(0,20); - ASSERT_CMD_RESPONSE_SIZE(1); - ASSERT_CMD_RESPONSE(0,TlmPacketizerComponentBase::OPCODE_SEND_PKT,12,Fw::CmdResponse::VALIDATION_ERROR); - - } - - void Tester :: - setPacketLevelTest() - { - this->component.setPacketList(packetList,ignore,0); - Fw::Time ts; - Fw::TlmBuffer buff; - - // first channel - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(0x20))); - this->invoke_to_TlmRecv(0,10,ts,buff); - - // second channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(0x15))); - this->invoke_to_TlmRecv(0,100,ts,buff); - - // third channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(0x14))); - this->invoke_to_TlmRecv(0,333,ts,buff); - - // fifth channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(0x1000000))); - this->invoke_to_TlmRecv(0,13,ts,buff); - - // sixth channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(0x1010))); - this->invoke_to_TlmRecv(0,250,ts,buff); - - // seventh channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(0x15))); - this->invoke_to_TlmRecv(0,22,ts,buff); - - this->setTestTime(this->m_testTime); - // run scheduler port to send packets - this->invoke_to_Run(0,0); - this->component.doDispatch(); - - // should be no packets sent since packet level is 0 - ASSERT_FROM_PORT_HISTORY_SIZE(0); - ASSERT_from_PktSend_SIZE(0); - - // send the command to select packet level 1 - this->clearHistory(); - this->sendCmd_SET_LEVEL(0,13,1); - this->component.doDispatch(); - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_LevelSet_SIZE(1); - ASSERT_EVENTS_LevelSet(0,1); - ASSERT_TLM_SIZE(1); - ASSERT_TLM_SendLevel_SIZE(1); - ASSERT_TLM_SendLevel(0,1); - - // send the packets - // first channel - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(0x20))); - this->invoke_to_TlmRecv(0,10,ts,buff); - - // second channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(0x15))); - this->invoke_to_TlmRecv(0,100,ts,buff); - - // third channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(0x14))); - this->invoke_to_TlmRecv(0,333,ts,buff); - - // fifth channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(0x1000000))); - this->invoke_to_TlmRecv(0,13,ts,buff); - - // sixth channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(0x1010))); - this->invoke_to_TlmRecv(0,250,ts,buff); - - // seventh channel - buff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,buff.serialize(static_cast(0x15))); - this->invoke_to_TlmRecv(0,22,ts,buff); - - this->setTestTime(this->m_testTime); - // run scheduler port to send packets - this->invoke_to_Run(0,0); - this->component.doDispatch(); - - // should be one packet sent since packet level is 1 - ASSERT_FROM_PORT_HISTORY_SIZE(1); - ASSERT_from_PktSend_SIZE(1); - - // Should be packet 4 - - Fw::ComBuffer comBuff1; - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff1.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff1.serialize(static_cast(4))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff1.serialize(this->m_testTime)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff1.serialize(static_cast(0x20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff1.serialize(static_cast(0x15))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff1.serialize(static_cast(0x14))); - - ASSERT_from_PktSend(0,comBuff1,static_cast(0)); - -return; - - ASSERT_FROM_PORT_HISTORY_SIZE(2); - ASSERT_from_PktSend_SIZE(2); - - // construct the packet buffers and make sure they are correct - - Fw::ComBuffer comBuff; - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(4))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(this->m_testTime)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(15))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(14))); - - ASSERT_from_PktSend(0,comBuff,static_cast(0)); - - comBuff.resetSer(); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(8))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(this->m_testTime)); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(20))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1000000))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(1010))); - ASSERT_EQ(Fw::FW_SERIALIZE_OK,comBuff.serialize(static_cast(15))); - - ASSERT_from_PktSend(1,comBuff,static_cast(0)); - - } - - void Tester :: - nonPacketizedChannelTest() { - - this->component.setPacketList(packetList,ignore,2); - Fw::Time ts; - Fw::TlmBuffer buff; - - // start at non-used channel - for (NATIVE_UINT_TYPE channel = 1000; channel < 1000 + TLMPACKETIZER_MAX_MISSING_TLM_CHECK; channel++) { - this->clearEvents(); - this->invoke_to_TlmRecv(0,channel,ts,buff); - ASSERT_EVENTS_SIZE(1); - ASSERT_EVENTS_NoChan_SIZE(1); - ASSERT_EVENTS_NoChan(0,channel); - } - - // One more channel should not emit event - this->clearEvents(); - this->invoke_to_TlmRecv(0,1000+TLMPACKETIZER_MAX_MISSING_TLM_CHECK,ts,buff); - ASSERT_EVENTS_SIZE(0); - ASSERT_EVENTS_NoChan_SIZE(0); - - // sending the missing channels again should emit no events - - for (NATIVE_UINT_TYPE channel = 1000; channel < 1000 + TLMPACKETIZER_MAX_MISSING_TLM_CHECK; channel++) { - this->clearEvents(); - this->invoke_to_TlmRecv(0,channel,ts,buff); - ASSERT_EVENTS_SIZE(0); - ASSERT_EVENTS_NoChan_SIZE(0); - } - - } - - void Tester :: - pingTest() { - - this->component.setPacketList(packetList,ignore,2); - // ping component - this->clearFromPortHistory(); - this->invoke_to_pingIn(0,static_cast(0x1234)); - this->component.doDispatch(); - ASSERT_from_pingOut_SIZE(1); - ASSERT_from_pingOut(0,static_cast(0x1234)); - - } - - // ---------------------------------------------------------------------- - // Handlers for typed from ports - // ---------------------------------------------------------------------- - - void Tester :: - from_Time_handler( - const NATIVE_INT_TYPE portNum, - Fw::Time &time - ) - { - time = this->m_testTime; - this->m_timeSent = true; - } - - void Tester :: - from_PktSend_handler( - const NATIVE_INT_TYPE portNum, - Fw::ComBuffer &data, - U32 context - ) - { +void Tester ::sendPacketsTest() { + this->component.setPacketList(packetList, ignore, 2); + Fw::Time ts; + Fw::TlmBuffer buff; + + // first channel + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(20))); + this->invoke_to_TlmRecv(0, 10, ts, buff); + + // second channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(15))); + this->invoke_to_TlmRecv(0, 100, ts, buff); + + // third channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(14))); + this->invoke_to_TlmRecv(0, 333, ts, buff); + + // fifth channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(1000000))); + this->invoke_to_TlmRecv(0, 13, ts, buff); + + // sixth channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(1010))); + this->invoke_to_TlmRecv(0, 250, ts, buff); + + // seventh channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(15))); + this->invoke_to_TlmRecv(0, 22, ts, buff); + + this->setTestTime(this->m_testTime); + // run scheduler port to send packets + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + + ASSERT_FROM_PORT_HISTORY_SIZE(2); + ASSERT_from_PktSend_SIZE(2); + + // construct the packet buffers and make sure they are correct + + Fw::ComBuffer comBuff; + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(4))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(this->m_testTime)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(15))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(14))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(8))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(this->m_testTime)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1000000))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1010))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(15))); + + ASSERT_from_PktSend(1, comBuff, static_cast(0)); +} + +void Tester ::sendPacketLevelsTest() { + this->component.setPacketList(packetList, ignore, 1); + Fw::Time ts; + Fw::TlmBuffer buff; + + // first channel + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(20))); + this->invoke_to_TlmRecv(0, 10, ts, buff); + + // second channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(15))); + this->invoke_to_TlmRecv(0, 100, ts, buff); + + // third channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(14))); + this->invoke_to_TlmRecv(0, 333, ts, buff); + + // fifth channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(1000000))); + this->invoke_to_TlmRecv(0, 13, ts, buff); + + // sixth channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(1010))); + this->invoke_to_TlmRecv(0, 250, ts, buff); + + // seventh channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(15))); + this->invoke_to_TlmRecv(0, 22, ts, buff); + + this->setTestTime(this->m_testTime); + // run scheduler port to send packets + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + + ASSERT_FROM_PORT_HISTORY_SIZE(2); + ASSERT_from_PktSend_SIZE(2); + + // construct the packet buffers and make sure they are correct + + Fw::ComBuffer comBuff; + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(4))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(this->m_testTime)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(15))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(14))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(8))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(this->m_testTime)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1000000))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1010))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(15))); + + ASSERT_from_PktSend(1, comBuff, static_cast(0)); +} + +void Tester ::updatePacketsTest() { + this->component.setPacketList(packetList, ignore, 2); + Fw::Time ts; + Fw::TlmBuffer buff; + + Fw::ComBuffer comBuff; + + // Initially no packets should be pushed + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + + // Should be no packets pushed + ASSERT_from_PktSend_SIZE(0); + + // first channel + ts.set(100, 1000); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(20))); + this->invoke_to_TlmRecv(0, 10, ts, buff); + + this->m_testTime.add(1, 0); + this->setTestTime(this->m_testTime); + this->clearFromPortHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + ASSERT_from_PktSend_SIZE(2); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(4))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(0))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(0))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(8))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(0))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(0))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(0))); + + ASSERT_from_PktSend(1, comBuff, static_cast(0)); + + // second channel + + buff.resetSer(); + ts.add(1, 0); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(15))); + this->invoke_to_TlmRecv(0, 100, ts, buff); + + this->m_testTime.add(1, 0); + this->setTestTime(this->m_testTime); + this->clearFromPortHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + + // only one should be pushed + ASSERT_from_PktSend_SIZE(1); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(4))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(15))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(0))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); + + buff.resetSer(); + ts.add(1, 0); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(14))); + this->invoke_to_TlmRecv(0, 333, ts, buff); + + this->clearFromPortHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + // only one should be pushed + ASSERT_from_PktSend_SIZE(1); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(4))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(15))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(14))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); + + buff.resetSer(); + ts.add(1, 0); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(1000000))); + this->invoke_to_TlmRecv(0, 13, ts, buff); + + this->clearFromPortHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + ASSERT_from_PktSend_SIZE(1); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(8))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1000000))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(0))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(0))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); + + buff.resetSer(); + ts.add(1, 0); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(1010))); + this->invoke_to_TlmRecv(0, 250, ts, buff); + + this->clearFromPortHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + ASSERT_from_PktSend_SIZE(1); + + comBuff.resetSer(); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(8))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1000000))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1010))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(0))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); + + buff.resetSer(); + ts.add(1, 0); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(15))); + this->invoke_to_TlmRecv(0, 22, ts, buff); + + this->clearFromPortHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + ASSERT_from_PktSend_SIZE(1); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(8))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1000000))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1010))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(15))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); + + //** Update all the packets again with new values + + // first channel + buff.resetSer(); + ts.add(1, 0); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(1000))); + this->invoke_to_TlmRecv(0, 10, ts, buff); + + this->clearFromPortHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + ASSERT_from_PktSend_SIZE(2); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(4))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1000))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(15))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(14))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(8))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1000))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1000000))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1010))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(15))); + + ASSERT_from_PktSend(1, comBuff, static_cast(0)); + + // second channel + + buff.resetSer(); + ts.add(1, 0); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(550))); + this->invoke_to_TlmRecv(0, 100, ts, buff); + + this->clearFromPortHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + ASSERT_from_PktSend_SIZE(1); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(4))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1000))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(550))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(14))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); + + buff.resetSer(); + ts.add(1, 0); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(211))); + this->invoke_to_TlmRecv(0, 333, ts, buff); + + this->clearFromPortHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + ASSERT_from_PktSend_SIZE(1); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(4))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1000))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(550))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(211))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); + + buff.resetSer(); + ts.add(1, 0); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(34441))); + this->invoke_to_TlmRecv(0, 13, ts, buff); + + this->clearFromPortHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + ASSERT_from_PktSend_SIZE(1); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(8))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1000))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(34441))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1010))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(15))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); + + buff.resetSer(); + ts.add(1, 0); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(8649))); + this->invoke_to_TlmRecv(0, 250, ts, buff); + + this->clearFromPortHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + ASSERT_from_PktSend_SIZE(1); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(8))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1000))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(34441))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(8649))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(15))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); + + buff.resetSer(); + ts.add(1, 0); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(65))); + this->invoke_to_TlmRecv(0, 22, ts, buff); + + this->clearFromPortHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + ASSERT_from_PktSend_SIZE(1); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(8))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1000))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(34441))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(8649))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(65))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); +} + +void Tester ::ignoreTest() { + this->component.setPacketList(packetList, ignore, 2); + Fw::Time ts; + Fw::TlmBuffer buff; + + Fw::ComBuffer comBuff; + + // Initially no packets should be pushed + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + + // Should be no packets pushed + ASSERT_from_PktSend_SIZE(0); + + // first channel + ts.set(100, 1000); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(20))); + this->invoke_to_TlmRecv(0, 10, ts, buff); + + this->m_testTime.add(1, 0); + this->setTestTime(this->m_testTime); + this->clearFromPortHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + ASSERT_from_PktSend_SIZE(2); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(4))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(0))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(0))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(8))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(ts)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(0))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(0))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(0))); + + ASSERT_from_PktSend(1, comBuff, static_cast(0)); + + // ignored channel + + buff.resetSer(); + ts.add(1, 0); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(20))); + this->invoke_to_TlmRecv(0, 25, ts, buff); + + this->m_testTime.add(1, 0); + this->setTestTime(this->m_testTime); + this->clearFromPortHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + + // no packets should be pushed + ASSERT_from_PktSend_SIZE(0); +} + +void Tester ::sendManualPacketTest() { + this->component.setPacketList(packetList, ignore, 2); + Fw::Time ts; + Fw::TlmBuffer buff; + + // first channel + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(20))); + this->invoke_to_TlmRecv(0, 10, ts, buff); + + // second channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(15))); + this->invoke_to_TlmRecv(0, 100, ts, buff); + + // third channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(14))); + this->invoke_to_TlmRecv(0, 333, ts, buff); + + // fifth channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(1000000))); + this->invoke_to_TlmRecv(0, 13, ts, buff); + + // sixth channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(1010))); + this->invoke_to_TlmRecv(0, 250, ts, buff); + + // seventh channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(15))); + this->invoke_to_TlmRecv(0, 22, ts, buff); + + this->setTestTime(this->m_testTime); + // run scheduler port to send packets + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + + ASSERT_FROM_PORT_HISTORY_SIZE(2); + ASSERT_from_PktSend_SIZE(2); + + // construct the packet buffers and make sure they are correct + + Fw::ComBuffer comBuff1; + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff1.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff1.serialize(static_cast(4))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff1.serialize(this->m_testTime)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff1.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff1.serialize(static_cast(15))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff1.serialize(static_cast(14))); + + ASSERT_from_PktSend(0, comBuff1, static_cast(0)); + + Fw::ComBuffer comBuff2; + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff2.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff2.serialize(static_cast(8))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff2.serialize(this->m_testTime)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff2.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff2.serialize(static_cast(1000000))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff2.serialize(static_cast(1010))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff2.serialize(static_cast(15))); + + ASSERT_from_PktSend(1, comBuff2, static_cast(0)); + + // should not be any new packets + this->clearHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + + ASSERT_FROM_PORT_HISTORY_SIZE(0); + ASSERT_from_PktSend_SIZE(0); + + // send command to manually send a packet + this->sendCmd_SEND_PKT(0, 12, 4); + this->component.doDispatch(); + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_PacketSent(0, 4); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE(0, TlmPacketizerComponentBase::OPCODE_SEND_PKT, 12, Fw::CmdResponse::OK); + // dispatch run call to send packet + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + ASSERT_from_PktSend_SIZE(1); + ASSERT_from_PktSend(0, comBuff1, static_cast(0)); + + // another packet + this->clearHistory(); + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + + ASSERT_FROM_PORT_HISTORY_SIZE(0); + ASSERT_from_PktSend_SIZE(0); + + // send command to manually send a packet + this->clearHistory(); + this->sendCmd_SEND_PKT(0, 12, 8); + this->component.doDispatch(); + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_PacketSent(0, 8); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE(0, TlmPacketizerComponentBase::OPCODE_SEND_PKT, 12, Fw::CmdResponse::OK); + // dispatch run call to send packet + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + ASSERT_from_PktSend_SIZE(1); + ASSERT_from_PktSend(0, comBuff2, static_cast(0)); + + // Try to send invalid packet + // send command to manually send a packet + this->clearHistory(); + this->sendCmd_SEND_PKT(0, 12, 20); + this->component.doDispatch(); + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_PacketNotFound(0, 20); + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE(0, TlmPacketizerComponentBase::OPCODE_SEND_PKT, 12, Fw::CmdResponse::VALIDATION_ERROR); +} + +void Tester ::setPacketLevelTest() { + this->component.setPacketList(packetList, ignore, 0); + Fw::Time ts; + Fw::TlmBuffer buff; + + // first channel + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(0x20))); + this->invoke_to_TlmRecv(0, 10, ts, buff); + + // second channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(0x15))); + this->invoke_to_TlmRecv(0, 100, ts, buff); + + // third channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(0x14))); + this->invoke_to_TlmRecv(0, 333, ts, buff); + + // fifth channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(0x1000000))); + this->invoke_to_TlmRecv(0, 13, ts, buff); + + // sixth channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(0x1010))); + this->invoke_to_TlmRecv(0, 250, ts, buff); + + // seventh channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(0x15))); + this->invoke_to_TlmRecv(0, 22, ts, buff); + + this->setTestTime(this->m_testTime); + // run scheduler port to send packets + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + + // should be no packets sent since packet level is 0 + ASSERT_FROM_PORT_HISTORY_SIZE(0); + ASSERT_from_PktSend_SIZE(0); + + // send the command to select packet level 1 + this->clearHistory(); + this->sendCmd_SET_LEVEL(0, 13, 1); + this->component.doDispatch(); + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_LevelSet_SIZE(1); + ASSERT_EVENTS_LevelSet(0, 1); + ASSERT_TLM_SIZE(1); + ASSERT_TLM_SendLevel_SIZE(1); + ASSERT_TLM_SendLevel(0, 1); + + // send the packets + // first channel + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(0x20))); + this->invoke_to_TlmRecv(0, 10, ts, buff); + + // second channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(0x15))); + this->invoke_to_TlmRecv(0, 100, ts, buff); + + // third channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(0x14))); + this->invoke_to_TlmRecv(0, 333, ts, buff); + + // fifth channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(0x1000000))); + this->invoke_to_TlmRecv(0, 13, ts, buff); + + // sixth channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(0x1010))); + this->invoke_to_TlmRecv(0, 250, ts, buff); + + // seventh channel + buff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, buff.serialize(static_cast(0x15))); + this->invoke_to_TlmRecv(0, 22, ts, buff); + + this->setTestTime(this->m_testTime); + // run scheduler port to send packets + this->invoke_to_Run(0, 0); + this->component.doDispatch(); + + // should be one packet sent since packet level is 1 + ASSERT_FROM_PORT_HISTORY_SIZE(1); + ASSERT_from_PktSend_SIZE(1); + + // Should be packet 4 + + Fw::ComBuffer comBuff1; + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff1.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff1.serialize(static_cast(4))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff1.serialize(this->m_testTime)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff1.serialize(static_cast(0x20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff1.serialize(static_cast(0x15))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff1.serialize(static_cast(0x14))); + + ASSERT_from_PktSend(0, comBuff1, static_cast(0)); + + return; + + ASSERT_FROM_PORT_HISTORY_SIZE(2); + ASSERT_from_PktSend_SIZE(2); + + // construct the packet buffers and make sure they are correct + + Fw::ComBuffer comBuff; + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(4))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(this->m_testTime)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(15))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(14))); + + ASSERT_from_PktSend(0, comBuff, static_cast(0)); + + comBuff.resetSer(); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, + comBuff.serialize(static_cast(Fw::ComPacket::FW_PACKET_PACKETIZED_TLM))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(8))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(this->m_testTime)); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(20))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1000000))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(1010))); + ASSERT_EQ(Fw::FW_SERIALIZE_OK, comBuff.serialize(static_cast(15))); + + ASSERT_from_PktSend(1, comBuff, static_cast(0)); +} + +void Tester ::nonPacketizedChannelTest() { + this->component.setPacketList(packetList, ignore, 2); + Fw::Time ts; + Fw::TlmBuffer buff; + + // start at non-used channel + for (NATIVE_UINT_TYPE channel = 1000; channel < 1000 + TLMPACKETIZER_MAX_MISSING_TLM_CHECK; channel++) { + this->clearEvents(); + this->invoke_to_TlmRecv(0, channel, ts, buff); + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_NoChan_SIZE(1); + ASSERT_EVENTS_NoChan(0, channel); + } + + // One more channel should not emit event + this->clearEvents(); + this->invoke_to_TlmRecv(0, 1000 + TLMPACKETIZER_MAX_MISSING_TLM_CHECK, ts, buff); + ASSERT_EVENTS_SIZE(0); + ASSERT_EVENTS_NoChan_SIZE(0); + + // sending the missing channels again should emit no events + + for (NATIVE_UINT_TYPE channel = 1000; channel < 1000 + TLMPACKETIZER_MAX_MISSING_TLM_CHECK; channel++) { + this->clearEvents(); + this->invoke_to_TlmRecv(0, channel, ts, buff); + ASSERT_EVENTS_SIZE(0); + ASSERT_EVENTS_NoChan_SIZE(0); + } +} + +void Tester ::pingTest() { + this->component.setPacketList(packetList, ignore, 2); + // ping component + this->clearFromPortHistory(); + this->invoke_to_pingIn(0, static_cast(0x1234)); + this->component.doDispatch(); + ASSERT_from_pingOut_SIZE(1); + ASSERT_from_pingOut(0, static_cast(0x1234)); +} + +// ---------------------------------------------------------------------- +// Handlers for typed from ports +// ---------------------------------------------------------------------- + +void Tester ::from_Time_handler(const NATIVE_INT_TYPE portNum, Fw::Time& time) { + time = this->m_testTime; + this->m_timeSent = true; +} + +void Tester ::from_PktSend_handler(const NATIVE_INT_TYPE portNum, Fw::ComBuffer& data, U32 context) { this->pushFromPortEntry_PktSend(data, context); - } - - void Tester :: - from_pingOut_handler( - const NATIVE_INT_TYPE portNum, - U32 key - ) - { - this->pushFromPortEntry_pingOut(key); - } +} - // ---------------------------------------------------------------------- - // Helper methods - // ---------------------------------------------------------------------- +void Tester ::from_pingOut_handler(const NATIVE_INT_TYPE portNum, U32 key) { + this->pushFromPortEntry_pingOut(key); +} - void Tester :: - connectPorts() - { +// ---------------------------------------------------------------------- +// Helper methods +// ---------------------------------------------------------------------- +void Tester ::connectPorts() { // PktSend - this->component.set_PktSend_OutputPort( - 0, - this->get_from_PktSend(0) - ); + this->component.set_PktSend_OutputPort(0, this->get_from_PktSend(0)); // Run - this->connect_to_Run( - 0, - this->component.get_Run_InputPort(0) - ); + this->connect_to_Run(0, this->component.get_Run_InputPort(0)); // TlmRecv - this->connect_to_TlmRecv( - 0, - this->component.get_TlmRecv_InputPort(0) - ); + this->connect_to_TlmRecv(0, this->component.get_TlmRecv_InputPort(0)); // cmdIn - this->connect_to_cmdIn( - 0, - this->component.get_cmdIn_InputPort(0) - ); + this->connect_to_cmdIn(0, this->component.get_cmdIn_InputPort(0)); // cmdRegOut - this->component.set_cmdRegOut_OutputPort( - 0, - this->get_from_cmdRegOut(0) - ); + this->component.set_cmdRegOut_OutputPort(0, this->get_from_cmdRegOut(0)); // cmdResponseOut - this->component.set_cmdResponseOut_OutputPort( - 0, - this->get_from_cmdResponseOut(0) - ); + this->component.set_cmdResponseOut_OutputPort(0, this->get_from_cmdResponseOut(0)); // eventOut - this->component.set_eventOut_OutputPort( - 0, - this->get_from_eventOut(0) - ); + this->component.set_eventOut_OutputPort(0, this->get_from_eventOut(0)); // pingIn - this->connect_to_pingIn( - 0, - this->component.get_pingIn_InputPort(0) - ); + this->connect_to_pingIn(0, this->component.get_pingIn_InputPort(0)); // pingOut - this->component.set_pingOut_OutputPort( - 0, - this->get_from_pingOut(0) - ); + this->component.set_pingOut_OutputPort(0, this->get_from_pingOut(0)); // textEventOut - this->component.set_textEventOut_OutputPort( - 0, - this->get_from_textEventOut(0) - ); + this->component.set_textEventOut_OutputPort(0, this->get_from_textEventOut(0)); // timeGetOut - this->component.set_timeGetOut_OutputPort( - 0, - this->get_from_timeGetOut(0) - ); + this->component.set_timeGetOut_OutputPort(0, this->get_from_timeGetOut(0)); // tlmOut - this->component.set_tlmOut_OutputPort( - 0, - this->get_from_tlmOut(0) - ); - - } - - void Tester::textLogIn(const FwEventIdType id, //!< The event ID - Fw::Time& timeTag, //!< The time - const Fw::LogSeverity severity, //!< The severity - const Fw::TextLogString& text //!< The event string - ) { - TextLogEntry e = { id, timeTag, severity, text }; + this->component.set_tlmOut_OutputPort(0, this->get_from_tlmOut(0)); +} - printTextLogHistoryEntry(e, stdout); - } +void Tester::textLogIn(const FwEventIdType id, //!< The event ID + Fw::Time& timeTag, //!< The time + const Fw::LogSeverity severity, //!< The severity + const Fw::TextLogString& text //!< The event string +) { + TextLogEntry e = {id, timeTag, severity, text}; + printTextLogHistoryEntry(e, stdout); +} - void Tester :: - initComponents() - { +void Tester ::initComponents() { this->init(); - this->component.init( - QUEUE_DEPTH, INSTANCE - ); - } + this->component.init(QUEUE_DEPTH, INSTANCE); +} -} // end namespace Svc +} // end namespace Svc diff --git a/Svc/TlmPacketizer/test/ut/Tester.hpp b/Svc/TlmPacketizer/test/ut/Tester.hpp index 99652415c2..3f7d45b187 100644 --- a/Svc/TlmPacketizer/test/ut/Tester.hpp +++ b/Svc/TlmPacketizer/test/ut/Tester.hpp @@ -16,135 +16,121 @@ namespace Svc { - class Tester : - public TlmPacketizerGTestBase - { - - // ---------------------------------------------------------------------- - // Construction and destruction - // ---------------------------------------------------------------------- - - public: - - //! Construct object Tester - //! - Tester(void); - - //! Destroy object Tester - //! - ~Tester(void); - - public: - - // ---------------------------------------------------------------------- - // Tests - // ---------------------------------------------------------------------- - - //! Initialization test - //! - void initTest(void); - - //! push telemetry test - //! - void pushTlmTest(void); - - //! send packets test - //! - void sendPacketsTest(void); - - //! send packets with levels test - //! - void sendPacketLevelsTest(void); - - //! update packets test - //! - void updatePacketsTest(void); - - //! non-packetized channel test - //! - void nonPacketizedChannelTest(void); - - //! ping test - //! - void pingTest(void); - - //! ignore test - //! - void ignoreTest(void); - - //! manually send packet test - //! - void sendManualPacketTest(void); - - //! set packet level test - //! - void setPacketLevelTest(void); - - private: - - // ---------------------------------------------------------------------- - // Handlers for typed from ports - // ---------------------------------------------------------------------- - - //! Handler for from_Time - //! - void from_Time_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::Time &time /*!< The U32 cmd argument*/ - ); - - //! Handler for from_PktSend - //! - void from_PktSend_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - Fw::ComBuffer &data, /*!< Buffer containing packet data*/ - U32 context /*!< Call context value; meaning chosen by user*/ - ); - - //! Handler for from_pingOut - //! - void from_pingOut_handler( - const NATIVE_INT_TYPE portNum, /*!< The port number*/ - U32 key /*!< Value to return to pinger*/ - ); - - virtual void textLogIn( - const FwEventIdType id, /*!< The event ID*/ - Fw::Time& timeTag, /*!< The time*/ - const Fw::LogSeverity severity, /*!< The severity*/ - const Fw::TextLogString& text /*!< The event string*/ - ); - - - private: - - // ---------------------------------------------------------------------- - // Helper methods - // ---------------------------------------------------------------------- - - //! Connect ports - //! - void connectPorts(void); - - //! Initialize components - //! - void initComponents(void); - - private: - - // ---------------------------------------------------------------------- - // Variables - // ---------------------------------------------------------------------- - - //! The component under test - //! - TlmPacketizer component; - - Fw::Time m_testTime; //!< store test time for packets - bool m_timeSent; //!< flag when time was sent - - }; - -} // end namespace Svc +class Tester : public TlmPacketizerGTestBase { + // ---------------------------------------------------------------------- + // Construction and destruction + // ---------------------------------------------------------------------- + + public: + //! Construct object Tester + //! + Tester(void); + + //! Destroy object Tester + //! + ~Tester(void); + + public: + // ---------------------------------------------------------------------- + // Tests + // ---------------------------------------------------------------------- + + //! Initialization test + //! + void initTest(void); + + //! push telemetry test + //! + void pushTlmTest(void); + + //! send packets test + //! + void sendPacketsTest(void); + + //! send packets with levels test + //! + void sendPacketLevelsTest(void); + + //! update packets test + //! + void updatePacketsTest(void); + + //! non-packetized channel test + //! + void nonPacketizedChannelTest(void); + + //! ping test + //! + void pingTest(void); + + //! ignore test + //! + void ignoreTest(void); + + //! manually send packet test + //! + void sendManualPacketTest(void); + + //! set packet level test + //! + void setPacketLevelTest(void); + + private: + // ---------------------------------------------------------------------- + // Handlers for typed from ports + // ---------------------------------------------------------------------- + + //! Handler for from_Time + //! + void from_Time_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::Time& time /*!< The U32 cmd argument*/ + ); + + //! Handler for from_PktSend + //! + void from_PktSend_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + Fw::ComBuffer& data, /*!< Buffer containing packet data*/ + U32 context /*!< Call context value; meaning chosen by user*/ + ); + + //! Handler for from_pingOut + //! + void from_pingOut_handler(const NATIVE_INT_TYPE portNum, /*!< The port number*/ + U32 key /*!< Value to return to pinger*/ + ); + + virtual void textLogIn(const FwEventIdType id, /*!< The event ID*/ + Fw::Time& timeTag, /*!< The time*/ + const Fw::LogSeverity severity, /*!< The severity*/ + const Fw::TextLogString& text /*!< The event string*/ + ); + + private: + // ---------------------------------------------------------------------- + // Helper methods + // ---------------------------------------------------------------------- + + //! Connect ports + //! + void connectPorts(void); + + //! Initialize components + //! + void initComponents(void); + + private: + // ---------------------------------------------------------------------- + // Variables + // ---------------------------------------------------------------------- + + //! The component under test + //! + TlmPacketizer component; + + Fw::Time m_testTime; //!< store test time for packets + bool m_timeSent; //!< flag when time was sent +}; + +} // end namespace Svc #endif diff --git a/Svc/TlmPacketizer/test/ut/main.cpp b/Svc/TlmPacketizer/test/ut/main.cpp index 3cd590702d..678a586ee0 100644 --- a/Svc/TlmPacketizer/test/ut/main.cpp +++ b/Svc/TlmPacketizer/test/ut/main.cpp @@ -3,64 +3,55 @@ // ALL RIGHTS RESERVED. United States Government Sponsorship // acknowledged. - -#include "Tester.hpp" #include #include +#include "Tester.hpp" -TEST(TestNominal,Initialization) { - - TEST_CASE(100.1.1,"Initialization"); +TEST(TestNominal, Initialization) { + TEST_CASE(100.1.1, "Initialization"); Svc::Tester tester; tester.initTest(); } - -TEST(TestNominal,PushTlm) { - - TEST_CASE(100.1.2,"Push Telemetry"); +TEST(TestNominal, PushTlm) { + TEST_CASE(100.1.2, "Push Telemetry"); Svc::Tester tester; tester.pushTlmTest(); } -TEST(TestNominal,SendPackets) { - - TEST_CASE(100.1.2,"Send Packets"); +TEST(TestNominal, SendPackets) { + TEST_CASE(100.1.2, "Send Packets"); Svc::Tester tester; tester.sendPacketsTest(); } -//TEST(TestNominal,SendPacketLevels) { +// TEST(TestNominal,SendPacketLevels) { // -// TEST_CASE(100.1.3,"Send Packets with levels"); -// Svc::Tester tester; -// tester.sendPacketLevelsTest(); -//} - -TEST(TestNominal,UpdatePacketsTest) { +// TEST_CASE(100.1.3,"Send Packets with levels"); +// Svc::Tester tester; +// tester.sendPacketLevelsTest(); +// } - TEST_CASE(100.1.4,"Update Packets"); +TEST(TestNominal, UpdatePacketsTest) { + TEST_CASE(100.1.4, "Update Packets"); Svc::Tester tester; tester.updatePacketsTest(); } -TEST(TestNominal,PingTest) { - - TEST_CASE(100.1.5,"Ping"); +TEST(TestNominal, PingTest) { + TEST_CASE(100.1.5, "Ping"); Svc::Tester tester; tester.pingTest(); } -TEST(TestNominal,IgnoredChannelTest) { - - TEST_CASE(100.1.6,"Ignored Channels"); +TEST(TestNominal, IgnoredChannelTest) { + TEST_CASE(100.1.6, "Ignored Channels"); Svc::Tester tester; tester.ignoreTest(); } -TEST(TestNominal,SendPacketTest) { - - TEST_CASE(100.1.7,"Manually sent packets"); +TEST(TestNominal, SendPacketTest) { + TEST_CASE(100.1.7, "Manually sent packets"); Svc::Tester tester; tester.sendManualPacketTest(); } @@ -72,9 +63,8 @@ TEST(TestNominal,SetPacketLevelTest) { tester.setPacketLevelTest(); } #endif -TEST(TestOffNominal,NonPacketizedChannelTest) { - - TEST_CASE(100.2.1,"Non-packetized Channels"); +TEST(TestOffNominal, NonPacketizedChannelTest) { + TEST_CASE(100.2.1, "Non-packetized Channels"); Svc::Tester tester; tester.nonPacketizedChannelTest(); } diff --git a/Svc/UdpReceiver/UdpReceiverComponentImpl.cpp b/Svc/UdpReceiver/UdpReceiverComponentImpl.cpp index 4b6181a537..8c9885b3de 100644 --- a/Svc/UdpReceiver/UdpReceiverComponentImpl.cpp +++ b/Svc/UdpReceiver/UdpReceiverComponentImpl.cpp @@ -12,7 +12,7 @@ #include -#include "Fw/Types/BasicTypes.hpp" +#include #include #include #include diff --git a/Svc/UdpSender/UdpSenderComponentImpl.cpp b/Svc/UdpSender/UdpSenderComponentImpl.cpp index 0271e2a928..9daa282562 100644 --- a/Svc/UdpSender/UdpSenderComponentImpl.cpp +++ b/Svc/UdpSender/UdpSenderComponentImpl.cpp @@ -12,7 +12,7 @@ #include -#include "Fw/Types/BasicTypes.hpp" +#include #include #include #include diff --git a/Svc/WatchDog/CMakeLists.txt b/Svc/WatchDog/CMakeLists.txt index 5a13e22a60..b155117329 100644 --- a/Svc/WatchDog/CMakeLists.txt +++ b/Svc/WatchDog/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # # Note: using PROJECT_NAME as EXECUTABLE_NAME @@ -10,4 +10,8 @@ set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/WatchDog.fpp" ) +set(MOD_DEPS + Fw/Port +) + register_fprime_module() diff --git a/Svc/locs.fpp b/Svc/locs.fpp deleted file mode 100644 index 7c79bd583d..0000000000 --- a/Svc/locs.fpp +++ /dev/null @@ -1,50 +0,0 @@ -locate component Svc.ActiveLogger at "ActiveLogger/ActiveLogger.fpp" -locate component Svc.ActiveRateGroup at "ActiveRateGroup/ActiveRateGroup.fpp" -locate component Svc.ActiveTextLogger at "ActiveTextLogger/ActiveTextLogger.fpp" -locate component Svc.AssertFatalAdapter at "AssertFatalAdapter/AssertFatalAdapter.fpp" -locate component Svc.BufferLogger at "BufferLogger/BufferLogger.fpp" -locate component Svc.BufferManager at "BufferManager/BufferManager.fpp" -locate component Svc.CmdSequencer at "CmdSequencer/CmdSequencer.fpp" -locate component Svc.ComLogger at "ComLogger/ComLogger.fpp" -locate component Svc.ComSplitter at "ComSplitter/ComSplitter.fpp" -locate component Svc.CommandDispatcher at "CmdDispatcher/CmdDispatcher.fpp" -locate component Svc.Deframer at "Deframer/Deframer.fpp" -locate component Svc.FatalHandler at "FatalHandler/FatalHandler.fpp" -locate component Svc.FileDownlink at "FileDownlink/FileDownlink.fpp" -locate component Svc.FileManager at "FileManager/FileManager.fpp" -locate component Svc.FileUplink at "FileUplink/FileUplink.fpp" -locate component Svc.Framer at "Framer/Framer.fpp" -locate component Svc.GenericHub at "GenericHub/GenericHub.fpp" -locate component Svc.GenericRepeater at "GenericRepeater/GenericRepeater.fpp" -locate component Svc.GroundInterface at "GroundInterface/GroundInterface.fpp" -locate component Svc.Health at "Health/Health.fpp" -locate component Svc.LinuxTimer at "LinuxTimer/LinuxTimer.fpp" -locate component Svc.PassiveTextLogger at "PassiveConsoleTextLogger/PassiveConsoleTextLogger.fpp" -locate component Svc.PolyDb at "PolyDb/PolyDb.fpp" -locate component Svc.PrmDb at "PrmDb/PrmDb.fpp" -locate component Svc.RateGroupDriver at "RateGroupDriver/RateGroupDriver.fpp" -locate component Svc.StaticMemory at "StaticMemory/StaticMemory.fpp" -locate component Svc.Time at "Time/Time.fpp" -locate component Svc.TlmChan at "TlmChan/TlmChan.fpp" -locate port Svc.CmdSeqCancel at "Seq/Seq.fpp" -locate port Svc.CmdSeqIn at "Seq/Seq.fpp" -locate port Svc.Cycle at "Cycle/Cycle.fpp" -locate port Svc.FatalEvent at "Fatal/Fatal.fpp" -locate port Svc.Ping at "Ping/Ping.fpp" -locate port Svc.Poly at "PolyIf/PolyIf.fpp" -locate port Svc.Sched at "Sched/Sched.fpp" -locate port Svc.SendFileComplete at "FileDownlink/FileDownlink.fpp" -locate port Svc.SendFileRequest at "FileDownlink/FileDownlink.fpp" -locate port Svc.WatchDog at "WatchDog/WatchDog.fpp" -locate type Svc.ActiveLogger.Enabled at "ActiveLogger/ActiveLogger.fpp" -locate type Svc.ActiveLogger.FilterSeverity at "ActiveLogger/ActiveLogger.fpp" -locate type Svc.BufferLogger.LogState at "BufferLogger/BufferLogger.fpp" -locate type Svc.CmdSequencer.BlockState at "CmdSequencer/CmdSequencer.fpp" -locate type Svc.CmdSequencer.FileReadStage at "CmdSequencer/CmdSequencer.fpp" -locate type Svc.CmdSequencer.SeqMode at "CmdSequencer/CmdSequencer.fpp" -locate type Svc.MeasurementStatus at "PolyIf/PolyIf.fpp" -locate type Svc.PrmDb.PrmReadError at "PrmDb/PrmDb.fpp" -locate type Svc.PrmDb.PrmWriteError at "PrmDb/PrmDb.fpp" -locate type Svc.SendFileResponse at "FileDownlink/FileDownlink.fpp" -locate type Svc.SendFileStatus at "FileDownlink/FileDownlink.fpp" -locate type Svc.TimerVal at "Cycle/Cycle.fpp" diff --git a/Svc/subdirs.txt b/Svc/subdirs.txt deleted file mode 100644 index 782fc8c0da..0000000000 --- a/Svc/subdirs.txt +++ /dev/null @@ -1,35 +0,0 @@ -ActiveLogger -ActiveRateGroup -ActiveTextLogger -AssertFatalAdapter -BufferLogger -BufferManager -CmdDispatcher -CmdSequencer -ComLogger -ComSplitter -Cycle -Deframer -Fatal -FatalHandler -FileDownlink -FileManager -FileUplink -Framer -GenericHub -GenericRepeater -GroundInterface -Health -LinuxTimer -PassiveConsoleTextLogger -Ping -PolyDb -PolyIf -PrmDb -RateGroupDriver -Sched -Seq -StaticMemory -Time -TlmChan -WatchDog diff --git a/Svc/update-locs b/Svc/update-locs deleted file mode 100755 index 76583058af..0000000000 --- a/Svc/update-locs +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -fpp-locate-defs `find . -name '*.fpp'` > locs.fpp diff --git a/Svc/update-subdirs b/Svc/update-subdirs deleted file mode 100755 index f86970a7cb..0000000000 --- a/Svc/update-subdirs +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -find . -mindepth 2 -name '*.fpp' | cut -d '/' -f 2 | sort | uniq > subdirs.txt diff --git a/Utils/CRCChecker.cpp b/Utils/CRCChecker.cpp index 3b1bbe92d1..e5ba06e444 100644 --- a/Utils/CRCChecker.cpp +++ b/Utils/CRCChecker.cpp @@ -26,7 +26,7 @@ namespace Utils { NATIVE_INT_TYPE i; NATIVE_INT_TYPE blocks; NATIVE_INT_TYPE remaining_bytes; - U64 filesize; + FwSizeType filesize; Os::File f; Os::FileSystem::Status fs_stat; Os::File::Status stat; @@ -46,7 +46,7 @@ namespace Utils { } int_file_size = static_cast(filesize); - if(static_cast(int_file_size) != filesize) + if(static_cast(int_file_size) != filesize) { return FAILED_FILE_SIZE_CAST; } @@ -154,7 +154,7 @@ namespace Utils { NATIVE_INT_TYPE i; NATIVE_INT_TYPE blocks; NATIVE_INT_TYPE remaining_bytes; - U64 filesize; + FwSizeType filesize; Os::File f; Os::FileSystem::Status fs_stat; Os::File::Status stat; @@ -172,7 +172,7 @@ namespace Utils { } int_file_size = static_cast(filesize); - if(static_cast(int_file_size) != filesize) + if(static_cast(int_file_size) != filesize) { return FAILED_FILE_SIZE_CAST; } diff --git a/Utils/CRCChecker.hpp b/Utils/CRCChecker.hpp index 8d277af931..d15c23e2e9 100644 --- a/Utils/CRCChecker.hpp +++ b/Utils/CRCChecker.hpp @@ -12,7 +12,7 @@ #ifndef CRC_CHECKER_HPP #define CRC_CHECKER_HPP -#include +#include namespace Utils { diff --git a/Utils/Hash/CMakeLists.txt b/Utils/Hash/CMakeLists.txt index e58862fa6c..c04cec2859 100644 --- a/Utils/Hash/CMakeLists.txt +++ b/Utils/Hash/CMakeLists.txt @@ -1,7 +1,7 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### diff --git a/Utils/Hash/HashBuffer.hpp b/Utils/Hash/HashBuffer.hpp index 71712081f9..eeee42da2a 100644 --- a/Utils/Hash/HashBuffer.hpp +++ b/Utils/Hash/HashBuffer.hpp @@ -13,7 +13,7 @@ #ifndef UTILS_HASH_BUFFER_HPP #define UTILS_HASH_BUFFER_HPP -#include +#include #include #include #include diff --git a/Utils/LockGuard.hpp b/Utils/LockGuard.hpp index b7e54c72ef..5b632101e3 100644 --- a/Utils/LockGuard.hpp +++ b/Utils/LockGuard.hpp @@ -12,7 +12,7 @@ #ifndef LockGuard_HPP #define LockGuard_HPP -#include +#include #include namespace Utils { diff --git a/Utils/RateLimiter.hpp b/Utils/RateLimiter.hpp index 58979fdcbd..8705bada36 100644 --- a/Utils/RateLimiter.hpp +++ b/Utils/RateLimiter.hpp @@ -13,7 +13,7 @@ #ifndef RateLimiter_HPP #define RateLimiter_HPP -#include +#include #include namespace Utils { diff --git a/Utils/TokenBucket.hpp b/Utils/TokenBucket.hpp index c4f171106d..845e279724 100644 --- a/Utils/TokenBucket.hpp +++ b/Utils/TokenBucket.hpp @@ -14,7 +14,7 @@ #ifndef TokenBucket_HPP #define TokenBucket_HPP -#include +#include #include #define MAX_TOKEN_BUCKET_TOKENS 1000 diff --git a/Utils/Types/CMakeLists.txt b/Utils/Types/CMakeLists.txt index 297c1cdbbd..5e098fb115 100644 --- a/Utils/Types/CMakeLists.txt +++ b/Utils/Types/CMakeLists.txt @@ -1,12 +1,13 @@ #### # F prime CMakeLists.txt: # -# SOURCE_FILES: combined list of source and autocoding diles +# SOURCE_FILES: combined list of source and autocoding files # MOD_DEPS: (optional) module dependencies # #### set(SOURCE_FILES "${CMAKE_CURRENT_LIST_DIR}/CircularBuffer.cpp" + "${CMAKE_CURRENT_LIST_DIR}/Queue.cpp" ) set(MOD_DEPS "Fw/Types" diff --git a/Utils/Types/CircularBuffer.cpp b/Utils/Types/CircularBuffer.cpp index 31d5fb34d7..b835f58585 100644 --- a/Utils/Types/CircularBuffer.cpp +++ b/Utils/Types/CircularBuffer.cpp @@ -12,7 +12,7 @@ * Revised March 2022 * Author: bocchino */ -#include +#include #include #include @@ -22,13 +22,37 @@ namespace Types { +CircularBuffer :: CircularBuffer() : + m_store(nullptr), + m_store_size(0), + m_head_idx(0), + m_allocated_size(0), + m_high_water_mark(0) +{ + +} + CircularBuffer :: CircularBuffer(U8* const buffer, const NATIVE_UINT_TYPE size) : - m_store(buffer), - m_store_size(size), + m_store(nullptr), + m_store_size(0), m_head_idx(0), - m_allocated_size(0) + m_allocated_size(0), + m_high_water_mark(0) { - FW_ASSERT(m_store_size > 0); + setup(buffer, size); +} + +void CircularBuffer :: setup(U8* const buffer, const NATIVE_UINT_TYPE size) { + FW_ASSERT(size > 0); + FW_ASSERT(buffer != nullptr); + FW_ASSERT(m_store == nullptr && m_store_size == 0); // Not already setup + + // Initialize buffer data + m_store = buffer; + m_store_size = size; + m_head_idx = 0; + m_allocated_size = 0; + m_high_water_mark = 0; } NATIVE_UINT_TYPE CircularBuffer :: get_allocated_size() const { @@ -36,6 +60,7 @@ NATIVE_UINT_TYPE CircularBuffer :: get_allocated_size() const { } NATIVE_UINT_TYPE CircularBuffer :: get_free_size() const { + FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called FW_ASSERT(m_allocated_size <= m_store_size, m_allocated_size); return m_store_size - m_allocated_size; } @@ -46,6 +71,7 @@ NATIVE_UINT_TYPE CircularBuffer :: advance_idx(NATIVE_UINT_TYPE idx, NATIVE_UINT } Fw::SerializeStatus CircularBuffer :: serialize(const U8* const buffer, const NATIVE_UINT_TYPE size) { + FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called FW_ASSERT(buffer != nullptr); // Check there is sufficient space if (size > get_free_size()) { @@ -60,14 +86,17 @@ Fw::SerializeStatus CircularBuffer :: serialize(const U8* const buffer, const NA } m_allocated_size += size; FW_ASSERT(m_allocated_size <= this->get_capacity(), m_allocated_size); + m_high_water_mark = (m_high_water_mark > m_allocated_size) ? m_high_water_mark : m_allocated_size; return Fw::FW_SERIALIZE_OK; } Fw::SerializeStatus CircularBuffer :: peek(char& value, NATIVE_UINT_TYPE offset) const { + FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called return peek(reinterpret_cast(value), offset); } Fw::SerializeStatus CircularBuffer :: peek(U8& value, NATIVE_UINT_TYPE offset) const { + FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called // Check there is sufficient data if ((sizeof(U8) + offset) > m_allocated_size) { return Fw::FW_DESERIALIZE_BUFFER_EMPTY; @@ -79,6 +108,7 @@ Fw::SerializeStatus CircularBuffer :: peek(U8& value, NATIVE_UINT_TYPE offset) c } Fw::SerializeStatus CircularBuffer :: peek(U32& value, NATIVE_UINT_TYPE offset) const { + FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called // Check there is sufficient data if ((sizeof(U32) + offset) > m_allocated_size) { return Fw::FW_DESERIALIZE_BUFFER_EMPTY; @@ -96,6 +126,7 @@ Fw::SerializeStatus CircularBuffer :: peek(U32& value, NATIVE_UINT_TYPE offset) } Fw::SerializeStatus CircularBuffer :: peek(U8* buffer, NATIVE_UINT_TYPE size, NATIVE_UINT_TYPE offset) const { + FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called FW_ASSERT(buffer != nullptr); // Check there is sufficient data if ((size + offset) > m_allocated_size) { @@ -112,6 +143,7 @@ Fw::SerializeStatus CircularBuffer :: peek(U8* buffer, NATIVE_UINT_TYPE size, NA } Fw::SerializeStatus CircularBuffer :: rotate(NATIVE_UINT_TYPE amount) { + FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called // Check there is sufficient data if (amount > m_allocated_size) { return Fw::FW_DESERIALIZE_BUFFER_EMPTY; @@ -122,9 +154,18 @@ Fw::SerializeStatus CircularBuffer :: rotate(NATIVE_UINT_TYPE amount) { } NATIVE_UINT_TYPE CircularBuffer ::get_capacity() const { + FW_ASSERT(m_store != nullptr && m_store_size != 0); // setup method was called return m_store_size; } +NATIVE_UINT_TYPE CircularBuffer ::get_high_water_mark() const { + return m_high_water_mark; +} + +void CircularBuffer ::clear_high_water_mark() { + m_high_water_mark = 0; +} + #ifdef CIRCULAR_DEBUG void CircularBuffer :: print() { NATIVE_UINT_TYPE idx = m_head_idx; diff --git a/Utils/Types/CircularBuffer.hpp b/Utils/Types/CircularBuffer.hpp index f62b7eca14..b885dc168c 100644 --- a/Utils/Types/CircularBuffer.hpp +++ b/Utils/Types/CircularBuffer.hpp @@ -18,7 +18,6 @@ #define TYPES_CIRCULAR_BUFFER_HPP #include -#include #include //#define CIRCULAR_DEBUG @@ -31,6 +30,15 @@ class CircularBuffer { * Circular buffer constructor. Wraps the supplied buffer as the new data store. Buffer * size is supplied in the 'size' argument. * + * Note: specification of storage buffer must be done using `setup` before use. + */ + CircularBuffer(); + + /** + * Circular buffer constructor. Wraps the supplied buffer as the new data store. Buffer + * size is supplied in the 'size' argument. This is equivalent to calling the no-argument constructor followed + * by setup(buffer, size). + * * Note: ownership of the supplied buffer is held until the circular buffer is deallocated * * \param buffer: supplied buffer used as a data store. @@ -38,6 +46,17 @@ class CircularBuffer { */ CircularBuffer(U8* const buffer, const NATIVE_UINT_TYPE size); + /** + * Wraps the supplied buffer as the new data store. Buffer size is supplied in the 'size' argument. Cannot be + * called after successful setup. + * + * Note: ownership of the supplied buffer is held until the circular buffer is deallocated + * + * \param buffer: supplied buffer used as a data store. + * \param size: the of the supplied data store. + */ + void setup(U8* const buffer, const NATIVE_UINT_TYPE size); + /** * Serialize a given buffer into this circular buffer. Will not accept more data than * space available. This means it will not overwrite existing data. @@ -105,6 +124,16 @@ class CircularBuffer { */ NATIVE_UINT_TYPE get_capacity() const; + /** + * Return the largest tracked allocated size + */ + NATIVE_UINT_TYPE get_high_water_mark() const; + + /** + * Clear tracking of the largest allocated size + */ + void clear_high_water_mark(); + #ifdef CIRCULAR_DEBUG void print(); #endif @@ -117,14 +146,16 @@ class CircularBuffer { */ NATIVE_UINT_TYPE advance_idx(NATIVE_UINT_TYPE idx, NATIVE_UINT_TYPE amount = 1) const; //! Physical store backing this circular buffer - U8* const m_store; + U8* m_store; //! Size of the physical store - const NATIVE_UINT_TYPE m_store_size; + NATIVE_UINT_TYPE m_store_size; //! Index into m_store of byte zero in the logical store. //! When memory is deallocated, this index moves forward and wraps around. NATIVE_UINT_TYPE m_head_idx; //! Allocated size (size of the logical store) NATIVE_UINT_TYPE m_allocated_size; + //! Maximum allocated size + NATIVE_UINT_TYPE m_high_water_mark; }; } //End Namespace Types #endif diff --git a/Utils/Types/Queue.cpp b/Utils/Types/Queue.cpp new file mode 100644 index 0000000000..ef41ee90bb --- /dev/null +++ b/Utils/Types/Queue.cpp @@ -0,0 +1,56 @@ +/* + * Queue.cpp: + * + * Implementation of the queue data type. + * + * Created on: July 5th, 2022 + * Author: lestarch + * + */ +#include "Queue.hpp" +#include + +namespace Types { + +Queue::Queue() : m_internal(), m_message_size(0) {} + +void Queue::setup(U8* const storage, const FwSizeType storage_size, const FwSizeType depth, const FwSizeType message_size) { + // Ensure that enough storage was supplied + const FwSizeType total_needed_size = depth * message_size; + FW_ASSERT(storage_size >= total_needed_size, storage_size, depth, message_size); + m_internal.setup(storage, total_needed_size); + m_message_size = message_size; +} + +Fw::SerializeStatus Queue::enqueue(const U8* const message, const FwSizeType size) { + FW_ASSERT(m_message_size > 0, m_message_size); // Ensure initialization + FW_ASSERT(m_message_size == size, size, m_message_size); // Message size is as expected + return m_internal.serialize(message, static_cast(m_message_size)); +} + +Fw::SerializeStatus Queue::dequeue(U8* const message, const FwSizeType size) { + FW_ASSERT(m_message_size > 0); // Ensure initialization + FW_ASSERT(m_message_size <= size, size, m_message_size); // Sufficient storage space for read message + Fw::SerializeStatus result = m_internal.peek(message, static_cast(m_message_size), 0); + if (result != Fw::FW_SERIALIZE_OK) { + return result; + } + return m_internal.rotate(m_message_size); +} + +NATIVE_UINT_TYPE Queue::get_high_water_mark() const { + FW_ASSERT(m_message_size > 0, m_message_size); + return m_internal.get_high_water_mark() / m_message_size; +} + +void Queue::clear_high_water_mark() { + m_internal.clear_high_water_mark(); +} + +NATIVE_UINT_TYPE Queue::getQueueSize() const { + FW_ASSERT(m_message_size > 0, m_message_size); + return m_internal.get_allocated_size()/m_message_size; +} + + +}; // namespace Types \ No newline at end of file diff --git a/Utils/Types/Queue.hpp b/Utils/Types/Queue.hpp new file mode 100644 index 0000000000..157233d8d7 --- /dev/null +++ b/Utils/Types/Queue.hpp @@ -0,0 +1,90 @@ +/* + * Queue.hpp: + * + * FIFO queue of fixed size messages. For use generally where non-concurrent, non-OS backed based FIFO queues are + * necessary. Message size is defined at construction time and all messages enqueued and dequeued must be of that fixed + * size. Wraps circular buffer to perform actual storage of messages. This implementation is not thread safe and the + * expectation is that the user will wrap it in concurrency constructs where necessary. + * + * Created on: July 5th, 2022 + * Author: lestarch + * + */ +#ifndef _UTILS_TYPES_QUEUE_HPP +#define _UTILS_TYPES_QUEUE_HPP +#include +#include +#include +#include + +namespace Types { + +class Queue { + public: + /** + * \brief constructs an uninitialized queue + */ + Queue(); + + /** + * \brief setup the queue object to setup storage + * + * The queue must be configured before use to setup storage parameters. This function supplies those parameters + * including depth, and message size. Storage size must be greater than or equal to the depth x message size. + * + * \param storage: storage memory allocation + * \param storage_size: size of the provided allocation + * \param depth: depth of the queue + * \param message_size: size of individual messages + */ + void setup(U8* const storage, const FwSizeType storage_size, const FwSizeType depth, const FwSizeType message_size); + + /** + * \brief pushes a fixed-size message onto the back of the queue + * + * Pushes a fixed-size message onto the queue. This performs a copy of the data onto the queue so the user is free + * to dispose the message data as soon as the call returns. Note: message is required to be of the size message_size + * as defined by the construction of the queue. Size is provided as a safety check to ensure the sent size is + * consistent with the expected size of the queue. + * + * This will return a non-Fw::SERIALIZE_OK status when the queue is full. + * + * \param message: message of size m_message_size to enqueue + * \param size: size of the message being sent. Must be equivalent to queue's message size. + * \return: Fw::SERIALIZE_OK on success, something else on failure + */ + Fw::SerializeStatus enqueue(const U8* const message, const FwSizeType size); + + /** + * \brief pops a fixed-size message off the front of the queue + * + * Pops a fixed-size message off the front of the queue. This performs a copy of the data into the provided message + * buffer. Note: message is required to be of the size message_size as defined by the construction of the queue. The + * size must be greater or equal to message size, although only message size bytes will be used. + * + * This will return a non-Fw::SERIALIZE_OK status when the queue is empty. + * + * \param message: message of size m_message_size to dequeue + * \param size: size of the buffer being supplied. + * \return: Fw::SERIALIZE_OK on success, something else on failure + */ + Fw::SerializeStatus dequeue(U8* const message, const FwSizeType size); + + /** + * Return the largest tracked allocated size + */ + NATIVE_UINT_TYPE get_high_water_mark() const; + + /** + * Clear tracking of the largest allocated size + */ + void clear_high_water_mark(); + + NATIVE_UINT_TYPE getQueueSize() const; + + private: + CircularBuffer m_internal; + FwSizeType m_message_size; +}; +} // namespace Types +#endif // _UTILS_TYPES_QUEUE_HPP diff --git a/Utils/Types/test/ut/CircularBuffer/CircularRules.hpp b/Utils/Types/test/ut/CircularBuffer/CircularRules.hpp index d24966098b..0d4484057b 100644 --- a/Utils/Types/test/ut/CircularBuffer/CircularRules.hpp +++ b/Utils/Types/test/ut/CircularBuffer/CircularRules.hpp @@ -19,7 +19,7 @@ #ifndef FPRIME_GROUNDINTERFACERULES_HPP #define FPRIME_GROUNDINTERFACERULES_HPP -#include +#include #include #include #include diff --git a/Utils/Types/test/ut/CircularBuffer/CircularState.hpp b/Utils/Types/test/ut/CircularBuffer/CircularState.hpp index b2c7b48723..535c29b569 100644 --- a/Utils/Types/test/ut/CircularBuffer/CircularState.hpp +++ b/Utils/Types/test/ut/CircularBuffer/CircularState.hpp @@ -7,7 +7,7 @@ * @author mstarch */ -#include +#include #include #ifndef FPRIME_CIRCULARSTATE_HPP diff --git a/Utils/test/ut/LockGuardTester.hpp b/Utils/test/ut/LockGuardTester.hpp index 009b236352..3d647897b7 100644 --- a/Utils/test/ut/LockGuardTester.hpp +++ b/Utils/test/ut/LockGuardTester.hpp @@ -15,7 +15,7 @@ #define LOCKGUARDTESTER_HPP #include "Utils/LockGuard.hpp" -#include +#include #include "gtest/gtest.h" namespace Utils { diff --git a/Utils/test/ut/RateLimiterTester.hpp b/Utils/test/ut/RateLimiterTester.hpp index c686cbefcb..90fef081ef 100644 --- a/Utils/test/ut/RateLimiterTester.hpp +++ b/Utils/test/ut/RateLimiterTester.hpp @@ -15,7 +15,7 @@ #define RATELIMITERTESTER_HPP #include "Utils/RateLimiter.hpp" -#include +#include #include "gtest/gtest.h" namespace Utils { diff --git a/Utils/test/ut/TokenBucketTester.hpp b/Utils/test/ut/TokenBucketTester.hpp index a8dfaffacb..9b6d162083 100644 --- a/Utils/test/ut/TokenBucketTester.hpp +++ b/Utils/test/ut/TokenBucketTester.hpp @@ -15,7 +15,7 @@ #define TOKENBUCKETTESTER_HPP #include "Utils/TokenBucket.hpp" -#include +#include #include "gtest/gtest.h" namespace Utils { diff --git a/ci/config.xml b/ci/config.xml index 310dcd03ca..42e50fee27 100644 --- a/ci/config.xml +++ b/ci/config.xml @@ -104,7 +104,7 @@ swcaegitadmin export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" . /opt/fprime-venv/bin/activate echo "Merging: origin/${ghprbTargetBranch} into ${ghprbActualCommit}}" -git merge origin/${ghprbTargetBranch} +GIT_EDITOR=true git merge origin/${ghprbTargetBranch} if (( $? != 0 )) then echo "[ERROR] Automatic merge failed." 1>&2 diff --git a/ci/tests/RPI.bash b/ci/tests/RPI.bash index e52387532d..95d73c2f9f 100755 --- a/ci/tests/RPI.bash +++ b/ci/tests/RPI.bash @@ -1,4 +1,5 @@ -#!/bin/bash +#!/bin/bash +set -x #### # RPI.bash: # @@ -21,26 +22,31 @@ export FPUTIL_DEPLOYS="${FPRIME_DIR}/RPI" echo -e "${BLUE}Starting CI test ${FPUTIL_DEPLOYS} RPI${NOCOLOR}" export CMAKE_EXTRA_SETTINGS="" -if [ ! -d "/opt/rpi/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf" ] +if [ ! -d "/usr/arm-linux-gnueabihf" ] then warn_and_cont "RPI tools not installed, refusing to test." continue fi -# For RPI deployment to disable FRAMEWORK UTS -export CMAKE_EXTRA_SETTINGS="${CMAKE_EXTRA_SETTINGS} -DFPRIME_ENABLE_FRAMEWORK_UTS=OFF" echo -e "${BLUE}Testing ${FPUTIL_DEPLOYS} against fprime-util targets: ${FPUTIL_TARGETS[@]}${NOCOLOR}" export CHECK_TARGET_PLATFORM="native" for target in "${FPUTIL_TARGETS[@]}" do + # For RPI deployment to disable FRAMEWORK UTS + export CMAKE_EXTRA_SETTINGS="-DFPRIME_ENABLE_FRAMEWORK_UTS=OFF" if [[ "${target}" == "generate" ]] then rm -rf "${FPUTIL_DEPLOYS}/build-fprime-automatic-"* fi + # When a sysroot is supplied on the base generate target (cross-compiler) add the SYSROOT to the run + if [[ "${target}" == "generate" ]] && [[ "$1" != "" ]] + then + export CMAKE_EXTRA_SETTINGS="${CMAKE_EXTRA_SETTINGS} -DCMAKE_SYSROOT=${1}" + fi fputil_action "${FPUTIL_DEPLOYS}" "${target}" done # Test Completed echo -e "${GREEN}CI test ${FPUTIL_DEPLOYS} RPI SUCCESSFUL${NOCOLOR}" -archive_logs \ No newline at end of file +archive_logs diff --git a/ci/tests/fputil.bash b/ci/tests/fputil.bash index 124a970472..58afee3a4c 100755 --- a/ci/tests/fputil.bash +++ b/ci/tests/fputil.bash @@ -96,13 +96,17 @@ function integration_test_run { # Run integration tests ( cd "${WORKDIR}/test" + if [[ "${DICTIONARY_PATH}" != "" ]] + then + DICTIONARY_ARGS="--dictionary ${WORKDIR}/${DICTIONARY_PATH}" + fi echo "[INFO] Running ${WORKDIR}/test's pytest integration tests" TIMEOUT="timeout" if ! command -v ${TIMEOUT} &> /dev/null then TIMEOUT="gtimeout" # macOS homebrew "coreutils" fi - ${TIMEOUT} --kill-after=10s 180s pytest + ${TIMEOUT} --kill-after=10s 180s pytest ${DICTIONARY_ARGS} ) RET_PYTEST=$? pkill -P $GDS_PID diff --git a/cmake/API.cmake b/cmake/API.cmake index 306cfce019..9bf7a33d25 100644 --- a/cmake/API.cmake +++ b/cmake/API.cmake @@ -13,6 +13,29 @@ #### set(FPRIME_TARGET_LIST "" CACHE INTERNAL "FPRIME_TARGET_LIST: custom fprime targets" FORCE) set(FPRIME_UT_TARGET_LIST "" CACHE INTERNAL "FPRIME_UT_TARGET_LIST: custom fprime targets" FORCE) +set(FPRIME_AUTOCODER_TARGET_LIST "" CACHE INTERNAL "FPRIME_AUTOCODER_TARGET_LIST: custom fprime targets" FORCE) + +#### +# Macro `restrict_platforms`: +# +# Restricts a CMakeLists.txt file to a given list of platforms. This prevents usage on platforms for which the module +# is incapable of being used and replaces the historical pattern of an if-tree detecting unsupported platforms. +# +# Usage: +# restrict_platforms(Linux Darwin) # Restricts to Linux and Darwin platforms +# +# Args: +# ARGN: list of platforms that are supported +##### +macro(restrict_platforms) + set(__CHECKER ${ARGN}) + if (NOT CMAKE_SYSTEM_NAME IN_LIST __CHECKER) + get_module_name("${CMAKE_CURRENT_LIST_DIR}") + message(STATUS "Platform ${CMAKE_SYSTEM_NAME} not supported for module ${MODULE_NAME}") + return() + endif() +endmacro() + #### # Function `add_fprime_subdirectory`: # @@ -325,7 +348,7 @@ endfunction(register_fprime_deployment) # unit test name, autocoding and source inputs for the unit test, and (optionally) any # non-standard link dependencies. # -# **Note:** This is ONLY run when the build type is TESTING. Unit testing is restricted to this build type as fprime +# **Note:** This is ONLY run when the BUILD_TESTING is enabled. Unit testing is restricted to this build type as fprime # sets additional flags when building for unit tests. # # Required variables (defined in calling scope): @@ -360,6 +383,11 @@ endfunction(register_fprime_deployment) # ``` # **Note:** this is typically called after any other register calls in the module. # +# - **UT_AUTO_HELPERS:** (optional) When set ON, a test helper file will be generated that auto-codes the connect ports +# and init components methods. This removes the maintenance overhead for these functions. ON additionally adds test +# source directories to the include path for the unit test target. When set to OFF, this helper file will be created +# when generating implementation templates allowing users to modify these files. Default: OFF +# # ### Unit-Test Example ### # # A standard unit test defines only UT_SOURCES. These sources have the test cpp files and the module @@ -423,7 +451,8 @@ endfunction(register_fprime_ut) macro(register_fprime_target TARGET_FILE_PATH) # Normal registered targets don't run in prescan if (NOT DEFINED FPRIME_PRESCAN) - register_fprime_target_helper("${TARGET_FILE_PATH}" FPRIME_TARGET_LIST) + register_fprime_list_helper("${TARGET_FILE_PATH}" FPRIME_TARGET_LIST) + setup_global_target("${TARGET_FILE_PATH}") endif() endmacro(register_fprime_target) @@ -438,34 +467,52 @@ endmacro(register_fprime_target) macro(register_fprime_ut_target TARGET_FILE_PATH) # UT targets only allowed when testing if (BUILD_TESTING AND NOT DEFINED FPRIME_PRESCAN) - register_fprime_target_helper("${TARGET_FILE_PATH}" FPRIME_UT_TARGET_LIST) + register_fprime_list_helper("${TARGET_FILE_PATH}" FPRIME_UT_TARGET_LIST) + setup_global_target("${TARGET_FILE_PATH}") endif() endmacro(register_fprime_ut_target) #### -# Macro `register_fprime_target_helper`: +# Macro `register_fprime_list_helper`: # # Helper function to do the actual registration. Also used to side-load prescan to bypass the not-on-prescan check. #### -macro(register_fprime_target_helper TARGET_FILE_PATH TARGET_LIST) +macro(register_fprime_list_helper TARGET_FILE_PATH TARGET_LIST) include("${TARGET_FILE_PATH}") # Prevent out-of-order setups get_property(MODULE_DETECTION_STARTED GLOBAL PROPERTY MODULE_DETECTION SET) if (MODULE_DETECTION_STARTED) message(FATAL_ERROR "Cannot register fprime target after including subdirectories or FPrime-Code.cmake'") endif() - # Get the target list to add this target to or use default - set(LIST_NAME FPRIME_TARGET_LIST) - if (${ARGC} GREATER 1) - set(LIST_NAME "${ARGV1}") - endif() get_property(TARGETS GLOBAL PROPERTY "${TARGET_LIST}") if (NOT TARGET_FILE_PATH IN_LIST TARGETS) - set_property(GLOBAL APPEND PROPERTY "${LIST_NAME}" "${TARGET_FILE_PATH}") - setup_global_target("${TARGET_FILE_PATH}") + set_property(GLOBAL APPEND PROPERTY "${TARGET_LIST}" "${TARGET_FILE_PATH}") endif() -endmacro(register_fprime_target_helper) +endmacro(register_fprime_list_helper) + +#### +# Macro `register_fprime_build_autocoder`: +# +# This function allows users to register custom autocoders into the build system. These autocoders will execute during +# the build process. An autocoder is defined in a CMake file and must do three things: +# 1. Call one of `autocoder_setup_for_individual_sources()` or `autocoder_setup_for_multiple_sources()` from file scope +# 2. Implement `_is_supported(AC_POSSIBLE_INPUT_FILE)` returning true the autocoder processes given source +# 3. Implement `_setup_autocode AC_INPUT_FILE)` to run the autocoder on files filter by item 2. +# See: [Autocoders](dev/autocoder_integration.md). +# +# This function takes in either a file path to a CMake file defining an autocoder target, or an short include path that accomplishes +# the same thing. Note: make sure the directory is on the CMake include path to use the second form. +# +# **TARGET_FILE_PATH:** include path or file path file defining above functions +### +macro(register_fprime_build_autocoder TARGET_FILE_PATH) + # Normal registered targets don't run in prescan + message(STATUS "Registering custom autocoder: ${TARGET_FILE_PATH}") + if (NOT DEFINED FPRIME_PRESCAN) + register_fprime_list_helper("${TARGET_FILE_PATH}" FPRIME_AUTOCODER_TARGET_LIST) + endif() +endmacro(register_fprime_build_autocoder) #### Documentation links # Next Topics: diff --git a/cmake/FPrime-Code.cmake b/cmake/FPrime-Code.cmake index b2f4ee2f82..39dee7a408 100644 --- a/cmake/FPrime-Code.cmake +++ b/cmake/FPrime-Code.cmake @@ -25,8 +25,8 @@ if (FPRIME_ENABLE_FRAMEWORK_UTS) set(__FPRIME_NO_UT_GEN__ OFF) endif() # Faux libraries used as interfaces to non-autocoded fpp items -add_library(config INTERFACE) add_library(Fpp INTERFACE) +add_subdirectory("${FPRIME_CONFIG_DIR}" "${CMAKE_BINARY_DIR}/config") add_subdirectory("${FPRIME_FRAMEWORK_PATH}/Fw/" "${CMAKE_BINARY_DIR}/F-Prime/Fw") add_subdirectory("${FPRIME_FRAMEWORK_PATH}/Svc/" "${CMAKE_BINARY_DIR}/F-Prime/Svc") add_subdirectory("${FPRIME_FRAMEWORK_PATH}/Os/" "${CMAKE_BINARY_DIR}/F-Prime/Os") diff --git a/cmake/FPrime.cmake b/cmake/FPrime.cmake index e859782589..f30dd16a38 100644 --- a/cmake/FPrime.cmake +++ b/cmake/FPrime.cmake @@ -22,6 +22,7 @@ message(STATUS "Searching for F prime modules in: ${FPRIME_BUILD_LOCATIONS}") message(STATUS "Autocoder constants file: ${FPRIME_AC_CONSTANTS_FILE}") message(STATUS "Configuration header directory: ${FPRIME_CONFIG_DIR}") +include(sanitizers) # Enable sanitizers if they are requested include(required) include(prescan) #Must come after required if tools detection is to be inherited include(platform/platform) @@ -33,12 +34,6 @@ include(autocoder/autocoder) include(target/target) include(API) -# Set the install directory for the package -if (DEFINED FPRIME_INSTALL_DEST) - set(CMAKE_INSTALL_PREFIX ${FPRIME_INSTALL_DEST} CACHE PATH "Install dir" FORCE) -elseif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT OR CMAKE_INSTALL_PREFIX STREQUAL "") - set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}/build-artifacts CACHE PATH "Install dir" FORCE) -endif() message(STATUS "Installation directory: ${CMAKE_INSTALL_PREFIX}") # Setup the global include directories @@ -61,9 +56,10 @@ endforeach() include_directories("${FPRIME_FRAMEWORK_PATH}") include_directories("${FPRIME_CONFIG_DIR}") -# To prescan, either we register the prescan target or we run the prescan CMake +# To prescan,register target process around safety check if (DEFINED FPRIME_PRESCAN) - register_fprime_target_helper(target/prescan FPRIME_TARGET_LIST) + register_fprime_list_helper(target/prescan FPRIME_TARGET_LIST) + setup_global_target(target/prescan) else() perform_prescan() endif() @@ -71,9 +67,12 @@ endif() # FPP locations must come at the front of the list, then build register_fprime_target(target/fpp_locs) register_fprime_target(target/build) +register_fprime_build_autocoder(autocoder/fpp) +register_fprime_build_autocoder(autocoder/ai_xml) +register_fprime_build_autocoder(autocoder/deployment_validation) +register_fprime_build_autocoder(autocoder/packets) register_fprime_target(target/noop) register_fprime_target(target/version) -register_fprime_target(target/dict) register_fprime_target(target/install) register_fprime_ut_target(target/ut) diff --git a/cmake/autocoder/ai_ut.cmake b/cmake/autocoder/ai_ut.cmake index 9765432698..98d8f2d651 100644 --- a/cmake/autocoder/ai_ut.cmake +++ b/cmake/autocoder/ai_ut.cmake @@ -31,13 +31,24 @@ endfunction (ai_ut_is_supported) # Required function, sets up a custom command to produce TesterBase and GTestBase files. #### function(ai_ut_setup_autocode AC_INPUT_FILE) - set(REMOVAL_LIST "${CMAKE_CURRENT_BINARY_DIR}/Tester.hpp ${CMAKE_CURRENT_BINARY_DIR}/Tester.cpp ${CMAKE_CURRENT_BINARY_DIR}/TestMain.cpp") - set(AUTOCODER_GENERATED "${CMAKE_CURRENT_BINARY_DIR}/TesterBase.cpp" "${CMAKE_CURRENT_BINARY_DIR}/TesterBase.hpp") + set(REMOVALS "${CMAKE_CURRENT_BINARY_DIR}/Tester.hpp" + "${CMAKE_CURRENT_BINARY_DIR}/Tester.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/TestMain.cpp") + set(AUTOCODER_GENERATED + "${CMAKE_CURRENT_BINARY_DIR}/TesterBase.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/TesterBase.hpp") + # GTest flag handling if (INCLUDE_GTEST) list(APPEND AUTOCODER_GENERATED "${CMAKE_CURRENT_BINARY_DIR}/GTestBase.cpp" "${CMAKE_CURRENT_BINARY_DIR}/GTestBase.hpp") else() - set(REMOVAL_LIST "${REMOVAL_LIST} ${CMAKE_CURRENT_BINARY_DIR}/GTestBase.cpp ${CMAKE_CURRENT_BINARY_DIR}/GTestBase.hpp") + list(APPEND REMOVALS "${CMAKE_CURRENT_BINARY_DIR}/GTestBase.cpp" "${CMAKE_CURRENT_BINARY_DIR}/GTestBase.hpp") + endif() + # Extra test helpers file + if (DEFINED UT_AUTO_HELPERS AND UT_AUTO_HELPERS) + list(APPEND AUTOCODER_GENERATED "${CMAKE_CURRENT_BINARY_DIR}/TesterHelpers.cpp") + else() + list(APPEND REMOVALS "${CMAKE_CURRENT_BINARY_DIR}/TesterHelpers.cpp") endif() # Get the shared setup for all AI autocoders @@ -46,7 +57,7 @@ function(ai_ut_setup_autocode AC_INPUT_FILE) add_custom_command( OUTPUT ${AUTOCODER_GENERATED} COMMAND ${AI_BASE_SCRIPT} -u "${AC_INPUT_FILE}" - COMMAND ${CMAKE_COMMAND} -E remove ${REMOVAL_LIST} + COMMAND ${CMAKE_COMMAND} -E remove ${REMOVALS} DEPENDS "${AC_INPUT_FILE}" "${CODEGEN_TARGET}" ) set(AUTOCODER_GENERATED "${AUTOCODER_GENERATED}" PARENT_SCOPE) diff --git a/cmake/autocoder/ai_ut_impl.cmake b/cmake/autocoder/ai_ut_impl.cmake index a058f03803..af06d1d73f 100644 --- a/cmake/autocoder/ai_ut_impl.cmake +++ b/cmake/autocoder/ai_ut_impl.cmake @@ -36,17 +36,25 @@ function(ai_ut_impl_setup_autocode AC_INPUT_FILE) ${CMAKE_CURRENT_SOURCE_DIR}/Tester.hpp ${CMAKE_CURRENT_SOURCE_DIR}/TestMain.cpp ) + set(REMOVALS + "${CMAKE_CURRENT_SOURCE_DIR}/TesterBase.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/TesterBase.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/GTestBase.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/GTestBase.cpp") + # Extra test helpers file + if (NOT DEFINED UT_AUTO_HELPERS OR NOT UT_AUTO_HELPERS) + list(APPEND AUTOCODER_GENERATED "${CMAKE_CURRENT_SOURCE_DIR}/TesterHelpers.cpp") + else() + list(APPEND REMOVALS "${CMAKE_CURRENT_SOURCE_DIR}/TesterHelpers.cpp") + endif() + # Get the shared setup for all AI autocoders ai_shared_setup("${CMAKE_CURRENT_SOURCE_DIR}") # Specifically setup the `add_custom_command` call as the requires extra commands to run add_custom_command( OUTPUT ${AUTOCODER_GENERATED} COMMAND ${AI_BASE_SCRIPT} -u "${AC_INPUT_FILE}" - COMMAND ${CMAKE_COMMAND} -E remove - ${CMAKE_CURRENT_SOURCE_DIR}/TesterBase.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/TesterBase.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/GTestBase.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/GTestBase.cpp + COMMAND ${CMAKE_COMMAND} -E remove ${REMOVALS} DEPENDS "${AC_INPUT_FILE}" "${CODEGEN_TARGET}" ) set(AUTOCODER_GENERATED "${AUTOCODER_GENERATED}" PARENT_SCOPE) diff --git a/cmake/autocoder/ai_xml.cmake b/cmake/autocoder/ai_xml.cmake index 007ddf344b..7a8013ccdf 100644 --- a/cmake/autocoder/ai_xml.cmake +++ b/cmake/autocoder/ai_xml.cmake @@ -15,9 +15,30 @@ autocoder_setup_for_individual_sources() # # Required function, processes ComponentAi.xml files. # `AC_INPUT_FILE` potential input to the autocoder +# ...: any number of arguments representing a list of previously generated files #### function(ai_xml_is_supported AC_INPUT_FILE) - autocoder_support_by_suffix("Ai.xml" "${AC_INPUT_FILE}") + ends_with(IS_SUPPORTED "${AC_INPUT_FILE}" "Ai.xml") + set(PREVIOUSLY_GENERATED) + if (ARGC GREATER_EQUAL 2) + set(PREVIOUSLY_GENERATED ${ARGV2}) + endif() + + # Don't generate cpp/hpp files that have already been generated + if (IS_SUPPORTED) + string(REPLACE "Ai.xml" "Ac.cpp" CPP_FILE "${AC_INPUT_FILE}") + string(REPLACE "Ai.xml" "Ac.hpp" HPP_FILE "${AC_INPUT_FILE}") + if(("${CPP_FILE}" IN_LIST PREVIOUSLY_GENERATED) AND ("${HPP_FILE}" IN_LIST PREVIOUSLY_GENERATED)) + set(IS_SUPPORTED FALSE) + endif() + + # If this Ai.xml file was not a generated product, then mark it as requiring a rebuild + if (NOT "${AC_INPUT_FILE}" IN_LIST PREVIOUSLY_GENERATED) + requires_regeneration("${AC_INPUT_FILE}") + endif() + endif() + # Note: set in PARENT_SCOPE in macro is intended. Caller **wants** to set IS_SUPPORTED in their parent's scope. + set(IS_SUPPORTED "${IS_SUPPORTED}" PARENT_SCOPE) endfunction (ai_xml_is_supported) #### @@ -44,7 +65,6 @@ macro(__ai_info XML_PATH MODULE_NAME) # Run the parser and capture the output. If an error occurs, that fatals CMake as we cannot continue set(MODULE_NAME_NO_SUFFIX "${MODULE_NAME}") set(PARSER_PATH "${FPRIME_FRAMEWORK_PATH}/cmake/autocoder/ai-parser/ai_parser.py") - set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${PARSER_PATH}") execute_process( COMMAND "${PYTHON}" "${PARSER_PATH}" "${XML_PATH}" "${MODULE_NAME_NO_SUFFIX}" "${FPRIME_CLOSEST_BUILD_ROOT}" RESULT_VARIABLE ERR_RETURN @@ -74,6 +94,8 @@ function(ai_xml_setup_autocode AC_INPUT_FILE) # Check type and respond if(XML_LOWER_TYPE STREQUAL "topologyapp") # Are we excluding the generated files or not + set_property(GLOBAL PROPERTY "${PROJECT_NAME}_FPRIME_DICTIONARY_FILE" + "${CMAKE_CURRENT_BINARY_DIR}/${OBJ_NAME}${XML_TYPE}Dictionary.xml") if (EXCLUDE_TOP_ACS) set(REMOVALS "${GENERATED_FILES}") set(GENERATED_FILES "${CMAKE_CURRENT_BINARY_DIR}/${OBJ_NAME}${XML_TYPE}Dictionary.xml") diff --git a/cmake/autocoder/autocoder.cmake b/cmake/autocoder/autocoder.cmake index 317d860f7f..c54bf4bac9 100644 --- a/cmake/autocoder/autocoder.cmake +++ b/cmake/autocoder/autocoder.cmake @@ -55,7 +55,7 @@ function(run_ac AUTOCODER_CMAKE SOURCES GENERATED_SOURCES) plugin_include_helper(AUTOCODER_NAME "${AUTOCODER_CMAKE}" is_supported setup_autocode get_generated_files get_dependencies) # Normalize and filter source paths so that what we intend to run is in a standard form normalize_paths(AC_INPUT_SOURCES "${SOURCES}" "${GENERATED_SOURCES}") - _filter_sources(AC_INPUT_SOURCES "${AC_INPUT_SOURCES}") + _filter_sources(AC_INPUT_SOURCES "${GENERATED_SOURCES}" "${AC_INPUT_SOURCES}") # Break early if there are no sources, no need to autocode nothing if (NOT AC_INPUT_SOURCES) @@ -98,19 +98,13 @@ function(run_ac AUTOCODER_CMAKE SOURCES GENERATED_SOURCES) set(GENERATED_FILES "${GENERATED_FILES_LIST}") else() __ac_process_sources("${AC_INPUT_SOURCES}") - if (GENERATED_FILES) - set(CONSUMED_SOURCES "${AC_INPUT_SOURCES}") - endif() + set(CONSUMED_SOURCES "${AC_INPUT_SOURCES}") endif() set_property(DIRECTORY PROPERTY "${SRCS_HASH}_DEPENDENCIES" "${MODULE_DEPENDENCIES}") set_property(DIRECTORY PROPERTY "${SRCS_HASH}_GENERATED" "${GENERATED_FILES}") set_property(DIRECTORY PROPERTY "${SRCS_HASH}_CONSUMED" "${CONSUMED_SOURCES}") set_property(DIRECTORY PROPERTY "${SRCS_HASH}_FILE_DEPENDENCIES" "${FILE_DEPENDENCIES}") _describe_autocoder_run("${AUTOCODER_NAME}") - # Configure depends on this source file if it causes a change to module dependencies - if (MODULE_DEPENDENCIES) - set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CONSUMED_SOURCES}) - endif() endif() get_property(DEPS DIRECTORY PROPERTY "${SRCS_HASH}_DEPENDENCIES") get_property(GENS DIRECTORY PROPERTY "${SRCS_HASH}_GENERATED") @@ -184,14 +178,15 @@ endfunction() # including an autocoder's CMake file and thus setting the active autocoder. Helper function. # # OUTPUT_NAME: name of output variable to set in parent scope +# GENERATED_SOURCES: sources created by other autocoders # ...: any number of arguments containing lists of sources #### -function(_filter_sources OUTPUT_NAME) +function(_filter_sources OUTPUT_NAME GENERATED_SOURCES) set(OUTPUT_LIST) # Loop over the list and check foreach (SOURCE_LIST IN LISTS ARGN) foreach(SOURCE IN LISTS SOURCE_LIST) - cmake_language(CALL "${AUTOCODER_NAME}_is_supported" "${SOURCE}") + cmake_language(CALL "${AUTOCODER_NAME}_is_supported" "${SOURCE}" "${GENERATED_SOURCES}") if (IS_SUPPORTED) list(APPEND OUTPUT_LIST "${SOURCE}") endif() @@ -230,8 +225,8 @@ function(__ac_process_sources SOURCES) add_custom_command(OUTPUT ${AUTOCODER_GENERATED} COMMAND ${AUTOCODER_SCRIPT} ${AUTOCODER_INPUTS} DEPENDS ${AUTOCODER_INPUTS} ${AUTOCODER_DEPENDENCIES}) endif() - set(MODULE_DEPENDENCIES ${AUTOCODER_DEPENDENCIES} PARENT_SCOPE) - set(GENERATED_FILES ${AUTOCODER_GENERATED} PARENT_SCOPE) - set(FILE_DEPENDENCIES ${AUTOCODER_INPUTS} PARENT_SCOPE) + set(MODULE_DEPENDENCIES "${AUTOCODER_DEPENDENCIES}" PARENT_SCOPE) + set(GENERATED_FILES "${AUTOCODER_GENERATED}" PARENT_SCOPE) + set(FILE_DEPENDENCIES "${AUTOCODER_INPUTS}" PARENT_SCOPE) endfunction() diff --git a/cmake/autocoder/deployment_validation.cmake b/cmake/autocoder/deployment_validation.cmake new file mode 100644 index 0000000000..47c20ebbc8 --- /dev/null +++ b/cmake/autocoder/deployment_validation.cmake @@ -0,0 +1,47 @@ +#### +# autocoder/deployment_validation.cmake +# +# An autocoder that performs validation steps on the deployment to ensure that it is well-formed. This will produce +# warning output when validation fails. +# +# Note: this autocoder is for validation purposes and DOES NOT produce any autocoded files. +##### +include(utilities) +include(autocoder/helpers) + +autocoder_setup_for_multiple_sources() + +#### +# `deployment_validation_is_supported`: +# +# Required function, processes .fpp files +#### +function(deployment_validation_is_supported AC_INPUT_FILE) + autocoder_support_by_suffix(".fpp" "${AC_INPUT_FILE}") # No re-scan, already done in FPP +endfunction (deployment_validation_is_supported) + +#### +# `deployment_validation_is_supported`: +# +# Required function, look for .fpp files defining a topology block and ensure the following equivalence: +# ${PROJECT_NAME} == topology name +# No files are produced by this autocoder. It runs to validate items as part of the autocoder system. +# +#### +function(deployment_validation_setup_autocode AC_INPUT_FILES) + foreach(AC_FILE IN LISTS AC_INPUT_FILES) + file(READ "${AC_FILE}" FILE_TEXT) + # Does this file match the pattern (module { topology {} }) + if (NOT FPRIME_SKIP_PROJECT_NAME_VALIDATION AND + FILE_TEXT MATCHES "^(.*\n)?[^\n#@]*topology +([a-zA-Z0-9_]+)" AND + NOT CMAKE_MATCH_2 STREQUAL "${PROJECT_NAME}") + message(WARNING + "Cmake project name '${PROJECT_NAME}' does not match topology name '${CMAKE_MATCH_2}'\n" + " Project CMakeLists.txt: ${PROJECT_SOURCE_DIR}/CMakeLists.txt\n" + " Topology FPP model: ${AC_FILE}\n" + ) + endif() + endforeach() + # This autocoder specifically does not produce any autocoder output + set(AUTOCODER_GENERATED "" PARENT_SCOPE) +endfunction(deployment_validation_setup_autocode) diff --git a/cmake/autocoder/fpp-wrapper/fpp-depend-parallelize.py b/cmake/autocoder/fpp-wrapper/fpp-depend-parallelize.py index cc75b9e40d..2bb45a71ce 100755 --- a/cmake/autocoder/fpp-wrapper/fpp-depend-parallelize.py +++ b/cmake/autocoder/fpp-wrapper/fpp-depend-parallelize.py @@ -5,6 +5,14 @@ from pathlib import Path +class ExceptionWithStandardError(Exception): + """Exception plus standard error""" + + def __init__(self, message, stderr): + message = f"{message}\n{stderr}" + super().__init__(message) + + def run_process(directory, arguments): """Runs the fpp-depend process""" working_dir = directory / "fpp-cache" @@ -16,6 +24,7 @@ def run_process(directory, arguments): stdin=subprocess.DEVNULL, stdout=capture_file, stderr=subprocess.PIPE, + text=True, ) @@ -23,7 +32,9 @@ def raise_on_error(process, arguments): """Waits for process, raises on error""" code = process.wait() if code != 0: - raise Exception(f"Failed to run '{' '.join(arguments)}'") + raise ExceptionWithStandardError( + f"Failed to run '{' '.join(arguments)}'", process.stderr.read() + ) def run_parallel_depend(fpp_depend, fpp_locs, file_input): diff --git a/cmake/autocoder/fpp.cmake b/cmake/autocoder/fpp.cmake index 81630b2195..41bee22156 100644 --- a/cmake/autocoder/fpp.cmake +++ b/cmake/autocoder/fpp.cmake @@ -54,7 +54,7 @@ endfunction(locate_fpp_tools) # `AC_INPUT_FILE` potential input to the autocoder #### function(fpp_is_supported AC_INPUT_FILE) - autocoder_support_by_suffix(".fpp" "${AC_INPUT_FILE}") + autocoder_support_by_suffix(".fpp" "${AC_INPUT_FILE}" TRUE) endfunction(fpp_is_supported) #### @@ -69,8 +69,12 @@ endfunction(fpp_is_supported) #### function(fpp_get_framework_dependency_helper MODULE_NAME FRAMEWORK) # Subset the framework dependencies, or where possible use the Fw interface target - if (NOT DEFINED FPRIME_FRAMEWORK_MODULES) + if (MODULE_NAME STREQUAL "config") + # config has no automatic dependencies + elseif (NOT DEFINED FPRIME_FRAMEWORK_MODULES) message(FATAL_ERROR "Fw/CMakeLists.txt not included in deployment") + elseif (MODULE_NAME STREQUAL Fw_Cfg) + # Skip Fw_Cfg as it is the root dependency elseif (NOT TARGET Fw OR MODULE_NAME IN_LIST FPRIME_FRAMEWORK_MODULES) list(APPEND FRAMEWORK ${FPRIME_FRAMEWORK_MODULES}) list(FIND FRAMEWORK "${MODULE_NAME}" START_INDEX) @@ -91,7 +95,7 @@ endfunction(fpp_get_framework_dependency_helper) # - GENERATED_FILES: a list of files generated for the given input sources # - MODULE_DEPENDENCIES: inter-module dependencies determined from the given input sources # - FILE_DEPENDENCIES: specific file dependencies of the given input sources -# - EXTRAS: used to publish the 'imported' file dependencies of the given input files +# - FPP_IMPORTS: The fpp model dependencies, which end up being the input to the -i flag for the fpp-to-cpp and fpp-to-xml tools # # Note: although this function is only required to set `GENERATED_FILES`, the remaining information is also set as # setting this information now will prevent a duplicated call to the tooling. @@ -137,21 +141,26 @@ function(fpp_info AC_INPUT_FILES) message(FATAL_ERROR) endif() - # Module dependencies are: detected "direct" + framework dependencies - fpp_to_modules("${DIRECT_DEPENDENCIES}" "${AC_INPUT_FILES}" MODULE_DEPENDENCIES) + # Module dependencies are: detected "direct" + framework dependencies - "included" files + set(FILTERED_DIRECT_DEPENDENCIES) + foreach(ITEM IN LISTS DIRECT_DEPENDENCIES) + if (NOT ITEM IN_LIST INCLUDED) + list(APPEND FILTERED_DIRECT_DEPENDENCIES "${ITEM}") + endif() + endforeach() + fpp_to_modules("${FILTERED_DIRECT_DEPENDENCIES}" MODULE_DEPENDENCIES) list(APPEND MODULE_DEPENDENCIES ${FRAMEWORK}) list(REMOVE_DUPLICATES MODULE_DEPENDENCIES) # File dependencies are any files that this depends on - set(FILE_DEPENDENCIES ${AC_INPUT_FILES} ${STDOUT}) + set(FILE_DEPENDENCIES ${AC_INPUT_FILES} ${INCLUDED}) # Should have been inherited from previous call to `get_generated_files` set(GENERATED_FILES "${GENERATED_FILES}" PARENT_SCOPE) set(MODULE_DEPENDENCIES "${MODULE_DEPENDENCIES}" PARENT_SCOPE) set(FILE_DEPENDENCIES "${FILE_DEPENDENCIES}" PARENT_SCOPE) - set(IMPORTED "${IMPORTED}" PARENT_SCOPE) + set(FPP_IMPORTS "${STDOUT}" PARENT_SCOPE) endfunction(fpp_info) - #### # Function `fpp_setup_autocode`: # @@ -165,12 +174,11 @@ function(fpp_setup_autocode AC_INPUT_FILES) message(FATAL_ERROR "fpp tools not found, please install them onto your system path") endif() fpp_info("${AC_INPUT_FILES}") - - string(REGEX REPLACE ";" "," FPRIME_BUILD_LOCATIONS_SEP_FPP "${FPRIME_BUILD_LOCATIONS}") - string(REGEX REPLACE ";" "," FPP_IMPORTED_SEP "${IMPORTED}") - set(INCLUDES) - if (FPP_IMPORTED_SEP) - set(INCLUDES "-i" "${FPP_IMPORTED_SEP}") + string(REGEX REPLACE ";" "," FPRIME_BUILD_LOCATIONS_COMMA_SEP "${FPRIME_BUILD_LOCATIONS}") + string(REGEX REPLACE ";" "," FPP_IMPORTS_COMMA_SEP "${FPP_IMPORTS}") + set(IMPORTS) + if (FPP_IMPORTS_COMMA_SEP) + set(IMPORTS "-i" "${FPP_IMPORTS_COMMA_SEP}") endif() # Separate the source files into the CPP and XML steps set(GENERATED_AI) @@ -182,26 +190,27 @@ function(fpp_setup_autocode AC_INPUT_FILES) list(APPEND GENERATED_CPP "${GENERATED}") endif() endforeach() - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/fpp-input-list" "${FILE_DEPENDENCIES}") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/fpp-input-list" "${FPP_IMPORTS};${AC_INPUT_FILES}") # Add in steps for Ai.xml generation if (GENERATED_AI) add_custom_command( OUTPUT ${GENERATED_AI} - COMMAND ${FPP_TO_XML} "-d" "${CMAKE_CURRENT_BINARY_DIR}" ${FILE_DEPENDENCIES} - "-p" "${FPRIME_BUILD_LOCATIONS_SEP_FPP}" - DEPENDS ${IMPORTED} ${FILE_DEPENDENCIES} ${MODULE_DEPENDENCIES} + COMMAND ${FPP_TO_XML} "-d" "${CMAKE_CURRENT_BINARY_DIR}" ${IMPORTS} ${AC_INPUT_FILES} + "-p" "${FPRIME_BUILD_LOCATIONS_COMMA_SEP}" + DEPENDS ${FILE_DEPENDENCIES} ${MODULE_DEPENDENCIES} ) endif() # Add in steps for CPP generation if (GENERATED_CPP) add_custom_command( - OUTPUT ${GENERATED_CPP} - COMMAND ${REMOVAL_FILE} ${FPP_TO_CPP} "-d" "${CMAKE_CURRENT_BINARY_DIR}" ${FILE_DEPENDENCIES} - "-p" "${FPRIME_BUILD_LOCATIONS_SEP_FPP},${CMAKE_BINARY_DIR}" - DEPENDS ${IMPORTED} ${FILE_DEPENDENCIES} ${MODULE_DEPENDENCIES} + OUTPUT ${GENERATED_CPP} + COMMAND ${FPP_TO_CPP} "-d" "${CMAKE_CURRENT_BINARY_DIR}" ${IMPORTS} ${AC_INPUT_FILES} + "-p" "${FPRIME_BUILD_LOCATIONS_COMMA_SEP},${CMAKE_BINARY_DIR}" + DEPENDS ${FILE_DEPENDENCIES} ${MODULE_DEPENDENCIES} ) endif() - set(AUTOCODER_GENERATED ${GENERATED_AI} ${GENERATED_CPP} PARENT_SCOPE) + set(AUTOCODER_GENERATED ${GENERATED_AI} ${GENERATED_CPP}) + set(AUTOCODER_GENERATED "${AUTOCODER_GENERATED}" PARENT_SCOPE) set(AUTOCODER_DEPENDENCIES "${MODULE_DEPENDENCIES}" PARENT_SCOPE) endfunction(fpp_setup_autocode) @@ -211,23 +220,18 @@ endfunction(fpp_setup_autocode) # Helper function. Converts a list of files and a list of autocoder inputs into a list of module names. # # FILE_LIST: list of files -# AC_INPUT_FILES: list of autocoder input files # OUTPUT_VAR: output variable to set with result #### -function(fpp_to_modules FILE_LIST AC_INPUT_FILES OUTPUT_VAR) +function(fpp_to_modules FILE_LIST OUTPUT_VAR) init_variables(OUTPUT_DATA) get_module_name("${CMAKE_CURRENT_SOURCE_DIR}") set(CURRENT_MODULE "${MODULE_NAME}") - foreach(INCLUDE IN LISTS AC_INPUT_FILES FILE_LIST) + foreach(INCLUDE IN LISTS FILE_LIST) get_module_name(${INCLUDE}) - # Here we are adding a module to the modules list if all three of the following are true: + # Here we are adding a module to the modules list if all of the following are true: # 1. Not present already (deduplication) # 2. Not the current module directory as learned by the path to the autocoder inputs - # 3. Not a child of the fprime configuration directory - # NOTE: item 3 is build on the assumption that configuration .fpp files do not require autocode, but maintain - # only definitions useful to other modules. This assumption holds as of v3.0.0, but should this assumption break - # remove the check here, return a known module name (e.g. 'config') for this directory, and place a - # CMakeLists.txt in that directory that sets up the aforementioned known module and associated target. + # 3. Not withing the config directory. Config dependencies are attached to every module automatically. if ("${MODULE_NAME}" IN_LIST OUTPUT_DATA OR CURRENT_MODULE STREQUAL MODULE_NAME OR INCLUDE MATCHES "${FPRIME_CONFIG_DIR}/.*") continue() # Skip adding to module list endif() diff --git a/cmake/autocoder/helpers.cmake b/cmake/autocoder/helpers.cmake index f93a1402ce..23e8e129b6 100644 --- a/cmake/autocoder/helpers.cmake +++ b/cmake/autocoder/helpers.cmake @@ -6,6 +6,7 @@ #### include_guard() include("utilities") +set_property(GLOBAL PROPERTY AUTO_RECONFIGURE_LIST) #### # Macro `autocoder_support_by_suffix`: # @@ -19,13 +20,41 @@ include("utilities") # # **SUFFIX**: suffix to support # **AC_INPUT_FILE**: file to check with suffix +# **REQUIRE_CMAKE_RESCAN:** (optional) this file should trigger a cmake rescan. Default: false #### macro(autocoder_support_by_suffix SUFFIX AC_INPUT_FILE) ends_with(IS_SUPPORTED "${AC_INPUT_FILE}" "${SUFFIX}") # Note: set in PARENT_SCOPE in macro is intended. Caller **wants** to set IS_SUPPORTED in their parent's scope. set(IS_SUPPORTED "${IS_SUPPORTED}" PARENT_SCOPE) + + # Files that are supported may also be marked as requiring a rescan. This is done through an optional third argument + if (IS_SUPPORTED AND ${ARGC} GREATER 2) + # CMake weirdness, if ${ARGC} is <= 2 then ${ARGV2} is inherited not from this macro call, but rather from the + # calling function. Thus we need a 2-tier if statement to prevent an explosion. + # See: https://cmake.org/cmake/help/latest/command/macro.html#argument-caveats + if (${ARGV2}) + requires_regeneration("${AC_INPUT_FILE}") + endif() + endif() endmacro() +#### +# Function `requires_regeneration`: +# +# Called by the autocoder when a source file needs to setup CMake to reconfigure when the source file changes. +# +# `AC_INPUT_FILE`: file to mark as tracked +#### +function(requires_regeneration AC_INPUT_FILE) + get_property(RECONFIGURE_LIST GLOBAL PROPERTY AUTO_RECONFIGURE_LIST) + get_filename_component(REAL_FILE "${AC_INPUT_FILE}" REALPATH) + if (NOT "${REAL_FILE}" IN_LIST RECONFIGURE_LIST) + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${AC_INPUT_FILE}") + list(APPEND RECONFIGURE_LIST "${REAL_FILE}") + set_property(GLOBAL PROPERTY AUTO_RECONFIGURE_LIST "${RECONFIGURE_LIST}") + endif() +endfunction() + #### # Function `_set_autocoder_name`: # diff --git a/cmake/autocoder/packets.cmake b/cmake/autocoder/packets.cmake new file mode 100644 index 0000000000..f2d5157b86 --- /dev/null +++ b/cmake/autocoder/packets.cmake @@ -0,0 +1,63 @@ +#### +# autocoder/packets.cmake +# +# Packets autocoder. +##### +include(utilities) +include(autocoder/helpers) +include(autocoder/ai-shared) + +set(PACKETS_AUTOCODER_SCRIPT "${FPRIME_FRAMEWORK_PATH}/Autocoders/Python/bin/tlm_packet_gen.py") + +autocoder_setup_for_individual_sources() +#### +# `packets_is_supported`: +# +# Required function, processes Ai.xml files. +# `AC_INPUT_FILE` potential input to the autocoder +# ...: any number of arguments representing a list of previously generated files +#### +function(packets_is_supported AC_INPUT_FILE) + autocoder_support_by_suffix("Packets.xml" "${AC_INPUT_FILE}" TRUE) +endfunction (packets_is_supported) + +#### +# `determine_topology_files`: +# +# Get topology determined from packet file. +#### +function(determine_topology_files AC_INPUT_FILE) + file(READ "${AC_INPUT_FILE}" FILE_CONTENTS) + string(REGEX REPLACE ".*([^>]*).*" "\\1" TOPOLOGY_FILE "${FILE_CONTENTS}") + # This will work as long as the topology ai file is not part of the fprime core "library" code + set(FULL_TOPOLOGY_FILE "${CMAKE_BINARY_DIR}/${TOPOLOGY_FILE}" PARENT_SCOPE) +endfunction(determine_topology_files) + +#### +# `packets_setup_autocode`: +# +# Required function, sets up a custom command to produce Ac.hpp and Ac.cpp files. +#### +function(packets_setup_autocode AC_INPUT_FILE) + determine_topology_files("${AC_INPUT_FILE}") + get_filename_component(AC_INPUT_FILE_NO_PATH "${AC_INPUT_FILE}" NAME) + + string(REPLACE ";" ":" FPRIME_BUILD_LOCATIONS_SEP "${FPRIME_BUILD_LOCATIONS}") + string(REPLACE "Packets.xml" "PacketsAc.cpp" CPP_FILE "${AC_INPUT_FILE_NO_PATH}") + string(REPLACE "Packets.xml" "PacketsAc.hpp" HPP_FILE "${AC_INPUT_FILE_NO_PATH}") + + set(GENERATED_FILES + "${CMAKE_CURRENT_BINARY_DIR}/${CPP_FILE}" + "${CMAKE_CURRENT_BINARY_DIR}/${HPP_FILE}" + ) + add_custom_command( + OUTPUT ${GENERATED_FILES} + COMMAND + PYTHONPATH=${PYTHON_AUTOCODER_DIR}/src:${PYTHON_AUTOCODER_DIR}/utils + BUILD_ROOT=${FPRIME_BUILD_LOCATIONS_SEP}:${CMAKE_BINARY_DIR}:${CMAKE_BINARY_DIR}/F-Prime + "${PYTHON}" "${PACKETS_AUTOCODER_SCRIPT}" "${AC_INPUT_FILE}" + DEPENDS "${AC_INPUT_FILE}" "${FULL_TOPOLOGY_FILE}" + ) + set(AUTOCODER_GENERATED "${GENERATED_FILES}" PARENT_SCOPE) + set(AUTOCODER_DEPENDENCIES "" PARENT_SCOPE) +endfunction(packets_setup_autocode) diff --git a/cmake/options.cmake b/cmake/options.cmake index 3c12f5b65b..a6c87efbd7 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -16,6 +16,13 @@ # the `-D` option there. # #### +# Remap changed settings +if (DEFINED FPRIME_INSTALL_DEST) + set(CMAKE_INSTALL_PREFIX ${FPRIME_INSTALL_DEST} CACHE PATH "Install dir" FORCE) +endif() +include("settings/ini") +ini_to_cache() + #### # `CMAKE_TOOLCHAIN_FILE:` @@ -181,6 +188,70 @@ option(FPRIME_SKIP_TOOLS_VERSION_CHECK "Skip the version checking of tools" OFF) #### option(FPRIME_CHECK_FRAMEWORK_VERSION "(Internal) Check framework version when building." OFF) +#### +# `ENABLE_SANITIZER_ADDRESS:` +# +# Enables Google's AddressSanitizer. AddressSanitizer is a memory error detector for C/C++. +# More information: https://github.com/google/sanitizers/wiki/AddressSanitizer +# Practically, this adds the -fsanitizers=address flag to both the compiler and linker for the whole build. +# +# **Values:** +# - ON: enables AddressSanitizer. +# - OFF: (default) does not enable AddressSanitizer. +# +# e.g. `-DENABLE_SANITIZER_ADDRESS=ON` +#### +option(ENABLE_SANITIZER_ADDRESS "Enable address sanitizer" OFF) + +#### +# `ENABLE_SANITIZER_LEAK:` +# +# Enables Google's LeakSanitizer. LeakSanitizer is a memory leak detector which is integrated into AddressSanitizer. +# More information: https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer +# Practically, this adds the -fsanitizers=leak flag to both the compiler and linker for the whole build. +# +# Note: LeakSanitizer is not available on macOS. Use AddressSanitizer instead. +# +# **Values:** +# - ON: enables LeakSanitizer. +# - OFF: (default) does not enable LeakSanitizer. +# +# e.g. `-DENABLE_SANITIZER_LEAK=ON` +#### +option(ENABLE_SANITIZER_LEAK "Enable leak sanitizer" OFF) + +#### +# `ENABLE_SANITIZER_UNDEFINED_BEHAVIOR:` +# +# Enables Google's UndefinedBehaviorSanitizer. UndefinedBehaviorSanitizer is an undefined behavior detector. +# More information: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html +# Practically, this adds the -fsanitizers=undefined flag to both the compiler and linker for the whole build. +# +# **Values:** +# - ON: enables UndefinedBehaviorSanitizer. +# - OFF: (default) does not enable UndefinedBehaviorSanitizer. +# +# e.g. `-DENABLE_SANITIZER_UNDEFINED_BEHAVIOR=ON` +#### +option(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR "Enable undefined behavior sanitizer" OFF) + +#### +# `ENABLE_SANITIZER_THREAD:` +# +# Enables Google's ThreadSanitizer. ThreadSanitizer is a tool that detects data races. +# More information: https://clang.llvm.org/docs/ThreadSanitizer.html +# Practically, this adds the -fsanitizers=thread flag to both the compiler and linker for the whole build. +# +# Note: ThreadSanitizer does not work with Address or Leak sanitizer enabled +# +# **Values:** +# - ON: enables ThreadSanitizer. +# - OFF: (default) does not enable ThreadSanitizer. +# +# e.g. `-DENABLE_SANITIZER_THREAD=ON` +#### +option(ENABLE_SANITIZER_THREAD "Enable thread sanitizer" OFF) + # Backwards compatibility, when build type=TESTING BUILD_TESTING is on string(TOUPPER "${CMAKE_BUILD_TYPE}" FPRIME_BUILD_TYPE) if (FPRIME_BUILD_TYPE STREQUAL "TESTING") @@ -265,13 +336,14 @@ if (DEFINED FPRIME_ENVIRONMENT_FILE) set(FPRIME_ENVIRONMENT_FILE "${FPRIME_ENVIRONMENT_FILE}" CACHE PATH "F prime environment file" FORCE) set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${FPRIME_ENVIRONMENT_FILE}") endif() -# Override the AC constants file when specified -if (NOT DEFINED FPRIME_AC_CONSTANTS_FILE) - set(FPRIME_AC_CONSTANTS_FILE "${FPRIME_FRAMEWORK_PATH}/config/AcConstants.ini" CACHE PATH "F prime AC constants.ini file" FORCE) -endif() # Settings for F config directory if (NOT DEFINED FPRIME_CONFIG_DIR) set(FPRIME_CONFIG_DIR "${FPRIME_FRAMEWORK_PATH}/config/") endif() set(FPRIME_CONFIG_DIR "${FPRIME_CONFIG_DIR}" CACHE PATH "F prime configuration header directory" FORCE) + +# Override the AC constants file when specified +if (NOT DEFINED FPRIME_AC_CONSTANTS_FILE) + set(FPRIME_AC_CONSTANTS_FILE "${FPRIME_CONFIG_DIR}/AcConstants.ini" CACHE PATH "F prime AC constants.ini file" FORCE) +endif() diff --git a/cmake/platform/Darwin.cmake b/cmake/platform/Darwin.cmake index b8bbf56494..35a6a8c4da 100644 --- a/cmake/platform/Darwin.cmake +++ b/cmake/platform/Darwin.cmake @@ -19,5 +19,5 @@ if (NOT DEFINED FPRIME_USE_BAREMETAL_SCHEDULER) FIND_PACKAGE ( Threads REQUIRED ) endif() -# Add linux include path which is compatible with Darwin for StandardTypes.hpp -include_directories(SYSTEM "${FPRIME_FRAMEWORK_PATH}/Fw/Types/Linux") +# Add linux include path which is compatible with Darwin for PlatformTypes.hpp +include_directories(SYSTEM "${CMAKE_CURRENT_LIST_DIR}/types") diff --git a/cmake/platform/Linux.cmake b/cmake/platform/Linux.cmake index d8e71e19ea..89beac4d55 100644 --- a/cmake/platform/Linux.cmake +++ b/cmake/platform/Linux.cmake @@ -15,4 +15,5 @@ add_definitions(-DTGT_OS_TYPE_LINUX) set(FPRIME_USE_POSIX ON) # Add Linux specific headers into the system -include_directories(SYSTEM "${FPRIME_FRAMEWORK_PATH}/Fw/Types/Linux") +include_directories(SYSTEM "${CMAKE_CURRENT_LIST_DIR}/types") + diff --git a/cmake/platform/platform.cmake.template b/cmake/platform/platform.cmake.template index d38e04898c..c3c3b5087a 100644 --- a/cmake/platform/platform.cmake.template +++ b/cmake/platform/platform.cmake.template @@ -3,7 +3,7 @@ # # This file acts as a template for the fprime platform files used by the CMake system. # These files specify build flags, compiler directives, and must specify an include -# directory for system includes like "StandardTypes.hpp". +# directory for system includes like "PlatformTypes.hpp". # # Follow all the steps in this template to create a platform file. Ensure # to remove the platform-failsafe (step 1) and fill in all tags. @@ -29,7 +29,7 @@ # F prime platform files are used to set F prime specific settings. This allows the user to control # some aspects of the F prime build at the top-level. This means setting global include directories # compiler definitions for the platform, threading libraries, etc. The bare-minimum platform file -# should specify an include directory for "StandardTypes.hpp" and a threading library if using +# should specify an include directory for "PlatformTypes.hpp" and a threading library if using # active components with OS supported threads. This can be done with the following lines: # # ``` @@ -67,7 +67,7 @@ if (NOT DEFINED FPRIME_USE_BAREMETAL_SCHEDULER) FIND_PACKAGE ( Threads REQUIRED ) endif() -# STEP 5: Specify a directory containing the "StandardTypes.hpp" headers, as well +# STEP 5: Specify a directory containing the "PlatformTypes.hpp" headers, as well # as other system headers. Other global headers can be placed here. # Note: Typically, the Linux directory is a good default, as it grabs # standard types from . diff --git a/cmake/platform/types/PlatformTypes.h b/cmake/platform/types/PlatformTypes.h new file mode 100644 index 0000000000..5e78a91122 --- /dev/null +++ b/cmake/platform/types/PlatformTypes.h @@ -0,0 +1,81 @@ +/** + * \brief PlatformTypes.h C-compatible type definitions for Linux/Darwin + * + * PlatformTypes.h is typically published by platform developers to define + * the standard available arithmetic types for use in fprime. This standard + * types header is designed to support standard Linux/Darwin distributions + * running on x86, x86_64 machines and using the standard gcc/clang compilers + * shipped with the operating system. + * + * In C++ code, users may use std::numeric_limits::min() + * to reference the min/max limits of a type. + */ +#ifndef PLATFORM_TYPES_H_ +#define PLATFORM_TYPES_H_ + +// Section 0: C Standard Types +// fprime depends on the existence of intN_t and uintN_t C standard ints and +// the mix/max values for those types. Platform developers must either: +// 1. define these types and definitions +// 2. include headers that define these types +// +// In addition, support for various type widths can be turned on/off with the +// switches in this section to control which of the C standard types are +// available in the system. fprime consumes this information and produces the +// UN, IN, and FN types we see in fprime code. +#include +#include + +// Define what types and checks are supported by this platform +#define FW_HAS_64_BIT 1 //!< Architecture supports 64 bit integers +#define FW_HAS_32_BIT 1 //!< Architecture supports 32 bit integers +#define FW_HAS_16_BIT 1 //!< Architecture supports 16 bit integers +#define FW_HAS_F64 1 //!< Architecture supports 64 bit floating point numbers +#define SKIP_FLOAT_IEEE_754_COMPLIANCE 0 //!< Check IEEE 754 compliance of floating point arithmetic + +// Section 1: Logical Types +// fprime requires platform implementors to define logical types for their +// system. The list of logical types can be found in the document: +// docs/Design/numerical-types.md with the names of the form "Platform*" + +typedef int PlatformIntType; +#define PRI_PlatformIntType "d" + +typedef unsigned int PlatformUIntType; +#define PRI_PlatformUIntType "u" + +typedef PlatformIntType PlatformIndexType; +#define PRI_PlatformIndexType PRI_PlatformIntType + +typedef PlatformUIntType PlatformSizeType; +#define PRI_PlatformSizeType PRI_PlatformUIntType + +typedef PlatformIntType PlatformAssertArgType; +#define PRI_PlatformAssertArgType PRI_PlatformIntType + +// Linux/Darwin definitions for pointer have various sizes across platforms +// and since these definitions need to be consistent we must ask the size. +#ifndef PLATFORM_POINTER_CAST_TYPE_DEFINED +// Check for __SIZEOF_POINTER__ or cause error +#ifndef __SIZEOF_POINTER__ +#error "Compiler does not support __SIZEOF_POINTER__, cannot use Linux/Darwin types" +#endif + +// Pointer sizes are determined by compiler +#if __SIZEOF_POINTER__ == 8 +typedef uint64_t PlatformPointerCastType; +#define PRI_PlatformPointerCastType PRIx64 +#elif __SIZEOF_POINTER__ == 4 +typedef uint32_t PlatformPointerCastType; +#define PRI_PlatformPointerCastType PRIx32 +#elif __SIZEOF_POINTER__ == 2 +typedef uint16_t PlatformPointerCastType; +#define PRI_PlatformPointerCastType PRIx16 +#elif __SIZEOF_POINTER__ == 1 +typedef uint8_t PlatformPointerCastType; +#define PRI_PlatformPointerCastType PRIx8 +#else +#error "Expected __SIZEOF_POINTER__ to be one of 8, 4, 2, or 1" +#endif +#endif +#endif // PLATFORM_TYPES_H_ diff --git a/cmake/prescan.cmake b/cmake/prescan.cmake index 5f0dc51b74..505eda58da 100644 --- a/cmake/prescan.cmake +++ b/cmake/prescan.cmake @@ -12,22 +12,43 @@ # full build or the information will be wrong. #### -# NOTE: **ensure** that list properties are added by hand in the actual call. Otherwise they are expanded and break -# the call below. -set(NEEDED_PROPERTIES - FPRIME_CONFIG_DIR - FPRIME_AC_CONSTANTS_FILE - FPRIME_ENVIRONMENT_FILE - FPRIME_SETTINGS_FILE - FPRIME_PROJECT_ROOT - FPRIME_FRAMEWORK_PATH - CMAKE_TOOLCHAIN_FILE - CMAKE_BUILD_TYPE - CMAKE_DEBUG_OUTPUT - FPRIME_USE_STUBBED_DRIVERS - FPRIME_USE_BAREMETAL_SCHEDULER - FPP_TOOLS_PATH - BUILD_TESTING +set(EXCLUDED_CACHE_VARIABLES + CMAKE_EDIT_COMMAND + CMAKE_HOME_DIRECTORY + CMAKE_INSTALL_NAME_TOOL + FPRIME_PRESCAN + FPRIME_VERSION_SCRIPT + CMAKE_C_COMPILER_FORCED + CMAKE_CXX_COMPILER_FORCED + FPRIME_SKIP_TOOLS_VERSION_CHECK + CMAKE_HAVE_LIBC_PTHREAD + CMAKE_HAVE_PTHREAD_H + CMAKE_SKIP_INSTALL_ALL_DEPENDENCY + FIND_PACKAGE_MESSAGE_DETAILS_Threads + BUILD_GMOCK + CMAKE_INSTALL_BINDIR + CMAKE_INSTALL_DATAROOTDIR + CMAKE_INSTALL_INCLUDEDIR + CMAKE_INSTALL_LIBDIR + CMAKE_INSTALL_LIBEXECDIR + CMAKE_INSTALL_LOCALSTATEDIR + CMAKE_INSTALL_OLDINCLUDEDIR + CMAKE_INSTALL_SBINDIR + CMAKE_INSTALL_SHAREDSTATEDIR + CMAKE_INSTALL_SYSCONFDIR + INSTALL_GTEST + VALGRIND + gmock_build_tests + gtest_build_samples + gtest_build_tests + gtest_disable_pthreads + gtest_force_shared_crt + gtest_hide_internal_symbols +) +set(TYPES_DISALLOWED_LIST + INTERNAL + STATIC + UNINITIALIZED ) # Directory in-which to build the prescan directory set(PRESCAN_DIR "${CMAKE_BINARY_DIR}/prescan") @@ -44,11 +65,27 @@ endif() #### function(_get_call_properties) set(CALL_PROPS) - foreach (PROPERTY IN LISTS NEEDED_PROPERTIES) - if (NOT "${${PROPERTY}}" STREQUAL "") - set(CALL_PROP "-D${PROPERTY}=${${PROPERTY}}") - list(APPEND CALL_PROPS "${CALL_PROP}") + get_cmake_property(CACHE_VARS CACHE_VARIABLES) + foreach (PROPERTY IN LISTS CACHE_VARS) + get_property(CACHE_TYPE CACHE "${PROPERTY}" PROPERTY TYPE) + # Exclude listed properties and empty properties + if ("${PROPERTY}" IN_LIST EXCLUDED_CACHE_VARIABLES) + continue() + # Exclude empty values + elseif("${${PROPERTY}}" STREQUAL "") + continue() + # Exclude internal cache values + elseif("${CACHE_TYPE}" IN_LIST TYPES_DISALLOWED_LIST) + continue() + endif() + # Add escaping for list type variables + string(REPLACE ";" "\\;" PROP_VALUE "${${PROPERTY}}" ) + # Check for debugging output + if (CMAKE_DEBUG_OUTPUT) + message(STATUS "[prescan] Adding cache variable: '${PROPERTY}=${PROP_VALUE}'") endif() + set(CALL_PROP "-D${PROPERTY}=${PROP_VALUE}") + list(APPEND CALL_PROPS "${CALL_PROP}") endforeach() set(CALL_PROPS "${CALL_PROPS}" PARENT_SCOPE) endfunction(_get_call_properties) @@ -80,7 +117,6 @@ function(perform_prescan) "-DCMAKE_C_COMPILER_FORCED=TRUE" "-DCMAKE_CXX_COMPILER_FORCED=TRUE" "-DFPRIME_SKIP_TOOLS_VERSION_CHECK=ON" - "-DFPRIME_LIBRARY_LOCATIONS=${FPRIME_LIBRARY_LOCATIONS}" ${CALL_PROPS} RESULT_VARIABLE result WORKING_DIRECTORY "${PRESCAN_DIR}" @@ -94,4 +130,4 @@ function(perform_prescan) file(READ "${CMAKE_BINARY_DIR}/prescan-fpp-list" FPP_LISTING OFFSET 1) # Skips leading ";" preventing null element set_property(GLOBAL PROPERTY FP_FPP_LIST ${FPP_LISTING}) message(STATUS "Performing CMake source prescan - DONE") -endfunction() \ No newline at end of file +endfunction() diff --git a/cmake/sanitizers.cmake b/cmake/sanitizers.cmake new file mode 100644 index 0000000000..4f826fedd6 --- /dev/null +++ b/cmake/sanitizers.cmake @@ -0,0 +1,51 @@ +#### +# sanitizers.cmake: +# +# Enables sanitizers in the build settings when requested by the user with -DENABLE_SANITIZER_<...>=ON. +# +# Sanitizers, by default, output their logs to stderr. To redirect the output to files instead, use the +# `log_path` option from the sanitizer _OPTIONS environment variable at runtime. For example, with UBSAN: +# >>> UBSAN_OPTIONS="log_path=/path/to/output_dir/file_prefix" fprime-util check +# or +# >>> UBSAN_OPTIONS="log_path=/path/to/output_dir/file_prefix" ./path/to/executable +# +# Note: is a prefix to which the sanitizer will add a unique ID to generate a unique filename. +# If a relative path is specified, this will be relative to the component's folder **in the build cache** +# if using fprime-util check, OR relative to the current directory if running a single executable. +#### + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + set(SANITIZERS) + + if(ENABLE_SANITIZER_ADDRESS) + list(APPEND SANITIZERS "address") + endif() + + if(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR) + list(APPEND SANITIZERS "undefined") + endif() + + if(ENABLE_SANITIZER_LEAK) + if(APPLE) + message(STATUS "[WARNING] Leak sanitizer is not supported on macOS") + else() + list(APPEND SANITIZERS "leak") + endif() + endif() + + if(ENABLE_SANITIZER_THREAD) + if("address" IN_LIST SANITIZERS OR "leak" IN_LIST SANITIZERS) + message(STATUS "[WARNING] Thread sanitizer does not work with Address or Leak sanitizer enabled") + else() + list(APPEND SANITIZERS "thread") + endif() + endif() + + list(JOIN SANITIZERS "," LIST_OF_SANITIZERS) + + if(LIST_OF_SANITIZERS AND NOT "${LIST_OF_SANITIZERS}" STREQUAL "") + message(STATUS "Enabled the following sanitizers: ${LIST_OF_SANITIZERS}") + add_compile_options(-fsanitize=${LIST_OF_SANITIZERS}) + add_link_options(-fsanitize=${LIST_OF_SANITIZERS}) + endif() +endif() diff --git a/cmake/settings/ini-to-stdio.py b/cmake/settings/ini-to-stdio.py new file mode 100644 index 0000000000..226b99e77d --- /dev/null +++ b/cmake/settings/ini-to-stdio.py @@ -0,0 +1,96 @@ +""" ini-to-stdio.py: + +Loads fprime style ini files into a format CMake can process. +""" +import argparse +import sys +from functools import partial + +from pathlib import Path +from typing import List + +from fprime.fbuild.settings import IniSettings + + +def print_setting(setting: str, value: str = "", ending: str = ";"): + """Print a setting for CMake + + Prints a setting for CMake using the format 'SETTING=VALUE;' producing a CMake list of settings. + + Args: + setting: name of setting in cmake + value: value to provide to cmake + ending: ending of the print line + """ + value = str(value).replace(";", "\\;") + print(f"{setting}={value}", end=ending) + + +def print_list_settings(items: List[str]): + """Print a list of settings of form SETTING=VALUE""" + for item in items: + splits = item.strip().split("=") + if splits[0] != "": + print_setting(*splits) + + +CMAKE_NEEDED_SETTINGS = { + "framework_path": partial(print_setting, "FPRIME_FRAMEWORK_PATH"), + "project_root": partial(print_setting, "FPRIME_PROJECT_ROOT"), + "config_directory": partial(print_setting, "FPRIME_CONFIG_DIR"), + "library_locations": lambda value: print_setting( + "FPRIME_LIBRARY_LOCATIONS", ";".join(str(item) for item in value) + ), + "default_cmake_options": lambda value: print_list_settings(value.split("\n")), + "ac_constants": partial(print_setting, "FPRIME_AC_CONSTANTS_FILE"), + # Sets two settings from install dest: fprime and cmake settings + "install_destination": partial(print_setting, "CMAKE_INSTALL_PREFIX"), +} + + +def main(): + """Do the thing.""" + parser = argparse.ArgumentParser() + parser.add_argument("settings", type=Path, help="Path to settings.ini") + parser.add_argument( + "toolchain", + nargs="?", + type=Path, + default=Path("native"), + help="Path to toolchain file", + ) + + args_ns = parser.parse_args() + loaded_settings = IniSettings.load( + args_ns.settings, str(args_ns.toolchain.stem), False + ) + loaded_settings_ut = IniSettings.load( + args_ns.settings, str(args_ns.toolchain.stem), True + ) + + for setting, handler in CMAKE_NEEDED_SETTINGS.items(): + try: + setting_value = loaded_settings[setting] + ut_setting_value = loaded_settings_ut[setting] + + assert ( + setting_value == ut_setting_value + ), f"CMake can only parse unittest independent settings" + output = loaded_settings[setting] + handler(output) + except KeyError as key_error: + print( + f"[WARNING] Failed to load settings.ini field {key_error}. Update fprime-util.", + end=";", + ) + # Print the last setting with no ending to prevent null-entry at list end + print_setting("FPRIME_SETTINGS_FILE", args_ns.settings, ending="") + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Exception as exc: + print(f"{exc}", file=sys.stderr) + sys.exit(1) diff --git a/cmake/settings/ini.cmake b/cmake/settings/ini.cmake new file mode 100644 index 0000000000..d072af9451 --- /dev/null +++ b/cmake/settings/ini.cmake @@ -0,0 +1,118 @@ +#### +# ini.cmake: +# +# This file loads settings from INI files. In cases where these settings are supplied via fprime-util, the settings are +# checked for discrepancy. This allows the cmake system to detect when it should be regenerated and has not been. In the +# case that the settings were not supplied, it sets them. +#### +include_guard() + +# Necessary global variables +set(SETTINGS_CMAKE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}") +find_program(PYTHON NAMES python3 python) #This happens before required + +#### +# FPRIME_UTIL_CRITICAL_LIST: +# +# This is a list of critical settings that are passed in from fprime-util. If these settings change in `settings.ini` +# they need to result in a WARNING to let the user know that had fprime-util be run, it now needs to be rerun. +#### +set(FPRIME_UTIL_CRITICAL_LIST + "FPRIME_FRAMEWORK_PATH" + "FPRIME_LIBRARY_LOCATIONS" + "FPRIME_PROJECT_ROOT" + "FPRIME_ENVIRONMENT_FILE" + "FPRIME_AC_CONSTANTS_FILE" + "FPRIME_CONFIG_DIR" + "FPRIME_INSTALL_DEST" +) + +#### +# ini_to_cache: +# +# Uses a python script to load INI files. These items are set into the CMake cache. +#### +function(ini_to_cache) + set(CALCULATED_INI "${CMAKE_SOURCE_DIR}/settings.ini") + + # Check if settings.ini is defined and is not what is expected + if (DEFINED FPRIME_SETTINGS_FILE AND NOT FPRIME_SETTINGS_FILE STREQUAL "${CALCULATED_INI}") + message(FATAL_ERROR "Provided settings.ini '${FPRIME_SETTINGS_FILE}' not expected file '${CALCULATED_INI}'") + endif() + # Execute the process + execute_process(COMMAND ${PYTHON} + "${SETTINGS_CMAKE_DIRECTORY}/ini-to-stdio.py" + "${CALCULATED_INI}" + ${CMAKE_TOOLCHAIN_FILE} + OUTPUT_VARIABLE INI_OUTPUT + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE RESULT_CODE + ) + # Check result code + if (NOT RESULT_CODE EQUAL 0) + message(FATAL_ERROR "Failed to process settings.ini file: ${CALCULATED_INI}") + endif() + + # Unset the CMAKE_INSTALL_PREFIX as we override it + if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT OR CMAKE_INSTALL_PREFIX STREQUAL "") + unset(CMAKE_INSTALL_PREFIX CACHE) + endif() + # Process line-by-line + foreach(LINE IN LISTS INI_OUTPUT) + # Skip malformed lines + if (NOT LINE MATCHES "^[A-Za-z0-9_]+=") + message(STATUS "${LINE}") + continue() + endif() + STRING(REPLACE ";" "\\;" LINE "${LINE}") + STRING(REPLACE "=" ";" LINE "${LINE}") + list(GET LINE 0 SETTING) + list(LENGTH LINE ELEMENTS) + if (ELEMENTS GREATER 1) + list(GET LINE 1 VALUE) + else() + set(VALUE "") + endif() + + # Here we set several cache variables: + # - _INI_: original setting, but was loaded from settings.ini + # - _CLI_: original setting, but was passed in via CLI + # These are used to detect changes and alert the user. + # If the setting is undefined, then we must load it from the INI file and set the proper value. + if (NOT DEFINED "${SETTING}") + # Print source of setting when debugging + if (CMAKE_DEBUG_OUTPUT) + message(STATUS "${SETTING} read from settings.ini as '${VALUE}'") + endif() + set("${SETTING}_INI_" "${VALUE}" CACHE INTERNAL "Original value of ${SETTING} from settings.ini") + set("${SETTING}" "${VALUE}" CACHE INTERNAL "") + # If setting was originally loaded, here, from settings.ini. We should check that it is correctly re-set. + elseif(DEFINED "${SETTING}_INI_") + # Changed INI files are hard-failure as it is difficult to know how/when to regenerate + if(NOT "${VALUE}" STREQUAL "${${SETTING}_INI_}") + # Print some extra output to help debug + if (CMAKE_DEBUG_OUTPUT) + message(WARNING "${SETTING} changed from '${${SETTING}_INI_}' to '${VALUE}'") + endif() + message(FATAL_ERROR "settings.ini field changed. Please regenerate.") + endif() + # If setting was passed in on CLI + elseif(DEFINED "${SETTING}_CLI_") + # Changed INI files are hard-failure as it is difficult to know how/when to regenerate + if(NOT "${VALUE}" STREQUAL "${${SETTING}_CLI_}" AND SETTING IN_LIST FPRIME_UTIL_CRITICAL_LIST) + # Print some extra output to help debug + if (CMAKE_DEBUG_OUTPUT) + message(WARNING "${SETTING} changed from '${${SETTING}_CLI_}' to '${VALUE}'") + endif() + message(WARNING "settings.ini field changed. This likely means fprime-util generate should be run.") + endif() + # Setting defined, but none of the check-values are set. This it is the first run, with items from CLI. + else() + # Print source of setting when debugging + if (CMAKE_DEBUG_OUTPUT) + message(STATUS "${SETTING} read from CLI as '${${SETTING}}'") + endif() + set("${SETTING}_CLI_" "${${SETTING}}" CACHE INTERNAL "Original value of ${SETTING} from CLI") + endif() + endforeach() +endfunction(ini_to_cache) diff --git a/cmake/target/build.cmake b/cmake/target/build.cmake index 81f000bfde..2430a2b577 100644 --- a/cmake/target/build.cmake +++ b/cmake/target/build.cmake @@ -54,16 +54,18 @@ function(build_setup_build_module MODULE SOURCES GENERATED EXCLUDED_SOURCES DEPE get_target_property(MODULE_SOURCES "${MODULE}" SOURCES) list(REMOVE_ITEM MODULE_SOURCES "${EMPTY}") - set_target_properties( - ${MODULE} - PROPERTIES - SOURCES "${MODULE_SOURCES}" - ) - # Setup the hash file for our sources - foreach(SRC_FILE IN LISTS MODULE_SOURCES) - set_hash_flag("${SRC_FILE}") - endforeach() - + # Only update module sources if the list is not empty. Otherwise we keep empty.c as the only source. + if (NOT "${MODULE_SOURCES}" STREQUAL "") + set_target_properties( + ${MODULE} + PROPERTIES + SOURCES "${MODULE_SOURCES}" + ) + # Setup the hash file for our sources + foreach(SRC_FILE IN LISTS MODULE_SOURCES) + set_assert_flags("${SRC_FILE}") + endforeach() + endif() # Includes the source, so that the Ac files can include source headers target_include_directories("${MODULE}" PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) @@ -114,7 +116,8 @@ endfunction() function(build_add_module_target MODULE TARGET SOURCES DEPENDENCIES) get_target_property(MODULE_TYPE "${MODULE}" FP_TYPE) message(STATUS "Adding ${MODULE_TYPE}: ${MODULE}") - run_ac_set("${SOURCES}" autocoder/fpp autocoder/ai_xml) + get_property(CUSTOM_AUTOCODERS GLOBAL PROPERTY FPRIME_AUTOCODER_TARGET_LIST) + run_ac_set("${SOURCES}" ${CUSTOM_AUTOCODERS}) resolve_dependencies(RESOLVED ${DEPENDENCIES} ${AC_DEPENDENCIES} ) build_setup_build_module("${MODULE}" "${SOURCES}" "${AC_GENERATED}" "${AC_SOURCES}" "${RESOLVED}") # Special flags applied to modules when compiling with testing enabled diff --git a/cmake/target/dict.cmake b/cmake/target/dict.cmake deleted file mode 100644 index b0297fb3da..0000000000 --- a/cmake/target/dict.cmake +++ /dev/null @@ -1,40 +0,0 @@ -#### -# dict.cmake: -# -# Dictionary target definition file. Used to define `dict` and `_dict` targets. Defined as -# a standard target pattern. This means that the following functions are defined: -# -# - `add_module_target`: adds sub-targets for '_dict' -#### - -# Dictionaries are per-deployment, a global variant does not make sense -function(dict_add_global_target) -endfunction() - -# For now, using the by-product output of the autocode step -function(dict_add_deployment_target) -endfunction() - -#### -# Dict function `add_module_target`: -# -# Process the dictionary target on each module that is defined. Since the topology module is going to do the dictionary -# generation work for us, we just need to add a dependency on the module that contains the dictionary in its list of -# autocoder output files. -# -# - **MODULE:** name of the module -# - **TARGET:** name of the top-target (e.g. dict). Use ${MODULE_NAME}_${TARGET_NAME} for a module specific target -# - **SOURCE_FILES:** list of source file inputs from the CMakeList.txt setup -# - **DEPENDENCIES:** MOD_DEPS input from CMakeLists.txt -#### -function(dict_add_module_target MODULE TARGET SOURCES DEPENDENCIES) - get_target_name(${TARGET} ${MODULE}) - run_ac_set("${SOURCES}" autocoder/fpp autocoder/ai_xml) - set(DICTIONARY "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}TopologyAppDictionary.xml") - foreach(FILE IN LISTS AC_GENERATED) - if (FILE STREQUAL DICTIONARY) - set_property(GLOBAL PROPERTY DICTIONARY_FILE "${DICTIONARY}") - break() - endif() - endforeach() -endfunction(dict_add_module_target) diff --git a/cmake/target/fpp_locs.cmake b/cmake/target/fpp_locs.cmake index 753991adc4..86f8b946ae 100644 --- a/cmake/target/fpp_locs.cmake +++ b/cmake/target/fpp_locs.cmake @@ -8,8 +8,6 @@ # Static and configuration FPP files set(FPP_CONFIGS - "${FPRIME_CONFIG_DIR}/AcConstants.fpp" - "${FPRIME_CONFIG_DIR}/FpConfig.fpp" "${FPRIME_FRAMEWORK_PATH}/Fpp/ToCpp.fpp" ) set(FPP_LOCATE_DEFS_HELPER "${FPRIME_FRAMEWORK_PATH}/cmake/autocoder/fpp-wrapper/fpp-redirect-helper") @@ -53,7 +51,7 @@ function(generate_locations) list(REMOVE_DUPLICATES FPP_FILES) execute_process(COMMAND "${FPP_LOCATE_DEFS_HELPER}" "${FPP_LOCS_FILE}" "${FPP_LOCATE_DEFS}" -d "${CMAKE_BINARY_DIR}" ${FPP_CONFIGS} ${FPP_FILES} RESULT_VARIABLE result) if (NOT result EQUAL 0) - message(FATAL_ERROR "Failed to run fpp-locate-deps") + message(FATAL_ERROR "Helper script 'fpp-redirect-helper' exited with reason: ${result}") endif() message(STATUS "Generating FPP location index - DONE") endfunction() diff --git a/cmake/target/install.cmake b/cmake/target/install.cmake index 3dd5d6f69e..118b8e8c9e 100644 --- a/cmake/target/install.cmake +++ b/cmake/target/install.cmake @@ -46,7 +46,7 @@ function(install_add_deployment_target MODULE TARGET SOURCES DEPENDENCIES FULL_D RUNTIME DESTINATION ${TOOLCHAIN_NAME}/bin LIBRARY DESTINATION ${TOOLCHAIN_NAME}/lib ARCHIVE DESTINATION ${TOOLCHAIN_NAME}/lib/static) - get_property(DICTIONARY GLOBAL PROPERTY DICTIONARY_FILE) + get_property(DICTIONARY GLOBAL PROPERTY "${PROJECT_NAME}_FPRIME_DICTIONARY_FILE") install(FILES ${DICTIONARY} DESTINATION ${TOOLCHAIN_NAME}/dict) add_custom_command(TARGET "${MODULE}" POST_BUILD COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target install) endfunction() diff --git a/cmake/target/ut.cmake b/cmake/target/ut.cmake index 0446af0e53..ab0fe13648 100644 --- a/cmake/target/ut.cmake +++ b/cmake/target/ut.cmake @@ -40,9 +40,34 @@ function(ut_add_deployment_target MODULE TARGET SOURCES DEPENDENCIES FULL_DEPEND endforeach() endfunction(ut_add_deployment_target) +#### +# Function `ut_setup_unit_test_include_directories`: +# +# Adds the include directories needed to make a unit test executable compile correctly. These directories are: +# 1. Current CMake binary directory for autogenerated headers +# 2. (If UT_AUTO_HELPERS) Containing folder for each .hpp for includes of the for '#include "Tester.hpp"' +# +# - **UT_EXE_NAME:** unit test executable name +# - **SOURCE_FILES:** list of source file inputs +#### +function(ut_setup_unit_test_include_directories UT_EXE_NAME SOURCE_FILES) + set(UT_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}") + # When running with auto-helpers, we need to include the .hpp directories as things are imported without path + # e.g. "#include " and there is no guarantee for the location of these files + if (DEFINED UT_AUTO_HELPERS AND UT_AUTO_HELPERS) + foreach(SOURCE_FILE IN LISTS SOURCE_FILES) + get_filename_component(SOURCE_EXT "${SOURCE_FILE}" LAST_EXT) + get_filename_component(SOURCE_DIR "${SOURCE_FILE}" DIRECTORY) + if (SOURCE_EXT STREQUAL ".cpp" AND NOT SOURCE_DIR IN_LIST UT_INCLUDE_DIRECTORIES) + list(APPEND UT_INCLUDE_DIRECTORIES "${SOURCE_DIR}") + endif() + endforeach() + endif() + target_include_directories("${UT_EXE_NAME}" PRIVATE ${UT_INCLUDE_DIRECTORIES}) +endfunction(ut_setup_unit_test_include_directories) #### -# Dict function `ut_add_module_target`: +# Function `ut_add_module_target`: # # Creates each module's coverage targets. Note: only run for "BUILD_TESTING=ON" builds. # @@ -61,7 +86,7 @@ function(ut_add_module_target MODULE_NAME TARGET_NAME SOURCE_FILES DEPENDENCIES) resolve_dependencies(RESOLVED gtest_main ${DEPENDENCIES} ${AC_DEPENDENCIES}) build_setup_build_module("${UT_EXE_NAME}" "${SOURCE_FILES}" "${AC_GENERATED}" "${AC_SOURCES}" "${RESOLVED}") - target_include_directories("${UT_EXE_NAME}" PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") + ut_setup_unit_test_include_directories("${UT_EXE_NAME}" "${SOURCE_FILES}") add_test(NAME ${UT_EXE_NAME} COMMAND ${UT_EXE_NAME}) # Create a module-level target if not already done diff --git a/cmake/test/data/TestDeployment/settings.ini b/cmake/test/data/TestDeployment/settings.ini new file mode 100644 index 0000000000..2a275d7277 --- /dev/null +++ b/cmake/test/data/TestDeployment/settings.ini @@ -0,0 +1,4 @@ +[fprime] +framework_path: ../../../.. +library_locations: ../test-fprime-library:../test-fprime-library2 +project_root: .. diff --git a/cmake/test/src/test_unittests.py b/cmake/test/src/test_unittests.py index c287447128..8dd9f0f3ea 100644 --- a/cmake/test/src/test_unittests.py +++ b/cmake/test/src/test_unittests.py @@ -49,7 +49,6 @@ "Svc_FileUplink_ut_exe", "Svc_Framer_ut_exe", "Svc_GenericHub_ut_exe", - "Svc_GenericRepeater_ut_exe", "Svc_GroundInterface_ut_exe", "Svc_Health_ut_exe", "Svc_LinuxTime_ut_exe", diff --git a/cmake/toolchain/raspberrypi.cmake b/cmake/toolchain/raspberrypi.cmake index 4ae1b7f846..799ec18fa1 100644 --- a/cmake/toolchain/raspberrypi.cmake +++ b/cmake/toolchain/raspberrypi.cmake @@ -1,41 +1,35 @@ #### # Raspberry PI Toolchain # -# A toolchain file for the raspberrypi. This toolchain can be used to build against the raspberry pi embedded Linux -# target. In order to use this toolchain, the raspberry pi build tools should be cloned onto a Linux build host. These -# tools are available at: [https://github.com/raspberrypi/tools](https://github.com/raspberrypi/tools) -# -# Typically these tools are cloned to `/opt/rpi/`. If they are cloned elsewhere, the user must set the environment -# variable `RPI_TOOLCHAIN_DIR` to the full path to the `arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf` directory before -# running CMake or `fprime-util generate`. -# -# e.g. should the user install the tools in ``/home/user1` then the environment variable might be set using -# `export RPI_TOOLCHAIN_DIR=/home/user/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/` +# This is a toolchain for the Raspberry Pi. This toolchain can be used ot build +# against the Raspberry Pi embedded Linux target. In order to use this toolchain, +# the Raspberry Pi cross-compiler should be installed on a Linux host. These +# tools are installable as follows: +# sudo apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf gdb-multiarch #### -# Set system name -set(CMAKE_SYSTEM_NAME "Linux") -set(CMAKE_SYSTEM_PROCESSOR "arm") -# Location of pi toolchain -set(RPI_TOOLCHAIN "$ENV{RPI_TOOLCHAIN_DIR}") -if ("${RPI_TOOLCHAIN}" STREQUAL "") - set(RPI_TOOLCHAIN "/opt/rpi/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf") -endif() -# Check toolchain directory exists -IF(NOT EXISTS "${RPI_TOOLCHAIN}") - message(FATAL_ERROR "RPI toolchain not found at ${RPI_TOOLCHAIN}. Install it, set RPI_TOOLCHAIN_DIR environment variable, or choose another toolchain") +# Set the system information +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR arm) +set(CMAKE_SYSTEM_VERSION 1) +# Configure the find commands for cross-compiling: tools from host, libraries, includes, and packages from cross-compiler/sysroot +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +# Check CMake sysroot +if (DEFINED CMAKE_SYSROOT) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT} ) endif() -message(STATUS "Using RPI toolchain at: ${RPI_TOOLCHAIN}") -# specify the cross compiler -set(CMAKE_C_COMPILER "${RPI_TOOLCHAIN}/bin/arm-linux-gnueabihf-gcc") -set(CMAKE_CXX_COMPILER "${RPI_TOOLCHAIN}/bin/arm-linux-gnueabihf-g++") -# where is the target environment -set(CMAKE_FIND_ROOT_PATH "${RPI_TOOLCHAIN}") +# Set the GNU ARM toolchain +find_program(CMAKE_AR NAMES arm-linux-gnueabihf-ar PATHS ENV RPI_TOOLCHAIN_DIR PATH_SUFFIXES bin REQUIRED) +find_program(CMAKE_C_COMPILER NAMES arm-linux-gnueabihf-gcc PATHS ENV RPI_TOOLCHAIN_DIR PATH_SUFFIXES bin REQUIRED) +find_program(CMAKE_CXX_COMPILER NAMES arm-linux-gnueabihf-g++ PATHS ENV RPI_TOOLCHAIN_DIR PATH_SUFFIXES bin REQUIRED) +message(STATUS "[arm-linux] C Compiler: ${CMAKE_C_COMPILER}") +message(STATUS "[arm-linux] CXX Compiler: ${CMAKE_CXX_COMPILER}") +find_program(CMAKE_ASM_COMPILER NAMES arm-linux-gnueabihf-as PATHS ENV RPI_TOOLCHAIN_DIR PATH_SUFFIXES bin REQUIRED) +find_program(CMAKE_OBJCOPY NAMES arm-linux-gnueabihf-objcopy PATHS ENV RPI_TOOLCHAIN_DIR PATH_SUFFIXES bin REQUIRED) +find_program(CMAKE_OBJDUMP NAMES arm-linux-gnueabihf-objdump PATHS ENV RPI_TOOLCHAIN_DIR PATH_SUFFIXES bin REQUIRED) -# search for programs in the build host directories -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -# for libraries and headers in the target directories -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/cmake/utilities.cmake b/cmake/utilities.cmake index 0435934d66..5dcff4e9f3 100644 --- a/cmake/utilities.cmake +++ b/cmake/utilities.cmake @@ -186,7 +186,7 @@ endfunction(ends_with) #### function(init_variables) foreach (VARIABLE IN LISTS ARGN) - set(${VARIABLE} PARENT_SCOPE) + set(${VARIABLE} "" PARENT_SCOPE) endforeach() endfunction(init_variables) @@ -385,6 +385,22 @@ function (read_from_lines CONTENT) endforeach() endfunction() +#### +# Function `full_path_from_build_relative_path`: +# +# Creates a full path from the shortened build-relative path. +# -**SHORT_PATH:** build relative path +# Return: full path from relative path +#### +function(full_path_from_build_relative_path SHORT_PATH OUTPUT_VARIABLE) + foreach(FPRIME_LOCATION IN LISTS FPRIME_BUILD_LOCATIONS) + if (EXISTS "${FPRIME_LOCATION}/${SHORT_PATH}") + set("${OUTPUT_VARIABLE}" "${FPRIME_LOCATION}/${SHORT_PATH}" PARENT_SCOPE) + return() + endif() + endforeach() + set("${OUTPUT_VARIABLE}" "" PARENT_SCOPE) +endfunction(full_path_from_build_relative_path) #### # Function `get_nearest_build_root`: @@ -485,19 +501,23 @@ function(get_expected_tool_version VID FILL_VARIABLE) endfunction(get_expected_tool_version) #### -# Function `set_hash_flag`: +# Function `set_assert_flags`: # # Adds a -DASSERT_FILE_ID=(First 8 digits of MD5) to each source file, and records the output in -# hashes.txt. This allows for asserts on file ID not string. +# hashes.txt. This allows for asserts on file ID not string. Also adds the -DASSERT_RELATIVE_PATH +# flag for handling relative path asserts. #### -function(set_hash_flag SRC) +function(set_assert_flags SRC) get_filename_component(FPRIME_CLOSEST_BUILD_ROOT_ABS "${FPRIME_CLOSEST_BUILD_ROOT}" ABSOLUTE) + get_filename_component(FPRIME_PROJECT_ROOT_ABS "${FPRIME_PROJECT_ROOT}" ABSOLUTE) string(REPLACE "${FPRIME_CLOSEST_BUILD_ROOT_ABS}/" "" SHORT_SRC "${SRC}") + string(REPLACE "${FPRIME_PROJECT_ROOT_ABS}/" "" SHORT_SRC "${SHORT_SRC}") + string(MD5 HASH_VAL "${SHORT_SRC}") string(SUBSTRING "${HASH_VAL}" 0 8 HASH_32) file(APPEND "${CMAKE_BINARY_DIR}/hashes.txt" "${SHORT_SRC}: 0x${HASH_32}\n") - SET_SOURCE_FILES_PROPERTIES(${SRC} PROPERTIES COMPILE_FLAGS -DASSERT_FILE_ID="0x${HASH_32}") -endfunction(set_hash_flag) + SET_SOURCE_FILES_PROPERTIES(${SRC} PROPERTIES COMPILE_FLAGS "-DASSERT_FILE_ID=0x${HASH_32} -DASSERT_RELATIVE_PATH='\"${SHORT_SRC}\"'") +endfunction(set_assert_flags) #### diff --git a/config/AcConstants.fpp b/config/AcConstants.fpp index f3febe1e45..c3a2e81da2 100644 --- a/config/AcConstants.fpp +++ b/config/AcConstants.fpp @@ -15,9 +15,6 @@ constant CmdDispatcherComponentCommandPorts = 30 @ Used for uplink/sequencer buffer/response ports constant CmdDispatcherSequencePorts = 5 -@ Outputs from the generic repeater -constant GenericRepeaterOutputPorts = 2 - @ Number of static memory allocations constant StaticMemoryAllocations = 4 @@ -27,6 +24,15 @@ constant HealthPingPorts = 25 @ Used for broadcasting completed file downlinks constant FileDownCompletePorts = 1 +@ Used for number of Fw::Com type ports supported by Svc::ComQueue +constant ComQueueComPorts = 2 + +@ Used for number of Fw::Buffer type ports supported by Svc::ComQueue +constant ComQueueBufferPorts = 1 + +@ Used for maximum number of connected buffer repeater consumers +constant BufferRepeaterOutputPorts = 10 + # ---------------------------------------------------------------------- # Hub connections. Connections on all deployments should mirror these settings. # ---------------------------------------------------------------------- diff --git a/config/AcConstants.ini b/config/AcConstants.ini index a3de80c54b..da417a0c2c 100644 --- a/config/AcConstants.ini +++ b/config/AcConstants.ini @@ -16,8 +16,5 @@ GenericHubOutputPorts = 10 GenericHubInputBuffers = 10 GenericHubOutputBuffers = 10 -; Outputs from the generic repeater. -GenericRepeaterOutputPorts = 2 - StaticMemoryAllocations = 4 \ No newline at end of file diff --git a/config/ActiveLoggerImplCfg.hpp b/config/ActiveLoggerImplCfg.hpp index 9639304977..e24f973b51 100644 --- a/config/ActiveLoggerImplCfg.hpp +++ b/config/ActiveLoggerImplCfg.hpp @@ -8,8 +8,6 @@ #ifndef ACTIVELOGGER_ACTIVELOGGERIMPLCFG_HPP_ #define ACTIVELOGGER_ACTIVELOGGERIMPLCFG_HPP_ -#include - // set default filters enum { diff --git a/config/BufferManagerComponentImplCfg.hpp b/config/BufferManagerComponentImplCfg.hpp index 08f271e46e..c3b4277953 100644 --- a/config/BufferManagerComponentImplCfg.hpp +++ b/config/BufferManagerComponentImplCfg.hpp @@ -1,7 +1,7 @@ #ifndef __BUFFERMANAGERCOMPONENTIMPLCFG_HPP__ #define __BUFFERMANAGERCOMPONENTIMPLCFG_HPP__ -#include +#include namespace Svc { static const NATIVE_UINT_TYPE BUFFERMGR_MAX_NUM_BINS = 10; diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt new file mode 100644 index 0000000000..643fd4f29a --- /dev/null +++ b/config/CMakeLists.txt @@ -0,0 +1,10 @@ +#### +# config/CMakeLists.txt: +# +# Sets a list of source files for cmake to process as part of autocoding. +#### +set(SOURCE_FILES + "${CMAKE_CURRENT_LIST_DIR}/FpConfig.fpp" + "${CMAKE_CURRENT_LIST_DIR}/AcConstants.fpp" +) +register_fprime_module(config) diff --git a/config/DeframerCfg.hpp b/config/DeframerCfg.hpp index 7f3badc89d..64eed47649 100644 --- a/config/DeframerCfg.hpp +++ b/config/DeframerCfg.hpp @@ -7,7 +7,7 @@ #ifndef SVC_DEFRAMER_CFG_HPP #define SVC_DEFRAMER_CFG_HPP -#include +#include namespace Svc { namespace DeframerCfg { diff --git a/config/FileDownlinkCfg.hpp b/config/FileDownlinkCfg.hpp index 8c39633395..113e6e10e1 100644 --- a/config/FileDownlinkCfg.hpp +++ b/config/FileDownlinkCfg.hpp @@ -6,7 +6,7 @@ #ifndef SVC_FILEDOWNLINK_FILEDOWNLINKCFG_HPP_ #define SVC_FILEDOWNLINK_FILEDOWNLINKCFG_HPP_ -#include +#include namespace Svc { // If this is set to true, the run handler will look to diff --git a/config/FpConfig.fpp b/config/FpConfig.fpp index 2f6a848e77..5341ba661b 100644 --- a/config/FpConfig.fpp +++ b/config/FpConfig.fpp @@ -1,7 +1,15 @@ -type FwEventIdType +type FwBuffSizeType type FwChanIdType +type FwEnumStoreType +type FwEventIdType +type FwIndexType type FwOpcodeType +type FwPacketDescriptorType type FwPrmIdType +type FwSizeType +type FwTimeBaseStoreType +type FwTimeContextStoreType +type FwTlmPacketizeIdType type NATIVE_INT_TYPE type NATIVE_UINT_TYPE type POINTER_CAST diff --git a/config/FpConfig.h b/config/FpConfig.h new file mode 100644 index 0000000000..12e92bd7d6 --- /dev/null +++ b/config/FpConfig.h @@ -0,0 +1,342 @@ +/** + * \file: FpConfig.h + * \author T. Canham, mstarch + * \brief C-compatible configuration header for fprime configuration + * + * \copyright + * Copyright 2009-2015, by the California Institute of Technology. + * ALL RIGHTS RESERVED. United States Government Sponsorship + * acknowledged. + */ +#include +#ifndef FPCONFIG_H_ +#define FPCONFIG_H_ + +typedef PlatformIndexType FwIndexType; +#define PRI_FwIndexType PRI_PlatformIndexType + +typedef PlatformSizeType FwSizeType; +#define PRI_FwSizeType PRI_PlatformSizeType + +typedef PlatformAssertArgType FwAssertArgType; +#define PRI_FwAssertArgType PRI_PlatformAssertArgType + +typedef PlatformIntType FwNativeIntType; +#define PRI_FwNativeIntType PRI_PlatformIntType + +typedef PlatformUIntType FwNativeUIntType; +#define PRI_FwNativeUIntType PRI_PlatformUIntType + +typedef U16 FwBuffSizeType; +#define PRI_FwBuffSizeType PRIu16 + +typedef I32 FwEnumStoreType; +#define PRI_FwEnumStoreType PRId32 + +// Define enumeration for Time base types +// Note: maintaining C-style +typedef enum { + TB_NONE, //!< No time base has been established + TB_PROC_TIME, //!< Indicates time is processor cycle time. Not tied to external time + TB_WORKSTATION_TIME, //!< Time as reported on workstation where software is running. For testing. + TB_DONT_CARE = + 0xFFFF //!< Don't care value for sequences. If FwTimeBaseStoreType is changed, value should be changed +} TimeBase; +#define FW_CONTEXT_DONT_CARE 0xFF //!< Don't care value for time contexts in sequences + +typedef U16 FwTimeBaseStoreType; +#define PRI_FwTimeBaseStoreType PRIu16 + +typedef U8 FwTimeContextStoreType; +#define PRI_FwTimeContextStoreType PRIu8 + +typedef U32 FwPacketDescriptorType; +#define PRI_FwPacketDescriptorType PRIu32 + +typedef U32 FwOpcodeType; +#define PRI_FwOpcodeType PRIu32 + +typedef U32 FwChanIdType; +#define PRI_FwChanIdType PRIu32 + +typedef U32 FwEventIdType; +#define PRI_FwEventIdType PRIu32 + +typedef U32 FwPrmIdType; +#define PRI_FwPrmIdType PRIu32 + +typedef U16 FwTlmPacketizeIdType; +#define PRI_FwTlmPacketizeIdType PRIu16 + +// Boolean values for serialization +#ifndef FW_SERIALIZE_TRUE_VALUE +#define FW_SERIALIZE_TRUE_VALUE (0xFF) //!< Value encoded during serialization for boolean true +#endif + +#ifndef FW_SERIALIZE_FALSE_VALUE +#define FW_SERIALIZE_FALSE_VALUE (0x00) //!< Value encoded during serialization for boolean false +#endif + +// Allow objects to have names. Allocates storage for each instance +#ifndef FW_OBJECT_NAMES +#define FW_OBJECT_NAMES \ + 1 //!< Indicates whether or not object names are stored (more memory, can be used for tracking objects) +#endif + +// To reduce binary size, FW_OPTIONAL_NAME() can be used to substitute strings with an empty string +// when running with FW_OBJECT_NAMES disabled +#if FW_OBJECT_NAMES == 1 +#define FW_OPTIONAL_NAME(name) name +#else +#define FW_OPTIONAL_NAME(name) "" +#endif + +// Add methods to query an object about its name. Can be overridden by derived classes +// For FW_OBJECT_TO_STRING to work, FW_OBJECT_NAMES must be enabled +#if FW_OBJECT_NAMES == 1 +#ifndef FW_OBJECT_TO_STRING +#define FW_OBJECT_TO_STRING \ + 1 //!< Indicates whether or not generated objects have toString() methods to dump internals (more code) +#endif +#else +#define FW_OBJECT_TO_STRING 0 +#endif + +// Adds the ability for all component related objects to register +// centrally. +#ifndef FW_OBJECT_REGISTRATION +#define FW_OBJECT_REGISTRATION \ + 1 //!< Indicates whether or not objects can register themselves (more code, more object tracking) +#endif + +#ifndef FW_QUEUE_REGISTRATION +#define FW_QUEUE_REGISTRATION 1 //!< Indicates whether or not queue registration is used +#endif + +#ifndef FW_BAREMETAL_SCHEDULER +#define FW_BAREMETAL_SCHEDULER \ + 0 //!< Indicates whether or not a baremetal scheduler should be used. Alternatively the Os scheduler is used. +#endif + +// Port Facilities + +// This allows tracing calls through ports for debugging +#ifndef FW_PORT_TRACING +#define FW_PORT_TRACING 1 //!< Indicates whether port calls are traced (more code, more visibility into execution) +#endif + +// This generates code to connect to serialized ports +#ifndef FW_PORT_SERIALIZATION +#define FW_PORT_SERIALIZATION \ + 1 //!< Indicates whether there is code in ports to serialize the call (more code, but ability to serialize calls + //!< for multi-note systems) +#endif + +// Component Facilities + +// Serialization + +// Add a type id when serialization is done. More storage, +// but better detection of errors +// TODO: Not working yet + +#ifndef FW_SERIALIZATION_TYPE_ID +#define FW_SERIALIZATION_TYPE_ID \ + 0 //!< Indicates if type id is stored when type is serialized. (More storage, but more type safety) +#endif + +// Number of bytes to use for serialization IDs. More +// bytes is more storage, but greater number of IDs +#if FW_SERIALIZATION_TYPE_ID +#ifndef FW_SERIALIZATION_TYPE_ID_BYTES +#define FW_SERIALIZATION_TYPE_ID_BYTES 4 //!< Number of bytes used to represent type id - more bytes, more ids +#endif +#endif + +// Set assertion form. Options: +// 1. FW_NO_ASSERT: assertions are compiled out +// 2. FW_FILEID_ASSERT: asserts report a file CRC and line number +// 3. FW_FILENAME_ASSERT: asserts report a file path (__FILE__) and line number +// 4. FW_RELATIVE_PATH_ASSERT: asserts report a relative path within F´ or F´ library and line number +#define FW_ASSERT_DFL_MSG_LEN 256 //!< Maximum assert message length when using the default assert handler +#ifndef FW_ASSERT_LEVEL +#define FW_ASSERT_LEVEL FW_FILENAME_ASSERT //!< Defines the type of assert used +#endif + +// Define max length of assert string +#ifndef FW_ASSERT_TEXT_SIZE +#define FW_ASSERT_TEXT_SIZE 120 //!< Size of string used to store assert description +#endif + +// Adjust various configuration parameters in the architecture. Some of the above enables may disable some of the values + +// The size of the object name stored in the object base class. Larger names will be truncated. +#if FW_OBJECT_NAMES +#ifndef FW_OBJ_NAME_MAX_SIZE +#define FW_OBJ_NAME_MAX_SIZE \ + 80 //!< Size of object name (if object names enabled). AC Limits to 80, truncation occurs above 80. +#endif +#endif + +// When querying an object as to an object-specific description, this specifies the size of the buffer to store the +// description. +#if FW_OBJECT_TO_STRING +#ifndef FW_OBJ_TO_STRING_BUFFER_SIZE +#define FW_OBJ_TO_STRING_BUFFER_SIZE 255 //!< Size of string storing toString() text +#endif +#endif + +#if FW_OBJECT_REGISTRATION +// For the simple object registry provided with the framework, this specifies how many objects the registry will store. +#ifndef FW_OBJ_SIMPLE_REG_ENTRIES +#define FW_OBJ_SIMPLE_REG_ENTRIES 500 //!< Number of objects stored in simple object registry +#endif +// When dumping the contents of the registry, this specifies the size of the buffer used to store object names. Should +// be >= FW_OBJ_NAME_MAX_SIZE. +#ifndef FW_OBJ_SIMPLE_REG_BUFF_SIZE +#define FW_OBJ_SIMPLE_REG_BUFF_SIZE 255 //!< Size of object registry dump string +#endif +#endif + +#if FW_QUEUE_REGISTRATION +// For the simple queue registry provided with the framework, this specifies how many queues the registry will store. +#ifndef FW_QUEUE_SIMPLE_QUEUE_ENTRIES +#define FW_QUEUE_SIMPLE_QUEUE_ENTRIES 100 //!< Number of queues stored in simple queue registry +#endif +#endif + +// Specifies the size of the string holding the queue name for queues +#ifndef FW_QUEUE_NAME_MAX_SIZE +#define FW_QUEUE_NAME_MAX_SIZE 80 //!< Max size of message queue name +#endif + +// Specifies the size of the string holding the task name for active components and tasks +#ifndef FW_TASK_NAME_MAX_SIZE +#define FW_TASK_NAME_MAX_SIZE 80 //!< Max size of task name +#endif + +// Specifies the size of the buffer that contains a communications packet. +#ifndef FW_COM_BUFFER_MAX_SIZE +#define FW_COM_BUFFER_MAX_SIZE 128 //!< Max size of Fw::Com buffer +#endif + +// Specifies the size of the buffer that contains the serialized command arguments. + +#ifndef FW_CMD_ARG_BUFFER_MAX_SIZE +#define FW_CMD_ARG_BUFFER_MAX_SIZE (FW_COM_BUFFER_MAX_SIZE - sizeof(FwOpcodeType) - sizeof(FwPacketDescriptorType)) +#endif + +// Specifies the maximum size of a string in a command argument +#ifndef FW_CMD_STRING_MAX_SIZE +#define FW_CMD_STRING_MAX_SIZE 40 //!< Max character size of command string arguments +#endif + +// Normally when a command is deserialized, the handler checks to see if there are any leftover +// bytes in the buffer. If there are, it assumes that the command was corrupted somehow since +// the serialized size should match the serialized size of the argument list. In some cases, +// command buffers are padded so the data can be larger than the serialized size of the command. +// Setting the below to zero will disable the check at the cost of not detecting commands that +// are too large. +#ifndef FW_CMD_CHECK_RESIDUAL +#define FW_CMD_CHECK_RESIDUAL 1 //!< Check for leftover command bytes +#endif + +// Specifies the size of the buffer that contains the serialized log arguments. +#ifndef FW_LOG_BUFFER_MAX_SIZE +#define FW_LOG_BUFFER_MAX_SIZE (FW_COM_BUFFER_MAX_SIZE - sizeof(FwEventIdType) - sizeof(FwPacketDescriptorType)) +#endif + +// Specifies the maximum size of a string in a log event +#ifndef FW_LOG_STRING_MAX_SIZE +#define FW_LOG_STRING_MAX_SIZE 100 //!< Max size of log string parameter type +#endif + +// Specifies the size of the buffer that contains the serialized telemetry value. +#ifndef FW_TLM_BUFFER_MAX_SIZE +#define FW_TLM_BUFFER_MAX_SIZE (FW_COM_BUFFER_MAX_SIZE - sizeof(FwChanIdType) - sizeof(FwPacketDescriptorType)) +#endif + +// Specifies the maximum size of a string in a telemetry channel +#ifndef FW_TLM_STRING_MAX_SIZE +#define FW_TLM_STRING_MAX_SIZE 40 //!< Max size of channelized telemetry string type +#endif + +// Specifies the size of the buffer that contains the serialized parameter value. +#ifndef FW_PARAM_BUFFER_MAX_SIZE +#define FW_PARAM_BUFFER_MAX_SIZE (FW_COM_BUFFER_MAX_SIZE - sizeof(FwPrmIdType) - sizeof(FwPacketDescriptorType)) +#endif + +// Specifies the maximum size of a string in a parameter +#ifndef FW_PARAM_STRING_MAX_SIZE +#define FW_PARAM_STRING_MAX_SIZE 40 //!< Max size of parameter string type +#endif + +// Specifies the maximum size of a file upload chunk +#ifndef FW_FILE_BUFFER_MAX_SIZE +#define FW_FILE_BUFFER_MAX_SIZE 255 //!< Max size of file buffer (i.e. chunk of file) +#endif + +// Specifies the maximum size of a string in an interface call +#ifndef FW_INTERNAL_INTERFACE_STRING_MAX_SIZE +#define FW_INTERNAL_INTERFACE_STRING_MAX_SIZE 256 //!< Max size of interface string parameter type +#endif + +// enables text logging of events as well as data logging. Adds a second logging port for text output. +#ifndef FW_ENABLE_TEXT_LOGGING +#define FW_ENABLE_TEXT_LOGGING 1 //!< Indicates whether text logging is turned on +#endif + +// Define the size of the text log string buffer. Should be large enough for format string and arguments +#ifndef FW_LOG_TEXT_BUFFER_SIZE +#define FW_LOG_TEXT_BUFFER_SIZE 256 //!< Max size of string for text log message +#endif + +// Define if serializables have toString() method. Turning off will save code space and +// string constants. Must be enabled if text logging enabled +#ifndef FW_SERIALIZABLE_TO_STRING +#define FW_SERIALIZABLE_TO_STRING 1 //!< Indicates if autocoded serializables have toString() methods +#endif + +#if FW_SERIALIZABLE_TO_STRING +#ifndef FW_SERIALIZABLE_TO_STRING_BUFFER_SIZE +#define FW_SERIALIZABLE_TO_STRING_BUFFER_SIZE 255 //!< Size of string to store toString() string output +#endif +#endif + +// Define if arrays have toString() method. +#ifndef FW_ARRAY_TO_STRING +#define FW_ARRAY_TO_STRING 1 //!< Indicates if autocoded arrays have toString() methods +#endif + +#if FW_ARRAY_TO_STRING +#ifndef FW_ARRAY_TO_STRING_BUFFER_SIZE +#define FW_ARRAY_TO_STRING_BUFFER_SIZE 256 //!< Size of string to store toString() string output +#endif +#endif + +// Some settings to enable AMPCS compatibility. This breaks regular ISF GUI compatibility +#ifndef FW_AMPCS_COMPATIBLE +#define FW_AMPCS_COMPATIBLE 0 //!< Whether or not JPL AMPCS ground system support is enabled. +#endif + +// These settings configure whether or not the timebase and context values for the Fw::Time +// class are used. Some systems may not use or need those fields + +#ifndef FW_USE_TIME_BASE +#define FW_USE_TIME_BASE 1 //!< Whether or not to use the time base +#endif + +#ifndef FW_USE_TIME_CONTEXT +#define FW_USE_TIME_CONTEXT 1 //!< Whether or not to serialize the time context +#endif +// +// These defines used for the FilepathCharString type + +#ifndef FW_FIXED_LENGTH_STRING_SIZE +#define FW_FIXED_LENGTH_STRING_SIZE 256 //!< Character array size for the filepath character type +#endif + +// *** NOTE configuration checks are in Fw/Cfg/ConfigCheck.cpp in order to have +// the type definitions in Fw/Types/BasicTypes available. + +#endif diff --git a/config/FpConfig.hpp b/config/FpConfig.hpp index 3224a25264..cc4b89d27c 100644 --- a/config/FpConfig.hpp +++ b/config/FpConfig.hpp @@ -1,361 +1,14 @@ /** - * \file - * \author T. Canham - * \brief ISF configuration file + * \file: FpConfig.hpp + * \author T. Canham, mstarch + * \brief C++-compatible configuration header for fprime configuration * * \copyright * Copyright 2009-2015, by the California Institute of Technology. * ALL RIGHTS RESERVED. United States Government Sponsorship * acknowledged. - *

*/ -#ifndef _FW_CONFIG_HPP_ -#define _FW_CONFIG_HPP_ - -// To enable various facilities, set the below to 0 or 1. If it is set in compiler flags, -// these defaults will be overridden - -// Available types - -#ifndef FW_HAS_64_BIT -#define FW_HAS_64_BIT 1 //!< Architecture supports 64 bit integers -#endif - -#ifndef FW_HAS_32_BIT -#define FW_HAS_32_BIT 1 //!< Architecture supports 32 bit integers -#endif - -#ifndef FW_HAS_16_BIT -#define FW_HAS_16_BIT 1 //!< Architecture supports 16 bit integers -#endif - -#ifndef FW_HAS_F64 -#define FW_HAS_F64 1 //!< Architecture supports 64 bit floating point numbers -#endif - -// Boolean values for serialization - -#ifndef FW_SERIALIZE_TRUE_VALUE -#define FW_SERIALIZE_TRUE_VALUE (0xFF) //!< Value encoded during serialization for boolean true -#endif - -#ifndef FW_SERIALIZE_FALSE_VALUE -#define FW_SERIALIZE_FALSE_VALUE (0x00) //!< Value encoded during serialization for boolean false -#endif - -#ifndef AssertArg -#define AssertArg U32 -#endif - -// typedefs for various serialization items -// *** NOTE *** Changes here MUST match GSE in order to decode the values correctly - -#ifndef FwPacketDescriptorType -#define FwPacketDescriptorType U32 //!< Type representation for a packet descriptor -#endif - -#ifndef FwOpcodeType -#define FwOpcodeType U32 //!< Type representation for a command opcode -#endif - -#ifndef FwChanIdType -#define FwChanIdType U32 //!< Type representation for a channel id -#endif - -#ifndef FwEventIdType -#define FwEventIdType U32 //!< Type representation for an event id -#endif - -#ifndef FwPrmIdType -#define FwPrmIdType U32 //!< Type representation for a parameter id -#endif - -#ifndef FwTlmPacketizeIdType -#define FwTlmPacketizeIdType U16 //!< Packetized telemetry packet id -#endif - -// How big the size of a buffer (or string) representation is -#ifndef FwBuffSizeType -#define FwBuffSizeType U16 //!< Type representation for storing a buffer or string size -#endif - -// How many bits are used to store an enumeration defined in XML during serialization. -#ifndef FwEnumStoreType -#define FwEnumStoreType I32 //!< Type representation for an enumeration value -#endif - -// Object facilities - -// Allow objects to have names. Allocates storage for each instance -#ifndef FW_OBJECT_NAMES -#define FW_OBJECT_NAMES 1 //!< Indicates whether or not object names are stored (more memory, can be used for tracking objects) -#endif - -// To reduce binary size, FW_OPTIONAL_NAME() can be used to substitute strings with an empty string -// when running with FW_OBJECT_NAMES disabled -#if FW_OBJECT_NAMES == 1 - #define FW_OPTIONAL_NAME(name) name -#else - #define FW_OPTIONAL_NAME(name) "" -#endif - -// Add methods to query an object about its name. Can be overridden by derived classes -// For FW_OBJECT_TO_STRING to work, FW_OBJECT_NAMES must be enabled -#if FW_OBJECT_NAMES == 1 - #ifndef FW_OBJECT_TO_STRING - #define FW_OBJECT_TO_STRING 1 //!< Indicates whether or not generated objects have toString() methods to dump internals (more code) - #endif -#else - #define FW_OBJECT_TO_STRING 0 -#endif - -// Adds the ability for all component related objects to register -// centrally. -#ifndef FW_OBJECT_REGISTRATION -#define FW_OBJECT_REGISTRATION 1 //!< Indicates whether or not objects can register themselves (more code, more object tracking) -#endif - -#ifndef FW_QUEUE_REGISTRATION -#define FW_QUEUE_REGISTRATION 1 //!< Indicates whether or not queue registration is used -#endif - -#ifndef FW_BAREMETAL_SCHEDULER -#define FW_BAREMETAL_SCHEDULER 0 //!< Indicates whether or not a baremetal scheduler should be used. Alternatively the Os scheduler is used. -#endif - -// Port Facilities - -// This allows tracing calls through ports for debugging -#ifndef FW_PORT_TRACING -#define FW_PORT_TRACING 1 //!< Indicates whether port calls are traced (more code, more visibility into execution) -#endif - -// This generates code to connect to serialized ports -#ifndef FW_PORT_SERIALIZATION -#define FW_PORT_SERIALIZATION 1 //!< Indicates whether there is code in ports to serialize the call (more code, but ability to serialize calls for multi-note systems) -#endif - -// Component Facilities - -// Serialization - -// Add a type id when serialization is done. More storage, -// but better detection of errors -// TODO: Not working yet - -#ifndef FW_SERIALIZATION_TYPE_ID -#define FW_SERIALIZATION_TYPE_ID 0 //!< Indicates if type id is stored when type is serialized. (More storage, but more type safety) -#endif - -// Number of bytes to use for serialization IDs. More -// bytes is more storage, but greater number of IDs -#if FW_SERIALIZATION_TYPE_ID - #ifndef FW_SERIALIZATION_TYPE_ID_BYTES - #define FW_SERIALIZATION_TYPE_ID_BYTES 4 //!< Number of bytes used to represent type id - more bytes, more ids - #endif -#endif - -// Turn asserts on or off - -#define FW_NO_ASSERT 1 //!< Asserts turned off -#define FW_FILEID_ASSERT 2 //!< File ID used - requires -DASSERT_FILE_ID=somevalue to be set on the compile command line -#define FW_FILENAME_ASSERT 3 //!< Uses the file name in the assert - image stores filenames -#define FW_ASSERT_DFL_MSG_LEN 256 //!< Maximum assert message length when using the default assert handler - -#ifndef FW_ASSERT_LEVEL -#define FW_ASSERT_LEVEL FW_FILENAME_ASSERT //!< Defines the type of assert used -#endif - -// Define max length of assert string -#ifndef FW_ASSERT_TEXT_SIZE -#define FW_ASSERT_TEXT_SIZE 120 //!< Size of string used to store assert description -#endif - -// Adjust various configuration parameters in the architecture. Some of the above enables may disable some of the values - -// The size of the object name stored in the object base class. Larger names will be truncated. -#if FW_OBJECT_NAMES - #ifndef FW_OBJ_NAME_MAX_SIZE - #define FW_OBJ_NAME_MAX_SIZE 80 //!< Size of object name (if object names enabled). AC Limits to 80, truncation occurs above 80. - #endif -#endif - -// When querying an object as to an object-specific description, this specifies the size of the buffer to store the description. -#if FW_OBJECT_TO_STRING - #ifndef FW_OBJ_TO_STRING_BUFFER_SIZE - #define FW_OBJ_TO_STRING_BUFFER_SIZE 255 //!< Size of string storing toString() text - #endif -#endif - -#if FW_OBJECT_REGISTRATION -// For the simple object registry provided with the framework, this specifies how many objects the registry will store. - #ifndef FW_OBJ_SIMPLE_REG_ENTRIES - #define FW_OBJ_SIMPLE_REG_ENTRIES 500 //!< Number of objects stored in simple object registry - #endif -// When dumping the contents of the registry, this specifies the size of the buffer used to store object names. Should be >= FW_OBJ_NAME_MAX_SIZE. - #ifndef FW_OBJ_SIMPLE_REG_BUFF_SIZE - #define FW_OBJ_SIMPLE_REG_BUFF_SIZE 255 //!< Size of object registry dump string - #endif -#endif - -#if FW_QUEUE_REGISTRATION -// For the simple queue registry provided with the framework, this specifies how many queues the registry will store. - #ifndef FW_QUEUE_SIMPLE_QUEUE_ENTRIES - #define FW_QUEUE_SIMPLE_QUEUE_ENTRIES 100 //!< Number of queues stored in simple queue registry - #endif -#endif - - -// Specifies the size of the string holding the queue name for queues -#ifndef FW_QUEUE_NAME_MAX_SIZE -#define FW_QUEUE_NAME_MAX_SIZE 80 //!< Max size of message queue name -#endif - -// Specifies the size of the string holding the task name for active components and tasks -#ifndef FW_TASK_NAME_MAX_SIZE -#define FW_TASK_NAME_MAX_SIZE 80 //!< Max size of task name -#endif - -// Specifies the size of the buffer that contains a communications packet. -#ifndef FW_COM_BUFFER_MAX_SIZE -#define FW_COM_BUFFER_MAX_SIZE 128 //!< Max size of Fw::Com buffer -#endif - -// Specifies the size of the buffer that contains the serialized command arguments. - -#ifndef FW_CMD_ARG_BUFFER_MAX_SIZE -#define FW_CMD_ARG_BUFFER_MAX_SIZE (FW_COM_BUFFER_MAX_SIZE - sizeof(FwOpcodeType) - sizeof(FwPacketDescriptorType)) -#endif - -// Specifies the maximum size of a string in a command argument -#ifndef FW_CMD_STRING_MAX_SIZE -#define FW_CMD_STRING_MAX_SIZE 40 //!< Max character size of command string arguments -#endif - -// Normally when a command is deserialized, the handler checks to see if there are any leftover -// bytes in the buffer. If there are, it assumes that the command was corrupted somehow since -// the serialized size should match the serialized size of the argument list. In some cases, -// command buffers are padded so the data can be larger than the serialized size of the command. -// Setting the below to zero will disable the check at the cost of not detecting commands that -// are too large. -#ifndef FW_CMD_CHECK_RESIDUAL -#define FW_CMD_CHECK_RESIDUAL 1 //!< Check for leftover command bytes -#endif - -// Specifies the size of the buffer that contains the serialized log arguments. -#ifndef FW_LOG_BUFFER_MAX_SIZE -#define FW_LOG_BUFFER_MAX_SIZE (FW_COM_BUFFER_MAX_SIZE - sizeof(FwEventIdType) - sizeof(FwPacketDescriptorType)) -#endif - -// Specifies the maximum size of a string in a log event -#ifndef FW_LOG_STRING_MAX_SIZE -#define FW_LOG_STRING_MAX_SIZE 100 //!< Max size of log string parameter type -#endif - -// Specifies the size of the buffer that contains the serialized telemetry value. -#ifndef FW_TLM_BUFFER_MAX_SIZE -#define FW_TLM_BUFFER_MAX_SIZE (FW_COM_BUFFER_MAX_SIZE - sizeof(FwChanIdType) - sizeof(FwPacketDescriptorType)) -#endif - -// Specifies the maximum size of a string in a telemetry channel -#ifndef FW_TLM_STRING_MAX_SIZE -#define FW_TLM_STRING_MAX_SIZE 40 //!< Max size of channelized telemetry string type -#endif - -// Specifies the size of the buffer that contains the serialized parameter value. -#ifndef FW_PARAM_BUFFER_MAX_SIZE -#define FW_PARAM_BUFFER_MAX_SIZE (FW_COM_BUFFER_MAX_SIZE - sizeof(FwPrmIdType) - sizeof(FwPacketDescriptorType)) -#endif - -// Specifies the maximum size of a string in a parameter -#ifndef FW_PARAM_STRING_MAX_SIZE -#define FW_PARAM_STRING_MAX_SIZE 40 //!< Max size of parameter string type -#endif - -// Specifies the maximum size of a file upload chunk -#ifndef FW_FILE_BUFFER_MAX_SIZE -#define FW_FILE_BUFFER_MAX_SIZE 255 //!< Max size of file buffer (i.e. chunk of file) -#endif - -// Specifies the maximum size of a string in an interface call -#ifndef FW_INTERNAL_INTERFACE_STRING_MAX_SIZE -#define FW_INTERNAL_INTERFACE_STRING_MAX_SIZE 256 //!< Max size of interface string parameter type -#endif - -// enables text logging of events as well as data logging. Adds a second logging port for text output. -#ifndef FW_ENABLE_TEXT_LOGGING -#define FW_ENABLE_TEXT_LOGGING 1 //!< Indicates whether text logging is turned on -#endif - - // Define the size of the text log string buffer. Should be large enough for format string and arguments -#ifndef FW_LOG_TEXT_BUFFER_SIZE -#define FW_LOG_TEXT_BUFFER_SIZE 256 //!< Max size of string for text log message -#endif - -// Define if serializables have toString() method. Turning off will save code space and -// string constants. Must be enabled if text logging enabled -#ifndef FW_SERIALIZABLE_TO_STRING -#define FW_SERIALIZABLE_TO_STRING 1 //!< Indicates if autocoded serializables have toString() methods -#endif - -#if FW_SERIALIZABLE_TO_STRING -#ifndef FW_SERIALIZABLE_TO_STRING_BUFFER_SIZE -#define FW_SERIALIZABLE_TO_STRING_BUFFER_SIZE 255 //!< Size of string to store toString() string output -#endif -#endif - -// Define if arrays have toString() method. -#ifndef FW_ARRAY_TO_STRING -#define FW_ARRAY_TO_STRING 1 //!< Indicates if autocoded arrays have toString() methods -#endif - -#if FW_ARRAY_TO_STRING -#ifndef FW_ARRAY_TO_STRING_BUFFER_SIZE -#define FW_ARRAY_TO_STRING_BUFFER_SIZE 256 //!< Size of string to store toString() string output -#endif -#endif - -// Some settings to enable AMPCS compatibility. This breaks regular ISF GUI compatibility -#ifndef FW_AMPCS_COMPATIBLE -#define FW_AMPCS_COMPATIBLE 0 //!< Whether or not JPL AMPCS ground system support is enabled. -#endif - -// Define enumeration for Time base types -enum TimeBase { - TB_NONE, //!< No time base has been established - TB_PROC_TIME, //!< Indicates time is processor cycle time. Not tied to external time - TB_WORKSTATION_TIME, //!< Time as reported on workstation where software is running. For testing. - TB_DONT_CARE = 0xFFFF //!< Don't care value for sequences. If FwTimeBaseStoreType is changed, value should be changed +#include +extern "C" { +#include }; - -// How many bits are used to store the time base -#ifndef FwTimeBaseStoreType -#define FwTimeBaseStoreType U16 //!< Storage conversion for time base in scripts/ground interface -#endif - -#ifndef FwTimeContextStoreType -#define FwTimeContextStoreType U8 //!< Storage conversion for time context in scripts/ground interface -#define FW_CONTEXT_DONT_CARE 0xFF //!< Don't care value for time contexts in sequences -#endif - -// These settings configure whether or not the timebase and context values for the Fw::Time -// class are used. Some systems may not use or need those fields - -#ifndef FW_USE_TIME_BASE -#define FW_USE_TIME_BASE 1 //!< Whether or not to use the time base -#endif - -#ifndef FW_USE_TIME_CONTEXT -#define FW_USE_TIME_CONTEXT 1 //!< Whether or not to serialize the time context -#endif -// -//These defines used for the FilepathCharString type - -#ifndef FW_FIXED_LENGTH_STRING_SIZE -#define FW_FIXED_LENGTH_STRING_SIZE 256 //!< Character array size for the filepath character type -#endif - -// *** NOTE configuration checks are in Fw/Cfg/ConfigCheck.cpp in order to have -// the type definitions in Fw/Types/BasicTypes available. - -#endif diff --git a/config/LinuxSerialDriverComponentImplCfg.hpp b/config/LinuxSerialDriverComponentImplCfg.hpp deleted file mode 100644 index f703e19c9c..0000000000 --- a/config/LinuxSerialDriverComponentImplCfg.hpp +++ /dev/null @@ -1,15 +0,0 @@ -/* - * LinuxSerialDriverComponentImplCfg.hpp - * - * Created on: Nov 29, 2016 - * Author: tcanham - */ - -#ifndef LINUXSERIALDRIVER_BLSPSERIALDRIVERCOMPONENTIMPLCFG_HPP_ -#define LINUXSERIALDRIVER_BLSPSERIALDRIVERCOMPONENTIMPLCFG_HPP_ - -enum { - DR_MAX_NUM_BUFFERS = 20, // Increasing this from 10 b/c RceAdapter couldn't always keep up with just 10 for reads -}; - -#endif /* LINUXSERIALDRIVER_BLSPSERIALDRIVERCOMPONENTIMPLCFG_HPP_ */ diff --git a/config/SocketIpDriverCfg.hpp b/config/SocketIpDriverCfg.hpp deleted file mode 100644 index 512da740c5..0000000000 --- a/config/SocketIpDriverCfg.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// ====================================================================== -// \title SocketIpDriverCfg.hpp -// \author mstarch -// \brief hpp file for SocketIpDriver component implementation class -// -// \copyright -// Copyright 2009-2015, by the California Institute of Technology. -// ALL RIGHTS RESERVED. United States Government Sponsorship -// acknowledged. -// -// ====================================================================== - -#ifndef REF_SOCKETIPDRIVERCFG_HPP -#define REF_SOCKETIPDRIVERCFG_HPP - -#define KEEPALIVE_DATA "sitting well" // Ground-based keepalive packet for filtering out packet - -enum SocketIpCfg { - SOCKET_TIMEOUT_SECONDS = 1, // Seconds component of timeout - SOCKET_TIMEOUT_MICROSECONDS = 0, // Milliseconds component of timeout - SOCKET_SEND_UDP = 1, // 0 - Send down using TCP, 1 - Send down using UDP - SOCKET_SEND_FLAGS = 0, // send, sendto FLAGS argument - SOCKET_RECV_FLAGS = 0, // recv FLAGS argument - RECONNECT_AUTOMATICALLY = 1, // Attempt to reconnect when a socket closes - MAX_SEND_ITERATIONS = 0xFFFF, // Maximum send iterations - MAX_RECV_BUFFER_SIZE = 2048, // Maximum and allocation size of the send buffer. TODO: use buffer manager - PRE_CONNECTION_RETRY_INTERVAL_MS = 1000, // Interval between connection retries before main recv thread starts - MAX_HOSTNAME_SIZE = 256 // Maximum stored hostname -}; - - - -#endif //REF_SOCKETIPDRIVERCFG_HPP diff --git a/config/TlmPacketizerCfg.hpp b/config/TlmPacketizerCfg.hpp new file mode 100644 index 0000000000..2b514374a9 --- /dev/null +++ b/config/TlmPacketizerCfg.hpp @@ -0,0 +1,43 @@ +/* + * TlmPacketizerComponentImplCfg.hpp + * + * Created on: Dec 10, 2017 + * Author: tim + */ + +// \copyright +// Copyright 2009-2015, by the California Institute of Technology. +// ALL RIGHTS RESERVED. United States Government Sponsorship +// acknowledged. + +#ifndef SVC_TLMPACKETIZER_TLMPACKETIZERCOMPONENTIMPLCFG_HPP_ +#define SVC_TLMPACKETIZER_TLMPACKETIZERCOMPONENTIMPLCFG_HPP_ + +#include + +namespace Svc { +static const NATIVE_UINT_TYPE MAX_PACKETIZER_PACKETS = 200; +static const NATIVE_UINT_TYPE TLMPACKETIZER_NUM_TLM_HASH_SLOTS = + 15; // !< Number of slots in the hash table. + // Works best when set to about twice the number of components producing telemetry +static const NATIVE_UINT_TYPE TLMPACKETIZER_HASH_MOD_VALUE = + 99; // !< The modulo value of the hashing function. + // Should be set to a little below the ID gaps to spread the entries around + +static const NATIVE_UINT_TYPE TLMPACKETIZER_HASH_BUCKETS = + 1000; // !< Buckets assignable to a hash slot. + // Buckets must be >= number of telemetry channels in system +static const NATIVE_UINT_TYPE TLMPACKETIZER_MAX_MISSING_TLM_CHECK = + 25; // !< Maximum number of missing telemetry channel checks + +// packet update mode +enum PacketUpdateMode { + PACKET_UPDATE_ALWAYS, // Always send packets, even if no changes to channel data + PACKET_UPDATE_ON_CHANGE, // Only send packets if any of the channels updates + PACKET_UPDATE_AFTER_FIRST_CHANGE, // Always send packets, but only after first channel has been updated +}; + +static const PacketUpdateMode PACKET_UPDATE_MODE = PACKET_UPDATE_ON_CHANGE; +} // namespace Svc + +#endif /* SVC_TLMPACKETIZER_TLMPACKETIZERCOMPONENTIMPLCFG_HPP_ */ diff --git a/config/UdpReceiverComponentImplCfg.hpp b/config/UdpReceiverComponentImplCfg.hpp index efe900898a..f09ee10e07 100644 --- a/config/UdpReceiverComponentImplCfg.hpp +++ b/config/UdpReceiverComponentImplCfg.hpp @@ -8,6 +8,8 @@ #ifndef SVC_UDPRECEIVER_UDPRECEIVERCOMPONENTIMPLCFG_HPP_ #define SVC_UDPRECEIVER_UDPRECEIVERCOMPONENTIMPLCFG_HPP_ +#include + namespace Svc { const static NATIVE_UINT_TYPE UDP_RECEIVER_MSG_SIZE = 256; } diff --git a/config/UdpSenderComponentImplCfg.hpp b/config/UdpSenderComponentImplCfg.hpp index 5641580934..3ed3660e06 100644 --- a/config/UdpSenderComponentImplCfg.hpp +++ b/config/UdpSenderComponentImplCfg.hpp @@ -8,6 +8,8 @@ #ifndef SVC_UDPSENDER_UDPSENDERCOMPONENTIMPLCFG_HPP_ #define SVC_UDPSENDER_UDPSENDERCOMPONENTIMPLCFG_HPP_ +#include + namespace Svc { static const NATIVE_UINT_TYPE UDP_SENDER_MSG_SIZE = 256; } diff --git a/config/locs.fpp b/config/locs.fpp deleted file mode 100644 index 602254c6dc..0000000000 --- a/config/locs.fpp +++ /dev/null @@ -1,19 +0,0 @@ -locate constant ActiveRateGroupOutputPorts at "AcConstants.fpp" -locate constant CmdDispatcherComponentCommandPorts at "AcConstants.fpp" -locate constant CmdDispatcherSequencePorts at "AcConstants.fpp" -locate constant FileDownCompletePorts at "AcConstants.fpp" -locate constant GenericHubInputBuffers at "AcConstants.fpp" -locate constant GenericHubInputPorts at "AcConstants.fpp" -locate constant GenericHubOutputBuffers at "AcConstants.fpp" -locate constant GenericHubOutputPorts at "AcConstants.fpp" -locate constant GenericRepeaterOutputPorts at "AcConstants.fpp" -locate constant HealthPingPorts at "AcConstants.fpp" -locate constant RateGroupDriverRateGroupPorts at "AcConstants.fpp" -locate constant StaticMemoryAllocations at "AcConstants.fpp" -locate type FwChanIdType at "FpConfig.fpp" -locate type FwEventIdType at "FpConfig.fpp" -locate type FwOpcodeType at "FpConfig.fpp" -locate type FwPrmIdType at "FpConfig.fpp" -locate type NATIVE_INT_TYPE at "FpConfig.fpp" -locate type NATIVE_UINT_TYPE at "FpConfig.fpp" -locate type POINTER_CAST at "FpConfig.fpp" diff --git a/config/update-locs b/config/update-locs deleted file mode 100755 index 76583058af..0000000000 --- a/config/update-locs +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -fpp-locate-defs `find . -name '*.fpp'` > locs.fpp diff --git a/docs/Design/communication-adapter-interface.md b/docs/Design/communication-adapter-interface.md new file mode 100644 index 0000000000..d26971aa62 --- /dev/null +++ b/docs/Design/communication-adapter-interface.md @@ -0,0 +1,96 @@ +# Communication Adapter Interface + +Any communication component (e.g. a radio component) that is intended for use with the standard F´ uplink and downlink +stack should implement the *Communication Adapter Interface*. This interface specifies both the ports and protocols used +to operate with the standard F´ uplink and downlink components. + +Implementors of this interface are referred to as *Communication Adapters*. + +![Communication Adapter Interface](./img/com-adapter.png) + +The communication adapter interface protocol is designed to work alongside the framer status protocol and the com queue +protocol to ensure that data messages do not overload a communication interface. These protocols are discussed below. + +## Ports + +The communication adapter interface is composed of three ports. These ports are used to transmit outgoing data through +some communication hardware and receive incoming data from that same hardware. These ports share types with the byte +stream driver model for backwards compatibility. + +| Kind | Suggested Name | Port Type | Usage | +|----------|----------------|-----------------------|----------------------------------------------------------------| +| `input` | `comDataIn` | `Drv.ByteStreamSend` | Port receiving `Fw::Buffer` objects for outgoing transmission. | +| `output` | `comDataOut` | `Drv.ByteStreamRecv` | Port producing incoming `Fw::Buffer` objects. | +| `output` | `comStatus` | `Fw.SuccessCondition` | Port indicating status of outgoing transmission. See protocol. | + + +> Note: components implementing the *Communication Adapter Interface* must deallocate any `Fw::Buffer` received on the +> `comDataIn` port or must delegate the deallocation to another component (e.g. a driver). +> See [Memory Management in F´](./memory.md) + +### comDataIn Description + +This port receives data from an F´ application in the form of an argument of `Fw::Buffer` type. This data is intended to +be sent out the communications interface managed by this component. From the perspective of the application this is +the outgoing data port. + +### comDataOut Description + +This port receives data from the communication interface managed by this component and provides it to the F´ application +in the form of an argument of `Fw::Buffer` type. From the perspective of the application this is the incoming data port. + +### comStatus Description + +This port carries a status of `Fw::Success::SUCCESS` or `Fw::Success::FAILURE` typically in response to a call to the +`comDataIn` port described above. + +> Note: it is critical to obey the protocol as described in the protocol section below. + +## Communication Queue Protocol + +`Svc::ComQueue` queues messages until the communication adapter is ready to receive these messages. For each +Fw::Success::SUCCESS message received, `Svc::ComQueue` will emit one message. `Svc::ComQueue` will not emit messages +at any other time. This implies several things: + +1. An initial `Fw::Success::SUCCESS` message must be sent to `Svc::ComQueue` to initiate data flow +2. A `Fw::Success::SUCCESS` must be eventually received in response to each message for data to continue to flow + +These implications are discussed in more depth in the appropriate protocol sections. + +## Framer Status Protocol + +Framing typically happens between `Svc::ComQueue` and a communications adapter. The `Svc::Framer` component implements +this protocol in order to interoperate with these other components. The action taken by this protocol is dependent on +the number of framed messages (frames) sent to the communication adapter in response to each message received from +`Svc::ComQueue`. + +| Produced Frames | Action | Rationale | +|-----------------|----------------------------------------|----------------------------------------------------------| +| 0 | Send one `Fw::Success::SUCCESS` status | Data must continue to flow to produce a frame | +| 1 | Pass through received statuses | Frame produced and communication adapter produces status | + +When a frame is produced the communication adapter is responsible for determining the status of the message and its +statuses must be passed through. When no frame is produced, the communication adapter does not receive a frame and is +incapable of producing a status. `Svc::Framer` must act appropriately in this case. + +> Note: `Svc::Framer` must also pass through the initiation message from the communication adapter to start data flow. + +## Communication Adapter Protocol + +The communication adapter must obey a specific protocol to indicate to F´ application components the status of outgoing +transmissions. This is done with the `comStatus` port. A communication status is one of two possibilities: + +| Status | Description | +|----------------------|-----------------------------------------------------------------------------------| +| Fw::Success::SUCCESS | *Communication adapter* transmission succeeded and is ready for more data. | +| Fw::Success::FAILURE | Last transmission failed; *communication adapter* is unable to receive more data. | + +* Fw::Success::SUCCESS may also indicate a connection/reconnection success when data flow must be initiated. + +A *Communication Adapter* shall emit either Fw::Success::SUCCESS or Fw::Success::FAILURE via the `comStatus` port once +for each call received on `comDataIn`. Additionally, a *Communication Adapter* shall emit Fw::Success::SUCCESS once at +startup to indicate communication is initially ready and once after each Fw::Success::FAILURE event to indicate that +communication has been restored. By emitting Fw::Success::SUCCESS after any failure, the communication adapter ensures +that each received message eventually results in a Fw::Success::SUCCESS. + +> It is imperative that *Communication Adapters* implement the `comStatus` protocol correctly. diff --git a/docs/Design/general.md b/docs/Design/general.md new file mode 100644 index 0000000000..61f98d3006 --- /dev/null +++ b/docs/Design/general.md @@ -0,0 +1,9 @@ +# Design and Philosophy of F´ + +This section of the documentation captures the design and philosophy of F´, the F´ framework, and flight software as +viewed through F´. + + +| Table of Contents | +|------------------------------------------------| +| [Numerical Types Design](./numerical-types.md) | \ No newline at end of file diff --git a/docs/Design/img/com-adapter.png b/docs/Design/img/com-adapter.png new file mode 100644 index 0000000000..e51a81a972 Binary files /dev/null and b/docs/Design/img/com-adapter.png differ diff --git a/docs/Design/img/com-adapter.txt b/docs/Design/img/com-adapter.txt new file mode 100644 index 0000000000..d80e60eaee --- /dev/null +++ b/docs/Design/img/com-adapter.txt @@ -0,0 +1,34 @@ +Com Queue +comQueueSend +0 +Framer +comIn +0 + +Com Queue +buffQueueSend +0 +Framer +bufferIn +0 + +Framer +comStatusOut +0 +Com Queue +comStatusIn +0 + +Framer +framedOut +0 +Communication Adapter +comDataIn +0 + +Communication Adapter +comStatus +0 +Framer +comStatusIn +0 diff --git a/docs/Design/memory.md b/docs/Design/memory.md new file mode 100644 index 0000000000..2f4b871bbd --- /dev/null +++ b/docs/Design/memory.md @@ -0,0 +1,3 @@ +# F´ Memory Management + +This page is under construction. \ No newline at end of file diff --git a/docs/Design/numerical-types.md b/docs/Design/numerical-types.md new file mode 100644 index 0000000000..881533c272 --- /dev/null +++ b/docs/Design/numerical-types.md @@ -0,0 +1,145 @@ +# F´ Numerical Types + +On physical hardware, numerical types have a size in bits. The sizes of these integers are either explicitly set by the +programmer or implicitly set by the compiler. i.e. `uint32_t` is explicitly 32-bits whereas `int` is implicitly set by +the compiler. Flight software practice encourages use of explicitly sized types because there is less risk of an +unintentional overflow when using explicitly sized types. However, in-practice it is nice to also use logical types that +represent concepts in the system (e.g. size) and are configured to use a specific size as determined by the platform. + +This document describes: fixed-width types and logical types. + +## Fixed Width Types + +In F´, fixed width types map to the standard definitions either in the C standard or in the `stdint.h` header as seen +below. Since platforms are not guaranteed to support all types (e.g. 64bits integers) these types can be turned off +by setting a configuration field to `0` in the platform-supplied `PlatformTypes.h` header. These types are on by +default and users must turn off types their compiler or platform does not support. + + +| F´ Type | Equivalent | `PlatformTypes.h` Configuration Field | +|---------|--------------|---------------------------------------| +| I8 | int8_t | n/a | +| I16 | int16_t | FW_HAS_16_BIT | +| I32 | int32_t | FW_HAS_32_BIT | +| I64 | int64_t | FW_HAS_64_BIT | +| U8 | uint8_t | n/a | +| U16 | uint16_t | FW_HAS_16_BIT | +| U32 | uint32_t | FW_HAS_32_BIT | +| U64 | uint64_t | FW_HAS_64_BIT | +| F32 | float | n/a | +| F64 | double | FW_HAS_F64 | + +Platform developers should include `stdint.h` or equivalent in their `PlatformTypes.h` to ensure F´ can construct a +mapping from the C equivalents to the F´ type. If for some reason that header does not exist or does not define all +types, then developers must define the missing C equivalent types directly in that header. + +To print these types, users may use the standard C++ PRI macros as shown described: +[https://cplusplus.com/reference/cinttypes/](https://cplusplus.com/reference/cinttypes/). + +The limits of these types can be obtained by using `std::numeric_limits::min()` and `std::numeric_limits::min()` +for the defined type T. + +```c++ +U32 value = 10; +U32 my_max = std::numeric_limits::max(); +printf("My value: %" PRIu32 " could store a max of: %" PRIu32 "\n", value, my_max); +``` + +## F´ Logical Integer Type Design + + +Typically, in flight software we try to use fixed-sized types wherever possible as this produces consistent results +across platforms. However, when building components for use on multiple different architectures it is nice to be able +to use logical integer types whose exact widths are determined by the platform and project instead of needing +to pick a one-size-fits-all fixed with type. For example, representing a size as an unsigned 64-bit integer is logical +on some systems that have 64-bit data widths, but will not compile on systems that do not define 64-bit integers at all +(8-bit systems often lack this data size). + +Thus, for these logical types the actual data size needs to be configured. This configuration needs to be available +from two sources: a given project, and a given platform. Platforms need to set the idea size for these types, and +projects need to be able to control these sizes when operating across multiple platforms. + +It is important to check against type limits when using these types to ensure compatibility across systems. + +### Platform Configured Types + +Platform developers must define the following logical types in the `PlatformTypes.h` header provided alongside their +CMake platform and toolchain files. Each type also defines a format specifier for use with the `printf` family of +functions. + +| Platform Logical Type | Format Specifier | Notes | +|-------------------------|-----------------------------|-----------------------------| +| PlatformIndexType | PRI_PlatformIndexType | Ports indices | +| PlatformSizeType | PRI_PlatformSizeType | Sizes | +| PlatformPointerCastType | PRI_PlatformPointerCastType | Pointers stored as integers | +| PlatformAssertArgType | PRI_PlatformAssertArgType | Argument to FW_ASSERT | +| PlatformIntType | PRI_PlatformIntType | Deprecated (see note) | +| PlatformUIntType | PRI_PlatformUIntType | Deprecated (see note) | + +A complete definition of each type for a given platform must be supplied within `PlatformTypes.h` as shown in the +example below. Notice the type is defined along with a format specifier. + +```c++ +typedef int32_t PlatformIndexType; +#define PRI_PlatformIndexType PRId32 +... +``` + +Limits for these types are obtained using the `std::numeric_limits::min()` and `std::numeric_limits::max()` +constants defined in the `limits` header. + +In order to print these types, developers can use the following example as a basis for using the PRI_* macros. This +example also shows the use of the type's minimum limit. + +```c++ +PlatformIndexType index = 3; +// Print the above index type, and the minimum value supported by the same type +printf("Index %" PRI_PlatformIndexType ". Min %" PRI_PlatformIndexType, index, std::numeric_limits::min()); +``` + +**Note:** in order for F´ to compile without warnings it is necessary that each of the platform types are elements in +the set of integers supplied by the C standard integers header (`stdint.h`). i.e. each type must be an `int8_t`, +`int16_t`, `int32_t`, `int64_t` or unsigned variants. On some compilers `int` and `unsigned int` are not members of that +set and on those platforms it is imperative that both `PlatformIntType` and `PlatformUIntType` be set to some fixed size +type instead. + +### Configurable Integer Types + +Project may configure the framework types that the framework and components use for implementation through +`FpConfig.h`. The default configuration as supplied with F´ uses the above platform types where applicable. + +| Framework Type | Logical Usage | Default | Format Specifier | Notes | +|-----------------|----------------------|-----------------------|---------------------|-------| +| FwIndexType | Port indices | PlatformIndexType | PRI_FwIndexType | | +| FwSizeType | Sizes | PlatformSizeType | PRI_FwSizeType | | +| FwAssertArgType | Arguments to asserts | PlatformAssertArgType | PRI_FwAssertArgType | | + +There is also a set of framework types that are used across F´ deployments and specifically interact with ground data +systems. These GDS types have defaults based on configurable platform independent fixed-widths as shown below: + +| GDS Type | Logical Usage | Default | Format Specifier | +|------------------------|----------------------------|-----------------------|----------------------------| +| FwBuffSizeType | `Fw::Buffer` sizes | U16 | PRI_FwBuffSizeType | +| FwEnumStoreType | Enumeration values | I32 | PRI_FwEnumStoreType | +| FwTimeBaseStoreType | Time base | U16 | PRI_FwTimeBaseStoreType | +| FwTimeContextStoreType | Time context | U8 | PRI_FwTimeContextStoreType | +| FwPacketDescriptorType | F´ packet descriptor field | U32 | PRI_FwPacketDescriptorType | +| FwOpcodeType | F´ command opcodes | U32 | PRI_FwOpcodeType | +| FwChanIdType | F´ channel ids | U32 | PRI_FwChanIdType | +| FwEventIdType | F´ event ids | U32 | PRI_FwEventIdType | +| FwPrmIdType | F´ parameter ids | U32 | PRI_FwPrmIdType | +| FwTlmPacketizeIdType | F´ telemetry packet ids | U16 | PRI_FwTlmPacketizeIdType | + +> Note: the F´ GDS expects the above types to use their default setting. Users intending to use the F´ GDS should not +> stray from the above definitions. + +All defaults can be overridden via project specific configuration supplying a custom `FpConfig.h`. A complete +definition of a framework/GDS type in `FpConfig.h` would look like: + +```c++ +#include +... +typedef U32 FwSizeType; +#define PRI_FwSizeType PRIu32 +... +``` diff --git a/docs/INSTALL.md b/docs/INSTALL.md index b75205a03f..7c398b69a9 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -5,113 +5,62 @@ title: "F´ Installation Guide" ## Overview -This installation guide is specifically designed to enable individuals and researchers to get up and -running with F´ quickly. Larger projects with specific requirements may need to extend this process. +This installation guide is specifically designed to enable individuals and researchers to get up and running with F´ quickly. Larger projects with specific requirements may need to extend this process. -**Note:** see the troubleshooting section at the bottom for help resolving common issues found during F´ installs. +**Note:** See the troubleshooting section at the bottom for help resolving common issues found during F´ installs. ## Requirements -F´ depends on several items before the user should attempt to install it. These requirements are -listed below and the user should ensure they are installed before proceeding with this guide. Should these items not -be available on the user's Operating System, then a Virtual Machine should be used. One option is -[VirtualBox](https://www.virtualbox.org/). +F´ depends on several items before the user should attempt to install it. These requirements are listed below and the user should ensure they are installed before proceeding with this guide. Requirements: 1. Linux or macOS operating system 2. git 3. [CMake 3.16](https://cmake.org/download/) or newer. CLI tool must be available on the system path. -4. CLang or GCC compiler +4. CLang or GNU C and C++ compilers (e.g. gcc and g++) 5. [Python 3.7+](https://www.python.org/downloads/), virtual environments, and PIP -**Note:** operating system specific notes are in the [Troubleshooting](#Troubleshooting) section below. +**Note:** OS-specific notes are in the [Troubleshooting](#Troubleshooting) section below. -### Setting Up F´ Environment +### Bootstrapping the F´ Development Environment -The ecosystem of tools supporting F´ is installed as python packages available via PIP. In order to install F´, the user should -setup an environment to run these tools in. - ->Note: Python is used by many operating systems. To prevent problems users are encouraged to run F´ python ->from within a [virtual environment](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/) - -**Setting Up a Virtual Environment** - -Choose a location to generate a virtual environment. This can be any path the user has read and write access to. In this guide we'll -use the path: `$HOME/fprime-venv` - -``` -python3 -m venv $HOME/fprime-venv -source $HOME/fprime-venv/bin/activate -pip install -U setuptools setuptools_scm wheel pip -``` - -> Note: `source $HOME/fprime-venv/bin/activate` must be run in each new terminal where the user wishes to use the virtual environment. - -### Cloning the F´ Repository and Installing F´ Tools - -Installation of F´ requires cloning of the F´ core repository. This uses Git. This will bring down the core framework and C++ files. -F´ ships with a `requirements.txt` file enumerating the tools F´ uses and their specific tested versions. - -**Clone F´ and Install Tools** +The ecosystem of tools supporting F´ is installed as python packages available via PIP. ``` -git clone https://github.com/nasa/fprime -pip install -r fprime/requirements.txt +pip install fprime-tools ``` ->Note: When changing F´ versions make sure to re-run the `pip install -r fprime/requirements.txt` to get the tested tool versions. ->Note: Alternative tool installations are described in [Advanced](#Advanced). +> Python is used by many operating systems. To prevent problems users are encouraged to run F´ python from within a [virtual environment](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/). This is set up when creating a new F´ project. -## Checking Your F´ Installation -The user may easily checkout that their F´ installation has succeeded by testing the following -commands. First, the user will test the build and Autocoder install. Next, the user will test the GDS -layer components. Should the user not have installed the given component, the commands won't work. - -**Testing F´ Autocoder Installation Via Building Ref Application** +### Creating a New F´ Project +The entrypoint to developing with F´ is creating a new project. This will clone the F´ repository and install the necessary tool versions for working with the specified version of F´. ``` -cd Ref -fprime-util generate -fprime-util build --jobs "$(nproc || printf '%s\n' 1)" +fprime-util new --project ``` - -**Testing F´ GDS Installation Via Running HTML GUI** - +This command will ask for some input. Sample responses are below: ``` -fprime-gds -g html -r /Ref/build-artifacts +project_name [MyProject]: MyProject +fprime_branch_or_tag [devel]: devel +Select install_venv: +1 - yes +2 - no +Choose from 1, 2 [1]: 1 ``` -**Note:** `Ref` should contain pre-built dictionaries and binaries for the user's system. This can -be achieved by running the Autocoder installation test (the user must have a working Autocoder -installation). +Next steps: [HelloWorld Tutorial](Tutorials/HelloWorld/Tutorial.md) ## Advanced -There are several advanced options users can consider while installing F´. However, users should be warned that some -knowledge of our tools and versions are often required. +There are several advanced options users can consider while installing F´. However, users should be warned that some knowledge of our tools and versions is often required. ### Installing Tab Completion -Several of F´s command-line utilities support tab completion. To enable these tools to use it, see the -[instructions here](UsersGuide/user/autocomplete.md). - - -## Installing Individual Tools - -Each of the F´ tools can be installed individually through sub packages. However, users should use care to ensure that -compatible versions are installed. +Several of F´s command-line utilities support tab completion. To enable these tools to use it, see the [instructions here](UsersGuide/user/autocomplete.md). -| Tool(s) | Package | -|-------------|--------------| -| fpp | fprime-fpp | -| fprime-util | fprime-tools | -| GDS | fprime-gds | - -> Note: `fprime-gds` depends on `fprime-tools`. It is advisable to install `fprime-gds` and let PIP pull in a compatible -version of `fprime-tools`. ### Installing Optional Components @@ -124,8 +73,7 @@ Some F´ packages contain optional components. These components can be installed | fprime-gds[test-api-xls] | Installs excel logging for use within the integration test framework | -> Note: these packages are optional as they pull in many additional packages and libraries. These may not be supported -on all systems. +> These packages are optional as they pull in many additional packages and libraries. These may not be supported on all systems. **Example:** ``` @@ -135,26 +83,34 @@ pip install fprime-gds[uart-adapter] ## Troubleshooting -This section will add some known hints to trouble-shooting with the installation of F´. This will hopefully help users -install things more effectively. +This section will add some known hints to trouble-shooting with the installation of F´. This will hopefully help users install things more effectively. ### fprime-util: command not found -If the user is using a virtual environment and receives the command not found, the problem is likely caused by the -environment not being sourced in a new terminal. Make sure to source the environment before running: +If the user is using a virtual environment and receives the 'command not found', the problem is likely caused by the environment not being sourced in a new terminal. Make sure to source the environment before running: ``` -source $HOME/fprime-venv/bin/activate +. $HOME/fprime-venv/bin/activate ``` -If installing without a virtual environment, PIP occasionally uses `$HOME/.local/bin` as a place to install user tools. -Users running without virtual environments should add this directory to the path. +If installing without a virtual environment, PIP occasionally uses `$HOME/.local/bin` as a place to install user tools. Users running without virtual environments should add this directory to the path. + +### Helper script 'fpp-redirect-helper' exited with reason: Permission denied + +This error can occur when the helper-script, *(`fprime/cmake/autocoder/fpp-wrapper/fpp-redirect-helper`)* loses its execution permission. + +To verify that this is the case, change to the directory containing `fpp-redirect-helper` and verify that it is executable. +* `cd fprime/cmake/autocoder/fpp-wrapper/` +* `ls -l` + +If it is not executable, add the permission back. + +* `chmod 700 fpp-redirect-helper` ### Ubuntu, Debian, Java and Python PIP -Ubuntu and possibly other Debian variants don't include the pip packages in the default python 3 installation. To get a -fully functional, use these commands on Ubuntu and Debian based systems: +Ubuntu and possibly other Debian variants don't include the pip packages in the default Python 3 installation. To get fully functional, use these commands on Ubuntu and Debian based systems: ``` sudo apt install git cmake default-jre python3 python3-pip python3-venv @@ -164,8 +120,7 @@ Now you should be able to run the installation without trouble. ### Mac OS X and CMake Command Not Found -If the user chooses to install CMake directly from the CMake site (not using homebrew nor Mac Ports), then the CMake -command-line tools must be added to the user's PATH or default system libraries. The quickest command to do that is: +If the user chooses to install CMake directly from the CMake site (not using homebrew nor Mac Ports), then the CMake command-line tools must be added to the user's PATH or default system libraries. The quickest command to do that is: ``` sudo "/Applications/CMake.app/Contents/bin/cmake-gui" --install @@ -175,7 +130,21 @@ More information can be found [here](https://stackoverflow.com/questions/3066860 ### System Python, Packages, and Python3 -Many operating systems offer python PIP packages through their package manager (apt, yum, etc). Most python projects -recommend avoiding those packages, but rather installing from PIP in a virtual environment. The reason for this is that -the version of the python package from the OS may not be the required version that the python project depends on. Thus, -users may choose to install F´ into a virtual environment. This is outside the scope of this document. +Many operating systems offer python PIP packages through their package manager (apt, yum, etc). Most python projects recommend avoiding those packages and instead installing them from PIP in a virtual environment. The reason for this is that the version of the python package from the OS may not be the required version that the python project depends on. Thus, users may choose to install F´ into a virtual environment. This is outside the scope of this document. + +### SSL Error with Python 3.7+ on macOS + +The version of openSSL bundled with Python 3.7+ requires access to macOS's root certificates. If the following error is encountered while installing fprime: + +``` +Failed find expected download: ``` -Finally you can run the Ref deployment on the Raspberry Pi as follows: +Finally, you can run the Ref deployment on the Raspberry Pi as follows: ```sh ./Ref -a -p 50000 ``` diff --git a/docs/Tutorials/GettingStarted/Tutorial.md b/docs/Tutorials/GettingStarted/Tutorial.md deleted file mode 100644 index 5d26ee81b2..0000000000 --- a/docs/Tutorials/GettingStarted/Tutorial.md +++ /dev/null @@ -1,262 +0,0 @@ -# Getting Started with F´ - -Prerequisites: [INSTALL.md](../../INSTALL.md) - -This tutorial will walk the user through the basic usage of the F´ development suite. This assumes that the user has run -through the above installation guide, and has a working F´ installation. - -The goal of this Tutorial is to build familiarity with the F´environment and tools. It does not walk the user through -creation of new F´ items, but rather use the existing F´ `Ref` example as a place to operate the tools, learn the -environment, and learn F´. - -The full development process is covered in the [Math Component Tutorial](../MathComponent/Tutorial.md), which will build -on the knowledge learned here. - -## Tutorial Goals - -The goal of this tutorial is to demonstrate the F´ tool suite as it applies to the F´ development process. Users will -first gain some understanding of F´ terminology followed by the F´ development process. Then they will use the tools to -walk the F´ development process steps against existing reference goals. - -## F´ Terminology - -This section will cover basic terminology used in this and other tutorials with respect to F´. It may be used as a -reference for keywords that have specific meaning in an F´ project. - -**Port:** a port represents a connection between *Components*. These act as communication channels in F´. This allows -*Components* to interact with each other. A set of *Ports* acts as a defined interface to a *Component*. - -**Component:** the location of program behavior. Components execute the software logic of the system and typically -define an interface of *Ports* that act allow them to interact with other *Components*. Components additionally -may define *Commands*, *Events*, *Channels*, and *Parameters*, which define standard data patterns in F´. - -**Topology**: a topology represents the full F´ system. It is a set of *Components* and the connections between those -*Components*. The *Topology* specifies the full system and all the communication channels. - -**Event:** an event, also known as an EVR, is a type of downlinked data that represents a single event in the system. -An event is composed of a name, format string, and set of arguments that described what happened. Events represent a -history of the system. Events are defined per-*component*. - -**Channel:** a channel, also known as a telemetry item, is a single value read and downlinked. Channels consist of -a type, a format specifier, and a value. Channels represent current system state. Channels are defined per-*component*. - -**Command:** a command is uplinked data items that instructs the system to perform an action. *Commands* consist of an -opcode, a mnemonic, and a list of arguments to the command. Commands are defined per-*component*. - -**Deployment:** a deployment is a single instance of F´. Although a single F´ project can use/define multiple -deployments, a deployment represents one build/executable. - -**Build Directory/Build Cache:** this directory, created by the `fprime-util` described below, is required to build -CMake projects. It stores all by-products, generated code, and build products from an F´ build. - -**Ground System:** the computer system running to collect the data from the running F´ deployment. There is a basic -ground system supplied with F´ for development purposes. - -**Toolchain:** a set of build tools to build for a specific architecture. i.e. the "raspberrypi" toolchain will build F´ -deployments for the arm/Linux architecture of the raspberry pi. - -## F´ Development Process - -F´ development typically starts with creating new Ports and Components as these can be built and tested as units and -then the full F´ system deployment topology can be assembled for integrated systems testing and release/operations. This -can be done iteratively by creating a few Components then integrating them into the system topology and then repeating -with the next most critical components. - -F´ development is a design-first approach. To start, a developer should design any unique ports that the Component will -need. If desired, the port can be built and compiled to ensure that the design is correct. Since the port will be -entirely auto-generated, developers usually refrain from unit testing the port and defer unit testing to the Component. - -Next, developers design components. Components are designed by specifying the ports that represent the Component's -interface and the Commands, Events and Channels that the Component handles. This tutorial focuses on the tool suite, so -the design is already in-place. Users can see the design by inspecting Components in the `Ref` directory. Creation of -new components from design through test is demonstrated in the [Math Component Tutorial](../MathComponent/Tutorial.md). - -The next step for developing a Component is to implement the code. To do this, one can generate template stubs to fill -with the developer's stubs. To do this, a user runs the F´ tool suite to generate these stubs. Then implements, builds, -and tests from there. Unit tests template stubs are generated in the same way, and should test-driven development be -preferred, these tests stubs could be generated and implemented before the Component's code. - -Finally, the Component is integrated into the deployment and the entire deployment may be built and installed. - -This tutorial will walk developers through generating the templates, building example Components, and -building/installing the full deployment. It will use the `Ref` application as an example for this. - -## Working the F´ Development Process with `fprime-util` - -In order to ease in development, the F´ team has created a small wrapper for the CMake build system. This will recover the -advantages of previous F´ development patterns, while allowing for the power and configurability of CMake as an underlying -build tool. - -### Build Cache Generation - -In order to run CMake, a build cache needs to be generated. This is typically done once for each platform the user wishes -to compile against. It is usually done right after F´ is checked-out and repeated for each platform as they are added. It -is a setup step and isn't formally part of the F´ development process. - -To run this tool, the developer will use the `generate` subcommand. It takes one optional argument: the toolchain file -used in CMake to compile for a specific platform. If not supplied, the `native` toolchain will be used and F´ will be -setup to run on the current platform (typically Mac OS, or Linux depending on the developer's chosen OS). - -**Generate the Ref Application for Native Compilation** - -To generate a native build, follow the commands shown below. It is assumed that the user has checked out the fprime repository -and is performing commands relative to the location of that checkout. - -``` -cd fprime/Ref -fprime-util generate -``` - -Here the utility will create two standard builds: one for the standard build, and one for the unit test build. This will enable -the user to take advantage of all parts of F´ without generating their own CMake build caches. **Note:** should a developer -be developing or improving F´ provided infrastructure components, then the `generate` command should be run in the F´ -root directory. However, most developers do not need this functionality. - -**Generate Cross-Compile of the Ref Application for Raspberry PI Platform** - -Most developers wish to run F´ on embedded hardware. This is done by generating a cross-compile using a different CMake -toolchain by providing the toolchain argument. The above invocations assume the default "native" toolchain. - -Here, the "raspberrypi" toolchain supplied by F´ is used. This will generate a cross-compile for the raspberry pi -architecture. The user should ensure to follow the Raspberry PI setup steps found at: [RPI](https://github.com/nasa/fprime/blob/master/RPI/README.md) -``` -cd fprime/Ref -fprime-util generate raspberrypi -``` - -## Creating Implementation Stubs - -Once the build system cache is generated, developers will need to generate the stubbed implementations of a Component's C++ -files. This can be done using the `impl` command of the F´ utility. These commands assume a default build has been generated. -Typically passing in a toolchain is unnecessary as these templates are platform agnostic. - -**Generating Implementation Stubs of SignalGen** -``` -cd fprime/Ref/SignalGen -fprime-util impl -``` - -This creates two files for the component. These are `Impl.cpp-template` and `Impl.hpp-template`. -The user can then rename these files to remove `-template`. The file is then ready for C++ development. By generating -`-template` files, we won't accidentally overwrite any existing implementation should the developer need to repeat this -step. - -## Creating Unit Test Implementations - -Once the build system cache is generated, developers will need to generate the stubbed implementations for creating -unit tests for a Component's C++. This can be done using the `impl --ut` command of the F´ utility. These commands -assume a default build has been generated. They can be run passing in a toolchain, but this is typically not done because -they are toolchain agnostic. - -**Generating Unit Test Stubs of SignalGen** -``` -cd fprime/Ref/SignalGen -fprime-util impl --ut -``` - -This creates the following files, that are typically moved to a sub folder called `test/ut`. The files created are -placed in the current directory and named: -``` -Tester.cpp -Tester.hpp -GTestBase.cpp -GTestBase.hpp -TesterBase.cpp -TesterBase.hpp -TestMain.cpp -``` - -### Building Components and Deployments - -Once a developer has implemented a component, it is time to build that component and test that component. In order to build -a component the `build` subcommand needs to be run. This will build the "current directory" that the developer is in. -That means that should the user change into a deployment directory then the build command will build the full deployment. -Should the user desire to build a component, navigate into the Component's directory and run the build command. - -**Build SignalGen Component** -``` -cd fprime/Ref/SignalGen -fprime-util build -``` - -The user can also build a deployment by navigating to the deployment directory and running the `build` command. This is -shown below: - -**Build Ref Deployment** -``` -cd fprime/Ref -fprime-util build -``` -**Note:** the user almost always wants to run the "install" command on deployments. This builds the binary like "build" -but also copies the binary to the deployments "bin" directory, i.e. `fprime/Ref/bin`. Install is described below. - -This process also built the Dictionaries for the project and places the dictionary in the "Top" folder of the deployment. -This happens any time the "install" or "build" command are run on a deployment. - -The user can also build a component or deployment for a cross-compile by specifying the toolchain. A previous generate -for that toolchain should have been run. Again for deployments, the user typically should run "install", see below. These -steps require the setup described here: [RPI](https://github.com/nasa/fprime/blob/master/RPI/README.md) - -``` -cd fprime/Ref/SignalGen -fprime-util build raspberrypi -cd fprime/Ref -fprime-util build raspberrypi -``` - -**Running the Binary Assuming Linux** -``` -cd fprime/Ref -fprime-util build -./build-artifacts/Linux/bin/Ref # Run the deployment -CTRL-C # Exit the application -``` -Running the application as part of the development ground data system is shown below. - -The user can also install a cross-compile. -``` -cd fprime/Ref -fprime-util build raspberrypi -``` - -## Building and Running Unit Tests - -Unit tests can be built using the `build --ut` command of the `fprime-util`. This will allow us to build the unit tests -in preparation to run them. The user can also just run `check` to build and run the unit tests. - -Before building unit tests, the unit test build cache must be generated: - -``` -cd fprime/Ref -fprime-util generate --ut -``` - -**Building Unit Test of SignalGen** -``` -cd fprime/Ref/SignalGen -fprime-util build --ut -``` - -Once built, the unit test can be run using the following command. **Note: this will produce a message warning of no -tests run because SigGen has no unit tests defined.** -``` -cd fprime/Ref/SignalGen -fprime-util check -``` -The user can also build the unit test, but must copy it to the hardware and run it here. This can be done with a cross- -compile by running the following commands. - -**Cross-Compile Unit Test of SignalGen** -``` -cd fprime/Ref/SignalGen -fprime-util build raspberrypi --ut -``` - -## Conclusion - -The user should now be familiar with F´ terminology and with the `fprime-util` tool used to build and develop F´ -applications. The next step is to follow the full `MathComponent` tutorial to create new *Ports*, *Components*, and -*Topologies*. This will walk the user through the entire development process, using the tool commands we learned here. - -**Next:** [Math Component Tutorial](../MathComponent/Tutorial.md) -**Also See:** [GPS Component Tutorial](../GpsTutorial/Tutorial.md) for a cross-compiling tutorial. diff --git a/docs/Tutorials/GpsTutorial/Tutorial.md b/docs/Tutorials/GpsTutorial/Tutorial.md index bb63a1c940..efd50bdf52 100644 --- a/docs/Tutorials/GpsTutorial/Tutorial.md +++ b/docs/Tutorials/GpsTutorial/Tutorial.md @@ -1,10 +1,9 @@ # F´ GPS Tutorial -**WARNING:** this tutorial is under revision for use with F´ 2.0.0. +**WARNING:** This tutorial is under revision for use with F´ 2.0.0. In this guide, we will cover the basics of working with F´ by attaching a GPS receiver to a serial driver and running -the application on a Raspberry PI. In order to fully benefit from this tutorial, the user should acquire any NMEA -compatible UART GPS receiver and a raspberry pi. In this tutorial, we use a NMEA GPS receiver with micro-USB such that +the application on a Raspberry PI. In order to fully benefit from this tutorial, the user should acquire any NMEA-compatible UART GPS receiver and a raspberry pi. In this tutorial, we use a NMEA GPS receiver with micro-USB such that the code may be run on both the laptop and the Raspberry PI. In the DIY electronics community there is an abundance of cheap GPS receivers based around the NMEA protocol. These @@ -15,7 +14,7 @@ receivers send are NMEA formatted ASCII text. This tutorial will show how to integrate one of these GPS receivers with the F´ framework by wrapping it in a Component and defining commands, telemetry, and log events. We will create a GpsApp deployment for the Component where it will -be wired to a standard UART driver in order to receive messages. Then we can cross compile it for the Raspberry PI and +be wired to a standard UART driver in order to receive messages. Then we can cross-compile it for the Raspberry PI and run the application against the F´ ground system. **Note:** A completed version of this tutorial app is available [here](https://github.com/fprime-community/gps-tutorial) @@ -23,7 +22,7 @@ for use as a demo or to help debug issues that come up when going through the tu ## Prerequisites -This tutorial assumes the user has gone through and understood [Getting Started Tutorial](../GettingStarted/Tutorial.md) +This tutorial assumes the user has gone through and understood [Getting Started Tutorial](../HelloWorld/Tutorial.md) and [MathComponent Tutorial](../MathComponent/Tutorial.md) This tutorial requires the user to have some basic software skills and have installed F´. The prerequisite skills to @@ -35,13 +34,13 @@ understand this tutorial are as follows: 4. An understanding of the raspberry pi, specifically SSHing into the pi and running applications Installation can be done by following the installation guide found at: [INSTALL.md](../../INSTALL.md). This guide -will walk the user through the installation process and verifying the installation. In addition, users may wish to -follow the [Getting Started Tutorial](../GettingStarted/Tutorial.md) in order to get a feel for the F´ environment and +will walk the user through the installation process and verify the installation. In addition, users may wish to +follow the [Getting Started Tutorial](../HelloWorld/Tutorial.md) in order to get a feel for the F´ environment and tools. ## Creating a Custom F´ Component -In this next section we will create a custom F´ component for reading GPS data off a UART based GPS module. It will +In this next section, we will create a custom F´ component for reading GPS data off a UART-based GPS module. It will receive data from a UART read port, process the data, and report telemetry from that data. We will then finish up by adding an event to report GPS lock status when it changes and a command to report lock status on demand. @@ -49,7 +48,7 @@ Our custom component has the following functional block diagram: ![GPS Component Diagram](img/gps-comp.png) -**Note:** there are a few other ports our component will need to wire to other components in the system, the above +**Note:** There are a few other ports our component will need to wire to other components in the system, the above diagram captures the ports needed for our desired functionality. ### Designing the GPS Component @@ -60,8 +59,7 @@ and Telemetry Channel specifications are also written in XML. Further informati [User Guide](../../UsersGuide/FprimeUserGuide.pdf). This application does not need any custom ports, as we are using the standard ports to create our GPS handler. Custom ports can be seen in the [Math Component Tutorial](../MathComponent/Tutorial.md). -In this section we will create a directory for our GPS component, and design the component through XML. The first step -to making the component is to make a project directory to hold our project, and a component subdirectory for our GPS. +In this section, we will create a directory for our GPS component, and design the component through XML. The first step in making the component is to make a project directory to hold our project, and a component subdirectory for our GPS. ```shell cd fprime @@ -76,7 +74,7 @@ specify commands, telemetry, and events. As can be seen, we are creating our com ports defined above, and 4 additional ports described below: 1. **cmdIn**: an input port of *Fw::Cmd* type used to process commands sent to this component. -2. **cmdRegOut**: an output port of *Fw::CmdReg* type used to register this component's with the command dispatcher +2. **cmdRegOut**: an output port of *Fw::CmdReg* type used to register this component with the command dispatcher 3. **cmdResponseOut**: an output port of *Fw::CmdResponse* type used respond to dispatched commands 4. **eventOut**: an output port of *Fw::Log* type used to send events out 5. **textEventOut**: an output port of *Fw::LogText* type used to send events in a text form @@ -94,9 +92,9 @@ The `GpsComponentAi.xml` file in the `Gps` subdirectory should look like: