From 4c3a37dee7f1787d67a5f8349c7e354f569c366d Mon Sep 17 00:00:00 2001 From: ZennDev1337 Date: Mon, 9 Oct 2023 08:25:48 +0200 Subject: [PATCH] commit save to work --- Examples/ArduboyFX/fxdrawballs/src/lib.rs | 500 +++++++++++++++++- .../ArduboyFX/fxloadgamestate/fxdata/fxdata.h | 2 +- Examples/ArduboyFX/fxloadgamestate/src/lib.rs | 41 +- .../src/library/arduboy/arduboy_export.h | 8 + .../src/library/arduboy/arduboyfx_export.h | 8 + arduboy-rust/src/library/arduboy2.rs | 42 +- arduboy-rust/src/library/arduboyfx/fx.rs | 17 + arduboy-rust/src/prelude.rs | 1 - 8 files changed, 607 insertions(+), 12 deletions(-) diff --git a/Examples/ArduboyFX/fxdrawballs/src/lib.rs b/Examples/ArduboyFX/fxdrawballs/src/lib.rs index 2ee7bdf..1fa5896 100644 --- a/Examples/ArduboyFX/fxdrawballs/src/lib.rs +++ b/Examples/ArduboyFX/fxdrawballs/src/lib.rs @@ -4,17 +4,511 @@ //Initialize the arduboy object use arduboy_rust::prelude::*; const arduboy: Arduboy2 = Arduboy2::new(); + +// FX Data +const FX_DATA_PAGE: u16 = 0xfffe; +const FX_DATA_BYTES: u32 = 392; +const FX_DATA_TILES: u32 = 0x000000; +const FX_DATA_TILES_WIDTH: u16 = 16; +const FX_DATA_TILESHEIGHT: u16 = 16; +const FX_DATA_TILES_FRAMES: u8 = 2; +const FX_DATA_TILEMAP: u32 = 0x000044; +const FX_DATA_BALLS: u32 = 0x000144; +const FX_DATA_BALLS_WIDTH: u16 = 16; +const FX_DATA_BALLSHEIGHT: u16 = 16; + +const FRAME_RATE: u8 = 60; +const MAX_BALLS: u8 = 55; +const CIRCLE_POINTS: u8 = 84; +const VISABLE_TILES_PER_COLUMN: u8 = 5; +const VISABLE_TILES_PER_ROW: u8 = 9; + +const ballWidth: u8 = 16; +const ballHeight: u8 = 16; +const tilemapWidth: u8 = 16; +const tileWidth: u8 = 16; +const tileHeight: u8 = 16; + +static mut circle_points: [Point; CIRCLE_POINTS as usize] = [ + Point { x: -15, y: 0 }, + Point { x: -15, y: 1 }, + Point { x: -15, y: 2 }, + Point { x: -15, y: 3 }, + Point { x: -15, y: 4 }, + Point { x: -14, y: 5 }, + Point { x: -14, y: 6 }, + Point { x: -13, y: 7 }, + Point { x: -13, y: 8 }, + Point { x: -12, y: 9 }, + Point { x: -11, y: 10 }, + Point { x: -10, y: 11 }, + Point { x: -9, y: 12 }, + Point { x: -8, y: 13 }, + Point { x: -7, y: 13 }, + Point { x: -6, y: 14 }, + Point { x: -5, y: 14 }, + Point { x: -4, y: 14 }, + Point { x: -3, y: 15 }, + Point { x: -2, y: 15 }, + Point { x: -1, y: 15 }, + Point { x: 0, y: 15 }, + Point { x: 1, y: 15 }, + Point { x: 2, y: 15 }, + Point { x: 3, y: 15 }, + Point { x: 4, y: 14 }, + Point { x: 5, y: 14 }, + Point { x: 6, y: 14 }, + Point { x: 7, y: 13 }, + Point { x: 8, y: 13 }, + Point { x: 9, y: 12 }, + Point { x: 10, y: 11 }, + Point { x: 11, y: 10 }, + Point { x: 12, y: 9 }, + Point { x: 12, y: 8 }, + Point { x: 13, y: 7 }, + Point { x: 13, y: 6 }, + Point { x: 14, y: 5 }, + Point { x: 14, y: 4 }, + Point { x: 14, y: 3 }, + Point { x: 14, y: 2 }, + Point { x: 14, y: 1 }, + Point { x: 15, y: 0 }, + Point { x: 15, y: -1 }, + Point { x: 15, y: -2 }, + Point { x: 15, y: -3 }, + Point { x: 15, y: -4 }, + Point { x: 14, y: -5 }, + Point { x: 14, y: -6 }, + Point { x: 13, y: -7 }, + Point { x: 13, y: -8 }, + Point { x: 12, y: -9 }, + Point { x: 11, y: -10 }, + Point { x: 10, y: -11 }, + Point { x: 9, y: -12 }, + Point { x: 8, y: -13 }, + Point { x: 7, y: -13 }, + Point { x: 6, y: -14 }, + Point { x: 5, y: -14 }, + Point { x: 4, y: -14 }, + Point { x: 3, y: -15 }, + Point { x: 2, y: -15 }, + Point { x: 1, y: -15 }, + Point { x: 0, y: -15 }, + Point { x: -1, y: -15 }, + Point { x: -2, y: -15 }, + Point { x: -3, y: -15 }, + Point { x: -4, y: -14 }, + Point { x: -5, y: -14 }, + Point { x: -6, y: -14 }, + Point { x: -7, y: -13 }, + Point { x: -8, y: -13 }, + Point { x: -9, y: -12 }, + Point { x: -10, y: -11 }, + Point { x: -11, y: -10 }, + Point { x: -12, y: -9 }, + Point { x: -12, y: -8 }, + Point { x: -13, y: -7 }, + Point { x: -13, y: -6 }, + Point { x: -14, y: -5 }, + Point { x: -14, y: -4 }, + Point { x: -14, y: -3 }, + Point { x: -14, y: -2 }, + Point { x: -14, y: -1 }, +]; + +static mut camera: Point = Point { x: 0, y: 0 }; +static mut map_location: Point = Point { x: 16, y: 16 }; +struct Ball { + x: i8, + y: i8, + xspeed: i8, + yspeed: i8, +} + +static mut ball: [Ball; MAX_BALLS as usize] = [ + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, + Ball { + x: 0, + y: 0, + xspeed: 0, + yspeed: 0, + }, +]; +static mut balls_visible: u8 = MAX_BALLS; +static mut pos: u8 = 0; + +static mut tilemap_buffer: [u8; VISABLE_TILES_PER_ROW as usize] = [0, 0, 0, 0, 0, 0, 0, 0, 0]; //The setup() function runs once when you turn your Arduboy on #[no_mangle] pub unsafe extern "C" fn setup() { // put your setup code here, to run once: arduboy.begin(); - arduboy.clear(); - arduboy.print(f!(b"Holmes is cool!\0")); - arduboy.display(); + arduboy.set_frame_rate(FRAME_RATE); + fx::begin_data(FX_DATA_PAGE); + ball.iter_mut().for_each(|b| { + b.x = random_less_than(113) as i8; + b.y = random_less_than(49) as i8; + b.xspeed = 1; + if random_less_than(100) > 49 { + b.xspeed = -b.xspeed + } + b.yspeed = 1; + if random_less_than(100) > 49 { + b.yspeed = -b.yspeed + } + }) } #[no_mangle] #[export_name = "loop"] pub unsafe extern "C" fn loop_() { // put your main code here, to run repeatedly: + if !arduboy.next_frame() { + return; + } + arduboy.poll_buttons(); + if arduboy.just_pressed(A) && balls_visible < MAX_BALLS { + balls_visible += 1; + } + if arduboy.just_pressed(B) && balls_visible > 0 { + balls_visible -= 1; + } + + if arduboy.pressed(UP) && map_location.y > 16 { + map_location.y -= 1; + } + if arduboy.pressed(DOWN) && map_location.y < 176 { + map_location.y += 1; + } + if arduboy.pressed(LEFT) && map_location.x > 16 { + map_location.x -= 1; + } + if arduboy.pressed(RIGHT) && map_location.x > 112 { + map_location.x += 1; + } + + camera.x = map_location.x + circle_points[pos as usize].x; + camera.y = map_location.y + circle_points[pos as usize].y; } diff --git a/Examples/ArduboyFX/fxloadgamestate/fxdata/fxdata.h b/Examples/ArduboyFX/fxloadgamestate/fxdata/fxdata.h index e19de84..bfe8d84 100644 --- a/Examples/ArduboyFX/fxloadgamestate/fxdata/fxdata.h +++ b/Examples/ArduboyFX/fxloadgamestate/fxdata/fxdata.h @@ -1,6 +1,6 @@ #pragma once -/**** FX data header generated by fxdata-build.py tool version 1.13 ****/ +/**** FX data header generated by fxdata-build.py tool version 1.15 ****/ using uint24_t = __uint24; diff --git a/Examples/ArduboyFX/fxloadgamestate/src/lib.rs b/Examples/ArduboyFX/fxloadgamestate/src/lib.rs index 2ee7bdf..1ced646 100644 --- a/Examples/ArduboyFX/fxloadgamestate/src/lib.rs +++ b/Examples/ArduboyFX/fxloadgamestate/src/lib.rs @@ -1,20 +1,57 @@ #![no_std] #![allow(non_upper_case_globals)] + //Include the Arduboy Library //Initialize the arduboy object use arduboy_rust::prelude::*; + const arduboy: Arduboy2 = Arduboy2::new(); //The setup() function runs once when you turn your Arduboy on +const FX_DATA_PAGE: u16 = 0xfff0; +const FX_DATA_BYTES: u32 = 0; +const FX_SAVE_PAGE: u16 = 0xfff0; +const FX_SAVE_BYTES: u32 = 2; + +struct GameState { + name: &'static str, + count: u16, +} + +static mut gamestate: GameState = GameState { + name: "\0", + count: 0, +}; + #[no_mangle] pub unsafe extern "C" fn setup() { // put your setup code here, to run once: arduboy.begin(); + fx::begin_data_save(FX_DATA_PAGE, FX_SAVE_PAGE); + if fx::load_game_state(&mut gamestate) > 1 { + gamestate.name = "Hello World !!!\0"; + gamestate.count = 1; + } else { + gamestate.name = "Save state Loaded\0"; + gamestate.count += 1; + } + fx::save_game_state(&gamestate); arduboy.clear(); - arduboy.print(f!(b"Holmes is cool!\0")); - arduboy.display(); + arduboy.set_cursor(0, 32 - 8); + arduboy.print(gamestate.name); + arduboy.set_cursor(0, 32 + 8); + arduboy.print("Number of times this\nscetch is run: \0"); + arduboy.print(gamestate.count); + fx::display(); } + #[no_mangle] #[export_name = "loop"] pub unsafe extern "C" fn loop_() { // put your main code here, to run repeatedly: + if !arduboy.next_frame() { + return; + } + if arduboy.buttons_state() > 0 { + arduboy.exit_to_bootloader() + } } diff --git a/arduboy-rust/Wrapper-Project/src/library/arduboy/arduboy_export.h b/arduboy-rust/Wrapper-Project/src/library/arduboy/arduboy_export.h index 4d6598c..9852d4a 100644 --- a/arduboy-rust/Wrapper-Project/src/library/arduboy/arduboy_export.h +++ b/arduboy-rust/Wrapper-Project/src/library/arduboy/arduboy_export.h @@ -200,4 +200,12 @@ extern "C" { arduboy.setRGBled(red, green, blue); } + uint8_t arduboy_buttons_state() + { + return arduboy.buttonsState(); + } + void arduboy_exit_to_bootloader() + { + arduboy.exitToBootloader(); + } } \ No newline at end of file diff --git a/arduboy-rust/Wrapper-Project/src/library/arduboy/arduboyfx_export.h b/arduboy-rust/Wrapper-Project/src/library/arduboy/arduboyfx_export.h index b50030c..5c07d29 100644 --- a/arduboy-rust/Wrapper-Project/src/library/arduboy/arduboyfx_export.h +++ b/arduboy-rust/Wrapper-Project/src/library/arduboy/arduboyfx_export.h @@ -94,4 +94,12 @@ extern "C" { FX::drawChar(c); } + uint8_t arduboyfx_load_game_state(uint8_t *gameState,size_t size) + { + return FX::loadGameState(gameState, size); + } + void arduboyfx_save_game_state(uint8_t *gameState,size_t size) + { + FX::saveGameState(gameState, size); + } } \ No newline at end of file diff --git a/arduboy-rust/src/library/arduboy2.rs b/arduboy-rust/src/library/arduboy2.rs index 6b9c99a..b4fcfeb 100644 --- a/arduboy-rust/src/library/arduboy2.rs +++ b/arduboy-rust/src/library/arduboy2.rs @@ -2,11 +2,13 @@ //! //! All of the functions are safe wrapped inside the [Arduboy2] struct. #![allow(dead_code)] + use crate::hardware::buttons::ButtonSet; use crate::print::Printable; use core::ffi::{c_char, c_int, c_long, c_size_t, c_uchar, c_uint, c_ulong}; use core::mem; use core::ops::Not; + /// The standard font size of the arduboy /// /// this is to calculate with it. @@ -29,6 +31,7 @@ pub enum Color { /// Led is on White, } + impl Not for Color { type Output = Self; @@ -39,6 +42,7 @@ impl Not for Color { } } } + /// This struct is used by a few Arduboy functions. #[derive(Debug, Clone, Copy)] pub struct Rect { @@ -51,6 +55,7 @@ pub struct Rect { /// Rect height pub height: u8, } + /// This struct is used by a few Arduboy functions. #[derive(Debug, Clone, Copy)] pub struct Point { @@ -62,6 +67,7 @@ pub struct Point { /// This is the struct to interact in a save way with the Arduboy2 C++ library. pub struct Arduboy2 {} + impl Arduboy2 { /// gives you a new instance of the [Arduboy2] /// ## Example @@ -348,7 +354,7 @@ impl Arduboy2 { /// ``` /// #![allow(non_upper_case_globals)] /// use arduboy_rust::prelude::*; - /// const arduboy:Arduboy2 =Arduboy2::new(); + /// const arduboy: Arduboy2 = Arduboy2::new(); /// let value: i16 = 42; /// /// arduboy.print(b"Hello World\n\0"[..]); // Prints "Hello World" and then sets the @@ -511,10 +517,10 @@ impl Arduboy2 { ///Parameters ///- color The name of the LED to set. The value given should be one of RED_LED, GREEN_LED or BLUE_LED. ///- val The brightness value for the LED, from 0 to 255. - /// + /// ///**Note** ///> In order to use this function, the 3 parameter version must first be called at least once, in order to initialize the hardware. - /// + /// ///This 2 parameter version of the function will set the brightness of a single LED within the RGB LED without affecting the current brightness of the other two. See the description of the 3 parameter version of this function for more details on the RGB LED. pub fn set_rgb_led_single(&self, color: u8, val: u8) { unsafe { set_rgb_led_single(color, val) } @@ -550,7 +556,7 @@ impl Arduboy2 { ///``` /// #![allow(non_upper_case_globals)] /// use arduboy_rust::prelude::*; - /// const arduboy:Arduboy2 =Arduboy2::new(); + /// const arduboy: Arduboy2 = Arduboy2::new(); /// /// if arduboy.everyXFrames(5) { /// if arduboy.pressed(A_BUTTON) { @@ -636,10 +642,30 @@ impl Arduboy2 { pub fn idle(&self) { unsafe { idle() } } + ///Get the current state of all buttons as a bitmask. + /// + ///### Returns + ///A bitmask of the state of all the buttons. + /// + ///The returned mask contains a bit for each button. For any pressed button, its bit will be 1. For released buttons their associated bits will be 0. + /// + ///The following defined mask values should be used for the buttons: + /// LEFT_BUTTON, RIGHT_BUTTON, UP_BUTTON, DOWN_BUTTON, A_BUTTON, B_BUTTON + pub fn buttons_state(&self) -> u8 { + unsafe { arduboy_buttons_state() } + } + ///Exit the sketch and start the bootloader. + /// + ///The sketch will exit and the bootloader will be started in command mode. The effect will be similar to pressing the reset button. + /// + ///This function is intended to be used to allow uploading a new sketch, when the USB code has been removed to gain more code space. Ideally, the sketch would present a "New Sketch Upload" menu or prompt telling the user to "Press and hold the DOWN button when the procedure to upload a new sketch has been initiated". + ///The sketch would then wait for the DOWN button to be pressed and then call this function. + pub fn exit_to_bootloader(&self) { + unsafe { arduboy_exit_to_bootloader() } + } } extern "C" { - #[link_name = "arduboy_begin"] fn begin(); @@ -797,4 +823,10 @@ extern "C" { #[link_name = "arduboy_set_rgb_led"] fn set_rgb_led(red: c_uchar, green: c_uchar, blue: c_uchar); + + #[link_name = "arduboy_buttons_state"] + fn arduboy_buttons_state() -> u8; + + #[link_name = "arduboy_exit_to_bootloader"] + fn arduboy_exit_to_bootloader(); } diff --git a/arduboy-rust/src/library/arduboyfx/fx.rs b/arduboy-rust/src/library/arduboyfx/fx.rs index e6db51c..bd938e6 100644 --- a/arduboy-rust/src/library/arduboyfx/fx.rs +++ b/arduboy-rust/src/library/arduboyfx/fx.rs @@ -74,7 +74,20 @@ pub fn set_font(address: u32, mode: u8) { pub fn set_font_mode(mode: u8) { unsafe { arduboyfx_set_font_mode(mode) }; } +pub fn load_game_state(your_struct: &mut T) -> u8 { + let pointer = your_struct as *mut T; + let object_pointer = pointer as *mut u8; + let object_size = core::mem::size_of::(); + unsafe { arduboyfx_load_game_state(object_pointer, object_size) } +} +pub fn save_game_state(your_struct: &T) { + let pointer = your_struct as *const T; + let object_pointer = pointer as *const u8; + let object_size = core::mem::size_of::(); + + unsafe { arduboyfx_save_game_state(object_pointer, object_size) } +} extern "C" { #[link_name = "arduboyfx_begin"] fn arduboyfx_begin(); @@ -115,5 +128,9 @@ extern "C" { fn arduboyfx_set_cursor_range(left: c_int, wrap: c_int); #[link_name = "arduboyfx_draw_char"] fn arduboyfx_draw_char(c: c_uchar); + #[link_name = "arduboyfx_load_game_state"] + fn arduboyfx_load_game_state(object: *mut u8, size: usize) -> u8; + #[link_name = "arduboyfx_save_game_state"] + fn arduboyfx_save_game_state(object: *const u8, size: usize); } diff --git a/arduboy-rust/src/prelude.rs b/arduboy-rust/src/prelude.rs index 53f58f3..3228782 100644 --- a/arduboy-rust/src/prelude.rs +++ b/arduboy-rust/src/prelude.rs @@ -11,7 +11,6 @@ pub use crate::hardware::led::{self, *}; pub use crate::heapless::{LinearMap, String, Vec}; pub use crate::library::arduboy2::{self, *}; pub use crate::library::arduboy_tones::{self, ArduboyTones}; -#[doc(hidden)] pub use crate::library::arduboyfx::{self, fx}; pub use crate::library::arduino::*; pub use crate::library::ardvoice::{self, ArdVoice};