Skip to content
This repository was archived by the owner on Jul 6, 2019. It is now read-only.

Idea for static configuration #207

Open
bgamari opened this issue Oct 22, 2014 · 2 comments
Open

Idea for static configuration #207

bgamari opened this issue Oct 22, 2014 · 2 comments
Labels

Comments

@bgamari
Copy link
Contributor

bgamari commented Oct 22, 2014

An alternative to platformtree

Imagine there existed a trait,

trait CompileTime {
    pub fn to_compile_time(tt: TokenTree) -> Self;
}

and a syntax extension providing an attribute (let's call it
compile_time) which given a type definition derived an appropriate
instance. For example,

#[compile_time]
enum Port { PortA, PortB }

#[compile_time]
struct Pin {
    pub block: Port,
    pub pin_n: uint,
}

#[compile_time]
struct SpiParams {
    pub speed: uint,
    pub phase: Level,
    pub polarity: Level,
    pub clk: Pin
    pub mosi: Pin
    pub miso: Pin
}

#[compile_time]
enum Level {High, Low}

Finally, we'll want a function,

fn to_compile_time<T: CompileTime>(tt: TokenTree) -> T

At this point we have something that could be used for compile-time
specification of configuration. The nice thing about this is that
we've punted all of the details of parsing to a reusable
component (compile_time). In fact, with CTFE this component may
almost disappear entirely. Moreover, we would benefit from any tooling
support the user might have due to the use of standard Rust syntax.

All the device bindings need to worry about
is a typical Rust struct. For instance you might have a syntax
extension which handles peripheral instantiation, e.g.

#[use(SPI0)]
const Spi0 = SpiParams {
      speed: 100000,
      phase: High,
      polarity: Low,
      clk: Pin(PortA, 1),
      mosi: Pin(PortA, 2),
      miso: Pin(PortA, 3),
}

where peripheral bindings would register with use with an interface
like,

pub fn register<Config: CompileTime>(instantiate: |Config| -> Result<TokenTree>);

Dealing with dependencies

One issue brought up by @farcaller is that of dependencies. Currently
Platform Tree deals with this by encoding them in its tree structure.

This obviously won't work in the above proposal.
In the case of simple dependencies
we can encode these as fields as we did with the Pins
above. But what if we have an open universe of potential
dependents?

Say we have an I2C device (say, for instance, an ADC). Its
configuration might look like this,

#[compile_time]
struct I2cAdc {
    addr: I2cAddress,
    resolution: AdcResolution,
    bus: &I2cBus,
}

Here we have encoded the device's dependency on its bus as a
reference. The binding would then be free to call something like
needs(self.bus) to ensure that its bus is initialized before it
attempts to initialize itself.

@farcaller
Copy link
Member

This replaces the parts of PT that do node -> instance conversion alongside with appropriate validations. It doesn't seem to handle the dependencies, right? And you'll still have the suffering of passing down any typed arguments down to task entry points (the #[zinc_task] thing)

@farcaller farcaller added the RFC label Oct 22, 2014
@bgamari
Copy link
Contributor Author

bgamari commented Oct 22, 2014

Correct, this focuses on the parsing side of the problem. I haven't pondered how the resulting configuration might be passed to the user at runtime. I haven't had much experience in this area but at first glance your approach of generating structs and passing them to user tasks seems quite workable. What has been the trouble with this approach in your experience?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants