Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support configuring components at compile time #600

Open
celskeggs opened this issue Feb 6, 2025 · 2 comments
Open

Support configuring components at compile time #600

celskeggs opened this issue Feb 6, 2025 · 2 comments
Labels
proposed feature A proposed new feature

Comments

@celskeggs
Copy link

We should support tracking compile-time component configuration in FPP. For example, we should be able to define a watchdog component with a "expiration delay" setting, and then being able to configure that setting when instantiating the component in a topology.

We can currently use tricks like phase Fpp.ToCpp.Phases.configComponents, but they are verbose and are not type checked.

@bocchino suggested this syntax for defining the component (comments mine):

# To define the component
active component Watchdog(expirationDelayMs: U32)
# To instantiate the component
instance watchdog: Watchdog(5000)

I like the suggested syntax, but there are two things I want to consider:

  1. Since there are some components that may have LOTS of compile-time configuration settings, I think it might be better to have the configured arguments named at the point of use.
  2. Sometimes there are components that need configuration settings that are related to specific connected components, and this syntax doesn't allow for locality.

Consider the following more versatile syntax, for the sake of argument:

# To define the component
active component Dispatcher {
    input setting cycle_duration_ms: U32

    output port start_execution: [MAX_CLIENTS] Svc.Sched
    input setting execution_time_ms: [MAX_CLIENTS] U32
}
# When wiring up the component in the topology
dispatcher.cycle_duration_ms = 1000

dispatcher.execution_time_ms[0] = 100
dispatcher.start_execution[0] -> activity1.start

dispatcher.execution_time_ms[1] = 400
dispatcher.start_execution[1] -> activity1.stop

dispatcher.execution_time_ms[2] = 300
dispatcher.start_execution[2] -> activity2.start

dispatcher.execution_time_ms[3] = 700
dispatcher.start_execution[3] -> activity2.stop

This example would be for a system that needs to run "activity1" from the 100th millisecond to the 400th millisecond of each second, and that needs to run "activity2" from the 300th millisecond to the 700th millisecond of each second.

@bocchino bocchino added the proposed feature A proposed new feature label Feb 6, 2025
@bocchino
Copy link
Collaborator

bocchino commented Feb 6, 2025

I agree that names are helpful at the point of instantiation, especially when there are many configuration parameters. One way to get the naming is to use an FPP struct type and value, e.g.,

struct FooConfig {
  config1: U32
  config2: F32
  ...
}

active component Foo(config: FooConfig) { ... }

instance foo: Foo({
  config1 = 10
  config2 = 3.0
  ...
}) ...

@bocchino
Copy link
Collaborator

bocchino commented Feb 7, 2025

You can also use a constant to reuse the same configuration for multiple instances:

constant fooConfig = {
  config1 = 10
  config2 = 3.0
  ...
}

instance foo1: Foo(fooConfig)
instance foo2: Foo(fooConfig)

And you can provide a default configuration:

struct FooConfig {
  config1: U32
  config2: F32
  ...
} default {
  config1 = 10
  config2 = 3.0
  ...
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposed feature A proposed new feature
Projects
Development

No branches or pull requests

2 participants