Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Svc/FpySequencer/FpySequencer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ FpySequencer ::FpySequencer(const char* const compName)
m_goalState(),
m_sequencesStarted(0),
m_statementsDispatched(0),
m_rng(),
m_rngSeeded(false),
m_runtime(),
m_breakpoint(),
m_tlm() {}
Expand Down
15 changes: 15 additions & 0 deletions Svc/FpySequencer/FpySequencer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "Svc/FpySequencer/SequenceSerializableAc.hpp"
#include "Svc/FpySequencer/StatementSerializableAc.hpp"
#include "config/FppConstantsAc.hpp"
#include <random>

static_assert(Svc::Fpy::MAX_SEQUENCE_ARG_COUNT <= std::numeric_limits<U8>::max(),
"Sequence arg count must be below U8 max");
Expand Down Expand Up @@ -63,6 +64,8 @@ class FpySequencer : public FpySequencerComponentBase {
FpySequencer_MemCmpDirective memCmp;
FpySequencer_StackCmdDirective stackCmd;
FpySequencer_PushTimeDirective pushTime;
FpySequencer_SetSeedDirective setSeed;
FpySequencer_PushRandDirective pushRand;
FpySequencer_GetFieldDirective getField;
FpySequencer_PeekDirective peek;
FpySequencer_StoreRelDirective storeRel;
Expand Down Expand Up @@ -541,6 +544,12 @@ class FpySequencer : public FpySequencerComponentBase {
//! Internal interface handler for directive_pushTime
void directive_pushTime_internalInterfaceHandler(const Svc::FpySequencer_PushTimeDirective& directive) override;

//! Internal interface handler for directive_setSeed
void directive_setSeed_internalInterfaceHandler(const Svc::FpySequencer_SetSeedDirective& directive) override;

//! Internal interface handler for directive_pushRand
void directive_pushRand_internalInterfaceHandler(const Svc::FpySequencer_PushRandDirective& directive) override;

//! Internal interface handler for directive_getField
void directive_getField_internalInterfaceHandler(const Svc::FpySequencer_GetFieldDirective& directive) override;

Expand Down Expand Up @@ -611,6 +620,10 @@ class FpySequencer : public FpySequencerComponentBase {
// otherwise, since construction
U64 m_statementsDispatched;

// per-component RNG state used by PUSH_RAND and later SET_SEED-style directives
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put these in Runtime struct

std::mt19937 m_rng;
bool m_rngSeeded = false;

// the runtime state of the sequence. encapsulates all state
// needed to run the sequence.
// this is distinct from the state of the sequencer. the
Expand Down Expand Up @@ -838,6 +851,8 @@ class FpySequencer : public FpySequencerComponentBase {
Signal memCmp_directiveHandler(const FpySequencer_MemCmpDirective& directive, DirectiveError& error);
Signal stackCmd_directiveHandler(const FpySequencer_StackCmdDirective& directive, DirectiveError& error);
Signal pushTime_directiveHandler(const FpySequencer_PushTimeDirective& directive, DirectiveError& error);
Signal setSeed_directiveHandler(const FpySequencer_SetSeedDirective& directive, DirectiveError& error);
Signal pushRand_directiveHandler(const FpySequencer_PushRandDirective& directive, DirectiveError& error);
Signal getField_directiveHandler(const FpySequencer_GetFieldDirective& directive, DirectiveError& error);
Signal peek_directiveHandler(const FpySequencer_PeekDirective& directive, DirectiveError& error);
Signal storeRel_directiveHandler(const FpySequencer_StoreRelDirective& directive, DirectiveError& error);
Expand Down
47 changes: 47 additions & 0 deletions Svc/FpySequencer/FpySequencerDirectives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,20 @@ void FpySequencer::directive_pushTime_internalInterfaceHandler(const Svc::FpySeq
handleDirectiveErrorCode(Fpy::DirectiveId::PUSH_TIME, error);
}

//! Internal interface handler for directive_setSeed
void FpySequencer::directive_setSeed_internalInterfaceHandler(const Svc::FpySequencer_SetSeedDirective& directive) {
DirectiveError error = DirectiveError::NO_ERROR;
this->sendSignal(this->setSeed_directiveHandler(directive, error));
handleDirectiveErrorCode(Fpy::DirectiveId::SET_SEED, error);
}

//! Internal interface handler for directive_pushRand
void FpySequencer::directive_pushRand_internalInterfaceHandler(const Svc::FpySequencer_PushRandDirective& directive) {
DirectiveError error = DirectiveError::NO_ERROR;
this->sendSignal(this->pushRand_directiveHandler(directive, error));
handleDirectiveErrorCode(Fpy::DirectiveId::PUSH_RAND, error);
}

//! Internal interface handler for directive_getField
void FpySequencer::directive_getField_internalInterfaceHandler(const Svc::FpySequencer_GetFieldDirective& directive) {
DirectiveError error = DirectiveError::NO_ERROR;
Expand Down Expand Up @@ -1283,6 +1297,39 @@ Signal FpySequencer::pushTime_directiveHandler(const FpySequencer_PushTimeDirect
return Signal::stmtResponse_success;
}

Signal FpySequencer::setSeed_directiveHandler(const FpySequencer_SetSeedDirective& directive, DirectiveError& error) {
if (this->m_runtime.stack.size < sizeof(U32)) {
error = DirectiveError::STACK_UNDERFLOW;
return Signal::stmtResponse_failure;
}

U32 seed = this->m_runtime.stack.pop<U32>();
this->m_rng.seed(seed);
this->m_rngSeeded = true;
return Signal::stmtResponse_success;
}

Signal FpySequencer::pushRand_directiveHandler(const FpySequencer_PushRandDirective& directive, DirectiveError& error) {
if (Fpy::MAX_STACK_SIZE - sizeof(U32) < this->m_runtime.stack.size) {
error = DirectiveError::STACK_OVERFLOW;
return Signal::stmtResponse_failure;
}

if (!this->m_rngSeeded) {
Fw::Time currentTime = this->getTime();
std::seed_seq seedSeq{static_cast<U32>(currentTime.getTimeBase()),
static_cast<U32>(currentTime.getContext()),
currentTime.getSeconds(),
currentTime.getUSeconds()};
this->m_rng.seed(seedSeq);
this->m_rngSeeded = true;
}

U32 randVal = static_cast<U32>(this->m_rng());
this->m_runtime.stack.push(randVal);
return Signal::stmtResponse_success;
}

Signal FpySequencer::getField_directiveHandler(const FpySequencer_GetFieldDirective& directive, DirectiveError& error) {
// Need sizeof(StackSizeType) for the offset AND parentSize for the parent data
// Check we have enough for the offset first
Expand Down
14 changes: 14 additions & 0 deletions Svc/FpySequencer/FpySequencerDirectives.fppi
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,16 @@ struct PushTimeDirective {
_empty: U8
}

@ pops a U32 from the stack and uses it to seed the RNG used by PushRandDirective
struct SetSeedDirective {
_empty: U8
}

@ pushes the next RNG value to the stack
struct PushRandDirective {
_empty: U8
}

@ grabs a specified region from a struct, pushes it to the stack, removing
@ the rest of the struct
struct GetFieldDirective {
Expand Down Expand Up @@ -223,6 +233,10 @@ internal port directive_stackCmd(directive: StackCmdDirective) priority 6 assert

internal port directive_pushTime(directive: PushTimeDirective) priority 6 assert

internal port directive_setSeed(directive: SetSeedDirective) priority 6 assert

internal port directive_pushRand(directive: PushRandDirective) priority 6 assert

internal port directive_getField(directive: GetFieldDirective) priority 6 assert

internal port directive_peek(directive: PeekDirective) priority 6 assert
Expand Down
28 changes: 28 additions & 0 deletions Svc/FpySequencer/FpySequencerRunState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,26 @@ Fw::Success FpySequencer::deserializeDirective(const Fpy::Statement& stmt, Direc
}
break;
}
case Fpy::DirectiveId::SET_SEED: {
new (&deserializedDirective.setSeed) FpySequencer_SetSeedDirective();
if (argBuf.getDeserializeSizeLeft() != 0) {
this->log_WARNING_HI_DirectiveDeserializeError(stmt.get_opCode(), this->currentStatementIdx(),
Fw::SerializeStatus::FW_DESERIALIZE_SIZE_MISMATCH,
argBuf.getDeserializeSizeLeft(), argBuf.getSize());
return Fw::Success::FAILURE;
}
break;
}
case Fpy::DirectiveId::PUSH_RAND: {
new (&deserializedDirective.pushRand) FpySequencer_PushRandDirective();
if (argBuf.getDeserializeSizeLeft() != 0) {
this->log_WARNING_HI_DirectiveDeserializeError(stmt.get_opCode(), this->currentStatementIdx(),
Fw::SerializeStatus::FW_DESERIALIZE_SIZE_MISMATCH,
argBuf.getDeserializeSizeLeft(), argBuf.getSize());
return Fw::Success::FAILURE;
}
break;
}
case Fpy::DirectiveId::GET_FIELD: {
new (&deserializedDirective.getField) FpySequencer_GetFieldDirective();
status = argBuf.deserializeTo(deserializedDirective.getField);
Expand Down Expand Up @@ -591,6 +611,14 @@ void FpySequencer::dispatchDirective(const DirectiveUnion& directive, const Fpy:
this->directive_pushTime_internalInterfaceInvoke(directive.pushTime);
return;
}
case Fpy::DirectiveId::SET_SEED: {
this->directive_setSeed_internalInterfaceInvoke(directive.setSeed);
return;
}
case Fpy::DirectiveId::PUSH_RAND: {
this->directive_pushRand_internalInterfaceInvoke(directive.pushRand);
return;
}
case Fpy::DirectiveId::GET_FIELD: {
this->directive_getField_internalInterfaceInvoke(directive.getField);
return;
Expand Down
4 changes: 3 additions & 1 deletion Svc/FpySequencer/FpySequencerTypes.fpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ module Svc {
STORE_ABS = 73
STORE_ABS_CONST_OFFSET = 74
POP_EVENT = 75
SET_SEED = 76
PUSH_RAND = 77
}

enum DirectiveErrorCode : U8 {
Expand Down Expand Up @@ -170,4 +172,4 @@ module Svc {
footer: Footer
}
}
}
}
64 changes: 29 additions & 35 deletions Svc/FpySequencer/docs/directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -866,33 +866,7 @@

**Requirement:** FPY-SEQ-010

## SET_FLAG (67)
Pops a bool off the stack, and sets a command sequencer flag from the value.

| Arg Name | Arg Type | Source | Description |
|----------|----------|--------|-------------|
| flag_idx | U8 | hardcoded | Index of the flag to set |
| value | bool | stack | Value to set the flag to |

| Stack Result Type | Description |
| ------------------|-------------|
| N/A | |

**Requirement:** FPY-SEQ-020

## GET_FLAG (68)
Gets a command sequencer flag and pushes its value to the stack as `FW_SERIALIZE_TRUE_VALUE` or `FW_SERIALIZE_FALSE_VALUE`.
| Arg Name | Arg Type | Source | Description |
|----------|----------|--------|-------------|
| flag_idx | U8 | hardcoded | Index of the flag to get |

| Stack Result Type | Description |
| ------------------|-------------|
| bool | The value of the flag |

**Requirement:** FPY-SEQ-020

## GET_FIELD (69)
## GET_FIELD (67)
Pops an offset (StackSizeType) off the stack. Takes a hard-coded number of bytes from top of stack, and then inside of that a second array of hard-coded number of bytes. The second array is offset by the value previously popped off the stack, with offset 0 meaning the second array starts furthest down the stack. Leaves only the second array of bytes, deleting the surrounding bytes.

| Arg Name | Arg Type | Source | Description |
Expand All @@ -907,7 +881,7 @@

**Requirement:** FPY-SEQ-019

## PEEK (70)
## PEEK (68)
Pops a StackSizeType `offset` off the stack, then a StackSizeType `byteCount`. Let `top` be the top of the stack. Takes the region starting at `top - offset - byteCount` and going to `top - offset`, and pushes this region to the top of the stack.
| Arg Name | Arg Type | Source | Description |
|----------|----------|--------|-------------|
Expand All @@ -920,7 +894,7 @@

**Requirement:** FPY-SEQ-009

## STORE_REL (71)
## STORE_REL (69)
Stores a value to a local variable at a runtime-determined offset relative to the current stack frame.

**Preconditions:**
Expand Down Expand Up @@ -948,7 +922,7 @@

**Requirement:** FPY-SEQ-009

## CALL (72)
## CALL (70)
Performs a function call. Pops the target directive index from the stack, saves the return address and current frame pointer to the stack, then transfers control to the target.

**Preconditions:**
Expand Down Expand Up @@ -984,7 +958,7 @@

**Requirement:** FPY-SEQ-009

## RETURN (73)
## RETURN (71)
Returns from a function call. Restores the caller's execution context and optionally returns a value.

**Preconditions:**
Expand Down Expand Up @@ -1033,7 +1007,7 @@

**Requirement:** FPY-SEQ-009

## LOAD_ABS (74)
## LOAD_ABS (72)
Loads a value from an absolute address in the stack (used for global variables), and pushes it to the stack.

**Preconditions:**
Expand All @@ -1059,7 +1033,7 @@

**Requirement:** FPY-SEQ-009

## STORE_ABS (75)
## STORE_ABS (73)
Stores a value to an absolute address in the stack (used for global variables), with the offset determined at runtime.

**Preconditions:**
Expand All @@ -1084,7 +1058,7 @@

**Requirement:** FPY-SEQ-009

## STORE_ABS_CONST_OFFSET (76)
## STORE_ABS_CONST_OFFSET (74)
Stores a value to an absolute address in the stack (used for global variables), with a compile-time-known offset.

**Preconditions:**
Expand All @@ -1108,7 +1082,7 @@

**Requirement:** FPY-SEQ-009

## POP_EVENT (77)
## POP_EVENT (75)
Pops a message size, message, and severity from the stack and emits an F Prime event.

**Preconditions:**
Expand Down Expand Up @@ -1142,3 +1116,23 @@
| message_size | StackSizeType | stack | Number of bytes to pop for the message. |
| message | bytes | stack | UTF-8 encoded message string. |
| severity | Fw.LogSeverity | stack | The event severity level. |

## SET_SEED (76)
Pops a `U32` seed value from the stack and uses it to seed the sequencer's internal PRNG.

| Arg Name | Arg Type | Source | Description |
|----------|----------|--------|-------------|
| seed | U32 | stack | Seed value used to initialize the PRNG |

| Stack Result Type | Description |
| ------------------|-------------|
| N/A | |


## PUSH_RAND (77)
Pushes the next PRNG value to the stack.
If this is called without the seed being manually set beforehand, then the seed will be set based on the current time.
`PUSH_RAND` uses `std::mt19937` from C++'s random library, a deterministic non-cryptographic PRNG. It is suitable for repeatable pseudo-random values, simulations, randomized sequencing behavior, or tests, but it does not qualify as a [CSPRNG](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator) and is not suitable for cryptographic keys, secrets, authentication tokens, or security-sensitive randomness.

Check failure on line 1135 in Svc/FpySequencer/docs/directives.md

View workflow job for this annotation

GitHub Actions / Check Spelling

`CSPRNG` is not a recognized word (unrecognized-spelling)
| Stack Result Type | Description |
| ------------------|-------------|
| U32 | The next pseudorandom 32-bit value from the sequencer's internal PRNG |
Loading
Loading