Compare commits

...

179 Commits

Author SHA1 Message Date
dependabot[bot]
94b4457154
Bump urllib3 from 2.5.0 to 2.6.0 (#4528)
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.5.0 to 2.6.0.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.5.0...2.6.0)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.6.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-09 14:09:27 -08:00
budhe888
1f860de821
Added missing undef for m_len in VxWorks collision fix (#4520)
Co-authored-by: Adit Sahasrabudhe <adit.sahasrabudhe@jpl.nasa.gov>
Co-authored-by: kevin-f-ortega <kevin.f.ortega@gmail.com>
2025-12-09 08:56:49 -08:00
Thomas Boyer-Chammard
f3b191beff
Address student review of Device Driver docs (#4509)
* First pass at addressing student review

* nits and pieces
2025-12-05 14:12:11 -08:00
Thomas Boyer-Chammard
59e1baa9d8
Add website navigability updates (#4504)
* Add minor website navigability updates

* Add navigation hint to User manual landing page

* add an arrow

* spelling
2025-12-05 14:08:24 -08:00
kevin-f-ortega
43de02bafd
Update docs for AssertHook (#4505) 2025-12-04 10:53:07 -08:00
Thomas Boyer-Chammard
6c80056596
Bump requirements.txt ahead of v4.1.0 release (#4488)
* Bump requirements.txt for v4.1.0 release

* Update GDS pointer to v4.1.0
2025-12-03 12:17:44 -08:00
M Starch
a8fe137283
Fix FPrimeRouter potential usage of invalid buffer (#4493)
* Fix #4491

* Formatting and enum size
2025-12-03 12:17:00 -08:00
Rob Bocchino
3a293cd705
FPP v3.1.0 (#4483)
* Update FPP version

* Update fpp version
2025-12-02 17:57:14 -08:00
mshahabn
e0afd3c3fb
Add missing implementation of GenericHub (#4420)
* Revise GenericHub model

* Revise GenericHub model

* Revise GenericHub model

* Update spelling

* Revise annotations

* Revise annotations for GenericHub model

* Revise annotations in GenericHub model

* Revise GenericHub model

* Revise GenericHub model

* Revise GenericHub model

* Revise GenericHub

* Revise GenericHub

* Revise GenericHub model

* Revise GenericHub model

* Revise GenericHub config

* Revise GenericHub model

* Revise GenericHub model

* Clean up naming in GenericHub implementation

* Revise GenericHub port names

* Revise annotations in GenericHub model

* Revise annotations in GenericHub model

* Revise annotations in GenericHub model

* Add ByteStreamDriverClient

* Revise ByteStreamDriverClient

* Revise ByteStreamDriverClient

* Revise driver interfaces

* Add PassiveByteStreamDriverClientSendAsync interface

* Add PassiveAsyncByteStreamDriverClient interface

* Add PassiveBufferDriver

* Revise PassiveByteStreamDriverClient interfaces

* Revise PassiveBufferDriver

* Revise Drv interfaces

* Revise PassiveBufferDriver

* Add PassiveBufferDriverClient

* Revise GenericHub model

Use interfaces from Drv

* Revise annotations in GenericHub model

* Revise FPP models

Point FPP to a non-released version with a bug fix

* Add ByteStreamBufferAdapter

* Revise ByteStreamBufferAdapter model

* Revise ByteStreamBufferAdapter

* Revise ByteStreamBufferAdapter

* Add AsyncByteStreamBufferAdapter

* Revise AsyncByteStreamBufferAdapter

* Revsie AsyncByteStreamBufferAdapter

* Revise AsyncByteStreamBufferAdapter

* Revise annotations in FPP model

* Revise ByteStreamBufferAdapter

* Bump fpp version

* Revise GenericHub model

* Revise GenericHub interface

* Revise GenericHub interface

* Fix typo in FPP annotations

* Revise Generic Hub model

* Fix spelling and formatting

* Review recommendations

---------

Co-authored-by: Rob Bocchino <bocchino@jpl.nasa.gov>
Co-authored-by: thomas-bc <thomas.boyerchammard@gmail.com>
2025-12-02 17:56:34 -08:00
M Starch
cddf38bb6f
Make Os::Queues use Fw::MemAllocator pattern for memory (#4451)
* Queues use MemAllocator pattern

* Derive queue allocation from MallocRegistry

* Formatting

* Fix UTs

* Fix CI

* Fix alignment in UT

* Formatting and sp

* Formatting, bad header

* More formatting

* Add queue teardown

* Deinit components

* Fix priority queue test

* Fix bug in priority queue allocation

* Correct comments

* Fix FppTest and Ref UTs

* Fix max heap teardown

* Fix review comment on max heap

* Fix null -> nullptr
2025-12-02 17:36:15 -08:00
dependabot[bot]
89a9e3247b
Bump werkzeug from 3.0.6 to 3.1.4 (#4480)
Bumps [werkzeug](https://github.com/pallets/werkzeug) from 3.0.6 to 3.1.4.
- [Release notes](https://github.com/pallets/werkzeug/releases)
- [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/werkzeug/compare/3.0.6...3.1.4)

---
updated-dependencies:
- dependency-name: werkzeug
  dependency-version: 3.1.4
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 14:27:49 -08:00
bevinduckett
a9e05045da
Add missing cstring includes (#4486)
* Modified the fprime-fpp version for fpp branch

* Fixes for missing includes

* Removed include from Fw/FPrimeBasicTypes.hpp and modified fprime-fpp version

* Fixed files that failed to include cstring header

* Changed string.h to cstring in BufferRepeater.cpp

* Updated formatting in ActivePhaser.cpp & BufferManagerComponentImpl.cpp

* Fixed formatting in FpySequencerStack.cpp & FpySequencerDirectives.cpp
2025-12-02 14:27:10 -08:00
djbyrne17
9fbf5800ab
Update Spi component to return a status on device access (#4452)
* Update Spi component to return a status on device access

* Format LinuxSpiDriver files and update comments from TODO to DEPRECATED

* Add assertions to LinuxSpiDriver

* Add assertions to LinuxSpiDriver

---------

Co-authored-by: djbyrne <djbyrne@jpl.nasa.gov>
2025-12-02 10:42:06 -08:00
M Starch
08f43279da
Fix improper file dependencies in the build (#4479) 2025-12-02 10:27:49 -08:00
Will MacCormack
e8c3fea70c
Add one more ifdef to allow POSIX_THREAD_ENABLE_NAMES off to compile (#4482) 2025-12-02 10:23:41 -08:00
Will MacCormack
b9a7059667
Set the Name of Fprime Tasks on Linux (#4428)
* Set the Name of Fprime Tasks on Linux

* prefix thread name w/ process name

* Revert "prefix thread name w/ process name"

This reverts commit 5867602f135c69022469c985b6de13458686e6a2.

* Add `setname` to spelling expected list

* Format My Changes

* Add in opt-out configuration

* Enable POSIX_THREADS_ENABLE_NAMES and fix ut

* Remove warning when flag set off

* UT thread names

* Add tmate session setup to build workflow

* Disable thread names on Ip UTs

* Use random thread ids in UTs

* Fix race condition

* Fix improper string set

---------

Co-authored-by: M Starch <LeStarch@googlemail.com>
Co-authored-by: Michael D Starch <Michael.D.Starch@jpl.nasa.gov>
2025-12-01 10:15:35 -08:00
Rob Bocchino
aed0837c9c
Merge FPP v3.1.0a12 (#4474)
* Bump fpp version to v3.1.0a11

* Update FPP version to v3.1.0a12
2025-11-24 10:07:44 -08:00
M Starch
f5902583ce
Add component send only test (configSend, open) (#4465)
* Add component send only (configSend, open) test

* Formatting
2025-11-20 17:08:21 -08:00
Thomas Boyer-Chammard
5baf4076ab
Add best practice to CONTRIBUTING.md (#4464)
* Add best practice to CONTRIBUTING.md

* mention clang-tidy optional

* Add code formatting command
2025-11-20 11:11:29 -08:00
kevin-f-ortega
ba95054a24
missing more comments (#4463) 2025-11-20 08:20:17 -08:00
kevin-f-ortega
081a2f8654
Add missing argument description to Os::RawTime (#4461) 2025-11-19 16:22:25 -08:00
djbyrne17
027b658208
Update UT guidelines in Contributing guide (#4421)
* Add clang-tidy to requirement.txt, and update Unit Test guideline

* Leave out of requirements until rPI is supported or avoided

* Fix spelling of macOS

---------

Co-authored-by: djbyrne <djbyrne@jpl.nasa.gov>
2025-11-19 15:31:50 -08:00
Thomas Boyer-Chammard
6d756f7431
Specify dictionary types as required by GDS (#4442)
* Specify dictionary types as required by GDS

* Update requirements.txt for fprime-tools

* Update documentation referencing type
2025-11-19 12:13:28 -08:00
M Starch
8cbba542fc
Make fpp-to-json opt-in by default (#4449) 2025-11-19 12:02:15 -08:00
Will MacCormack
31b6488723
Print the task name when socket open/recv fails (#4434)
* Log task name of socket that failed to open port

* Give failed to recv the same treatment

* Format my changes
2025-11-18 16:56:22 -08:00
M Starch
62dd7445db
Restrict core C and DH when turning off text loggers (#4438) 2025-11-18 16:56:11 -08:00
M Starch
afb6f13853
Add convienence functions to MemoryAllocator (#4439)
* Add convienence functions to MemoryAllocator

* Fix comments
2025-11-18 16:55:57 -08:00
kevin-f-ortega
6388f046e1
Add undef to fix VxWorks collision problem (#4424)
* adding undef to fix collission problem.

* Fix comment typo in UdpSocket.hpp
2025-11-18 10:05:11 -08:00
Joseph Perez
6a132c5df4
Remove redundant line from ActiveRateGroup SDD (#4435) 2025-11-18 10:02:15 -08:00
Tristan
317ba3d7e0
Update fprime-gds version to 4.0.2a10 (#4433) 2025-11-18 09:48:15 -08:00
djbyrne17
402c0317b6
Update obsolete link in docs (#4423)
* Update obsolete link and screenshots

* Revert image updates

---------

Co-authored-by: djbyrne <djbyrne@jpl.nasa.gov>
Co-authored-by: chammard <thomas.boyer.chammard@jpl.nasa.gov>
2025-11-17 10:40:58 -08:00
Rob Bocchino
589871a957
Update FPP version to 3.1.0a10 (#4418) 2025-11-13 09:03:22 -08:00
M Starch
cc2522b257
Add fpp-to-json to FPP model sub-build (#4268)
* Add fpp-to-json to FPP model subbuild

* Update fprime-fpp version to 3.1.0a9
2025-11-11 17:59:32 -08:00
M Starch
6af7bcd5a9
ComAggregator updates (#4402)
* Fix timeout queue overflow with long transmissions

* Fix aggregator existing design

* Fix exactly full edge case

* Bump FPP version
2025-11-11 17:20:18 -08:00
Zimri Leisher
1c87278b6b
Clean up FpySequencer directives (#4395)
* Remove assert and float floor div

* Rename add/sub/mul

---------

Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-11-11 17:20:01 -08:00
Rob Bocchino
a587677fae
Fix FppTest (#4410)
* Fix regression in FppTest

* Rename SerializeBufferBase to LinearBufferBase

* Revise FppTest

Add missing tests to CMakeLists
2025-11-11 10:50:37 -08:00
Rob Bocchino
a46fccf54d
Fix Ref build (#4409)
CMake directives were out of order
2025-11-11 10:49:12 -08:00
Ian Brault
2b65cc83cf
Add new Fw::ConstStringBase type for strings backed by immutable string literals (#4269)
* Add new Fw::StringBase type StaticString for strings backed my immutable literals

* Spellcheck fix

* Add disclaimer comment about use of StaticString

* Refactor the StringBase interface into an immutable ConstStringBase abstract base class and the now mutable StringBase class

* Rename StaticString to ConstExternalString and inherit from ConstStringBase

* Fix typo

* Change references from StringBase to ConstStringBase where applicable

* Updates following review meeting: add missing deserialize function and add new error status, move length function implementation into ConstStringBase so it is not pure virtual

* Clang format fix

* Additional clang-format fixes

* Fix the copy-assignment operator for StringBase not being correctly evaluated

* Clang format fix

* Explicitly delete the Serializable assignment operator and provide a skeleton implementation for RawTimeInterface to appease the compiler

* Revert "Explicitly delete the Serializable assignment operator and provide a skeleton implementation for RawTimeInterface to appease the compiler"

This reverts commit 086d7bcd3ca9c4f6e553d7fc34d0d126a69a165b.

* Move ConstStringBase to separate hpp/cpp files, plus other pull request feedback

* Clang format fix

* Update length implementation for ConstStringBase and ConstExternalString

* Improved asserts in ConstExternalString constructor

Co-authored-by: Rob Bocchino <bocchino@icloud.com>

* Fixed ConstStringBase length implementation

Co-authored-by: Rob Bocchino <bocchino@icloud.com>

* Clang format fix

* Add some UTs for ConstExternalString, fix non-overridden interfaces, and fix ConstStringBase::maxLength asserting for zero capacity strings

* Spell-check fix for ConstExternalString UTs

* Revise length implementation in ConstStringBase

If the capacity is zero, return zero

* Format

---------

Co-authored-by: Ian Brault <ian.r.brault@jpl.nasa.gov>
Co-authored-by: Rob Bocchino <bocchino@icloud.com>
Co-authored-by: Rob Bocchino <bocchino@jpl.nasa.gov>
Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-11-07 09:50:05 -08:00
dependabot[bot]
90bac90821
Bump brotli from 1.1.0 to 1.2.0 (#4400)
Bumps [brotli](https://github.com/google/brotli) from 1.1.0 to 1.2.0.
- [Release notes](https://github.com/google/brotli/releases)
- [Changelog](https://github.com/google/brotli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/brotli/compare/go/cbrotli/v1.1.0...v1.2.0)

---
updated-dependencies:
- dependency-name: brotli
  dependency-version: 1.2.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-07 08:27:05 -08:00
Thomas Boyer-Chammard
ba5988bfcd
Add How-To Implement a Bus Driver guide (device driver 2 of 2) (#4398)
* initial changes

* v0.1

* More improvements

* fix spelling
2025-11-06 16:29:40 -08:00
Thomas Boyer-Chammard
d669ea2c5a
Replace FpConfig.h header with FPP model elements (#4393)
* Update FpConfig.h

* Update AcConstants.fpp

* Update FPrimeBasicTypes.hpp

* Update BasicTypes.h

* Update FpySequencer.hpp

* Update FpConfig.h

* Update FPrimeBasicTypes.hpp

* Update BasicTypes.h

* Update BasicTypes.h

* Update BasicTypes.h

* Update BasicTypes.h

* Update BasicTypes.h

* Update BasicTypes.h

* Update BasicTypes.h

* Update FPrimeBasicTypes.hpp

* Update FPrimeBasicTypes.hpp

* Update FpConfig.h

* Update AcConstants.fpp

* Revert casts

* Add static_cast in asserts, reorganize files per feature

* Fix static_assert after merging devel

* Add assert to static cast

* clean up comments and TODOs

* formatting

* Fix formatting

* Fix RHEL8 error

* Other UT cast fix

* cast one side only

* fix spelling and move assert count to FpConstants

* Reorder and comments

* rob test

* re-add double cast

* Revert testing static_cast

* Update docs

* use SIZE_OF variables instead of hardcoding value

* Update FpConfig in CMake tests

---------

Co-authored-by: ekswang <eric.k.wang@jpl.nasa.gov>
2025-11-06 16:29:15 -08:00
Vince Woo
48e4720419
Created new SerialBufferBase as a parent of SerializeBufferBase (now renamed LinearBufferBase). (#4288)
* Created new SerialBufferBase as a parent of SerializeBufferBase. Renaming interface functions to be less confusing.

* Deprecating copyRawOffset. No direct use-cases in F' core.

* Make SerialBufferBase a true pure virtual interface.

* Changing Serializable to work with SerialBufferBase parent interface.

* Changing copyRaw and copyRawOffset to work with SerialBufferBase

* Updating documentation for SerialBufferBase usage

* Adding some documentation. Adding missing ASSERT in copyRaw. Fixing some bugs that new ASSERT uncovered.

* Renaming SerializeBufferBase to LinearBufferBase. Add a using declaration to maintain backwards compatability. Properly mark LinearBufferBase functions as override.

* Filling in the rest of the docstrings for the classes in Serializable

* Removing redundant virtual keyword on override function

* Applying clang formatting

* Incorporating PR comments

* Fix compile issues

* Bump version to alpha

* Format

* v

---------

Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-11-06 16:23:20 -08:00
M Starch
b254e981a1
Update directives documentation with requirements (#4385)
* Update directives documentation with requirements

Added requirements for various directives and updated documentation.

* Refine sequencer requirements for clarity

* sp, missing exit requirement

* Update requirement references in directives.md

* Adding missing stack results as N/A

* Update requirements and descriptions in directives.md

Updated requirements for various directives and clarified descriptions. Removed unused directives and added TODOs for further specification.

* Update sequencer requirements in sdd.md

* Add in 2's complement notes.

Updated integer operations to use unsigned 64-bit integers and clarified handling of integers with 2's complement representation.

* Update documentation with 2's complement caution

Added caution note about 2's complement representation requirement.

* sp
2025-11-04 09:29:06 -08:00
Zimri Leisher
b1b613fd0c
FpySequencer Add DUMP_STACK_TO_FILE command (#4384)
* Add DUMP_STACK_TO_FILE command

* Add docstring

* Fix bug in directive

* format
2025-11-04 09:18:55 -08:00
Saransh Chopra
903677e97d
Fix clang-tidy checks (#4379)
* fix(.clang-tidy): `Checks` is supposed to be a comma separated list of checks

* fix clang-tidy warning

* fix a few lint warnings

* run clang-format

* more format
2025-11-03 17:45:54 -08:00
Thomas Boyer-Chammard
d6f43b02ff
Add How-To implement a Device Manager (device driver 1 of 2) (#4378)
* Add guide for developing device drivers in F Prime

* Add develop-device-driver.md

* Update device driver docs

* small fixes

* Polish things up

* more polishing

* spelling and link fixes

* Address review comments
2025-11-03 11:41:06 -08:00
Zimri Leisher
d0e9508988
FpySequencer new directives for loops (#4356)
* Rework exit, push tlm and push prm

* Rename store to store const offset

* Add new dirs for loops

* Compiling again

* Add UTs, passing

* Format

* sp

* Update schema version

* Update error code names

* Update directives documentation

* Add new stack class, switch DUPLICATE to PEEK

* Update peek docs

* Remove old docs

* sp

* sp, format
2025-11-03 10:03:38 -08:00
Copilot
aa4517c69b
Add Configuration section to BufferManager SDD (#4355)
* Initial plan

* Add Configuration section to BufferManager SDD

Co-authored-by: thomas-bc <49786685+thomas-bc@users.noreply.github.com>

* Improve example by adding component instantiation

Co-authored-by: thomas-bc <49786685+thomas-bc@users.noreply.github.com>

* Simplify configuration example and remove TBD sections per review feedback

Co-authored-by: thomas-bc <49786685+thomas-bc@users.noreply.github.com>

* Manual updates

* add link

* Address review feedback: clarify memID, bin entry wording, and numBuffers description

Co-authored-by: thomas-bc <49786685+thomas-bc@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: thomas-bc <49786685+thomas-bc@users.noreply.github.com>
Co-authored-by: thomas-bc <thomas.boyerchammard@gmail.com>
2025-11-03 09:36:28 -08:00
M Starch
edf5c85d09
Allow bypass of posix_fallocate with FPRIME_SYNTHETIC_FALLOCATE (#4380) 2025-11-03 09:33:34 -08:00
M Starch
695478d1a1
Bump fprime-gds to 4.0.2a9 for FileUplink fix (#4382) 2025-11-03 09:30:44 -08:00
M Starch
c51921aca3
Add more error checking to Fpy arithmetic directives (#4331)
* Add more error checking to arithmetic directives

* sp

* Inadvertant double literal fix

* Add missing std::
2025-10-30 10:43:08 -07:00
M Starch
cb9f3a982b
Clarify Fpy float operation behavior in documentation (#4328)
* Clarify float operation behavior in documentation

Updated float operations to specify handling of NaN and infinity.  Fixes #3892, #3893.

* sp correcting neq definition

* sp
2025-10-30 10:42:20 -07:00
M Starch
033f504418
Document sequencer requirements and directives (#4373)
* Document sequencer requirements and directives

Added detailed requirements for the sequencer, including support for various directives and operations.

* Reorganize sequencer requirements in documentation
2025-10-29 13:13:12 -07:00
Thomas Boyer-Chammard
fdc582bc56
Update CI for top-level namespace structure (#4353)
* Update CI for top-level namespace structure

* update deployment expect file

* Fix other led-blinker workflows

* Fix dictionary name

* formatting to trigger CI

* Update MathTutorial CI build location

* add fprime location
2025-10-29 11:07:36 -07:00
Thomas Boyer-Chammard
0d78cd407c
Fix macOS CI intermittent failure (#4347)
* Attempt CI fix and test debug setup

* Sleep longer to wait for downlink

* why tho?

* revert misc debug things
2025-10-22 17:26:25 -07:00
Philip Romano
bf12f48c27
Adjust task priorities to fit within supported platform priority ranges (#4337)
* Adjust task priorities to fit in supported platforms' priority ranges

Darwin's task priority range is most restrictive (15-47); adjusted priorities
to reside within that range.

* Add comment clarifying TASK_PRIORITY_DEFAULT and TASK_DEFAULT

* Adjust relative task priorities for uplink and downlink

This moves uplink tasks to higher priority than downlink tasks and places
consumer tasks at higher priority than producer tasks.
2025-10-22 15:46:05 -07:00
Philip Romano
3f25d8b535
Change FPP enums to smallest representation (#4342)
For all FPP enums in the framework, set the representing type to the minimum
width that can represent the enum's member constants.
2025-10-22 15:44:10 -07:00
Thomas Boyer-Chammard
c0b75fb06a
Refactor FrameAccumulator not to assert on incorrect size_out (#4340)
* Refactor FrameAccumulator not to assert on incorrect size_out

* spelling

* revert port names

* Update check logic
2025-10-22 15:17:27 -07:00
Andrei Tumbar
6bdd79f290
Time Limited Event Throttle (#4306)
* Time Limited Event Throttle

* Bump fpp version

* Bump fpp version to include dictionary fix

* Bump fpp
2025-10-21 11:19:09 -07:00
Thomas Boyer-Chammard
38361bebd1
Fix RawTime UT oversight on initialization (#4330)
* Fix RawTime UT oversight on initialization

* fix include path

* update calculation method

* revert to 5000 steps
2025-10-21 09:52:25 -07:00
Thomas Boyer-Chammard
4261f9d815
Update RawTime UTs to require a platform-specific helper (#4323)
* tmp

* Update RawTime.Now test to require a platform-specific helper

* Fix ordering for GitHub rendering not to trip up

* spelling
2025-10-20 14:16:12 -07:00
M Starch
c909a19a54
Add alignment to memory allocator (#4319)
* Add alignment to memory allocator

* Fix undefined reference

* Fix enum type comparison

* Switch to enum class

* format

* Fix time

* Update Fw/Types/MallocAllocator.hpp

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Update Fw/Types/MmapAllocator.hpp

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
2025-10-20 12:51:36 -07:00
M Starch
4705b6c989
Fix O_SYNC on systems without the definition (#4322) 2025-10-20 11:10:35 -07:00
Thomas Boyer-Chammard
626473fc4e
Add News page to nav.yml (#4317) 2025-10-16 16:08:30 -07:00
Thomas Boyer-Chammard
1ff13ac93f
Address student feedback for How-To Framing protocol (#4314)
* Address student review feedback for How-To Framing protocol

* last couple nits

* fix spelling

* ugh

* add review comments
2025-10-16 15:51:00 -07:00
M Starch
a8328b95cf
Enhance Fpy docs with state machine diagram (#4315)
* Enhance documentation with state machine diagram

* sp
2025-10-16 15:34:37 -07:00
M Starch
4afac326ba
Update contribution guidelines for clarity and CCB process (#4312)
* Update contribution guidelines for clarity and process

Clarified the process for submitting pull requests and emphasized the importance of opening an issue first. Updated the note about F´ Autocoder Python and its replacement by FPP.

* Fix typo and reorganize CONTRIBUTING.md structure

Corrected a typo in the Code Contribution Process section and reorganized the structure of the CONTRIBUTING.md file for clarity.

* Update CONTRIBUTING.md

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
2025-10-16 10:47:33 -07:00
Zimri Leisher
2fca863e4d
FpySequencer flag system (#4259)
* Much work on set flags

* Little more work on flags

* Get UTs passing

* Defaults for flags

* Add uts for set flag

* Switch from bitfield to boolean array

* fix ut

* more work on flag system

* Add some uts

* Add getflag dir

* format

* Update docs

* sp

* Remove update on change from bool tlm

* pr feedback

---------

Co-authored-by: Zimri Leisher <zimri.leisher@fireflyspace.com>
2025-10-14 13:49:22 -07:00
Mishaal
0fc995fefd
Provide ability to update parameters via a file (#4165)
* Save point for PRM_SET_FILE work, add basic infrastruture

* fprime-format

* Create prime and backup DB, initial implementation of file based set, some UT updates

* More work on Prime and Backup DBs including helper methods, utilizing those for copy, and UTs

* spelling

* printf in Tester fix

* printf in Tester fix

* printf in Tester fix

* Remove a debug printf, update new method args, additional offNom Set File tests

* Spelling and format

* Clean up comments

* Sync with upstream devel updates

* Add additional UT for reverting parameter db on set file failure

* Spelling and format

* Updates to PrmDb after first review; change to active/staging design

* Spelling

* Remove FIXME comment

* Review fixes

* Fix UT

* Format

* Format II

* Format III

---------

Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-10-14 13:40:27 -07:00
Cel Skeggs
9c11872889
Mark SwAssert declarations as noinline (#4304)
* Mark SwAssert declarations as noinline

Without this change, a compiler using LTO may inline the zeros that are
inserted as additional parameters for the call to defaultSwAssert. This
increases code size to optimize for the off-nominal condition where an
assertion is tripped.

In my testing, this single change reduces my largest deployment's
code size by 11%.

* Add 'noinline' to dictionary

* Update Fw/Types/Assert.hpp

Co-authored-by: Rob Bocchino <bocchino@icloud.com>

---------

Co-authored-by: M Starch <LeStarch@googlemail.com>
Co-authored-by: Rob Bocchino <bocchino@icloud.com>
2025-10-14 12:55:33 -07:00
M Starch
2ee27f82f3
Add Communication Aggregator Component (#4264)
* Add aggregator component

* Add com aggregator to subtopology

* Fix aggregator issues

* Format and SDD

* Add basic UTs

* Fix not-empty check, test

* sp

* Fix author tag

* Bump GDS for aggregation; timeout aggregator

* Bump comQueue event size

* Increase timeout for integration tests

* Update Fw/Buffer/Buffer.hpp

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Update Svc/ComAggregator/CMakeLists.txt

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Update Svc/ComAggregator/docs/sdd.md

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Update Svc/ComAggregator/docs/sdd.md

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Remove unused variable 'good' in action doClear

* A usage note about APID.

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
2025-10-13 16:28:57 -07:00
Will MacCormack
9a7123c190
Little Endian Serialization (#4294)
* Passing the Default BIG Arg to Serialize Functions

* Fails on Ac Files

* Compiles w/ little endian autocode

* Unit Tests Pass

* Little Endian deserializeTo & Unit Test Little Endian SerDes

* Add little-endian SerDes examples to docs

* Add & Respect Endianness for Array Lengths & Remove unneeded Fw:: Prefix

* Switch to enum class Endianness

* Fixes for enum class Endianness

* Run code formatter

* Bump fpp to v3.1.0a4

* Update Fw/Time/Time.hpp

* Update Fw/Time/Time.hpp

---------

Co-authored-by: Rob Bocchino <bocchino@jpl.nasa.gov>
Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-10-13 14:15:06 -07:00
Will MacCormack
d385cb45ac
Bump fprime-gds to 4.0.2a8 in requirements.txt (#4299)
Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-10-13 13:18:24 -07:00
djbyrne17
2de91b0916
NonASCII characters removed (#4298)
Co-authored-by: djbyrne <djbyrne@jpl.nasa.gov>
2025-10-13 09:41:41 -07:00
Andrei Tumbar
e1098018e2
Bump FPP with unified tool (#4287) 2025-10-09 17:00:24 -07:00
Angelina-2007
e34c019c3b
Fix typos in cross-compiling docs (#4280) 2025-10-09 10:38:41 -07:00
M Starch
74dd80e2b7
Add FPRIME_CMAKE_QUIET option (#4276)
* Add FPRIME_CMAKE_QUIET option

* Remove makefile deadcode

* Attempt CI debug

Add debugging message for FPRIME_SUB_BUILD_JOBS variable.

* Fix argument passing for sub-build jobs

* Update cmake/sub-build/sub-build.cmake

* Update cmake/sub-build/sub-build.cmake

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
2025-10-08 16:30:36 -07:00
M Starch
7aa034c526
Add option for installing static libs (#4277) 2025-10-08 13:43:31 -07:00
M Starch
6c2698cea1
Bump C++ to 14 (#4278) 2025-10-08 13:39:20 -07:00
Thomas Boyer-Chammard
a4579d2fca
Add ErrorNotify port to CCSDS deframers (#4267)
* Add ErrorNotify port to CCSDS deframers

* Rename ErrorType to FrameError

* Update SDDs
2025-10-08 13:38:43 -07:00
Zimri Leisher
896803ad20
Add PUSH_TIME directive (#4275)
* Add push_time dir

* Add docs and UT

* format
2025-10-08 13:32:33 -07:00
Zimri Leisher
35840d549d
Add STEP command to FpySequencer (#4239)
* Remove debug prefix from breakpoint commands, start working on line by line step

* Actually add teh step cmd, some uts, update docs

* Fix step ut

* Split up tlm chans, add more for breakpoint stuff

* format

* Remove update on change from bool telemetry channels
2025-10-08 13:22:03 -07:00
Will MacCormack
589ed5d437
Switch to U64 Logger Tests (#4262)
* Use U64 for LoggerTests

* Switch `%llu` to PRI_U64

* Add back the `%` before PRI_U64

* clang-format LoggerRules.cpp
2025-10-06 13:26:36 -07:00
Rob Bocchino
e9d7f3ab66
Data structure library, phase 2 (#4062)
* Revise RedBlackTree impl docs

* Revise RedBlackTree impl docs

* Revise RedBlackTree impl docs

* Revise RedBlackTree impl docs

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl docs

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Fix typo

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl docs

* Revise RedBlackTree impl docs

* Revise RedBlackTree impl

* Revise RedBlackTreeImpl docs

* Revise Fw/DataStructures

Reformat code

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise Fw/DataStructures

Fix compile errors on Linux

* Fix comments

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise ArrayMap docs

* Remove helper scripts

* Revise tests for Fw/DataStructures

* Fix spelling

* Fix Markdown link

* Fix uninitialized variable in test

* Fix uninitialized variable in test

* Fix "spelling"

Why is the spelling check enforcing arbitrary rules of style?

* Fix comments

* Revise RedBlackTree impl docs

* Start adding RedBlackTree impl

* Revise tests for ArraySetOrMapImpl

* Revise RedBlackTree impl

* Revise comment

* Revise comment

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise ArraySetOrMap impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Add RedBlackTree impl tester

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Fix comments

* Revise RedBlackTree impl

* Fix comments

* Revise comments

* Revise comments

* Revise comments

* Revise statement order for clarity

* Revise unit tests for RedBlackTree impl

* Revise RedBlackTree impl tests

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Add build and clean scripts

Working around regressions in the F Prime build system

* Revise build

Fix warnings

* Revise RedBlackTree impl and tests

* Revise tests for RedBlackTree impl

* Revise RedBlackTree impl and tests

* Revise RedBlackTree tests

Remove debug print statements

* Revise RedBlackTree impl tester

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise build script

* Revise RedBlackTree tests

* Revise RedBlackTree tests

* Revise RedBlackTree tests

* Revise RedBlackTree tests

* Revise RedBlackTree tests

* Revise RedBlackTree impl tests

* Revise RedBlackTree impl tests

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl tests

* Revise RedBlackTree impl tests

* Revise RedBlackTree impl tests

* Revise RedBlackTree impl tests

* Revise RedBlackTree impl tests

* Revise RedBlackTree impl tests

* Revise RedBlackTree impl test

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise comment

* Revise RedBlackTree impl and tests

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl

* Revise RedBlackTree impl tests

* Revise RedBlackTree impl tests

* Revise RedBlackTree impl

* Revise RedBlackTree impl tests

* Revise formatting

* Format code

* Revise docs

* Revise docs for Fw/DataStructures

* Revise Array and ExternalArray

Add static assertions

* Revise FifoQueue and Stack

Add static assertions

* Revise ArraySet and ArrayMap

Add static assertions

* Revise docs for ExternalRedBlackTreeMap

* Revise docs for ExternalRedBlackTreeSet

* Revise docs for RedBlackTreeMap

* Revise docs for RedBlackTreeSet

* Revise ExternalRedBlackTreeMap tests

* Refactor ExternalStackTester

* Revise ArrayMap tests

* Add RedBlackTreeMap

* Revise RedBlackTreeMap tests

* Revise RedBlackTreeMap

* Add ExternalRedBlackTreeSet

* Add missing file

* Revise SetConstIterator

* Revise ExternalRedBlackTreeSet tests

* Revise ExternalRedBlackTreeSet tests

* Revise ExternalRedBlackTreeSet tests

* Revise ExternalRedBlackTreeSet tests

* Revise ExternalRedBlackTreeSet tests

* Revise ExternalRedBlackTree tests

* Revise ExternalArraySet tests

* Revise ExternalArraySet tests

* Add RedBlackTreeSet

* Revise RedBlackTreeSet tests

* Refactor ArraySetTest

* Revise RedBlackTreeSetOrMapImpl docs

* Revise array initialization

* Revise comments

* Revise Array initialization

* Revise Array design and implementation

* Revert changes to Fw/DataStructures

* Revise Array

* Revise Array

* Revise Array

* Fix formatting

* Add SizedContainer base class

* Revise StackBase

Make it inherit from SizedContainer
Revise stack tests

* Revise MapBase

Make it inherit from SizedContainer
Revise tests

* Revise SetBase

Make it inherit from SizedContainer
Revise tests

* Revise DataStructures design

Add SizedContainer

* Revise SDD for DataStructures

* Revise DataStructures design

* Revise DataStructures design

* Revise DataStructures design

* Revise DataStructures design

* Fix spelling

* Revise zero-arg constructor for Array

* Revise Array interface

Make it consistent with the arrays generated by FPP

* Fix to assertion

* Format code

* Fix spelling

* Fix spelling

* Add -Wno-comment to suppress warnings for now

* Revise comments

* Revise diagrams

* Fix comment warnings on gcc

* Eliminate tabs

* Remove utility scripts

* Revise placement of break statements

* Rename function

getParentDirection --> getDirectionFromParent

* Add comment

* Add svg diagram

* Add svg diagram

* Add svg files

* Revise diagram

* Replace png with svg

* Replace png with svg

* Replace png with svg

* Revise comment

* Revise SDD for red-black tree

* Revise SDD for red-black tree
2025-10-06 13:26:23 -07:00
M Starch
20477ad9c8
Make GenericHub EXCLUDE_FROM_ALL (#4178)
* Make GenericHub EXCLUDE_FROM_ALL

* Add a build stage for Svc_GenericHub

CppCheck requires every target to be built.

* sp

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
2025-10-06 10:48:05 -07:00
Andrei Tumbar
498546eac9
Bump FPP to 3.1.0a2 (#4263) 2025-10-06 10:19:51 -07:00
Ian Brault
c7048d0b9c
Fix for PosixFileTest UT failure (#4254)
Co-authored-by: Ian Brault <ian.r.brault@jpl.nasa.gov>
2025-10-06 10:19:08 -07:00
kevin-f-ortega
0a945a55c9
must be explicit when using unions otherwise size mispatch could occur (#4256)
* must be explicit when using unions otherwise size mispatch could occur

* fixed formatting
2025-10-06 10:18:20 -07:00
Cel Skeggs
7fbe13086a
Clear up encoding and newline errors (#4252)
* Require and add newlines at EOF in all C++ code

* Fix use of UTF-8 encoding in ci/config.xml

* Add missing newlines to ends of other files
2025-10-02 13:34:25 -07:00
Thomas Boyer-Chammard
1786ffee01
Update CI to use latest macOS intel runners (#4251) 2025-10-02 13:27:47 -07:00
Zimri Leisher
9139148de2
FpySequencer Add push tlm val and time dir (#4230)
* Add push tlm val and time dir

* Update sdd with latest directives

* format

* Rework overflow check
2025-09-30 13:47:43 -07:00
Steven Doran
43ed537106
CWE 453 cmd buffer assert (#4198)
* Initial fix for CWE-453-CmdBufferAssert

* Added EVR throttle; updated ut

* Updated unit tests

* Updated UT to check for TLM update

* Implemented finding from pull request

* Removed Test Directory

* Update model and SDD

* Move telemetry to rate group to prevent flood

* Fix Ref topology

* Format

* sp

---------

Co-authored-by: bitWarrior <bitWarrior@protonmail.com>
Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-09-30 13:26:04 -07:00
Ian Brault
157f0f4d23
Fix inconsistencies in Drv.LinuxUartDriver SDD (#4237)
Co-authored-by: Ian Brault <ian.r.brault@jpl.nasa.gov>
2025-09-30 11:20:54 -07:00
kevin-f-ortega
3fa2ed9716
Bump fprime-gds dependency (#4236) 2025-09-30 11:19:55 -07:00
Thomas Boyer-Chammard
0e40726440
Add nomenclature document (#4200)
* Add nomenclature document

* whitespaces

* whitespaces

* fix spelling

* Update nomenclature with software slug representation

Added software slug representation for F Prime.

* sp

---------

Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-09-29 13:48:44 -07:00
Pavly Gerges (pavl_g)
6433f694c7
RateGroup Docs Enhancements (#4196)
* Update rate-group.md

* Update expect.txt

* Added a word to the dictionary.
2025-09-26 15:01:57 -07:00
M Starch
8b1d627139
Add improvements to ComQueue (#4190)
* Move dequeued ComBuffer to persistent memory

* Add ordering notes to com interface docs

* Add buffer ownership tracking

* Assert dequeue status for serialized buffer

Added status check for dequeue operation to ensure successful serialization.

* Fix static_assert -> static_cast

* Fix format
2025-09-25 15:05:08 -07:00
M Starch
73ab9621e4
Ci zephyr (#4141)
* Add reusable action and workflow for CI and set up

* Add branch for testing

* Call correct workflow

* Remove superfluous input (tmp)

* Switch to fprime-actions

* Add with

* Actions typo

* Add plugin package installation

* Add build stage

* Fix container

* Remove container

* Trial of West

* Add custom setup

* Add push event

* Fix event data mining for push

* Fix push payload usage

* Fix branch detection

* Fix bash-foo

* Fix resuable project CI

* Add custom runner set up

* Typo

* Add intgration step

* Fix archive download

* Debug commands

* Download after setup

* Fix download path

* adding workflow for pico2 zephyr

* updated reusable workflow to clean up when done, otherwise garbase is left and it causes issues with subsequent runs

* fixing formatting because it matters

* Remove erroneous clean-up

* sp

* Add make space step

* Fix review requests

---------

Co-authored-by: Kevin F. Ortega <kevin.f.ortega@jpl.nasa.gov>
2025-09-25 13:29:58 -07:00
kevin-f-ortega
8ad0b830e8
regex is a bit wrong. It never would work with 'Os/File.hpp' (#4193) 2025-09-25 12:34:31 -07:00
Thomas Boyer-Chammard
9141f01919
Fix Intermittent UT failure in FprimeDeframer (#4177)
* Fix random UT failure in FprimeDeframer

* Update UTs and docs to reflect expectations
2025-09-23 09:28:30 -04:00
chuynh4duarte
b377be2a9f
Update Int to match PR4079 and clean-up Int Misc (#4111)
* update seq_gen to match PR 4079

* comment-out check specific number of events.  re-run multi without cause error

* fixed format

* change warn_hi to greater_or_equal_to 1 and put back 2 extra AppendFile

---------

Co-authored-by: Cindy T Huynh <chuynh@jpl.nasa.gov>
Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-09-22 10:21:39 -07:00
Mishaal
bae7d2573c
Socket automatic reconnections in dedicated thread (#4136)
* Initial addition of dedicated reconnect task in SocketComponentHelper

* Updates to fix UT errors, address FIXMEs, update comments

* Additional FIXMEs and doc updates

* Spelling fix

* Format

* Format and some delay updates

* Address second request FIXMEs (remove)

* Unconditional stop & join in UDP tester cleanup

* Address FIXMEs and update Task to init singleton in a thread and address sanitizer safe manner

* Spelling

* Address PR review comments
2025-09-22 10:09:35 -07:00
jp
40142d7d39
Add system resources integration test (#4126) 2025-09-22 08:40:45 -07:00
Vince Woo
3422cfa117
Mark legacy serialize and deserialize methods as DEPRECATED. Upgrade remaining references to legacy methods. (#4145)
* Mark legacy serialize and deserialize functions as deprecated. Clean up of remaining legacy references.

* Upgrading serialization in FppTestProject and Ref

* Fixed formatting issues
2025-09-22 07:57:34 -07:00
Mishaal
01e3d70925
Add support to set socket options for IP sockets (#4146)
* Add setsockopt support

* Format

* format and spelling in cfg
2025-09-22 07:27:06 -07:00
Andrei Tumbar
5bee1a1151
Add Fw::TimeInterval constructor for computing delta between start/en… (#4172)
* Add Fw::TimeInterval constructor for computing delta between start/end time

* Format code

* Make the constructor better
2025-09-22 07:17:10 -07:00
Rob Royce
241e74ea1d
Fix grammatical error in F' introduction (#4174) 2025-09-21 13:12:20 -07:00
Andrei Tumbar
b28709cbdb
FPP 3.1.0a1 (#4161) 2025-09-17 14:14:14 -07:00
kevin-f-ortega
38f0c1f3b2
Update supported platforms document (#4152)
* moving feather m4 to the supported target table

* udpated dates
2025-09-15 16:36:05 -07:00
M Starch
e21fa7b109
Add Svc.BufferAllocation FPP interface (#4148)
* Add Fw::Buffer allocation interface

* Update Svc/Interfaces/Allocation.fpp

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Rename BufferAllocation.fpp interface file

* Update input file for Svc_Interfaces module

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
2025-09-15 16:35:24 -07:00
Thomas Boyer-Chammard
ade6cc5ff3
Make APID and FwPacketDescriptorType the same width (#4076)
* Make APID same width as FwPacketDescriptorType

* Rename ComCfg.APID to ComCfg.Apid

* Fix FprimeDeframer UTs

* FpySequencer stack based architecture (#3975)

* Some work towards stack based arch

* Bring fp/int conv up to date

* Get compiling with stack based arch

* Start trying to fix UTs

* Start adding store/load dirs

* Add push val dir

* UTs are running

* UTs passing

* Make exit stack based

* Fix more uts

* Fix final UTs

* sp

* Fix overflow potential err

* Fix another overflow

* same error fix

* Update sdd

* sp

* Fix undefined behavior with bitshift of signed integer

* sp

---------

Co-authored-by: Zimri Leisher <zimri.leisher@fireflyspace.com>

* Fix AI Policy link in PR template (#4019)

* Update NOTICE.txt references (#4045)

With the removal of the Autocoders directory, we also remove the pyparsestring usage.

* Reformat FppTest (#4048)

* Update Drv IP stack to use FwSizeType instead of U32 (#4013)

* Update IP stack source to use SizeType instead of I/U32

* Update UTs reflecting U32/I32 change to SizeType

* Static cast sizes per review

* Fix commented out thing

* Basic data structure library, phase 1 (#3927)

* Revise SDD for SetBase

* Revise SDD for SetBase

* Revise SDD for Fw/DataStructures

* Revise SDD for FifoQueue

* Revise SDD for Fw/DataStructures

* Revise SDD for MapBase

* Revise SDD for StackBase

* Revise SDD for Fw/DataStructures

* Revise SDD for Fw/DataStructures

* Add StackBase.hpp

* Add ExternalStack.hpp

* Add Stack.hpp

* Add ExternalStackTest

* Revise Stack tests

* Revise ExternalStack

* Revise ExternalStackTest

* Revise ExternalStackTest

* Revise ExternalStackTest

* Revise ExternalStackTest

* Add StackTest

* Revise SDD for Fw/DataStructures

* Revise SDD for Fw/DataStructures

* Revise SDD for Fw/DataStructures

* Add MapIterator

* Add SetIterator

* Add SetOrMapIterator

* Add MapBase.hpp

* Revise SDD for Fw/DataStructures

* Revise SDD for ArraySetOrMapImpl

* Revise SDD for ArraySetOrMapImpl

* Revise SDD for ExternalArray

* Revise SDD for Fw/DataStructures

* Revise SDD for Fw/DataStructures

* Revise MapBase

* Revise MapBase

* Revise comments

* Revise SDD for ArraySetOrMapImpl

* Revise Fw/DataStructures

* Add ArraySetOrMapImpl

* Add ExternalArrayMap

* Revise ExternalArrayMap

* Revise Fw/DataStructures

* Revise SetBase

* Revise SDD for Fw/DataStructures

* Revise SDD for ExternalArraySet

* Revise SDD for ExternalArraySet

* Revise SDD for ArraySetOrMapImpl

* Revise Fw/DataStructures

* Revise SDD for Fw/DataStructures

* Revise Fw/DataStructures tests

* Revise unit tests for Fw/DataStructures

* Revise tests for ArraySetOrMapImpl

* Revise unit tests for Fw/DataStructures

* Revise unit tests for Fw/DataStructures

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for Fw/DataStructures

* Revise SDD for SetOrMapIterator

* Add ExternalArrayMapTest

* Revise ExternalArrayMapTest

* Revise design for sets and maps

* Revert changes to design

* Revise unit tests for Fw/DataStructures

* Revise unit tests for Fw/DataStructures

* Revise ExternalArrayMapTest

* Revise ExternalArrayMapTest

* Revise unit tests for ArraySetOrMapImpl

* Revise ExternalArrayMapTest

* Revise ExternalArrayMapTest and MapTest

* Revise MapTestScenarios

* Revise ExternalArrayMapTest

* Revise ExternalArrayMapTest

* Revise ExternalArrayMapTest

* Revise array set and map

Remove at function from interface.
It breaks the array or set abstraction.
It provides little value, since one can use the iterator
provided by SetBase or MapBase to range over the elements.

* Revise ExternalArrayMapTest

* Add ExternalArraySetTest

* Revise ExternalArraySet and ExternalArrayMap

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest and ExternalArrayMapTest

* Revise ArraySetOrMapImplTest

* Revise ExternalArrayMapTest

* Revise ExternalArraySetTest

* Revise SDD for ArrayMap

* Revise SDD for ArraySet

* Revise SDD for ArraySet

* Add ArrayMap

* Revise ArrayMapTest

* Revise Fw/DataStructures

* Revise SDDs for ArrayMap and ArraySet

* Revise Fw/DataStructures

* Refactor map test scenarios

* Refactor data structures tests

* Refactor SetTestScenarios

* Refactor FifoQueueTestScenarios

* Refactor ExternalFifoQueueTest

* Revise Fifo Queue tests

* Refactor ExternalFifoQueueTest

* Revise comments

* Revise Stack tests

* Revise Stack tests

* Refactor Stack tests

* Revise Stack tests

* Revise Array

Remove getStaticSize

* Refactor Fifo tests

* Refactor ArraySetOrMapImplTest

* Revise data structures design

Rename Iterator to Entry

* Revise data structures implementation

Rename Iterator to Entry

* Revise data structures impl and test

Rename Iterator to Entry throughout

* Revise data structures implementation

Rename SetOrMapEntry to SetOrMapImplEntry

* Revise data structure implementation

Rename Entry to ImplEntry

* Revise data structures design

Rename symbols to match implementation

* Revise design for data structures

Add ConstIterator to Map

* Revise ArraySetOrMapImpl

Add ConstIterator

* Add iterators to DS implementation

* Revise map iteration

* Revise unit tests

Use iterators for maps

* Revise iterators

* Revise iterators

* Rename MapEntry to MapConstEntry

* Revise map interface

* Rename SetOrMapImplEntry to SetOrMapImplConstEntry

* Revert "Rename SetOrMapImplEntry to SetOrMapImplConstEntry"

This reverts commit cc6371d03c8f65fa130212d589812cf4ab3714fe.

* Rename SetEntry to SetConstEntry

* Add SetConstIterator

* Revise SetBase and unit tests

Use iterators

* Revise set interface

* Revise comments

* Reformat code

* Revise array set and map impl

Remove forward links

* Revise data structures tests

* Revise Set iterator

* Remove SetConstEntry

* Refactor SetOrMapImplEntry

* Pull in changes from rb-tree branch

* Revise MapBase

* Revise MapBase and docs

* Revise MapBase

* Revise MapBase

* Revise iterators

* Revise MapConstIterator docs

* Rename MapConstEntry to MapEntry

* Revise MapEntry

* Fix MapBase docs

* Revise MapConstIterator

* Revise MapEntry

* Revise MapConstIterator docs

* Revise docs for ExternalArrayMap

* Revise ArrayMap docs

* Revise ArraySetOrMapImpl

* Revise SetOrMapImplEntry

* Revise MapEntry

* Revise map and set interfaces

* Revert changes to map interface

* Rename MapEntry to MapEntryBase

* Revise type aliases

* Reformat code

* Revise SetBase

* Revise map interface

* Revise set and map interface

* Revise ExternalArraySet docs

* Revise ArraySet

* Revise ArraySet docs

* Revise SetConstIterator

* Revise SetBase

* Revise SetBase docs

* Revise SetBase

* Revise ArraySet

* Revise ArraySet docs

* Revise ExternalArraySet docs

* Add SetOrMapImplEntry

* Revise ArraySetOrMapImpl

* Revise Fw/DataStructures

Reformat code

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise Fw/DataStructures

Fix compile errors on Linux

* Fix comments

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise ArrayMap docs

* Remove helper scripts

* Revise tests for Fw/DataStructures

* Fix spelling

* Fix Markdown link

* Fix uninitialized variable in test

* Fix uninitialized variable in test

* Fix "spelling"

Why is the spelling check enforcing arbitrary rules of style?

* Fix comments

* Revise tests for ArraySetOrMapImpl

* Revise comment

* Revise ArraySetOrMap impl

* Revise formatting

* Revise docs

* Revise docs for Fw/DataStructures

* Revise Array and ExternalArray

Add static assertions

* Revise FifoQueue and Stack

Add static assertions

* Revise ArraySet and ArrayMap

Add static assertions

* Revise ArrayMap tests

* Revise ExternalArraySet tests

* Refactor ArraySetTest

* Revise array initialization

* Revise comments

* Revise Array initialization

* Revise Array design and implementation

* Revert changes to Fw/DataStructures

* Revise Array

* Revise Array

* Revise Array

* Fix formatting

* Add SizedContainer base class

* Revise StackBase

Make it inherit from SizedContainer
Revise stack tests

* Revise MapBase

Make it inherit from SizedContainer
Revise tests

* Revise SetBase

Make it inherit from SizedContainer
Revise tests

* Revise DataStructures design

Add SizedContainer

* Revise SDD for DataStructures

* Revise DataStructures design

* Revise DataStructures design

* Revise DataStructures design

* Revise DataStructures design

* Fix spelling

* Revise zero-arg constructor for Array

* Revise Array interface

Make it consistent with the arrays generated by FPP

* Fix to assertion

* FpySequencer arithmetic (#4025)

* Some work towards stack based arch

* Bring fp/int conv up to date

* Get compiling with stack based arch

* Start trying to fix UTs

* Start adding store/load dirs

* Add push val dir

* UTs are running

* UTs passing

* Make exit stack based

* Fix more uts

* Fix final UTs

* sp

* Fix overflow potential err

* Fix another overflow

* same error fix

* Format

* Also add to format checker

* Add math directives

* Add integer extension and truncation

* Also check correct size on stack

* Fix comment

* Push cmd response to stack

* Cast cmd response code to i32

* Add stack cmd, memcmp, discard dirs

* Fix some bugs with stack cmd

* Fix lil bug in sgtack cmd

* same bug

* Fix another bug sry

* Update sdd

* sp

* Fix undefined behavior with bitshift of signed integer

* sp

* Fix lil bug in timeout detection of stack cmd

* Switch format check to do all Svc dirs

* Reformat, and fix packet descriptor serialize bug

* Add UTs for all of arith ops

* Add tests for disc, memcmp, stack cmd

* Add deser tests for those three dirs

* sp

* Format

* Replace magic numbers with sizeofs

* Add currentStatementIdx helper function

* Format

* Split imod into smod and umod

* sp

* Add fmod, copy python behavior for fmod and smod

---------

Co-authored-by: Zimri Leisher <zimri.leisher@fireflyspace.com>

* Update supported platforms (#4071)

* improved step to contribute back

* added delivery date for targeted platforms

* added tbd since we are not sure at the moment

* fixed column data

* updating list of supported targets. This reflects how F Prime runs on these hardware with zephyr.

* alphabetized list and added link for freertos

* fix spelling

* rename Apple M* to Apple Silicon

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Add ground derived channels how-to guide (#4074)

* Initial derived channel work

* Write ground-derived channels

* Update plugin handler

* Updating publishChannel case

Updated method name to follow naming conventions.

* Fix method name to use snake_case in documentation

* Add environment setup to CONTRIBUTING.md (#4078)

* Fix typo `cp` to `cd` in CONTRIBUTING.md

* Mention Python venv requirements for running tests

* Add logic for assert failure short circuiting in `AssertFatalAdapter` (#4042)

* Add logic for assertion short circuiting

- Add guard logic to AssertFatalAdapter to prevent a cascading FW_ASSERT chain from occurring
- If any assert checks fail while handling an in-progress assert check failure, reportAssert will log the
additional assert and execute the system-specific assert handler before returning

* Update assert guard logic to counter based

- Instead of using a bool guard to determine when to off-ramp from a series of FW_ASSERT check failures,
use a counter that is configurable in a program's FpConfig.h file

---------

Co-authored-by: M Starch <LeStarch@googlemail.com>

* Add subtopology documentation (#4072)

* Add subtopology guide

* fix typo and how-to

* Add reference link

* Add event ID filters to text logger components (#4028)

* Add event ID filter to PassiveConsoleTextLogger

* Add event ID filter to ActiveTextLogger

* Add const qualifier to filtered event list pointers

* Fix assert argument types

* Fix clang format errors

* Fix copy-paste error on include file

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Add missing initialization to ActiveTextLogger constructor

---------

Co-authored-by: Ian Brault <ian.r.brault@jpl.nasa.gov>
Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
Co-authored-by: M Starch <LeStarch@googlemail.com>

* Bump GDS to v4.0.2a3 (#4079)

* Bump to v4.0.2a2 (GDS)

* Fix integration tests

* Fix requirements.txt

* Allow FPP arrays of arbitrary size (#4073)

* Revise array tests

Update constructor calls to conform to new code gen
Format the code

* Reformat FppTest

* Revise requirements.txt

* Update requirements.txt

* Update fpp version

* Revise Ref to conform to FPP changes

* Remove trailing spaces

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Update project structure in cookiecutters CI (#3991)

* Update project structure

* Fix sourcing path

* fix paths

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Fix #3397 (#4086)

* Add test driven development how-to (#4090)

* Add test driven development how-to

* sp; review

* Add reusable InT test scripts (#3923)

* add deployment function

* update file to use config json file

* remove unuse function

* fix typos

* fixed spelling

* update to use get_mnemonic

* rm shellcmd from fileManager and add health & systemResources testcase

* check memory usage and number of CPUs

* remove Ref.PingReceiver and fixed typos

* fixed spelling fileDownlink,health,systemResources and add config.json file

* Update config.json

* replace ActiveLogger to EventManager

* Updated config.json use lowercase CdhCore and FileHandling(fileDownlink,fileManager,prmDb) and ComCcsds(cmdSeq) etc

* update test_cmd_version to compare version of telemetry channel vs. evr version

* extend max_delay to work with Raspberry pi

* rename config.json to int_config.json

* delete Ref/config.json new file name int_config.json

* add time.sleep between AppendFile cmd to work with rasberry Pi

* fix int_config.json and add new Int DpMgr, DpWriter and DpCatalog

* add comments to confirm /tmp/1MiB.txt and /tmp/test_seq.seq exist before execute script

* add send uplink files

* Rename config.json, fix spelling

* python formatting

---------

Co-authored-by: Cindy T Huynh <chuynh@jpl.nasa.gov>
Co-authored-by: M Starch <LeStarch@googlemail.com>
Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
Co-authored-by: Kevin F. Ortega <kevin.f.ortega@jpl.nasa.gov>

* Modify LinuxTimer interface for consistency (#4087)

* Use Fw::TimeInterval in LinuxTimer

* Fix Linux FD typo

* Fix interval timer UT

* Format

* Fix assert casts

* Fix ComLogger UTs

* Fix FppTest microseconds

* Fix casting

* Fix overflow

* FpySequencer U32 stack size + some error telemetry (#4065)

* Switch everything that references stack size or offset to U32

* Add dir err tlm

* Rename tlm point to be consistent

* Update state tlm type to enumstoretype

* Make new Fpy::StackSizeType alias

* Add explanation for why we chose U32

* Fix one more static cast

* Bump schema vers to 2

---------

Co-authored-by: Zimri Leisher <zimri.leisher@fireflyspace.com>

* Add Framing subtopologies and use them within Com subtopologies (#4113)

* Update ComX subtopologies to not include ComStub and update Ref

* Cosmetic updates

* Working FramingCcsds subtopology used in ComCcsds

* Revert Ref to use ComCcsds

* Move FramingSubtopology into ComCcsds build module

* Working ComFprime subtopology

* Cosmetic updates

* formatting

* Incorporate student feedback for ground derived channels (#4117)

* Update fprime-gds version to 4.0.2a4 (#4118)

* Revise subtopology development documentation (#4119)

* Revise subtopology development documentation

* Document subtopology configuration process

Added detailed instructions for configuring subtopologies, including module setup and CMake integration.

* Enhance documentation on subtopology structure

Added recommendations for including documentation and optional files in subtopology.

* fix spelling

* fix spelling v2 final

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Add SDD for ComCcsds subtopology (#4128)

* Create SDD for ComCcsds subtopology

* Update Svc/Subtopologies/ComCcsds/docs/sdd.md

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Update Svc/Subtopologies/ComCcsds/docs/sdd.md

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Update Svc/Subtopologies/ComCcsds/docs/sdd.md

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Revise CCSDS subtopology entries and limitations

Updated descriptions for CCSDS subtopologies and clarified limitations.

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Create SDD for CdhCore subtopology (#4121)

* Create SDD for CdhCore subtopology

Added a comprehensive Software Design Document (SDD) for the CdhCore subtopology, detailing requirements, design, usage, configuration, and traceability.

* sp

* Update SDD with review feedback

Added section for rate-group connection points and updated instance requirements.

* Feedback updates on common port patters, health, and worker (#4115)

* Feedback updates on common port patters, health, and worker

* Fix typos and improve clarity in documentation

* Fix typo in health-checking documentation - pt 2

Corrected a typo in the description of Svc.Health regarding configurable timeouts.

* Fix typo in manager-worker documentation - pt 3

* Fix formatting in health-checking documentation

* Add Software Design Document for FileHandling subtopology (#4125)

* Add FPP state machine How-To (#4096)

* Add FPP state machine How-To

* Fix state definitions in state diagram for newlines

* sp

Clarified wording regarding state transitions in the documentation.

* Missing `.`

Co-authored-by: Rob Bocchino <bocchino@icloud.com>

* Review updates

* Update links in define-state-machines.md

* sp

---------

Co-authored-by: Rob Bocchino <bocchino@icloud.com>

* Add Software Design Document for ComFprime subtopology (#4127)

* Add Software Design Document for ComFprime subtopology

* sp

* fix spelling and same feedback as ComCcsds

* Update instance summary in sdd.md documentation

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Add file size and subdirectory support to FileManager directory listing feature (#4041)

* Enhancement: Added file size and subdirectory support to FileManager directory listing feature

* Refactor to directory listing feature using rategroup 2 component

* Spelling fixes to expect.txt, config feilds for schedin call, fixes on comments/types

* Fix for spellcheck

* Replace fixed size with FileNameStringSize for commands

* Fix minor nits

* Formatting

* Remove fileManager instance, use FileHandling.fileManager

* Fix review feedback

---------

Co-authored-by: M Starch <LeStarch@googlemail.com>

* Revise Communication Adapter Interface documentation (#4133)

Updated reference to the Communication Adapter Interface in the documentation to reflect changes in the interface file names and added usage instructions.

* Add ActivePhaser to Svc (#3974)

* Initial open source review of active phaser

* Start working on ActivePhaser's FPP model

* Add ActivePhaser implementation

* Start working on unit tests

* Fill in test logic

* Add comments

* Guard against writing outside of container

* Add comment

* Update comments

* Fix comment on overflow

* Comment on the use of actual_start and others

* Add comments and max connection count

* Add comments

* Phaser updates

* Add telemetry channels

* Update comments, fix FPP, update API calls in tester

* Apply formatter

* Minor comment change

* Fix spelling

* First draft of SDD

* Revert "Add telemetry channels"

This reverts commit 1690e51e125477d032e07fa8cd3882d6db2b8b3b.

* PRIVATE -> private

* Add friend class declaration for ActivePhaserTester

* Fix FIXMEs where possible

* Formatting

* Fix minor UT issues

* Remove (void)

---------

Co-authored-by: ZIIIKT <shaokail@jpl.nasa.gov>
Co-authored-by: M Starch <LeStarch@googlemail.com>
Co-authored-by: Michael D Starch <Michael.D.Starch@jpl.nasa.gov>

* Fix other UTs

* Bump GDS dependency to latest v4.0.2a5

* Bump fprime-gds to v4.0.2a6

* Update dictionary command in seqgen tests

---------

Co-authored-by: Zimri Leisher <zimri.leisher@gmail.com>
Co-authored-by: Zimri Leisher <zimri.leisher@fireflyspace.com>
Co-authored-by: M Starch <LeStarch@googlemail.com>
Co-authored-by: Rob Bocchino <bocchino@jpl.nasa.gov>
Co-authored-by: kevin-f-ortega <kevin.f.ortega@gmail.com>
Co-authored-by: Philip Romano <pjromano94@gmail.com>
Co-authored-by: Kyle Jones <kylej@jpl.nasa.gov>
Co-authored-by: Ian Brault <ian@brault.dev>
Co-authored-by: Ian Brault <ian.r.brault@jpl.nasa.gov>
Co-authored-by: chuynh4duarte <chuynh4duarte@gmail.com>
Co-authored-by: Cindy T Huynh <chuynh@jpl.nasa.gov>
Co-authored-by: Kevin F. Ortega <kevin.f.ortega@jpl.nasa.gov>
Co-authored-by: Rob Bocchino <bocchino@icloud.com>
Co-authored-by: Isaac Garibay <144189484+Isaac-G5900@users.noreply.github.com>
Co-authored-by: Shaokai (Jerry) Lin <shaokai@berkeley.edu>
Co-authored-by: ZIIIKT <shaokail@jpl.nasa.gov>
Co-authored-by: Michael D Starch <Michael.D.Starch@jpl.nasa.gov>
2025-09-12 14:41:44 -07:00
Thomas Boyer-Chammard
6190d9610b
Update custom framing How-To guide (#4144) 2025-09-12 11:52:41 -07:00
Rob Bocchino
9871fd5608
Call destructors when ExternalArray releases memory for which it has called constructors (#4143)
* Revise SDD for ExternalArray

Add element destructor calls

* Revise ExternalArray

Destroy array elements allocated as bare memory

* Refactor ExternalArray

* Refactor ExternalArray

* Revise commment

* Revise comment

* Revise SDD for ExternalArray
2025-09-11 19:16:45 -07:00
Thomas Boyer-Chammard
942c9eb6ac
Bump fprime-tools (#4142) 2025-09-11 16:28:26 -07:00
Copilot
965109bc50
Add SDD documentation for LinuxUartDriver component (#4124)
* Initial plan

* Add complete SDD documentation for LinuxUartDriver component

Co-authored-by: LeStarch <995330+LeStarch@users.noreply.github.com>

* Address all SDD review comments: numbering, requirement IDs, FPP examples

Co-authored-by: thomas-bc <49786685+thomas-bc@users.noreply.github.com>

* manual fixes

* Remove one level of section numbering in LinuxUartDriver SDD

Co-authored-by: thomas-bc <49786685+thomas-bc@users.noreply.github.com>

* woop woop

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: LeStarch <995330+LeStarch@users.noreply.github.com>
Co-authored-by: thomas-bc <49786685+thomas-bc@users.noreply.github.com>
2025-09-11 14:52:52 -07:00
Thomas Boyer-Chammard
054c51ad3e
Revise install instructions with latest project structure (#4139) 2025-09-11 14:51:08 -07:00
Vince Woo
4f381110a1
Fixing LinuxSpiDriver issues; Adding function argument check and completing read-after-write checks (#4137)
* Fixing read-after-write checks for SPI configuration. Adding UT.

* Add assert to validate the read and write buffers are the same size in SpiReadWrite_handler

* Corrected WARNING_LOW -> WARNING_LO

* Fixing event Strings and invalid SpiFrequency

* Reverting changes to LinuxSpiDriverTester

* Removing redundant variable write_clock
2025-09-10 18:26:02 -07:00
Thomas Boyer-Chammard
31919e6931
Fix test logic for TcDeframer CRC check (#4138) 2025-09-10 17:58:01 -07:00
Thomas Boyer-Chammard
ba65039fff
Finish code formatting (#4134) 2025-09-10 15:02:07 -07:00
Shaokai (Jerry) Lin
c8e2d44877
Add ActivePhaser to Svc (#3974)
* Initial open source review of active phaser

* Start working on ActivePhaser's FPP model

* Add ActivePhaser implementation

* Start working on unit tests

* Fill in test logic

* Add comments

* Guard against writing outside of container

* Add comment

* Update comments

* Fix comment on overflow

* Comment on the use of actual_start and others

* Add comments and max connection count

* Add comments

* Phaser updates

* Add telemetry channels

* Update comments, fix FPP, update API calls in tester

* Apply formatter

* Minor comment change

* Fix spelling

* First draft of SDD

* Revert "Add telemetry channels"

This reverts commit 1690e51e125477d032e07fa8cd3882d6db2b8b3b.

* PRIVATE -> private

* Add friend class declaration for ActivePhaserTester

* Fix FIXMEs where possible

* Formatting

* Fix minor UT issues

* Remove (void)

---------

Co-authored-by: ZIIIKT <shaokail@jpl.nasa.gov>
Co-authored-by: M Starch <LeStarch@googlemail.com>
Co-authored-by: Michael D Starch <Michael.D.Starch@jpl.nasa.gov>
2025-09-10 09:39:39 -07:00
M Starch
82fff1abc8
Revise Communication Adapter Interface documentation (#4133)
Updated reference to the Communication Adapter Interface in the documentation to reflect changes in the interface file names and added usage instructions.
2025-09-09 21:36:26 -07:00
Isaac Garibay
fff0e0bf77
Add file size and subdirectory support to FileManager directory listing feature (#4041)
* Enhancement: Added file size and subdirectory support to FileManager directory listing feature

* Refactor to directory listing feature using rategroup 2 component

* Spelling fixes to expect.txt, config feilds for schedin call, fixes on comments/types

* Fix for spellcheck

* Replace fixed size with FileNameStringSize for commands

* Fix minor nits

* Formatting

* Remove fileManager instance, use FileHandling.fileManager

* Fix review feedback

---------

Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-09-09 14:46:07 -07:00
M Starch
1ee55a0c90
Add Software Design Document for ComFprime subtopology (#4127)
* Add Software Design Document for ComFprime subtopology

* sp

* fix spelling and same feedback as ComCcsds

* Update instance summary in sdd.md documentation

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
2025-09-09 13:08:02 -07:00
M Starch
aabfa56193
Add FPP state machine How-To (#4096)
* Add FPP state machine How-To

* Fix state definitions in state diagram for newlines

* sp

Clarified wording regarding state transitions in the documentation.

* Missing `.`

Co-authored-by: Rob Bocchino <bocchino@icloud.com>

* Review updates

* Update links in define-state-machines.md

* sp

---------

Co-authored-by: Rob Bocchino <bocchino@icloud.com>
2025-09-09 12:31:21 -07:00
M Starch
3e41e2052b
Add Software Design Document for FileHandling subtopology (#4125) 2025-09-09 09:27:38 -07:00
M Starch
4c0092751c
Feedback updates on common port patters, health, and worker (#4115)
* Feedback updates on common port patters, health, and worker

* Fix typos and improve clarity in documentation

* Fix typo in health-checking documentation - pt 2

Corrected a typo in the description of Svc.Health regarding configurable timeouts.

* Fix typo in manager-worker documentation - pt 3

* Fix formatting in health-checking documentation
2025-09-08 18:09:23 -07:00
M Starch
d9ecb8b637
Create SDD for CdhCore subtopology (#4121)
* Create SDD for CdhCore subtopology

Added a comprehensive Software Design Document (SDD) for the CdhCore subtopology, detailing requirements, design, usage, configuration, and traceability.

* sp

* Update SDD with review feedback

Added section for rate-group connection points and updated instance requirements.
2025-09-08 18:04:07 -07:00
M Starch
4429614ea4
Add SDD for ComCcsds subtopology (#4128)
* Create SDD for ComCcsds subtopology

* Update Svc/Subtopologies/ComCcsds/docs/sdd.md

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Update Svc/Subtopologies/ComCcsds/docs/sdd.md

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Update Svc/Subtopologies/ComCcsds/docs/sdd.md

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Revise CCSDS subtopology entries and limitations

Updated descriptions for CCSDS subtopologies and clarified limitations.

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
2025-09-08 17:53:50 -07:00
M Starch
9cb948ed5d
Revise subtopology development documentation (#4119)
* Revise subtopology development documentation

* Document subtopology configuration process

Added detailed instructions for configuring subtopologies, including module setup and CMake integration.

* Enhance documentation on subtopology structure

Added recommendations for including documentation and optional files in subtopology.

* fix spelling

* fix spelling v2 final

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
2025-09-08 10:41:06 -07:00
M Starch
0dbc4febbc
Update fprime-gds version to 4.0.2a4 (#4118) 2025-09-04 17:05:39 -07:00
M Starch
bce0b5de79
Incorporate student feedback for ground derived channels (#4117) 2025-09-04 13:27:51 -07:00
Thomas Boyer-Chammard
d014f30a96
Add Framing subtopologies and use them within Com subtopologies (#4113)
* Update ComX subtopologies to not include ComStub and update Ref

* Cosmetic updates

* Working FramingCcsds subtopology used in ComCcsds

* Revert Ref to use ComCcsds

* Move FramingSubtopology into ComCcsds build module

* Working ComFprime subtopology

* Cosmetic updates

* formatting
2025-09-03 18:04:37 -07:00
Zimri Leisher
77f286f3ed
FpySequencer U32 stack size + some error telemetry (#4065)
* Switch everything that references stack size or offset to U32

* Add dir err tlm

* Rename tlm point to be consistent

* Update state tlm type to enumstoretype

* Make new Fpy::StackSizeType alias

* Add explanation for why we chose U32

* Fix one more static cast

* Bump schema vers to 2

---------

Co-authored-by: Zimri Leisher <zimri.leisher@fireflyspace.com>
2025-09-03 15:53:28 -07:00
M Starch
10f2b49d3f
Modify LinuxTimer interface for consistency (#4087)
* Use Fw::TimeInterval in LinuxTimer

* Fix Linux FD typo

* Fix interval timer UT

* Format

* Fix assert casts

* Fix ComLogger UTs

* Fix FppTest microseconds

* Fix casting

* Fix overflow
2025-09-02 15:22:07 -07:00
chuynh4duarte
8b9ac2197d
Add reusable InT test scripts (#3923)
* add deployment function

* update file to use config json file

* remove unuse function

* fix typos

* fixed spelling

* update to use get_mnemonic

* rm shellcmd from fileManager and add health & systemResources testcase

* check memory usage and number of CPUs

* remove Ref.PingReceiver and fixed typos

* fixed spelling fileDownlink,health,systemResources and add config.json file

* Update config.json

* replace ActiveLogger to EventManager

* Updated config.json use lowercase CdhCore and FileHandling(fileDownlink,fileManager,prmDb) and ComCcsds(cmdSeq) etc

* update test_cmd_version to compare version of telemetry channel vs. evr version

* extend max_delay to work with Raspberry pi

* rename config.json to int_config.json

* delete Ref/config.json new file name int_config.json

* add time.sleep between AppendFile cmd to work with rasberry Pi

* fix int_config.json and add new Int DpMgr, DpWriter and DpCatalog

* add comments to confirm /tmp/1MiB.txt and /tmp/test_seq.seq exist before execute script

* add send uplink files

* Rename config.json, fix spelling

* python formatting

---------

Co-authored-by: Cindy T Huynh <chuynh@jpl.nasa.gov>
Co-authored-by: M Starch <LeStarch@googlemail.com>
Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
Co-authored-by: Kevin F. Ortega <kevin.f.ortega@jpl.nasa.gov>
2025-08-29 10:29:39 -07:00
M Starch
b90345e9df
Add test driven development how-to (#4090)
* Add test driven development how-to

* sp; review
2025-08-29 10:28:55 -07:00
M Starch
976ad2b28e
Fix #3397 (#4086) 2025-08-27 18:11:14 -07:00
M Starch
42c665f080
Update project structure in cookiecutters CI (#3991)
* Update project structure

* Fix sourcing path

* fix paths

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
2025-08-27 15:42:51 -07:00
Rob Bocchino
9ec8c559de
Allow FPP arrays of arbitrary size (#4073)
* Revise array tests

Update constructor calls to conform to new code gen
Format the code

* Reformat FppTest

* Revise requirements.txt

* Update requirements.txt

* Update fpp version

* Revise Ref to conform to FPP changes

* Remove trailing spaces

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
2025-08-27 15:24:32 -07:00
M Starch
287a0211eb
Bump GDS to v4.0.2a3 (#4079)
* Bump to v4.0.2a2 (GDS)

* Fix integration tests

* Fix requirements.txt
2025-08-27 14:25:41 -07:00
Ian Brault
d911fb903f
Add event ID filters to text logger components (#4028)
* Add event ID filter to PassiveConsoleTextLogger

* Add event ID filter to ActiveTextLogger

* Add const qualifier to filtered event list pointers

* Fix assert argument types

* Fix clang format errors

* Fix copy-paste error on include file

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Add missing initialization to ActiveTextLogger constructor

---------

Co-authored-by: Ian Brault <ian.r.brault@jpl.nasa.gov>
Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-08-27 12:22:53 -07:00
Thomas Boyer-Chammard
373f81d0f3
Add subtopology documentation (#4072)
* Add subtopology guide

* fix typo and how-to

* Add reference link
2025-08-27 12:13:51 -07:00
Kyle Jones
513582f420
Add logic for assert failure short circuiting in AssertFatalAdapter (#4042)
* Add logic for assertion short circuiting

- Add guard logic to AssertFatalAdapter to prevent a cascading FW_ASSERT chain from occurring
- If any assert checks fail while handling an in-progress assert check failure, reportAssert will log the
additional assert and execute the system-specific assert handler before returning

* Update assert guard logic to counter based

- Instead of using a bool guard to determine when to off-ramp from a series of FW_ASSERT check failures,
use a counter that is configurable in a program's FpConfig.h file

---------

Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-08-27 09:56:06 -07:00
Philip Romano
a20535ea42
Add environment setup to CONTRIBUTING.md (#4078)
* Fix typo `cp` to `cd` in CONTRIBUTING.md

* Mention Python venv requirements for running tests
2025-08-26 17:33:24 -07:00
M Starch
475f323525
Add ground derived channels how-to guide (#4074)
* Initial derived channel work

* Write ground-derived channels

* Update plugin handler

* Updating publishChannel case

Updated method name to follow naming conventions.

* Fix method name to use snake_case in documentation
2025-08-26 14:41:55 -07:00
kevin-f-ortega
94f67e4e21
Update supported platforms (#4071)
* improved step to contribute back

* added delivery date for targeted platforms

* added tbd since we are not sure at the moment

* fixed column data

* updating list of supported targets. This reflects how F Prime runs on these hardware with zephyr.

* alphabetized list and added link for freertos

* fix spelling

* rename Apple M* to Apple Silicon

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
2025-08-25 17:32:20 -07:00
Zimri Leisher
f4439a8cc9
FpySequencer arithmetic (#4025)
* Some work towards stack based arch

* Bring fp/int conv up to date

* Get compiling with stack based arch

* Start trying to fix UTs

* Start adding store/load dirs

* Add push val dir

* UTs are running

* UTs passing

* Make exit stack based

* Fix more uts

* Fix final UTs

* sp

* Fix overflow potential err

* Fix another overflow

* same error fix

* Format

* Also add to format checker

* Add math directives

* Add integer extension and truncation

* Also check correct size on stack

* Fix comment

* Push cmd response to stack

* Cast cmd response code to i32

* Add stack cmd, memcmp, discard dirs

* Fix some bugs with stack cmd

* Fix lil bug in sgtack cmd

* same bug

* Fix another bug sry

* Update sdd

* sp

* Fix undefined behavior with bitshift of signed integer

* sp

* Fix lil bug in timeout detection of stack cmd

* Switch format check to do all Svc dirs

* Reformat, and fix packet descriptor serialize bug

* Add UTs for all of arith ops

* Add tests for disc, memcmp, stack cmd

* Add deser tests for those three dirs

* sp

* Format

* Replace magic numbers with sizeofs

* Add currentStatementIdx helper function

* Format

* Split imod into smod and umod

* sp

* Add fmod, copy python behavior for fmod and smod

---------

Co-authored-by: Zimri Leisher <zimri.leisher@fireflyspace.com>
2025-08-21 14:08:40 -07:00
Rob Bocchino
bdade025d0
Basic data structure library, phase 1 (#3927)
* Revise SDD for SetBase

* Revise SDD for SetBase

* Revise SDD for Fw/DataStructures

* Revise SDD for FifoQueue

* Revise SDD for Fw/DataStructures

* Revise SDD for MapBase

* Revise SDD for StackBase

* Revise SDD for Fw/DataStructures

* Revise SDD for Fw/DataStructures

* Add StackBase.hpp

* Add ExternalStack.hpp

* Add Stack.hpp

* Add ExternalStackTest

* Revise Stack tests

* Revise ExternalStack

* Revise ExternalStackTest

* Revise ExternalStackTest

* Revise ExternalStackTest

* Revise ExternalStackTest

* Add StackTest

* Revise SDD for Fw/DataStructures

* Revise SDD for Fw/DataStructures

* Revise SDD for Fw/DataStructures

* Add MapIterator

* Add SetIterator

* Add SetOrMapIterator

* Add MapBase.hpp

* Revise SDD for Fw/DataStructures

* Revise SDD for ArraySetOrMapImpl

* Revise SDD for ArraySetOrMapImpl

* Revise SDD for ExternalArray

* Revise SDD for Fw/DataStructures

* Revise SDD for Fw/DataStructures

* Revise MapBase

* Revise MapBase

* Revise comments

* Revise SDD for ArraySetOrMapImpl

* Revise Fw/DataStructures

* Add ArraySetOrMapImpl

* Add ExternalArrayMap

* Revise ExternalArrayMap

* Revise Fw/DataStructures

* Revise SetBase

* Revise SDD for Fw/DataStructures

* Revise SDD for ExternalArraySet

* Revise SDD for ExternalArraySet

* Revise SDD for ArraySetOrMapImpl

* Revise Fw/DataStructures

* Revise SDD for Fw/DataStructures

* Revise Fw/DataStructures tests

* Revise unit tests for Fw/DataStructures

* Revise tests for ArraySetOrMapImpl

* Revise unit tests for Fw/DataStructures

* Revise unit tests for Fw/DataStructures

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for Fw/DataStructures

* Revise SDD for SetOrMapIterator

* Add ExternalArrayMapTest

* Revise ExternalArrayMapTest

* Revise design for sets and maps

* Revert changes to design

* Revise unit tests for Fw/DataStructures

* Revise unit tests for Fw/DataStructures

* Revise ExternalArrayMapTest

* Revise ExternalArrayMapTest

* Revise unit tests for ArraySetOrMapImpl

* Revise ExternalArrayMapTest

* Revise ExternalArrayMapTest and MapTest

* Revise MapTestScenarios

* Revise ExternalArrayMapTest

* Revise ExternalArrayMapTest

* Revise ExternalArrayMapTest

* Revise array set and map

Remove at function from interface.
It breaks the array or set abstraction.
It provides little value, since one can use the iterator
provided by SetBase or MapBase to range over the elements.

* Revise ExternalArrayMapTest

* Add ExternalArraySetTest

* Revise ExternalArraySet and ExternalArrayMap

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest and ExternalArrayMapTest

* Revise ArraySetOrMapImplTest

* Revise ExternalArrayMapTest

* Revise ExternalArraySetTest

* Revise SDD for ArrayMap

* Revise SDD for ArraySet

* Revise SDD for ArraySet

* Add ArrayMap

* Revise ArrayMapTest

* Revise Fw/DataStructures

* Revise SDDs for ArrayMap and ArraySet

* Revise Fw/DataStructures

* Refactor map test scenarios

* Refactor data structures tests

* Refactor SetTestScenarios

* Refactor FifoQueueTestScenarios

* Refactor ExternalFifoQueueTest

* Revise Fifo Queue tests

* Refactor ExternalFifoQueueTest

* Revise comments

* Revise Stack tests

* Revise Stack tests

* Refactor Stack tests

* Revise Stack tests

* Revise Array

Remove getStaticSize

* Refactor Fifo tests

* Refactor ArraySetOrMapImplTest

* Revise data structures design

Rename Iterator to Entry

* Revise data structures implementation

Rename Iterator to Entry

* Revise data structures impl and test

Rename Iterator to Entry throughout

* Revise data structures implementation

Rename SetOrMapEntry to SetOrMapImplEntry

* Revise data structure implementation

Rename Entry to ImplEntry

* Revise data structures design

Rename symbols to match implementation

* Revise design for data structures

Add ConstIterator to Map

* Revise ArraySetOrMapImpl

Add ConstIterator

* Add iterators to DS implementation

* Revise map iteration

* Revise unit tests

Use iterators for maps

* Revise iterators

* Revise iterators

* Rename MapEntry to MapConstEntry

* Revise map interface

* Rename SetOrMapImplEntry to SetOrMapImplConstEntry

* Revert "Rename SetOrMapImplEntry to SetOrMapImplConstEntry"

This reverts commit cc6371d03c8f65fa130212d589812cf4ab3714fe.

* Rename SetEntry to SetConstEntry

* Add SetConstIterator

* Revise SetBase and unit tests

Use iterators

* Revise set interface

* Revise comments

* Reformat code

* Revise array set and map impl

Remove forward links

* Revise data structures tests

* Revise Set iterator

* Remove SetConstEntry

* Refactor SetOrMapImplEntry

* Pull in changes from rb-tree branch

* Revise MapBase

* Revise MapBase and docs

* Revise MapBase

* Revise MapBase

* Revise iterators

* Revise MapConstIterator docs

* Rename MapConstEntry to MapEntry

* Revise MapEntry

* Fix MapBase docs

* Revise MapConstIterator

* Revise MapEntry

* Revise MapConstIterator docs

* Revise docs for ExternalArrayMap

* Revise ArrayMap docs

* Revise ArraySetOrMapImpl

* Revise SetOrMapImplEntry

* Revise MapEntry

* Revise map and set interfaces

* Revert changes to map interface

* Rename MapEntry to MapEntryBase

* Revise type aliases

* Reformat code

* Revise SetBase

* Revise map interface

* Revise set and map interface

* Revise ExternalArraySet docs

* Revise ArraySet

* Revise ArraySet docs

* Revise SetConstIterator

* Revise SetBase

* Revise SetBase docs

* Revise SetBase

* Revise ArraySet

* Revise ArraySet docs

* Revise ExternalArraySet docs

* Add SetOrMapImplEntry

* Revise ArraySetOrMapImpl

* Revise Fw/DataStructures

Reformat code

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise Fw/DataStructures

Fix compile errors on Linux

* Fix comments

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise ArrayMap docs

* Remove helper scripts

* Revise tests for Fw/DataStructures

* Fix spelling

* Fix Markdown link

* Fix uninitialized variable in test

* Fix uninitialized variable in test

* Fix "spelling"

Why is the spelling check enforcing arbitrary rules of style?

* Fix comments

* Revise tests for ArraySetOrMapImpl

* Revise comment

* Revise ArraySetOrMap impl

* Revise formatting

* Revise docs

* Revise docs for Fw/DataStructures

* Revise Array and ExternalArray

Add static assertions

* Revise FifoQueue and Stack

Add static assertions

* Revise ArraySet and ArrayMap

Add static assertions

* Revise ArrayMap tests

* Revise ExternalArraySet tests

* Refactor ArraySetTest

* Revise array initialization

* Revise comments

* Revise Array initialization

* Revise Array design and implementation

* Revert changes to Fw/DataStructures

* Revise Array

* Revise Array

* Revise Array

* Fix formatting

* Add SizedContainer base class

* Revise StackBase

Make it inherit from SizedContainer
Revise stack tests

* Revise MapBase

Make it inherit from SizedContainer
Revise tests

* Revise SetBase

Make it inherit from SizedContainer
Revise tests

* Revise DataStructures design

Add SizedContainer

* Revise SDD for DataStructures

* Revise DataStructures design

* Revise DataStructures design

* Revise DataStructures design

* Revise DataStructures design

* Fix spelling

* Revise zero-arg constructor for Array

* Revise Array interface

Make it consistent with the arrays generated by FPP

* Fix to assertion
2025-08-21 13:56:35 -07:00
Thomas Boyer-Chammard
6915c93c10
Update Drv IP stack to use FwSizeType instead of U32 (#4013)
* Update IP stack source to use SizeType instead of I/U32

* Update UTs reflecting U32/I32 change to SizeType

* Static cast sizes per review

* Fix commented out thing
2025-08-21 08:55:17 -07:00
Rob Bocchino
7972392cf4
Reformat FppTest (#4048) 2025-08-19 17:48:16 -07:00
M Starch
d6cd606e66
Update NOTICE.txt references (#4045)
With the removal of the Autocoders directory, we also remove the pyparsestring usage.
2025-08-19 10:54:26 -07:00
Thomas Boyer-Chammard
a070ee768a
Fix AI Policy link in PR template (#4019) 2025-08-13 14:25:03 -07:00
Zimri Leisher
30a3902e3e
FpySequencer stack based architecture (#3975)
* Some work towards stack based arch

* Bring fp/int conv up to date

* Get compiling with stack based arch

* Start trying to fix UTs

* Start adding store/load dirs

* Add push val dir

* UTs are running

* UTs passing

* Make exit stack based

* Fix more uts

* Fix final UTs

* sp

* Fix overflow potential err

* Fix another overflow

* same error fix

* Update sdd

* sp

* Fix undefined behavior with bitshift of signed integer

* sp

---------

Co-authored-by: Zimri Leisher <zimri.leisher@fireflyspace.com>
2025-08-13 09:51:30 -07:00
Ethan Chee
2dea8abedf
Add static_cast to ambiguous serialize call in FpySequencer (#4008) 2025-08-10 13:46:44 -07:00
Thomas Boyer-Chammard
abb09e4a68
Bump Tools and GDS (#4000)
Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-08-06 17:42:06 -07:00
Thomas Boyer-Chammard
4e5bb71460
Fix HelloWorld CI following update to v4.0 (#3997) 2025-08-06 16:02:15 -07:00
Amber Borjigin
b72d866d19
Generative AI documentation Added (#3932)
* fixing error #3897

* Generative AI documentation added

* Update GENERATIVE_AI.md

* Update GENERATIVE_AI.md

* Update pull_request_template.md

resolving comments

* Update OsTime.cpp

resolving comment

* updating expect.txt to have "GPT"

* Update GENERATIVE_AI.md

Co-authored-by: Rob Bocchino <bocchino@icloud.com>

* Fix relative link and display

* updates to GENERATIVE_AI.md

* Fix merge

* Update GENERATIVE_AI.md

* Update cross-compilation.md

* reverting back to AI b/c branch confusion

* updating disclosure and file name

* Update to current in fprime devel

* Fix relative link and display

---------

Co-authored-by: M Starch <LeStarch@googlemail.com>
Co-authored-by: Rob Bocchino <bocchino@icloud.com>
Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
2025-08-06 15:32:52 -07:00
M Starch
4deda3d75f
Update to FPP v3.0.0, Tools v4.0.0, and GDS v4.0.0 (#3995)
* Update to FPP v3.0.0

* Bump GDS and tools version
2025-08-06 13:50:58 -07:00
Vince Woo
f38010abca
(De)Serialization clean up of temporary workarounds (#3971)
* Staging DEPRECATE changes in preparation for new FPP alpha. Removed backwards compat hacks. Updated some uses of the legacy functions that were missed originally.

* Remove declaration of serialize and deserialize from RawTime as those should be inherited now

* Removing FW_SERIALIZE_UNIMPLEMENTED and FW_DESERIALIZE_UNIMPLEMENTED from SerializeStatus

* Removing superfluous comma

* Missed AmpcsEvrLogPacket. Fixing a minor whitespace issue in Serializable.

* Un-deprecating serialize/deserialize for this release

* Restoring DEPRECATED for the noLength functions

* Pulling in fpp 3.0.0a17. Fixing some lingering issues with refactoring.

* Format files

* Update fprime-fpp package

* Fixing some lingering issues with serialization modernization.

* Fixing weird merge issue with AmpcsEvrLogPacket

* More clang issue fixes

* Still pesky clang formatting issues. Superfluous whitespace.

* Removing redundant virtuals for overriden methods

* Incorporating PR comments

* clang formatted Serializable.hpp

* Removing redundant serialize and deserialize methods in TestAbsType. Inherit from parent.

---------

Co-authored-by: thomas-bc <thomas.boyerchammard@gmail.com>
2025-08-06 11:50:32 -07:00
Thomas Boyer-Chammard
89bccfa438
Differentiate sync/async ByteStreamDriver and update ComStub to work with both (#3987)
* Update ByteStream interface, interface implementations (and UTs) and ComStub

* Update ComStub UTs

* Fix RHEL8 static cast failure

* spelling

* Update Async driver to async port

* Make code more readable... part 1

* Refactor code for human readability

* Update docs

* Remove unused helper
2025-08-06 11:21:06 -07:00
M Starch
96f445f6ef
Update teardown ordering (#3990) 2025-08-06 11:19:08 -07:00
Joaquim Silveira
ab16b2aabf
feat: removed unnecessary assert (#3973) 2025-08-06 09:37:20 -07:00
Thomas Boyer-Chammard
be7e4ea098
Fix F Prime location in LedBlinker CI (#3988)
* Fix F Prime location in LedBlinker CI

* Fix framing-selection
2025-08-05 18:51:01 -07:00
M Starch
21faffa6f8
CMake documentation refactor (#3981)
* CMake documentation refactor

* sp

* Update cmake-implementations.md
2025-08-05 16:52:14 -07:00
Justine West
dfaf496263
Add DP Demo for testing DPs and fprime-dp-writer (#3951)
* Initial DpDemo component, added test for decoding DPs

* Updated Dp demo to include additional types, arrays, and struct records

* Added struct member array to DP demo

* Remove unused tlm

* Cleanup after merging devel

* Add deepdiff to requirements, fix formatting, update spelling

* fpp v3.0.0a16

* fprime-gds v4.0.0a10

* Add 3 array record cases to DP demo

* Remove comments

* Remove deepdiff

* Formatting, update spelling

* FPP v3.0.0a18

* Spelling

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
2025-08-05 12:28:00 -07:00
M Starch
d460468b1b
Rate drive sent/receive telemetry (#3980)
* Rate drive sent/receive telemetry

* Format

* Make telemetry std::atomic
2025-08-05 09:37:45 -07:00
Thomas Boyer-Chammard
c69ff72110
Format Svc and add to CI (#3978)
* Format Svc and add to CI

* Fix comlogger include

* fix assert UTs

* Fix static analysis warning

* formatting
2025-08-04 16:21:47 -07:00
Amber Borjigin
e7840dee81
Update cross-compilation.md (#3979) 2025-08-04 15:41:32 -07:00
M Starch
5ce0c5ada8
Bump fprime-tools version (#3972)
* Bump fprime-tools version

* Fix relative path problem
2025-08-04 14:05:54 -07:00
M Starch
feb1418a0f
Fix LinuxUartDriver bytes count (#3948)
* Add bytes sent telemetry

* Add bytes received

* Fix missing m_

* Casting

* formatting

---------

Co-authored-by: Joseph AD <223160513+bojops@users.noreply.github.com>
Co-authored-by: Bobbie AD <223160241+bagamerguy@users.noreply.github.com>
2025-08-04 13:50:17 -07:00
Thomas Boyer-Chammard
ab58cf18fb
Format Fw and add to CI (#3976)
* Format Fw and add to CI

* Fix include of HPP file instead of H in extern C

* Fix format strings
2025-08-04 12:56:02 -07:00
Mishaal
02afd01545
Fix warnings reported by clang-tidy 20.1 (#3949)
* Clang 20.1 UT Errors

* CI fixes

* Remove m_rng and use STest

* 1 more update to STest

* Resolve spellcheck conflict

* Resolve spellcheck conflict

* Init severityString to null ptr

* Fix CPP formatting

* Format QueueRules.cpp

---------

Co-authored-by: thomas-bc <thomas.boyerchammard@gmail.com>
Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
2025-08-01 17:21:07 -07:00
Thomas Boyer-Chammard
60e7cb7993
Remove XML dependencies from requirements (#3961)
* Remove XML dependencies from requirements

* Upgrade fprime-tools

* Fix locate_fpp_tools version check
2025-08-01 16:24:06 -07:00
Andrei Tumbar
bf7d9866cf
Improve backward compatibility [de]serialize[From/To] fallback on Fw::Serializable and Fw::Buffer (#3962) 2025-08-01 13:28:32 -07:00
Amber Borjigin
29b9f2b4bf
Bump GDS to latest release (#3964)
* Bump GDS to latest release 

Fixes #3963

* Set LEDBlinker to FPrime Framing

* Set Rasbperry Pi Integration Test Framer

* Remove spurious 'g'

---------

Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-08-01 08:52:22 -07:00
Justine West
67be6defa0
Update data types doc (#3957)
* Update data types docs

* Move alias type to its own section
2025-07-31 15:52:15 -07:00
Thomas Boyer-Chammard
e17d42a9ff
Format Drv module (#3960)
* Format Drv module

* Add Drv to format CI check

* Fix double // in include path
2025-07-31 15:49:45 -07:00
Thomas Boyer-Chammard
578e61f1da
Format Os Module (#3959)
* Format Os module

* Add Os to format-check CI

* Remove double semi-colon
2025-07-31 15:40:30 -07:00
Kyle Jones
26aad95ec0
Updates Types.fpp to use optimized sizes for enumerations (#3956)
- Update enumerations in Types.fpp to use U8 instead of the default I32; the full I32 size is not needed for these simple enumerations
2025-07-31 15:14:19 -07:00
1440 changed files with 76988 additions and 45912 deletions

View File

@ -2,4 +2,5 @@
BasedOnStyle: Chromium
IndentWidth: 4
ColumnLimit: 120
AccessModifierOffset: -2
AccessModifierOffset: -2
InsertNewlineAtEOF: true

View File

@ -6,6 +6,6 @@ Checks: >
modernize-redundant-void-arg,
modernize-use-bool-literals,
modernize-use-nullptr,
readability-braces-around-statements
-clang-analyzer-security.insecureAPI.rand,
readability-braces-around-statements,
-clang-analyzer-security.insecureAPI.rand
WarningsAsErrors: '*'

View File

@ -1,5 +1,7 @@
set timeout 180
spawn fprime-bootstrap project
expect -re {.*Project name.*}
expect -re {.*Project repository name.*}
send "my-project\r"
expect -re {.*Project top-level namespace.*}
send "MyProject\r"
expect eof

View File

@ -2,6 +2,8 @@ set timeout 60
spawn fprime-util new --deployment
expect -re {Deployment name.*}
send "MyDeployment\r"
expect -re {Deployment namespace.*}
send "MyNamespace\r"
expect -re {.*Select communication driver type}
send "1\r"
expect -re "Add .*MyDeployment.*"

View File

@ -32,13 +32,19 @@ baremetal
batchmode
BDV
bfree
BHn
bibtex
Bies
binaryfile
BINDIR
bitmaps
bitshifts
bitwidth
bocchino
boolt
bsd
BSDI
bst
BUFFERALLOCATE
BUFFERALLOCATIONFAILED
BUFFERGETOUT
@ -58,6 +64,7 @@ Campuzano
carg
CBF
CBLOCK
CCACHE
CCB
CComponent
ccsds
@ -110,6 +117,7 @@ coravy
coreutils
Coverity
CPHA
CPIU
cplusplus
CPOL
cppcheck
@ -136,6 +144,7 @@ CYCLEOUT
DATAPRODUCTS
DATAPRODUCTSSUBTOPOLOGY
DATAROOTDIR
datasheet
DDDTHH
Debian
deconstructor
@ -177,6 +186,7 @@ DPWRITER
DRAINBUFFERS
drv
drvtcpserversocket
DSL
dspal
DSSC
Dstate
@ -189,6 +199,7 @@ ECLIPSEHELP
EHAs
eip
Elts
emptydir
endcond
endfunction
endmacro
@ -209,6 +220,7 @@ externalproject
FAKELOGGER
fbuild
fdp
featherm
fecf
FEEDNAME
feq
@ -222,17 +234,20 @@ FILEDOWNLINKCFG
FILEHANDLING
FILEHANDLINGSUBTOPOLOGY
FILEID
FILEMANAGERCONFIG
FILEOPENERROR
FILEWRITEERROR
fio
fle
FNDELAY
fne
fontcolor
FONTPATH
foodoodie
foodoodiehoo
FPCONFIG
fpext
fpow
fpp
fppi
fpptest
@ -243,13 +258,12 @@ fptr
fptrunc
fputil
fpy
fpyc
FPYSEQUENCER
freeram
Fregoso
fres
frsize
fsblkcnt
fsrc
fsw
FWCASSERT
gcda
@ -270,6 +284,7 @@ gpiochip
gpioevent
gpiohandle
gpioline
GPT
Graphviz
grayscales
GROUNDINTERFACERULES
@ -277,6 +292,7 @@ GSE
gtags
gtest
gtimeout
GTK
Guire
GVCID
HACKSM
@ -303,40 +319,41 @@ HTMLHELP
ibd
ieeetr
ieq
iext
iflag
ifstr
ilhs
imple
inbool
INCLUDEDIR
ine
initstate
inkscape
inorder
installable
intlimits
inttypes
INVALIDBUFFER
INVALIDHEADER
INVALIDHEADERHASH
invis
invisi
ioc
ioctl
ipas
IPCFG
IPHELPER
irhs
isf
isgreater
isgreaterequal
isless
islessequal
isr
isrc
isunordered
itimerspec
itr
itrunc
itval
janamian
jawest
Jax
jdk
jdperez
@ -367,12 +384,15 @@ LINEEVENT
LINEHANDLE
linelength
lineoffset
LISTDIRECTORY
lld
llu
LOCALSTATEDIR
LOGGERRULES
LOGPACKET
lseek
LTK
lvar
LVL
lxml
MACROFILE
@ -400,6 +420,7 @@ MMAPALLOCATOR
MML
modbus
MOVEFILE
Mpu
msc
mscfile
mseconds
@ -417,6 +438,10 @@ ncsl
newtio
nmsgs
NOBLOCK
NODELABEL
noinline
NOLINT
NOLINTNEXTLINE
noparent
norecords
NOSPEC
@ -439,6 +464,7 @@ openmct
openpyxl
openssldir
optarg
optin
optind
orgslist
ortega
@ -472,6 +498,7 @@ patsubst
pdflatex
penv
PERLMOD
PHASERMEMBEROUT
PINGENTRIES
PINGSEND
pkill
@ -486,6 +513,7 @@ PORTOUT
PORTSELECTOR
ppandian
pregen
prescaler
prioritization
PRIORITYQUEUE
prm
@ -529,6 +557,7 @@ RATELIMITERTESTER
rawtime
RAWTIMETESTER
RBF
rbt
RCHILD
rcvd
rdwr
@ -558,6 +587,7 @@ sbom
scid
scm
sdd
sdiv
searchdata
SENDPARTIAL
seqgen
@ -565,10 +595,10 @@ serializables
setaffinity
setinheritsched
SETLOGGING
setname
setprotocol
setschedparam
setschedpolicy
setser
setstacksize
settime
sev
@ -580,11 +610,13 @@ SHAREDSTATEDIR
SHELLCOMMAND
showinitializer
sideeffect
siext
Signedness
Silveira
sitofp
sle
sloc
smod
socio
SOCKETHELPER
SOCKETIPDRIVER
@ -675,13 +707,15 @@ tparam
TPP
trinomials
tts
typedef'ed
typedef
typedef'ed
uart
udiv
UDPSOCKET
uge
uitofp
UML
umod
UNEXP
unistd
UNITTESTASSERT
@ -708,9 +742,11 @@ wrs
wxgui
wxy
Xapian
XBee
xdf
xdffe
xsltproc
xxxx
XXYY
ziext
zimri

View File

@ -3,20 +3,25 @@
|**_Related Issue(s)_**| |
|**_Has Unit Tests (y/n)_**| |
|**_Documentation Included (y/n)_**| |
|**_Generative AI was used in this contribution (y/n)_**| |
---
## Change Description
A description of the changes contained in the PR.
<!-- A description of the changes contained in the PR. -->
## Rationale
A rationale for this change. e.g. fixes bug, or most projects need XYZ feature.
<!-- A rationale for this change. e.g. fixes bug, or most projects need XYZ feature. -->
## Testing/Review Recommendations
Fill in testing procedures, specific items to focus on for review, or other info to help the team verify these changes are flight-quality.
<!-- Fill in testing procedures, specific items to focus on for review, or other info to help the team verify these changes are flight-quality. -->
## Future Work
Note any additional work that will be done relating to this issue.
<!-- Note any additional work that will be done relating to this issue. -->
## AI Usage (see [policy](https://github.com/nasa/fprime/blob/devel/AI_POLICY.md))
<!-- If AI was used, please describe how it was utilized (e.g., code generation, documentation, testing, debugging assistance, etc.). -->

View File

@ -38,7 +38,7 @@ jobs:
- uses: ./.github/actions/setup
- name: Build Framework
run: |
fprime-util generate
fprime-util generate -DFPRIME_ENABLE_JSON_MODEL_GENERATION=ON
fprime-util build --all -j4
Ref:
@ -59,7 +59,7 @@ jobs:
- name: Build Ref
run: |
cd Ref
fprime-util generate
fprime-util generate -DFPRIME_ENABLE_JSON_MODEL_GENERATION=ON
fprime-util build -j4
UTs:

View File

@ -48,8 +48,9 @@ jobs:
fprime-util generate -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
fprime-util build --all --jobs "$(nproc || printf '%s\n' 1)"
# Since our subtopologies have EXCLUDE_FROM_ALL, we need to explicitly build them
# Add EXCLUDE_FROM_ALL targets as we need to explicitly build them
fprime-util build --target Svc_Subtopologies --jobs "$(nproc || printf '%s\n' 1)"
fprime-util build --target Svc_GenericHub --jobs "$(nproc || printf '%s\n' 1)"
echo CPPCHECK_OPTS=--project="$GITHUB_WORKSPACE/build-fprime-automatic-native/compile_commands.json" >> $GITHUB_ENV
- name: Run cppcheck

View File

@ -23,6 +23,7 @@ env:
AARCH64_TOOLCHAIN_DIR: /tmp/aarch64-toolchain
AARCH64_TOOLCHAIN_URL: https://developer.arm.com/-/media/Files/downloads/gnu-a/10.2-2020.11/binrel/gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu.tar.xz
ARM_TOOLS_PATH: /tmp/aarch64-toolchain
FPRIME_LOCATION: ./lib/fprime
jobs:
get-branch:
@ -46,11 +47,11 @@ jobs:
uses: actions/checkout@v4
with:
submodules: true
path: ./fprime
path: ${{ env.FPRIME_LOCATION }}
fetch-depth: 0
- uses: ./fprime/.github/actions/setup
- uses: ./lib/fprime/.github/actions/setup
with:
location: ./fprime
location: ${{ env.FPRIME_LOCATION }}
- name: "Download and Setup AArch64 Linux Toolchain"
run: |
mkdir -p ${AARCH64_TOOLCHAIN_DIR}
@ -67,8 +68,8 @@ jobs:
run: |
mkdir -p aarch64-linux-artifacts
cp -r ./build-artifacts aarch64-linux-artifacts
cp -r Components/Led/test/int aarch64-linux-artifacts
- name: 'Archive Build Artifacts'
cp -r LedBlinker/Components/Led/test/int aarch64-linux-artifacts
- name: "Archive Build Artifacts"
uses: actions/upload-artifact@v4
with:
name: aarch64-linux-artifacts
@ -83,7 +84,7 @@ jobs:
- name: "Checkout F´ Repository"
uses: actions/checkout@v4
with:
sparse-checkout: 'requirements.txt'
sparse-checkout: "requirements.txt"
sparse-checkout-cone-mode: false
- name: "Setup environment"
run: |
@ -96,13 +97,14 @@ jobs:
name: aarch64-linux-artifacts
- name: Run Integration Tests
run: |
DEPLOYMENT=LedBlinker_LedBlinkerDeployment
. venv/bin/activate
mkdir -p ci-logs
chmod +x ./build-artifacts/aarch64-linux/LedBlinker/bin/LedBlinker
fprime-gds --ip-client -d ./build-artifacts/aarch64-linux/LedBlinker --logs ./ci-logs &
chmod +x ./build-artifacts/aarch64-linux/${DEPLOYMENT}/bin/${DEPLOYMENT}
fprime-gds --ip-client -d ./build-artifacts/aarch64-linux/${DEPLOYMENT} --logs ./ci-logs &
sleep 10
pytest --dictionary ./build-artifacts/aarch64-linux/LedBlinker/dict/LedBlinkerTopologyDictionary.json ./int/led_integration_tests.py
- name: 'Archive logs'
pytest --dictionary ./build-artifacts/aarch64-linux/${DEPLOYMENT}/dict/LedBlinkerDeploymentTopologyDictionary.json ./int/led_integration_tests.py
- name: "Archive logs"
uses: actions/upload-artifact@v4
if: always()
with:

View File

@ -31,6 +31,7 @@ jobs:
uses: ./.github/workflows/reusable-project-builder.yml
with:
target_repository: fprime-community/fprime-tutorial-hello-world
build_location: HelloWorldDeployment
fprime_location: ./lib/fprime
build_location: Hello/HelloWorldDeployment
run_unit_tests: false # no UTs in HelloWorld project
target_ref: ${{ needs.get-branch.outputs.target-branch }}

View File

@ -31,6 +31,7 @@ jobs:
uses: ./.github/workflows/reusable-project-builder.yml
with:
target_repository: fprime-community/fprime-workshop-led-blinker
build_location: LedBlinker
fprime_location: lib/fprime
build_location: LedBlinker/LedBlinkerDeployment
run_unit_tests: true
target_ref: ${{ needs.get-branch.outputs.target-branch }}

View File

@ -31,6 +31,7 @@ jobs:
uses: ./.github/workflows/reusable-project-builder.yml
with:
target_repository: fprime-community/fprime-tutorial-math-component
build_location: MathDeployment
build_location: MathProject/MathDeployment
fprime_location: ./lib/fprime
run_unit_tests: true
target_ref: ${{ needs.get-branch.outputs.target-branch }}

View File

@ -73,41 +73,43 @@ jobs:
uses: actions/checkout@v4
with:
submodules: true
path: ./MyProject/lib/fprime
path: ./my-project/lib/fprime
fetch-depth: 0
- name: "Update dependencies and install fprime-tools"
run: |
cd MyProject
cd my-project
. fprime-venv/bin/activate
pip install -U -r ./lib/fprime/requirements.txt
pip install -U -r ./requirements.txt
pip install git+https://github.com/nasa/fprime-tools@${{ needs.get-tools-branch.outputs.target-branch }}
- name: "Version Check"
run: |
cd MyProject
cd my-project
. fprime-venv/bin/activate
fprime-util version-check
- name: "Test Generate and Build Project"
run: |
cd MyProject
cd my-project
. fprime-venv/bin/activate
fprime-util generate
fprime-util build -j4
- name: "Test New Deployment and Build"
run: |
cd MyProject
cd my-project
. fprime-venv/bin/activate
expect ./lib/fprime/.github/actions/cookiecutter-check/deployment.expect
cd MyProject
expect ../lib/fprime/.github/actions/cookiecutter-check/deployment.expect
cd MyDeployment
fprime-util build -j4
- name: "Test New Component and Build"
run: |
cd MyProject
cd my-project
. fprime-venv/bin/activate
expect ./lib/fprime/.github/actions/cookiecutter-check/component.expect
cd MyProject
expect ../lib/fprime/.github/actions/cookiecutter-check/component.expect
cd MyComponent
fprime-util build -j4

View File

@ -0,0 +1,36 @@
# Cross-compile https://github.com/fprime-community/fprime-zephyr-reference
name: "External Repo: Zephyr Reference (Pico 2)"
on:
push:
branches: [ devel, release/** ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ devel, release/** ]
paths-ignore:
- 'docs/**'
- '**.md'
- '.github/actions/spelling/**'
- '.github/ISSUE_TEMPLATE/**'
# Cancel in-progress runs if a newer run is started on a given PR
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ !contains(github.ref, 'devel') && !contains(github.ref, 'release/')}}
jobs:
get-branch:
name: "Get target branch"
uses: ./.github/workflows/reusable-get-pr-branch.yml
with:
target_repository: fprime-community/fprime-zephyr-reference
build:
name: "Zephyr Build"
needs: get-branch
uses: ./.github/workflows/reusable-project-ci.yml
with:
target_repository: fprime-community/fprime-zephyr-reference
target_ref: ${{ needs.get-branch.outputs.target-branch }}
ci_config_file: ./lib/fprime-zephyr/ci/sample-configs/pico2.yml

View File

@ -0,0 +1,36 @@
# Cross-compile https://github.com/fprime-community/fprime-zephyr-reference
name: "External Repo: Zephyr Reference (Teensy 4.1)"
on:
push:
branches: [ devel, release/** ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ devel, release/** ]
paths-ignore:
- 'docs/**'
- '**.md'
- '.github/actions/spelling/**'
- '.github/ISSUE_TEMPLATE/**'
# Cancel in-progress runs if a newer run is started on a given PR
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ !contains(github.ref, 'devel') && !contains(github.ref, 'release/')}}
jobs:
get-branch:
name: "Get target branch"
uses: ./.github/workflows/reusable-get-pr-branch.yml
with:
target_repository: fprime-community/fprime-zephyr-reference
build:
name: "Zephyr Build"
needs: get-branch
uses: ./.github/workflows/reusable-project-ci.yml
with:
target_repository: fprime-community/fprime-zephyr-reference
target_ref: ${{ needs.get-branch.outputs.target-branch }}
ci_config_file: ./lib/fprime-zephyr/ci/sample-configs/teensy41.yml

View File

@ -21,6 +21,7 @@ concurrency:
env:
RPI_TOOLCHAIN_DIR: /tmp/rpi-toolchain
FPRIME_LOCATION: ./lib/fprime
jobs:
get-branch:
@ -44,11 +45,11 @@ jobs:
uses: actions/checkout@v4
with:
submodules: true
path: ./fprime
path: ${{ env.FPRIME_LOCATION }}
fetch-depth: 0
- uses: ./fprime/.github/actions/setup
- uses: ./lib/fprime/.github/actions/setup
with:
location: ./fprime
location: ${{ env.FPRIME_LOCATION }}
- name: "Setup RPI Toolchain"
uses: fprime-community/setup-rpi-sysroot@main
- name: "Generate RPI Build Cache"
@ -56,13 +57,14 @@ jobs:
fprime-util generate raspberrypi
- name: "Build RPI"
run: |
cd LedBlinker/LedBlinkerDeployment
fprime-util build raspberrypi
- name: "Prepare artifacts"
run: |
mkdir -p rpi-artifacts
cp -r ./build-artifacts rpi-artifacts
cp -r Components/Led/test/int rpi-artifacts
- name: 'Archive Build Artifacts'
cp -r LedBlinker/Components/Led/test/int rpi-artifacts
- name: "Archive Build Artifacts"
uses: actions/upload-artifact@v4
with:
name: rpi-artifacts
@ -77,7 +79,7 @@ jobs:
- name: "Checkout F´ Repository"
uses: actions/checkout@v4
with:
sparse-checkout: 'requirements.txt'
sparse-checkout: "requirements.txt"
sparse-checkout-cone-mode: false
- name: "Setup environment"
run: |
@ -90,13 +92,14 @@ jobs:
name: rpi-artifacts
- name: Run Integration Tests
run: |
DEPLOYMENT=LedBlinker_LedBlinkerDeployment
. venv/bin/activate
mkdir -p ci-logs
chmod +x ./build-artifacts/raspberrypi/LedBlinker/bin/LedBlinker
fprime-gds --ip-client -d ./build-artifacts/raspberrypi/LedBlinker --logs ./ci-logs &
chmod +x ./build-artifacts/raspberrypi/${DEPLOYMENT}/bin/${DEPLOYMENT}
fprime-gds --ip-client -d ./build-artifacts/raspberrypi/${DEPLOYMENT} --logs ./ci-logs &
sleep 10
pytest --dictionary ./build-artifacts/raspberrypi/LedBlinker/dict/LedBlinkerTopologyDictionary.json ./int/led_integration_tests.py
- name: 'Archive logs'
pytest --dictionary ./build-artifacts/raspberrypi/${DEPLOYMENT}/dict/LedBlinkerDeploymentTopologyDictionary.json ./int/led_integration_tests.py
- name: "Archive logs"
uses: actions/upload-artifact@v4
if: always()
with:

View File

@ -29,12 +29,19 @@ jobs:
- uses: ./.github/actions/setup
- name: "Check C++ Formatting"
env:
# Svc is currently listing all but Svc/FpySequencer
CHECKED_DIRS: >-
Fw/Buffer
Fw/Cmd
Fw/Com
Svc/Ccsds
Svc/EventManager
CFDP
default
Drv
FppTestProject
Fw
Os
Ref
Svc
TestUtils
Utils
run: |
fprime-util format --check --dirs $CHECKED_DIRS
shell: bash

View File

@ -33,7 +33,7 @@ jobs:
- name: "Generate UT build cache"
working-directory: ./FppTestProject
run: |
fprime-util generate --ut
fprime-util generate --ut -DFPRIME_ENABLE_JSON_MODEL_GENERATION=ON
shell: bash
- name: "Build UTs"
working-directory: ./FppTestProject/FppTest

View File

@ -30,7 +30,7 @@ jobs:
- name: "Generate Ref Deployment"
working-directory: ./Ref
run: |
fprime-util generate
fprime-util generate -DFPRIME_ENABLE_JSON_MODEL_GENERATION=ON
shell: bash
- name: "Run fpp-to-json on Ref topology"
working-directory: ./Ref/Top

View File

@ -6,10 +6,10 @@ name: Python Dependency Check
on:
push:
paths:
- 'requirements.txt'
- "requirements.txt"
pull_request:
paths:
- 'requirements.txt'
- "requirements.txt"
# Cancel in-progress runs if a newer run is started on a given PR
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@ -21,8 +21,8 @@ jobs:
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
# macos-13 is the last Intel-family runner; macos-latest is ARM
runner: [macos-13, macos-latest, ubuntu-22.04, ubuntu-latest]
# Purposefully test on both ARM and Intel macOS (macos-latest is ARM)
runner: [macos-15-intel, macos-latest, ubuntu-22.04, ubuntu-latest]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}

View File

@ -34,14 +34,16 @@ jobs:
- name: "Get target branch"
id: get_target_branch
run: |
BRANCH_NAME="${GITHUB_REF#refs/heads/}"
echo "Looking for 'pr-${{ github.event.number }}'/'${BRANCH_NAME}'"
response_code_pr=`curl -w '%{response_code}' https://api.github.com/repos/${{ inputs.target_repository }}/branches/pr-${{ github.event.number }} -o /dev/null`
response_code_base=`curl -w '%{response_code}' https://api.github.com/repos/${{ inputs.target_repository }}/branches/${{ github.event.pull_request.base.ref }} -o /dev/null`
response_code_branch=`curl -w '%{response_code}' https://api.github.com/repos/${{ inputs.target_repository }}/branches/${BRANCH_NAME} -o /dev/null`
if [[ "${{ github.event_name }}" == "pull_request" && "$response_code_pr" == "200" ]]; then
echo "TARGET_BRANCH=pr-${{ github.event.number }}" >> $GITHUB_OUTPUT
echo "PR branch found, using pr-${{ github.event.number }}"
elif [[ "${{ github.event_name }}" == "pull_request" && "$response_code_base" == "200" ]]; then
echo "TARGET_BRANCH=${{ github.event.pull_request.base.ref }}" >> $GITHUB_OUTPUT
echo "Base branch found, using ${{ github.event.pull_request.base.ref }}"
elif [[ "$response_code_branch" == "200" ]]; then
echo "TARGET_BRANCH=${BRANCH_NAME}" >> $GITHUB_OUTPUT
echo "Base branch found, using ${BRANCH_NAME}"
else
echo "TARGET_BRANCH=${{ inputs.default_target_ref }}" >> $GITHUB_OUTPUT
echo "PR branch not found, using ${{ inputs.default_target_ref }}"

View File

@ -0,0 +1,85 @@
# This workflow is intended for reuse by other workflows and will not run directly (no triggers).
# The behavior is to run the steps of fprime-ci.
name: "F´ CI - Reusable Workflow"
on:
workflow_call:
inputs:
target_repository:
description: "Additional external repository to checkout (<owner>/<repo>)"
required: true
type: string
fprime_location:
description: "Relative path from the external project root to its F´ submodule"
required: false
type: string
default: "./lib/fprime"
target_ref:
description: "Branch on target to checkout"
required: false
type: string
default: "devel"
ci_config_file:
required: true
type: string
run_unit_tests:
description: "Run an additional job in parallel to run unit tests."
required: false
type: boolean
default: true
runs_on:
description: "Platform to run on. Defaults to ubuntu-22.04"
required: false
type: string
default: "ubuntu-22.04"
runs_on_int:
description: "Platform to run integration tests on. Defaults to: apple-ci"
required: false
type: string
default: "apple-ci"
runs_on_ut:
description: "Platform to run UTs on. Defaults to ubuntu-22.04"
required: false
type: string
default: "ubuntu-22.04"
jobs:
build:
runs-on: ${{ inputs.runs_on }}
name: "Build"
steps:
- name: "Make Space"
uses: nasa/fprime-actions/make-space@devel
- name: "Set up target repository"
uses: nasa/fprime-actions/external-repository-setup@devel
with:
target_repository: ${{ inputs.target_repository }}
fprime_location: ${{ inputs.fprime_location }}
target_ref: ${{ inputs.target_ref }}
stage: build
- name: "Build Binary"
run: |
CCACHE_DISABLE=1 fprime-ci -c ${{ inputs.ci_config_file }} --add-stage build
- name: Archive Results
uses: actions/upload-artifact@v4
with:
name: archive.tar.gz
path: ./archive.tar.gz
integration-tests:
needs: build
name: "Integration Tests"
runs-on: ${{ inputs.runs_on_int }}
steps:
- name: "Set up target repository"
uses: nasa/fprime-actions/external-repository-setup@devel
with:
target_repository: ${{ inputs.target_repository }}
fprime_location: ${{ inputs.fprime_location }}
target_ref: ${{ inputs.target_ref }}
stage: int
- name: Pull Archive Results
uses: actions/download-artifact@v4
with:
name: archive.tar.gz
- name: "Integration tests"
run: |
fprime-ci -c ${{ inputs.ci_config_file }} --skip-stage build

1
.gitignore vendored
View File

@ -26,6 +26,7 @@ RemoteSystemsTempFiles
*.stackdump
Dict
*.core
*.swp
**/coverage/
*.gcov

View File

@ -38,6 +38,8 @@ nav:
- Svc:
- "Svc/**/docs/sdd.md"
- Fw:
- DataStructures:
- "Fw/DataStructures/docs/**.md"
- "Fw/**/docs/sdd.md"
- Drv:
- "Drv/**/docs/sdd.md"
@ -47,3 +49,4 @@ nav:
- "docs/reference/*.md"
- Support: '../support'
- Events: '../events'
- News: "../news"

84
AI_POLICY.md Normal file
View File

@ -0,0 +1,84 @@
# F´ Generative AI Usage Guidelines
We're excited about the potential of generative AI to help make [F´](https://github.com/nasa/fprime) development more productive, enjoyable, and accessible! Whether you're using AI to write code, improve documentation, or learn about complex systems, we welcome the thoughtful use of these powerful tools in your F´ contributions.
This guide shares our community's approach to using generative AI effectively and responsibly. You'll find practical tips, best practices, and simple guidelines to help you get the most out of AI tools while maintaining the quality standards that make F´ great.
## Our Position on Generative AI
F´ embraces technological advancement and innovation. Generative AI tools can assist with:
- Code generation and refactoring
- Documentation creation and improvement
- Test case development
- Debugging assistance
- Design pattern suggestions
- Learning and understanding our codebases
However, the use of generative AI must align with our commitment to high technical standards, quality, and the collaborative nature of open source development.
## Disclosure
To maintain transparency and enable effective code review, contributors **must disclose all generative AI usage**.
This includes contributions in the forms of **Pull Requests**, **Issues** or **Discussions**.
### Pull Request Submissions for Contributors
1. **Fill-In the "AI Used (y/n)" table entry** in the pull request template disclosing whether Gen AI was used in the pull request
2. **Provide details in the "AI Usage" section** describing how generative AI was utilized
### What to Disclose
Include information about:
- **Type of assistance**: Code generation, documentation, debugging, testing, refactoring, etc.
- **Scope of usage**: Which files, functions, or sections were AI-assisted
- **Tool(s) used**: Name of the AI system(s) employed (e.g., GitHub Copilot, ChatGPT, etc.)
- **Level of modification**: Whether AI-generated content was used as-is, modified, or used as inspiration
### What AI Cannot Replace
- **Domain expertise** in flight software and embedded systems
- **Understanding of F Prime architecture** and design patterns
- **Critical thinking** about system requirements and constraints
- **Human judgment** on safety-critical decisions
- **Community collaboration** and peer review processes
## Best Practices
### Providing Guidelines to AI Tools
When working with generative AI, provide clear rules and context to improve code quality and consistency. For Example:
- **Reference F´ Style Guidelines**: Include the [F´ Style Guidelines](https://github.com/nasa/fprime/wiki/F%C2%B4-Style-Guidelines) in your prompts
- **Enforce coding standards**: Instruct AI to avoid "magic numbers" and use descriptive variable names or comments
- **Provide project context**: Share relevant F´ architectural patterns and component structures
### Quality and Responsibility
- **Review all AI-generated code** thoroughly before submission
- **Verify necessity and relevance** - Remove verbose or unnecessary AI-generated content
- **Be concise** - Edit AI output to be clear and to-the-point
- **Ensure compliance** with F Prime coding standards and style guidelines
- **Verify correctness** and test all AI-assisted implementations
- **Maintain authorship responsibility** - you are accountable for all submitted code regardless of its origin
### Security
- **Be cautious with external dependencies** suggested by AI tools
- **Validate security implications** of AI-generated code, especially for flight software
### Code Review Considerations
- **Provide context** to reviewers about AI usage to enable informed evaluation
- **Be prepared to explain** AI-generated logic and design decisions
- **Accept feedback gracefully** - AI-generated code is not exempt from revision requests
- **Document complex AI-assisted algorithms** clearly for future maintainers
## Getting Help
If you have questions about appropriate AI usage or need guidance on disclosure:
- Open a [Discussion](https://github.com/nasa/fprime/discussions) for community input
- Contact the Community Managers for specific guidance

View File

@ -14,133 +14,83 @@
#include "Fw/Types/Assert.hpp"
static U32 min(const U32 a, const U32 b) {
return (a < b) ? a : b;
return (a < b) ? a : b;
}
namespace CFDP {
Checksum ::
Checksum() : m_value(0)
{
Checksum ::Checksum() : m_value(0) {}
}
Checksum ::Checksum(const U32 value) : m_value(value) {}
Checksum ::
Checksum(const U32 value) : m_value(value)
{
}
Checksum ::
Checksum(const Checksum &original)
{
Checksum ::Checksum(const Checksum& original) {
this->m_value = original.getValue();
}
}
Checksum ::
~Checksum()
{
Checksum ::~Checksum() {}
}
Checksum& Checksum ::
operator=(const Checksum& checksum)
{
Checksum& Checksum ::operator=(const Checksum& checksum) {
this->m_value = checksum.m_value;
return *this;
}
}
bool Checksum ::
operator==(const Checksum& checksum) const
{
bool Checksum ::operator==(const Checksum& checksum) const {
return this->m_value == checksum.m_value;
}
}
bool Checksum ::
operator!=(const Checksum& checksum) const
{
return not (*this == checksum);
}
bool Checksum ::operator!=(const Checksum& checksum) const {
return not(*this == checksum);
}
U32 Checksum ::
getValue() const
{
U32 Checksum ::getValue() const {
return this->m_value;
}
}
void Checksum ::
update(
const U8 *const data,
const U32 offset,
const U32 length
)
{
void Checksum ::update(const U8* const data, const U32 offset, const U32 length) {
U32 index = 0;
// Add the first word unaligned if necessary
const U32 offsetMod4 = offset % 4;
if (offsetMod4 != 0) {
const U8 wordLength = static_cast<U8>(min(length, 4 - offsetMod4));
this->addWordUnaligned(
&data[index],
static_cast<U8>(offset + index),
wordLength
);
index += wordLength;
const U8 wordLength = static_cast<U8>(min(length, 4 - offsetMod4));
this->addWordUnaligned(&data[index], static_cast<U8>(offset + index), wordLength);
index += wordLength;
}
// Add the middle words aligned
for ( ; index + 4 <= length; index += 4) {
addWordAligned(&data[index]);
for (; index + 4 <= length; index += 4) {
addWordAligned(&data[index]);
}
// Add the last word unaligned if necessary
if (index < length) {
const U8 wordLength = static_cast<U8>(length - index);
this->addWordUnaligned(
&data[index],
static_cast<U8>(offset + index),
wordLength
);
const U8 wordLength = static_cast<U8>(length - index);
this->addWordUnaligned(&data[index], static_cast<U8>(offset + index), wordLength);
}
}
}
void Checksum ::
addWordAligned(const U8 *const word)
{
void Checksum ::addWordAligned(const U8* const word) {
for (U8 i = 0; i < 4; ++i) {
addByteAtOffset(word[i], i);
addByteAtOffset(word[i], i);
}
}
}
void Checksum ::
addWordUnaligned(
const U8 *word,
const U8 position,
const U8 length
)
{
void Checksum ::addWordUnaligned(const U8* word, const U8 position, const U8 length) {
FW_ASSERT(length < 4);
U8 offset = position % 4;
for (U8 i = 0; i < length; ++i) {
addByteAtOffset(word[i], offset);
++offset;
if (offset == 4) {
offset = 0;
}
addByteAtOffset(word[i], offset);
++offset;
if (offset == 4) {
offset = 0;
}
}
}
void Checksum ::
addByteAtOffset(
const U8 byte,
const U8 offset
)
{
FW_ASSERT(offset < 4);
const U32 addend = static_cast<U32>(byte) << (8*(3-offset));
this->m_value += addend;
}
}
void Checksum ::addByteAtOffset(const U8 byte, const U8 offset) {
FW_ASSERT(offset < 4);
const U32 addend = static_cast<U32>(byte) << (8 * (3 - offset));
this->m_value += addend;
}
} // namespace CFDP

View File

@ -17,130 +17,120 @@
namespace CFDP {
//! \class Checksum
//! \brief Class representing a 32-bit checksum as mandated by the CCSDS File
//! Delivery Protocol.
//!
//! This checksum is calculated by update of an existing 32-bit value
//! with the "next" 32-bit string drawn from the file data. Beginning
//! at the start of the file, a 4-byte window moves up the file by four
//! bytes per update. The update itself replaces the existing checksum
//! with the byte-wise sum of the existing checksum and the file data
//! contained in the window. Overflows in the addition are permitted
//! and the carry discarded.
//!
//! If an update is to be made beginning at an offset into the file
//! which is not aligned to a 4-byte boundary, the window is treated
//! as beginning at the last 4-byte boundary, but is left-zero-padded.
//! Similarly, where the file data for an update ends on an unaligned
//! byte, the window extends up to the next boundary and is
//! right-zero-padded.
//!
//! ## Example
//!
//! For buffer 0xDE 0xAD 0xBE 0xEF 0xCA 0xFE and initial zero checksum:
//!
//! ------------------------------------ Update 1
//! Window 0xDE 0xAD 0xBE 0xEF
//! Checksum 0xDEADBEEF
//!
//! ------------------------------------ Update 2
//! Window 0xCA 0xFE
//! Checksum 0xDEADBEEF+
//! 0xCAFE0000
//! ----------
//! 0xA8ABBEEF <- Final value
class Checksum {
//! \class Checksum
//! \brief Class representing a 32-bit checksum as mandated by the CCSDS File
//! Delivery Protocol.
//!
//! This checksum is calculated by update of an existing 32-bit value
//! with the "next" 32-bit string drawn from the file data. Beginning
//! at the start of the file, a 4-byte window moves up the file by four
//! bytes per update. The update itself replaces the existing checksum
//! with the byte-wise sum of the existing checksum and the file data
//! contained in the window. Overflows in the addition are permitted
//! and the carry discarded.
//!
//! If an update is to be made beginning at an offset into the file
//! which is not aligned to a 4-byte boundary, the window is treated
//! as beginning at the last 4-byte boundary, but is left-zero-padded.
//! Similarly, where the file data for an update ends on an unaligned
//! byte, the window extends up to the next boundary and is
//! right-zero-padded.
//!
//! ## Example
//!
//! For buffer 0xDE 0xAD 0xBE 0xEF 0xCA 0xFE and initial zero checksum:
//!
//! ------------------------------------ Update 1
//! Window 0xDE 0xAD 0xBE 0xEF
//! Checksum 0xDEADBEEF
//!
//! ------------------------------------ Update 2
//! Window 0xCA 0xFE
//! Checksum 0xDEADBEEF+
//! 0xCAFE0000
//! ----------
//! 0xA8ABBEEF <- Final value
class Checksum {
public:
// ----------------------------------------------------------------------
// Types
// ----------------------------------------------------------------------
public:
public:
// ----------------------------------------------------------------------
// Construction and destruction
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Types
// ----------------------------------------------------------------------
//! Construct a fresh Checksum object.
Checksum();
public:
//! Construct a Checksum object and initialize it with a value.
Checksum(const U32 value);
// ----------------------------------------------------------------------
// Construction and destruction
// ----------------------------------------------------------------------
//! Copy a Checksum object.
Checksum(const Checksum& original);
//! Construct a fresh Checksum object.
Checksum();
//! Destroy a Checksum object.
~Checksum();
//! Construct a Checksum object and initialize it with a value.
Checksum(const U32 value);
public:
// ----------------------------------------------------------------------
// Public instance methods
// ----------------------------------------------------------------------
//! Copy a Checksum object.
Checksum(const Checksum &original);
//! Assign checksum to this.
Checksum& operator=(const Checksum& checksum);
//! Destroy a Checksum object.
~Checksum();
//! Compare checksum and this for equality.
bool operator==(const Checksum& checksum) const;
public:
//! Compare checksum and this for inequality.
bool operator!=(const Checksum& checksum) const;
// ----------------------------------------------------------------------
// Public instance methods
// ----------------------------------------------------------------------
//! Update the checksum value by accumulating words in the given data.
//!
//! \important The data and data-length passed to this method are specifically
//! those over which the update is made, rather than the entire
//! file. Typically, therefore, `data` will be a pointer to the
//! byte given by the offset, e.g. `&file_buffer[offset]`.
//!
void update(const U8* const data, //!< Beginning of the data over which to update.
const U32 offset, //!< Offset into the file at which the data begins.
const U32 length //!< Length of the update data in bytes.
);
//! Assign checksum to this.
Checksum& operator=(const Checksum& checksum);
//! Get the checksum value
U32 getValue() const;
//! Compare checksum and this for equality.
bool operator==(const Checksum& checksum) const;
private:
// ----------------------------------------------------------------------
// Private instance methods
// ----------------------------------------------------------------------
//! Compare checksum and this for inequality.
bool operator!=(const Checksum& checksum) const;
//! Add a four-byte aligned word to the checksum value
void addWordAligned(const U8* const word //! The word
);
//! Update the checksum value by accumulating words in the given data.
//!
//! \important The data and data-length passed to this method are specifically
//! those over which the update is made, rather than the entire
//! file. Typically, therefore, `data` will be a pointer to the
//! byte given by the offset, e.g. `&file_buffer[offset]`.
//!
void update(const U8* const data, //!< Beginning of the data over which to update.
const U32 offset, //!< Offset into the file at which the data begins.
const U32 length //!< Length of the update data in bytes.
);
//! Add a four-byte unaligned word to the checksum value
void addWordUnaligned(const U8* const word, //! The word
const U8 position, //! The position of the word relative to the start of the file
const U8 length //! The number of valid bytes in the word
);
//! Get the checksum value
U32 getValue() const;
//! Add byte to value at offset in word
void addByteAtOffset(const U8 byte, //! The byte
const U8 offset //! The offset
);
private:
private:
// ----------------------------------------------------------------------
// Private member variables
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Private instance methods
// ----------------------------------------------------------------------
//! The accumulated checksum value
U32 m_value;
};
//! Add a four-byte aligned word to the checksum value
void addWordAligned(
const U8 *const word //! The word
);
//! Add a four-byte unaligned word to the checksum value
void addWordUnaligned(
const U8 *const word, //! The word
const U8 position, //! The position of the word relative to the start of the file
const U8 length //! The number of valid bytes in the word
);
//! Add byte to value at offset in word
void addByteAtOffset(
const U8 byte, //! The byte
const U8 offset //! The offset
);
private:
// ----------------------------------------------------------------------
// Private member variables
// ----------------------------------------------------------------------
//! The accumulated checksum value
U32 m_value;
};
}
} // namespace CFDP
#endif

View File

@ -1,4 +1,4 @@
// ======================================================================
// ======================================================================
// \title CFDP/Checksum/GTest/Checksums.cpp
// \author bocchino
// \brief cpp file for CFDP Checksum gtest utilities
@ -7,26 +7,21 @@
// Copyright (C) 2016, California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship
// acknowledged.
//
// ======================================================================
//
// ======================================================================
#include "CFDP/Checksum/GTest/Checksums.hpp"
namespace CFDP {
namespace GTest {
void Checksums ::
compare(
const CFDP::Checksum& expected,
const CFDP::Checksum& actual
)
{
const U32 expectedValue = expected.getValue();
const U32 actualValue = actual.getValue();
ASSERT_EQ(expectedValue, actualValue);
}
}
namespace GTest {
void Checksums ::compare(const CFDP::Checksum& expected, const CFDP::Checksum& actual) {
const U32 expectedValue = expected.getValue();
const U32 actualValue = actual.getValue();
ASSERT_EQ(expectedValue, actualValue);
}
} // namespace GTest
} // namespace CFDP

View File

@ -1,4 +1,4 @@
// ======================================================================
// ======================================================================
// \title CFDP/Checksum/GTest/Checksums.hpp
// \author bocchino
// \brief hpp file for CFDP Checksum gtest utilities
@ -7,8 +7,8 @@
// Copyright (C) 2016 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship
// acknowledged.
//
// ======================================================================
//
// ======================================================================
#ifndef GTest_CFDP_Checksums_HPP
#define GTest_CFDP_Checksums_HPP
@ -19,21 +19,20 @@
namespace CFDP {
namespace GTest {
namespace GTest {
//! Utilities for testing Checksum operations
//!
namespace Checksums {
//! Utilities for testing Checksum operations
//!
namespace Checksums {
void compare(
const CFDP::Checksum& expected, //!< Expected value
const CFDP::Checksum& actual //!< Actual value
);
}
}
void compare(const CFDP::Checksum& expected, //!< Expected value
const CFDP::Checksum& actual //!< Actual value
);
}
} // namespace GTest
} // namespace CFDP
#endif

View File

@ -1,5 +1,5 @@
// ----------------------------------------------------------------------
// Main.cpp
// Main.cpp
// ----------------------------------------------------------------------
#include "gtest/gtest.h"
@ -8,49 +8,47 @@
using namespace CFDP;
const U8 data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
const U8 data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
const U32 expectedValue =
(data[0] << 3*8) + (data[1] << 2*8) + (data[2] << 1*8) + data[3] +
(data[4] << 3*8) + (data[5] << 2*8) + (data[6] << 1*8) + data[7];
const U32 expectedValue = (data[0] << 3 * 8) + (data[1] << 2 * 8) + (data[2] << 1 * 8) + data[3] + (data[4] << 3 * 8) +
(data[5] << 2 * 8) + (data[6] << 1 * 8) + data[7];
TEST(Checksum, OnePacket) {
Checksum checksum;
checksum.update(data, 0, 8);
ASSERT_EQ(expectedValue, checksum.getValue());
Checksum checksum;
checksum.update(data, 0, 8);
ASSERT_EQ(expectedValue, checksum.getValue());
}
TEST(Checksum, TwoPacketsAligned) {
Checksum checksum;
checksum.update(&data[0], 0, 4);
checksum.update(&data[4], 4, 4);
ASSERT_EQ(expectedValue, checksum.getValue());
Checksum checksum;
checksum.update(&data[0], 0, 4);
checksum.update(&data[4], 4, 4);
ASSERT_EQ(expectedValue, checksum.getValue());
}
TEST(Checksum, TwoPacketsUnaligned1) {
Checksum checksum;
checksum.update(&data[0], 0, 3);
checksum.update(&data[3], 3, 5);
ASSERT_EQ(expectedValue, checksum.getValue());
Checksum checksum;
checksum.update(&data[0], 0, 3);
checksum.update(&data[3], 3, 5);
ASSERT_EQ(expectedValue, checksum.getValue());
}
TEST(Checksum, TwoPacketsUnaligned2) {
Checksum checksum;
checksum.update(&data[0], 0, 5);
checksum.update(&data[5], 5, 3);
ASSERT_EQ(expectedValue, checksum.getValue());
Checksum checksum;
checksum.update(&data[0], 0, 5);
checksum.update(&data[5], 5, 3);
ASSERT_EQ(expectedValue, checksum.getValue());
}
TEST(Checksum, ThreePackets) {
Checksum checksum;
checksum.update(&data[0], 0, 2);
checksum.update(&data[2], 2, 3);
checksum.update(&data[5], 5, 3);
ASSERT_EQ(expectedValue, checksum.getValue());
Checksum checksum;
checksum.update(&data[0], 0, 2);
checksum.update(&data[2], 2, 3);
checksum.update(&data[5], 5, 3);
ASSERT_EQ(expectedValue, checksum.getValue());
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -16,20 +16,11 @@ Specific Ways to Contribute:
- [Ask a Question or Suggest Improvements](https://github.com/nasa/fprime/discussions/new)
- [Report a Bug or Mistake](https://github.com/nasa/fprime/issues/new/choose)
- [Review Contributions](https://github.com/nasa/fprime/pulls)
- Submit a Pull Request
- Submit a Pull Request see: [Code Contribution Process](#cod-ontribution-process)
- Contribute to Ongoing Discussions and Reviews
Feel free to contribute any way that suits your skills and enjoy.
> **Note:** [F´ Autocoder Python](https://github.com/nasa/fprime/tree/master/Autocoders) is being actively replaced
> by [FPP](https://github.com/fprime-community/fpp). Thus we will no longer accept changes to this code except for
> security and critical bug fixes done in the most minimal fashion.
>
> We do love Python fixes, please consider contributing to
> [fprime-tools](https://github.com/fprime-community/fprime-tools) or
> [fprime-gds](https://github.com/fprime-community/fprime-gds)
## Where to Start
First, contributors should build some understanding of F´. Read through the documentation, try a tutorial, or run a
@ -44,28 +35,13 @@ with an [easy first issue](https://github.com/nasa/fprime/issues?q=is%3Aissue+is
When starting to modify F´ directly, ask questions, seek help, and be patient. Remember to review the project structure,
development process, and helpful tips sections below.
## Project Structure
## Code Contribution Process
The F´ project is designed as a base software [framework](https://github.com/nasa/fprime) with additional
[packages](https://github.com/fprime-community) designed to extend the framework. This means that occasionally we may
move contributions in or out of these packages.
All code contributions to F´ begin with an issue. Whether you're fixing a bug, adding a feature, or improving documentation, please start by opening an issue describing your proposal. The Change Control Board (CCB) reviews and approves issues before work begins to ensure alignment with project goals and standards. Once approved, you can proceed with implementation and submit a pull request (PR).
Key packages include:
If a PR is opened for work that does not correspond to an approved issue, the PR will be routed through the CCB process first—reviewed on a best-effort basis—and may be delayed or declined depending on CCB decisions.You can read more about how this process works in the [F´ Governance document](https://github.com/nasa/fprime/blob/devel/GOVERNANCE.md).
- [fpp](https://github.com/fprime-community/fpp): fpp development repository
- [fprime-tools](https://github.com/fprime-community/fprime-tools): `fprime-util` development repository
- [fprime-gds](https://github.com/fprime-community/fprime-gds): `fprime-gds` development repository
### F´ Repository Structure
Contributors to the [fprime](https://github.com/nasa/fprime) repository should understand the following key folders:
- [docs/UsersGuide](https://github.com/nasa/fprime/tree/devel/docs/UsersGuide): add new documentation in this or a subfolder
- [Fw](https://github.com/nasa/fprime/tree/devel/Fw): changes here will be reviewed carefully because this code is critical across F
- [Ref](https://github.com/nasa/fprime/tree/devel/Ref): update and maintain the Reference application here
## Development Process
### Development Process
F´ follows a standard git flow development model. Developers should start with a
[fork](https://docs.github.com/en/get-started/quickstart/fork-a-repo) of one of the F´ repositories and then develop
@ -84,6 +60,11 @@ git checkout -b <desired branch name>
Once a pull request has been submitted the following process will begin.
**Best practice: commit messages and PRs**
We recommend users to use an [imperative-style phrasing](https://cbea.ms/git-commit/#imperative) when writing commit messages. F´ uses the "Squash & Merge" strategy, meaning that all commits made on a PR branch will be combined into one squashed commit when merged into F´. The commit message for the squashed commit defaults to use the title of the Pull Request, so we do ask contributors to please follow the imperative-style phrasing for the title of their Pull Requests.
When opening a Pull Request, please fill in the given template, and link to any relevant issue on the repository.
### Submission Review
The pull request changes will be reviewed by the team and community supporting F´. Often this means that a discussion on
@ -121,13 +102,31 @@ The checks are configured to run on the `devel` branch of each external reposito
Maintainers will gladly help you in this process.
## Final Approval and Submission
### Final Approval and Submission
Once all corrections have been made, automated checks are passing, and a maintainer has given final approval, it is time
to contribute the submission. A maintainer will handle this final step and once complete changes should appear in the
`devel` branch. You can help this process by submitting any deferred or future work items as issues using the links
above.
## Project Structure
The F´ project is designed as a base software [framework](https://github.com/nasa/fprime) with additional
[packages](https://github.com/fprime-community) designed to extend the framework. This means that occasionally we may
move contributions in or out of these packages.
Key packages include:
- [fpp](https://github.com/fprime-community/fpp): fpp development repository
- [fprime-tools](https://github.com/fprime-community/fprime-tools): `fprime-util` development repository
- [fprime-gds](https://github.com/fprime-community/fprime-gds): `fprime-gds` development repository
### F´ Repository Structure
Contributors to the [fprime](https://github.com/nasa/fprime) repository should refer to the following guide to understand the repository structure: [A Tour of the Source Tree](docs/user-manual/overview/source-tree.md)
## Helpful Tips
This section will describe some helpful tips for contributing to F´.
@ -141,42 +140,54 @@ changes across many files.
Keep in mind that editors that fix whitespace automatically can cause many small changes. Even with advanced GitHub
tools this can increase the effort required to review a submission. Be careful with the changes you are submitting.
## Run Tests
### Run Tests
The automatic checking system will run all our unit tests and integration tests across several systems. However, this
process will take time. Try to run the unit tests locally during development before submitting a PR and use the
automatic checks as a safety net.
Building and running the tests has the same Python virtual environment requirements as developing an F´ project, which
is usually set up by fprime-bootstrap. Steps to set up the environment outside a project are included below.
The tests can be run using the following commands:
```bash
# Go into the fprime directory
cp MY_FPRIME_DIRECTORY
cd MY_FPRIME_DIRECTORY
# Run CI tests on fprime
./ci/tests/Framework.bash
# Set up and activate a Python virtual environment, if none already:
python3 -m venv .venv
source .venv/bin/activate
# Run CI tests on the reference application
./ci/tests/Ref.bash
# Make sure Python packages from ./requirements.txt are installed and up-to-date:
pip install -Ur requirements.txt
# Initialize googletest submodule:
git submodule update --init --recursive
# Run the static analyzer with the basic configuration
# Purge unit test directory
fprime-util purge
# Generate the build files for clang-tidy. Make sure clang-tidy is installed.
fprime-util generate --ut -DCMAKE_CXX_CLANG_TIDY=clang-tidy-12
# Generate the build files. Using clang-tidy is optional, but recommended to match the CI checks.
# On macOS, expect a CMake Warning 'Leak sanitizer is not supported on macOS in cmake/sanitizers.cmake'
fprime-util generate --ut -DCMAKE_CXX_CLANG_TIDY=clang-tidy
# Build fprime with the static analyzer
fprime-util build --all --ut -j16
fprime-util build --all --ut
# Run the static analyzer with additional flight code checks
# Purge release directory
fprime-util purge
# Generate the build files for clang-tidy. Make sure clang-tidy is installed.
fprime-util generate -DCMAKE_CXX_CLANG_TIDY="clang-tidy-12;--config-file=$PWD/release.clang-tidy"
# Build fprime with the static analyzer
fprime-util build --all -j16
# Run Unit Tests
fprime-util check --all
```
## Development with modified FPP version
### Code formatting
The F´ repository enforces formatting with `clang-format`. Most IDEs offer tools to format on demand or auto-format on "Save". To run formatting yourself, `fprime-util` provides a quick way to format all files that have been modified since you branched off of `devel`:
```bash
git diff --name-only devel...HEAD | fprime-util format --stdin
```
### Development with modified FPP version
In case FPP needs to be locally changed, first uninstall all `fprime-fpp-*` `pip` packages, and install FPP
using the procedure mentioned in the [FPP readme](https://github.com/nasa/fpp/blob/main/compiler/README.adoc).
@ -190,5 +201,5 @@ cp MY_FPRIME_DIRECTORY
# Generate the build files without checking the FPP version
fprime-util generate -DFPRIME_SKIP_TOOLS_VERSION_CHECK=1
# Build the project
fprime-util build -j4
```
fprime-util build
```

View File

@ -0,0 +1,52 @@
// ======================================================================
// \title AsyncByteStreamBufferAdapter.cpp
// \author bocchino
// \brief cpp file for AsyncByteStreamBufferAdapter component implementation class
// ======================================================================
#include "Drv/AsyncByteStreamBufferAdapter/AsyncByteStreamBufferAdapter.hpp"
namespace Drv {
// ----------------------------------------------------------------------
// Component construction and destruction
// ----------------------------------------------------------------------
AsyncByteStreamBufferAdapter::AsyncByteStreamBufferAdapter(const char* const compName)
: AsyncByteStreamBufferAdapterComponentBase(compName) {}
AsyncByteStreamBufferAdapter::~AsyncByteStreamBufferAdapter() {}
// ----------------------------------------------------------------------
// Handler implementations for typed input ports
// ----------------------------------------------------------------------
void AsyncByteStreamBufferAdapter::bufferIn_handler(FwIndexType portNum, Fw::Buffer& fwBuffer) {
// TODO: If m_driverIsReady then send fwBuffer on toByteStreamDriver_out
// TODO: Otherwise
// TODO: Log the error
// TODO: Send fwBuffer on bufferInReturn_out
}
void AsyncByteStreamBufferAdapter::bufferOutReturn_handler(FwIndexType portNum, Fw::Buffer& fwBuffer) {
// TODO: Send fwBuffer on fromByteStreamDriverReturn_out
}
void AsyncByteStreamBufferAdapter::byteStreamDriverReady_handler(FwIndexType portNum) {
this->m_driverIsReady = true;
}
void AsyncByteStreamBufferAdapter::fromByteStreamDriver_handler(FwIndexType portNum,
Fw::Buffer& buffer,
const Drv::ByteStreamStatus& status) {
// TODO: If the status is OK, then send buffer on toByteStreamDriver_out
// TODO: Otherwise log the error and send buffer on fromByteStreamDriverReturn_out
}
void AsyncByteStreamBufferAdapter::toByteStreamDriverReturn_handler(FwIndexType portNum,
Fw::Buffer& buffer,
const Drv::ByteStreamStatus& status) {
// TODO: Send fwBuffer on bufferInReturn_out
}
} // namespace Drv

View File

@ -0,0 +1,33 @@
module Drv {
@ A passive component for mediating between the AsyncByteStreamDriver
@ interface and the PassiveBufferDriver interface
@
@ Sample topology:
@
@ -----------------------------------------------------------
@ | |
@ | AsyncByteStreamDriver <--> AsyncByteStreamBufferAdapter | <--> PassiveBufferDriverClient
@ | |
@ -----------------------------------------------------------
@
@ The two components in the box function together as a PassiveBufferDriver:
@
@ -------------------------------------------------
@ | |
@ | PassiveBufferDriver | <--> PassiveBufferDriverClient
@ | |
@ -------------------------------------------------
@
passive component AsyncByteStreamBufferAdapter {
@ AsyncByteStreamBufferAdapter is a passive client of the
@ AsyncByteStreamDriver interface
import PassiveAsyncByteStreamDriverClient
@ AsyncByteStreamBufferAdapter is a PassiveBufferDriver
import PassiveBufferDriver
}
}

View File

@ -0,0 +1,80 @@
// ======================================================================
// \title AsyncByteStreamBufferAdapter.hpp
// \author bocchino
// \brief hpp file for AsyncByteStreamBufferAdapter component implementation class
// ======================================================================
#ifndef Drv_AsyncByteStreamBufferAdapter_HPP
#define Drv_AsyncByteStreamBufferAdapter_HPP
#include "Drv/AsyncByteStreamBufferAdapter/AsyncByteStreamBufferAdapterComponentAc.hpp"
namespace Drv {
class AsyncByteStreamBufferAdapter final : public AsyncByteStreamBufferAdapterComponentBase {
public:
// ----------------------------------------------------------------------
// Component construction and destruction
// ----------------------------------------------------------------------
//! Construct AsyncByteStreamBufferAdapter object
AsyncByteStreamBufferAdapter(const char* const compName //!< The component name
);
//! Destroy AsyncByteStreamBufferAdapter object
~AsyncByteStreamBufferAdapter();
private:
// ----------------------------------------------------------------------
// Handler implementations for typed input ports
// ----------------------------------------------------------------------
//! Handler implementation for bufferIn
//!
//! Port for receiving buffers
void bufferIn_handler(FwIndexType portNum, //!< The port number
Fw::Buffer& fwBuffer //!< The buffer
) override;
//! Handler implementation for bufferOutReturn
//!
//! Port for receiving buffers sent on bufferOut and then returned
void bufferOutReturn_handler(FwIndexType portNum, //!< The port number
Fw::Buffer& fwBuffer //!< The buffer
) override;
//! Handler implementation for byteStreamDriver
//!
//! Port for receiving ready signals from the driver
//! Sample connection: byteStreamDriver.ready -> byteStreamDriverClient.byteStreamReady
void byteStreamDriverReady_handler(FwIndexType portNum //!< The port number
) override;
//! Handler implementation for fromByteStreamDriver
//!
//! Port for receiving data from the driver
//! Sample connection: byteStreamDriver.$recv -> byteStreamDriverClient.fromDriver
void fromByteStreamDriver_handler(FwIndexType portNum, //!< The port number
Fw::Buffer& buffer,
const Drv::ByteStreamStatus& status) override;
//! Handler implementation for toByteStreamDriverReturn
//!
//! Port for receiving buffers sent on toByteStreamDriver and then returned
//! Sample connection: driver.sendReturnOut -> client.toByteStreamDriverReturn
void toByteStreamDriverReturn_handler(FwIndexType portNum, //!< The port number
Fw::Buffer& buffer,
const Drv::ByteStreamStatus& status) override;
private:
// ----------------------------------------------------------------------
// Private member variables
// ----------------------------------------------------------------------
//! Whether the driver is ready
bool m_driverIsReady = false;
};
} // namespace Drv
#endif

View File

@ -0,0 +1,10 @@
set(SOURCE_FILES
"${CMAKE_CURRENT_LIST_DIR}/AsyncByteStreamBufferAdapter.fpp"
"${CMAKE_CURRENT_LIST_DIR}/AsyncByteStreamBufferAdapter.cpp"
)
set(MOD_DEPS
"Fw/Logger"
)
register_fprime_module()

View File

@ -0,0 +1,47 @@
// ======================================================================
// \title ByteStreamBufferAdapter.cpp
// \author bocchino
// \brief cpp file for ByteStreamBufferAdapter component implementation class
// ======================================================================
#include "Drv/ByteStreamBufferAdapter/ByteStreamBufferAdapter.hpp"
namespace Drv {
// ----------------------------------------------------------------------
// Component construction and destruction
// ----------------------------------------------------------------------
ByteStreamBufferAdapter::ByteStreamBufferAdapter(const char* const compName)
: ByteStreamBufferAdapterComponentBase(compName) {}
ByteStreamBufferAdapter::~ByteStreamBufferAdapter() {}
// ----------------------------------------------------------------------
// Handler implementations for typed input ports
// ----------------------------------------------------------------------
void ByteStreamBufferAdapter::bufferIn_handler(FwIndexType portNum, Fw::Buffer& fwBuffer) {
// TODO: If m_driverIsReady then
// TODO: Send fwBuffer on toByteStreamDriver_out
// TODO: Check the return status. If there is an error, then log it to the Logger.
// TODO: Otherwise log the error
// TODO: Send fwBuffer on bufferInReturn_out
}
void ByteStreamBufferAdapter::bufferOutReturn_handler(FwIndexType portNum, Fw::Buffer& fwBuffer) {
// TODO: Send fwBuffer on fromByteStreamDriverReturn_out
}
void ByteStreamBufferAdapter::fromByteStreamDriver_handler(FwIndexType portNum,
Fw::Buffer& buffer,
const Drv::ByteStreamStatus& status) {
// TODO: If the status is OK, then send buffer on toByteStreamDriver_out
// TODO: Otherwise log the error and send buffer on fromByteStreamDriverReturn_out
}
void ByteStreamBufferAdapter::byteStreamDriverReady_handler(FwIndexType portNum) {
this->m_driverIsReady = true;
}
} // namespace Drv

View File

@ -0,0 +1,33 @@
module Drv {
@ A passive component for mediating between the ByteStreamDriver
@ interface and the PassiveBufferDriver interface
@
@ Sample topology:
@
@ -------------------------------------------------
@ | |
@ | ByteStreamDriver <--> ByteStreamBufferAdapter | <--> PassiveBufferDriverClient
@ | |
@ -------------------------------------------------
@
@ The two components in the box function together as a PassiveBufferDriver:
@
@ -------------------------------------------------
@ | |
@ | PassiveBufferDriver | <--> PassiveBufferDriverClient
@ | |
@ -------------------------------------------------
@
passive component ByteStreamBufferAdapter {
@ ByteStreamBufferAdapter is a passive client of the ByteStreamDriver
@ interface
import PassiveByteStreamDriverClient
@ ByteStreamBufferAdapter is a PassiveBufferDriver
import PassiveBufferDriver
}
}

View File

@ -0,0 +1,72 @@
// ======================================================================
// \title ByteStreamBufferAdapter.hpp
// \author bocchino
// \brief hpp file for ByteStreamBufferAdapter component implementation class
// ======================================================================
#ifndef Drv_ByteStreamBufferAdapter_HPP
#define Drv_ByteStreamBufferAdapter_HPP
#include "Drv/ByteStreamBufferAdapter/ByteStreamBufferAdapterComponentAc.hpp"
namespace Drv {
class ByteStreamBufferAdapter final : public ByteStreamBufferAdapterComponentBase {
public:
// ----------------------------------------------------------------------
// Component construction and destruction
// ----------------------------------------------------------------------
//! Construct ByteStreamBufferAdapter object
ByteStreamBufferAdapter(const char* const compName //!< The component name
);
//! Destroy ByteStreamBufferAdapter object
~ByteStreamBufferAdapter();
private:
// ----------------------------------------------------------------------
// Handler implementations for typed input ports
// ----------------------------------------------------------------------
//! Handler implementation for bufferIn
//!
//! Port for receiving buffers
void bufferIn_handler(FwIndexType portNum, //!< The port number
Fw::Buffer& fwBuffer //!< The buffer
) override;
//! Handler implementation for bufferOutReturn
//!
//! Port for receiving buffers sent on bufferOut and then returned
void bufferOutReturn_handler(FwIndexType portNum, //!< The port number
Fw::Buffer& fwBuffer //!< The buffer
) override;
//! Handler implementation for byteStreamIn
//!
//! Port for receiving data from the driver
//! Sample connection: byteStreamDriver.$recv -> byteStreamDriverClient.byteStreamIn
void fromByteStreamDriver_handler(FwIndexType portNum, //!< The port number
Fw::Buffer& buffer,
const Drv::ByteStreamStatus& status) override;
//! Handler implementation for byteStreamReady
//!
//! Port for receiving ready signals from the driver
//! Sample connection: byteStreamDriver.ready -> byteStreamDriverClient.byteStreamDriverReady
void byteStreamDriverReady_handler(FwIndexType portNum //!< The port number
) override;
private:
// ----------------------------------------------------------------------
// Private member variables
// ----------------------------------------------------------------------
//! Whether the driver is ready
bool m_driverIsReady = false;
};
} // namespace Drv
#endif

View File

@ -0,0 +1,10 @@
set(SOURCE_FILES
"${CMAKE_CURRENT_LIST_DIR}/ByteStreamBufferAdapter.fpp"
"${CMAKE_CURRENT_LIST_DIR}/ByteStreamBufferAdapter.cpp"
)
set(MOD_DEPS
"Fw/Logger"
)
register_fprime_module()

View File

@ -1,7 +1,7 @@
module Drv {
@ Status returned by the send call
enum ByteStreamStatus {
enum ByteStreamStatus : U8 {
OP_OK @< Operation worked as expected
SEND_RETRY @< Data send should be retried
RECV_NO_DATA @< Receive worked, but there was no data
@ -10,12 +10,17 @@ module Drv {
@ Port to exchange buffer and status with the ByteStreamDriver model
@ This port is used for receiving data from the driver as well as on
@ callback of a send call
@ callback of an asynchronous send call
port ByteStreamData(
ref buffer: Fw.Buffer,
status: ByteStreamStatus
)
@ Synchronous only - Send data out through the byte stream
port ByteStreamSend(
ref sendBuffer: Fw.Buffer @< Data to send
) -> ByteStreamStatus
@ Signal indicating the driver is ready to send and received data
port ByteStreamReady()

View File

@ -5,10 +5,15 @@ The outgoing stream is represented by the input `send` port; other components ca
## Design
There are two versions for the ByteStreamDriver, a synchronous version (`Drv.ByteStreamDriver`) and an asynchronous version (`Drv.AsyncByteStreamDriver`). In the synchronous version, the (guarded) `send` port blocks and returns status. In the asynchronous version, the (async) `send` port calls back on the `sendReturnOut` port to return status and buffer ownership.
### Send
The manager component (for example a radio manager) initiates the transfer of send data by calling the "send" port.
The caller will provide a `Fw::Buffer` containing the data to send. The driver component **must** perform a callback on its `sendReturnOut` port to return the status of that send as well as returning ownership of the `Fw::Buffer` to the caller.
The manager component (for example a radio manager) initiates the transfer of send data by calling the "send" port. The caller will provide a `Fw::Buffer` containing the data to send.
1. Async case: The driver component **must** perform a callback on its `sendReturnOut` port to return the status of that send as well as returning ownership of the `Fw::Buffer` to the caller.
2. Sync case: The driver component **must** return a status of the send operation and ownership of the `Fw::Buffer` to the caller.
These responses are an enumeration whose values are described in the following table:
| Value | Description | Buffer Ownership |
@ -19,8 +24,7 @@ These responses are an enumeration whose values are described in the following t
### Receive
In the callback formation, the byte stream driver component initiates the transfer of received data by calling the
"recv" output port. This port transfers any read data in a `Fw::Buffer` along with a status for the receive.
The byte stream driver component initiates the transfer of received data by calling the "recv" output port. This port transfers any read data in a `Fw::Buffer` along with a status for the receive.
This status is an enumeration whose values are described in the following table:
| Value | Description |
@ -29,11 +33,11 @@ This status is an enumeration whose values are described in the following table:
| ByteStreamStatus::RECV_NO_DATA | Receive worked, but there was no data |
| ByteStreamStatus::OTHER_ERROR | Receive produced an error and buffer contains no valid data. |
The following components implement the byte stream model using a callback formation:
The following components implement the byte stream model using the synchronous interface:
- [`Drv::TcpClient`](../../TcpClient/docs/sdd.md): a F´ component wrapper of the tcp client
- [`Drv::TcpServer`](../../TcpServer/docs/sdd.md): a F´ component wrapper of the tcp server
- [`Drv::Udp`](../../Udp/docs/sdd.md): a F´ component wrapper of the udp
- `Drv::LinuxUartDriver`
- [`Drv::LinuxUartDriver`](../../LinuxUartDriver/docs/sdd.md): a F´ component wrapper of the Linux UART driver
## Requirements

View File

@ -5,11 +5,13 @@ add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Interfaces/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Ports/")
# Components
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/AsyncByteStreamBufferAdapter/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ByteStreamBufferAdapter/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ByteStreamDriverModel/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxGpioDriver/")
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}/LinuxSpiDriver/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LinuxUartDriver/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Ip/")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/TcpClient/")

View File

@ -0,0 +1,23 @@
module Drv {
# In the asynchronous ByteStreamDriver interface, the send operation is non-blocking,
# and returns status through the sendReturnOut callback
@ Asynchronous ByteStreamDriver interface
interface AsyncByteStreamDriver {
@ Port invoked when the driver is ready to send/receive data
output port ready: Drv.ByteStreamReady
@ Port invoked by the driver when it receives data
output port $recv: Drv.ByteStreamData
@ Invoke this port to send data out the driver (asynchronous)
@ Status and ownership of the buffer are returned through the sendReturnOut callback
async input port $send: Fw.BufferSend
@ Port returning ownership of data received on $send port
output port sendReturnOut: Drv.ByteStreamData
@ Port receiving back ownership of data sent out on $recv port
guarded input port recvReturnIn: Fw.BufferSend
}
}

View File

@ -1,4 +1,8 @@
module Drv {
# In the synchronous ByteStreamDriver interface, the send operation is blocking
# and returns a send status
@ Synchronous ByteStreamDriver interface
interface ByteStreamDriver {
@ Port invoked when the driver is ready to send/receive data
output port ready: Drv.ByteStreamReady
@ -6,11 +10,9 @@ module Drv {
@ Port invoked by the driver when it receives data
output port $recv: Drv.ByteStreamData
@ Invoke this port to send data out the driver
guarded input port $send: Fw.BufferSend
@ Port returning ownership of data received on $send port
output port sendReturnOut: Drv.ByteStreamData
@ Invoke this port to send data out the driver (synchronous)
@ Status is returned, and ownership of the buffer is retained by the caller
guarded input port $send: Drv.ByteStreamSend
@ Port receiving back ownership of data sent out on $recv port
guarded input port recvReturnIn: Fw.BufferSend

View File

@ -8,9 +8,15 @@
register_fprime_module(
Drv_Interfaces
AUTOCODER_INPUTS
"${CMAKE_CURRENT_LIST_DIR}/AsyncByteStreamDriver.fpp"
"${CMAKE_CURRENT_LIST_DIR}/ByteStreamDriver.fpp"
"${CMAKE_CURRENT_LIST_DIR}/Gpio.fpp"
"${CMAKE_CURRENT_LIST_DIR}/I2c.fpp"
"${CMAKE_CURRENT_LIST_DIR}/PassiveAsyncByteStreamDriverClient.fpp"
"${CMAKE_CURRENT_LIST_DIR}/PassiveBufferDriver.fpp"
"${CMAKE_CURRENT_LIST_DIR}/PassiveBufferDriverClient.fpp"
"${CMAKE_CURRENT_LIST_DIR}/PassiveByteStreamDriverClient.fpp"
"${CMAKE_CURRENT_LIST_DIR}/PassiveByteStreamDriverClientReadyRecv.fpp"
"${CMAKE_CURRENT_LIST_DIR}/Spi.fpp"
"${CMAKE_CURRENT_LIST_DIR}/Tick.fpp"
INTERFACE

View File

@ -0,0 +1,25 @@
module Drv {
@ The send interface of passive client of an asynchronous byte stream driver
interface PassiveByteStreamDriverClientSendAsync {
@ Port for sending data to the driver
@ Sample connection: client.toByteStreamDriver -> driver.$send
output port toByteStreamDriver: Fw.BufferSend
@ Port for receiving buffers sent on toByteStreamDriver and then returned
@ Sample connection: driver.sendReturnOut -> client.toByteStreamDriverReturn
sync input port toByteStreamDriverReturn: Drv.ByteStreamData
}
@ A passive client of an asynchronous byte stream driver
interface PassiveAsyncByteStreamDriverClient {
import PassiveByteStreamDriverClientReadyRecv
import PassiveByteStreamDriverClientSendAsync
}
}

View File

@ -0,0 +1,14 @@
module Drv {
@ A passive buffer driver
interface PassiveBufferDriver {
@ The interface for sending data to the driver
import Fw.PassiveBufferIn
@ The interface for receiving data from the driver
import Fw.PassiveBufferOut
}
}

View File

@ -0,0 +1,40 @@
module Drv {
@ The send interface of passive client of a buffer driver
interface PassiveBufferDriverClientSend {
@ Port for sending data to the driver
@ Sample connection: client.toBufferDriver -> driver.bufferIn
output port toBufferDriver: Fw.BufferSend
@ Port for receiving buffers sent on toBufferDriver and then returned
@ Sample connection: driver.bufferInReturn -> client.toBufferDriverReturn
sync input port toBufferDriverReturn: Fw.BufferSend
}
@ The receive interface of passive client of a buffer driver
interface PassiveBufferDriverClientRecv {
@ Port for receiving data from the driver
@ Sample connection: driver.bufferOut -> client.fromBufferDriver
sync input port fromBufferDriver: Fw.BufferSend
@ Port for returning buffers received on fromBufferDriver
@ Sample connection: client.fromBufferDriverReturn -> driver.bufferOutReturn
output port fromBufferDriverReturn: Fw.BufferSend
}
@ A passive client of a buffer driver
interface PassiveBufferDriverClient {
@ The interface for sending data to the driver
import PassiveBufferDriverClientSend
@ The interface for receiving data from the driver
import PassiveBufferDriverClientRecv
}
}

View File

@ -0,0 +1,22 @@
module Drv {
@ The send interface of passive client of a synchronous byte stream driver
interface PassiveByteStreamDriverClientSendSync {
@ Port for sending data to the driver
@ Sample connection: client.toByteStreamDriver -> driver.$send
output port toByteStreamDriver: Drv.ByteStreamSend
}
@ A passive client of a synchronous byte stream driver
interface PassiveByteStreamDriverClient {
@ The ready and receive interfaces
import PassiveByteStreamDriverClientReadyRecv
@ The send interface
import PassiveByteStreamDriverClientSendSync
}
}

View File

@ -0,0 +1,26 @@
module Drv {
@ The ready and receive interfaces for a byte stream driver client
interface PassiveByteStreamDriverClientReadyRecv {
# ----------------------------------------------------------------------
# Ready interface
# ----------------------------------------------------------------------
@ Port for receiving ready signals from the driver
@ Sample connection: byteStreamDriver.ready -> byteStreamDriverClient.byteStreamDriverReady
sync input port byteStreamDriverReady: Drv.ByteStreamReady
# ----------------------------------------------------------------------
# Receive interface
# ----------------------------------------------------------------------
@ Port for receiving data from the driver
@ Sample connection: byteStreamDriver.$recv -> byteStreamDriverClient.fromDriver
sync input port fromByteStreamDriver: Drv.ByteStreamData
@ Port for returning ownership of buffers received on fromDriver
@ Sample connection: byteStreamDriverClient.byteStreamReturn -> byteStreamDriver.recvReturnIn
output port fromByteStreamDriverReturn: Fw.BufferSend
}
}

View File

@ -1,5 +1,9 @@
module Drv {
interface Spi {
@ Port to perform a synchronous write/read operation over the SPI bus
guarded input port SpiWriteRead: Drv.SpiWriteRead
@ DEPRECATED Use SpiWriteRead port instead (same operation with a return value)
@ Port to perform a synchronous read/write operation over the SPI bus
sync input port SpiReadWrite: Drv.SpiReadWrite
}

View File

@ -9,12 +9,12 @@
// acknowledged.
//
// ======================================================================
#include <cstring>
#include <Drv/Ip/IpSocket.hpp>
#include <Fw/Types/Assert.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#include <Fw/Types/StringUtils.hpp>
#include <sys/time.h>
#include <Drv/Ip/IpSocket.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#include <Fw/Types/Assert.hpp>
#include <Fw/Types/StringUtils.hpp>
#include <cstring>
// This implementation has primarily implemented to isolate
// the socket interface from the F' Fw::Buffer class.
@ -22,42 +22,43 @@
// the m_data member in Fw::Buffer.
#ifdef TGT_OS_TYPE_VXWORKS
#include <socket.h>
#include <inetLib.h>
#include <errnoLib.h>
#include <fioLib.h>
#include <hostLib.h>
#include <inetLib.h>
#include <ioLib.h>
#include <vxWorks.h>
#include <sockLib.h>
#include <fioLib.h>
#include <taskLib.h>
#include <socket.h>
#include <sysLib.h>
#include <errnoLib.h>
#include <taskLib.h>
#include <vxWorks.h>
#include <cstring>
#elif defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <arpa/inet.h>
#else
#error OS not supported for IP Socket Communications
#endif
namespace Drv {
IpSocket::IpSocket() : m_timeoutSeconds(0), m_timeoutMicroseconds(0), m_port(0) {
::memset(m_hostname, 0, sizeof(m_hostname));
}
SocketIpStatus IpSocket::configure(const char* const hostname, const U16 port, const U32 timeout_seconds, const U32 timeout_microseconds) {
SocketIpStatus IpSocket::configure(const char* const hostname,
const U16 port,
const U32 timeout_seconds,
const U32 timeout_microseconds) {
FW_ASSERT(timeout_microseconds < 1000000, static_cast<FwAssertArgType>(timeout_microseconds));
FW_ASSERT(this->isValidPort(port), static_cast<FwAssertArgType>(port));
FW_ASSERT(hostname != nullptr);
this->m_timeoutSeconds = timeout_seconds;
this->m_timeoutMicroseconds = timeout_microseconds;
this->m_port = port;
(void) Fw::StringUtils::string_copy(this->m_hostname, hostname, static_cast<FwSizeType>(SOCKET_MAX_HOSTNAME_SIZE));
(void)Fw::StringUtils::string_copy(this->m_hostname, hostname, static_cast<FwSizeType>(SOCKET_MAX_HOSTNAME_SIZE));
return SOCK_SUCCESS;
}
@ -75,7 +76,7 @@ SocketIpStatus IpSocket::setupTimeouts(int socketFd) {
timeout.tv_sec = static_cast<time_t>(this->m_timeoutSeconds);
timeout.tv_usec = static_cast<suseconds_t>(this->m_timeoutMicroseconds);
// set socket write to timeout after 1 sec
if (setsockopt(socketFd, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char *>(&timeout), sizeof(timeout)) < 0) {
if (setsockopt(socketFd, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char*>(&timeout), sizeof(timeout)) < 0) {
return SOCK_FAILED_TO_SET_SOCKET_OPTIONS;
}
#endif
@ -128,15 +129,14 @@ SocketIpStatus IpSocket::open(SocketDescriptor& socketDescriptor) {
return status;
}
SocketIpStatus IpSocket::send(const SocketDescriptor& socketDescriptor, const U8* const data, const U32 size) {
FW_ASSERT(socketDescriptor.fd != -1, static_cast<FwAssertArgType>(socketDescriptor.fd));
SocketIpStatus IpSocket::send(const SocketDescriptor& socketDescriptor, const U8* const data, const FwSizeType size) {
FW_ASSERT(data != nullptr);
FW_ASSERT(size > 0);
U32 total = 0;
I32 sent = 0;
FwSizeType total = 0;
FwSignedSizeType sent = 0;
// Attempt to send out data and retry as necessary
for (U32 i = 0; (i < SOCKET_MAX_ITERATIONS) && (total < size); i++) {
for (FwSizeType i = 0; (i < SOCKET_MAX_ITERATIONS) && (total < size); i++) {
errno = 0;
// Send using my specific protocol
sent = this->sendProtocol(socketDescriptor, data + total, size - total);
@ -153,7 +153,7 @@ SocketIpStatus IpSocket::send(const SocketDescriptor& socketDescriptor, const U8
return SOCK_SEND_ERROR;
}
FW_ASSERT(sent > 0, static_cast<FwAssertArgType>(sent));
total += static_cast<U32>(sent);
total += static_cast<FwSizeType>(sent);
}
// Failed to retry enough to send all data
if (total < size) {
@ -164,16 +164,16 @@ SocketIpStatus IpSocket::send(const SocketDescriptor& socketDescriptor, const U8
return SOCK_SUCCESS;
}
SocketIpStatus IpSocket::recv(const SocketDescriptor& socketDescriptor, U8* data, U32& req_read) {
//TODO: Uncomment FW_ASSERT for socketDescriptor.fd once we fix TcpClientTester to not pass in uninitialized socketDescriptor
// FW_ASSERT(socketDescriptor.fd != -1, static_cast<FwAssertArgType>(socketDescriptor.fd));
SocketIpStatus IpSocket::recv(const SocketDescriptor& socketDescriptor, U8* data, FwSizeType& req_read) {
// TODO: Uncomment FW_ASSERT for socketDescriptor.fd once we fix TcpClientTester to not pass in uninitialized
// socketDescriptor
// FW_ASSERT(socketDescriptor.fd != -1, static_cast<FwAssertArgType>(socketDescriptor.fd));
FW_ASSERT(data != nullptr);
I32 bytes_received_or_status; // Stores the return value from recvProtocol
FwSignedSizeType bytes_received_or_status; // Stores the return value from recvProtocol
// Loop primarily for EINTR. Other conditions should lead to an earlier exit.
for (U32 i = 0; i < SOCKET_MAX_ITERATIONS; i++) {
for (FwSizeType i = 0; i < SOCKET_MAX_ITERATIONS; i++) {
errno = 0;
// Pass the current value of req_read (max buffer size) to recvProtocol.
// recvProtocol returns bytes read or -1 on error.
@ -181,13 +181,13 @@ SocketIpStatus IpSocket::recv(const SocketDescriptor& socketDescriptor, U8* data
if (bytes_received_or_status > 0) {
// Successfully read data
req_read = static_cast<U32>(bytes_received_or_status);
req_read = static_cast<FwSizeType>(bytes_received_or_status);
return SOCK_SUCCESS;
} else if (bytes_received_or_status == 0) {
// Handle zero return based on protocol-specific behavior
req_read = 0;
return this->handleZeroReturn();
} else { // bytes_received_or_status == -1, an error occurred
} else { // bytes_received_or_status == -1, an error occurred
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
// Non-blocking socket would block, or SO_RCVTIMEO timeout occurred.
req_read = 0;
@ -195,7 +195,7 @@ SocketIpStatus IpSocket::recv(const SocketDescriptor& socketDescriptor, U8* data
} else if ((errno == ECONNRESET) || (errno == EBADF)) {
// Connection reset or bad file descriptor.
req_read = 0;
return SOCK_DISCONNECTED; // Or a more specific error like SOCK_READ_ERROR
return SOCK_DISCONNECTED; // Or a more specific error like SOCK_READ_ERROR
} else {
// Other socket read error.
req_read = 0;
@ -214,4 +214,22 @@ SocketIpStatus IpSocket::handleZeroReturn() {
return SOCK_DISCONNECTED;
}
SocketIpStatus IpSocket::setupSocketOptions(int socketFd) {
// Iterate over the socket options and set them
for (const auto& options : IP_SOCKET_OPTIONS) {
int status = 0;
if (options.type == SOCK_OPT_INT) {
status = setsockopt(socketFd, options.level, options.option, &options.value.intVal,
sizeof(options.value.intVal));
} else {
status = setsockopt(socketFd, options.level, options.option, &options.value.sizeVal,
sizeof(options.value.sizeVal));
}
if (status) {
return SOCK_FAILED_TO_SET_SOCKET_OPTIONS;
}
}
return SOCK_SUCCESS;
}
} // namespace Drv

View File

@ -13,14 +13,14 @@
#define DRV_IP_IPHELPER_HPP_
#include <Fw/FPrimeBasicTypes.hpp>
#include <config/IpCfg.hpp>
#include <Os/Mutex.hpp>
#include <config/IpCfg.hpp>
namespace Drv {
struct SocketDescriptor final {
int fd = -1; //!< Used for all sockets to track the communication file descriptor
int serverFd = -1; //!< Used for server sockets to track the listening file descriptor
int fd = -1; //!< Used for all sockets to track the communication file descriptor
int serverFd = -1; //!< Used for server sockets to track the listening file descriptor
};
/**
@ -57,7 +57,7 @@ enum SocketIpStatus {
class IpSocket {
public:
IpSocket();
virtual ~IpSocket(){};
virtual ~IpSocket() {};
/**
* \brief configure the ip socket with host and transmission timeouts
*
@ -76,7 +76,9 @@ class IpSocket {
* \param send_timeout_microseconds: send timeout microseconds portion. Must be less than 1000000
* \return status of configure
*/
virtual SocketIpStatus configure(const char* hostname, const U16 port, const U32 send_timeout_seconds,
virtual SocketIpStatus configure(const char* hostname,
const U16 port,
const U32 send_timeout_seconds,
const U32 send_timeout_microseconds);
/**
@ -114,7 +116,7 @@ class IpSocket {
* \param size: size of data to send
* \return status of the send, SOCK_DISCONNECTED to reopen, SOCK_SUCCESS on success, something else on error
*/
virtual SocketIpStatus send(const SocketDescriptor& socketDescriptor, const U8* const data, const U32 size);
virtual SocketIpStatus send(const SocketDescriptor& socketDescriptor, const U8* const data, const FwSizeType size);
/**
* \brief receive data from the IP socket from the given buffer
*
@ -131,7 +133,7 @@ class IpSocket {
* \param size: maximum size of data buffer to fill
* \return status of the send, SOCK_DISCONNECTED to reopen, SOCK_SUCCESS on success, something else on error
*/
SocketIpStatus recv(const SocketDescriptor& fd, U8* const data, U32& size);
SocketIpStatus recv(const SocketDescriptor& fd, U8* const data, FwSizeType& size);
/**
* \brief closes the socket
@ -173,7 +175,7 @@ class IpSocket {
* \brief setup the socket timeout properties of the opened outgoing socket
* \param socketDescriptor: socket descriptor to setup
* \return status of timeout setup
*/
*/
SocketIpStatus setupTimeouts(int socketFd);
/**
@ -196,7 +198,9 @@ class IpSocket {
* \param size: size of data to send
* \return: size of data sent, or -1 on error.
*/
virtual I32 sendProtocol(const SocketDescriptor& socketDescriptor, const U8* const data, const U32 size) = 0;
virtual FwSignedSizeType sendProtocol(const SocketDescriptor& socketDescriptor,
const U8* const data,
const FwSizeType size) = 0;
/**
* \brief Protocol specific implementation of recv. Called directly with error handling from recv.
@ -205,7 +209,9 @@ class IpSocket {
* \param size: size of data buffer
* \return: size of data received, or -1 on error.
*/
virtual I32 recvProtocol(const SocketDescriptor& socketDescriptor, U8* const data, const U32 size) = 0;
virtual FwSignedSizeType recvProtocol(const SocketDescriptor& socketDescriptor,
U8* const data,
const FwSizeType size) = 0;
/**
* \brief Handle zero return from recvProtocol
@ -218,9 +224,16 @@ class IpSocket {
*/
virtual SocketIpStatus handleZeroReturn();
/**
* \brief setup the socket options of the input socket as defined in IpCfg.hpp
* \param socketFd: socket file descriptor
* \return status of setup options
*/
SocketIpStatus setupSocketOptions(int socketFd);
U32 m_timeoutSeconds;
U32 m_timeoutMicroseconds;
U16 m_port; //!< IP address port used
U16 m_port; //!< IP address port used
char m_hostname[SOCKET_MAX_HOSTNAME_SIZE]; //!< Hostname to supply
};
} // namespace Drv

View File

@ -21,11 +21,27 @@ SocketComponentHelper::SocketComponentHelper() {}
SocketComponentHelper::~SocketComponentHelper() {}
void SocketComponentHelper::start(const Fw::StringBase &name,
void SocketComponentHelper::start(const Fw::ConstStringBase& name,
const FwTaskPriorityType priority,
const Os::Task::ParamType stack,
const Os::Task::ParamType cpuAffinity) {
FW_ASSERT(m_task.getState() == Os::Task::State::NOT_STARTED); // It is a coding error to start this task multiple times
const Os::Task::ParamType cpuAffinity,
const FwTaskPriorityType priorityReconnect,
const Os::Task::ParamType stackReconnect,
const Os::Task::ParamType cpuAffinityReconnect) {
// Reconnect Thread
FW_ASSERT(m_reconnectTask.getState() ==
Os::Task::State::NOT_STARTED); // It is a coding error to start this task multiple times
this->m_reconnectStop = false;
Fw::String reconnectName;
reconnectName.format("%s_reconnect", name.toChar());
Os::Task::Arguments reconnectArguments(reconnectName, SocketComponentHelper::reconnectTask, this, priorityReconnect,
stackReconnect, cpuAffinityReconnect);
Os::Task::Status reconnectStat = m_reconnectTask.start(reconnectArguments);
FW_ASSERT(Os::Task::OP_OK == reconnectStat, static_cast<FwAssertArgType>(reconnectStat));
// Read Thread
FW_ASSERT(m_task.getState() ==
Os::Task::State::NOT_STARTED); // It is a coding error to start this task multiple times
this->m_stop = false;
// Note: the first step is for the IP socket to open the port
Os::Task::Arguments arguments(name, SocketComponentHelper::readTask, this, priority, stack, cpuAffinity);
@ -45,7 +61,6 @@ SocketIpStatus SocketComponentHelper::open() {
} else {
local_open = OpenState::SKIP;
}
}
if (local_open == OpenState::OPENING) {
FW_ASSERT(this->m_descriptor.fd == -1); // Ensure we are not opening an opened socket
@ -80,18 +95,19 @@ void SocketComponentHelper::setAutomaticOpen(bool auto_open) {
this->m_reopen = auto_open;
}
bool SocketComponentHelper::getAutomaticOpen() {
Os::ScopeLock scopedLock(this->m_lock);
return this->m_reopen;
}
SocketIpStatus SocketComponentHelper::reopen() {
SocketIpStatus status = SOCK_SUCCESS;
if (not this->isOpened()) {
// Check for auto-open before attempting to reopen
bool reopen = false;
{
Os::ScopeLock scopedLock(this->m_lock);
reopen = this->m_reopen;
}
// Open a network connection if it has not already been open
bool reopen = this->getAutomaticOpen();
if (not reopen) {
status = SOCK_AUTO_CONNECT_DISABLED;
// Open a network connection if it has not already been open
} else {
status = this->open();
if (status == SocketIpStatus::SOCK_ANOTHER_THREAD_OPENING) {
@ -102,22 +118,23 @@ SocketIpStatus SocketComponentHelper::reopen() {
return status;
}
SocketIpStatus SocketComponentHelper::send(const U8* const data, const U32 size) {
SocketIpStatus SocketComponentHelper::send(const U8* const data, const FwSizeType size) {
SocketIpStatus status = SOCK_SUCCESS;
this->m_lock.lock();
SocketDescriptor descriptor = this->m_descriptor;
this->m_lock.unlock();
// Prevent transmission before connection, or after a disconnect
if (descriptor.fd == -1) {
status = this->reopen();
// if reopen wasn't successful, pass the that up to the caller
if(status != SOCK_SUCCESS) {
return status;
this->requestReconnect();
SocketIpStatus reconnectStat = this->waitForReconnect();
if (reconnectStat == SOCK_SUCCESS) {
// Refresh local copy after reopen
this->m_lock.lock();
descriptor = this->m_descriptor;
this->m_lock.unlock();
} else {
return reconnectStat;
}
// Refresh local copy after reopen
this->m_lock.lock();
descriptor = this->m_descriptor;
this->m_lock.unlock();
}
status = this->getSocketHandler().send(descriptor, data, size);
if (status == SOCK_DISCONNECTED) {
@ -138,8 +155,15 @@ void SocketComponentHelper::close() {
this->m_open = OpenState::NOT_OPEN;
}
/* Read Thread */
Os::Task::Status SocketComponentHelper::join() {
return m_task.join();
Os::Task::Status stat = m_task.join();
Os::Task::Status reconnectStat = this->joinReconnect();
if (stat == Os::Task::Status::OP_OK) {
return reconnectStat;
}
return stat;
}
void SocketComponentHelper::stop() {
@ -148,6 +172,7 @@ void SocketComponentHelper::stop() {
Os::ScopeLock scopeLock(m_lock);
this->m_stop = true;
}
this->stopReconnect();
this->shutdown(); // Break out of any receives and fully shutdown
}
@ -157,7 +182,7 @@ bool SocketComponentHelper::running() {
return running;
}
SocketIpStatus SocketComponentHelper::recv(U8* data, U32 &size) {
SocketIpStatus SocketComponentHelper::recv(U8* data, FwSizeType& size) {
SocketIpStatus status = SOCK_SUCCESS;
// Check for previously disconnected socket
this->m_lock.lock();
@ -178,31 +203,25 @@ void SocketComponentHelper::readLoop() {
do {
// Prevent transmission before connection, or after a disconnect
if ((not this->isOpened()) and this->running()) {
status = this->reopen();
this->requestReconnect();
status = this->waitForReconnect();
// When reopen is disabled, just break as this is a exit condition for the loop
if (status == SOCK_AUTO_CONNECT_DISABLED) {
break;
}
// If the reconnection failed in any other way, warn, wait, and retry
else if (status != SOCK_SUCCESS) {
Fw::Logger::log("[WARNING] Failed to open port with status %d and errno %d\n", status, errno);
(void)Os::Task::delay(SOCKET_RETRY_INTERVAL);
continue;
}
}
// If the network connection is open, read from it
if (this->isOpened() and this->running()) {
Fw::Buffer buffer = this->getBuffer();
U8* data = buffer.getData();
FW_ASSERT(data);
FW_ASSERT_NO_OVERFLOW(buffer.getSize(), U32);
U32 size = static_cast<U32>(buffer.getSize());
FwSizeType size = buffer.getSize();
// recv blocks, so it may have been a while since its done an isOpened check
status = this->recv(data, size);
if ((status != SOCK_SUCCESS) && (status != SOCK_INTERRUPTED_TRY_AGAIN) && (status != SOCK_NO_DATA_AVAILABLE)) {
Fw::Logger::log("[WARNING] Failed to recv from port with status %d and errno %d\n",
status,
errno);
if ((status != SOCK_SUCCESS) && (status != SOCK_INTERRUPTED_TRY_AGAIN) &&
(status != SOCK_NO_DATA_AVAILABLE)) {
Fw::Logger::log("[WARNING] %s failed to recv from port with status %d and errno %d\n",
this->m_task.getName().toChar(), status, errno);
this->close();
buffer.setSize(0);
} else {
@ -215,7 +234,7 @@ void SocketComponentHelper::readLoop() {
// This will loop until stopped. If auto-open is disabled, this will break when reopen returns disabled status
while (this->running());
// Close the socket
this->close(); // Close the port entirely
this->close(); // Close the port entirely
}
void SocketComponentHelper::readTask(void* pointer) {
@ -223,4 +242,124 @@ void SocketComponentHelper::readTask(void* pointer) {
SocketComponentHelper* self = reinterpret_cast<SocketComponentHelper*>(pointer);
self->readLoop();
}
/* Reconnect Thread */
Os::Task::Status SocketComponentHelper::joinReconnect() {
return m_reconnectTask.join();
}
void SocketComponentHelper::stopReconnect() {
Os::ScopeLock scopeLock(this->m_reconnectLock);
this->m_reconnectState = ReconnectState::NOT_RECONNECTING;
this->m_reconnectStop = true;
}
bool SocketComponentHelper::runningReconnect() {
Os::ScopeLock scopedLock(this->m_reconnectLock);
bool running = not this->m_reconnectStop;
return running;
}
void SocketComponentHelper::reconnectLoop() {
SocketIpStatus status = SOCK_SUCCESS;
while (this->runningReconnect()) {
// Check if we need to reconnect
bool reconnect = false;
{
Os::ScopeLock scopedLock(this->m_reconnectLock);
if (this->m_reconnectState == ReconnectState::REQUEST_RECONNECT) {
this->m_reconnectState = ReconnectState::RECONNECT_IN_PROGRESS;
reconnect = true;
}
// If we were already in or are now in RECONNECT_IN_PROGRESS we
// need to try to reconnect, again
else if (this->m_reconnectState == ReconnectState::RECONNECT_IN_PROGRESS) {
reconnect = true;
}
}
if (reconnect) {
status = this->reopen();
// Reopen Case 1: Auto Connect is disabled, so no longer
// try to reconnect
if (status == SOCK_AUTO_CONNECT_DISABLED) {
Os::ScopeLock scopedLock(this->m_reconnectLock);
this->m_reconnectState = ReconnectState::NOT_RECONNECTING;
}
// Reopen Case 2: Success, so no longer
// try to reconnect
else if (status == SOCK_SUCCESS) {
Os::ScopeLock scopedLock(this->m_reconnectLock);
this->m_reconnectState = ReconnectState::NOT_RECONNECTING;
}
// Reopen Case 3: Keep trying to reconnect - NO reconnect
// state change
else {
Fw::Logger::log("[WARNING] %s failed to open port with status %d and errno %d\n",
this->m_task.getName().toChar(), status, errno);
(void)Os::Task::delay(SOCKET_RETRY_INTERVAL);
}
} else {
// After a brief delay, we will loop again
(void)Os::Task::delay(this->m_reconnectCheckInterval);
}
}
}
void SocketComponentHelper::reconnectTask(void* pointer) {
FW_ASSERT(pointer);
SocketComponentHelper* self = reinterpret_cast<SocketComponentHelper*>(pointer);
self->reconnectLoop();
}
void SocketComponentHelper::requestReconnect() {
Os::ScopeLock scopedLock(this->m_reconnectLock);
if (m_reconnectState == ReconnectState::NOT_RECONNECTING) {
m_reconnectState = ReconnectState::REQUEST_RECONNECT;
}
return;
}
SocketIpStatus SocketComponentHelper::waitForReconnect(Fw::TimeInterval timeout) {
// Do not attempt to reconnect if auto reconnect config flag is disabled
if (!this->getAutomaticOpen()) {
return SOCK_AUTO_CONNECT_DISABLED;
}
Fw::TimeInterval elapsed = Fw::TimeInterval(0, 0);
while (elapsed < timeout) {
// If the reconnect thread is NOT reconnecting, we are done waiting
// If we are no longer running the reconnect thread, we are done waiting
{
Os::ScopeLock scopedLock(this->m_reconnectLock);
if (this->m_reconnectState == ReconnectState::NOT_RECONNECTING) {
break;
}
if (this->m_reconnectStop) {
break;
}
}
// Wait a bit before checking again
(void)Os::Task::delay(this->m_reconnectWaitInterval);
elapsed.add(this->m_reconnectWaitInterval.getSeconds(), this->m_reconnectWaitInterval.getUSeconds());
}
// If we have completed our loop, check if we are connected or if
// auto connect was disabled during our wait
if (this->isOpened()) {
return SOCK_SUCCESS;
}
// Check one more time if auto reconnect config flag got disabled
if (!this->getAutomaticOpen()) {
return SOCK_AUTO_CONNECT_DISABLED;
}
return SOCK_DISCONNECTED; // Indicates failure of this attempt, another reopen needed
}
} // namespace Drv

View File

@ -12,10 +12,11 @@
#ifndef DRV_SocketComponentHelper_HPP
#define DRV_SocketComponentHelper_HPP
#include <Fw/Buffer/Buffer.hpp>
#include <Drv/Ip/IpSocket.hpp>
#include <Os/Task.hpp>
#include <Fw/Buffer/Buffer.hpp>
#include <Os/Condition.hpp>
#include <Os/Mutex.hpp>
#include <Os/Task.hpp>
namespace Drv {
/**
@ -27,12 +28,8 @@ namespace Drv {
*/
class SocketComponentHelper {
public:
enum OpenState{
NOT_OPEN,
OPENING,
OPEN,
SKIP
};
enum OpenState { NOT_OPEN, OPENING, OPEN, SKIP };
enum ReconnectState { NOT_RECONNECTING, REQUEST_RECONNECT, RECONNECT_IN_PROGRESS };
/**
* \brief constructs the socket read task
*/
@ -52,14 +49,25 @@ class SocketComponentHelper {
* default behavior is to automatically open connections.
*
* \param name: name of the task
* \param priority: priority of the started task. See: Os::Task::start. Default: TASK_PRIORITY_DEFAULT, not prioritized
* \param stack: stack size provided to the task. See: Os::Task::start. Default: TASK_DEFAULT, posix threads default
* \param cpuAffinity: cpu affinity provided to task. See: Os::Task::start. Default: TASK_DEFAULT, don't care
* \param priority: priority of the started read task. See: Os::Task::start. Default: TASK_PRIORITY_DEFAULT, not
* prioritized
* \param stack: stack size provided to the read task. See: Os::Task::start. Default: TASK_DEFAULT, posix threads
* default
* \param cpuAffinity: cpu affinity provided to read task. See: Os::Task::start. Default: TASK_DEFAULT, don't care
* \param priorityReconnect: priority of the started reconnect task. See: Os::Task::start. Default:
* TASK_PRIORITY_DEFAULT, not prioritized
* \param stackReconnect: stack size provided to the reconnect task. See: Os::Task::start. Default: TASK_DEFAULT,
* posix threads default
* \param cpuAffinityReconnect: cpu affinity provided to reconnect task. See: Os::Task::start. Default:
* TASK_DEFAULT, don't care
*/
void start(const Fw::StringBase &name,
void start(const Fw::ConstStringBase& name,
const FwTaskPriorityType priority = Os::Task::TASK_PRIORITY_DEFAULT,
const Os::Task::ParamType stack = Os::Task::TASK_DEFAULT,
const Os::Task::ParamType cpuAffinity = Os::Task::TASK_DEFAULT);
const Os::Task::ParamType cpuAffinity = Os::Task::TASK_DEFAULT,
const FwTaskPriorityType priorityReconnect = Os::Task::TASK_PRIORITY_DEFAULT,
const Os::Task::ParamType stackReconnect = Os::Task::TASK_DEFAULT,
const Os::Task::ParamType cpuAffinityReconnect = Os::Task::TASK_DEFAULT);
/**
* \brief open the socket for communications
@ -73,7 +81,7 @@ class SocketComponentHelper {
*/
SocketIpStatus open();
/**
/**
* \brief check if IP socket has previously been opened
*
* Check if this IpSocket has previously been opened. In the case of Udp this will check for outgoing transmissions
@ -87,13 +95,21 @@ class SocketComponentHelper {
/**
* \brief set socket to automatically open connections when true, or not when false
*
* When passed `true`, this instructs the socket to automatically open a socket and reopen socket failed connections. When passed `false`
* the user must explicitly call the `open` method to open the socket initially and when a socket fails.
* When passed `true`, this instructs the socket to automatically open a socket and reopen socket failed
* connections. When passed `false` the user must explicitly call the `open` method to open the socket initially and
* when a socket fails.
*
* \param auto_open: true to automatically open and reopen sockets, false otherwise
*/
void setAutomaticOpen(bool auto_open);
/**
* \brief get socket automatically open connections status
*
* \return status of auto_open
*/
bool getAutomaticOpen();
/**
* \brief send data to the IP socket from the given buffer
*
@ -102,7 +118,7 @@ class SocketComponentHelper {
* \param size: size of data to send
* \return status of send, SOCK_SUCCESS for success, something else on error
*/
SocketIpStatus send(const U8* const data, const U32 size);
SocketIpStatus send(const U8* const data, const FwSizeType size);
/**
* \brief receive data from the IP socket from the given buffer
@ -112,7 +128,7 @@ class SocketComponentHelper {
* \param size: maximum size of data buffer to fill
* \return status of the send, SOCK_DISCONNECTED to reopen, SOCK_SUCCESS on success, something else on error
*/
SocketIpStatus recv(U8* data, U32 &size);
SocketIpStatus recv(U8* data, FwSizeType& size);
/**
* \brief close the socket communications
@ -137,6 +153,7 @@ class SocketComponentHelper {
* \brief is the read loop running
*/
bool running();
bool runningReconnect();
/**
* \brief stop the socket read task and close the associated socket.
@ -146,6 +163,8 @@ class SocketComponentHelper {
*/
void stop();
void stopReconnect();
/**
* \brief joins to the stopping read task to wait for it to close
*
@ -156,11 +175,19 @@ class SocketComponentHelper {
*/
Os::Task::Status join();
Os::Task::Status joinReconnect();
protected:
/**
* \brief receive off the TCP socket
*/
virtual void readLoop();
/**
* \brief reconnect TCP socket
*/
virtual void reconnectLoop();
/**
* \brief returns a reference to the socket handler
*
@ -202,7 +229,6 @@ class SocketComponentHelper {
*/
virtual void connected() = 0;
/**
* \brief a task designed to read from the socket and output incoming data
*
@ -210,25 +236,64 @@ class SocketComponentHelper {
*/
static void readTask(void* pointer);
/**
* \brief a task designed for socket reconnection
*
* \param pointer: pointer to "this" component
*/
static void reconnectTask(void* pointer);
/**
* \brief signal to reconnect task that a reconnect is needed
*
*/
void requestReconnect();
/**
* \brief wait method for a task to wait for a reconnect request to complete
*
* After requesting a reconnect, tasks should call this method
* to wait for the reconnect thread to complete
*
*
* \param timeout: timeout so that the wait doesn't hang indefinitely
*
* \return status of the reconnect request, SOCK_DISCONNECTED for
* reopen again, or SOCK_SUCCESS on success, something else on error
*/
SocketIpStatus waitForReconnect(Fw::TimeInterval timeout = Fw::TimeInterval(1, 0));
private:
/**
* \brief Re-open port if it has been disconnected
*
* This function is a helper to handle the situations where this code needs to safely reopen a socket. User code should
* connect using the `open` call. This is for opening/reopening in situations where automatic open is performed
* within this socket helper.
* This function is a helper to handle the situations where this code needs to safely reopen a socket. User code
* should connect using the `open` call. This is for opening/reopening in situations where automatic open is
* performed within this socket helper.
*
* \return status of reconnect, SOCK_SUCCESS for success, something else on error
*/
SocketIpStatus reopen();
protected:
bool m_reopen = true; //!< Force reopen on disconnect
SocketDescriptor m_descriptor;
// Read/recv
Os::Task m_task;
Os::Mutex m_lock;
SocketDescriptor m_descriptor;
bool m_reopen = true; //!< Force reopen on disconnect
bool m_stop = true; //!< Stops the task when set to true
OpenState m_open = OpenState::NOT_OPEN; //!< Have we successfully opened
bool m_stop = true; //!< Stops the task when set to true
OpenState m_open = OpenState::NOT_OPEN; //!< Have we successfully opened
// Reconnect
Os::Task m_reconnectTask;
Os::Mutex m_reconnectLock;
bool m_reconnectStop = true;
ReconnectState m_reconnectState = ReconnectState::NOT_RECONNECTING;
Fw::TimeInterval m_reconnectCheckInterval =
Fw::TimeInterval(0, 50000); // 50 ms, Interval at which reconnect task loop checks for requests
Fw::TimeInterval m_reconnectWaitInterval =
Fw::TimeInterval(0, 10000); // 10 ms, Interval at which reconnect requesters wait for response
};
}
} // namespace Drv
#endif // DRV_SocketComponentHelper_HPP

View File

@ -11,28 +11,28 @@
// ======================================================================
#include <Drv/Ip/TcpClientSocket.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#include <Fw/Logger/Logger.hpp>
#include <Fw/Types/Assert.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#ifdef TGT_OS_TYPE_VXWORKS
#include <socket.h>
#include <inetLib.h>
#include <fioLib.h>
#include <hostLib.h>
#include <ioLib.h>
#include <vxWorks.h>
#include <sockLib.h>
#include <taskLib.h>
#include <sysLib.h>
#include <errnoLib.h>
#include <cstring>
#include <errnoLib.h>
#include <fioLib.h>
#include <hostLib.h>
#include <inetLib.h>
#include <ioLib.h>
#include <sockLib.h>
#include <socket.h>
#include <sysLib.h>
#include <taskLib.h>
#include <vxWorks.h>
#include <cstring>
#elif defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#else
#error OS not supported for IP Socket Communications
#error OS not supported for IP Socket Communications
#endif
#include <cstdio>
@ -46,7 +46,6 @@ bool TcpClientSocket::isValidPort(U16 port) {
return port != 0;
}
SocketIpStatus TcpClientSocket::openProtocol(SocketDescriptor& socketDescriptor) {
int socketFd = -1;
struct sockaddr_in address;
@ -70,6 +69,11 @@ SocketIpStatus TcpClientSocket::openProtocol(SocketDescriptor& socketDescriptor)
return SOCK_INVALID_IP_ADDRESS;
};
if (IpSocket::setupSocketOptions(socketFd) != SOCK_SUCCESS) {
::close(socketFd);
return SOCK_FAILED_TO_SET_SOCKET_OPTIONS;
}
// Now apply timeouts
if (IpSocket::setupTimeouts(socketFd) != SOCK_SUCCESS) {
::close(socketFd);
@ -86,12 +90,18 @@ SocketIpStatus TcpClientSocket::openProtocol(SocketDescriptor& socketDescriptor)
return SOCK_SUCCESS;
}
I32 TcpClientSocket::sendProtocol(const SocketDescriptor& socketDescriptor, const U8* const data, const U32 size) {
return static_cast<I32>(::send(socketDescriptor.fd, data, size, SOCKET_IP_SEND_FLAGS));
FwSignedSizeType TcpClientSocket::sendProtocol(const SocketDescriptor& socketDescriptor,
const U8* const data,
const FwSizeType size) {
return static_cast<FwSignedSizeType>(
::send(socketDescriptor.fd, data, static_cast<size_t>(size), SOCKET_IP_SEND_FLAGS));
}
I32 TcpClientSocket::recvProtocol(const SocketDescriptor& socketDescriptor, U8* const data, const U32 size) {
return static_cast<I32>(::recv(socketDescriptor.fd, data, size, SOCKET_IP_RECV_FLAGS));
FwSignedSizeType TcpClientSocket::recvProtocol(const SocketDescriptor& socketDescriptor,
U8* const data,
const FwSizeType size) {
return static_cast<FwSignedSizeType>(
::recv(socketDescriptor.fd, data, static_cast<size_t>(size), SOCKET_IP_RECV_FLAGS));
}
} // namespace Drv

View File

@ -12,8 +12,8 @@
#ifndef DRV_TCPCLIENT_TCPHELPER_HPP_
#define DRV_TCPCLIENT_TCPHELPER_HPP_
#include <Fw/FPrimeBasicTypes.hpp>
#include <Drv/Ip/IpSocket.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#include <config/IpCfg.hpp>
namespace Drv {
@ -29,6 +29,7 @@ class TcpClientSocket : public IpSocket {
* \brief Constructor for client socket tcp implementation
*/
TcpClientSocket();
protected:
/**
* \brief Check if the given port is valid for the socket
@ -55,7 +56,9 @@ class TcpClientSocket : public IpSocket {
* \param size: size of data to send
* \return: size of data sent, or -1 on error.
*/
I32 sendProtocol(const SocketDescriptor& socketDescriptor, const U8* const data, const U32 size) override;
FwSignedSizeType sendProtocol(const SocketDescriptor& socketDescriptor,
const U8* const data,
const FwSizeType size) override;
/**
* \brief Protocol specific implementation of recv. Called directly with error handling from recv.
* \param socketDescriptor: descriptor to recv from
@ -63,7 +66,9 @@ class TcpClientSocket : public IpSocket {
* \param size: size of data buffer
* \return: size of data received, or -1 on error.
*/
I32 recvProtocol(const SocketDescriptor& socketDescriptor, U8* const data, const U32 size) override;
FwSignedSizeType recvProtocol(const SocketDescriptor& socketDescriptor,
U8* const data,
const FwSizeType size) override;
};
} // namespace Drv

View File

@ -10,28 +10,28 @@
//
// ======================================================================
#include <Drv/Ip/TcpServerSocket.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#include <Fw/Logger/Logger.hpp>
#include <Fw/Types/Assert.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#ifdef TGT_OS_TYPE_VXWORKS
#include <socket.h>
#include <inetLib.h>
#include <fioLib.h>
#include <hostLib.h>
#include <ioLib.h>
#include <vxWorks.h>
#include <sockLib.h>
#include <taskLib.h>
#include <sysLib.h>
#include <errnoLib.h>
#include <cstring>
#include <errnoLib.h>
#include <fioLib.h>
#include <hostLib.h>
#include <inetLib.h>
#include <ioLib.h>
#include <sockLib.h>
#include <socket.h>
#include <sysLib.h>
#include <taskLib.h>
#include <vxWorks.h>
#include <cstring>
#elif defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#else
#error OS not supported for IP Socket Communications
#error OS not supported for IP Socket Communications
#endif
#include <cstring>
@ -66,6 +66,11 @@ SocketIpStatus TcpServerSocket::startup(SocketDescriptor& socketDescriptor) {
return SOCK_INVALID_IP_ADDRESS;
};
if (IpSocket::setupSocketOptions(serverFd) != SOCK_SUCCESS) {
::close(serverFd);
return SOCK_FAILED_TO_SET_SOCKET_OPTIONS;
}
// TCP requires bind to an address to the socket
if (::bind(serverFd, reinterpret_cast<struct sockaddr*>(&address), sizeof(address)) < 0) {
::close(serverFd);
@ -73,14 +78,15 @@ SocketIpStatus TcpServerSocket::startup(SocketDescriptor& socketDescriptor) {
}
socklen_t size = sizeof(address);
if (::getsockname(serverFd, reinterpret_cast<struct sockaddr *>(&address), &size) == -1) {
if (::getsockname(serverFd, reinterpret_cast<struct sockaddr*>(&address), &size) == -1) {
::close(serverFd);
return SOCK_FAILED_TO_READ_BACK_PORT;
}
// TCP requires listening on the socket. Since we only expect a single client, set the TCP backlog (second argument) to 1 to prevent queuing of multiple clients.
// TCP requires listening on the socket. Since we only expect a single client, set the TCP backlog (second argument)
// to 1 to prevent queuing of multiple clients.
if (::listen(serverFd, 1) < 0) {
::close(serverFd);
return SOCK_FAILED_TO_LISTEN; // What we have here is a failure to communicate
return SOCK_FAILED_TO_LISTEN; // What we have here is a failure to communicate
}
Fw::Logger::log("Listening for single client at %s:%hu\n", m_hostname, m_port);
FW_ASSERT(serverFd != -1);
@ -105,7 +111,7 @@ SocketIpStatus TcpServerSocket::openProtocol(SocketDescriptor& socketDescriptor)
// TCP requires accepting on the socket to get the client socket file descriptor.
clientFd = ::accept(serverFd, nullptr, nullptr);
if (clientFd < 0) {
return SOCK_FAILED_TO_ACCEPT; // What we have here is a failure to communicate
return SOCK_FAILED_TO_ACCEPT; // What we have here is a failure to communicate
}
// Setup client send timeouts
if (IpSocket::setupTimeouts(clientFd) != SOCK_SUCCESS) {
@ -118,15 +124,19 @@ SocketIpStatus TcpServerSocket::openProtocol(SocketDescriptor& socketDescriptor)
return SOCK_SUCCESS;
}
I32 TcpServerSocket::sendProtocol(const SocketDescriptor& socketDescriptor, const U8* const data, const U32 size) {
return static_cast<I32>(::send(socketDescriptor.fd, data, size, SOCKET_IP_SEND_FLAGS));
FwSignedSizeType TcpServerSocket::sendProtocol(const SocketDescriptor& socketDescriptor,
const U8* const data,
const FwSizeType size) {
return static_cast<FwSignedSizeType>(
::send(socketDescriptor.fd, data, static_cast<size_t>(size), SOCKET_IP_SEND_FLAGS));
}
I32 TcpServerSocket::recvProtocol(const SocketDescriptor& socketDescriptor, U8* const data, const U32 size) {
I32 size_buf;
FwSignedSizeType TcpServerSocket::recvProtocol(const SocketDescriptor& socketDescriptor,
U8* const data,
const FwSizeType size) {
// recv will return 0 if the client has done an orderly shutdown
size_buf = static_cast<I32>(::recv(socketDescriptor.fd, data, size, SOCKET_IP_RECV_FLAGS));
return size_buf;
return static_cast<FwSignedSizeType>(
::recv(socketDescriptor.fd, data, static_cast<size_t>(size), SOCKET_IP_RECV_FLAGS));
}
} // namespace Drv

View File

@ -12,8 +12,8 @@
#ifndef DRV_TCPSERVER_TCPHELPER_HPP_
#define DRV_TCPSERVER_TCPHELPER_HPP_
#include <Fw/FPrimeBasicTypes.hpp>
#include <Drv/Ip/IpSocket.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#include <config/IpCfg.hpp>
namespace Drv {
@ -76,7 +76,9 @@ class TcpServerSocket : public IpSocket {
* \param size: size of data to send
* \return: size of data sent, or -1 on error.
*/
I32 sendProtocol(const SocketDescriptor& socketDescriptor, const U8* const data, const U32 size) override;
FwSignedSizeType sendProtocol(const SocketDescriptor& socketDescriptor,
const U8* const data,
const FwSizeType size) override;
/**
* \brief Protocol specific implementation of recv. Called directly with error handling from recv.
* \param socketDescriptor: descriptor to recv from
@ -84,10 +86,9 @@ class TcpServerSocket : public IpSocket {
* \param size: size of data buffer
* \return: size of data received, or -1 on error.
*/
I32 recvProtocol(const SocketDescriptor& socketDescriptor, U8* const data, const U32 size) override;
FwSignedSizeType recvProtocol(const SocketDescriptor& socketDescriptor,
U8* const data,
const FwSizeType size) override;
};
} // namespace Drv

View File

@ -10,32 +10,32 @@
//
// ======================================================================
#include <Drv/Ip/UdpSocket.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#include <Fw/Logger/Logger.hpp>
#include <Fw/Types/Assert.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#include <Fw/Types/StringUtils.hpp>
#ifdef TGT_OS_TYPE_VXWORKS
#include <socket.h>
#include <inetLib.h>
#include <fioLib.h>
#include <hostLib.h>
#include <ioLib.h>
#include <vxWorks.h>
#include <sockLib.h>
#include <taskLib.h>
#include <sysLib.h>
#include <errnoLib.h>
#include <cstring>
#include <errnoLib.h>
#include <fioLib.h>
#include <hostLib.h>
#include <inetLib.h>
#include <ioLib.h>
#include <sockLib.h>
#include <socket.h>
#include <sysLib.h>
#include <taskLib.h>
#include <vxWorks.h>
#include <cstring>
#else
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
#include <cerrno>
#include <cstring>
#include <new>
#include <cerrno>
namespace Drv {
@ -46,13 +46,18 @@ UdpSocket::UdpSocket() : IpSocket(), m_recv_configured(false) {
UdpSocket::~UdpSocket() = default;
SocketIpStatus UdpSocket::configure(const char* const hostname, const U16 port, const U32 timeout_seconds, const U32 timeout_microseconds) {
FW_ASSERT(0); // Must use configureSend and/or configureRecv
SocketIpStatus UdpSocket::configure(const char* const hostname,
const U16 port,
const U32 timeout_seconds,
const U32 timeout_microseconds) {
FW_ASSERT(0); // Must use configureSend and/or configureRecv
return SocketIpStatus::SOCK_INVALID_CALL;
}
SocketIpStatus UdpSocket::configureSend(const char* const hostname, const U16 port, const U32 timeout_seconds, const U32 timeout_microseconds) {
SocketIpStatus UdpSocket::configureSend(const char* const hostname,
const U16 port,
const U32 timeout_seconds,
const U32 timeout_microseconds) {
FW_ASSERT(hostname != nullptr);
FW_ASSERT(this->isValidPort(port));
FW_ASSERT(timeout_microseconds < 1000000);
@ -63,18 +68,18 @@ SocketIpStatus UdpSocket::configureRecv(const char* hostname, const U16 port) {
FW_ASSERT(hostname != nullptr);
FW_ASSERT(this->isValidPort(port));
FW_ASSERT(Fw::StringUtils::string_length(hostname, SOCKET_MAX_HOSTNAME_SIZE) < SOCKET_MAX_HOSTNAME_SIZE);
// Initialize the receive address structure
(void)::memset(&m_addr_recv, 0, sizeof(m_addr_recv));
m_addr_recv.sin_family = AF_INET;
m_addr_recv.sin_port = htons(port);
// Convert hostname to IP address
SocketIpStatus status = IpSocket::addressToIp4(hostname, &m_addr_recv.sin_addr);
if (status != SOCK_SUCCESS) {
return status;
}
this->m_recv_configured = true;
return SOCK_SUCCESS;
}
@ -86,7 +91,7 @@ U16 UdpSocket::getRecvPort() {
SocketIpStatus UdpSocket::bind(const int fd) {
FW_ASSERT(fd != -1);
struct sockaddr_in address = this->m_addr_recv;
// OS specific settings
#if defined TGT_OS_TYPE_VXWORKS || TGT_OS_TYPE_DARWIN
address.sin_len = static_cast<U8>(sizeof(struct sockaddr_in));
@ -97,25 +102,24 @@ SocketIpStatus UdpSocket::bind(const int fd) {
}
socklen_t size = sizeof(address);
if (::getsockname(fd, reinterpret_cast<struct sockaddr *>(&address), &size) == -1) {
if (::getsockname(fd, reinterpret_cast<struct sockaddr*>(&address), &size) == -1) {
return SOCK_FAILED_TO_READ_BACK_PORT;
}
// Update m_addr_recv with the actual port assigned (for ephemeral port support)
this->m_addr_recv.sin_port = address.sin_port;
return SOCK_SUCCESS;
}
SocketIpStatus UdpSocket::openProtocol(SocketDescriptor& socketDescriptor) {
if (this->m_port == 0 && !this->m_recv_configured) {
return SOCK_INVALID_CALL; // Neither send nor receive is configured
return SOCK_INVALID_CALL; // Neither send nor receive is configured
}
SocketIpStatus status = SOCK_SUCCESS;
int socketFd = -1;
// Initialize address structure to zero before use
struct sockaddr_in address;
(void)::memset(&address, 0, sizeof(address));
@ -147,6 +151,11 @@ SocketIpStatus UdpSocket::openProtocol(SocketDescriptor& socketDescriptor) {
return status;
};
if (IpSocket::setupSocketOptions(socketFd) != SOCK_SUCCESS) {
::close(socketFd);
return SOCK_FAILED_TO_SET_SOCKET_OPTIONS;
}
// Now apply timeouts
status = this->setupTimeouts(socketFd);
if (status != SOCK_SUCCESS) {
@ -163,7 +172,7 @@ SocketIpStatus UdpSocket::openProtocol(SocketDescriptor& socketDescriptor) {
status = this->bind(socketFd);
if (status != SOCK_SUCCESS) {
(void) ::close(socketFd); // Closing FD as a retry will reopen send side
(void)::close(socketFd); // Closing FD as a retry will reopen send side
return status;
}
}
@ -172,9 +181,9 @@ SocketIpStatus UdpSocket::openProtocol(SocketDescriptor& socketDescriptor) {
char recv_addr[INET_ADDRSTRLEN];
const char* recv_addr_str = inet_ntop(AF_INET, &(this->m_addr_recv.sin_addr), recv_addr, INET_ADDRSTRLEN);
if (recv_addr_str == nullptr) {
(void) Fw::StringUtils::string_copy(recv_addr, "INVALID_ADDR", INET_ADDRSTRLEN);
(void)Fw::StringUtils::string_copy(recv_addr, "INVALID_ADDR", INET_ADDRSTRLEN);
}
if ((port == 0) && (recv_port > 0)) {
Fw::Logger::log("Setup to only receive udp at %s:%hu\n", recv_addr, recv_port);
} else if ((port > 0) && (recv_port == 0)) {
@ -182,33 +191,39 @@ SocketIpStatus UdpSocket::openProtocol(SocketDescriptor& socketDescriptor) {
} else if ((port > 0) && (recv_port > 0)) {
Fw::Logger::log("Setup to receive udp at %s:%hu and send to %s:%hu\n", recv_addr, recv_port, m_hostname, port);
}
FW_ASSERT(status == SOCK_SUCCESS, static_cast<FwAssertArgType>(status));
socketDescriptor.fd = socketFd;
return status;
}
I32 UdpSocket::sendProtocol(const SocketDescriptor& socketDescriptor, const U8* const data, const U32 size) {
FW_ASSERT(this->m_addr_send.sin_family != 0); // Make sure the address was previously setup
FW_ASSERT(socketDescriptor.fd >= 0); // File descriptor should be valid
FW_ASSERT(data != nullptr); // Data pointer should not be null
return static_cast<I32>(::sendto(socketDescriptor.fd, data, size, SOCKET_IP_SEND_FLAGS,
reinterpret_cast<struct sockaddr *>(&this->m_addr_send), sizeof(this->m_addr_send)));
FwSignedSizeType UdpSocket::sendProtocol(const SocketDescriptor& socketDescriptor,
const U8* const data,
const FwSizeType size) {
FW_ASSERT(this->m_addr_send.sin_family != 0); // Make sure the address was previously setup
FW_ASSERT(socketDescriptor.fd >= 0); // File descriptor should be valid
FW_ASSERT(data != nullptr); // Data pointer should not be null
return static_cast<FwSignedSizeType>(
::sendto(socketDescriptor.fd, data, static_cast<size_t>(size), SOCKET_IP_SEND_FLAGS,
reinterpret_cast<struct sockaddr*>(&this->m_addr_send), sizeof(this->m_addr_send)));
}
I32 UdpSocket::recvProtocol(const SocketDescriptor& socketDescriptor, U8* const data, const U32 size) {
FW_ASSERT(this->m_addr_recv.sin_family != 0); // Make sure the address was previously setup
FW_ASSERT(socketDescriptor.fd >= 0); // File descriptor should be valid
FW_ASSERT(data != nullptr); // Data pointer should not be null
FwSignedSizeType UdpSocket::recvProtocol(const SocketDescriptor& socketDescriptor,
U8* const data,
const FwSizeType size) {
FW_ASSERT(this->m_addr_recv.sin_family != 0); // Make sure the address was previously setup
FW_ASSERT(socketDescriptor.fd >= 0); // File descriptor should be valid
FW_ASSERT(data != nullptr); // Data pointer should not be null
// Initialize sender address structure to zero
struct sockaddr_in sender_addr;
(void)::memset(&sender_addr, 0, sizeof(sender_addr));
socklen_t sender_addr_len = sizeof(sender_addr);
I32 received = static_cast<I32>(::recvfrom(socketDescriptor.fd, data, size, SOCKET_IP_RECV_FLAGS,
reinterpret_cast<struct sockaddr*>(&sender_addr), &sender_addr_len));
FwSignedSizeType received = static_cast<FwSignedSizeType>(
::recvfrom(socketDescriptor.fd, data, static_cast<size_t>(size), SOCKET_IP_RECV_FLAGS,
reinterpret_cast<struct sockaddr*>(&sender_addr), &sender_addr_len));
// If we have not configured a send port, set it to the source of the last received packet
if (received >= 0 && this->m_addr_send.sin_port == 0) {
this->m_addr_send = sender_addr;
@ -218,21 +233,21 @@ I32 UdpSocket::recvProtocol(const SocketDescriptor& socketDescriptor, U8* const
return received;
}
SocketIpStatus UdpSocket::send(const SocketDescriptor& socketDescriptor, const U8* const data, const U32 size) {
SocketIpStatus UdpSocket::send(const SocketDescriptor& socketDescriptor, const U8* const data, const FwSizeType size) {
// Note: socketDescriptor.fd can be -1 in some test cases
FW_ASSERT((size == 0) || (data != nullptr));
// Special case for zero-length datagrams in UDP
if (size == 0) {
errno = 0;
I32 sent = this->sendProtocol(socketDescriptor, data, 0);
FwSignedSizeType sent = this->sendProtocol(socketDescriptor, data, 0);
if (sent == -1) {
if (errno == EINTR) {
// For zero-length datagrams, we'll just try once more if interrupted
errno = 0;
sent = this->sendProtocol(socketDescriptor, data, 0);
}
if (sent == -1) {
if ((errno == EBADF) || (errno == ECONNRESET)) {
return SOCK_DISCONNECTED;
@ -244,7 +259,7 @@ SocketIpStatus UdpSocket::send(const SocketDescriptor& socketDescriptor, const U
// For zero-length datagrams in UDP, success is either 0 or a non-negative value
return SOCK_SUCCESS;
}
// For non-zero-length data, delegate to the base class implementation
return IpSocket::send(socketDescriptor, data, size);
}

View File

@ -12,17 +12,25 @@
#ifndef DRV_IP_UDPSOCKET_HPP_
#define DRV_IP_UDPSOCKET_HPP_
#include <Fw/FPrimeBasicTypes.hpp>
#include <Drv/Ip/IpSocket.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#include <config/IpCfg.hpp>
// Include system headers for sockaddr_in
#ifdef TGT_OS_TYPE_VXWORKS
#include <socket.h>
#include <inetLib.h>
#include <inetLib.h>
#include <socket.h>
// Undefine these Vxworks-defined macros because
// they collide with member variables in F Prime.
// These macros are defined somewhere in inetLib.h.
#undef m_type
#undef m_data
#undef m_len
#else
#include <sys/socket.h>
#include <arpa/inet.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
namespace Drv {
@ -49,7 +57,9 @@ class UdpSocket : public IpSocket {
*
* \warning configure is disabled for UdpSocket. Use configureSend and configureRecv instead.
*/
SocketIpStatus configure(const char* hostname, const U16 port, const U32 send_timeout_seconds,
SocketIpStatus configure(const char* hostname,
const U16 port,
const U32 send_timeout_seconds,
const U32 send_timeout_microseconds) override;
/**
@ -70,7 +80,9 @@ class UdpSocket : public IpSocket {
* \param send_timeout_microseconds: send timeout microseconds portion. Must be less than 1000000
* \return status of configure
*/
SocketIpStatus configureSend(const char* hostname, const U16 port, const U32 send_timeout_seconds,
SocketIpStatus configureSend(const char* hostname,
const U16 port,
const U32 send_timeout_seconds,
const U32 send_timeout_microseconds);
/**
@ -105,7 +117,7 @@ class UdpSocket : public IpSocket {
* \param size: size of data to send
* \return: status of the send operation
*/
SocketIpStatus send(const SocketDescriptor& socketDescriptor, const U8* const data, const U32 size) override;
SocketIpStatus send(const SocketDescriptor& socketDescriptor, const U8* const data, const FwSizeType size) override;
protected:
/**
@ -127,7 +139,9 @@ class UdpSocket : public IpSocket {
* \param size: size of data to send
* \return: size of data sent, or -1 on error.
*/
I32 sendProtocol(const SocketDescriptor& socketDescriptor, const U8* const data, const U32 size) override;
FwSignedSizeType sendProtocol(const SocketDescriptor& socketDescriptor,
const U8* const data,
const FwSizeType size) override;
/**
* \brief Protocol specific implementation of recv. Called directly with error handling from recv.
* \param socketDescriptor: descriptor to recv from
@ -135,7 +149,9 @@ class UdpSocket : public IpSocket {
* \param size: size of data buffer
* \return: size of data received, or -1 on error.
*/
I32 recvProtocol(const SocketDescriptor& socketDescriptor, U8* const data, const U32 size) override;
FwSignedSizeType recvProtocol(const SocketDescriptor& socketDescriptor,
U8* const data,
const FwSizeType size) override;
/**
* \brief Handle zero return from recvProtocol for UDP
*
@ -149,7 +165,7 @@ class UdpSocket : public IpSocket {
private:
struct sockaddr_in m_addr_send; //!< UDP server address for sending
struct sockaddr_in m_addr_recv; //!< UDP server address for receiving
bool m_recv_configured; //!< True if configureRecv was called
bool m_recv_configured; //!< True if configureRecv was called
};
} // namespace Drv

View File

@ -154,11 +154,11 @@ socketBoth.configureRecv(127.0.0.1, 60212);
```
### Support for Ephemeral Ports
Drv::UdpSocket supports ephemeral ports through passing a 0 as the port argument for either `Drv::UdpSocket::configureSend`
Drv::UdpSocket supports ephemeral ports through passing a 0 as the port argument for either `Drv::UdpSocket::configureSend`
or `Drv::UdpSocket::configureRecv`.
For `Drv::UdpSocket::configureSend` this means that you would like to set up the UdpSocket to be able to respond to the source
port that is indicated in the UDP datagrams you receive. Note that this configuration will set up the send port to the port
For `Drv::UdpSocket::configureSend` this means that you would like to set up the UdpSocket to be able to respond to the source
port that is indicated in the UDP datagrams you receive. Note that this configuration will set up the send port to the port
specified only in the first message received.
For `Drv::UdpSocket::configureRecv` this means that you would like to be assigned an ephemeral port. This would generally be used
@ -168,16 +168,17 @@ for setting up a sender that would like to receive responses to messages on an e
The Drv::SocketComponentHelper is intended as a base class used to add in the functionality of an automatically reconnecting
receive thread to another class (typically an F´ component) as well as an interface between the component using an IP socket
and the IP socket library functions implemented in this folder. In order for this thread to function, the inheritor must
and the IP socket library functions implemented in this folder. In order for the receive thread to function, the inheritor must
implement several methods to provide the necessary interaction of this thread. These functions are described in the next
section.
section. The automatic reconnection is handled by a separate dedicated thread upon request from either the receive thread
or a send request.
In order to start the receiving thread a call to the `Drv::SocketComponentHelper::start` method is performed passing
in a name, and all arguments to `Os::Task::start` to start the task. An optional parameter, reconnect, will determine if
this read task will reconnect to sockets should a disconnect or error occur. Once started the read task will continue
in a name, and all arguments to `Os::Task::start` to start the receive and reconnect tasks. An optional parameter, reconnect,
will determine if this read task will request reconnects to sockets should a disconnect or error occur. Once started, the read task will continue
until a `Drv::SocketComponentHelper::stop` has been called or an error occurred when started without reconnect set to
`true`. Once the socket stop call has been made, the user should call `Drv::SocketComponentHelper::join` in order to
wait until the full task has finished. `Drv::SocketComponentHelper::stop` will call `Drv::SocketComponentHelper::close` on the
wait until the full tasks have finished. `Drv::SocketComponentHelper::stop` will call `Drv::SocketComponentHelper::close` on the
provided Drv::IpSocket to ensure that any blocking reads exit freeing the thread to completely stop. Normal usage of
a Drv::SocketComponentHelper derived class is shown below.
@ -187,7 +188,7 @@ uplinkComm.start(name); // Default reconnect=true
...
uplinkComm.stop();
(void) uplinkComm.join();
(void) uplinkComm.join(); // this will join the receive and reconnect tasks
```
`Drv::SocketComponentHelper::open` and `Drv::SocketComponentHelper::close` convenience methods are also provided to open and close the

View File

@ -3,10 +3,10 @@
//
#include "PortSelector.hpp"
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <arpa/inet.h>
namespace Drv {
namespace Test {
@ -29,19 +29,18 @@ U16 get_free_port(bool udp) {
};
// When we are setting up for receiving as well, then we must bind to a port
if (::bind(socketFd, reinterpret_cast<struct sockaddr *>(&address), sizeof(address)) == -1) {
if (::bind(socketFd, reinterpret_cast<struct sockaddr*>(&address), sizeof(address)) == -1) {
::close(socketFd);
return 0;
}
socklen_t size = sizeof(address);
if (::getsockname(socketFd, reinterpret_cast<struct sockaddr *>(&address), &size) == -1) {
if (::getsockname(socketFd, reinterpret_cast<struct sockaddr*>(&address), &size) == -1) {
::close(socketFd);
return 0;
}
U16 port = ntohs(address.sin_port);
::close(socketFd); // Close this recursion's port again, such that we don't infinitely loop
::close(socketFd); // Close this recursion's port again, such that we don't infinitely loop
return port;
}
}
}
} // namespace Test
} // namespace Drv

View File

@ -23,6 +23,6 @@ namespace Test {
* \return 0 on error, or a free port on success
*/
U16 get_free_port(bool is_udp = false);
}
}
} // namespace Test
} // namespace Drv
#endif // DRV_TEST_PORTSELECTOR_HPP

View File

@ -1,52 +1,52 @@
//
// Created by mstarch on 12/10/20.
//
#include <Os/Task.hpp>
#include <Drv/Ip/test/ut/SocketTestHelper.hpp>
#include "STest/Pick/Pick.hpp"
#include <gtest/gtest.h>
#include <Drv/Ip/test/ut/SocketTestHelper.hpp>
#include <Os/Task.hpp>
#include "STest/Pick/Pick.hpp"
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <arpa/inet.h>
#include <config/IpCfg.hpp>
namespace Drv {
namespace Test {
const U32 MAX_DRV_TEST_MESSAGE_SIZE = 1024;
const FwSizeType MAX_DRV_TEST_MESSAGE_SIZE = 1024;
void force_recv_timeout(int fd, Drv::IpSocket& socket) {
// Set timeout socket option
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 50; // 50ms max before test failure
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char *>(&timeout), sizeof(timeout));
timeout.tv_usec = 50; // 50ms max before test failure
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char*>(&timeout), sizeof(timeout));
}
void validate_random_data(U8 *data, U8 *truth, FwSizeType size) {
void validate_random_data(U8* data, U8* truth, FwSizeType size) {
for (FwSizeType i = 0; i < size; i++) {
ASSERT_EQ(data[i], truth[i]);
}
}
void fill_random_data(U8 *data, FwSizeType size) {
void fill_random_data(U8* data, FwSizeType size) {
ASSERT_NE(size, 0u) << "Trying to fill random data of size 0";
for (FwSizeType i = 0; i < size; i++) {
data[i] = static_cast<U8>(STest::Pick::any());
}
}
void validate_random_buffer(Fw::Buffer &buffer, U8 *data) {
void validate_random_buffer(Fw::Buffer& buffer, U8* data) {
validate_random_data(buffer.getData(), data, buffer.getSize());
buffer.setSize(0);
}
U32 fill_random_buffer(Fw::Buffer &buffer) {
FwSizeType fill_random_buffer(Fw::Buffer& buffer) {
buffer.setSize(static_cast<FwSizeType>(STest::Pick::lowerUpper(1, static_cast<U32>(buffer.getSize()))));
fill_random_data(buffer.getData(), buffer.getSize());
return static_cast<U32>(buffer.getSize());
return buffer.getSize();
}
void drain(Drv::IpSocket& receiver, Drv::SocketDescriptor& receiver_fd) {
@ -54,18 +54,18 @@ void drain(Drv::IpSocket& receiver, Drv::SocketDescriptor& receiver_fd) {
// Drain the server in preparation for close
while (status == Drv::SOCK_SUCCESS || status == Drv::SOCK_NO_DATA_AVAILABLE) {
U8 buffer[1];
U32 size = sizeof buffer;
FwSizeType size = sizeof buffer;
status = receiver.recv(receiver_fd, buffer, size);
}
ASSERT_EQ(status, Drv::SocketIpStatus::SOCK_DISCONNECTED) << "Socket did not disconnect as expected";
}
void receive_all(Drv::IpSocket& receiver, Drv::SocketDescriptor& receiver_fd, U8* buffer, U32 size) {
void receive_all(Drv::IpSocket& receiver, Drv::SocketDescriptor& receiver_fd, U8* buffer, FwSizeType size) {
ASSERT_NE(buffer, nullptr);
U32 received_size = 0;
FwSizeType received_size = 0;
Drv::SocketIpStatus status;
do {
U32 size_in_out = size - received_size;
FwSizeType size_in_out = size - received_size;
status = receiver.recv(receiver_fd, buffer + received_size, size_in_out);
ASSERT_TRUE((status == Drv::SOCK_NO_DATA_AVAILABLE || status == Drv::SOCK_SUCCESS));
received_size += size_in_out;
@ -73,8 +73,11 @@ void receive_all(Drv::IpSocket& receiver, Drv::SocketDescriptor& receiver_fd, U8
EXPECT_EQ(received_size, size);
}
void send_recv(Drv::IpSocket& sender, Drv::IpSocket& receiver, Drv::SocketDescriptor& sender_fd, Drv::SocketDescriptor& receiver_fd) {
U32 size = MAX_DRV_TEST_MESSAGE_SIZE;
void send_recv(Drv::IpSocket& sender,
Drv::IpSocket& receiver,
Drv::SocketDescriptor& sender_fd,
Drv::SocketDescriptor& receiver_fd) {
FwSizeType size = MAX_DRV_TEST_MESSAGE_SIZE;
U8 buffer_out[MAX_DRV_TEST_MESSAGE_SIZE] = {0};
U8 buffer_in[MAX_DRV_TEST_MESSAGE_SIZE] = {0};
@ -91,5 +94,5 @@ U64 get_configured_delay_ms() {
(static_cast<U64>(SOCKET_RETRY_INTERVAL.getUSeconds()) / 1000);
}
}
}
} // namespace Test
} // namespace Drv

View File

@ -1,9 +1,9 @@
//
// Created by mstarch on 12/10/20.
//
#include <Fw/FPrimeBasicTypes.hpp>
#include <Fw//Buffer/Buffer.hpp>
#include <Drv/Ip/IpSocket.hpp>
#include <Fw/Buffer/Buffer.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#ifndef DRV_TEST_SOCKETHELPER_HPP
#define DRV_TEST_SOCKETHELPER_HPP
@ -19,7 +19,7 @@ static constexpr U16 MAX_ITER = 10;
* @param fd: socket file descriptor
* @param socket: socket to make timeout
*/
void force_recv_timeout(int fd, Drv::IpSocket &socket);
void force_recv_timeout(int fd, Drv::IpSocket& socket);
/**
* Validate random data from data against truth
@ -27,27 +27,27 @@ void force_recv_timeout(int fd, Drv::IpSocket &socket);
* @param truth: truth data to validate
* @param size: size to validate
*/
void validate_random_data(U8 *data, U8 *truth, FwSizeType size);
void validate_random_data(U8* data, U8* truth, FwSizeType size);
/**
* Fills in the given data buffer with randomly picked data.
* @param data: data to file
* @param size: size of fill
*/
void fill_random_data(U8 *data, FwSizeType size);
void fill_random_data(U8* data, FwSizeType size);
/**
* Validates a given buffer against the data provided.
* @param buffer: buffer to validate
* @param truth: correct data to validate against
*/
void validate_random_buffer(Fw::Buffer &buffer, U8 *data);
void validate_random_buffer(Fw::Buffer& buffer, U8* data);
/**
* Fill random data into the buffer (using a random length).
* @param buffer: buffer to fill.
*/
U32 fill_random_buffer(Fw::Buffer &buffer);
FwSizeType fill_random_buffer(Fw::Buffer& buffer);
/**
* Send/receive pair.
@ -56,7 +56,10 @@ U32 fill_random_buffer(Fw::Buffer &buffer);
* @param sender_fd: file descriptor for sender
* @param receiver_fd: file descriptor for receiver
*/
void send_recv(Drv::IpSocket& sender, Drv::IpSocket& receiver, Drv::SocketDescriptor& sender_fd, Drv::SocketDescriptor& receiver_fd);
void send_recv(Drv::IpSocket& sender,
Drv::IpSocket& receiver,
Drv::SocketDescriptor& sender_fd,
Drv::SocketDescriptor& receiver_fd);
/**
* Drain bytes from the socket until disconnect received.
@ -72,17 +75,17 @@ void drain(Drv::IpSocket& receiver, Drv::SocketDescriptor& drain_fd);
* @param buffer: buffer
* @param size: size to receive
*/
void receive_all(Drv::IpSocket& receiver, Drv::SocketDescriptor& receiver_fd, U8* buffer, U32 size);
void receive_all(Drv::IpSocket& receiver, Drv::SocketDescriptor& receiver_fd, U8* buffer, FwSizeType size);
/**
* Wait on socket change.
*/
bool wait_on_change(Drv::IpSocket &socket, bool open, U32 iterations);
bool wait_on_change(Drv::IpSocket& socket, bool open, U32 iterations);
/**
* Wait on started
*/
bool wait_on_started(Drv::IpSocket &socket, bool open, U32 iterations);
*/
bool wait_on_started(Drv::IpSocket& socket, bool open, U32 iterations);
/**
* Get the configured delay, converted to milliseconds
@ -90,6 +93,6 @@ bool wait_on_started(Drv::IpSocket &socket, bool open, U32 iterations);
*/
U64 get_configured_delay_ms();
}
}
} // namespace Test
} // namespace Drv
#endif

View File

@ -2,22 +2,21 @@
// Created by mstarch on 12/7/20.
//
#include <gtest/gtest.h>
#include <Drv/Ip/TcpClientSocket.hpp>
#include <Drv/Ip/TcpServerSocket.hpp>
#include <Drv/Ip/IpSocket.hpp>
#include <Drv/Ip/SocketComponentHelper.hpp>
#include <Os/Console.hpp>
#include <Fw/Logger/Logger.hpp>
#include <Drv/Ip/TcpClientSocket.hpp>
#include <Drv/Ip/TcpServerSocket.hpp>
#include <Drv/Ip/test/ut/SocketTestHelper.hpp>
#include <Fw/Logger/Logger.hpp>
#include <Os/Console.hpp>
Os::Console logger;
void test_with_loop(U32 iterations) {
Drv::SocketIpStatus status1 = Drv::SOCK_SUCCESS;
Drv::SocketIpStatus status2 = Drv::SOCK_SUCCESS;
U16 port = 0; // Choose a port
U16 port = 0; // Choose a port
Drv::TcpServerSocket server;
Drv::SocketDescriptor server_fd;
Drv::SocketDescriptor client_fd;
@ -28,7 +27,7 @@ void test_with_loop(U32 iterations) {
// Loop through a bunch of client disconnects
for (U32 i = 0; i < iterations; i++) {
Drv::TcpClientSocket client;
client.configure("127.0.0.1", server.getListenPort(),0,100);
client.configure("127.0.0.1", server.getListenPort(), 0, 100);
// client_fd gets assigned a real value here
status1 = client.open(client_fd);
EXPECT_EQ(status1, Drv::SOCK_SUCCESS) << "With errno: " << errno;
@ -37,7 +36,6 @@ void test_with_loop(U32 iterations) {
status2 = server.open(server_fd);
EXPECT_EQ(status2, Drv::SOCK_SUCCESS);
// If all the opens worked, then run this
if (Drv::SOCK_SUCCESS == status1 && Drv::SOCK_SUCCESS == status2) {
// Force the sockets not to hang, if at all possible
@ -55,7 +53,6 @@ void test_with_loop(U32 iterations) {
server.terminate(server_fd);
}
TEST(Nominal, TestNominalTcp) {
test_with_loop(1);
}

View File

@ -2,24 +2,20 @@
// Created by mstarch on 12/7/20.
//
#include <gtest/gtest.h>
#include <cstring>
#include <cerrno>
#include <cstring>
#include <string>
#include <Drv/Ip/UdpSocket.hpp>
#include <Drv/Ip/IpSocket.hpp>
#include <Os/Console.hpp>
#include <Fw/Logger/Logger.hpp>
#include <Drv/Ip/UdpSocket.hpp>
#include <Drv/Ip/test/ut/PortSelector.hpp>
#include <Drv/Ip/test/ut/SocketTestHelper.hpp>
#include <Fw/Logger/Logger.hpp>
#include <Os/Console.hpp>
Os::Console logger;
enum UdpMode {
DUPLEX,
SEND,
RECEIVE
};
enum UdpMode { DUPLEX, SEND, RECEIVE };
void test_with_loop(U32 iterations, UdpMode udp_mode) {
Drv::SocketIpStatus status1 = Drv::SOCK_SUCCESS;
@ -106,34 +102,34 @@ TEST(UdpZeroLength, TestZeroLengthUdpDatagram) {
Drv::SocketDescriptor recv_fd;
U16 port = Drv::Test::get_free_port(true);
ASSERT_NE(0, port);
// Configure receiver and sender
ASSERT_EQ(receiver.configureRecv("127.0.0.1", port), Drv::SOCK_SUCCESS);
ASSERT_EQ(receiver.open(recv_fd), Drv::SOCK_SUCCESS);
ASSERT_EQ(sender.configureSend("127.0.0.1", port, 1, 0), Drv::SOCK_SUCCESS);
ASSERT_EQ(sender.open(send_fd), Drv::SOCK_SUCCESS);
// Send a zero-length datagram using the F' socket wrapper
U8 empty_data[1] = {0}; // Buffer is required, but size is 0
ASSERT_EQ(sender.send(send_fd, empty_data, 0), Drv::SOCK_SUCCESS)
U8 empty_data[1] = {0}; // Buffer is required, but size is 0
ASSERT_EQ(sender.send(send_fd, empty_data, 0), Drv::SOCK_SUCCESS)
<< "Failed to send zero-length datagram using F' socket wrapper";
// Add a small delay to ensure the packet has time to be processed by the OS
usleep(10000); // 10ms delay
usleep(10000); // 10ms delay
// Receive the zero-length datagram using the F' socket wrapper
U8 recv_buf[1] = {0xFF};
U32 recv_buf_len = 1;
I32 recv_status = receiver.recv(recv_fd, recv_buf, recv_buf_len);
FwSizeType recv_buf_len = 1;
FwSignedSizeType recv_status = receiver.recv(recv_fd, recv_buf, recv_buf_len);
// Expect 0 (success) for a zero-length datagram.
ASSERT_EQ(recv_status, 0)
<< "Expected recv_status 0 for zero-length datagram, but got " << recv_status << " with errno=" << errno;
ASSERT_EQ(recv_status, 0) << "Expected recv_status 0 for zero-length datagram, but got " << recv_status
<< " with errno=" << errno;
// Check that the received length is reported as 0
ASSERT_EQ(recv_buf_len, 0) << "Expected received length 0, but got " << recv_buf_len;
// Check that the received buffer is unchanged meaning no data was received
ASSERT_EQ(recv_buf[0], 0xFF) << "Expected unchanged buffer (0xFF), but got " << recv_buf[0];
@ -163,23 +159,23 @@ TEST(Ephemeral, TestEphemeralPorts) {
// Send a test message
const char* msg = "hello from ephemeral sender";
U32 msg_len = static_cast<U32>(strlen(msg) + 1);
FwSizeType msg_len = static_cast<FwSizeType>(strlen(msg) + 1);
ASSERT_EQ(sender.send(send_fd, reinterpret_cast<const U8*>(msg), msg_len), Drv::SOCK_SUCCESS);
// Receive the message and capture sender's port
char recv_buf[64] = {0};
U32 recv_buf_len = sizeof(recv_buf);
FwSizeType recv_buf_len = sizeof(recv_buf);
ASSERT_EQ(receiver.recv(recv_fd, reinterpret_cast<U8*>(recv_buf), recv_buf_len), Drv::SOCK_SUCCESS);
ASSERT_STREQ(msg, recv_buf);
// Receiver sends a response back to sender
const char* reply = "reply from receiver";
U32 reply_len = static_cast<U32>(strlen(reply) + 1);
FwSizeType reply_len = static_cast<FwSizeType>(strlen(reply) + 1);
ASSERT_EQ(receiver.send(recv_fd, reinterpret_cast<const U8*>(reply), reply_len), Drv::SOCK_SUCCESS);
// Sender receives the response
char reply_buf[64] = {0};
U32 reply_buf_len = sizeof(reply_buf);
FwSizeType reply_buf_len = sizeof(reply_buf);
ASSERT_EQ(sender.recv(send_fd, reinterpret_cast<U8*>(reply_buf), reply_buf_len), Drv::SOCK_SUCCESS);
ASSERT_STREQ(reply, reply_buf);

View File

@ -20,11 +20,11 @@
#include <sys/ioctl.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <type_traits>
namespace Drv {
Os::File::Status errno_to_file_status(int errno_input) {
Os::File::Status status = Os::File::Status::OTHER_ERROR;
switch (errno_input) {
@ -123,7 +123,7 @@ U32 configuration_to_event_flags(Drv::LinuxGpioDriver::GpioConfiguration configu
}
LinuxGpioDriver ::~LinuxGpioDriver() {
(void) ::close(this->m_fd);
(void)::close(this->m_fd);
}
// ----------------------------------------------------------------------
@ -138,7 +138,7 @@ Os::File::Status LinuxGpioDriver ::setupLineHandle(const int chip_descriptor,
Os::File::Status status = Os::File::OP_OK;
// Set up the GPIO request
struct gpiohandle_request request;
(void) ::memset(&request, 0, sizeof request);
(void)::memset(&request, 0, sizeof request);
request.lineoffsets[0] = gpio;
Fw::StringUtils::string_copy(request.consumer_label, FW_OPTIONAL_NAME(this->getObjName()),
static_cast<FwSizeType>(sizeof request.consumer_label));
@ -164,7 +164,7 @@ Os::File::Status LinuxGpioDriver ::setupLineEvent(const int chip_descriptor,
Os::File::Status status = Os::File::OP_OK;
// Set up the GPIO request
struct gpioevent_request event;
(void) ::memset(&event, 0, sizeof event);
(void)::memset(&event, 0, sizeof event);
event.lineoffset = gpio;
Fw::StringUtils::string_copy(event.consumer_label, FW_OPTIONAL_NAME(this->getObjName()),
static_cast<FwSizeType>(sizeof event.consumer_label));
@ -188,7 +188,8 @@ Os::File::Status LinuxGpioDriver ::open(const char* device,
Os::File::Status status = Os::File::OP_OK;
Os::File chip_file;
FW_ASSERT(device != nullptr);
FW_ASSERT(configuration < MAX_GPIO_CONFIGURATION and configuration >= 0, static_cast<FwAssertArgType>(configuration));
FW_ASSERT(configuration < MAX_GPIO_CONFIGURATION and configuration >= 0,
static_cast<FwAssertArgType>(configuration));
// Open chip file and check for success
status = chip_file.open(device, Os::File::Mode::OPEN_WRITE);
@ -197,10 +198,9 @@ Os::File::Status LinuxGpioDriver ::open(const char* device,
return status;
}
// Read chip information and check for correctness
int chip_descriptor =
reinterpret_cast<Os::Posix::File::PosixFileHandle*>(chip_file.getHandle())->m_file_descriptor;
int chip_descriptor = reinterpret_cast<Os::Posix::File::PosixFileHandle*>(chip_file.getHandle())->m_file_descriptor;
struct gpiochip_info chip_info;
(void) ::memset(&chip_info, 0, sizeof chip_info);
(void)::memset(&chip_info, 0, sizeof chip_info);
int return_value = ioctl(chip_descriptor, GPIO_GET_CHIPINFO_IOCTL, &chip_info);
if (return_value != 0) {
status = errno_to_file_status(errno);
@ -215,13 +215,13 @@ Os::File::Status LinuxGpioDriver ::open(const char* device,
}
Fw::String pin_message("Unknown");
struct gpioline_info pin_info;
(void) ::memset(&pin_info, 0, sizeof pin_info);
(void)::memset(&pin_info, 0, sizeof pin_info);
pin_info.line_offset = gpio;
return_value = ioctl(chip_descriptor, GPIO_GET_LINEINFO_IOCTL, &pin_info);
if (return_value == 0) {
const bool has_consumer = pin_info.consumer[0] != '\0';
pin_message.format("%s%s%s", pin_info.name, has_consumer ? " with current consumer " : "",
has_consumer ? pin_info.consumer : "");
has_consumer ? pin_info.consumer : "");
}
// Set up pin and set file descriptor for it
@ -247,8 +247,7 @@ Os::File::Status LinuxGpioDriver ::open(const char* device,
this->log_WARNING_HI_OpenPinError(Fw::String(device), gpio, pin_message,
Os::FileStatus(static_cast<Os::FileStatus::T>(status)));
} else {
this->log_DIAGNOSTIC_OpenChip(Fw::String(chip_info.name), Fw::String(chip_info.label),
gpio, pin_message);
this->log_DIAGNOSTIC_OpenChip(Fw::String(chip_info.name), Fw::String(chip_info.label), gpio, pin_message);
this->m_fd = pin_fd;
this->m_configuration = configuration;
}
@ -259,7 +258,7 @@ Drv::GpioStatus LinuxGpioDriver ::gpioRead_handler(const FwIndexType portNum, Fw
Drv::GpioStatus status = Drv::GpioStatus::INVALID_MODE;
if (this->m_configuration == GpioConfiguration::GPIO_INPUT) {
struct gpiohandle_data values;
(void) ::memset(&values, 0, sizeof values);
(void)::memset(&values, 0, sizeof values);
int return_value = ioctl(this->m_fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &values);
if (return_value != 0) {
status = errno_to_gpio_status(errno);
@ -275,7 +274,7 @@ Drv::GpioStatus LinuxGpioDriver ::gpioWrite_handler(const FwIndexType portNum, c
Drv::GpioStatus status = Drv::GpioStatus::INVALID_MODE;
if (this->m_configuration == GpioConfiguration::GPIO_OUTPUT) {
struct gpiohandle_data values;
(void) ::memset(&values, 0, sizeof values);
(void)::memset(&values, 0, sizeof values);
values.values[0] = (state == Fw::Logic::HIGH) ? 1 : 0;
int return_value = ioctl(this->m_fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &values);
if (return_value != 0) {
@ -291,16 +290,19 @@ void LinuxGpioDriver ::pollLoop() {
// Ensure size of FwSizeType is large enough to fit the necessary ranges
// NOTE: casts to unsigned types for int and ssize_t are made to avoid sign-compare warning;
// in both cases the cast is safe because max() returns nonnegative value.
static_assert(GPIO_POLL_TIMEOUT < static_cast<unsigned int>(std::numeric_limits<int>::max()), "Poll timeout would overflow");
static_assert(GPIO_POLL_TIMEOUT < static_cast<unsigned int>(std::numeric_limits<int>::max()),
"Poll timeout would overflow");
static_assert(sizeof(struct gpioevent_data) < std::numeric_limits<FwSizeType>::max(), "FwSizeType too small");
using unsigned_ssize_t = std::make_unsigned<ssize_t>::type;
static_assert(static_cast<unsigned_ssize_t>(std::numeric_limits<ssize_t>::max()) <= std::numeric_limits<FwSizeType>::max(), "FwSizeType too small");
static_assert(
static_cast<unsigned_ssize_t>(std::numeric_limits<ssize_t>::max()) <= std::numeric_limits<FwSizeType>::max(),
"FwSizeType too small");
// Setup poll information
pollfd file_descriptors[1];
// Loop forever
while (this->getRunning()) {
// Setup polling
(void) ::memset(file_descriptors, 0, sizeof file_descriptors);
(void)::memset(file_descriptors, 0, sizeof file_descriptors);
file_descriptors[0].fd = this->m_fd;
file_descriptors[0].events = POLLIN; // Ask for read data available
// Poll for fd bing ready

View File

@ -10,119 +10,92 @@
//
// ======================================================================
#include "Fw/Types/Assert.hpp"
#include <Fw/FPrimeBasicTypes.hpp>
#include <Drv/LinuxI2cDriver/LinuxI2cDriver.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#include <Fw/Logger/Logger.hpp>
#include "Fw/Types/Assert.hpp"
#include <unistd.h> // required for I2C device access
#include <fcntl.h> // required for I2C device configuration
#include <sys/ioctl.h> // required for I2C device usage
#include <linux/i2c.h> // required for struct / constant definitions
#include <linux/i2c-dev.h> // required for constant definitions
#include <fcntl.h> // required for I2C device configuration
#include <linux/i2c-dev.h> // required for constant definitions
#include <linux/i2c.h> // required for struct / constant definitions
#include <sys/ioctl.h> // required for I2C device usage
#include <unistd.h> // required for I2C device access
#include <cerrno>
namespace Drv {
// ----------------------------------------------------------------------
// Construction, initialization, and destruction
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Construction, initialization, and destruction
// ----------------------------------------------------------------------
LinuxI2cDriver ::
LinuxI2cDriver(
const char *const compName
) : LinuxI2cDriverComponentBase(compName),
m_fd(-1)
{
LinuxI2cDriver ::LinuxI2cDriver(const char* const compName) : LinuxI2cDriverComponentBase(compName), m_fd(-1) {}
}
LinuxI2cDriver::
~LinuxI2cDriver()
{
if (-1 != this->m_fd) { // check if file is open
::close(this->m_fd);
LinuxI2cDriver::~LinuxI2cDriver() {
if (-1 != this->m_fd) { // check if file is open
::close(this->m_fd);
}
}
}
bool LinuxI2cDriver::open(const char* device) {
FW_ASSERT(device);
this->m_fd = ::open(device, O_RDWR);
return (-1 != this->m_fd);
}
bool LinuxI2cDriver::open(const char* device) {
FW_ASSERT(device);
this->m_fd = ::open(device, O_RDWR);
return (-1 != this->m_fd);
}
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
// Note this port handler is guarded, so we can make the ioctl call
// Note this port handler is guarded, so we can make the ioctl call
Drv::I2cStatus LinuxI2cDriver ::write_handler(const FwIndexType portNum, U32 addr, Fw::Buffer& serBuffer) {
// Make sure file has been opened
if (-1 == this->m_fd) {
return I2cStatus::I2C_OPEN_ERR;
}
Drv::I2cStatus LinuxI2cDriver ::
write_handler(
const FwIndexType portNum,
U32 addr,
Fw::Buffer &serBuffer
)
{
// Make sure file has been opened
if (-1 == this->m_fd) {
return I2cStatus::I2C_OPEN_ERR;
}
// select slave address
int stat = ioctl(this->m_fd, I2C_SLAVE, addr);
if (stat == -1) {
return I2cStatus::I2C_ADDRESS_ERR;
}
// make sure it isn't a null pointer
FW_ASSERT(serBuffer.getData());
FW_ASSERT_NO_OVERFLOW(serBuffer.getSize(), size_t);
// write data
ssize_t status_write = write(this->m_fd, serBuffer.getData(), static_cast<size_t>(serBuffer.getSize()));
if (status_write == -1) {
return I2cStatus::I2C_WRITE_ERR;
}
return I2cStatus::I2C_OK;
}
// select slave address
int stat = ioctl(this->m_fd, I2C_SLAVE, addr);
if (stat == -1) {
return I2cStatus::I2C_ADDRESS_ERR;
}
// make sure it isn't a null pointer
FW_ASSERT(serBuffer.getData());
FW_ASSERT_NO_OVERFLOW(serBuffer.getSize(), size_t);
// write data
ssize_t status_write = write(this->m_fd, serBuffer.getData(), static_cast<size_t>(serBuffer.getSize()));
if (status_write == -1) {
return I2cStatus::I2C_WRITE_ERR;
}
return I2cStatus::I2C_OK;
}
Drv::I2cStatus LinuxI2cDriver ::read_handler(const FwIndexType portNum, U32 addr, Fw::Buffer& serBuffer) {
// Make sure file has been opened
if (-1 == this->m_fd) {
return I2cStatus::I2C_OPEN_ERR;
}
Drv::I2cStatus LinuxI2cDriver ::
read_handler(
const FwIndexType portNum,
U32 addr,
Fw::Buffer &serBuffer
)
{
// Make sure file has been opened
if (-1 == this->m_fd) {
return I2cStatus::I2C_OPEN_ERR;
}
// select slave address
int stat = ioctl(this->m_fd, I2C_SLAVE, addr);
if (stat == -1) {
return I2cStatus::I2C_ADDRESS_ERR;
}
// make sure it isn't a null pointer
FW_ASSERT(serBuffer.getData());
// read data
FW_ASSERT_NO_OVERFLOW(serBuffer.getSize(), size_t);
ssize_t status_read = read(this->m_fd, serBuffer.getData(), static_cast<size_t>(serBuffer.getSize()));
if (status_read == -1) {
return I2cStatus::I2C_READ_ERR;
}
return I2cStatus::I2C_OK;
}
Drv::I2cStatus LinuxI2cDriver ::
writeRead_handler(
const FwIndexType portNum, /*!< The port number*/
U32 addr,
Fw::Buffer &writeBuffer,
Fw::Buffer &readBuffer
){
// select slave address
int stat = ioctl(this->m_fd, I2C_SLAVE, addr);
if (stat == -1) {
return I2cStatus::I2C_ADDRESS_ERR;
}
// make sure it isn't a null pointer
FW_ASSERT(serBuffer.getData());
// read data
FW_ASSERT_NO_OVERFLOW(serBuffer.getSize(), size_t);
ssize_t status_read = read(this->m_fd, serBuffer.getData(), static_cast<size_t>(serBuffer.getSize()));
if (status_read == -1) {
return I2cStatus::I2C_READ_ERR;
}
return I2cStatus::I2C_OK;
}
Drv::I2cStatus LinuxI2cDriver ::writeRead_handler(const FwIndexType portNum, /*!< The port number*/
U32 addr,
Fw::Buffer& writeBuffer,
Fw::Buffer& readBuffer) {
// Make sure file has been opened
if (-1 == this->m_fd) {
return I2cStatus::I2C_OPEN_ERR;
@ -141,13 +114,13 @@ namespace Drv {
// Start address
rdwr_msgs[0].addr = static_cast<U16>(addr);
rdwr_msgs[0].flags = 0; // write
rdwr_msgs[0].flags = 0; // write
rdwr_msgs[0].len = static_cast<U16>(writeBuffer.getSize());
rdwr_msgs[0].buf = writeBuffer.getData();
// Read buffer
rdwr_msgs[1].addr = static_cast<U16>(addr);
rdwr_msgs[1].flags = I2C_M_RD; // read
rdwr_msgs[1].flags = I2C_M_RD; // read
rdwr_msgs[1].len = static_cast<U16>(readBuffer.getSize());
rdwr_msgs[1].buf = readBuffer.getData();
@ -155,15 +128,15 @@ namespace Drv {
rdwr_data.msgs = rdwr_msgs;
rdwr_data.nmsgs = 2;
//Use ioctl to perform the combined write/read transaction
// Use ioctl to perform the combined write/read transaction
int stat = ioctl(this->m_fd, I2C_RDWR, &rdwr_data);
if(stat == -1){
//Because we're using ioctl to perform the transaction we dont know exactly the type of error that occurred
return I2cStatus::I2C_OTHER_ERR;
if (stat == -1) {
// Because we're using ioctl to perform the transaction we dont know exactly the type of error that occurred
return I2cStatus::I2C_OTHER_ERR;
}
return I2cStatus::I2C_OK;
}
}
} // end namespace Drv
} // end namespace Drv

View File

@ -17,62 +17,51 @@
namespace Drv {
class LinuxI2cDriver final :
public LinuxI2cDriverComponentBase
{
class LinuxI2cDriver final : public LinuxI2cDriverComponentBase {
public:
// ----------------------------------------------------------------------
// Construction, initialization, and destruction
// ----------------------------------------------------------------------
public:
//! Construct object LinuxI2cDriver
//!
LinuxI2cDriver(const char* const compName);
// ----------------------------------------------------------------------
// Construction, initialization, and destruction
// ----------------------------------------------------------------------
bool open(const char* device);
//! Destroy object LinuxI2cDriver
//!
~LinuxI2cDriver();
//! Construct object LinuxI2cDriver
//!
LinuxI2cDriver(const char *const compName);
private:
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
bool open(const char* device);
//! Destroy object LinuxI2cDriver
//!
~LinuxI2cDriver();
//! Handler implementation for write
//!
I2cStatus write_handler(const FwIndexType portNum, /*!< The port number*/
U32 addr,
Fw::Buffer& serBuffer);
private:
//! Handler implementation for read
//!
I2cStatus read_handler(const FwIndexType portNum, /*!< The port number*/
U32 addr,
Fw::Buffer& serBuffer);
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
//! Handler implementation for writeRead
//!
I2cStatus writeRead_handler(const FwIndexType portNum, /*!< The port number*/
U32 addr,
Fw::Buffer& writeBuffer,
Fw::Buffer& readBuffer);
//! Handler implementation for write
//!
I2cStatus write_handler(
const FwIndexType portNum, /*!< The port number*/
U32 addr,
Fw::Buffer &serBuffer
);
// Prevent unused field error when using stub
#ifndef STUBBED_LINUX_I2C_DRIVER
int m_fd; //!< i2c file descriptor
#endif
};
//! Handler implementation for read
//!
I2cStatus read_handler(
const FwIndexType portNum, /*!< The port number*/
U32 addr,
Fw::Buffer &serBuffer
);
//! Handler implementation for writeRead
//!
I2cStatus writeRead_handler(
const FwIndexType portNum, /*!< The port number*/
U32 addr,
Fw::Buffer &writeBuffer,
Fw::Buffer &readBuffer
);
// Prevent unused field error when using stub
#ifndef STUBBED_LINUX_I2C_DRIVER
int m_fd; //!< i2c file descriptor
#endif
};
} // end namespace Drv
} // end namespace Drv
#endif

View File

@ -10,68 +10,43 @@
//
// ======================================================================
#include "Fw/Types/Assert.hpp"
#include <Fw/FPrimeBasicTypes.hpp>
#include <Drv/LinuxI2cDriver/LinuxI2cDriver.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#include "Fw/Types/Assert.hpp"
namespace Drv {
// ----------------------------------------------------------------------
// Construction, initialization, and destruction
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Construction, initialization, and destruction
// ----------------------------------------------------------------------
LinuxI2cDriver ::LinuxI2cDriver(
const char *const compName
) : LinuxI2cDriverComponentBase(compName)
{
LinuxI2cDriver ::LinuxI2cDriver(const char* const compName) : LinuxI2cDriverComponentBase(compName) {}
}
LinuxI2cDriver ::~LinuxI2cDriver() {}
LinuxI2cDriver ::
~LinuxI2cDriver()
{
}
bool LinuxI2cDriver::open(const char* device) {
bool LinuxI2cDriver::open(const char* device) {
return true;
}
}
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
// Note this port handler is guarded, so we can make the ioctl call
// Note this port handler is guarded, so we can make the ioctl call
I2cStatus LinuxI2cDriver ::
write_handler(
const FwIndexType portNum,
U32 addr,
Fw::Buffer &serBuffer
)
{
I2cStatus LinuxI2cDriver ::write_handler(const FwIndexType portNum, U32 addr, Fw::Buffer& serBuffer) {
return I2cStatus::I2C_OK;
}
}
Drv::I2cStatus LinuxI2cDriver ::
read_handler(
const FwIndexType portNum,
U32 addr,
Fw::Buffer &serBuffer
)
{
Drv::I2cStatus LinuxI2cDriver ::read_handler(const FwIndexType portNum, U32 addr, Fw::Buffer& serBuffer) {
return I2cStatus::I2C_OK;
}
}
Drv::I2cStatus LinuxI2cDriver ::
writeRead_handler(
const FwIndexType portNum, /*!< The port number*/
U32 addr,
Fw::Buffer &writeBuffer,
Fw::Buffer &readBuffer
){
Drv::I2cStatus LinuxI2cDriver ::writeRead_handler(const FwIndexType portNum, /*!< The port number*/
U32 addr,
Fw::Buffer& writeBuffer,
Fw::Buffer& readBuffer) {
return I2cStatus::I2C_OK;
}
}
} // end namespace Drv
} // end namespace Drv

View File

@ -17,69 +17,45 @@
namespace Drv {
// ----------------------------------------------------------------------
// Construction and destruction
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Construction and destruction
// ----------------------------------------------------------------------
LinuxI2cDriverTester ::
LinuxI2cDriverTester() :
LinuxI2cDriverGTestBase("Tester", MAX_HISTORY_SIZE),
component("LinuxI2cDriver")
{
LinuxI2cDriverTester ::LinuxI2cDriverTester()
: LinuxI2cDriverGTestBase("Tester", MAX_HISTORY_SIZE), component("LinuxI2cDriver") {
this->initComponents();
this->connectPorts();
}
}
LinuxI2cDriverTester ::
~LinuxI2cDriverTester()
{
LinuxI2cDriverTester ::~LinuxI2cDriverTester() {}
}
// ----------------------------------------------------------------------
// Tests
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Tests
// ----------------------------------------------------------------------
void LinuxI2cDriverTester ::sendData(U32 addr, U8* data, Fw::Buffer::SizeType size) {
Fw::Buffer dataBuff;
dataBuff.setdata(static_cast<PlatformPointerCastType>(data));
dataBuff.setsize(size);
this->invoke_to_write(0, addr, dataBuff);
}
void LinuxI2cDriverTester ::
sendData(U32 addr, U8* data, Fw::Buffer::SizeType size)
{
Fw::Buffer dataBuff;
dataBuff.setdata(static_cast<PlatformPointerCastType>(data));
dataBuff.setsize(size);
this->invoke_to_write(0,addr,dataBuff);
}
void LinuxI2cDriverTester::open(const char* device) {
this->component.open(device);
}
void LinuxI2cDriverTester::open(const char* device) {
this->component.open(device);
}
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
void LinuxI2cDriverTester ::
connectPorts()
{
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
void LinuxI2cDriverTester ::connectPorts() {
// write
this->connect_to_write(
0,
this->component.get_write_InputPort(0)
);
this->connect_to_write(0, this->component.get_write_InputPort(0));
}
}
void LinuxI2cDriverTester ::
initComponents()
{
void LinuxI2cDriverTester ::initComponents() {
this->init();
this->component.init(
INSTANCE
);
}
this->component.init(INSTANCE);
}
} // end namespace Drv
} // end namespace Drv

View File

@ -18,62 +18,54 @@
namespace Drv {
class LinuxI2cDriverTester :
public LinuxI2cDriverGTestBase
{
class LinuxI2cDriverTester : public LinuxI2cDriverGTestBase {
// ----------------------------------------------------------------------
// Construction and destruction
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Construction and destruction
// ----------------------------------------------------------------------
public:
//! Construct object LinuxI2cDriverTester
//!
LinuxI2cDriverTester();
public:
//! Destroy object LinuxI2cDriverTester
//!
~LinuxI2cDriverTester();
//! Construct object LinuxI2cDriverTester
//!
LinuxI2cDriverTester();
public:
// ----------------------------------------------------------------------
// Tests
// ----------------------------------------------------------------------
//! Destroy object LinuxI2cDriverTester
//!
~LinuxI2cDriverTester();
//! To do
//!
void sendData(U32 addr, U8* data, Fw::Buffer::SizeType size);
public:
void open(const char* device);
// ----------------------------------------------------------------------
// Tests
// ----------------------------------------------------------------------
private:
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
//! To do
//!
void sendData(U32 addr, U8* data, Fw::Buffer::SizeType size);
//! Connect ports
//!
void connectPorts();
void open(const char* device);
//! Initialize components
//!
void initComponents();
private:
private:
// ----------------------------------------------------------------------
// Variables
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
//! The component under test
//!
LinuxI2cDriver component;
};
//! Connect ports
//!
void connectPorts();
//! Initialize components
//!
void initComponents();
private:
// ----------------------------------------------------------------------
// Variables
// ----------------------------------------------------------------------
//! The component under test
//!
LinuxI2cDriver component;
};
} // end namespace Drv
} // end namespace Drv
#endif

View File

@ -1,58 +1,53 @@
#include <unistd.h>
#include <Fw/Types/StringUtils.hpp>
#include <LinuxI2cDriverTester.hpp>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
TEST(TestNominal,Nominal) {
TEST(TestNominal, Nominal) {
Drv::LinuxI2cDriverTester tester;
}
const char* help = "[-h] -d <I2C device> -a <I2C address> <byte 0> <byte1> ... <byteN>";
int main(int argc, char* argv[]) {
int c;
U32 addr = 0;
char device[80];
device[0] = 0;
while ((c = getopt (argc, argv, "hd:a:")) != -1) {
while ((c = getopt(argc, argv, "hd:a:")) != -1) {
switch (c) {
case 'h':
printf("test_ut %s\n",argv[0],help);
printf("test_ut %s\n", argv[0], help);
return 0;
case 'a':
addr = strtoul(optarg,0,0);
addr = strtoul(optarg, 0, 0);
break;
case 'd':
(void) Fw::StringUtils::string_copy(device, optarg, sizeof(device));
(void)Fw::StringUtils::string_copy(device, optarg, sizeof(device));
break;
default:
printf("test_ut %s\n",argv[0],help);
printf("test_ut %s\n", argv[0], help);
return -1;
}
}
printf("Address: %d (0x%02X) Device: %s\n",addr,addr,device);
printf("Address: %d (0x%02X) Device: %s\n", addr, addr, device);
U8 data[12];
for (int i = optind; i < argc; i++) {
data[optind-i] = strtoul(argv[i],0,0);
printf("Data: %s 0x%02X\n",argv[i],data[optind-i]);
data[optind - i] = strtoul(argv[i], 0, 0);
printf("Data: %s 0x%02X\n", argv[i], data[optind - i]);
}
Drv::LinuxI2cDriverTester tester;
tester.open(device);
tester.sendData(addr,data,argc-optind);
tester.sendData(addr, data, argc - optind);
return 0;
}

View File

@ -29,6 +29,18 @@ event SPI_WriteError(
format "Error writing/reading SPI device {}.{}: {}" \
throttle 5
@ SPI configuration mismatch
event SPI_ConfigMismatch(
device: I32 @< The device
select: I32 @< The chip select
parameter: string @< The parameter being configured
write_value: U32 @< The value written
read_value: U32 @< The value read
) \
severity warning low \
id 3 \
format "SPI device {}.{} configuration mismatch for {}: wrote {}, read {}"
@ SPI open notification
event SPI_PortOpened(
device: I32 @< The device

View File

@ -10,7 +10,7 @@
namespace Drv {
using LinuxSpiDriver = LinuxSpiDriverComponentImpl;
using LinuxSpiDriver = LinuxSpiDriverComponentImpl;
}

View File

@ -10,161 +10,193 @@
//
// ======================================================================
#include <fcntl.h>
#include <linux/spi/spidev.h>
#include <linux/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#include <Fw/Types/Assert.hpp>
#include <Fw/Types/FileNameString.hpp>
#include <Fw/Types/String.hpp>
#include <cerrno>
#include <cstdint>
#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <cerrno>
#include <cstring>
static_assert(FW_USE_PRINTF_FAMILY_FUNCTIONS_IN_STRING_FORMATTING, "Cannot use SPI driver without full string formatting");
static_assert(FW_USE_PRINTF_FAMILY_FUNCTIONS_IN_STRING_FORMATTING,
"Cannot use SPI driver without full string formatting");
namespace Drv {
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
void LinuxSpiDriverComponentImpl::SpiReadWrite_handler(
const FwIndexType portNum, Fw::Buffer &writeBuffer,
Fw::Buffer &readBuffer) {
// @ DEPRECATED: Use SpiWriteRead port instead (same operation with a return value)
void LinuxSpiDriverComponentImpl::SpiReadWrite_handler(const FwIndexType portNum,
Fw::Buffer& writeBuffer,
Fw::Buffer& readBuffer) {
FW_ASSERT(portNum >= 0, static_cast<FwAssertArgType>(portNum));
FW_ASSERT(writeBuffer.isValid());
FW_ASSERT(readBuffer.isValid());
(void)SpiWriteRead_handler(portNum, writeBuffer, readBuffer);
}
if (this->m_fd == -1) {
return;
}
SpiStatus LinuxSpiDriverComponentImpl::SpiWriteRead_handler(const FwIndexType portNum,
Fw::Buffer& writeBuffer,
Fw::Buffer& readBuffer) {
FW_ASSERT(portNum >= 0, static_cast<FwAssertArgType>(portNum));
FW_ASSERT(writeBuffer.isValid());
FW_ASSERT(readBuffer.isValid());
FW_ASSERT(writeBuffer.getSize() == readBuffer.getSize());
spi_ioc_transfer tr;
// Zero for unused fields:
memset(&tr, 0, sizeof(tr));
tr.tx_buf = reinterpret_cast<__u64>(writeBuffer.getData());
tr.rx_buf = reinterpret_cast<__u64>(readBuffer.getData());
FW_ASSERT_NO_OVERFLOW(writeBuffer.getSize(), __u32);
tr.len = static_cast<__u32>(writeBuffer.getSize());
/*
.speed_hz = 0,
.delay_usecs = 0,
.bits_per_word = 0,
.cs_change = 0,
.tx_nbits = 0, // on more-recent kernel versions;
.rx_nbits = 0, // on more-recent kernel versions;
.pad = 0
*/
int stat = ioctl(this->m_fd, SPI_IOC_MESSAGE(1), &tr);
if (stat < 1) {
this->log_WARNING_HI_SPI_WriteError(this->m_device,this->m_select,stat);
}
this->m_bytes += readBuffer.getSize();
this->tlmWrite_SPI_Bytes(this->m_bytes);
if (this->m_fd == -1) {
return SpiStatus::SPI_OPEN_ERR;
}
bool LinuxSpiDriverComponentImpl::open(FwIndexType device,
FwIndexType select,
SpiFrequency clock,
SpiMode spiMode) {
FW_ASSERT(device >= 0, static_cast<FwAssertArgType>(device));
FW_ASSERT(select >= 0, static_cast<FwAssertArgType>(select));
spi_ioc_transfer tr;
// Zero for unused fields:
memset(&tr, 0, sizeof(tr));
tr.tx_buf = reinterpret_cast<__u64>(writeBuffer.getData());
tr.rx_buf = reinterpret_cast<__u64>(readBuffer.getData());
FW_ASSERT_NO_OVERFLOW(writeBuffer.getSize(), __u32);
tr.len = static_cast<__u32>(writeBuffer.getSize());
/*
.speed_hz = 0,
.delay_usecs = 0,
.bits_per_word = 0,
.cs_change = 0,
.tx_nbits = 0, // on more-recent kernel versions;
.rx_nbits = 0, // on more-recent kernel versions;
.pad = 0
*/
this->m_device = device;
this->m_select = select;
int fd;
int ret;
int stat = ioctl(this->m_fd, SPI_IOC_MESSAGE(1), &tr);
// Open:
Fw::FileNameString devString;
Fw::FormatStatus formatStatus = devString.format("/dev/spidev%" PRI_FwIndexType ".%" PRI_FwIndexType, device, select);
FW_ASSERT(formatStatus == Fw::FormatStatus::SUCCESS);
if (stat < 1) {
this->log_WARNING_HI_SPI_WriteError(this->m_device, this->m_select, stat);
return SpiStatus::SPI_OTHER_ERR;
}
this->m_bytes += readBuffer.getSize();
this->tlmWrite_SPI_Bytes(this->m_bytes);
fd = ::open(devString.toChar(), O_RDWR);
if (fd == -1) {
this->log_WARNING_HI_SPI_OpenError(device,select,fd);
return false;
}
return SpiStatus::SPI_OK;
}
this->m_fd = fd;
bool LinuxSpiDriverComponentImpl::open(FwIndexType device, FwIndexType select, SpiFrequency clock, SpiMode spiMode) {
FW_ASSERT(device >= 0, static_cast<FwAssertArgType>(device));
FW_ASSERT(select >= 0, static_cast<FwAssertArgType>(select));
// Configure:
/*
* SPI Mode 0, 1, 2, 3
*/
this->m_device = device;
this->m_select = select;
int fd;
int ret;
U8 mode; // Mode Select (CPOL = 0/1, CPHA = 0/1)
switch(spiMode) {
case SpiMode::SPI_MODE_CPOL_LOW_CPHA_LOW:
mode = SPI_MODE_0;
break;
case SpiMode::SPI_MODE_CPOL_LOW_CPHA_HIGH:
mode = SPI_MODE_1;
break;
case SpiMode::SPI_MODE_CPOL_HIGH_CPHA_LOW:
mode = SPI_MODE_2;
break;
case SpiMode::SPI_MODE_CPOL_HIGH_CPHA_HIGH:
mode = SPI_MODE_3;
break;
default:
//Assert if the device SPI Mode is not in the correct range
FW_ASSERT(0, spiMode);
break;
}
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
return false;
}
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
return false;
}
/*
* 8 bits per word
*/
U8 bits = 8;
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
return false;
}
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
return false;
}
/*
* Max speed in Hz
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &clock);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
return false;
}
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &clock);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
return false;
}
return true;
// Open:
Fw::FileNameString devString;
Fw::FormatStatus formatStatus =
devString.format("/dev/spidev%" PRI_FwIndexType ".%" PRI_FwIndexType, device, select);
FW_ASSERT(formatStatus == Fw::FormatStatus::SUCCESS);
fd = ::open(devString.toChar(), O_RDWR);
if (fd == -1) {
this->log_WARNING_HI_SPI_OpenError(device, select, fd);
return false;
}
LinuxSpiDriverComponentImpl::~LinuxSpiDriverComponentImpl() {
(void) close(this->m_fd);
this->m_fd = fd;
// Configure:
/*
* SPI Mode 0, 1, 2, 3
*/
U8 mode; // Mode Select (CPOL = 0/1, CPHA = 0/1)
switch (spiMode) {
case SpiMode::SPI_MODE_CPOL_LOW_CPHA_LOW:
mode = SPI_MODE_0;
break;
case SpiMode::SPI_MODE_CPOL_LOW_CPHA_HIGH:
mode = SPI_MODE_1;
break;
case SpiMode::SPI_MODE_CPOL_HIGH_CPHA_LOW:
mode = SPI_MODE_2;
break;
case SpiMode::SPI_MODE_CPOL_HIGH_CPHA_HIGH:
mode = SPI_MODE_3;
break;
default:
// Assert if the device SPI Mode is not in the correct range
FW_ASSERT(0, spiMode);
break;
}
} // end namespace Drv
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
return false;
}
U8 read_mode = 0;
ret = ioctl(fd, SPI_IOC_RD_MODE, &read_mode);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
return false;
}
if (mode != read_mode) {
this->log_WARNING_LO_SPI_ConfigMismatch(device, select, Fw::String("MODE"), mode, read_mode);
}
/*
* 8 bits per word
*/
U8 bits = 8;
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
return false;
}
U8 read_bits = 0;
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &read_bits);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
return false;
}
if (bits != read_bits) {
this->log_WARNING_LO_SPI_ConfigMismatch(device, select, Fw::String("BITS_PER_WORD"), bits, read_bits);
}
/*
* Max speed in Hz
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &clock);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
return false;
}
SpiFrequency read_clock;
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &read_clock);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
return false;
}
if (clock != read_clock) {
this->log_WARNING_LO_SPI_ConfigMismatch(device, select, Fw::String("MAX_SPEED_HZ"), clock, read_clock);
}
return true;
}
LinuxSpiDriverComponentImpl::~LinuxSpiDriverComponentImpl() {
(void)close(this->m_fd);
}
} // end namespace Drv

View File

@ -17,83 +17,84 @@
namespace Drv {
/**
* This was taken from the dspal_tester example
*
* Supported SPI frequency to talk to MPU9x50 slave device
* MPU9x50 SPI interface supports upto 20MHz frequency. However 20MHz is not
* reliable in our test and corrupted data is observed.
*/
enum SpiFrequency
{
SPI_FREQUENCY_1MHZ = 1000000UL,
SPI_FREQUENCY_5MHZ = 5000000UL,
SPI_FREQUENCY_10MHZ = 10000000UL,
SPI_FREQUENCY_15MHZ = 15000000UL,
SPI_FREQUENCY_20MHZ = 20000000UL,
};
/**
* This was taken from the dspal_tester example
*
* Supported SPI frequency to talk to MPU9x50 slave device
* MPU9x50 SPI interface supports upto 20MHz frequency. However 20MHz is not
* reliable in our test and corrupted data is observed.
*/
enum SpiFrequency {
SPI_FREQUENCY_1MHZ = 1000000UL,
SPI_FREQUENCY_5MHZ = 5000000UL,
SPI_FREQUENCY_10MHZ = 10000000UL,
SPI_FREQUENCY_15MHZ = 15000000UL,
SPI_FREQUENCY_20MHZ = 20000000UL,
};
/**
* SPI Mode Select
*
* Defines the SPI Clock Polarity and Phase for each SPI Transaction.
*
* SPI Clock Polarity(CPOL): Defines clock polarity as idle low (CPOL = 0) or idle high(CPOL = 1)
* SPI Clock Phase(CPHA): Defines if data is shifted out on the rising clock edge and sampled
* on the falling clock edge(CPHA = 0) or if data is shifted out on the
* falling clock edge and sampled on the rising clock edge(CPHA=1)
*
*/
enum SpiMode
{
SPI_MODE_CPOL_LOW_CPHA_LOW, ///< (CPOL = 0, CPHA = 0)
SPI_MODE_CPOL_LOW_CPHA_HIGH,///< (CPOL = 0, CPHA = 1)
SPI_MODE_CPOL_HIGH_CPHA_LOW,///< (CPOL = 1, CPHA = 0)
SPI_MODE_CPOL_HIGH_CPHA_HIGH,///< (CPOL = 1, CPHA = 1)
};
/**
* SPI Mode Select
*
* Defines the SPI Clock Polarity and Phase for each SPI Transaction.
*
* SPI Clock Polarity(CPOL): Defines clock polarity as idle low (CPOL = 0) or idle high(CPOL = 1)
* SPI Clock Phase(CPHA): Defines if data is shifted out on the rising clock edge and sampled
* on the falling clock edge(CPHA = 0) or if data is shifted out on the
* falling clock edge and sampled on the rising clock edge(CPHA=1)
*
*/
enum SpiMode {
SPI_MODE_CPOL_LOW_CPHA_LOW, ///< (CPOL = 0, CPHA = 0)
SPI_MODE_CPOL_LOW_CPHA_HIGH, ///< (CPOL = 0, CPHA = 1)
SPI_MODE_CPOL_HIGH_CPHA_LOW, ///< (CPOL = 1, CPHA = 0)
SPI_MODE_CPOL_HIGH_CPHA_HIGH, ///< (CPOL = 1, CPHA = 1)
};
class LinuxSpiDriverComponentImpl final : public LinuxSpiDriverComponentBase {
class LinuxSpiDriverComponentImpl final : public LinuxSpiDriverComponentBase {
public:
// ----------------------------------------------------------------------
// Construction, initialization, and destruction
// ----------------------------------------------------------------------
public:
//! Construct object LinuxSpiDriver
//!
LinuxSpiDriverComponentImpl(const char* const compName /*!< The component name*/
);
// ----------------------------------------------------------------------
// Construction, initialization, and destruction
// ----------------------------------------------------------------------
//! Destroy object LinuxSpiDriver
//!
~LinuxSpiDriverComponentImpl();
//! Construct object LinuxSpiDriver
//!
LinuxSpiDriverComponentImpl(
const char * const compName /*!< The component name*/
);
//! Open device
bool open(FwIndexType device,
FwIndexType select,
SpiFrequency clock,
SpiMode spiMode = SpiMode::SPI_MODE_CPOL_LOW_CPHA_LOW);
//! Destroy object LinuxSpiDriver
//!
~LinuxSpiDriverComponentImpl();
private:
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
//! Open device
bool open(FwIndexType device,
FwIndexType select,
SpiFrequency clock,
SpiMode spiMode = SpiMode::SPI_MODE_CPOL_LOW_CPHA_LOW);
//! Handler implementation for SpiWriteRead
//!
SpiStatus SpiWriteRead_handler(const FwIndexType portNum, /*!< The port number*/
Fw::Buffer& WriteBuffer,
Fw::Buffer& readBuffer);
private:
// @ DEPRECATED: Use SpiWriteRead port instead (same operation with a return value)
//! Handler implementation for SpiReadWrite
//!
void SpiReadWrite_handler(const FwIndexType portNum, /*!< The port number*/
Fw::Buffer& WriteBuffer,
Fw::Buffer& readBuffer);
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
int m_fd;
FwIndexType m_device;
FwIndexType m_select;
FwSizeType m_bytes;
};
//! Handler implementation for SpiReadWrite
//!
void SpiReadWrite_handler(const FwIndexType portNum, /*!< The port number*/
Fw::Buffer &WriteBuffer, Fw::Buffer &readBuffer);
int m_fd;
FwIndexType m_device;
FwIndexType m_select;
FwSizeType m_bytes;
};
} // end namespace Drv
} // end namespace Drv
#endif

View File

@ -15,19 +15,11 @@
namespace Drv {
// ----------------------------------------------------------------------
// Construction, initialization, and destruction
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Construction, initialization, and destruction
// ----------------------------------------------------------------------
LinuxSpiDriverComponentImpl::
LinuxSpiDriverComponentImpl(const char * const compName) :
LinuxSpiDriverComponentBase(compName),
m_fd(-1),
m_device(-1),
m_select(-1),
m_bytes(0)
{
LinuxSpiDriverComponentImpl::LinuxSpiDriverComponentImpl(const char* const compName)
: LinuxSpiDriverComponentBase(compName), m_fd(-1), m_device(-1), m_select(-1), m_bytes(0) {}
}
} // end namespace Drv
} // end namespace Drv

View File

@ -15,24 +15,25 @@
namespace Drv {
bool LinuxSpiDriverComponentImpl::open(FwIndexType device,
FwIndexType select,
SpiFrequency clock,
SpiMode spiMode) {
return false;
}
bool LinuxSpiDriverComponentImpl::open(FwIndexType device, FwIndexType select, SpiFrequency clock, SpiMode spiMode) {
return false;
}
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
void LinuxSpiDriverComponentImpl::SpiReadWrite_handler(
const FwIndexType portNum, Fw::Buffer &WriteBuffer,
Fw::Buffer &readBuffer) {
}
SpiStatus LinuxSpiDriverComponentImpl::SpiWriteRead_handler(const FwIndexType portNum,
Fw::Buffer& WriteBuffer,
Fw::Buffer& readBuffer) {
return SpiStatus::SPI_OK;
}
LinuxSpiDriverComponentImpl::~LinuxSpiDriverComponentImpl() {
// @ DEPRECATED: Use SpiWriteRead port instead (same operation with a return value)
void LinuxSpiDriverComponentImpl::SpiReadWrite_handler(const FwIndexType portNum,
Fw::Buffer& WriteBuffer,
Fw::Buffer& readBuffer) {}
}
LinuxSpiDriverComponentImpl::~LinuxSpiDriverComponentImpl() {}
} // end namespace Drv
} // end namespace Drv

View File

@ -17,114 +17,84 @@
namespace Drv {
// ----------------------------------------------------------------------
// Construction and destruction
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Construction and destruction
// ----------------------------------------------------------------------
LinuxSpiDriverTester ::
LinuxSpiDriverTester() :
LinuxSpiDriverTesterBase("Tester", MAX_HISTORY_SIZE),
component("LinuxSpiDriver")
{
LinuxSpiDriverTester ::LinuxSpiDriverTester()
: LinuxSpiDriverTesterBase("Tester", MAX_HISTORY_SIZE), component("LinuxSpiDriver") {
this->initComponents();
this->connectPorts();
}
}
LinuxSpiDriverTester ::
~LinuxSpiDriverTester()
{
LinuxSpiDriverTester ::~LinuxSpiDriverTester() {}
}
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
void LinuxSpiDriverTester ::
connectPorts()
{
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
void LinuxSpiDriverTester ::connectPorts() {
// SpiReadWrite
this->connect_to_SpiReadWrite(
0,
this->component.get_SpiReadWrite_InputPort(0)
);
this->connect_to_SpiReadWrite(0, this->component.get_SpiReadWrite_InputPort(0));
// Tlm
this->component.set_Tlm_OutputPort(
0,
this->get_from_Tlm(0)
);
this->component.set_Tlm_OutputPort(0, this->get_from_Tlm(0));
// Time
this->component.set_Time_OutputPort(
0,
this->get_from_Time(0)
);
this->component.set_Time_OutputPort(0, this->get_from_Time(0));
// Log
this->component.set_Log_OutputPort(
0,
this->get_from_Log(0)
);
this->component.set_Log_OutputPort(0, this->get_from_Log(0));
// LogText
this->component.set_LogText_OutputPort(
0,
this->get_from_LogText(0)
);
this->component.set_LogText_OutputPort(0, this->get_from_LogText(0));
}
}
void LinuxSpiDriverTester ::
initComponents()
{
void LinuxSpiDriverTester ::initComponents() {
this->init();
this->component.init(
INSTANCE
);
this->component.init(INSTANCE);
this->component.open(8,0,SPI_FREQUENCY_1MHZ);
}
this->component.open(8, 0, SPI_FREQUENCY_1MHZ);
}
void LinuxSpiDriverTester::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 };
void LinuxSpiDriverTester::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);
}
printTextLogHistoryEntry(e, stdout);
}
void LinuxSpiDriverTester::sendBuffer(BYTE* buffer, FwSizeType size) {
Fw::Buffer w;
w.setdata(reinterpret_cast<PlatformPointerCastType>(buffer));
w.setsize(size);
void LinuxSpiDriverTester::sendBuffer(BYTE* buffer, FwSizeType size) {
Fw::Buffer w;
w.setdata(reinterpret_cast<PlatformPointerCastType>(buffer));
w.setsize(size);
printf("WRITE: ");
for (FwSizeType byte = 0; byte < size; byte++) {
printf("0x%02X ",buffer[byte]);
}
printf("\n");
printf("WRITE: ");
for (FwSizeType byte = 0; byte < size; byte++) {
printf("0x%02X ", buffer[byte]);
}
printf("\n");
BYTE* rb = 0;
rb = new BYTE[size];
BYTE* rb = 0;
rb = new BYTE[size];
FW_ASSERT(rb);
FW_ASSERT(rb);
Fw::Buffer r(0,0, reinterpret_cast<PlatformPointerCastType>(rb),size);
Fw::Buffer r(0, 0, reinterpret_cast<PlatformPointerCastType>(rb), size);
this->invoke_to_SpiReadWrite(0,w,r);
this->invoke_to_SpiReadWrite(0, w, r);
BYTE* d = (BYTE*)r.getdata();
printf("READ: ");
for (FwSizeType byte = 0; byte < size; byte++) {
printf("0x%02X ",d[byte]);
}
printf("\n");
BYTE* d = (BYTE*)r.getdata();
printf("READ: ");
for (FwSizeType byte = 0; byte < size; byte++) {
printf("0x%02X ", d[byte]);
}
printf("\n");
delete[] rb;
}
delete[] rb;
}
} // end namespace Drv
} // end namespace Drv

View File

@ -13,72 +13,63 @@
#ifndef TESTER_HPP
#define TESTER_HPP
#include "LinuxSpiDriverGTestBase.hpp"
#include "Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.hpp"
#include "LinuxSpiDriverGTestBase.hpp"
namespace Drv {
class LinuxSpiDriverTester :
public LinuxSpiDriverTesterBase
{
class LinuxSpiDriverTester : public LinuxSpiDriverTesterBase {
// ----------------------------------------------------------------------
// Construction and destruction
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Construction and destruction
// ----------------------------------------------------------------------
public:
//! Construct object LinuxSpiDriverTester
//!
LinuxSpiDriverTester();
public:
//! Destroy object LinuxSpiDriverTester
//!
~LinuxSpiDriverTester();
//! Construct object LinuxSpiDriverTester
//!
LinuxSpiDriverTester();
public:
// ----------------------------------------------------------------------
// Tests
// ----------------------------------------------------------------------
//! Destroy object LinuxSpiDriverTester
//!
~LinuxSpiDriverTester();
//! To do
//!
void sendBuffer(U8* buffer, FwSizeType size);
public:
private:
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Tests
// ----------------------------------------------------------------------
//! Connect ports
//!
void connectPorts();
//! To do
//!
void sendBuffer(U8* buffer, FwSizeType size);
//! Initialize components
//!
void initComponents();
private:
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
);
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
private:
// ----------------------------------------------------------------------
// Variables
// ----------------------------------------------------------------------
//! Connect ports
//!
void connectPorts();
//! The component under test
//!
LinuxSpiDriverComponentImpl component;
};
//! Initialize components
//!
void initComponents();
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
);
private:
// ----------------------------------------------------------------------
// Variables
// ----------------------------------------------------------------------
//! The component under test
//!
LinuxSpiDriverComponentImpl component;
};
} // end namespace Drv
} // end namespace Drv
#endif

View File

@ -2,25 +2,24 @@
// Main.cpp
// ----------------------------------------------------------------------
#include "LinuxSpiDriverTester.hpp"
#include <cstdlib>
#include "LinuxSpiDriverTester.hpp"
//TEST(Test, NominalTlm) {
// Svc::LinuxSpiDriverTester tester;
// tester.nominalTlm();
//}
int main(int argc, char **argv) {
// TEST(Test, NominalTlm) {
// Svc::LinuxSpiDriverTester tester;
// tester.nominalTlm();
// }
int main(int argc, char** argv) {
Drv::LinuxSpiDriverTester tester;
U8 buffer[argc-1];
U8 buffer[argc - 1];
// scan args for bytes
for (int byte = 0; byte < argc-1; byte++) {
buffer[byte] = strtol(argv[1+byte],0,0);
for (int byte = 0; byte < argc - 1; byte++) {
buffer[byte] = strtol(argv[1 + byte], 0, 0);
}
tester.sendBuffer(buffer,sizeof(buffer));
tester.sendBuffer(buffer, sizeof(buffer));
}

View File

@ -19,7 +19,7 @@
#include <fcntl.h>
#include <termios.h>
#include <cerrno>
#include <cstring>
namespace Drv {
@ -28,8 +28,13 @@ namespace Drv {
// ----------------------------------------------------------------------
LinuxUartDriver ::LinuxUartDriver(const char* const compName)
: LinuxUartDriverComponentBase(compName), m_fd(-1), m_allocationSize(0), m_device("NOT_EXIST"), m_quitReadThread(false) {
}
: LinuxUartDriverComponentBase(compName),
m_fd(-1),
m_allocationSize(0),
m_device("NOT_EXIST"),
m_bytesSent(0),
m_bytesReceived(0),
m_quitReadThread(false) {}
bool LinuxUartDriver::open(const char* const device,
UartBaudRate baud,
@ -43,7 +48,6 @@ bool LinuxUartDriver::open(const char* const device,
this->m_device = 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
@ -277,7 +281,7 @@ bool LinuxUartDriver::open(const char* const device,
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
this->ready_out(0); // Indicate the driver is connected
}
return true;
}
@ -292,28 +296,33 @@ LinuxUartDriver ::~LinuxUartDriver() {
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
void LinuxUartDriver ::send_handler(const FwIndexType portNum, Fw::Buffer& serBuffer) {
void LinuxUartDriver ::run_handler(FwIndexType portNum, U32 context) {
this->tlmWrite_BytesSent(this->m_bytesSent);
this->tlmWrite_BytesRecv(this->m_bytesReceived);
}
Drv::ByteStreamStatus LinuxUartDriver ::send_handler(const FwIndexType portNum, Fw::Buffer& serBuffer) {
Drv::ByteStreamStatus status = Drv::ByteStreamStatus::OP_OK;
if (this->m_fd == -1 || serBuffer.getData() == nullptr || serBuffer.getSize() == 0) {
status = Drv::ByteStreamStatus::OTHER_ERROR;
} else {
unsigned char *data = serBuffer.getData();
unsigned char* data = serBuffer.getData();
FW_ASSERT_NO_OVERFLOW(serBuffer.getSize(), size_t);
size_t xferSize = static_cast<size_t>(serBuffer.getSize());
ssize_t stat = ::write(this->m_fd, data, xferSize);
if (-1 == stat || static_cast<size_t>(stat) != xferSize) {
Fw::LogStringArg _arg = this->m_device;
this->log_WARNING_HI_WriteError(_arg, static_cast<I32>(stat));
status = Drv::ByteStreamStatus::OTHER_ERROR;
Fw::LogStringArg _arg = this->m_device;
this->log_WARNING_HI_WriteError(_arg, static_cast<I32>(stat));
status = Drv::ByteStreamStatus::OTHER_ERROR;
} else {
this->m_bytesSent += static_cast<FwSizeType>(stat);
}
}
// Return the buffer back to the caller
sendReturnOut_out(0, serBuffer, status);
return status;
}
void LinuxUartDriver::recvReturnIn_handler(FwIndexType portNum, Fw::Buffer& fwBuffer) {
this->deallocate_out(0, fwBuffer);
}
@ -323,7 +332,7 @@ void LinuxUartDriver ::serialReadTaskEntry(void* ptr) {
Drv::ByteStreamStatus status = ByteStreamStatus::OTHER_ERROR; // added by m.chase 03.06.2017
LinuxUartDriver* comp = reinterpret_cast<LinuxUartDriver*>(ptr);
while (!comp->m_quitReadThread) {
Fw::Buffer buff = comp->allocate_out(0,comp->m_allocationSize);
Fw::Buffer buff = comp->allocate_out(0, comp->m_allocationSize);
// On failed allocation, error
if (buff.getData() == nullptr) {
@ -356,14 +365,18 @@ void LinuxUartDriver ::serialReadTaskEntry(void* ptr) {
} else if (stat > 0) {
buff.setSize(static_cast<U32>(stat));
status = ByteStreamStatus::OP_OK; // added by m.chase 03.06.2017
comp->m_bytesReceived += static_cast<FwSizeType>(stat);
} else {
status = ByteStreamStatus::OTHER_ERROR; // Simply to return the buffer
status = ByteStreamStatus::OTHER_ERROR; // Simply to return the buffer
}
comp->recv_out(0, buff, status); // added by m.chase 03.06.2017
}
}
void LinuxUartDriver ::start(FwTaskPriorityType priority, Os::Task::ParamType stackSize, Os::Task::ParamType cpuAffinity) {
void LinuxUartDriver ::start(FwTaskPriorityType priority,
Os::Task::ParamType stackSize,
Os::Task::ParamType cpuAffinity) {
Os::TaskString task("SerReader");
Os::Task::Arguments arguments(task, serialReadTaskEntry, this, priority, stackSize, cpuAffinity);
Os::Task::Status stat = this->m_readTask.start(arguments);

View File

@ -14,6 +14,9 @@ module Drv {
@ Deallocation of allocated buffers
output port deallocate: Fw.BufferSend
@ The rate group input for sending telemetry
sync input port run: Svc.Sched
# ----------------------------------------------------------------------
# Special ports
# ----------------------------------------------------------------------

View File

@ -18,6 +18,7 @@
#include <Os/Task.hpp>
#include <termios.h>
#include <atomic>
namespace Drv {
@ -34,30 +35,30 @@ class LinuxUartDriver final : public LinuxUartDriverComponentBase {
//! Configure UART parameters
enum UartBaudRate {
BAUD_9600=9600,
BAUD_19200=19200,
BAUD_38400=38400,
BAUD_57600=57600,
BAUD_115K=115200,
BAUD_230K=230400,
BAUD_9600 = 9600,
BAUD_19200 = 19200,
BAUD_38400 = 38400,
BAUD_57600 = 57600,
BAUD_115K = 115200,
BAUD_230K = 230400,
#ifdef TGT_OS_TYPE_LINUX
BAUD_460K=460800,
BAUD_921K=921600,
BAUD_1000K=1000000,
BAUD_1152K=1152000,
BAUD_1500K=1500000,
BAUD_2000K=2000000,
BAUD_460K = 460800,
BAUD_921K = 921600,
BAUD_1000K = 1000000,
BAUD_1152K = 1152000,
BAUD_1500K = 1500000,
BAUD_2000K = 2000000,
#ifdef B2500000
BAUD_2500K=2500000,
BAUD_2500K = 2500000,
#endif
#ifdef B3000000
BAUD_3000K=3000000,
BAUD_3000K = 3000000,
#endif
#ifdef B3500000
BAUD_3500K=3500000,
BAUD_3500K = 3500000,
#endif
#ifdef B4000000
BAUD_4000K=4000000
BAUD_4000K = 4000000
#endif
#endif
};
@ -67,7 +68,11 @@ class LinuxUartDriver final : public LinuxUartDriverComponentBase {
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, FwSizeType allocationSize);
bool open(const char* const device,
UartBaudRate baud,
UartFlowControl fc,
UartParity parity,
FwSizeType allocationSize);
//! start the serial poll thread.
//! buffSize is the max receive buffer size
@ -91,29 +96,37 @@ class LinuxUartDriver final : public LinuxUartDriverComponentBase {
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
//! Handler implementation for run
//!
//! The rate group input for sending telemetry
void run_handler(FwIndexType portNum, //!< The port number
U32 context //!< The call order
) override;
//! Handler implementation for serialSend
//!
void send_handler(FwIndexType portNum, /*!< The port number*/
Fw::Buffer& serBuffer) override;
Drv::ByteStreamStatus send_handler(FwIndexType portNum, /*!< The port number*/
Fw::Buffer& serBuffer) override;
//! Handler implementation for recvReturnIn
//!
//! Port receiving back ownership of data sent out on $recv port
void recvReturnIn_handler(FwIndexType portNum, //!< The port number
Fw::Buffer& fwBuffer //!< The buffer
) override;
Fw::Buffer& fwBuffer //!< The buffer
) override;
int m_fd; //!< file descriptor returned for I/O device
FwSizeType m_allocationSize; //!< size of allocation request to memory manager
const char* m_device; //!< original device path
int m_fd; //!< file descriptor returned for I/O device
FwSizeType 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
std::atomic<FwSizeType> m_bytesSent; //!< number of bytes sent
std::atomic<FwSizeType> m_bytesReceived; //!< number of bytes received
bool m_quitReadThread; //!< flag to quit thread
};
} // end namespace Drv

View File

@ -1,5 +1,5 @@
@ Bytes Sent
telemetry BytesSent: U32 id 0
telemetry BytesSent: FwSizeType id 0
@ Bytes Received
telemetry BytesRecv: U32 id 1
telemetry BytesRecv: FwSizeType id 1

View File

@ -0,0 +1,177 @@
# Drv::LinuxUartDriver
## 1. Introduction
The LinuxUartDriver component provides a Linux-specific implementation of a UART (Universal Asynchronous Receiver-Transmitter) serial communication driver. It implements the byte stream driver model interface (see [`Drv.ByteStreamDriver`](../../Interfaces/ByteStreamDriver.fpp)) to enable serial communication with external devices through UART ports on Linux systems.
The component wraps Linux termios API functionality to provide configurable serial communication with support for various baud rates, flow control options, and parity settings. It implements bidirectional communication using a dedicated receive thread and synchronous send operations.
For more information on the ByteStreamDriverModel see: [`Drv::ByteStreamDriverModel`](../../ByteStreamDriverModel/docs/sdd.md).
## 2. Requirements
| Name | Description | Validation |
|---|---|---|
| LINUX-UART-COMP-001 | The LinuxUartDriver component shall implement the Drv.ByteStreamDriver interface | inspection |
| LINUX-UART-COMP-002 | The LinuxUartDriver component shall provide configurable baud rates from 9600 to 4MHz | inspection |
| LINUX-UART-COMP-003 | The LinuxUartDriver component shall provide configurable flow control (none/hardware) | inspection |
| LINUX-UART-COMP-004 | The LinuxUartDriver component shall provide configurable parity (none/odd/even) | inspection |
| LINUX-UART-COMP-005 | The LinuxUartDriver component shall provide a dedicated read thread for receiving data | inspection |
| LINUX-UART-COMP-006 | The LinuxUartDriver component shall report telemetry for bytes sent and received | inspection |
| LINUX-UART-COMP-007 | The LinuxUartDriver component shall handle UART errors and report them via events | inspection |
| LINUX-UART-COMP-008 | The LinuxUartDriver component shall support buffer allocation for receive operations | inspection |
## 3. Design
The LinuxUartDriver component implements the design specified by the [`Drv.ByteStreamDriver`](../../Interfaces/ByteStreamDriver.fpp) interface.
### 3.1 Architecture
The component consists of the following key elements:
- **UART Configuration**: Handles device opening, baud rate, flow control, and parity settings using Linux termios API
- **Send Handler**: Synchronous transmission of data via the `send` port (guarded input port)
- **Receive Thread**: Asynchronous reception of data via a dedicated thread that calls the `recv` output port
- **Buffer Management**: Integration with F´ buffer allocation system for memory management
- **Telemetry Reporting**: Tracks and reports bytes sent and received statistics
- **Error Handling**: Comprehensive error detection and event reporting
### 3.2 Send Operation
When data is sent via the `send` input port:
1. The component validates the file descriptor and buffer
2. Data is written to the UART device using the Linux `write()` system call
3. Bytes sent counter is updated for telemetry
4. Status is returned indicating success or failure
### 3.3 Receive Operation
The receive operation runs in a separate thread:
1. A buffer is allocated from the buffer manager
2. The thread blocks on `read()` waiting for incoming data
3. Received data is packaged in the buffer and sent via `recv` output port
4. Bytes received counter is updated for telemetry
5. Errors are logged and reported via events
### 3.4 Threading Model
The component uses a single dedicated thread for receive operations (`serialReadTaskEntry`). This thread:
- Runs continuously until `quitReadThread()` is called
- Allocates buffers for each receive operation
- Handles timeouts and errors gracefully
- Can be started with configurable priority and stack size
## 4. Usage
The LinuxUartDriver must be configured with device parameters before use. The typical usage pattern is:
1. **Open Device**: Configure the UART device with desired parameters
2. **Start Receive Thread**: Begin the receive thread for incoming data
3. **Send/Receive Data**: Use the ByteStreamDriverModel ports for communication
4. **Shutdown**: Stop the receive thread and close the device
### 4.1 Configuration Example
The LinuxUartDriver should be instantiated in the FPP topology and configured using separate functions following F´ patterns:
```cpp
// Configuration function - called during topology setup
void configureTopology() {
// Open UART device with configuration
bool success = uart.open("/dev/ttyUSB0", // Device path
Drv::LinuxUartDriver::BAUD_115K, // 115200 baud rate
Drv::LinuxUartDriver::NO_FLOW, // No flow control
Drv::LinuxUartDriver::PARITY_NONE, // No parity
1024); // Buffer size
if (!success) {
// Handle configuration error
}
...
}
// Startup function - called when starting tasks
void setupTopology() {
// Start receive thread
uart.start(UART_PRIORITY, // Thread priority
32 * 1024, // Thread stack size
Os::Task::TASK_DEFAULT); // Thread CPU affinity mask
}
// Shutdown function - called during teardown
void teardownTopology() {
uart.quitReadThread();
uart.join();
}
```
### 4.2 Integration with Rate Groups
The component includes a `run` input port for telemetry reporting that should be connected to a rate group in the FPP topology:
```fpp
# In topology.fpp connections section
connections RateGroups {
# Connect UART driver to rate group for telemetry
rateGroup1Comp.RateGroupMemberOut[N] -> uart.run
}
```
## 5. Configuration
### 5.1 Device Parameters
| Parameter | Type | Description | Valid Values |
|-----------|------|-------------|--------------|
| device | const char* | Path to UART device | Linux device path (e.g., "/dev/ttyUSB0") |
| baud | Drv::LinuxUartDriver::UartBaudRate | Communication baud rate | See baud rate enumeration |
| fc | Drv::LinuxUartDriver::UartFlowControl | Flow control setting | NO_FLOW, HW_FLOW |
| parity | Drv::LinuxUartDriver::UartParity | Parity setting | PARITY_NONE, PARITY_ODD, PARITY_EVEN |
| allocationSize | FwSizeType | Receive buffer size | Positive integer (bytes) |
### 5.2 Baud Rate Options
The component supports the following baud rates:
| Enumeration | Numeric Value | Availability |
|-------------|---------------|--------------|
| BAUD_9600 | 9600 | All platforms |
| BAUD_19200 | 19200 | All platforms |
| BAUD_38400 | 38400 | All platforms |
| BAUD_57600 | 57600 | All platforms |
| BAUD_115K | 115200 | All platforms |
| BAUD_230K | 230400 | All platforms |
| BAUD_460K | 460800 | Linux only |
| BAUD_921K | 921600 | Linux only |
| BAUD_1000K | 1000000 | Linux only |
| BAUD_1152K | 1152000 | Linux only |
| BAUD_1500K | 1500000 | Linux only |
| BAUD_2000K | 2000000 | Linux only |
| BAUD_2500K | 2500000 | Linux only (if supported) |
| BAUD_3000K | 3000000 | Linux only (if supported) |
| BAUD_3500K | 3500000 | Linux only (if supported) |
| BAUD_4000K | 4000000 | Linux only (if supported) |
### 5.3 Thread Configuration
The receive thread can be configured with:
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| priority | FwTaskPriorityType | TASK_PRIORITY_DEFAULT | Thread priority |
| stackSize | Os::Task::ParamType | TASK_DEFAULT | Thread stack size |
| cpuAffinity | Os::Task::ParamType | TASK_DEFAULT | CPU affinity mask |
### 5.4 Events and Telemetry
The component generates the following events:
- **OpenError**: UART device open failures
- **ConfigError**: UART configuration failures
- **WriteError**: Data transmission errors
- **ReadError**: Data reception errors
- **PortOpened**: Successful device configuration
- **NoBuffers**: Buffer allocation failures
- **BufferTooSmall**: Insufficient buffer size
The component reports the following telemetry:
- **BytesSent**: Total bytes transmitted
- **BytesRecv**: Total bytes received

View File

@ -3,42 +3,44 @@
namespace Drv {
DataBuffer::DataBuffer(const U8 *args, FwSizeType size) {
Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(args,size);
FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,static_cast<FwAssertArgType>(stat));
}
DataBuffer::DataBuffer(const U8* args, FwSizeType size) {
Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(args, size);
FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, static_cast<FwAssertArgType>(stat));
}
DataBuffer::DataBuffer() {
}
DataBuffer::DataBuffer() {}
DataBuffer::~DataBuffer() {
}
DataBuffer::~DataBuffer() {}
DataBuffer::DataBuffer(const DataBuffer& other) : Fw::SerializeBufferBase() {
Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(other.m_data,other.getBuffLength());
FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,static_cast<FwAssertArgType>(stat));
}
DataBuffer::DataBuffer(const DataBuffer& other) : Fw::SerializeBufferBase() {
Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(other.m_data, other.getSize());
FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, static_cast<FwAssertArgType>(stat));
}
DataBuffer& DataBuffer::operator=(const DataBuffer& other) {
if(this == &other) {
return *this;
}
Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(other.m_data,other.getBuffLength());
FW_ASSERT(Fw::FW_SERIALIZE_OK == stat,static_cast<FwAssertArgType>(stat));
DataBuffer& DataBuffer::operator=(const DataBuffer& other) {
if (this == &other) {
return *this;
}
FwSizeType DataBuffer::getBuffCapacity() const {
return sizeof(this->m_data);
}
const U8* DataBuffer::getBuffAddr() const {
return this->m_data;
}
U8* DataBuffer::getBuffAddr() {
return this->m_data;
}
Fw::SerializeStatus stat = Fw::SerializeBufferBase::setBuff(other.m_data, other.getSize());
FW_ASSERT(Fw::FW_SERIALIZE_OK == stat, static_cast<FwAssertArgType>(stat));
return *this;
}
FwSizeType DataBuffer::getCapacity() const {
return sizeof(this->m_data);
}
FwSizeType DataBuffer::getBuffCapacity() const {
return this->getCapacity();
}
const U8* DataBuffer::getBuffAddr() const {
return this->m_data;
}
U8* DataBuffer::getBuffAddr() {
return this->m_data;
}
} // namespace Drv

View File

@ -6,28 +6,29 @@
namespace Drv {
class DataBuffer : public Fw::SerializeBufferBase {
public:
enum {
DATA_BUFFER_SIZE = 256,
SERIALIZED_TYPE_ID = 1010,
SERIALIZED_SIZE = DATA_BUFFER_SIZE + sizeof(FwBuffSizeType)
};
DataBuffer(const U8 *args, FwSizeType size);
DataBuffer();
DataBuffer(const DataBuffer& other);
virtual ~DataBuffer();
DataBuffer& operator=(const DataBuffer& other);
FwSizeType getBuffCapacity() const; // !< returns capacity, not current size, of buffer
U8* getBuffAddr();
const U8* getBuffAddr() const;
private:
U8 m_data[DATA_BUFFER_SIZE]; // packet data buffer
class DataBuffer : public Fw::SerializeBufferBase {
public:
enum {
DATA_BUFFER_SIZE = 256,
SERIALIZED_TYPE_ID = 1010,
SERIALIZED_SIZE = DATA_BUFFER_SIZE + sizeof(FwBuffSizeType)
};
}
DataBuffer(const U8* args, FwSizeType size);
DataBuffer();
DataBuffer(const DataBuffer& other);
virtual ~DataBuffer();
DataBuffer& operator=(const DataBuffer& other);
DEPRECATED(FwSizeType getBuffCapacity() const, "Use getCapacity() instead");
FwSizeType getCapacity() const;
U8* getBuffAddr();
const U8* getBuffAddr() const;
private:
U8 m_data[DATA_BUFFER_SIZE]; // packet data buffer
};
} // namespace Drv
#endif

View File

@ -1,5 +1,5 @@
module Drv {
enum GpioStatus {
enum GpioStatus : U8 {
OP_OK @< Operation succeeded
NOT_OPENED @< Pin was never opened
INVALID_MODE @< Operation not permitted with current configuration

View File

@ -11,7 +11,7 @@ module Drv {
module Drv {
enum I2cStatus {
enum I2cStatus : U8 {
I2C_OK = 0 @< Transaction okay
I2C_ADDRESS_ERR = 1 @< I2C address invalid
I2C_WRITE_ERR = 2 @< I2C write failed

View File

@ -1,8 +1,28 @@
module Drv {
port SpiWriteRead(
ref writeBuffer: Fw.Buffer
ref readBuffer: Fw.Buffer
) -> Drv.SpiStatus
@ DEPRECATED: Use SpiWriteRead port instead (same operation with a return value)
port SpiReadWrite(
ref writeBuffer: Fw.Buffer
ref readBuffer: Fw.Buffer
ref readBuffer: Fw.Buffer
)
}
module Drv {
enum SpiStatus : U8 {
SPI_OK = 0 @< Transaction okay
SPI_OPEN_ERR = 1 @< SPI driver failed to open device
SPI_CONFIG_ERR = 2 @< SPI read failed
SPI_MISMATCH_ERR = 3 @< SPI read failed
SPI_WRITE_ERR = 4 @< SPI write failed
SPI_OTHER_ERR = 5 @< Other errors that do not fit
}
}

View File

@ -10,7 +10,7 @@
namespace Drv {
typedef TcpClientComponentImpl TcpClient;
typedef TcpClientComponentImpl TcpClient;
}

View File

@ -10,30 +10,25 @@
//
// ======================================================================
#include <limits>
#include <Drv/TcpClient/TcpClientComponentImpl.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#include <limits>
#include "Fw/Types/Assert.hpp"
namespace Drv {
// ----------------------------------------------------------------------
// Construction, initialization, and destruction
// ----------------------------------------------------------------------
TcpClientComponentImpl::TcpClientComponentImpl(const char* const compName)
: TcpClientComponentBase(compName) {}
TcpClientComponentImpl::TcpClientComponentImpl(const char* const compName) : TcpClientComponentBase(compName) {}
SocketIpStatus TcpClientComponentImpl::configure(const char* hostname,
const U16 port,
const U32 send_timeout_seconds,
const U32 send_timeout_microseconds,
FwSizeType buffer_size) {
// Check that ensures the configured buffer size fits within the limits fixed-width type, U32
FW_ASSERT(buffer_size <= std::numeric_limits<U32>::max(), static_cast<FwAssertArgType>(buffer_size));
m_allocation_size = buffer_size; // Store the buffer size
m_allocation_size = buffer_size; // Store the buffer size
return m_socket.configure(hostname, port, send_timeout_seconds, send_timeout_microseconds);
}
@ -48,18 +43,16 @@ IpSocket& TcpClientComponentImpl::getSocketHandler() {
}
Fw::Buffer TcpClientComponentImpl::getBuffer() {
return allocate_out(0, static_cast<U32>(m_allocation_size));
return allocate_out(0, m_allocation_size);
}
void TcpClientComponentImpl::sendBuffer(Fw::Buffer buffer, SocketIpStatus status) {
Drv::ByteStreamStatus recvStatus = ByteStreamStatus::OTHER_ERROR;
if (status == SOCK_SUCCESS) {
recvStatus = ByteStreamStatus::OP_OK;
}
else if (status == SOCK_NO_DATA_AVAILABLE) {
} else if (status == SOCK_NO_DATA_AVAILABLE) {
recvStatus = ByteStreamStatus::RECV_NO_DATA;
}
else {
} else {
recvStatus = ByteStreamStatus::OTHER_ERROR;
}
this->recv_out(0, buffer, recvStatus);
@ -69,16 +62,14 @@ void TcpClientComponentImpl::connected() {
if (isConnected_ready_OutputPort(0)) {
this->ready_out(0);
}
}
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
void TcpClientComponentImpl::send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) {
FW_ASSERT_NO_OVERFLOW(fwBuffer.getSize(), U32);
Drv::SocketIpStatus status = send(fwBuffer.getData(), static_cast<U32>(fwBuffer.getSize()));
Drv::ByteStreamStatus TcpClientComponentImpl::send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) {
Drv::SocketIpStatus status = send(fwBuffer.getData(), fwBuffer.getSize());
Drv::ByteStreamStatus returnStatus;
switch (status) {
case SOCK_INTERRUPTED_TRY_AGAIN:
@ -91,8 +82,7 @@ void TcpClientComponentImpl::send_handler(const FwIndexType portNum, Fw::Buffer&
returnStatus = ByteStreamStatus::OTHER_ERROR;
break;
}
// Return the buffer and status to the caller
this->sendReturnOut_out(0, fwBuffer, returnStatus);
return returnStatus;
}
void TcpClientComponentImpl::recvReturnIn_handler(FwIndexType portNum, Fw::Buffer& fwBuffer) {

View File

@ -21,8 +21,7 @@
namespace Drv {
class TcpClientComponentImpl final : public TcpClientComponentBase, public SocketComponentHelper {
friend class TcpClientTester;
friend class TcpClientTester;
public:
// ----------------------------------------------------------------------
@ -103,12 +102,10 @@ class TcpClientComponentImpl final : public TcpClientComponentBase, public Socke
/**
* \brief called when the IPv4 system has been connected
*/
*/
void connected() override;
private:
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
@ -127,17 +124,16 @@ class TcpClientComponentImpl final : public TcpClientComponentBase, public Socke
* \param portNum: fprime port number of the incoming port call
* \param fwBuffer: buffer containing data to be sent
*/
void send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) override;
Drv::ByteStreamStatus send_handler(const FwIndexType portNum, Fw::Buffer& fwBuffer) override;
//! Handler implementation for recvReturnIn
//!
//! Port receiving back ownership of data sent out on $recv port
void recvReturnIn_handler(FwIndexType portNum, //!< The port number
Fw::Buffer& fwBuffer //!< The buffer
) override;
Fw::Buffer& fwBuffer //!< The buffer
) override;
Drv::TcpClientSocket m_socket; //!< Socket implementation
Drv::TcpClientSocket m_socket; //!< Socket implementation
// Member variable to store the buffer size
FwSizeType m_allocation_size;
@ -145,4 +141,4 @@ class TcpClientComponentImpl final : public TcpClientComponentBase, public Socke
} // end namespace Drv
#endif // end TcpClientComponentImpl
#endif // end TcpClientComponentImpl

View File

@ -4,7 +4,6 @@
#include "TcpClientTester.hpp"
TEST(Nominal, TcpClientBasicMessaging) {
Drv::TcpClientTester tester;
tester.test_basic_messaging();

View File

@ -10,10 +10,10 @@
//
// ======================================================================
#include "TcpClientTester.hpp"
#include "STest/Pick/Pick.hpp"
#include <Os/Console.hpp>
#include <Drv/Ip/test/ut/PortSelector.hpp>
#include <Drv/Ip/test/ut/SocketTestHelper.hpp>
#include <Os/Console.hpp>
#include "STest/Pick/Pick.hpp"
Os::Console logger;
@ -23,18 +23,20 @@ namespace Drv {
// Construction and destruction
// ----------------------------------------------------------------------
void TcpClientTester ::setup_helper(Drv::TcpServerSocket& server, Drv::SocketDescriptor& server_fd, bool recv_thread, bool reconnect) {
void TcpClientTester ::setup_helper(Drv::TcpServerSocket& server,
Drv::SocketDescriptor& server_fd,
bool recv_thread,
bool reconnect) {
Drv::SocketIpStatus serverStat = Drv::SOCK_SUCCESS;
U16 port = 0;
U16 port = 0;
server.configure("127.0.0.1", port, 0, 100);
serverStat = server.startup(server_fd);
this->component.configure("127.0.0.1", server.getListenPort(), 0, 100);
ASSERT_EQ(serverStat, SOCK_SUCCESS)
<< "TCP server startup error: " << strerror(errno) << std::endl
<< "Port: " << port << std::endl;
ASSERT_EQ(serverStat, SOCK_SUCCESS) << "TCP server startup error: " << strerror(errno) << std::endl
<< "Port: " << port << std::endl;
// Start up a receive thread
if (recv_thread) {
@ -44,7 +46,6 @@ void TcpClientTester ::setup_helper(Drv::TcpServerSocket& server, Drv::SocketDes
}
}
void TcpClientTester ::test_with_loop(U32 iterations, bool recv_thread) {
U8 buffer[sizeof(m_data_storage)] = {};
Drv::SocketIpStatus status1 = Drv::SOCK_SUCCESS;
@ -56,13 +57,14 @@ void TcpClientTester ::test_with_loop(U32 iterations, bool recv_thread) {
// Loop through a bunch of client disconnects
for (U32 i = 0; i < iterations; i++) {
U32 size = sizeof(m_data_storage);
FwSizeType size = sizeof(m_data_storage);
// Not testing with reconnect thread, we will need to open ourselves
if (not recv_thread) {
status1 = this->component.open();
} else {
EXPECT_TRUE(this->wait_on_change(this->component.getSocketHandler(), true, Drv::Test::get_configured_delay_ms()/10 + 1));
EXPECT_TRUE(this->wait_on_change(this->component.getSocketHandler(), true,
Drv::Test::get_configured_delay_ms() / 10 + 1));
}
EXPECT_TRUE(this->component.isOpened());
// fd has now been updated to be a value we need to keep track of
@ -72,16 +74,13 @@ void TcpClientTester ::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.isOpened())) {
if ((Drv::SOCK_SUCCESS == status1) && (Drv::SOCK_SUCCESS == status2) && (this->component.isOpened())) {
// Force the sockets not to hang, if at all possible
Drv::Test::force_recv_timeout(this->component.m_descriptor.fd, this->component.getSocketHandler());
Drv::Test::force_recv_timeout(server_fd.serverFd, server);
m_data_buffer.setSize(sizeof(m_data_storage));
size = Drv::Test::fill_random_buffer(m_data_buffer);
invoke_to_send(0, m_data_buffer);
ASSERT_from_sendReturnOut_SIZE(i + 1);
Drv::ByteStreamStatus status = this->fromPortHistory_sendReturnOut->at(i).status;
Drv::ByteStreamStatus status = invoke_to_send(0, m_data_buffer);
EXPECT_EQ(status, ByteStreamStatus::OP_OK);
Drv::Test::receive_all(server, server_fd, buffer, size);
Drv::Test::validate_random_buffer(m_data_buffer, buffer);
@ -91,7 +90,8 @@ void TcpClientTester ::test_with_loop(U32 iterations, bool recv_thread) {
m_data_buffer.setSize(sizeof(m_data_storage));
status2 = server.send(server_fd, m_data_buffer.getData(), m_data_buffer.getSize());
EXPECT_EQ(status2, Drv::SOCK_SUCCESS);
while (not m_spinner) {}
while (not m_spinner) {
}
}
}
// Properly stop the client on the last iteration
@ -115,7 +115,8 @@ void TcpClientTester ::test_with_loop(U32 iterations, bool recv_thread) {
TcpClientTester ::TcpClientTester()
: TcpClientGTestBase("Tester", MAX_HISTORY_SIZE),
component("TcpClient"),
m_data_buffer(m_data_storage, 0), m_spinner(true) {
m_data_buffer(m_data_storage, 0),
m_spinner(true) {
this->initComponents();
this->connectPorts();
::memset(m_data_storage, 0, sizeof(m_data_storage));
@ -123,7 +124,7 @@ TcpClientTester ::TcpClientTester()
TcpClientTester ::~TcpClientTester() {}
bool TcpClientTester::wait_on_change(Drv::IpSocket &socket, bool open, U32 iterations) {
bool TcpClientTester::wait_on_change(Drv::IpSocket& socket, bool open, U32 iterations) {
for (U32 i = 0; i < iterations; i++) {
if (open == this->component.isOpened()) {
return true;
@ -137,7 +138,6 @@ bool TcpClientTester::wait_on_change(Drv::IpSocket &socket, bool open, U32 itera
// Tests
// ----------------------------------------------------------------------
void TcpClientTester ::test_basic_messaging() {
test_with_loop(1);
}
@ -151,7 +151,7 @@ void TcpClientTester ::test_receive_thread() {
}
void TcpClientTester ::test_advanced_reconnect() {
test_with_loop(10, true); // Up to 10 * RECONNECT_MS
test_with_loop(10, true); // Up to 10 * RECONNECT_MS
}
void TcpClientTester ::test_no_automatic_send_connection() {
@ -171,7 +171,8 @@ void TcpClientTester ::test_no_automatic_recv_connection() {
Drv::SocketDescriptor server_fd;
this->setup_helper(server, server_fd, true, false);
// Wait for connection to not start
EXPECT_FALSE(this->wait_on_change(this->component.getSocketHandler(), true, Drv::Test::get_configured_delay_ms()/10 + 1));
EXPECT_FALSE(
this->wait_on_change(this->component.getSocketHandler(), true, Drv::Test::get_configured_delay_ms() / 10 + 1));
ASSERT_FALSE(this->component.isOpened());
// Clean-up even if the thread (incorrectly) started
this->component.stop();
@ -184,7 +185,7 @@ void TcpClientTester ::test_buffer_deallocation() {
U8 data[1];
Fw::Buffer buffer(data, sizeof(data));
this->invoke_to_recvReturnIn(0, buffer);
ASSERT_from_deallocate_SIZE(1); // incoming buffer should be deallocated
ASSERT_from_deallocate_SIZE(1); // incoming buffer should be deallocated
ASSERT_EQ(this->fromPortHistory_deallocate->at(0).fwBuffer.getData(), data);
ASSERT_EQ(this->fromPortHistory_deallocate->at(0).fwBuffer.getSize(), sizeof(data));
}
@ -193,15 +194,11 @@ void TcpClientTester ::test_buffer_deallocation() {
// Handler overrides for typed from ports
// ----------------------------------------------------------------------
void TcpClientTester ::
from_recv_handler(
const FwIndexType portNum,
Fw::Buffer &recvBuffer,
const ByteStreamStatus &ByteStreamStatus
)
{
void TcpClientTester ::from_recv_handler(const FwIndexType portNum,
Fw::Buffer& recvBuffer,
const ByteStreamStatus& ByteStreamStatus) {
this->pushFromPortEntry_recv(recvBuffer, ByteStreamStatus);
if (ByteStreamStatus == ByteStreamStatus::OP_OK){
if (ByteStreamStatus == ByteStreamStatus::OP_OK) {
// Make sure we can get to unblocking the spinner
EXPECT_EQ(m_data_buffer.getSize(), recvBuffer.getSize()) << "Invalid transmission size";
Drv::Test::validate_random_buffer(m_data_buffer, recvBuffer.getData());
@ -211,16 +208,11 @@ void TcpClientTester ::test_buffer_deallocation() {
delete[] recvBuffer.getData();
}
Fw::Buffer TcpClientTester ::
from_allocate_handler(
const FwIndexType portNum,
FwSizeType size
)
{
Fw::Buffer TcpClientTester ::from_allocate_handler(const FwIndexType portNum, FwSizeType size) {
this->pushFromPortEntry_allocate(size);
Fw::Buffer buffer(new U8[size], size);
m_data_buffer2 = buffer;
return buffer;
}
}
} // end namespace Drv

View File

@ -13,115 +13,103 @@
#ifndef TESTER_HPP
#define TESTER_HPP
#include "TcpClientGTestBase.hpp"
#include "Drv/TcpClient/TcpClientComponentImpl.hpp"
#include "Drv/Ip/TcpServerSocket.hpp"
#include "Drv/TcpClient/TcpClientComponentImpl.hpp"
#include "TcpClientGTestBase.hpp"
#define SEND_DATA_BUFFER_SIZE 1024
namespace Drv {
class TcpClientTester :
public TcpClientGTestBase
{
// Maximum size of histories storing events, telemetry, and port outputs
static const U32 MAX_HISTORY_SIZE = 1000;
// Instance ID supplied to the component instance under test
static const FwEnumStoreType TEST_INSTANCE_ID = 0;
// Queue depth supplied to component instance under test
static const FwSizeType TEST_INSTANCE_QUEUE_DEPTH = 100;
class TcpClientTester : public TcpClientGTestBase {
// Maximum size of histories storing events, telemetry, and port outputs
static const FwSizeType MAX_HISTORY_SIZE = 1000;
// Instance ID supplied to the component instance under test
static const FwEnumStoreType TEST_INSTANCE_ID = 0;
// Queue depth supplied to component instance under test
static const FwSizeType TEST_INSTANCE_QUEUE_DEPTH = 100;
// ----------------------------------------------------------------------
// Construction and destruction
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Construction and destruction
// ----------------------------------------------------------------------
public:
public:
//! Construct object TcpClientTester
//!
TcpClientTester();
//! Construct object TcpClientTester
//!
TcpClientTester();
//! Destroy object TcpClientTester
//!
~TcpClientTester();
//! Destroy object TcpClientTester
//!
~TcpClientTester();
public:
// ----------------------------------------------------------------------
// Tests
// ----------------------------------------------------------------------
public:
void setup_helper(Drv::TcpServerSocket& server, Drv::SocketDescriptor& server_fd, bool recv_thread, bool reconnect);
// ----------------------------------------------------------------------
// Tests
// ----------------------------------------------------------------------
void test_basic_messaging();
void setup_helper(Drv::TcpServerSocket& server, Drv::SocketDescriptor& server_fd, bool recv_thread, bool reconnect);
void test_multiple_messaging();
void test_basic_messaging();
void test_receive_thread();
void test_multiple_messaging();
void test_advanced_reconnect();
void test_receive_thread();
void test_no_automatic_send_connection();
void test_advanced_reconnect();
void test_no_automatic_recv_connection();
void test_no_automatic_send_connection();
void test_with_loop(U32 iterations, bool recv_thread = false);
void test_no_automatic_recv_connection();
void test_buffer_deallocation();
void test_with_loop(U32 iterations, bool recv_thread=false);
private:
// ----------------------------------------------------------------------
// Handler overrides for typed from ports
// ----------------------------------------------------------------------
void test_buffer_deallocation();
//! Handler for from_recv
//!
void from_recv_handler(const FwIndexType portNum, /*!< The port number*/
Fw::Buffer& recvBuffer,
const ByteStreamStatus& ByteStreamStatus) override;
private:
//! Handler for from_allocate
//!
Fw::Buffer from_allocate_handler(const FwIndexType portNum, /*!< The port number*/
FwSizeType size) override;
// ----------------------------------------------------------------------
// Handler overrides for typed from ports
// ----------------------------------------------------------------------
private:
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
//! Handler for from_recv
//!
void from_recv_handler(
const FwIndexType portNum, /*!< The port number*/
Fw::Buffer &recvBuffer,
const ByteStreamStatus &ByteStreamStatus
) override;
bool wait_on_change(Drv::IpSocket& socket, bool open, U32 iterations);
//! Handler for from_allocate
//!
Fw::Buffer from_allocate_handler(
const FwIndexType portNum, /*!< The port number*/
FwSizeType size
) override;
//! Connect ports
//!
void connectPorts();
private:
//! Initialize components
//!
void initComponents();
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
private:
// ----------------------------------------------------------------------
// Variables
// ----------------------------------------------------------------------
bool wait_on_change(Drv::IpSocket &socket, bool open, U32 iterations);
//! The component under test
//!
TcpClientComponentImpl component;
Fw::Buffer m_data_buffer;
Fw::Buffer m_data_buffer2;
U8 m_data_storage[SEND_DATA_BUFFER_SIZE];
std::atomic<bool> m_spinner;
};
//! Connect ports
//!
void connectPorts();
//! Initialize components
//!
void initComponents();
private:
// ----------------------------------------------------------------------
// Variables
// ----------------------------------------------------------------------
//! The component under test
//!
TcpClientComponentImpl component;
Fw::Buffer m_data_buffer;
Fw::Buffer m_data_buffer2;
U8 m_data_storage[SEND_DATA_BUFFER_SIZE];
std::atomic<bool> m_spinner;
};
} // end namespace Drv
} // end namespace Drv
#endif

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