Ian Chamberlain
1 year ago
18 changed files with 450 additions and 211 deletions
@ -0,0 +1,40 @@ |
|||||||
|
name: Setup Rust3DS |
||||||
|
description: Set up CI environment for Rust + 3DS development |
||||||
|
|
||||||
|
inputs: |
||||||
|
toolchain: |
||||||
|
description: The Rust toolchain to use for the steps |
||||||
|
required: true |
||||||
|
default: nightly |
||||||
|
|
||||||
|
runs: |
||||||
|
using: composite |
||||||
|
steps: |
||||||
|
# https://github.com/nektos/act/issues/917#issuecomment-1074421318 |
||||||
|
- if: ${{ env.ACT }} |
||||||
|
shell: bash |
||||||
|
name: Hack container for local development |
||||||
|
run: | |
||||||
|
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - |
||||||
|
sudo apt-get install -y nodejs |
||||||
|
|
||||||
|
- name: Setup default Rust toolchain |
||||||
|
# Use this helper action so we get matcher support |
||||||
|
# https://github.com/actions-rust-lang/setup-rust-toolchain/pull/15 |
||||||
|
uses: actions-rust-lang/setup-rust-toolchain@v1 |
||||||
|
with: |
||||||
|
components: clippy, rustfmt, rust-src |
||||||
|
toolchain: ${{ inputs.toolchain }} |
||||||
|
|
||||||
|
- name: Install build tools for host |
||||||
|
shell: bash |
||||||
|
run: sudo apt-get update && sudo apt-get install -y build-essential |
||||||
|
|
||||||
|
- name: Install cargo-3ds |
||||||
|
shell: bash |
||||||
|
run: cargo install cargo-3ds |
||||||
|
|
||||||
|
- name: Set PATH to include devkitARM |
||||||
|
shell: bash |
||||||
|
# For some reason devkitARM/bin is not part of the default PATH in the container |
||||||
|
run: echo "${DEVKITARM}/bin" >> $GITHUB_PATH |
@ -0,0 +1,67 @@ |
|||||||
|
name: CI |
||||||
|
|
||||||
|
on: |
||||||
|
push: |
||||||
|
branches: |
||||||
|
- master |
||||||
|
pull_request: |
||||||
|
branches: |
||||||
|
- master |
||||||
|
workflow_dispatch: |
||||||
|
|
||||||
|
env: |
||||||
|
# actions-rust-lang/setup-rust-toolchain sets some default RUSTFLAGS, which we don't want to use |
||||||
|
RUSTFLAGS: "" |
||||||
|
|
||||||
|
jobs: |
||||||
|
lint: |
||||||
|
strategy: |
||||||
|
matrix: |
||||||
|
toolchain: |
||||||
|
- nightly-2023-06-01 |
||||||
|
|
||||||
|
runs-on: ubuntu-latest |
||||||
|
container: devkitpro/devkitarm |
||||||
|
steps: |
||||||
|
- name: Checkout branch |
||||||
|
uses: actions/checkout@v2 |
||||||
|
|
||||||
|
- uses: ./.github/actions/setup |
||||||
|
with: |
||||||
|
toolchain: ${{ matrix.toolchain }} |
||||||
|
|
||||||
|
- name: Check formatting |
||||||
|
run: cargo fmt --all --verbose -- --check |
||||||
|
|
||||||
|
- name: Run clippy |
||||||
|
# We have to build the test crate here since it's not included in build-std by default |
||||||
|
run: cargo 3ds clippy -Zbuild-std=std,test --color=always --verbose --all-targets |
||||||
|
|
||||||
|
test: |
||||||
|
strategy: |
||||||
|
matrix: |
||||||
|
toolchain: |
||||||
|
# Oldest supported nightly |
||||||
|
- nightly-2023-06-01 |
||||||
|
- nightly |
||||||
|
|
||||||
|
continue-on-error: ${{ matrix.toolchain == 'nightly' }} |
||||||
|
runs-on: ubuntu-latest |
||||||
|
container: devkitpro/devkitarm |
||||||
|
steps: |
||||||
|
- name: Checkout branch |
||||||
|
uses: actions/checkout@v3 |
||||||
|
|
||||||
|
- uses: ./.github/actions/setup |
||||||
|
with: |
||||||
|
toolchain: ${{ matrix.toolchain }} |
||||||
|
|
||||||
|
- name: Build lib tests |
||||||
|
run: cargo 3ds test --no-run --lib |
||||||
|
|
||||||
|
- name: Build integration tests |
||||||
|
run: cargo 3ds test --no-run --test integration |
||||||
|
|
||||||
|
- name: Build doc tests |
||||||
|
# need build-std=test until https://github.com/rust3ds/cargo-3ds/pull/42 |
||||||
|
run: cargo 3ds test --doc -Zbuild-std=std,test |
@ -0,0 +1,14 @@ |
|||||||
|
# Generated by Cargo |
||||||
|
# will have compiled files and executables |
||||||
|
debug/ |
||||||
|
target/ |
||||||
|
|
||||||
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries |
||||||
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html |
||||||
|
Cargo.lock |
||||||
|
|
||||||
|
# These are backup files generated by rustfmt |
||||||
|
**/*.rs.bk |
||||||
|
|
||||||
|
# MSVC Windows builds of rustc generate these, which store debugging information |
||||||
|
*.pdb |
@ -0,0 +1,15 @@ |
|||||||
|
[package] |
||||||
|
name = "test-runner" |
||||||
|
version = "0.1.0" |
||||||
|
edition = "2021" |
||||||
|
|
||||||
|
[features] |
||||||
|
console = [] |
||||||
|
gdb = [] |
||||||
|
socket = [] |
||||||
|
|
||||||
|
[dependencies] |
||||||
|
ctru-rs = { git = "https://github.com/rust3ds/ctru-rs" } |
||||||
|
ctru-sys = { git = "https://github.com/rust3ds/ctru-rs" } |
||||||
|
libc = "0.2.147" |
||||||
|
shim-3ds = { git = "https://github.com/rust3ds/shim-3ds", version = "0.1.0" } |
@ -1,29 +0,0 @@ |
|||||||
FROM buildpack-deps:latest as builder |
|
||||||
|
|
||||||
# ARG CITRA_RELEASE=nightly-1783 |
|
||||||
# ARG CITRA_RELEASE_FILE=citra-linux-20220902-746609f.tar.xz |
|
||||||
|
|
||||||
ARG CITRA_CHANNEL=nightly |
|
||||||
ARG CITRA_RELEASE=1816 |
|
||||||
|
|
||||||
WORKDIR /tmp |
|
||||||
COPY ./citra/download_citra.sh /usr/local/bin/download_citra |
|
||||||
RUN apt-get update -y && apt-get install -y jq |
|
||||||
RUN download_citra ${CITRA_CHANNEL} ${CITRA_RELEASE} |
|
||||||
|
|
||||||
FROM ubuntu:latest |
|
||||||
|
|
||||||
RUN apt-get update -y && \ |
|
||||||
apt-get install -y \ |
|
||||||
libswscale5 \ |
|
||||||
libsdl2-2.0-0 \ |
|
||||||
libavformat58 \ |
|
||||||
libavfilter7 \ |
|
||||||
xvfb |
|
||||||
|
|
||||||
COPY --from=builder /tmp/citra /usr/local/bin |
|
||||||
COPY ./citra/sdl2-config.ini /root/.config/citra-emu/ |
|
||||||
|
|
||||||
WORKDIR /app |
|
||||||
|
|
||||||
CMD [ "citra", "--version" ] |
|
@ -0,0 +1,16 @@ |
|||||||
|
# https://github.com/devkitPro/libctru/blob/master/libctru/source/system/stack_adjust.s#LL28C23-L28C23 |
||||||
|
# or should this be `_exit` ? |
||||||
|
break __ctru_exit |
||||||
|
commands |
||||||
|
# TODO: needed? |
||||||
|
continue |
||||||
|
# ARM calling convention will put the exit code in r0 when __ctru_exit is called. |
||||||
|
# Just tell GDB to exit with the same code, since it doesn't get passed back when |
||||||
|
# the program exits |
||||||
|
quit $r0 |
||||||
|
end |
||||||
|
|
||||||
|
# TODO: parametrize or pass as command line arg instead |
||||||
|
target extended-remote 192.168.0.167:4003 |
||||||
|
# target extended-remote :4000 |
||||||
|
continue |
@ -0,0 +1,51 @@ |
|||||||
|
use ctru::prelude::*; |
||||||
|
use ctru::services::gfx::{Flush, Swap}; |
||||||
|
|
||||||
|
use super::TestRunner; |
||||||
|
|
||||||
|
pub struct ConsoleRunner { |
||||||
|
gfx: Gfx, |
||||||
|
hid: Hid, |
||||||
|
apt: Apt, |
||||||
|
} |
||||||
|
|
||||||
|
impl Default for ConsoleRunner { |
||||||
|
fn default() -> Self { |
||||||
|
let gfx = Gfx::new().unwrap(); |
||||||
|
let hid = Hid::new().unwrap(); |
||||||
|
let apt = Apt::new().unwrap(); |
||||||
|
|
||||||
|
gfx.top_screen.borrow_mut().set_wide_mode(true); |
||||||
|
|
||||||
|
Self { gfx, hid, apt } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl TestRunner for ConsoleRunner { |
||||||
|
type Context<'this> = Console<'this>; |
||||||
|
|
||||||
|
fn setup(&mut self) -> Self::Context<'_> { |
||||||
|
Console::new(self.gfx.top_screen.borrow_mut()) |
||||||
|
} |
||||||
|
|
||||||
|
fn cleanup(mut self, _test_result: std::io::Result<bool>) { |
||||||
|
// We don't actually care about the test result, either way we'll stop
|
||||||
|
// and show the results to the user
|
||||||
|
|
||||||
|
// Wait to make sure the user can actually see the results before we exit
|
||||||
|
println!("Press START to exit."); |
||||||
|
|
||||||
|
while self.apt.main_loop() { |
||||||
|
let mut screen = self.gfx.top_screen.borrow_mut(); |
||||||
|
screen.flush_buffers(); |
||||||
|
screen.swap_buffers(); |
||||||
|
|
||||||
|
self.gfx.wait_for_vblank(); |
||||||
|
|
||||||
|
self.hid.scan_input(); |
||||||
|
if self.hid.keys_down().contains(KeyPad::START) { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
use ctru::error::ResultCode; |
||||||
|
|
||||||
|
use super::TestRunner; |
||||||
|
|
||||||
|
#[derive(Default)] |
||||||
|
pub struct GdbRunner; |
||||||
|
|
||||||
|
impl Drop for GdbRunner { |
||||||
|
fn drop(&mut self) { |
||||||
|
unsafe { ctru_sys::gdbHioDevExit() } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl TestRunner for GdbRunner { |
||||||
|
type Context<'this> = (); |
||||||
|
|
||||||
|
fn setup(&mut self) -> Self::Context<'_> { |
||||||
|
// TODO: `ctru` expose safe API to do this and call that instead
|
||||||
|
|| -> ctru::Result<()> { |
||||||
|
unsafe { |
||||||
|
ResultCode(ctru_sys::gdbHioDevInit())?; |
||||||
|
// TODO: should we actually redirect stdin or nah?
|
||||||
|
ResultCode(ctru_sys::gdbHioDevRedirectStdStreams(true, true, true))?; |
||||||
|
} |
||||||
|
Ok(()) |
||||||
|
}() |
||||||
|
.expect("failed to redirect I/O streams to GDB"); |
||||||
|
} |
||||||
|
|
||||||
|
fn cleanup(self, test_result: std::io::Result<bool>) { |
||||||
|
// GDB actually has the opportunity to inspect the exit code,
|
||||||
|
// unlike other runners, so let's follow the default behavior of the
|
||||||
|
// stdlib test runner.
|
||||||
|
match test_result { |
||||||
|
Ok(success) => { |
||||||
|
if success { |
||||||
|
std::process::exit(0); |
||||||
|
} else { |
||||||
|
std::process::exit(101); |
||||||
|
} |
||||||
|
} |
||||||
|
Err(err) => { |
||||||
|
eprintln!("Error: {err}"); |
||||||
|
std::process::exit(101); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,158 @@ |
|||||||
|
//! Custom test runner for building/running tests on the 3DS.
|
||||||
|
//!
|
||||||
|
//! This library can be used with
|
||||||
|
//! [`custom_test_frameworks`](https://doc.rust-lang.org/unstable-book/language-features/custom-test-frameworks.html)
|
||||||
|
//! to enable normal Rust testing workflows for 3DS homebrew.
|
||||||
|
|
||||||
|
#![feature(test)] |
||||||
|
#![feature(custom_test_frameworks)] |
||||||
|
#![test_runner(run_gdb)] |
||||||
|
|
||||||
|
extern crate test; |
||||||
|
|
||||||
|
mod console; |
||||||
|
mod gdb; |
||||||
|
mod socket; |
||||||
|
|
||||||
|
use console::ConsoleRunner; |
||||||
|
use gdb::GdbRunner; |
||||||
|
use socket::SocketRunner; |
||||||
|
|
||||||
|
use test::{ColorConfig, OutputFormat, TestDescAndFn, TestFn, TestOpts}; |
||||||
|
|
||||||
|
/// Show test output in GDB, using the [File I/O Protocol] (called HIO in some 3DS
|
||||||
|
/// homebrew resources). Both stdout and stderr will be printed to the GDB console.
|
||||||
|
///
|
||||||
|
/// [File I/O Protocol]: https://sourceware.org/gdb/onlinedocs/gdb/File_002dI_002fO-Overview.html#File_002dI_002fO-Overview
|
||||||
|
pub fn run_gdb(tests: &[&TestDescAndFn]) { |
||||||
|
run::<GdbRunner>(tests) |
||||||
|
} |
||||||
|
|
||||||
|
/// Run tests using the `ctru` [`Console`] (print results to the 3DS screen).
|
||||||
|
/// This is mostly useful for running tests manually, especially on real hardware.
|
||||||
|
///
|
||||||
|
/// [`Console`]: ctru::console::Console
|
||||||
|
pub fn run_console(tests: &[&TestDescAndFn]) { |
||||||
|
run::<ConsoleRunner>(tests) |
||||||
|
} |
||||||
|
|
||||||
|
/// Show test output via a network socket to `3dslink`. This runner is only useful
|
||||||
|
/// on real hardware, since `3dslink` doesn't work with emulators.
|
||||||
|
///
|
||||||
|
/// See [`Soc::redirect_to_3dslink`] for more details.
|
||||||
|
///
|
||||||
|
/// [`Soc::redirect_to_3dslink`]: ctru::services::soc::Soc::redirect_to_3dslink
|
||||||
|
pub fn run_socket(tests: &[&TestDescAndFn]) { |
||||||
|
run::<SocketRunner>(tests) |
||||||
|
} |
||||||
|
|
||||||
|
fn run<Runner: TestRunner>(tests: &[&TestDescAndFn]) { |
||||||
|
std::env::set_var("RUST_BACKTRACE", "1"); |
||||||
|
|
||||||
|
let mut runner = Runner::default(); |
||||||
|
let ctx = runner.setup(); |
||||||
|
|
||||||
|
let opts = TestOpts { |
||||||
|
force_run_in_process: true, |
||||||
|
run_tests: true, |
||||||
|
// TODO: color doesn't work because of TERM/TERMINFO.
|
||||||
|
// With RomFS we might be able to fake this out nicely...
|
||||||
|
color: ColorConfig::AlwaysColor, |
||||||
|
format: OutputFormat::Pretty, |
||||||
|
test_threads: Some(1), |
||||||
|
// Hopefully this interface is more stable vs specifying individual options,
|
||||||
|
// and parsing the empty list of args should always work, I think.
|
||||||
|
// TODO Ideally we could pass actual std::env::args() here too
|
||||||
|
..test::test::parse_opts(&[]).unwrap().unwrap() |
||||||
|
}; |
||||||
|
|
||||||
|
let tests = tests.iter().map(|t| make_owned_test(t)).collect(); |
||||||
|
let result = test::run_tests_console(&opts, tests); |
||||||
|
|
||||||
|
drop(ctx); |
||||||
|
|
||||||
|
runner.cleanup(result); |
||||||
|
} |
||||||
|
|
||||||
|
/// Adapted from [`test::make_owned_test`].
|
||||||
|
/// Clones static values for putting into a dynamic vector, which `test_main()`
|
||||||
|
/// needs to hand out ownership of tests to parallel test runners.
|
||||||
|
///
|
||||||
|
/// This will panic when fed any dynamic tests, because they cannot be cloned.
|
||||||
|
fn make_owned_test(test: &TestDescAndFn) -> TestDescAndFn { |
||||||
|
let testfn = match test.testfn { |
||||||
|
TestFn::StaticTestFn(f) => TestFn::StaticTestFn(f), |
||||||
|
TestFn::StaticBenchFn(f) => TestFn::StaticBenchFn(f), |
||||||
|
_ => panic!("non-static tests passed to test::test_main_static"), |
||||||
|
}; |
||||||
|
|
||||||
|
TestDescAndFn { |
||||||
|
testfn, |
||||||
|
desc: test.desc.clone(), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// A helper trait to make the behavior of test runners consistent.
|
||||||
|
trait TestRunner: Sized + Default { |
||||||
|
/// Any context the test runner needs to remain alive for the duration of
|
||||||
|
/// the test. This can be used for things that need to borrow the test runner
|
||||||
|
/// itself.
|
||||||
|
// TODO: with associated type defaults this could be `= ();`
|
||||||
|
type Context<'this> |
||||||
|
where |
||||||
|
Self: 'this; |
||||||
|
|
||||||
|
/// Create the [`Context`](Self::Context), if any.
|
||||||
|
fn setup(&mut self) -> Self::Context<'_>; |
||||||
|
|
||||||
|
/// Handle the results of the test and perform any necessary cleanup.
|
||||||
|
/// The [`Context`](Self::Context) will be dropped just before this is called.
|
||||||
|
fn cleanup(self, test_result: std::io::Result<bool>); |
||||||
|
} |
||||||
|
|
||||||
|
/// This module has stubs needed to link the test library, but they do nothing
|
||||||
|
/// because we don't actually need them for the runner to work.
|
||||||
|
mod link_fix { |
||||||
|
#[no_mangle] |
||||||
|
extern "C" fn execvp( |
||||||
|
_argc: *const libc::c_char, |
||||||
|
_argv: *mut *const libc::c_char, |
||||||
|
) -> libc::c_int { |
||||||
|
-1 |
||||||
|
} |
||||||
|
|
||||||
|
#[no_mangle] |
||||||
|
extern "C" fn pipe(_fildes: *mut libc::c_int) -> libc::c_int { |
||||||
|
-1 |
||||||
|
} |
||||||
|
|
||||||
|
#[no_mangle] |
||||||
|
extern "C" fn sigemptyset(_arg1: *mut libc::sigset_t) -> ::libc::c_int { |
||||||
|
-1 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// Verify that doctests work as expected
|
||||||
|
/// ```
|
||||||
|
/// assert_eq!(2 + 2, 4);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```should_panic
|
||||||
|
/// assert_eq!(2 + 2, 5);
|
||||||
|
/// ```
|
||||||
|
#[cfg(doctest)] |
||||||
|
struct Dummy; |
||||||
|
|
||||||
|
#[cfg(test)] |
||||||
|
mod tests { |
||||||
|
#[test] |
||||||
|
fn it_works() { |
||||||
|
assert_eq!(2 + 2, 4); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
#[should_panic] |
||||||
|
fn it_fails() { |
||||||
|
assert_eq!(2 + 2, 5); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
use ctru::prelude::*; |
||||||
|
|
||||||
|
use super::TestRunner; |
||||||
|
|
||||||
|
pub struct SocketRunner { |
||||||
|
soc: Soc, |
||||||
|
} |
||||||
|
|
||||||
|
impl Default for SocketRunner { |
||||||
|
fn default() -> Self { |
||||||
|
Self { |
||||||
|
soc: Soc::new().expect("failed to initialize network service"), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl TestRunner for SocketRunner { |
||||||
|
type Context<'this> = (); |
||||||
|
|
||||||
|
fn setup(&mut self) -> Self::Context<'_> { |
||||||
|
self.soc |
||||||
|
.redirect_to_3dslink(true, true) |
||||||
|
.expect("failed to redirect to socket"); |
||||||
|
} |
||||||
|
|
||||||
|
fn cleanup(self, _test_result: std::io::Result<bool>) {} |
||||||
|
} |
@ -1,119 +0,0 @@ |
|||||||
# This file is automatically @generated by Cargo. |
|
||||||
# It is not intended for manual editing. |
|
||||||
version = 3 |
|
||||||
|
|
||||||
[[package]] |
|
||||||
name = "bitflags" |
|
||||||
version = "1.3.2" |
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" |
|
||||||
|
|
||||||
[[package]] |
|
||||||
name = "cfg-if" |
|
||||||
version = "1.0.0" |
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" |
|
||||||
|
|
||||||
[[package]] |
|
||||||
name = "const-zero" |
|
||||||
version = "0.1.0" |
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||||
checksum = "a1d3d68618a1f2c2d86e0bd2adec82e31960ca11aaeb5f353ff01746a4e08f36" |
|
||||||
|
|
||||||
[[package]] |
|
||||||
name = "ctru-rs" |
|
||||||
version = "0.7.1" |
|
||||||
source = "git+https://github.com/Meziu/ctru-rs.git#ac6c81e7819185be46576af3441f5260d39a2320" |
|
||||||
dependencies = [ |
|
||||||
"bitflags", |
|
||||||
"cfg-if", |
|
||||||
"const-zero", |
|
||||||
"ctru-sys", |
|
||||||
"libc", |
|
||||||
"linker-fix-3ds", |
|
||||||
"once_cell", |
|
||||||
"pthread-3ds", |
|
||||||
"toml", |
|
||||||
"widestring", |
|
||||||
] |
|
||||||
|
|
||||||
[[package]] |
|
||||||
name = "ctru-sys" |
|
||||||
version = "0.4.1" |
|
||||||
source = "git+https://github.com/Meziu/ctru-rs.git#ac6c81e7819185be46576af3441f5260d39a2320" |
|
||||||
dependencies = [ |
|
||||||
"libc", |
|
||||||
] |
|
||||||
|
|
||||||
[[package]] |
|
||||||
name = "libc" |
|
||||||
version = "0.2.132" |
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||||
checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" |
|
||||||
|
|
||||||
[[package]] |
|
||||||
name = "linker-fix-3ds" |
|
||||||
version = "0.1.0" |
|
||||||
source = "git+https://github.com/Meziu/rust-linker-fix-3ds.git#d5d3be4a0da876df6d6ac55cc8b48488713e149a" |
|
||||||
dependencies = [ |
|
||||||
"ctru-sys", |
|
||||||
"libc", |
|
||||||
] |
|
||||||
|
|
||||||
[[package]] |
|
||||||
name = "once_cell" |
|
||||||
version = "1.10.0" |
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||||
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" |
|
||||||
|
|
||||||
[[package]] |
|
||||||
name = "pthread-3ds" |
|
||||||
version = "0.1.0" |
|
||||||
source = "git+https://github.com/Meziu/pthread-3ds.git#42a80c0e816251138df535648258671d93e047a6" |
|
||||||
dependencies = [ |
|
||||||
"ctru-sys", |
|
||||||
"libc", |
|
||||||
"spin", |
|
||||||
"static_assertions", |
|
||||||
] |
|
||||||
|
|
||||||
[[package]] |
|
||||||
name = "serde" |
|
||||||
version = "1.0.137" |
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||||
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" |
|
||||||
|
|
||||||
[[package]] |
|
||||||
name = "spin" |
|
||||||
version = "0.9.3" |
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||||
checksum = "c530c2b0d0bf8b69304b39fe2001993e267461948b890cd037d8ad4293fa1a0d" |
|
||||||
|
|
||||||
[[package]] |
|
||||||
name = "static_assertions" |
|
||||||
version = "1.1.0" |
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" |
|
||||||
|
|
||||||
[[package]] |
|
||||||
name = "test-crate" |
|
||||||
version = "0.1.0" |
|
||||||
dependencies = [ |
|
||||||
"ctru-rs", |
|
||||||
"ctru-sys", |
|
||||||
] |
|
||||||
|
|
||||||
[[package]] |
|
||||||
name = "toml" |
|
||||||
version = "0.5.9" |
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||||
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" |
|
||||||
dependencies = [ |
|
||||||
"serde", |
|
||||||
] |
|
||||||
|
|
||||||
[[package]] |
|
||||||
name = "widestring" |
|
||||||
version = "0.2.2" |
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
|
||||||
checksum = "7157704c2e12e3d2189c507b7482c52820a16dfa4465ba91add92f266667cadb" |
|
@ -1,9 +0,0 @@ |
|||||||
[package] |
|
||||||
name = "test-crate" |
|
||||||
version = "0.1.0" |
|
||||||
edition = "2021" |
|
||||||
authors = [""] |
|
||||||
|
|
||||||
[dependencies] |
|
||||||
ctru-rs = { git = "https://github.com/Meziu/ctru-rs.git" } |
|
||||||
ctru-sys = { git = "https://github.com/Meziu/ctru-rs.git" } |
|
@ -1,53 +0,0 @@ |
|||||||
use std::time::Duration; |
|
||||||
|
|
||||||
use ctru::console::Console; |
|
||||||
use ctru::gfx::Gfx; |
|
||||||
use ctru::services::apt::Apt; |
|
||||||
use ctru::services::hid::{Hid, KeyPad}; |
|
||||||
|
|
||||||
fn main() { |
|
||||||
ctru::init(); |
|
||||||
let gfx = Gfx::init().expect("Couldn't obtain GFX controller"); |
|
||||||
let hid = Hid::init().expect("Couldn't obtain HID controller"); |
|
||||||
let apt = Apt::init().expect("Couldn't obtain APT controller"); |
|
||||||
// let _console = Console::init(gfx.top_screen.borrow_mut());
|
|
||||||
|
|
||||||
let _ = unsafe { ctru_sys::consoleDebugInit(ctru_sys::debugDevice_SVC) }; |
|
||||||
|
|
||||||
std::env::set_var("RUST_BACKTRACE", "full"); |
|
||||||
|
|
||||||
let res = unsafe { ctru_sys::gdbHioDevInit() }; |
|
||||||
if res != 0 { |
|
||||||
eprintln!("failed to init gdbHIO: {res}"); |
|
||||||
} else { |
|
||||||
eprintln!("init gdb hio"); |
|
||||||
} |
|
||||||
|
|
||||||
// let res = unsafe { ctru_sys::gdbHioDevRedirectStdStreams(false, true, true) };
|
|
||||||
// if res != 0 {
|
|
||||||
// eprintln!("failed to redirect gdbHIO: {res}");
|
|
||||||
// } else {
|
|
||||||
// eprintln!("redirected gdb hio");
|
|
||||||
// }
|
|
||||||
|
|
||||||
println!("hey stdout"); |
|
||||||
eprintln!("hey stderr"); |
|
||||||
|
|
||||||
// Main loop
|
|
||||||
while apt.main_loop() { |
|
||||||
//Scan all the inputs. This should be done once for each frame
|
|
||||||
hid.scan_input(); |
|
||||||
|
|
||||||
if hid.keys_down().contains(KeyPad::KEY_START) { |
|
||||||
break; |
|
||||||
} |
|
||||||
// Flush and swap framebuffers
|
|
||||||
gfx.flush_buffers(); |
|
||||||
gfx.swap_buffers(); |
|
||||||
|
|
||||||
//Wait for VBlank
|
|
||||||
gfx.wait_for_vblank(); |
|
||||||
} |
|
||||||
|
|
||||||
unsafe { ctru_sys::gdbHioDevExit() }; |
|
||||||
} |
|
Loading…
Reference in new issue