Skip to content

Commit

Permalink
feat(melpo+config): Initial "platform configuration" support, startin…
Browse files Browse the repository at this point in the history
…g with Melpo (#202)

This PR is the initial work towards implementing #199.

This introduces a `config` crate, which provides tools for platforms to
have compile time defined configuration as a toml file.

This PR only implements these changes for `melpomene`, as adding support
to hardware platforms may require more invasive crate re-orgs.
  • Loading branch information
jamesmunns authored Aug 2, 2023
1 parent 7d5c8cb commit e1cce16
Show file tree
Hide file tree
Showing 24 changed files with 1,074 additions and 229 deletions.
238 changes: 221 additions & 17 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ members = [
"source/forth3",
"source/sermux-proto",
"source/trace-proto",
"source/config",

# tools
"tools/crowtty",
Expand All @@ -20,6 +21,7 @@ members = [
"platforms/allwinner-d1/core",
"platforms/beepy",
"platforms/melpomene",
"platforms/melpomene/melpo-config",
]

exclude = ["platforms/pomelo", "platforms/esp32c3-buddy"]
Expand Down
12 changes: 6 additions & 6 deletions platforms/allwinner-d1/boards/src/bin/mq-pro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
extern crate alloc;

use core::time::Duration;
use kernel::maitake::sync::WaitCell;
use mnemos_beepy::i2c_puppet::{HsvColor, I2cPuppetClient, I2cPuppetServer, I2cPuppetSettings};
use mnemos_d1_core::{
ccu::Ccu,
Expand All @@ -13,7 +14,6 @@ use mnemos_d1_core::{
timer::Timers,
Ram, D1,
};
use kernel::maitake::sync::WaitCell;

const HEAP_SIZE: usize = 384 * 1024 * 1024;

Expand Down Expand Up @@ -76,8 +76,7 @@ fn main() -> ! {
let i2c_puppet_up = d1
.kernel
.initialize(async move {
let settings = I2cPuppetSettings::default()
.with_poll_interval(Duration::from_secs(2));
let settings = I2cPuppetSettings::default().with_poll_interval(Duration::from_secs(2));
d1.kernel.sleep(Duration::from_secs(2)).await;
I2cPuppetServer::register(d1.kernel, settings, i2c_puppet_irq)
.await
Expand Down Expand Up @@ -130,8 +129,8 @@ fn main() -> ! {
}

fn init_i2c_puppet_irq(gpio: &mut d1_pac::GPIO, plic: &mut Plic) -> &'static WaitCell {
use mnemos_d1_core::plic::Priority;
use d1_pac::Interrupt;
use mnemos_d1_core::plic::Priority;

static I2C_PUPPET_IRQ: WaitCell = WaitCell::new();

Expand Down Expand Up @@ -165,14 +164,15 @@ fn init_i2c_puppet_irq(gpio: &mut d1_pac::GPIO, plic: &mut Plic) -> &'static Wai
// configure ISR
unsafe {
plic.register(Interrupt::GPIOB_NS, handle_pb_eint_irq);
plic.activate(Interrupt::GPIOB_NS, Priority::P1).expect("could not activate GPIOB_NS ISR");
plic.activate(Interrupt::GPIOB_NS, Priority::P1)
.expect("could not activate GPIOB_NS ISR");
}

// XXX(eliza): right now, this will *only* handle the i2c_puppet IRQ. this isn't
// going to scale well if we want to be able to handle other IRQs on PB7 pins,
// especially if we want those to be defined in cross-platform code...
fn handle_pb_eint_irq() {
let gpio = { unsafe { & *d1_pac::GPIO::ptr() } };
let gpio = { unsafe { &*d1_pac::GPIO::ptr() } };
gpio.pb_eint_status.modify(|r, w| {
if r.eint7_status().is_pending() {
// wake the i2c_puppet waker.
Expand Down
1 change: 0 additions & 1 deletion platforms/esp32c3-buddy/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 12 additions & 12 deletions platforms/melpomene/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@ homepage = "https://mnemos.dev"
readme = "./README.md"
license = "MIT OR Apache-2.0"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
melpo-config = { path = "./melpo-config" }
serde = { version = "1.0.178", features = ["derive"] }
mnemos-config = { path = "../../source/config", features = ["use-std"] }
mnemos-kernel = { package = "mnemos", path = "../../source/kernel" }

[dependencies]
serde = { version = "1.0.178", features = ["derive"] }
melpo-config = { path = "./melpo-config" }
mnemos-config = { path = "../../source/config" }

[dependencies.tracing]
version = "0.1.35"
Expand Down Expand Up @@ -103,14 +112,5 @@ trace-console = ["console-subscriber", "humantime"]
trace-fmt = ["tracing-subscriber/fmt", "atty"]
# Note, the "trace-modality" feature requires the use of the Auxon modality tool.
# More information: https://auxon.io/products/modality
trace-modality = [
"tracing-modality",
# Note, works around a missing feature set in tracing-modality, can
# be changed later
"tokio/net",
"tokio/sync",
]
default = [
"trace-console",
"trace-fmt",
]
trace-modality = ["tracing-modality", "tokio/net", "tokio/sync"]
default = ["trace-console", "trace-fmt"]
3 changes: 3 additions & 0 deletions platforms/melpomene/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
mnemos_config::buildtime::render_project::<melpo_config::PlatformConfig>("melpo.toml").unwrap();
}
10 changes: 10 additions & 0 deletions platforms/melpomene/melpo-config/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "melpo-config"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { version = "1.0.178", features = ["derive"] }
mnemos-kernel = { package = "mnemos", path = "../../../source/kernel"}
130 changes: 130 additions & 0 deletions platforms/melpomene/melpo-config/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
//! Configuration types for Melpomene
//!
//! Separate crate so it can be used from the build.rs script
use std::{net::SocketAddr, time::Duration};

use mnemos_kernel::forth::Params;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct PlatformConfig {
/// TCP simulated uart driver settings
///
/// If this field is None, then the tcp uart service will not
/// be spawned.
pub tcp_uart: TcpUartConfig,

/// Embedded Graphics Simulator display settings
///
/// If this field is None, then the display service will not
/// be spawned.
pub display: DisplayConfig,

/// Forth GUI shell settings
///
/// If this field is None, then the shell service will not
/// be spawned.
pub forth_shell: ForthShell,

/// The maximum amount of time to sleep before repolling the
/// executor (even if no simulated IRQs are received)
pub sleep_cap: Option<Duration>,
}

impl PlatformConfig {
pub const fn default_sleep_cap() -> Duration {
Duration::from_millis(100)
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct TcpUartConfig {
/// Should the TCP UART be enabled?
#[serde(default)]
pub enabled: bool,
/// The maximum kchannel depth for processing messages
#[serde(default = "TcpUartConfig::default_kchannel_depth")]
pub kchannel_depth: usize,
/// Incoming TCP buffer size in bytes
#[serde(default = "TcpUartConfig::default_incoming_size")]
pub incoming_size: usize,
/// Outgoing TCP buffer size in bytes
#[serde(default = "TcpUartConfig::default_outgoing_size")]
pub outgoing_size: usize,
/// Socket addr opened as a simulated serial port
///
/// For example: "127.0.0.1:9999"
#[serde(default = "TcpUartConfig::default_socket_addr")]
pub socket_addr: SocketAddr,
}

impl TcpUartConfig {
pub const DEFAULT_KCHANNEL_DEPTH: usize = 2;
pub const DEFAULT_INCOMING_SIZE: usize = 4096;
pub const DEFAULT_OUTGOING_SIZE: usize = 4096;
pub const DEFAULT_SOCKET_ADDR_STR: &str = "127.0.0.1:9999";

const fn default_kchannel_depth() -> usize {
Self::DEFAULT_KCHANNEL_DEPTH
}
const fn default_incoming_size() -> usize {
Self::DEFAULT_INCOMING_SIZE
}
const fn default_outgoing_size() -> usize {
Self::DEFAULT_OUTGOING_SIZE
}
fn default_socket_addr() -> SocketAddr {
Self::DEFAULT_SOCKET_ADDR_STR.parse().unwrap()
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct DisplayConfig {
/// Should the display be enabled
#[serde(default)]
pub enabled: bool,
/// The maximum kchannel depth for processing messages
#[serde(default = "DisplayConfig::default_kchannel_depth")]
pub kchannel_depth: usize,
/// The maximum number of frames per second. Must be >= 1
#[serde(default = "DisplayConfig::default_frames_per_second")]
pub frames_per_second: usize,
}

impl DisplayConfig {
pub const DEFAULT_KCHANNEL_DEPTH: usize = 2;
pub const DEFAULT_FRAMES_PER_SECOND: usize = 20;

const fn default_kchannel_depth() -> usize {
Self::DEFAULT_KCHANNEL_DEPTH
}
const fn default_frames_per_second() -> usize {
Self::DEFAULT_FRAMES_PER_SECOND
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ForthShell {
/// Should the forth shell be enabled
#[serde(default)]
pub enabled: bool,
/// IO buffer capacity in bytes
#[serde(default = "ForthShell::default_capacity")]
pub capacity: usize,
/// Forth shell parameters
#[serde(default = "ForthShell::default_params")]
pub params: Params,
}

impl ForthShell {
pub const DEFAULT_CAPACITY: usize = 1024;
pub const DEFAULT_PARAMS: Params = Params::new();

const fn default_capacity() -> usize {
Self::DEFAULT_CAPACITY
}
const fn default_params() -> Params {
Self::DEFAULT_PARAMS
}
}
66 changes: 66 additions & 0 deletions platforms/melpomene/melpo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Melpomene configuration
#
# Required fields are defined below. Commented out items are the default
# values, uncomment to override the defaults.

[kernel]
max_drivers = 16
timer_granularity = { secs = 0, nanos = 1000 } # 1us

[services.keyboard_mux]
enabled = true
# max_keyboards = 8
# buffer_capacity = 32
sermux_port_enabled = true
# sermux_port = 2

[services.serial_mux]
enabled = true
# max_ports = 16
# max_frame = 512

[services.spawnulator]
enabled = true
# capacity = 16

[services.sermux_loopback]
enabled = true
# port = 0
# buffer_size = 128

[services.sermux_hello]
enabled = true
# port = 1
# buffer_size = 32
# message = "hello\r\n"
# interval = { secs = 1, nanos = 0 }

[platform]
# sleep_cap = { secs = 0, nanos = 100_000_000 } # 100ms

[platform.display]
enabled = true
# kchannel_depth = 2
# frames_per_second = 20

[platform.tcp_uart]
enabled = true
# socket_addr = "127.0.0.1:9999"
# incoming_size = 4096
# outgoing_size = 4096
# kchannel_depth = 2

[platform.forth_shell]
enabled = true
# capacity = 1024

# [platform.forth_shell.params]
# stack_size = 256
# input_buf_size = 256
# output_buf_size = 256
# dictionary_size = 4096
# stdin_capacity = 1024
# stdout_capacity = 1024
# bag_of_holding_capacity = 16
# spawnulator_timeout = { secs = 5, nanos = 0 }

13 changes: 1 addition & 12 deletions platforms/melpomene/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,9 @@
use crate::{sim_drivers::tcp_serial, sim_tracing};
use crate::sim_tracing;
use clap::Parser;
use std::net::SocketAddr;

#[derive(Parser, Debug)]
#[clap(author, version, about)]
pub struct Args {
#[clap(flatten)]
pub melpomene: MelpomeneOptions,

#[clap(flatten)]
pub tracing: sim_tracing::TracingOpts,
}

#[derive(Debug, clap::Args)]
pub struct MelpomeneOptions {
/// Address to bind the TCP listener for the simulated serial port.
#[clap(long, default_value_t = tcp_serial::default_addr())]
pub serial_addr: SocketAddr,
}
Loading

0 comments on commit e1cce16

Please sign in to comment.