Skip to content
Merged
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
50 changes: 13 additions & 37 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,6 @@ pub enum Commands {
/// Show the full path to the virtual filesystem.
Vfs,

/// Send a cheat code into a running game.
Cheat(CheatArgs),

/// Show runtime stats for a running device (or emulator).
Monitor(MonitorArgs),

/// Show live runtime logs from a running device.
Logs(LogsArgs),

/// Control a running device or emulator.
Runtime(RuntimeArgs),

Expand Down Expand Up @@ -271,27 +262,6 @@ pub struct ShotsDownloadArgs {
pub output: Option<PathBuf>,
}

#[derive(Debug, Parser)]
pub struct MonitorArgs {
/// Path to serial port to connect to a running device.
#[arg(long, default_value = None)]
pub port: Option<String>,

#[arg(long, default_value_t = 115_200)]
pub baud_rate: u32,
}

#[derive(Debug, Parser)]
pub struct LogsArgs {
/// Path to serial port to connect to a running device.
#[arg(long)]
pub port: String,

/// The serial port Baud rate.
#[arg(long, default_value_t = 115_200)]
pub baud_rate: u32,
}

#[derive(Debug, Parser)]
pub struct InspectArgs {
/// ID of the ROM to inspect.
Expand Down Expand Up @@ -319,13 +289,6 @@ pub struct CheatArgs {
#[arg()]
pub value: String,

/// Path to serial port to connect to a running device.
#[arg(long, default_value = None)]
pub port: Option<String>,

#[arg(long, default_value_t = 115_200)]
pub baud_rate: u32,

/// Path to the project root.
#[arg(default_value = ".")]
pub root: PathBuf,
Expand All @@ -346,6 +309,19 @@ pub struct RuntimeArgs {

#[derive(Debug, Parser)]
pub enum RuntimeCommands {
/// Send a cheat code.
Cheat(CheatArgs),

/// Show runtime stats.
Monitor,

/// Show live runtime logs.
Logs,

/// Take a screenshot.
#[clap(alias("shot"), alias("snap"), alias("photo"))]
Screenshot,

/// Restart the running app.
#[clap(alias("reload"))]
Restart,
Expand Down
58 changes: 33 additions & 25 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,44 @@ use std::fmt::Display;
use std::path::PathBuf;

pub fn run_command(vfs: PathBuf, command: &Commands) -> anyhow::Result<()> {
use Commands::*;
match command {
Commands::Build(args) => cmd_build(vfs, args),
Commands::Export(args) => cmd_export(&vfs, args),
Commands::Import(args) => cmd_import(&vfs, args),
Commands::New(args) => cmd_new(args),
Commands::Emulator(args) => cmd_emulator(args),
Commands::Badges(args) => cmd_badges(&vfs, args),
Commands::Boards(args) => cmd_boards(&vfs, args),
Commands::Cheat(args) => cmd_cheat(args),
Commands::Monitor(args) => cmd_monitor(&vfs, args),
Commands::Logs(args) => cmd_logs(args),
Commands::Inspect(args) => cmd_inspect(&vfs, args),
Commands::Repl(args) => cmd_repl(&vfs, args),
Commands::Shots(ShotsCommands::Download(args)) => cmd_shots_download(&vfs, args),
Commands::Key(KeyCommands::New(args)) => cmd_key_new(&vfs, args),
Commands::Key(KeyCommands::Add(args)) => cmd_key_add(&vfs, args),
Commands::Key(KeyCommands::Pub(args)) => cmd_key_pub(&vfs, args),
Commands::Key(KeyCommands::Priv(args)) => cmd_key_priv(&vfs, args),
Commands::Key(KeyCommands::Rm(args)) => cmd_key_rm(&vfs, args),
Commands::Catalog(CatalogCommands::List(args)) => cmd_catalog_list(args),
Commands::Catalog(CatalogCommands::Show(args)) => cmd_catalog_show(args),
Commands::Name(NameCommands::Get) => cmd_name_get(&vfs),
Commands::Name(NameCommands::Set(args)) => cmd_name_set(&vfs, args),
Commands::Name(NameCommands::Generate) => cmd_name_generate(&vfs),
Commands::Runtime(root_args) => match &root_args.command {
Build(args) => cmd_build(vfs, args),
Export(args) => cmd_export(&vfs, args),
Import(args) => cmd_import(&vfs, args),
New(args) => cmd_new(args),
Emulator(args) => cmd_emulator(args),
Badges(args) => cmd_badges(&vfs, args),
Boards(args) => cmd_boards(&vfs, args),
Inspect(args) => cmd_inspect(&vfs, args),
Repl(args) => cmd_repl(&vfs, args),
Shots(ShotsCommands::Download(args)) => cmd_shots_download(&vfs, args),
Key(command) => match command {
KeyCommands::New(args) => cmd_key_new(&vfs, args),
KeyCommands::Add(args) => cmd_key_add(&vfs, args),
KeyCommands::Pub(args) => cmd_key_pub(&vfs, args),
KeyCommands::Priv(args) => cmd_key_priv(&vfs, args),
KeyCommands::Rm(args) => cmd_key_rm(&vfs, args),
},
Catalog(command) => match command {
CatalogCommands::List(args) => cmd_catalog_list(args),
CatalogCommands::Show(args) => cmd_catalog_show(args),
},
Name(command) => match command {
NameCommands::Get => cmd_name_get(&vfs),
NameCommands::Set(args) => cmd_name_set(&vfs, args),
NameCommands::Generate => cmd_name_generate(&vfs),
},
Runtime(root_args) => match &root_args.command {
RuntimeCommands::Restart => cmd_restart(root_args),
RuntimeCommands::Exit => cmd_exit(root_args),
RuntimeCommands::Id => cmd_id(root_args),
RuntimeCommands::Screenshot => cmd_screenshot(root_args),
RuntimeCommands::Cheat(args) => cmd_cheat(root_args, args),
RuntimeCommands::Monitor => cmd_monitor(root_args),
RuntimeCommands::Logs => cmd_logs(root_args),
},
Commands::Vfs => cmd_vfs(),
Vfs => cmd_vfs(),
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/commands/cheat.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use crate::args::CheatArgs;
use crate::args::{CheatArgs, RuntimeArgs};
use crate::config::Config;
use crate::net::connect;
use anyhow::{bail, Context, Result};
use firefly_types::serial;
use std::path::Path;

pub fn cmd_cheat(args: &CheatArgs) -> Result<()> {
pub fn cmd_cheat(root_args: &RuntimeArgs, args: &CheatArgs) -> Result<()> {
println!("⏳️ connecting...");
let mut stream = connect(&args.port)?;
let mut stream = connect(root_args)?;
stream.set_timeout(2);

{
Expand Down
7 changes: 3 additions & 4 deletions src/commands/logs.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::args::LogsArgs;
use crate::args::RuntimeArgs;
use crate::net::connect;
use anyhow::{Context, Result};
use crossterm::cursor::MoveToColumn;
Expand All @@ -8,9 +8,8 @@ use crossterm::terminal::{Clear, ClearType};
use firefly_types::serial::Response;
use std::io::{stdout, Write};

pub fn cmd_logs(args: &LogsArgs) -> Result<()> {
let port = Some(args.port.to_string());
let mut stream = connect(&port).context("open the serial port")?;
pub fn cmd_logs(root_args: &RuntimeArgs) -> Result<()> {
let mut stream = connect(root_args).context("open the serial port")?;
stream.set_timeout(3600);
println!("listening...");
let mut prev_time = chrono::Local::now(); // when the previous record was received
Expand Down
2 changes: 1 addition & 1 deletion src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ pub use monitor::cmd_monitor;
pub use name::{cmd_name_generate, cmd_name_get, cmd_name_set};
pub use new::cmd_new;
pub use repl::cmd_repl;
pub use runtime::{cmd_exit, cmd_id, cmd_restart};
pub use runtime::{cmd_exit, cmd_id, cmd_restart, cmd_screenshot};
pub use shots::cmd_shots_download;
pub use vfs::cmd_vfs;
11 changes: 5 additions & 6 deletions src/commands/monitor.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use crate::args::MonitorArgs;
use crate::args::RuntimeArgs;
use crate::net::{connect, is_timeout, Stream};
use anyhow::{Context, Result};
use crossterm::{cursor, event, execute, style, terminal};
use firefly_types::serial;
use std::io;
use std::path::Path;
use std::time::{Duration, Instant};

const COL1: u16 = 8;
Expand Down Expand Up @@ -35,19 +34,19 @@ impl Stats {
}
}

pub fn cmd_monitor(_vfs: &Path, args: &MonitorArgs) -> Result<()> {
pub fn cmd_monitor(root_args: &RuntimeArgs) -> Result<()> {
execute!(io::stdout(), terminal::EnterAlternateScreen).context("enter alt screen")?;
execute!(io::stdout(), cursor::Hide).context("hide cursor")?;
terminal::enable_raw_mode().context("enable raw mode")?;
let res = monitor_inner(args);
let res = monitor_inner(root_args);
terminal::disable_raw_mode().context("disable raw mode")?;
execute!(io::stdout(), cursor::Show).context("show cursor")?;
execute!(io::stdout(), terminal::LeaveAlternateScreen).context("leave alt screen")?;
res
}

fn monitor_inner(args: &MonitorArgs) -> Result<()> {
let mut stream = connect(&args.port)?;
fn monitor_inner(root_args: &RuntimeArgs) -> Result<()> {
let mut stream = connect(root_args)?;
stream.set_timeout(3600);
let mut stats = Stats::default();
request_device_stats(&mut *stream, &mut stats)?;
Expand Down
59 changes: 32 additions & 27 deletions src/commands/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,60 +5,53 @@ use firefly_types::serial;

pub fn cmd_exit(root_args: &RuntimeArgs) -> Result<()> {
println!("⏳️ connecting...");
let mut stream = connect(&root_args.port)?;
let mut stream = connect(root_args)?;
stream.set_timeout(2);

println!("⌛ exiting the running app...");
let req = serial::Request::Exit;
stream.send(&req).context("send request")?;

for _ in 0..5 {
let resp = stream.next()?;
if matches!(resp, serial::Response::Ok) {
println!("✅ exited");
return Ok(());
}
}
bail!("timed out waiting for response")
wait_for_ok(stream)
}

pub fn cmd_restart(root_args: &RuntimeArgs) -> Result<()> {
println!("⏳️ connecting...");
let mut stream = connect(&root_args.port)?;
let mut stream = connect(root_args)?;
stream.set_timeout(2);

let (author_id, app_id) = read_app_id(&mut *stream).context("fetch ID")?;

println!("⌛ restarting {author_id}.{app_id}...");
let req = serial::Request::Launch((author_id, app_id));
stream.send(&req).context("send request")?;

for _ in 0..5 {
let resp = stream.next()?;
if matches!(resp, serial::Response::Ok) {
println!("✅ restarted");
return Ok(());
}
}
bail!("timed out waiting for response")
wait_for_ok(stream)
}

pub fn cmd_id(root_args: &RuntimeArgs) -> Result<()> {
eprintln!("⏳️ connecting...");
let mut stream = connect(&root_args.port)?;
let mut stream = connect(root_args)?;
stream.set_timeout(2);

let (author_id, app_id) = read_app_id(&mut *stream).context("fetch ID")?;
eprintln!("✅ got the ID:");
println!("{author_id}.{app_id}");
Ok(())
}

pub fn read_app_id(stream: &mut dyn Stream) -> Result<(String, String)> {
println!("⌛ fetching running app ID...");
stream
.send(&serial::Request::AppId)
.context("send request")?;
pub fn cmd_screenshot(root_args: &RuntimeArgs) -> Result<()> {
eprintln!("⏳️ connecting...");
let mut stream = connect(root_args)?;
stream.set_timeout(2);

println!("⌛ sending request...");
let req = serial::Request::Screenshot;
stream.send(&req).context("send request")?;
wait_for_ok(stream)
}

fn read_app_id(stream: &mut dyn Stream) -> Result<(String, String)> {
println!("⌛ fetching running app ID...");
let req = serial::Request::AppId;
stream.send(&req).context("send request")?;
for _ in 0..5 {
let resp = stream.next()?;
if let serial::Response::AppID(id) = resp {
Expand All @@ -67,3 +60,15 @@ pub fn read_app_id(stream: &mut dyn Stream) -> Result<(String, String)> {
}
bail!("timed out waiting for response")
}

fn wait_for_ok(stream: Box<dyn Stream>) -> Result<()> {
let mut stream = stream;
for _ in 0..5 {
let resp = stream.next()?;
if matches!(resp, serial::Response::Ok) {
println!("✅ done");
return Ok(());
}
}
bail!("timed out waiting for response")
}
11 changes: 5 additions & 6 deletions src/net.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::args::RuntimeArgs;
use anyhow::{Context, Result};
use firefly_types::serial::{Request, Response};
use firefly_types::Encode;
Expand All @@ -11,18 +12,16 @@ static IP: IpAddr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
const TCP_PORT_MIN: u16 = 3210;
const TCP_PORT_MAX: u16 = 3217;

#[expect(clippy::ref_option)]
pub fn connect(port: &Option<String>) -> Result<Box<dyn Stream>> {
let stream: Box<dyn Stream> = if let Some(port) = port {
Box::new(connect_device(port)?)
pub fn connect(root_args: &RuntimeArgs) -> Result<Box<dyn Stream>> {
let stream: Box<dyn Stream> = if let Some(port) = &root_args.port {
Box::new(connect_device(port, root_args.baud_rate)?)
} else {
Box::new(connect_emulator()?)
};
Ok(stream)
}

fn connect_device(port: &str) -> Result<SerialStream> {
let baud_rate = 115_200;
fn connect_device(port: &str, baud_rate: u32) -> Result<SerialStream> {
let port = serialport::new(port, baud_rate)
.open()
.context("open the serial port")?;
Expand Down