├── .gitignore ├── .vscode └── settings.json ├── rust-toolchain.toml ├── bm13xx-protocol ├── src │ ├── lib.rs │ ├── error.rs │ ├── fmt.rs │ ├── crc.rs │ └── response.rs ├── Cargo.toml └── examples │ ├── chain_enum.rs │ ├── reg_probe.rs │ ├── version_rolling.rs │ └── core_reg_probe.rs ├── Cargo.toml ├── bm13xx-asic ├── Cargo.toml └── src │ ├── error.rs │ ├── core_register │ ├── core_reg2.rs │ ├── core_enable.rs │ ├── core_reg8.rs │ ├── core_reg11.rs │ ├── sweep_clock.rs │ ├── mod.rs │ ├── core_reg22.rs │ ├── core_error.rs │ ├── hash_clock.rs │ ├── process_monitor.rs │ └── clock_delay.rs │ ├── register │ ├── timeout.rs │ ├── hash_counting_number.rs │ ├── hash_rate.rs │ ├── nonce_returned_timeout.rs │ ├── returned_single_pattern_status.rs │ ├── error_flag.rs │ ├── pll_parameter.rs │ ├── return_group_pattern_status.rs │ ├── i2c.rs │ ├── external_temperature_sensor.rs │ ├── unknown.rs │ ├── nonce_counter.rs │ ├── frequency_sweep.rs │ ├── pll_divider.rs │ ├── ticket_mask.rs │ ├── midstate_calc.rs │ ├── chip_identification.rs │ ├── mod.rs │ ├── chip_nonce_offset.rs │ ├── uart_relay.rs │ ├── analog_mux.rs │ ├── soft_reset.rs │ ├── core_register.rs │ ├── io_driver_strenght.rs │ ├── fast_uart.rs │ └── misc.rs │ ├── lib.rs │ ├── sha.rs │ └── fmt.rs ├── bm1366 ├── Cargo.toml └── src │ └── fmt.rs ├── bm1370 ├── Cargo.toml └── src │ └── fmt.rs ├── bm1397 ├── Cargo.toml └── src │ └── fmt.rs ├── .github └── workflows │ └── rust-ci.yml ├── LICENSE-MIT ├── README.md ├── bm13xx-chain ├── Cargo.toml ├── src │ ├── error.rs │ └── fmt.rs └── examples │ └── cli.rs ├── shell.nix └── LICENSE-APACHE /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target/ 3 | *.log 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "nixEnvSelector.nixFile": "${workspaceFolder}/shell.nix" 3 | } -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "stable" 3 | components = ["rustfmt", "clippy"] 4 | -------------------------------------------------------------------------------- /bm13xx-protocol/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! BM13xx protocol. 2 | 3 | #![no_std] 4 | #![macro_use] 5 | pub(crate) mod fmt; 6 | 7 | mod crc; 8 | mod error; 9 | 10 | pub mod command; 11 | pub mod response; 12 | 13 | pub use self::error::{Error, Result}; 14 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "bm1366", 5 | "bm1370", 6 | "bm1397", 7 | "bm13xx-asic", 8 | "bm13xx-chain", 9 | "bm13xx-protocol", 10 | ] 11 | 12 | [workspace.dependencies] 13 | crc = "3.3" 14 | defmt = { version = "1.0" } 15 | derive_more = { version = "2.0", default-features = false } 16 | embedded-hal = "1.0" 17 | embedded-hal-async = "1.0" 18 | embedded-io-async = "0.6" 19 | fugit = "0.3" 20 | heapless = "0.9" 21 | log = "0.4" 22 | rustversion = "1.0" 23 | -------------------------------------------------------------------------------- /bm13xx-asic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | categories = ["embedded", "no-std"] 3 | edition = "2021" 4 | name = "bm13xx-asic" 5 | rust-version = "1.86.0" 6 | version = "0.2.0" 7 | 8 | [dependencies] 9 | bm13xx-protocol = { path = "../bm13xx-protocol" } 10 | 11 | defmt = { workspace = true, optional = true } 12 | derive_more = { workspace = true, features = ["from"] } 13 | fugit = { workspace = true } 14 | log = { workspace = true, optional = true } 15 | rustversion = { workspace = true } 16 | 17 | [features] 18 | defmt = ["dep:defmt", "bm13xx-protocol/defmt", "fugit/defmt"] 19 | -------------------------------------------------------------------------------- /bm13xx-asic/src/error.rs: -------------------------------------------------------------------------------- 1 | use derive_more::From; 2 | 3 | pub type Result = core::result::Result; 4 | 5 | #[derive(Debug, PartialEq, From)] 6 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 7 | pub enum Error { 8 | // -- register 9 | UnknownRegister { reg_addr: u8 }, 10 | } 11 | 12 | #[rustversion::since(1.81)] 13 | impl core::error::Error for Error {} 14 | 15 | #[rustversion::since(1.81)] 16 | impl core::fmt::Display for Error { 17 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 18 | write!(f, "{self:?}") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /bm1366/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | categories = ["embedded", "no-std"] 3 | edition = "2021" 4 | name = "bm1366" 5 | rust-version = "1.86.0" 6 | version = "0.2.0" 7 | 8 | [dependencies] 9 | "bm13xx-asic" = { path = "../bm13xx-asic" } 10 | "bm13xx-protocol" = { path = "../bm13xx-protocol" } 11 | 12 | defmt = { workspace = true, optional = true } 13 | fugit = { workspace = true } 14 | heapless = { workspace = true } 15 | log = { workspace = true, optional = true } 16 | 17 | [features] 18 | defmt = [ 19 | "dep:defmt", 20 | "bm13xx-asic/defmt", 21 | "bm13xx-protocol/defmt", 22 | "fugit/defmt", 23 | "heapless/defmt", 24 | ] 25 | -------------------------------------------------------------------------------- /bm1370/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | categories = ["embedded", "no-std"] 3 | edition = "2021" 4 | name = "bm1370" 5 | rust-version = "1.86.0" 6 | version = "0.2.0" 7 | 8 | [dependencies] 9 | "bm13xx-asic" = { path = "../bm13xx-asic" } 10 | "bm13xx-protocol" = { path = "../bm13xx-protocol" } 11 | 12 | defmt = { workspace = true, optional = true } 13 | fugit = { workspace = true } 14 | heapless = { workspace = true } 15 | log = { workspace = true, optional = true } 16 | 17 | [features] 18 | defmt = [ 19 | "dep:defmt", 20 | "bm13xx-asic/defmt", 21 | "bm13xx-protocol/defmt", 22 | "fugit/defmt", 23 | "heapless/defmt", 24 | ] 25 | -------------------------------------------------------------------------------- /bm1397/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | categories = ["embedded", "no-std"] 3 | edition = "2021" 4 | name = "bm1397" 5 | rust-version = "1.86.0" 6 | version = "0.2.0" 7 | 8 | [dependencies] 9 | "bm13xx-asic" = { path = "../bm13xx-asic" } 10 | "bm13xx-protocol" = { path = "../bm13xx-protocol" } 11 | 12 | defmt = { workspace = true, optional = true } 13 | fugit = { workspace = true } 14 | heapless = { workspace = true } 15 | log = { workspace = true, optional = true } 16 | 17 | [features] 18 | defmt = [ 19 | "dep:defmt", 20 | "bm13xx-asic/defmt", 21 | "bm13xx-protocol/defmt", 22 | "fugit/defmt", 23 | "heapless/defmt", 24 | ] 25 | -------------------------------------------------------------------------------- /bm13xx-protocol/src/error.rs: -------------------------------------------------------------------------------- 1 | use derive_more::From; 2 | 3 | pub type Result = core::result::Result; 4 | 5 | #[derive(Debug, PartialEq, From)] 6 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 7 | pub enum Error { 8 | // -- response 9 | InvalidPreamble, 10 | UnsupportedCoreSmallCoreCnt, 11 | InvalidCrc { expected: u8, actual: u8 }, 12 | } 13 | 14 | #[rustversion::since(1.81)] 15 | impl core::error::Error for Error {} 16 | 17 | #[rustversion::since(1.81)] 18 | impl core::fmt::Display for Error { 19 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 20 | write!(f, "{self:?}") 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /bm13xx-asic/src/core_register/core_reg2.rs: -------------------------------------------------------------------------------- 1 | use crate::core_register::CoreRegister; 2 | 3 | /// # Hash Clock Ctrl core register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct CoreReg2(pub u8); 6 | impl_boilerplate_for_core_reg!(CoreReg2); 7 | 8 | impl CoreReg2 { 9 | pub const ID: u8 = 2; 10 | } 11 | 12 | impl ::core::fmt::Display for CoreReg2 { 13 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 14 | f.debug_struct("CoreReg2").finish() 15 | } 16 | } 17 | 18 | #[cfg(feature = "defmt")] 19 | impl defmt::Format for CoreReg2 { 20 | fn format(&self, fmt: defmt::Formatter) { 21 | defmt::write!(fmt, "CoreReg2 {{ }}",); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/timeout.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # Time Out register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct TimeOut(pub u32); 6 | impl_boilerplate_for!(TimeOut); 7 | 8 | impl TimeOut { 9 | pub const ADDR: u8 = 0x5C; 10 | 11 | // const TMOUT_OFFSET: u8 = 0; 12 | 13 | // const TMOUT_MASK: u32 = 0xffff; 14 | } 15 | 16 | impl core::fmt::Display for TimeOut { 17 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 18 | f.debug_struct("TimeOut").finish() 19 | } 20 | } 21 | 22 | #[cfg(feature = "defmt")] 23 | impl defmt::Format for TimeOut { 24 | fn format(&self, fmt: defmt::Formatter) { 25 | defmt::write!(fmt, "TimeOut {{ }}",); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /bm13xx-asic/src/core_register/core_enable.rs: -------------------------------------------------------------------------------- 1 | use crate::core_register::CoreRegister; 2 | 3 | /// # Core Enable core register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct CoreEnable(pub u8); 6 | impl_boilerplate_for_core_reg!(CoreEnable); 7 | 8 | impl CoreEnable { 9 | pub const ID: u8 = 4; 10 | 11 | // const CORE_EN_I_OFFSET: u8 = 0; 12 | 13 | // const CORE_EN_I_MASK: u8 = 0xff; 14 | } 15 | 16 | impl ::core::fmt::Display for CoreEnable { 17 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 18 | f.debug_struct("CoreEnable").finish() 19 | } 20 | } 21 | 22 | #[cfg(feature = "defmt")] 23 | impl defmt::Format for CoreEnable { 24 | fn format(&self, fmt: defmt::Formatter) { 25 | defmt::write!(fmt, "CoreEnable {{ }}",); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/hash_counting_number.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # Hash Counting Number register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct HashCountingNumber(pub u32); 6 | impl_boilerplate_for!(HashCountingNumber); 7 | 8 | impl HashCountingNumber { 9 | pub const ADDR: u8 = 0x10; 10 | 11 | // const HCN_OFFSET: u8 = 0; 12 | 13 | // const HCN_MASK: u32 = 0xffff_ffff; 14 | } 15 | 16 | impl core::fmt::Display for HashCountingNumber { 17 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 18 | f.debug_struct("HashCountingNumber").finish() 19 | } 20 | } 21 | 22 | #[cfg(feature = "defmt")] 23 | impl defmt::Format for HashCountingNumber { 24 | fn format(&self, fmt: defmt::Formatter) { 25 | defmt::write!(fmt, "HashCountingNumber {{ }}",); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/hash_rate.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # Hash Rate register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct HashRate(pub u32); 6 | impl_boilerplate_for!(HashRate); 7 | 8 | impl HashRate { 9 | pub const ADDR: u8 = 0x04; 10 | 11 | // const LONG_OFFSET: u8 = 31; 12 | // const HASHRATE_OFFSET: u8 = 0; 13 | 14 | // const LONG_MASK: u32 = 0b1; 15 | // const HASHRATE_MASK: u32 = 0x7fff_ffff; 16 | } 17 | 18 | impl core::fmt::Display for HashRate { 19 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 20 | f.debug_struct("HashRate").finish() 21 | } 22 | } 23 | 24 | #[cfg(feature = "defmt")] 25 | impl defmt::Format for HashRate { 26 | fn format(&self, fmt: defmt::Formatter) { 27 | defmt::write!(fmt, "HashRate {{ }}",); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /bm13xx-asic/src/core_register/core_reg8.rs: -------------------------------------------------------------------------------- 1 | use crate::core_register::CoreRegister; 2 | 3 | /// # Hash Clock Ctrl core register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct CoreReg8(pub u8); 6 | impl_boilerplate_for_core_reg!(CoreReg8); 7 | 8 | impl CoreReg8 { 9 | pub const ID: u8 = 8; 10 | 11 | // const SOME_OFFSET: u8 = 5; 12 | // const SOME2_OFFSET: u8 = 0; 13 | 14 | // const SOME_MASK: u8 = 0b11; 15 | // const SOME2_MASK: u8 = 0b1; 16 | } 17 | 18 | impl ::core::fmt::Display for CoreReg8 { 19 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 20 | f.debug_struct("CoreReg8").finish() 21 | } 22 | } 23 | 24 | #[cfg(feature = "defmt")] 25 | impl defmt::Format for CoreReg8 { 26 | fn format(&self, fmt: defmt::Formatter) { 27 | defmt::write!(fmt, "CoreReg8 {{ }}",); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.github/workflows/rust-ci.yml: -------------------------------------------------------------------------------- 1 | name: Rust CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | env: 12 | CARGO_TERM_COLOR: always 13 | RUSTFLAGS: "-Dwarnings" 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Set up Rust 21 | uses: actions/checkout@v4 22 | - uses: awalsh128/cache-apt-pkgs-action@latest 23 | with: 24 | packages: libudev-dev 25 | version: 1.0 26 | - name: Build 27 | run: cargo build --verbose 28 | - name: Test 29 | run: cargo test --verbose 30 | - name: Format 31 | run: cargo fmt --check 32 | - name: Clippy 33 | run: cargo clippy --verbose -- -D warnings 34 | # - name: Audit 35 | # run: cargo audit 36 | -------------------------------------------------------------------------------- /bm13xx-asic/src/core_register/core_reg11.rs: -------------------------------------------------------------------------------- 1 | use crate::core_register::CoreRegister; 2 | 3 | /// # Hash Clock Ctrl core register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct CoreReg11(pub u8); 6 | impl_boilerplate_for_core_reg!(CoreReg11); 7 | 8 | impl CoreReg11 { 9 | pub const ID: u8 = 11; 10 | 11 | // const SOME_OFFSET: u8 = 5; 12 | // const SOME2_OFFSET: u8 = 0; 13 | 14 | // const SOME_MASK: u8 = 0b11; 15 | // const SOME2_MASK: u8 = 0b1; 16 | } 17 | 18 | impl ::core::fmt::Display for CoreReg11 { 19 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 20 | f.debug_struct("CoreReg11").finish() 21 | } 22 | } 23 | 24 | #[cfg(feature = "defmt")] 25 | impl defmt::Format for CoreReg11 { 26 | fn format(&self, fmt: defmt::Formatter) { 27 | defmt::write!(fmt, "CoreReg11 {{ }}",); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/nonce_returned_timeout.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # Nonce Returned Timeout register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct NonceReturnedTimeout(pub u32); 6 | impl_boilerplate_for!(NonceReturnedTimeout); 7 | 8 | impl NonceReturnedTimeout { 9 | pub const ADDR: u8 = 0x9C; 10 | 11 | // const SWEEP_TIMEOUT_OFFSET: u8 = 0; 12 | 13 | // const SWEEP_TIMEOUT_MASK: u32 = 0xffff; 14 | } 15 | 16 | impl core::fmt::Display for NonceReturnedTimeout { 17 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 18 | f.debug_struct("NonceReturnedTimeout").finish() 19 | } 20 | } 21 | 22 | #[cfg(feature = "defmt")] 23 | impl defmt::Format for NonceReturnedTimeout { 24 | fn format(&self, fmt: defmt::Formatter) { 25 | defmt::write!(fmt, "NonceReturnedTimeout {{ }}",); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /bm13xx-asic/src/core_register/sweep_clock.rs: -------------------------------------------------------------------------------- 1 | use crate::core_register::CoreRegister; 2 | 3 | /// # Sweep Clock Ctrl core register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct SweepClockCtrl(pub u8); 6 | impl_boilerplate_for_core_reg!(SweepClockCtrl); 7 | 8 | impl SweepClockCtrl { 9 | pub const ID: u8 = 7; 10 | 11 | // const SWPF_MODE_OFFSET: u8 = 7; 12 | // const CLK_SEL_OFFSET: u8 = 0; 13 | 14 | // const SWPF_MODE_MASK: u8 = 0b1; 15 | // const CLK_SEL_MASK: u8 = 0b1111; 16 | } 17 | 18 | impl ::core::fmt::Display for SweepClockCtrl { 19 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 20 | f.debug_struct("SweepClockCtrl").finish() 21 | } 22 | } 23 | 24 | #[cfg(feature = "defmt")] 25 | impl defmt::Format for SweepClockCtrl { 26 | fn format(&self, fmt: defmt::Formatter) { 27 | defmt::write!(fmt, "SweepClockCtrl {{ }}",); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/returned_single_pattern_status.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # Returned Single Pattern Status register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct ReturnedSinglePatternStatus(pub u32); 6 | impl_boilerplate_for!(ReturnedSinglePatternStatus); 7 | 8 | impl ReturnedSinglePatternStatus { 9 | pub const ADDR: u8 = 0xA0; 10 | 11 | // const RSPS_OFFSET: u8 = 0; 12 | 13 | // const RSPS_MASK: u32 = 0xffff_ffff; 14 | } 15 | 16 | impl core::fmt::Display for ReturnedSinglePatternStatus { 17 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 18 | f.debug_struct("ReturnedSinglePatternStatus").finish() 19 | } 20 | } 21 | 22 | #[cfg(feature = "defmt")] 23 | impl defmt::Format for ReturnedSinglePatternStatus { 24 | fn format(&self, fmt: defmt::Formatter) { 25 | defmt::write!(fmt, "ReturnedSinglePatternStatus {{ }}",); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/error_flag.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # Error Flag register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct ErrorFlag(pub u32); 6 | impl_boilerplate_for!(ErrorFlag); 7 | 8 | impl ErrorFlag { 9 | pub const ADDR: u8 = 0x48; 10 | 11 | // const CMD_ERR_CNT_OFFSET: u8 = 24; 12 | // const WORK_ERR_CNT_OFFSET: u8 = 16; 13 | // const CORE_RESP_ERR_OFFSET: u8 = 0; 14 | 15 | // const CMD_ERR_CNT_MASK: u32 = 0xff; 16 | // const WORK_ERR_CNT_MASK: u32 = 0xff; 17 | // const CORE_RESP_ERR_MASK: u32 = 0xff; 18 | } 19 | 20 | impl core::fmt::Display for ErrorFlag { 21 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 22 | f.debug_struct("ErrorFlag").finish() 23 | } 24 | } 25 | 26 | #[cfg(feature = "defmt")] 27 | impl defmt::Format for ErrorFlag { 28 | fn format(&self, fmt: defmt::Formatter) { 29 | defmt::write!(fmt, "ErrorFlag {{ }}",); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bm13xx-protocol/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | categories = ["embedded", "no-std"] 3 | edition = "2021" 4 | name = "bm13xx-protocol" 5 | rust-version = "1.86.0" 6 | version = "0.2.0" 7 | 8 | [dependencies] 9 | crc = { workspace = true } 10 | defmt = { workspace = true, optional = true } 11 | derive_more = { workspace = true, features = ["from"] } 12 | heapless = { workspace = true } 13 | log = { workspace = true, optional = true } 14 | rustversion = { workspace = true } 15 | 16 | [features] 17 | defmt = ["dep:defmt", "heapless/defmt"] 18 | 19 | [dev-dependencies] 20 | env_logger = "0.11" 21 | serialport = { version = "4.4", default-features = false } 22 | 23 | [[example]] 24 | name = "reg_probe" 25 | path = "examples/reg_probe.rs" 26 | 27 | [[example]] 28 | name = "core_reg_probe" 29 | path = "examples/core_reg_probe.rs" 30 | 31 | [[example]] 32 | name = "version_rolling" 33 | path = "examples/version_rolling.rs" 34 | 35 | [[example]] 36 | name = "chain_enum" 37 | path = "examples/chain_enum.rs" 38 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/pll_parameter.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # PLL Parameter registers 4 | /// 5 | /// Used to set PLL parameters. 6 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 7 | pub struct PLL0Parameter(pub u32); 8 | impl_boilerplate_for!(PLL0Parameter); 9 | 10 | impl PLL0Parameter { 11 | pub const ADDR: u8 = 0x08; 12 | } 13 | 14 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 15 | pub struct PLL1Parameter(pub u32); 16 | impl_boilerplate_for!(PLL1Parameter); 17 | 18 | impl PLL1Parameter { 19 | pub const ADDR: u8 = 0x60; 20 | } 21 | 22 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 23 | pub struct PLL2Parameter(pub u32); 24 | impl_boilerplate_for!(PLL2Parameter); 25 | 26 | impl PLL2Parameter { 27 | pub const ADDR: u8 = 0x64; 28 | } 29 | 30 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 31 | pub struct PLL3Parameter(pub u32); 32 | impl_boilerplate_for!(PLL3Parameter); 33 | 34 | impl PLL3Parameter { 35 | pub const ADDR: u8 = 0x68; 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /bm13xx-asic/src/register/return_group_pattern_status.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # Returned Group Pattern Status register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct ReturnedGroupPatternStatus(pub u32); 6 | impl_boilerplate_for!(ReturnedGroupPatternStatus); 7 | 8 | impl ReturnedGroupPatternStatus { 9 | pub const ADDR: u8 = 0x98; 10 | 11 | // const RGPS3_OFFSET: u8 = 24; 12 | // const RGPS2_OFFSET: u8 = 16; 13 | // const RGPS1_OFFSET: u8 = 8; 14 | // const RGPS0_OFFSET: u8 = 0; 15 | 16 | // const RGPS3_MASK: u32 = 0b1111; 17 | // const RGPS2_MASK: u32 = 0b1111; 18 | // const RGPS1_MASK: u32 = 0b1111; 19 | // const RGPS0_MASK: u32 = 0b1111; 20 | } 21 | 22 | impl core::fmt::Display for ReturnedGroupPatternStatus { 23 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 24 | f.debug_struct("ReturnedGroupPatternStatus").finish() 25 | } 26 | } 27 | 28 | #[cfg(feature = "defmt")] 29 | impl defmt::Format for ReturnedGroupPatternStatus { 30 | fn format(&self, fmt: defmt::Formatter) { 31 | defmt::write!(fmt, "ReturnedGroupPatternStatus {{ }}",); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/i2c.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # I2C Control register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct I2CControl(pub u32); 6 | impl_boilerplate_for!(I2CControl); 7 | 8 | impl I2CControl { 9 | pub const ADDR: u8 = 0x1C; 10 | 11 | // const BUSY_OFFSET: u8 = 31; 12 | // const DO_CMD_OFFSET: u8 = 24; 13 | // const I2C_ADDR_OFFSET: u8 = 17; 14 | // const RD_WR_OFFSET: u8 = 16; 15 | // const I2C_REG_ADDR_OFFSET: u8 = 8; 16 | // const I2C_REG_VAL_OFFSET: u8 = 0; 17 | 18 | // const BUSY_MASK: u32 = 0b1; 19 | // const DO_CMD_MASK: u32 = 0b1; 20 | // const I2C_ADDR_MASK: u32 = 0x7f; 21 | // const RD_WR_MASK: u32 = 0b1; 22 | // const I2C_REG_ADDR_MASK: u32 = 0xff; 23 | // const I2C_REG_VAL_MASK: u32 = 0xff; 24 | } 25 | 26 | impl core::fmt::Display for I2CControl { 27 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 28 | f.debug_struct("I2CControl").finish() 29 | } 30 | } 31 | 32 | #[cfg(feature = "defmt")] 33 | impl defmt::Format for I2CControl { 34 | fn format(&self, fmt: defmt::Formatter) { 35 | defmt::write!(fmt, "I2CControl {{ }}",); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/external_temperature_sensor.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # External Temperature Sensor Read register 4 | /// 5 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 6 | pub struct ExternalTemperatureSensorRead(pub u32); 7 | impl_boilerplate_for!(ExternalTemperatureSensorRead); 8 | 9 | impl ExternalTemperatureSensorRead { 10 | pub const ADDR: u8 = 0x44; 11 | 12 | // const LOCAL_TEMP_ADDR_OFFSET: u8 = 24; 13 | // const LOCAL_TEMP_DATA_OFFSET: u8 = 16; 14 | // const EXTERNAL_TEMP_ADDR_OFFSET: u8 = 8; 15 | // const EXTERNAL_TEMP_DATA_OFFSET: u8 = 0; 16 | 17 | // const LOCAL_TEMP_ADDR_MASK: u32 = 0xff; 18 | // const LOCAL_TEMP_DATA_MASK: u32 = 0xff; 19 | // const EXTERNAL_TEMP_ADDR_MASK: u32 = 0xff; 20 | // const EXTERNAL_TEMP_DATA_MASK: u32 = 0xff; 21 | } 22 | 23 | impl core::fmt::Display for ExternalTemperatureSensorRead { 24 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 25 | f.debug_struct("ExternalTemperatureSensorRead").finish() 26 | } 27 | } 28 | 29 | #[cfg(feature = "defmt")] 30 | impl defmt::Format for ExternalTemperatureSensorRead { 31 | fn format(&self, fmt: defmt::Formatter) { 32 | defmt::write!(fmt, "ExternalTemperatureSensorRead {{ }}",); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /bm13xx-protocol/examples/chain_enum.rs: -------------------------------------------------------------------------------- 1 | extern crate bm13xx_protocol; 2 | 3 | use std::thread::sleep; 4 | use std::time::Duration; 5 | 6 | use bm13xx_protocol::command::{Command, Destination}; 7 | use bm13xx_protocol::response::{Response, ResponseType}; 8 | 9 | fn main() { 10 | env_logger::init(); 11 | 12 | // let ports = serialport::available_ports().expect("No ports found!"); 13 | // for p in ports { 14 | // println!("{}", p.port_name); 15 | // } 16 | let mut port = serialport::new("/dev/ttyAMA0", 115_200) 17 | .timeout(Duration::from_millis(100)) 18 | .open() 19 | .expect("Failed to open port"); 20 | 21 | // ChipIdentification 22 | let cmd = Command::read_reg(0x00, Destination::All); 23 | println!(">> {:x?}", cmd); 24 | port.write_all(&cmd).expect("Write failed!"); 25 | loop { 26 | let mut resp: [u8; 9] = [0u8; 9]; 27 | port.read_exact(&mut resp).expect("Found no data!"); 28 | println!("<< {:x?}", resp); 29 | match Response::parse(&resp, 8).expect("Error parsing") { 30 | ResponseType::Reg(reg) => println!("{:x?}", reg), 31 | ResponseType::Job(job) => println!("{:x?}", job), 32 | ResponseType::JobVer(job) => println!("{:x?}", job), 33 | }; 34 | sleep(Duration::from_millis(50)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `bm13xx-rs` 2 | 3 | [![Crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | ![MIT licensed][license-image] 6 | 7 | Rust driver for the BM13xx Bitcoin Mining Asic family. 8 | 9 | ## Resources 10 | 11 | - [BM1397 documentation][doc-bm1397] 12 | - [BM1366 documentation][doc-bm1366] 13 | 14 | ## License 15 | 16 | Dual licensed under your choice of either of: 17 | 18 | - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or 19 | http://www.apache.org/licenses/LICENSE-2.0) 20 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or 21 | http://opensource.org/licenses/MIT) 22 | 23 | ### Contribution 24 | 25 | Unless you explicitly state otherwise, any contribution intentionally submitted 26 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall 27 | be dual licensed as above, without any additional terms or conditions. 28 | 29 | [crate-image]: https://img.shields.io/crates/v/bm13xx-rs.svg 30 | [crate-link]: https://crates.io/crates/bm13xx-rs 31 | [docs-image]: https://docs.rs/bm13xx-rs/badge.svg 32 | [docs-link]: https://docs.rs/bm13xxrs/ 33 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 34 | [doc-bm1397]: https://github.com/skot/BM1397/blob/master/bm1397.md 35 | [doc-bm1366]: https://github.com/skot/BM1397/blob/master/bm1366.md 36 | -------------------------------------------------------------------------------- /bm13xx-chain/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | categories = ["embedded", "no-std"] 3 | edition = "2021" 4 | name = "bm13xx-chain" 5 | rust-version = "1.86.0" 6 | version = "0.2.0" 7 | 8 | [dependencies] 9 | bm13xx-asic = { path = "../bm13xx-asic" } 10 | bm13xx-protocol = { path = "../bm13xx-protocol" } 11 | 12 | defmt = { workspace = true, optional = true } 13 | derive_more = { workspace = true, features = ["from"] } 14 | embedded-hal = { workspace = true } 15 | embedded-hal-async = { workspace = true } 16 | embedded-io-async = { workspace = true } 17 | fugit = { workspace = true } 18 | heapless = { workspace = true } 19 | log = { workspace = true, optional = true } 20 | rustversion = { workspace = true } 21 | 22 | [features] 23 | defmt = [ 24 | "dep:defmt", 25 | "bm13xx-asic/defmt", 26 | "bm13xx-protocol/defmt", 27 | "embedded-hal/defmt-03", 28 | "embedded-hal-async/defmt-03", 29 | "embedded-io-async/defmt-03", 30 | "fugit/defmt", 31 | "heapless/defmt", 32 | ] 33 | 34 | [dev-dependencies] 35 | bm1366 = { path = "../bm1366" } 36 | 37 | embedded-io = { version = "0.6", features = ["std"] } 38 | env_logger = "0.11" 39 | inquire = "0.7" 40 | linux-embedded-hal = "0.4" 41 | tokio = { version = "1.38", features = ["macros", "time", "rt-multi-thread"] } 42 | tokio-serial = "5.4" 43 | 44 | [[example]] 45 | name = "bm13xx-cli" 46 | path = "examples/cli.rs" 47 | -------------------------------------------------------------------------------- /bm13xx-protocol/examples/reg_probe.rs: -------------------------------------------------------------------------------- 1 | extern crate bm13xx_protocol; 2 | 3 | use std::thread::sleep; 4 | use std::time::Duration; 5 | 6 | use bm13xx_protocol::command::{Command, Destination}; 7 | use bm13xx_protocol::response::{Response, ResponseType}; 8 | 9 | fn main() { 10 | env_logger::init(); 11 | 12 | // let ports = serialport::available_ports().expect("No ports found!"); 13 | // for p in ports { 14 | // println!("{}", p.port_name); 15 | // } 16 | let mut port = serialport::new("/dev/ttyUSB0", 115_200) 17 | .timeout(Duration::from_millis(100)) 18 | .open() 19 | .expect("Failed to open port"); 20 | 21 | // loop over all possible register addresses 22 | for reg_addr in (0x00u8..0xFC).step_by(4) { 23 | let cmd = Command::read_reg(reg_addr, Destination::Chip(0)); 24 | println!(">> {:x?}", cmd); 25 | port.write_all(&cmd).expect("Write failed!"); 26 | 27 | let mut resp: [u8; 9] = [0u8; 9]; 28 | port.read_exact(&mut resp).expect("Found no data!"); 29 | println!("<< {:x?}", resp); 30 | match Response::parse(&resp, 8).expect("Error parsing") { 31 | ResponseType::Reg(reg) => println!("{:x?}", reg), 32 | ResponseType::Job(job) => println!("{:x?}", job), 33 | ResponseType::JobVer(job) => println!("{:x?}", job), 34 | }; 35 | sleep(Duration::from_millis(50)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /bm13xx-asic/src/core_register/mod.rs: -------------------------------------------------------------------------------- 1 | //! BM13xx Core Registers. 2 | 3 | pub trait CoreRegister { 4 | fn id(&self) -> u8; 5 | fn val(&self) -> u8; 6 | } 7 | 8 | macro_rules! impl_boilerplate_for_core_reg { 9 | ($REG:ident) => { 10 | impl From for $REG { 11 | fn from(val: u8) -> Self { 12 | Self(val) 13 | } 14 | } 15 | 16 | impl From<$REG> for u8 { 17 | fn from(val: $REG) -> u8 { 18 | val.0 19 | } 20 | } 21 | 22 | impl CoreRegister for $REG { 23 | fn id(&self) -> u8 { 24 | Self::ID 25 | } 26 | fn val(&self) -> u8 { 27 | self.0 28 | } 29 | } 30 | }; 31 | } 32 | 33 | mod clock_delay; 34 | mod core_enable; 35 | mod core_error; 36 | mod core_reg11; 37 | mod core_reg2; 38 | mod core_reg22; 39 | mod core_reg8; 40 | mod hash_clock; 41 | mod process_monitor; 42 | mod sweep_clock; 43 | 44 | pub use clock_delay::{ClockDelayCtrl, ClockDelayCtrlV2}; 45 | pub use core_enable::CoreEnable; 46 | pub use core_error::CoreError; 47 | pub use core_reg11::CoreReg11; 48 | pub use core_reg2::CoreReg2; // different than ProcessMonitorData but reuse of ID=2 49 | pub use core_reg22::CoreReg22; 50 | pub use core_reg8::CoreReg8; 51 | pub use hash_clock::{HashClockCounter, HashClockCtrl}; 52 | pub use process_monitor::{ProcessMonitorCtrl, ProcessMonitorData, ProcessMonitorSelect}; 53 | pub use sweep_clock::SweepClockCtrl; 54 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/unknown.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | macro_rules! unknown { 4 | ($REG:ident, $ADDR:expr) => { 5 | /// # $REG register 6 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 7 | pub struct $REG(pub u32); 8 | impl_boilerplate_for!($REG); 9 | 10 | impl $REG { 11 | pub const ADDR: u8 = $ADDR; 12 | } 13 | 14 | impl core::fmt::Display for $REG { 15 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 16 | f.debug_struct("$REG").finish() 17 | } 18 | } 19 | 20 | #[cfg(feature = "defmt")] 21 | impl defmt::Format for $REG { 22 | fn format(&self, fmt: defmt::Formatter) { 23 | defmt::write!(fmt, "$REG {{ }}",); 24 | } 25 | } 26 | }; 27 | } 28 | 29 | unknown!(Time1sCounter, 0x04); 30 | unknown!(TopProcessMonitor, 0x24); 31 | unknown!(CoreNumber, 0x30); 32 | unknown!(Reg34, 0x34); 33 | unknown!(TicketNonceCounter, 0x90); 34 | unknown!(RegAC, 0xAC); 35 | unknown!(RegB0, 0xB0); 36 | unknown!(RegB4, 0xB4); 37 | unknown!(RegB8, 0xB8); 38 | unknown!(RegBC, 0xBC); 39 | unknown!(RegC0, 0xC0); 40 | unknown!(RegC4, 0xC4); 41 | unknown!(RegC8, 0xC8); 42 | unknown!(RegCC, 0xCC); 43 | unknown!(FrequencySweepControl, 0xD0); 44 | unknown!(RegD4, 0xD4); 45 | unknown!(RegD8, 0xD8); 46 | unknown!(SweepNonceRetTimeout, 0xDC); 47 | unknown!(RegE0, 0xE0); 48 | unknown!(RegE4, 0xE4); 49 | unknown!(RegE8, 0xE8); 50 | unknown!(RegEC, 0xEC); 51 | unknown!(RegF0, 0xF0); 52 | unknown!(RegF4, 0xF4); 53 | unknown!(RegF8, 0xF8); 54 | unknown!(RegFC, 0xFC); 55 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/nonce_counter.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # Nonce Error Counter register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct NonceErrorCounter(pub u32); 6 | impl_boilerplate_for!(NonceErrorCounter); 7 | 8 | impl NonceErrorCounter { 9 | pub const ADDR: u8 = 0x4C; 10 | 11 | // const ERR_CNT_OFFSET: u8 = 0; 12 | 13 | // const ERR_CNT_MASK: u32 = 0xffff_ffff; 14 | } 15 | 16 | impl core::fmt::Display for NonceErrorCounter { 17 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 18 | f.debug_struct("NonceErrorCounter").finish() 19 | } 20 | } 21 | 22 | #[cfg(feature = "defmt")] 23 | impl defmt::Format for NonceErrorCounter { 24 | fn format(&self, fmt: defmt::Formatter) { 25 | defmt::write!(fmt, "NonceErrorCounter {{ }}",); 26 | } 27 | } 28 | 29 | /// # Nonce Overflow Counter register 30 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 31 | pub struct NonceOverflowCounter(pub u32); 32 | impl_boilerplate_for!(NonceOverflowCounter); 33 | 34 | impl NonceOverflowCounter { 35 | pub const ADDR: u8 = 0x50; 36 | 37 | // const OVRF_CNT_OFFSET: u8 = 0; 38 | 39 | // const OVRF_CNT_MASK: u32 = 0xffff_ffff; 40 | } 41 | 42 | impl core::fmt::Display for NonceOverflowCounter { 43 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 44 | f.debug_struct("NonceOverflowCounter").finish() 45 | } 46 | } 47 | 48 | #[cfg(feature = "defmt")] 49 | impl defmt::Format for NonceOverflowCounter { 50 | fn format(&self, fmt: defmt::Formatter) { 51 | defmt::write!(fmt, "NonceOverflowCounter {{ }}",); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /bm13xx-asic/src/core_register/core_reg22.rs: -------------------------------------------------------------------------------- 1 | use crate::core_register::CoreRegister; 2 | 3 | /// # Hash Clock Ctrl core register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct CoreReg22(pub u8); 6 | impl_boilerplate_for_core_reg!(CoreReg22); 7 | 8 | impl CoreReg22 { 9 | pub const ID: u8 = 22; 10 | 11 | const EN_OFFSET: u8 = 6; 12 | 13 | const EN_MASK: u8 = 0b1; 14 | 15 | /// ## Handle the enable field. 16 | /// 17 | /// ### Example 18 | /// ``` 19 | /// use bm13xx_asic::core_register::CoreReg22; 20 | /// 21 | /// let mut core_reg_22 = CoreReg22(0x00); // BM1366 default value 22 | /// assert!(!core_reg_22.enabled()); 23 | /// assert!(core_reg_22.enable().enabled()); 24 | /// assert!(!core_reg_22.disable().enabled()); 25 | /// ``` 26 | pub const fn enabled(&self) -> bool { 27 | (self.0 >> Self::EN_OFFSET) & Self::EN_MASK != 0 28 | } 29 | pub fn enable(&mut self) -> &mut Self { 30 | self.0 |= Self::EN_MASK << Self::EN_OFFSET; 31 | self 32 | } 33 | pub fn disable(&mut self) -> &mut Self { 34 | self.0 &= !(Self::EN_MASK << Self::EN_OFFSET); 35 | self 36 | } 37 | } 38 | 39 | impl ::core::fmt::Display for CoreReg22 { 40 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 41 | f.debug_struct("CoreReg22") 42 | .field("enabled", &self.enabled()) 43 | .finish() 44 | } 45 | } 46 | 47 | #[cfg(feature = "defmt")] 48 | impl defmt::Format for CoreReg22 { 49 | fn format(&self, fmt: defmt::Formatter) { 50 | defmt::write!(fmt, "CoreReg22 {{ enabled: {} }}", self.enabled(),); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/frequency_sweep.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # Frequency Sweep Control 1 register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct FrequencySweepControl1(pub u32); 6 | impl_boilerplate_for!(FrequencySweepControl1); 7 | 8 | impl FrequencySweepControl1 { 9 | pub const ADDR: u8 = 0x90; 10 | 11 | // const SWEEP_STATE_OFFSET: u8 = 24; 12 | 13 | // const SWEEP_STATE_MASK: u32 = 0b111; 14 | } 15 | 16 | impl core::fmt::Display for FrequencySweepControl1 { 17 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 18 | f.debug_struct("FrequencySweepControl1").finish() 19 | } 20 | } 21 | 22 | #[cfg(feature = "defmt")] 23 | impl defmt::Format for FrequencySweepControl1 { 24 | fn format(&self, fmt: defmt::Formatter) { 25 | defmt::write!(fmt, "FrequencySweepControl1 {{ }}",); 26 | } 27 | } 28 | 29 | /// # Golden Nonce For Sweep Return register 30 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 31 | pub struct GoldenNonceForSweepReturn(pub u32); 32 | impl_boilerplate_for!(GoldenNonceForSweepReturn); 33 | 34 | impl GoldenNonceForSweepReturn { 35 | pub const ADDR: u8 = 0x94; 36 | 37 | // const GNOSWR_OFFSET: u8 = 0; 38 | 39 | // const GNOSWR_MASK: u32 = 0xffff_ffff; 40 | } 41 | 42 | impl core::fmt::Display for GoldenNonceForSweepReturn { 43 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 44 | f.debug_struct("GoldenNonceForSweepReturn").finish() 45 | } 46 | } 47 | 48 | #[cfg(feature = "defmt")] 49 | impl defmt::Format for GoldenNonceForSweepReturn { 50 | fn format(&self, fmt: defmt::Formatter) { 51 | defmt::write!(fmt, "GoldenNonceForSweepReturn {{ }}",); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /bm13xx-asic/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! BM13xx ASIC representation. 2 | 3 | #![no_std] 4 | #![macro_use] 5 | pub(crate) mod fmt; 6 | 7 | pub mod core_register; 8 | mod error; 9 | pub mod pll; 10 | pub mod register; 11 | pub mod sha; 12 | 13 | pub use self::error::{Error, Result}; 14 | 15 | use bm13xx_protocol::command::Destination; 16 | 17 | use fugit::HertzU64; 18 | 19 | #[derive(Debug, Clone, PartialEq)] 20 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 21 | pub struct CmdDelay { 22 | pub cmd: [u8; 11], 23 | pub delay_ms: u32, 24 | } 25 | 26 | #[derive(Debug, Default, Clone, PartialEq)] 27 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 28 | pub enum SequenceStep { 29 | #[default] 30 | None, 31 | Init(usize), 32 | Baudrate(usize), 33 | ResetCore(usize), 34 | HashFreq(usize), 35 | SplitNonce(usize), 36 | VersionRolling(usize), 37 | } 38 | 39 | pub trait Asic { 40 | fn reset(&mut self); 41 | fn chip_id(&self) -> u16; 42 | fn core_count(&self) -> usize; 43 | fn core_small_core_count(&self) -> usize; 44 | fn small_core_count(&self) -> usize; 45 | fn cno_interval(&self) -> usize; 46 | fn cno_bits(&self) -> u32; 47 | fn hash_freq(&self) -> HertzU64; 48 | fn init_next(&mut self, difficulty: u32) -> Option; 49 | fn set_baudrate_next( 50 | &mut self, 51 | baudrate: u32, 52 | chain_domain_cnt: usize, 53 | domain_asic_cnt: usize, 54 | asic_addr_interval: usize, 55 | ) -> Option; 56 | fn reset_core_next(&mut self, dest: Destination) -> Option; 57 | fn set_hash_freq_next(&mut self, target_freq: HertzU64) -> Option; 58 | fn split_nonce_between_chips_next( 59 | &mut self, 60 | chain_asic_num: usize, 61 | asic_addr_interval: usize, 62 | ) -> Option; 63 | fn set_version_rolling_next(&mut self, mask: u32) -> Option; 64 | } 65 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/pll_divider.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # PLL Divider registers 4 | /// 5 | /// Used to set PLL parameters. 6 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 7 | pub struct PLL0Divider(pub u32); 8 | impl_boilerplate_for!(PLL0Divider); 9 | 10 | impl PLL0Divider { 11 | pub const ADDR: u8 = 0x70; 12 | } 13 | 14 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 15 | pub struct PLL1Divider(pub u32); 16 | impl_boilerplate_for!(PLL1Divider); 17 | 18 | impl PLL1Divider { 19 | pub const ADDR: u8 = 0x74; 20 | } 21 | 22 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 23 | pub struct PLL2Divider(pub u32); 24 | impl_boilerplate_for!(PLL2Divider); 25 | 26 | impl PLL2Divider { 27 | pub const ADDR: u8 = 0x78; 28 | } 29 | 30 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 31 | pub struct PLL3Divider(pub u32); 32 | impl_boilerplate_for!(PLL3Divider); 33 | 34 | impl PLL3Divider { 35 | pub const ADDR: u8 = 0x7C; 36 | } 37 | 38 | trait PLLDividerRegister: Register {} 39 | 40 | impl dyn PLLDividerRegister { 41 | // const PLLDIV3_OFFSET: u8 = 24; 42 | // const PLLDIV2_OFFSET: u8 = 16; 43 | // const PLLDIV1_OFFSET: u8 = 8; 44 | // const PLLDIV0_OFFSET: u8 = 0; 45 | 46 | // const PLLDIV3_MASK: u32 = 0b1111; 47 | // const PLLDIV2_MASK: u32 = 0b1111; 48 | // const PLLDIV1_MASK: u32 = 0b1111; 49 | // const PLLDIV0_MASK: u32 = 0b1111; 50 | } 51 | 52 | impl core::fmt::Display for dyn PLLDividerRegister { 53 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 54 | f.debug_struct("PLLDivider").finish() 55 | } 56 | } 57 | 58 | #[cfg(feature = "defmt")] 59 | impl defmt::Format for dyn PLLDividerRegister { 60 | fn format(&self, fmt: defmt::Formatter) { 61 | defmt::write!(fmt, "PLLDivider {{ }}",); 62 | } 63 | } 64 | 65 | impl PLLDividerRegister for PLL0Divider {} 66 | impl PLLDividerRegister for PLL1Divider {} 67 | impl PLLDividerRegister for PLL2Divider {} 68 | impl PLLDividerRegister for PLL3Divider {} 69 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs ? import { }, 3 | }: 4 | let 5 | unstable = 6 | import (builtins.fetchTarball "https://github.com/nixos/nixpkgs/tarball/nixos-unstable") 7 | { }; 8 | overrides = (builtins.fromTOML (builtins.readFile ./rust-toolchain.toml)); 9 | libPath = 10 | with pkgs; 11 | lib.makeLibraryPath [ 12 | # load external libraries that you need in your rust project here 13 | ]; 14 | in 15 | pkgs.mkShell rec { 16 | buildInputs = with pkgs; [ 17 | clang 18 | cmake 19 | # Replace llvmPackages with llvmPackages_X, where X is the latest LLVM version (at the time of writing, 16) 20 | llvmPackages.bintools 21 | openssl 22 | pkg-config 23 | unstable.rust-analyzer 24 | rustup 25 | ]; 26 | RUSTC_VERSION = overrides.toolchain.channel; 27 | # https://github.com/rust-lang/rust-bindgen#environment-variables 28 | LIBCLANG_PATH = pkgs.lib.makeLibraryPath [ pkgs.llvmPackages_latest.libclang.lib ]; 29 | shellHook = '' 30 | export PATH=$PATH:''${CARGO_HOME:-~/.cargo}/bin 31 | export PATH=$PATH:''${RUSTUP_HOME:-~/.rustup}/toolchains/$RUSTC_VERSION-x86_64-unknown-linux-gnu/bin/ 32 | ''; 33 | # Add precompiled library to rustc search path 34 | RUSTFLAGS = ( 35 | builtins.map (a: ''-L ${a}/lib'') [ 36 | # add libraries here (e.g. pkgs.libvmi) 37 | ] 38 | ); 39 | PKG_CONFIG_PATH = "${pkgs.openssl.dev}/lib/pkgconfig"; 40 | LD_LIBRARY_PATH = libPath; 41 | # Add glibc, clang, glib, and other headers to bindgen search path 42 | BINDGEN_EXTRA_CLANG_ARGS = 43 | # Includes normal include path 44 | (builtins.map (a: ''-I"${a}/include"'') [ 45 | # add dev libraries here (e.g. pkgs.libvmi.dev) 46 | pkgs.glibc.dev 47 | ]) 48 | # Includes with special directory paths 49 | ++ [ 50 | ''-I"${pkgs.llvmPackages_latest.libclang.lib}/lib/clang/${pkgs.llvmPackages_latest.libclang.version}/include"'' 51 | ''-I"${pkgs.glib.dev}/include/glib-2.0"'' 52 | ''-I${pkgs.glib.out}/lib/glib-2.0/include/'' 53 | ]; 54 | } 55 | -------------------------------------------------------------------------------- /bm13xx-asic/src/core_register/core_error.rs: -------------------------------------------------------------------------------- 1 | use crate::core_register::CoreRegister; 2 | 3 | /// # Core Error core register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct CoreError(pub u8); 6 | impl_boilerplate_for_core_reg!(CoreError); 7 | 8 | impl CoreError { 9 | pub const ID: u8 = 3; 10 | 11 | const INI_NONCE_ERR_OFFSET: u8 = 4; 12 | const CMD_ERR_CNT_OFFSET: u8 = 0; 13 | 14 | const INI_NONCE_ERR_MASK: u8 = 0b1; 15 | const CMD_ERR_CNT_MASK: u8 = 0b1111; 16 | 17 | /// ## Get the Ini Nonce Error state. 18 | /// 19 | /// This returns an `bool` with the Ini Nonce Error state. 20 | /// 21 | /// ### Example 22 | /// 23 | /// ``` 24 | /// use bm13xx_asic::core_register::CoreError; 25 | /// 26 | /// assert!(!CoreError(0x00).ini_nonce_err()); 27 | /// ``` 28 | pub const fn ini_nonce_err(&self) -> bool { 29 | (self.0 >> Self::INI_NONCE_ERR_OFFSET) & Self::INI_NONCE_ERR_MASK 30 | == Self::INI_NONCE_ERR_MASK 31 | } 32 | 33 | /// ## Get the Command Error Count. 34 | /// 35 | /// This returns an `u8` with the Command Error Count. 36 | /// 37 | /// ### Example 38 | /// 39 | /// ``` 40 | /// use bm13xx_asic::core_register::CoreError; 41 | /// 42 | /// assert_eq!(CoreError(0x00).cmd_err_cnt(), 0x00); 43 | /// ``` 44 | pub const fn cmd_err_cnt(&self) -> u8 { 45 | (self.0 >> Self::CMD_ERR_CNT_OFFSET) & Self::CMD_ERR_CNT_MASK 46 | } 47 | } 48 | 49 | impl ::core::fmt::Display for CoreError { 50 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 51 | f.debug_struct("CoreError") 52 | .field("ini_nonce_err", &self.ini_nonce_err()) 53 | .field("cmd_err_cnt", &self.cmd_err_cnt()) 54 | .finish() 55 | } 56 | } 57 | 58 | #[cfg(feature = "defmt")] 59 | impl defmt::Format for CoreError { 60 | fn format(&self, fmt: defmt::Formatter) { 61 | defmt::write!( 62 | fmt, 63 | "CoreError {{ ini_nonce_err: {}, cmd_err_cnt: {} }}", 64 | self.ini_nonce_err(), 65 | self.cmd_err_cnt() 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /bm13xx-protocol/examples/version_rolling.rs: -------------------------------------------------------------------------------- 1 | extern crate bm13xx_protocol; 2 | 3 | use std::thread::sleep; 4 | use std::time::Duration; 5 | 6 | use bm13xx_protocol::command::{Command, Destination}; 7 | use bm13xx_protocol::response::{Response, ResponseType}; 8 | 9 | fn main() { 10 | env_logger::init(); 11 | 12 | // let ports = serialport::available_ports().expect("No ports found!"); 13 | // for p in ports { 14 | // println!("{}", p.port_name); 15 | // } 16 | let mut port = serialport::new("/dev/ttyUSB0", 115_200) 17 | .timeout(Duration::from_millis(100)) 18 | .open() 19 | .expect("Failed to open port"); 20 | 21 | // Read ChipIdentification before enabling Version Rolling 22 | let cmd = Command::read_reg(0x00, Destination::Chip(0)); 23 | println!(">> {:x?}", cmd); 24 | port.write_all(&cmd).expect("Write failed!"); 25 | 26 | let mut resp = [0u8; 9]; 27 | port.read_exact(&mut resp).expect("Found no data!"); 28 | println!("<< {:x?}", resp); 29 | match Response::parse(&resp, 8).expect("Error parsing") { 30 | ResponseType::Reg(reg) => println!("{:x?}", reg), 31 | ResponseType::Job(job) => println!("{:x?}", job), 32 | ResponseType::JobVer(job) => println!("{:x?}", job), 33 | }; 34 | 35 | sleep(Duration::from_millis(50)); 36 | 37 | // Enable Version Rolling 38 | let cmd = Command::write_reg(0xA4, 0x8000FFFF, Destination::Chip(0)); 39 | println!(">> {:x?}", cmd); 40 | port.write_all(&cmd).expect("Write failed!"); 41 | 42 | sleep(Duration::from_millis(50)); 43 | 44 | // Read ChipIdentification after enabling Version Rolling 45 | let cmd = Command::read_reg(0x00, Destination::Chip(0)); 46 | println!(">> {:x?}", cmd); 47 | port.write_all(&cmd).expect("Write failed!"); 48 | 49 | let mut resp = [0u8; 11]; 50 | port.read_exact(&mut resp).expect("Found no data!"); 51 | println!("<< {:x?}", resp); 52 | match Response::parse_version(&resp, 8).expect("Error parsing") { 53 | ResponseType::Reg(reg) => println!("{:x?}", reg), 54 | ResponseType::Job(job) => println!("{:x?}", job), 55 | ResponseType::JobVer(job) => println!("{:x?}", job), 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/ticket_mask.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # Ticket Mask register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct TicketMask(pub u32); 6 | impl_boilerplate_for!(TicketMask); 7 | 8 | impl TicketMask { 9 | pub const ADDR: u8 = 0x14; 10 | 11 | // const TM3_OFFSET: u8 = 24; 12 | // const TM2_OFFSET: u8 = 16; 13 | // const TM1_OFFSET: u8 = 8; 14 | // const TM0_OFFSET: u8 = 0; 15 | 16 | // const TM3_MASK: u32 = 0xff; 17 | // const TM2_MASK: u32 = 0xff; 18 | // const TM1_MASK: u32 = 0xff; 19 | // const TM0_MASK: u32 = 0xff; 20 | 21 | /// ## Create a new `TicketMask` from a difficulty. 22 | /// 23 | /// ### Example 24 | /// 25 | /// ``` 26 | /// use bm13xx_asic::register::{Register, TicketMask}; 27 | /// 28 | /// assert_eq!(TicketMask::from_difficulty(256), TicketMask(0x0000_00ff)); 29 | /// assert_eq!(TicketMask::from_difficulty(512), TicketMask(0x0000_80ff)); 30 | /// ``` 31 | pub fn from_difficulty(diff: u32) -> Self { 32 | let largest_power_of_two = (1u32 << (31 - diff.leading_zeros())) - 1u32; 33 | Self(largest_power_of_two.to_le().reverse_bits().to_be()) 34 | } 35 | } 36 | 37 | impl core::fmt::Display for TicketMask { 38 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 39 | f.debug_struct("TicketMask").finish() 40 | } 41 | } 42 | 43 | #[cfg(feature = "defmt")] 44 | impl defmt::Format for TicketMask { 45 | fn format(&self, fmt: defmt::Formatter) { 46 | defmt::write!(fmt, "TicketMask {{ }}",); 47 | } 48 | } 49 | 50 | /// # Ticket Mask 2 register 51 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 52 | pub struct TicketMask2(pub u32); 53 | impl_boilerplate_for!(TicketMask2); 54 | 55 | impl TicketMask2 { 56 | pub const ADDR: u8 = 0x38; 57 | 58 | // const TM_OFFSET: u8 = 0; 59 | 60 | // const TM_MASK: u32 = 0xffff_ffff; 61 | } 62 | 63 | impl core::fmt::Display for TicketMask2 { 64 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 65 | f.debug_struct("TicketMask2").finish() 66 | } 67 | } 68 | 69 | #[cfg(feature = "defmt")] 70 | impl defmt::Format for TicketMask2 { 71 | fn format(&self, fmt: defmt::Formatter) { 72 | defmt::write!(fmt, "TicketMask2 {{ }}",); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/midstate_calc.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # MidstateCalc register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct MidstateCalc(pub u32); 6 | impl_boilerplate_for!(MidstateCalc); 7 | 8 | impl MidstateCalc { 9 | pub const ADDR: u8 = 0xA4; 10 | 11 | const EN_OFFSET: u8 = 31; 12 | const EN2_OFFSET: u8 = 28; 13 | const MASK_OFFSET: u8 = 0; 14 | 15 | const EN_MASK: u32 = 0x1; 16 | const MASK_MASK: u32 = 0xffff; 17 | 18 | /// ## Handle the enabled field. 19 | /// 20 | /// Get and set the enabled state. 21 | /// 22 | /// ### Example 23 | /// 24 | /// ``` 25 | /// use bm13xx_asic::register::MidstateCalc; 26 | /// 27 | /// let mut vers_roll = MidstateCalc(0x0000_FFFF); 28 | /// assert!(!vers_roll.enabled()); 29 | /// assert!(vers_roll.enable().enabled()); 30 | /// assert!(!vers_roll.disable().enabled()); 31 | /// ``` 32 | pub const fn enabled(&self) -> bool { 33 | ((self.0 >> Self::EN_OFFSET) & Self::EN_MASK == Self::EN_MASK) 34 | && ((self.0 >> Self::EN2_OFFSET) & Self::EN_MASK == Self::EN_MASK) 35 | } 36 | pub fn enable(&mut self) -> &mut Self { 37 | self.0 |= Self::EN_MASK << Self::EN_OFFSET; 38 | self.0 |= Self::EN_MASK << Self::EN2_OFFSET; 39 | self 40 | } 41 | pub fn disable(&mut self) -> &mut Self { 42 | self.0 &= !(Self::EN_MASK << Self::EN_OFFSET); 43 | self.0 &= !(Self::EN_MASK << Self::EN2_OFFSET); 44 | self 45 | } 46 | 47 | /// ## Handle the mask field. 48 | /// 49 | /// Get and set the mask value. 50 | /// 51 | /// ### Example 52 | /// 53 | /// ``` 54 | /// use bm13xx_asic::register::MidstateCalc; 55 | /// 56 | /// let mut vers_roll = MidstateCalc(0x0000_FFFF); 57 | /// assert_eq!(vers_roll.mask(), 0x1fff_e000); 58 | /// assert_eq!(vers_roll.set_mask(0x1fff_e000).mask(), 0x1fff_e000); 59 | /// ``` 60 | pub const fn mask(&self) -> u32 { 61 | ((self.0 >> Self::MASK_OFFSET) & Self::MASK_MASK) << 13 62 | } 63 | pub fn set_mask(&mut self, mask: u32) -> &mut Self { 64 | self.0 &= !(Self::MASK_MASK << Self::MASK_OFFSET); 65 | self.0 |= ((mask >> 13) & Self::MASK_MASK) << Self::MASK_OFFSET; 66 | self 67 | } 68 | } 69 | 70 | impl core::fmt::Display for MidstateCalc { 71 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 72 | f.debug_struct("VersionRolling").finish() 73 | } 74 | } 75 | 76 | #[cfg(feature = "defmt")] 77 | impl defmt::Format for MidstateCalc { 78 | fn format(&self, fmt: defmt::Formatter) { 79 | defmt::write!(fmt, "VersionRolling {{ }}",); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/chip_identification.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # Chip Identification register 4 | /// 5 | /// Used to identify a chip. 6 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 7 | pub struct ChipIdentification(pub u32); 8 | impl_boilerplate_for!(ChipIdentification); 9 | 10 | impl ChipIdentification { 11 | pub const ADDR: u8 = 0x00; 12 | 13 | const CHIP_ID_OFFSET: u8 = 16; 14 | const CORE_NUM_OFFSET: u8 = 8; 15 | const ADDR_OFFSET: u8 = 0; 16 | 17 | const CHIP_ID_MASK: u32 = 0xffff; 18 | const CORE_NUM_MASK: u32 = 0xff; 19 | const ADDR_MASK: u32 = 0xff; 20 | 21 | /// ## Get the chip identifier. 22 | /// 23 | /// This returns an `u16` with the chip_id value. 24 | /// 25 | /// ### Example 26 | /// 27 | /// ``` 28 | /// use bm13xx_asic::register::ChipIdentification; 29 | /// 30 | /// assert_eq!(ChipIdentification(0x1397_1800).chip_id(), 0x1397); 31 | /// ``` 32 | pub const fn chip_id(&self) -> u16 { 33 | ((self.0 >> Self::CHIP_ID_OFFSET) & Self::CHIP_ID_MASK) as u16 34 | } 35 | 36 | /// ## Get the number of internal cores. 37 | /// 38 | /// This returns an `u8` with the core_num value. 39 | /// 40 | /// ### Example 41 | /// 42 | /// ``` 43 | /// use bm13xx_asic::register::ChipIdentification; 44 | /// 45 | /// assert_eq!(ChipIdentification(0x1397_1800).core_num(), 0x18); 46 | /// ``` 47 | pub const fn core_num(&self) -> u8 { 48 | ((self.0 >> Self::CORE_NUM_OFFSET) & Self::CORE_NUM_MASK) as u8 49 | } 50 | 51 | /// ## Get the chip address on the chain. 52 | /// 53 | /// This returns an `u8` with the address value. 54 | /// 55 | /// ### Example 56 | /// 57 | /// ``` 58 | /// use bm13xx_asic::register::ChipIdentification; 59 | /// 60 | /// assert_eq!(ChipIdentification(0x1397_1800).chip_addr(), 0x00); 61 | /// ``` 62 | pub const fn chip_addr(&self) -> u8 { 63 | ((self.0 >> Self::ADDR_OFFSET) & Self::ADDR_MASK) as u8 64 | } 65 | } 66 | 67 | impl core::fmt::Display for ChipIdentification { 68 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 69 | f.debug_struct("ChipIdentification") 70 | .field("chip_id", &self.chip_id()) 71 | .field("core_num", &self.core_num()) 72 | .field("chip_addr", &self.chip_addr()) 73 | .finish() 74 | } 75 | } 76 | 77 | #[cfg(feature = "defmt")] 78 | impl defmt::Format for ChipIdentification { 79 | fn format(&self, fmt: defmt::Formatter) { 80 | defmt::write!( 81 | fmt, 82 | "ChipIdentification {{ chip_id: {}, core_num: {}, chip_addr: {} }}", 83 | self.chip_id(), 84 | self.core_num(), 85 | self.chip_addr(), 86 | ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /bm13xx-chain/src/error.rs: -------------------------------------------------------------------------------- 1 | use bm13xx_asic::register::ChipIdentification; 2 | use bm13xx_protocol::response::{RegisterResponse, ResponseType}; 3 | use derive_more::From; 4 | 5 | pub type Result = core::result::Result>; 6 | 7 | #[derive(PartialEq, From)] 8 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 9 | pub enum Error { 10 | /// We received a response from ASIC which does not correspond to the command sent 11 | UnexpectedResponse { resp: ResponseType }, 12 | /// We received a register response which does not correspond to the register read command 13 | BadRegisterResponse { reg_resp: RegisterResponse }, 14 | /// We enumerated an ASIC which does not correspond to the chip we are looking for 15 | UnexpectedAsic { chip_ident: ChipIdentification }, 16 | /// We enumerated an empty chain 17 | EmptyChain, 18 | /// The BM13xx protocol returned an error 19 | #[from] 20 | Protocol(bm13xx_protocol::Error), 21 | /// The serial interface returned an error 22 | Io(IO), 23 | /// The gpio interface returned an error on Busy signal 24 | Busy(B), 25 | /// The gpio interface returned an error on Reset signal 26 | Reset(R), 27 | /// The serial interface returned an error while setting baudrate 28 | SetBaudrate, 29 | } 30 | 31 | #[rustversion::since(1.81)] 32 | impl core::error::Error 33 | for Error 34 | { 35 | } 36 | 37 | #[rustversion::since(1.81)] 38 | impl core::fmt::Display 39 | for Error 40 | { 41 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 42 | write!(f, "{self:?}") 43 | } 44 | } 45 | 46 | impl core::fmt::Debug 47 | for Error 48 | { 49 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 50 | match self { 51 | Error::UnexpectedResponse { resp } => f 52 | .debug_struct("UnexpectedResponse") 53 | .field("resp", &format_args!("{:x?}", resp)) 54 | .finish(), 55 | Error::BadRegisterResponse { reg_resp } => f 56 | .debug_struct("BadRegisterResponse") 57 | .field("reg_resp", &format_args!("{:x?}", reg_resp)) 58 | .finish(), 59 | Error::UnexpectedAsic { chip_ident } => f 60 | .debug_struct("UnexpectedAsic") 61 | .field("chip_ident", &format_args!("{:x?}", chip_ident)) 62 | .finish(), 63 | Error::EmptyChain => f.debug_struct("EmptyChain").finish(), 64 | Error::Protocol(protocol_err) => f.debug_tuple("Protocol").field(protocol_err).finish(), 65 | Error::Io(io_err) => f.debug_tuple("Io").field(io_err).finish(), 66 | Error::Busy(gpio_err) => f.debug_tuple("Busy").field(gpio_err).finish(), 67 | Error::Reset(gpio_err) => f.debug_tuple("Reset").field(gpio_err).finish(), 68 | Error::SetBaudrate => f.debug_struct("SetBaudrate").finish(), 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /bm13xx-protocol/examples/core_reg_probe.rs: -------------------------------------------------------------------------------- 1 | extern crate bm13xx_protocol; 2 | 3 | use std::thread::sleep; 4 | use std::time::Duration; 5 | 6 | use bm13xx_protocol::command::{Command, Destination}; 7 | 8 | fn main() { 9 | env_logger::init(); 10 | 11 | // let ports = serialport::available_ports().expect("No ports found!"); 12 | // for p in ports { 13 | // println!("{}", p.port_name); 14 | // } 15 | let mut port = serialport::new("/dev/ttyUSB0", 115_200) 16 | .timeout(Duration::from_millis(100)) 17 | .open() 18 | .expect("Failed to open port"); 19 | 20 | // BM1366 need this 21 | /* Soft Open Core */ 22 | println!("Soft Open Core"); 23 | let cmd = Command::write_reg(0xA8, 0x0007_010f, Destination::All); 24 | println!(">> {:x?}", cmd); 25 | port.write_all(&cmd).expect("Write failed!"); 26 | let cmd = Command::write_reg(0x18, 0xFF00_C100, Destination::All); 27 | println!(">> {:x?}", cmd); 28 | port.write_all(&cmd).expect("Write failed!"); 29 | sleep(Duration::from_millis(200)); 30 | 31 | let cmd = Command::write_reg(0xA8, 0x0007_0000, Destination::All); 32 | println!(">> {:x?}", cmd); 33 | port.write_all(&cmd).expect("Write failed!"); 34 | let cmd = Command::write_reg(0x18, 0xFF0F_C100, Destination::All); 35 | println!(">> {:x?}", cmd); 36 | port.write_all(&cmd).expect("Write failed!"); 37 | sleep(Duration::from_millis(400)); 38 | 39 | let cmd = Command::write_reg(0x3c, 0x8000_82aa, Destination::All); 40 | println!(">> {:x?}", cmd); 41 | port.write_all(&cmd).expect("Write failed!"); 42 | sleep(Duration::from_millis(200)); 43 | 44 | // loop over all possible core register id (5 bits) 45 | println!("Read all Core Registers"); 46 | for core_reg_id in 0u32..32 { 47 | if core_reg_id == 4 { 48 | let cmd = Command::write_reg(0x3c, 0x8000_8301, Destination::Chip(0)); 49 | println!(">> {:x?}", cmd); 50 | port.write_all(&cmd).expect("Write failed!"); 51 | sleep(Duration::from_millis(10)); 52 | } 53 | if core_reg_id == 16 { 54 | let cmd = Command::write_reg(0x3c, 0x8000_8f06, Destination::Chip(0)); 55 | println!(">> {:x?}", cmd); 56 | port.write_all(&cmd).expect("Write failed!"); 57 | sleep(Duration::from_millis(10)); 58 | } 59 | let cmd = Command::write_reg(0x3c, 0x8000_00ff + (core_reg_id << 8), Destination::Chip(0)); 60 | println!(">> {:x?}", cmd); 61 | port.write_all(&cmd).expect("Write failed!"); 62 | 63 | sleep(Duration::from_millis(10)); 64 | 65 | let cmd = Command::read_reg(0x40, Destination::Chip(0)); 66 | println!(">> {:x?}", cmd); 67 | port.write_all(&cmd).expect("Write failed!"); 68 | 69 | let mut resp = [0u8; 9]; 70 | if port.read_exact(&mut resp).is_ok() { 71 | println!("<< {:x?}", resp); 72 | println!(".insert({}, 0x{:02x}).unwrap()", core_reg_id, resp[5]); 73 | } 74 | while port.read_exact(&mut resp).is_ok() { 75 | println!("<< {:x?}", resp); 76 | } 77 | sleep(Duration::from_millis(100)); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/mod.rs: -------------------------------------------------------------------------------- 1 | pub trait Register { 2 | fn addr(&self) -> u8; 3 | fn val(&self) -> u32; 4 | } 5 | 6 | macro_rules! impl_boilerplate_for { 7 | ($REG:ident) => { 8 | impl From for $REG { 9 | fn from(val: u32) -> Self { 10 | Self(val) 11 | } 12 | } 13 | 14 | impl From<$REG> for u32 { 15 | fn from(val: $REG) -> u32 { 16 | val.0 17 | } 18 | } 19 | 20 | impl Register for $REG { 21 | fn addr(&self) -> u8 { 22 | Self::ADDR 23 | } 24 | fn val(&self) -> u32 { 25 | self.0 26 | } 27 | } 28 | }; 29 | } 30 | 31 | mod analog_mux; 32 | mod chip_identification; 33 | mod chip_nonce_offset; 34 | mod clock_order; 35 | mod core_register; 36 | mod error_flag; 37 | mod external_temperature_sensor; 38 | mod fast_uart; 39 | mod frequency_sweep; 40 | mod hash_counting_number; 41 | mod hash_rate; 42 | mod i2c; 43 | mod io_driver_strenght; 44 | mod midstate_calc; 45 | mod misc; 46 | mod nonce_counter; 47 | mod nonce_returned_timeout; 48 | mod pll_divider; 49 | mod pll_parameter; 50 | mod return_group_pattern_status; 51 | mod returned_single_pattern_status; 52 | mod soft_reset; 53 | mod ticket_mask; 54 | mod timeout; 55 | mod uart_relay; 56 | mod unknown; 57 | 58 | pub use analog_mux::{AnalogMuxControl, AnalogMuxControlV2}; 59 | pub use chip_identification::ChipIdentification; 60 | pub use chip_nonce_offset::{ChipNonceOffset, ChipNonceOffsetV2}; 61 | pub use clock_order::{ 62 | ClockOrderControl0, ClockOrderControl1, ClockOrderStatus, ClockSelect, OrderedClockEnable, 63 | OrderedClockMonitor, 64 | }; 65 | pub use core_register::{CoreRegisterControl, CoreRegisterValue}; 66 | pub use error_flag::ErrorFlag; 67 | pub use external_temperature_sensor::ExternalTemperatureSensorRead; 68 | pub use fast_uart::{BaudrateClockSelectV2, FastUARTConfiguration, FastUARTConfigurationV2}; 69 | pub use frequency_sweep::{FrequencySweepControl1, GoldenNonceForSweepReturn}; 70 | pub use hash_counting_number::HashCountingNumber; 71 | pub use hash_rate::HashRate; 72 | pub use i2c::I2CControl; 73 | pub use io_driver_strenght::{DriverRSelect, DriverSelect, IoDriverStrenghtConfiguration}; 74 | pub use midstate_calc::MidstateCalc; 75 | pub use misc::{BaudrateClockSelect, MiscControl, MiscControlV2}; 76 | pub use nonce_counter::{NonceErrorCounter, NonceOverflowCounter}; 77 | pub use nonce_returned_timeout::NonceReturnedTimeout; 78 | pub use pll_divider::{PLL0Divider, PLL1Divider, PLL2Divider, PLL3Divider}; 79 | pub use pll_parameter::{PLL0Parameter, PLL1Parameter, PLL2Parameter, PLL3Parameter}; 80 | pub use return_group_pattern_status::ReturnedGroupPatternStatus; 81 | pub use returned_single_pattern_status::ReturnedSinglePatternStatus; 82 | pub use soft_reset::SoftResetControl; 83 | pub use ticket_mask::{TicketMask, TicketMask2}; 84 | pub use timeout::TimeOut; 85 | pub use uart_relay::UARTRelay; 86 | pub use unknown::{ 87 | CoreNumber, FrequencySweepControl, Reg34, RegAC, RegB0, RegB4, RegB8, RegBC, RegC0, RegC4, 88 | RegC8, RegCC, RegD4, RegD8, RegE0, RegE4, RegE8, RegEC, RegF0, RegF4, RegF8, RegFC, 89 | SweepNonceRetTimeout, TicketNonceCounter, Time1sCounter, TopProcessMonitor, 90 | }; 91 | -------------------------------------------------------------------------------- /bm13xx-asic/src/sha.rs: -------------------------------------------------------------------------------- 1 | /// # Small Core 2 | #[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)] 3 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 4 | pub struct SmallCore {} 5 | 6 | /// # Core 7 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 8 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 9 | pub struct Core { 10 | small_cores: [SmallCore; SC], 11 | } 12 | 13 | impl Core { 14 | pub fn new() -> Self { 15 | Core { 16 | small_cores: [SmallCore::default(); SC], 17 | } 18 | } 19 | 20 | /// ## Get the number of Small Cores in the Core 21 | /// 22 | /// ### Example 23 | /// ``` 24 | /// use bm13xx_asic::sha::Core; 25 | /// 26 | /// let core = Core::<4>::new(); 27 | /// assert_eq!(core.small_core_count(), 4); 28 | /// ``` 29 | pub const fn small_core_count(&self) -> usize { 30 | SC 31 | } 32 | } 33 | 34 | impl Default for Core { 35 | fn default() -> Self { 36 | Self::new() 37 | } 38 | } 39 | 40 | /// # ASIC 41 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 42 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 43 | pub struct Sha { 44 | cores: [Core; C], 45 | } 46 | 47 | impl Sha { 48 | pub fn new() -> Self { 49 | Sha { 50 | cores: [Core::::new(); C], 51 | } 52 | } 53 | 54 | /// ## Get the number of Cores in the ASIC 55 | /// 56 | /// ### Example 57 | /// ``` 58 | /// use bm13xx_asic::sha::Sha; 59 | /// 60 | /// let asic = Sha::<168, 672, 4, 4>::new(); // BM1397 61 | /// assert_eq!(asic.core_count(), 168); 62 | /// ``` 63 | pub const fn core_count(&self) -> usize { 64 | C 65 | } 66 | 67 | /// ## Get the number of Small Cores in the ASIC 68 | /// 69 | /// ### Example 70 | /// ``` 71 | /// use bm13xx_asic::sha::Sha; 72 | /// 73 | /// let asic = Sha::<168, 672, 4, 4>::new(); // BM1397 74 | /// assert_eq!(asic.small_core_count(), 672); 75 | /// ``` 76 | pub const fn small_core_count(&self) -> usize { 77 | SC 78 | } 79 | 80 | /// ## Get the number of Small Cores in a single Core of the ASIC 81 | /// 82 | /// ### Example 83 | /// ``` 84 | /// use bm13xx_asic::sha::Sha; 85 | /// 86 | /// let asic = Sha::<168, 672, 4, 4>::new(); // BM1397 87 | /// assert_eq!(asic.core_small_core_count(), 4); 88 | /// ``` 89 | pub const fn core_small_core_count(&self) -> usize { 90 | CSC 91 | } 92 | 93 | /// ## Get the number of Domains in the ASIC 94 | /// 95 | /// ### Example 96 | /// ``` 97 | /// use bm13xx_asic::sha::Sha; 98 | /// 99 | /// let asic = Sha::<168, 672, 4, 4>::new(); // BM1397 100 | /// assert_eq!(asic.domain_count(), 4); 101 | /// ``` 102 | pub const fn domain_count(&self) -> usize { 103 | D 104 | } 105 | } 106 | 107 | impl Default 108 | for Sha 109 | { 110 | fn default() -> Self { 111 | Self::new() 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/chip_nonce_offset.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # Chip Nonce Offset register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct ChipNonceOffset(pub u32); 6 | impl_boilerplate_for!(ChipNonceOffset); 7 | 8 | impl ChipNonceOffset { 9 | pub const ADDR: u8 = 0x0C; 10 | 11 | // const CNOV_OFFSET: u8 = 31; 12 | // const CNO_OFFSET: u8 = 0; 13 | 14 | // const CNOV_MASK: u32 = 0b1; 15 | pub const CNO_MASK: u32 = 0b111; 16 | } 17 | 18 | impl core::fmt::Display for ChipNonceOffset { 19 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 20 | f.debug_struct("ChipNonceOffset").finish() 21 | } 22 | } 23 | 24 | #[cfg(feature = "defmt")] 25 | impl defmt::Format for ChipNonceOffset { 26 | fn format(&self, fmt: defmt::Formatter) { 27 | defmt::write!(fmt, "ChipNonceOffset {{ }}",); 28 | } 29 | } 30 | 31 | /// # Chip Nonce Offset register 32 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 33 | pub struct ChipNonceOffsetV2(pub u32); 34 | impl_boilerplate_for!(ChipNonceOffsetV2); 35 | 36 | impl ChipNonceOffsetV2 { 37 | pub const ADDR: u8 = 0x0C; 38 | 39 | const CNOV_OFFSET: u8 = 31; 40 | const CNO_OFFSET: u8 = 0; 41 | 42 | const CNOV_MASK: u32 = 0b1; 43 | pub const CNO_MASK: u32 = 0xffff; 44 | 45 | /// ## Create a chip nonce offset for a given asic in a given chain. 46 | /// 47 | /// ### Example 48 | /// 49 | /// ``` 50 | /// use bm13xx_asic::register::ChipNonceOffsetV2; 51 | /// 52 | /// assert_eq!(ChipNonceOffsetV2::new(1, 65), ChipNonceOffsetV2(0x8000_03f1)); 53 | /// assert_eq!(ChipNonceOffsetV2::new(64, 65), ChipNonceOffsetV2(0x8000_fc10)); 54 | /// ``` 55 | pub fn new(asic_index: usize, chain_asic_num: usize) -> Self { 56 | if chain_asic_num == 0 { 57 | Self(0) 58 | } else { 59 | Self( 60 | (Self::CNOV_MASK << Self::CNOV_OFFSET) 61 | + (Self::CNO_MASK + 1) * (asic_index as u32) / (chain_asic_num as u32) 62 | + if asic_index > 0 { 1 } else { 0 }, 63 | ) 64 | } 65 | } 66 | 67 | /// ## Get the chip nonce offset value. 68 | /// 69 | /// This returns an `u16` with the offset value. 70 | /// 71 | /// ### Example 72 | /// 73 | /// ``` 74 | /// use bm13xx_asic::register::ChipNonceOffsetV2; 75 | /// 76 | /// assert_eq!(ChipNonceOffsetV2(0x8000_03f1).offset(), 0x03f1); 77 | /// ``` 78 | pub const fn offset(&self) -> u16 { 79 | ((self.0 >> Self::CNO_OFFSET) & Self::CNO_MASK) as u16 80 | } 81 | 82 | /// ## Get the chip nonce offset validity. 83 | /// 84 | /// This returns an `bool` with the offset validity. 85 | /// 86 | /// ### Example 87 | /// 88 | /// ``` 89 | /// use bm13xx_asic::register::ChipNonceOffsetV2; 90 | /// 91 | /// assert_eq!(ChipNonceOffsetV2(0x8000_03f1).offset(), 0x03f1); 92 | /// ``` 93 | pub const fn valid(&self) -> bool { 94 | (self.0 >> (Self::CNOV_OFFSET)) & Self::CNOV_MASK == Self::CNOV_MASK 95 | } 96 | } 97 | 98 | impl core::fmt::Display for ChipNonceOffsetV2 { 99 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 100 | f.debug_struct("ChipNonceOffsetV2").finish() 101 | } 102 | } 103 | 104 | #[cfg(feature = "defmt")] 105 | impl defmt::Format for ChipNonceOffsetV2 { 106 | fn format(&self, fmt: defmt::Formatter) { 107 | defmt::write!(fmt, "ChipNonceOffsetV2 {{ }}",); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /bm13xx-asic/src/core_register/hash_clock.rs: -------------------------------------------------------------------------------- 1 | use crate::core_register::CoreRegister; 2 | 3 | /// # Hash Clock Ctrl core register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct HashClockCtrl(pub u8); 6 | impl_boilerplate_for_core_reg!(HashClockCtrl); 7 | 8 | impl HashClockCtrl { 9 | pub const ID: u8 = 5; 10 | 11 | const EN_OFFSET: u8 = 6; 12 | const PLL_SRC_OFFSET: u8 = 0; 13 | 14 | const EN_MASK: u8 = 0b1; 15 | const PLL_SRC_MASK: u8 = 0b1; 16 | 17 | /// ## Handle the enable field. 18 | /// 19 | /// ### Example 20 | /// ``` 21 | /// use bm13xx_asic::core_register::HashClockCtrl; 22 | /// 23 | /// let mut hash_clock_ctrl = HashClockCtrl(0x40); // BM1366 default value 24 | /// assert!(hash_clock_ctrl.enabled()); 25 | /// assert!(!hash_clock_ctrl.disable().enabled()); 26 | /// assert!(hash_clock_ctrl.enable().enabled()); 27 | /// ``` 28 | pub const fn enabled(&self) -> bool { 29 | (self.0 >> Self::EN_OFFSET) & Self::EN_MASK != 0 30 | } 31 | pub fn enable(&mut self) -> &mut Self { 32 | self.0 |= Self::EN_MASK << Self::EN_OFFSET; 33 | self 34 | } 35 | pub fn disable(&mut self) -> &mut Self { 36 | self.0 &= !(Self::EN_MASK << Self::EN_OFFSET); 37 | self 38 | } 39 | 40 | /// ## Handle the PLL source field. 41 | /// 42 | /// ### Example 43 | /// ``` 44 | /// use bm13xx_asic::core_register::HashClockCtrl; 45 | /// 46 | /// let mut hash_clock_ctrl = HashClockCtrl(0x40); // BM1366 default value 47 | /// assert_eq!(hash_clock_ctrl.pll_source(), 0); 48 | /// assert_eq!(hash_clock_ctrl.set_pll_source(1).pll_source(), 1); // max value 49 | /// assert_eq!(hash_clock_ctrl.set_pll_source(2).pll_source(), 0); // out of bound value 50 | /// ``` 51 | pub const fn pll_source(&self) -> u8 { 52 | (self.0 >> Self::PLL_SRC_OFFSET) & Self::PLL_SRC_MASK 53 | } 54 | pub fn set_pll_source(&mut self, pll_id: u8) -> &mut Self { 55 | self.0 &= !(Self::PLL_SRC_MASK << Self::PLL_SRC_OFFSET); 56 | self.0 |= (pll_id & Self::PLL_SRC_MASK) << Self::PLL_SRC_OFFSET; 57 | self 58 | } 59 | } 60 | 61 | impl ::core::fmt::Display for HashClockCtrl { 62 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 63 | f.debug_struct("HashClockCtrl") 64 | .field("enabled", &self.enabled()) 65 | .field("pll_source", &self.pll_source()) 66 | .finish() 67 | } 68 | } 69 | 70 | #[cfg(feature = "defmt")] 71 | impl defmt::Format for HashClockCtrl { 72 | fn format(&self, fmt: defmt::Formatter) { 73 | defmt::write!( 74 | fmt, 75 | "HashClockCtrl {{ enabled: {}, pll_source: {} }}", 76 | self.enabled(), 77 | self.pll_source(), 78 | ); 79 | } 80 | } 81 | 82 | /// # Hash Clock Counter core register 83 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 84 | pub struct HashClockCounter(pub u8); 85 | impl_boilerplate_for_core_reg!(HashClockCounter); 86 | 87 | impl HashClockCounter { 88 | pub const ID: u8 = 6; 89 | 90 | // const CLOCK_CNT_OFFSET: u8 = 0; 91 | 92 | // const CLOCK_CNT_MASK: u8 = 0xff; 93 | } 94 | 95 | impl ::core::fmt::Display for HashClockCounter { 96 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 97 | f.debug_struct("HashClockCounter").finish() 98 | } 99 | } 100 | 101 | #[cfg(feature = "defmt")] 102 | impl defmt::Format for HashClockCounter { 103 | fn format(&self, fmt: defmt::Formatter) { 104 | defmt::write!(fmt, "HashClockCounter {{ }}",); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/uart_relay.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # UART Relay register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct UARTRelay(pub u32); 6 | impl_boilerplate_for!(UARTRelay); 7 | 8 | impl UARTRelay { 9 | pub const ADDR: u8 = 0x2C; 10 | 11 | const GAP_CNT_OFFSET: u8 = 16; 12 | const RO_REL_EN_OFFSET: u8 = 1; 13 | const CO_REL_EN_OFFSET: u8 = 0; 14 | 15 | const GAP_CNT_MASK: u32 = 0xffff; 16 | const RO_REL_EN_MASK: u32 = 0b1; 17 | const CO_REL_EN_MASK: u32 = 0b1; 18 | 19 | /// ## Handle the GAP_CNT field. 20 | /// 21 | /// Get and set the GAP_CNT value. 22 | /// 23 | /// ### Example 24 | /// 25 | /// ``` 26 | /// use bm13xx_asic::register::UARTRelay; 27 | /// 28 | /// let mut uart_relay = UARTRelay(0x000f_0000); // BM1366 default value 29 | /// assert_eq!(uart_relay.gap_cnt(), 0x000f); 30 | /// assert_eq!(uart_relay.set_gap_cnt(0).gap_cnt(), 0); // min value 31 | /// assert_eq!(uart_relay.set_gap_cnt(0xffff).gap_cnt(), 0xffff); // max value 32 | /// ``` 33 | pub const fn gap_cnt(&self) -> u16 { 34 | ((self.0 >> Self::GAP_CNT_OFFSET) & Self::GAP_CNT_MASK) as u16 35 | } 36 | pub fn set_gap_cnt(&mut self, gap_cnt: u16) -> &mut Self { 37 | self.0 &= !(Self::GAP_CNT_MASK << Self::GAP_CNT_OFFSET); 38 | self.0 |= ((gap_cnt as u32) & Self::GAP_CNT_MASK) << Self::GAP_CNT_OFFSET; 39 | self 40 | } 41 | 42 | /// ## Handle the RO_REL_EN field. 43 | /// 44 | /// ### Example 45 | /// ``` 46 | /// use bm13xx_asic::register::UARTRelay; 47 | /// 48 | /// let mut uart_relay = UARTRelay(0x000f_0000); // BM1366 default value 49 | /// assert!(!uart_relay.ro_relay_enabled()); 50 | /// assert!(uart_relay.enable_ro_relay().ro_relay_enabled()); 51 | /// assert!(!uart_relay.disable_ro_relay().ro_relay_enabled()); 52 | /// ``` 53 | pub const fn ro_relay_enabled(&self) -> bool { 54 | (self.0 >> Self::RO_REL_EN_OFFSET) & Self::RO_REL_EN_MASK != 0 55 | } 56 | pub fn enable_ro_relay(&mut self) -> &mut Self { 57 | self.0 |= Self::RO_REL_EN_MASK << Self::RO_REL_EN_OFFSET; 58 | self 59 | } 60 | pub fn disable_ro_relay(&mut self) -> &mut Self { 61 | self.0 &= !(Self::RO_REL_EN_MASK << Self::RO_REL_EN_OFFSET); 62 | self 63 | } 64 | 65 | /// ## Handle the CO_REL_EN field. 66 | /// 67 | /// ### Example 68 | /// ``` 69 | /// use bm13xx_asic::register::UARTRelay; 70 | /// 71 | /// let mut uart_relay = UARTRelay(0x000f_0000); // BM1366 default value 72 | /// assert!(!uart_relay.co_relay_enabled()); 73 | /// assert!(uart_relay.enable_co_relay().co_relay_enabled()); 74 | /// assert!(!uart_relay.disable_co_relay().co_relay_enabled()); 75 | /// ``` 76 | pub const fn co_relay_enabled(&self) -> bool { 77 | (self.0 >> Self::CO_REL_EN_OFFSET) & Self::CO_REL_EN_MASK != 0 78 | } 79 | pub fn enable_co_relay(&mut self) -> &mut Self { 80 | self.0 |= Self::CO_REL_EN_MASK << Self::CO_REL_EN_OFFSET; 81 | self 82 | } 83 | pub fn disable_co_relay(&mut self) -> &mut Self { 84 | self.0 &= !(Self::CO_REL_EN_MASK << Self::CO_REL_EN_OFFSET); 85 | self 86 | } 87 | } 88 | 89 | impl core::fmt::Display for UARTRelay { 90 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 91 | f.debug_struct("UARTRelay").finish() 92 | } 93 | } 94 | 95 | #[cfg(feature = "defmt")] 96 | impl defmt::Format for UARTRelay { 97 | fn format(&self, fmt: defmt::Formatter) { 98 | defmt::write!(fmt, "UARTRelay {{ }}",); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/analog_mux.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # Analog Mux Control register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct AnalogMuxControl(pub u32); 6 | impl_boilerplate_for!(AnalogMuxControl); 7 | 8 | impl AnalogMuxControl { 9 | pub const ADDR: u8 = 0x54; 10 | 11 | const DIODE_VDD_MUX_SEL_OFFSET: u8 = 0; 12 | 13 | const DIODE_VDD_MUX_SEL_MASK: u32 = 0b111; 14 | 15 | /// ## Handle the `DIODE_VDD_MUX_SEL` field. 16 | /// 17 | /// Get and set the `DIODE_VDD_MUX_SEL` value. 18 | /// 19 | /// ### Example 20 | /// ``` 21 | /// use bm13xx_asic::register::AnalogMuxControl; 22 | /// 23 | /// let mut ana_mux = AnalogMuxControl(0x0000_0000); // BM1397 default value 24 | /// assert_eq!(ana_mux.diode_vdd_mux_sel(), 0); 25 | /// assert_eq!(ana_mux.set_diode_vdd_mux_sel(3).diode_vdd_mux_sel(), 3); 26 | /// assert_eq!(ana_mux.set_diode_vdd_mux_sel(0x7).diode_vdd_mux_sel(), 0x7); // max value 27 | /// assert_eq!(ana_mux.set_diode_vdd_mux_sel(0x8).diode_vdd_mux_sel(), 0); // out of bound value 28 | /// ``` 29 | pub const fn diode_vdd_mux_sel(&self) -> u8 { 30 | ((self.0 >> Self::DIODE_VDD_MUX_SEL_OFFSET) & Self::DIODE_VDD_MUX_SEL_MASK) as u8 31 | } 32 | pub fn set_diode_vdd_mux_sel(&mut self, mux_sel: u8) -> &mut Self { 33 | self.0 &= !(Self::DIODE_VDD_MUX_SEL_MASK << Self::DIODE_VDD_MUX_SEL_OFFSET); 34 | self.0 |= 35 | ((mux_sel as u32) & Self::DIODE_VDD_MUX_SEL_MASK) << Self::DIODE_VDD_MUX_SEL_OFFSET; 36 | self 37 | } 38 | } 39 | 40 | impl core::fmt::Display for AnalogMuxControl { 41 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 42 | f.debug_struct("AnalogMuxControl") 43 | .field("diode_vdd_mux_sel", &self.diode_vdd_mux_sel()) 44 | .finish() 45 | } 46 | } 47 | 48 | #[cfg(feature = "defmt")] 49 | impl defmt::Format for AnalogMuxControl { 50 | fn format(&self, fmt: defmt::Formatter) { 51 | defmt::write!( 52 | fmt, 53 | "AnalogMuxControlV2 {{ diode_vdd_mux_sel: {} }}", 54 | self.diode_vdd_mux_sel(), 55 | ); 56 | } 57 | } 58 | 59 | /// # Analog Mux Control register 60 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 61 | pub struct AnalogMuxControlV2(pub u32); 62 | impl_boilerplate_for!(AnalogMuxControlV2); 63 | 64 | impl AnalogMuxControlV2 { 65 | pub const ADDR: u8 = 0x54; 66 | 67 | const DIODE_VDD_MUX_SEL_OFFSET: u8 = 0; 68 | 69 | const DIODE_VDD_MUX_SEL_MASK: u32 = 0b1111; 70 | 71 | /// ## Handle the `DIODE_VDD_MUX_SEL` field. 72 | /// 73 | /// Get and set the `DIODE_VDD_MUX_SEL` value. 74 | /// 75 | /// ### Example 76 | /// ``` 77 | /// use bm13xx_asic::register::AnalogMuxControlV2; 78 | /// 79 | /// let mut ana_mux = AnalogMuxControlV2(0x0000_0000); // BM1366 default value 80 | /// assert_eq!(ana_mux.diode_vdd_mux_sel(), 0); 81 | /// assert_eq!(ana_mux.set_diode_vdd_mux_sel(3).diode_vdd_mux_sel(), 3); // BM1366 init() value 82 | /// assert_eq!(ana_mux.set_diode_vdd_mux_sel(0xf).diode_vdd_mux_sel(), 0xf); // max value 83 | /// assert_eq!(ana_mux.set_diode_vdd_mux_sel(0x10).diode_vdd_mux_sel(), 0); // out of bound value 84 | /// ``` 85 | pub const fn diode_vdd_mux_sel(&self) -> u8 { 86 | ((self.0 >> Self::DIODE_VDD_MUX_SEL_OFFSET) & Self::DIODE_VDD_MUX_SEL_MASK) as u8 87 | } 88 | pub fn set_diode_vdd_mux_sel(&mut self, mux_sel: u8) -> &mut Self { 89 | self.0 &= !(Self::DIODE_VDD_MUX_SEL_MASK << Self::DIODE_VDD_MUX_SEL_OFFSET); 90 | self.0 |= 91 | ((mux_sel as u32) & Self::DIODE_VDD_MUX_SEL_MASK) << Self::DIODE_VDD_MUX_SEL_OFFSET; 92 | self 93 | } 94 | } 95 | 96 | impl core::fmt::Display for AnalogMuxControlV2 { 97 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 98 | f.debug_struct("AnalogMuxControlV2") 99 | .field("diode_vdd_mux_sel", &self.diode_vdd_mux_sel()) 100 | .finish() 101 | } 102 | } 103 | 104 | #[cfg(feature = "defmt")] 105 | impl defmt::Format for AnalogMuxControlV2 { 106 | fn format(&self, fmt: defmt::Formatter) { 107 | defmt::write!( 108 | fmt, 109 | "AnalogMuxControlV2 {{ diode_vdd_mux_sel: {} }}", 110 | self.diode_vdd_mux_sel(), 111 | ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/soft_reset.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # SoftResetControl register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct SoftResetControl(pub u32); 6 | impl_boilerplate_for!(SoftResetControl); 7 | 8 | impl SoftResetControl { 9 | pub const ADDR: u8 = 0xA8; 10 | 11 | const B10_OFFSET: u8 = 10; 12 | const B8_OFFSET: u8 = 8; 13 | const B7_4_OFFSET: u8 = 4; 14 | const B3_0_OFFSET: u8 = 0; 15 | 16 | const B10_MASK: u32 = 0x1; 17 | const B8_MASK: u32 = 0x1; 18 | const B7_4_MASK: u32 = 0xf; 19 | const B3_0_MASK: u32 = 0xf; 20 | 21 | /// ## Handle the B10 field. 22 | /// 23 | /// Get and set the B10 state. 24 | /// 25 | /// ### Example 26 | /// 27 | /// ``` 28 | /// use bm13xx_asic::register::SoftResetControl; 29 | /// 30 | /// let mut sft_rst_ctrl = SoftResetControl(0x0007_0000); // BM1366 default value 31 | /// assert!(!sft_rst_ctrl.is_b10()); 32 | /// assert!(sft_rst_ctrl.set_b10().is_b10()); 33 | /// assert!(!sft_rst_ctrl.clr_b10().is_b10()); 34 | /// ``` 35 | pub const fn is_b10(&self) -> bool { 36 | (self.0 >> Self::B10_OFFSET) & Self::B10_MASK == Self::B10_MASK 37 | } 38 | pub fn set_b10(&mut self) -> &mut Self { 39 | self.0 |= Self::B10_MASK << Self::B10_OFFSET; 40 | self 41 | } 42 | pub fn clr_b10(&mut self) -> &mut Self { 43 | self.0 &= !(Self::B10_MASK << Self::B10_OFFSET); 44 | self 45 | } 46 | 47 | /// ## Handle the B8 field. 48 | /// 49 | /// Get and set the B8 state. 50 | /// 51 | /// ### Example 52 | /// 53 | /// ``` 54 | /// use bm13xx_asic::register::SoftResetControl; 55 | /// 56 | /// let mut sft_rst_ctrl = SoftResetControl(0x0007_0000); // BM1366 default value 57 | /// assert!(!sft_rst_ctrl.is_b8()); 58 | /// assert!(sft_rst_ctrl.set_b8().is_b8()); 59 | /// assert!(!sft_rst_ctrl.clr_b8().is_b8()); 60 | /// ``` 61 | pub const fn is_b8(&self) -> bool { 62 | (self.0 >> Self::B8_OFFSET) & Self::B8_MASK == Self::B8_MASK 63 | } 64 | pub fn set_b8(&mut self) -> &mut Self { 65 | self.0 |= Self::B8_MASK << Self::B8_OFFSET; 66 | self 67 | } 68 | pub fn clr_b8(&mut self) -> &mut Self { 69 | self.0 &= !(Self::B8_MASK << Self::B8_OFFSET); 70 | self 71 | } 72 | 73 | /// ## Handle the B\[7:4\] field. 74 | /// 75 | /// Get and set the B\[7:4\] value. 76 | /// 77 | /// ### Example 78 | /// 79 | /// ``` 80 | /// use bm13xx_asic::register::SoftResetControl; 81 | /// 82 | /// let mut sft_rst_ctrl = SoftResetControl(0x0007_0000); // BM1366 default value 83 | /// assert_eq!(sft_rst_ctrl.b7_4(), 0); 84 | /// assert_eq!(sft_rst_ctrl.set_b7_4(0xf).b7_4(), 0xf); // max value 85 | /// assert_eq!(sft_rst_ctrl.set_b7_4(0x10).b7_4(), 0); // out of bound value 86 | /// ``` 87 | pub const fn b7_4(&self) -> u8 { 88 | ((self.0 >> Self::B7_4_OFFSET) & Self::B7_4_MASK) as u8 89 | } 90 | pub fn set_b7_4(&mut self, b7_4: u8) -> &mut Self { 91 | self.0 &= !(Self::B7_4_MASK << Self::B7_4_OFFSET); 92 | self.0 |= ((b7_4 as u32) & Self::B7_4_MASK) << Self::B7_4_OFFSET; 93 | self 94 | } 95 | 96 | /// ## Handle the B\[3:0\] field. 97 | /// 98 | /// Get and set the B\[3:0\] value. 99 | /// 100 | /// ### Example 101 | /// 102 | /// ``` 103 | /// use bm13xx_asic::register::SoftResetControl; 104 | /// 105 | /// let mut sft_rst_ctrl = SoftResetControl(0x0007_0000); // BM1366 default value 106 | /// assert_eq!(sft_rst_ctrl.b3_0(), 0); 107 | /// assert_eq!(sft_rst_ctrl.set_b3_0(0xf).b3_0(), 0xf); // max value 108 | /// assert_eq!(sft_rst_ctrl.set_b3_0(0x10).b3_0(), 0); // out of bound value 109 | /// ``` 110 | pub const fn b3_0(&self) -> u8 { 111 | ((self.0 >> Self::B3_0_OFFSET) & Self::B3_0_MASK) as u8 112 | } 113 | pub fn set_b3_0(&mut self, b3_0: u8) -> &mut Self { 114 | self.0 &= !(Self::B3_0_MASK << Self::B3_0_OFFSET); 115 | self.0 |= ((b3_0 as u32) & Self::B3_0_MASK) << Self::B3_0_OFFSET; 116 | self 117 | } 118 | } 119 | 120 | impl core::fmt::Display for SoftResetControl { 121 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 122 | f.debug_struct("RegA8").finish() 123 | } 124 | } 125 | 126 | #[cfg(feature = "defmt")] 127 | impl defmt::Format for SoftResetControl { 128 | fn format(&self, fmt: defmt::Formatter) { 129 | defmt::write!(fmt, "RegA8 {{ }}",); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/core_register.rs: -------------------------------------------------------------------------------- 1 | use crate::{core_register::CoreRegister, register::Register}; 2 | 3 | /// # Core Register Control register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct CoreRegisterControl(pub u32); 6 | impl_boilerplate_for!(CoreRegisterControl); 7 | 8 | impl CoreRegisterControl { 9 | pub const ADDR: u8 = 0x3C; 10 | 11 | const DO_CMD_OFFSET: u8 = 31; 12 | const CORE_ID_OFFSET: u8 = 16; 13 | const RD_WR_OFFSET: u8 = 15; 14 | const CORE_REG_ID_OFFSET: u8 = 8; 15 | const CORE_REG_VAL_OFFSET: u8 = 0; 16 | 17 | const DO_CMD_MASK: u32 = 0b1; 18 | const RD_WR_MASK: u32 = 0b1; 19 | const CORE_ID_MASK: u32 = 0x1ff; 20 | const CORE_REG_ID_MASK: u32 = 0x1f; 21 | const CORE_REG_VAL_MASK: u32 = 0xff; 22 | 23 | /// ## Set CoreRegisterControl for a Core Register Read. 24 | /// 25 | /// ### Example 26 | /// 27 | /// ``` 28 | /// use bm13xx_asic::register::{CoreRegisterControl, Register}; 29 | /// use bm13xx_asic::core_register::{ClockDelayCtrl}; 30 | /// 31 | /// assert_eq!(CoreRegisterControl::read_core_reg(0, ClockDelayCtrl(0x74)), 0x8000_00ff); 32 | /// ``` 33 | pub fn read_core_reg(core_id: u8, core_reg: impl CoreRegister) -> u32 { 34 | (Self::DO_CMD_MASK << Self::DO_CMD_OFFSET) 35 | | (((core_id as u32) & Self::CORE_ID_MASK) << Self::CORE_ID_OFFSET) 36 | | (((core_reg.id() as u32) & Self::CORE_REG_ID_MASK) << Self::CORE_REG_ID_OFFSET) 37 | | Self::CORE_REG_VAL_MASK 38 | } 39 | /// ## Set CoreRegisterControl for a Core Register Write. 40 | /// 41 | /// ### Example 42 | /// 43 | /// ``` 44 | /// use bm13xx_asic::register::{CoreRegisterControl, Register}; 45 | /// use bm13xx_asic::core_register::{ClockDelayCtrl}; 46 | /// 47 | /// assert_eq!(CoreRegisterControl::write_core_reg(0, ClockDelayCtrl(0x74)), 0x8000_8074); 48 | pub fn write_core_reg(core_id: u8, core_reg: impl CoreRegister) -> u32 { 49 | (Self::DO_CMD_MASK << Self::DO_CMD_OFFSET) 50 | | (Self::RD_WR_MASK << Self::RD_WR_OFFSET) 51 | | (((core_id as u32) & Self::CORE_ID_MASK) << Self::CORE_ID_OFFSET) 52 | | (((core_reg.id() as u32) & Self::CORE_REG_ID_MASK) << Self::CORE_REG_ID_OFFSET) 53 | | (((core_reg.val() as u32) & Self::CORE_REG_VAL_MASK) << Self::CORE_REG_VAL_OFFSET) 54 | } 55 | } 56 | 57 | impl core::fmt::Display for CoreRegisterControl { 58 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 59 | f.debug_struct("CoreRegisterControl").finish() 60 | } 61 | } 62 | 63 | #[cfg(feature = "defmt")] 64 | impl defmt::Format for CoreRegisterControl { 65 | fn format(&self, fmt: defmt::Formatter) { 66 | defmt::write!(fmt, "CoreRegisterControl {{ }}",); 67 | } 68 | } 69 | 70 | /// # Core Register Value register 71 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 72 | pub struct CoreRegisterValue(pub u32); 73 | impl_boilerplate_for!(CoreRegisterValue); 74 | 75 | impl CoreRegisterValue { 76 | pub const ADDR: u8 = 0x40; 77 | 78 | const CORE_ID_OFFSET: u8 = 16; 79 | const FOUND_OFFSET: u8 = 8; 80 | const CORE_REG_VAL_OFFSET: u8 = 0; 81 | 82 | const CORE_ID_MASK: u32 = 0x1ff; 83 | const FOUND_MASK: u32 = 0xff; 84 | const CORE_REG_VAL_MASK: u32 = 0xff; 85 | 86 | /// ## Get the CORE_ID. 87 | /// 88 | /// This returns an `u16` with the CORE_ID value. 89 | /// 90 | /// ### Example 91 | /// 92 | /// ``` 93 | /// use bm13xx_asic::register::CoreRegisterValue; 94 | /// 95 | /// let crv: CoreRegisterValue = CoreRegisterValue(0x0001_1234); 96 | /// assert_eq!(crv.core_id(), 0x0001); 97 | /// ``` 98 | pub const fn core_id(&self) -> u16 { 99 | ((self.0 >> Self::CORE_ID_OFFSET) & Self::CORE_ID_MASK) as u16 100 | } 101 | 102 | /// ## Get the FOUND. 103 | /// 104 | /// This returns an `u8` with the FOUND value. 105 | /// 106 | /// ### Example 107 | /// 108 | /// ``` 109 | /// use bm13xx_asic::register::CoreRegisterValue; 110 | /// 111 | /// let crv: CoreRegisterValue = CoreRegisterValue(0x0001_1234); 112 | /// assert_eq!(crv.found(), 0x12); 113 | /// ``` 114 | pub const fn found(&self) -> u8 { 115 | ((self.0 >> Self::FOUND_OFFSET) & Self::FOUND_MASK) as u8 116 | } 117 | 118 | /// ## Get the CORE_REG_VAL. 119 | /// 120 | /// This returns an `u8` with the CORE_REG_VAL value. 121 | /// 122 | /// ### Example 123 | /// 124 | /// ``` 125 | /// use bm13xx_asic::register::CoreRegisterValue; 126 | /// 127 | /// let crv: CoreRegisterValue = CoreRegisterValue(0x0001_1234); 128 | /// assert_eq!(crv.core_reg_val(), 0x34); 129 | /// ``` 130 | pub const fn core_reg_val(&self) -> u8 { 131 | ((self.0 >> Self::CORE_REG_VAL_OFFSET) & Self::CORE_REG_VAL_MASK) as u8 132 | } 133 | } 134 | 135 | impl core::fmt::Display for CoreRegisterValue { 136 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 137 | f.debug_struct("CoreRegisterValue").finish() 138 | } 139 | } 140 | 141 | #[cfg(feature = "defmt")] 142 | impl defmt::Format for CoreRegisterValue { 143 | fn format(&self, fmt: defmt::Formatter) { 144 | defmt::write!(fmt, "CoreRegisterValue {{ }}",); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /bm13xx-chain/examples/cli.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use bm1366::BM1366; 4 | use bm13xx_chain::Chain; 5 | 6 | use embedded_hal_async::delay::DelayNs; 7 | use fugit::HertzU64; 8 | use inquire::Select; 9 | use linux_embedded_hal::SysfsPin; 10 | use std::{env, error::Error, time::Duration}; 11 | use tokio::time::sleep; 12 | use tokio_adapter::FromTokio; 13 | use tokio_serial::SerialStream; 14 | 15 | struct Delay; 16 | 17 | impl DelayNs for Delay { 18 | async fn delay_ns(&mut self, n: u32) { 19 | sleep(Duration::from_nanos(n.into())).await; 20 | } 21 | } 22 | 23 | #[tokio::main] 24 | async fn main() -> Result<(), Box> { 25 | env_logger::init(); 26 | 27 | let mut args: Vec = env::args().collect(); 28 | 29 | // use the first arg as serial port, query interactively if not given 30 | let port = if args.len() == 2 { 31 | args.pop().unwrap() 32 | } else { 33 | let ports = tokio_serial::available_ports()?; 34 | let ports: Vec = ports.into_iter().map(|p| p.port_name).collect(); 35 | Select::new("Which serial port should be used?", ports).prompt()? 36 | }; 37 | 38 | let builder = tokio_serial::new(port, 115_200).timeout(Duration::from_millis(50)); 39 | let serial = SerialStream::open(&builder)?; 40 | let uart = FromTokio::new(serial); 41 | 42 | let bm1366 = BM1366::default(); 43 | let fake_busy = SysfsPin::new(127); 44 | let fake_reset = SysfsPin::new(128); 45 | 46 | let mut chain = Chain::enumerate(bm1366, uart, fake_busy, fake_reset, Delay).await?; 47 | println!("Enumerated {} asics", chain.asic_cnt); 48 | println!("Interval: {}", chain.asic_addr_interval); 49 | chain.init(256).await?; 50 | chain.change_baudrate(1_000_000).await?; 51 | chain.reset_all_cores().await?; 52 | chain.set_hash_freq(HertzU64::MHz(525)).await?; 53 | chain.enable_version_rolling(0x1fff_e000).await?; 54 | Ok(()) 55 | } 56 | 57 | mod tokio_adapter { 58 | //! Adapters to/from `tokio::io` traits. 59 | 60 | use core::future::poll_fn; 61 | use core::pin::Pin; 62 | use core::task::Poll; 63 | 64 | /// Adapter from `tokio::io` traits. 65 | #[derive(Clone)] 66 | pub struct FromTokio { 67 | inner: T, 68 | } 69 | 70 | impl FromTokio { 71 | /// Create a new adapter. 72 | pub fn new(inner: T) -> Self { 73 | Self { inner } 74 | } 75 | 76 | /// Consume the adapter, returning the inner object. 77 | pub fn into_inner(self) -> T { 78 | self.inner 79 | } 80 | } 81 | 82 | impl FromTokio { 83 | /// Borrow the inner object. 84 | pub fn inner(&self) -> &T { 85 | &self.inner 86 | } 87 | 88 | /// Mutably borrow the inner object. 89 | pub fn inner_mut(&mut self) -> &mut T { 90 | &mut self.inner 91 | } 92 | } 93 | 94 | impl embedded_io::ErrorType for FromTokio { 95 | type Error = std::io::Error; 96 | } 97 | 98 | impl embedded_io_async::ReadReady for FromTokio { 99 | fn read_ready(&mut self) -> Result { 100 | Ok(true) // TODO: fix this 101 | } 102 | } 103 | 104 | impl embedded_io_async::Read for FromTokio { 105 | async fn read(&mut self, buf: &mut [u8]) -> Result { 106 | // The current tokio implementation (https://github.com/tokio-rs/tokio/blob/tokio-1.33.0/tokio/src/io/poll_evented.rs#L165) 107 | // does not consider the case of buf.is_empty() as a special case, 108 | // which can cause Poll::Pending to be returned at the end of the stream when called with an empty buffer. 109 | // This poll will, however, never become ready, as no more bytes will be received. 110 | if buf.is_empty() { 111 | return Ok(0); 112 | } 113 | 114 | poll_fn(|cx| { 115 | let mut buf = tokio::io::ReadBuf::new(buf); 116 | match Pin::new(&mut self.inner).poll_read(cx, &mut buf) { 117 | Poll::Ready(r) => match r { 118 | Ok(()) => Poll::Ready(Ok(buf.filled().len())), 119 | Err(e) => Poll::Ready(Err(e)), 120 | }, 121 | Poll::Pending => Poll::Pending, 122 | } 123 | }) 124 | .await 125 | } 126 | } 127 | 128 | impl embedded_io_async::Write for FromTokio { 129 | async fn write(&mut self, buf: &[u8]) -> Result { 130 | match poll_fn(|cx| Pin::new(&mut self.inner).poll_write(cx, buf)).await { 131 | Ok(0) if !buf.is_empty() => Err(std::io::ErrorKind::WriteZero.into()), 132 | Ok(n) => Ok(n), 133 | Err(e) => Err(e), 134 | } 135 | } 136 | 137 | async fn flush(&mut self) -> Result<(), Self::Error> { 138 | poll_fn(|cx| Pin::new(&mut self.inner).poll_flush(cx)).await 139 | } 140 | } 141 | 142 | impl bm13xx_chain::Baud for FromTokio { 143 | fn set_baudrate(&mut self, baudrate: u32) { 144 | self.inner_mut().set_baud_rate(baudrate).unwrap() 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /bm1366/src/fmt.rs: -------------------------------------------------------------------------------- 1 | #![macro_use] 2 | #![allow(unused_macros)] 3 | 4 | #[cfg(all(feature = "defmt", feature = "log"))] 5 | compile_error!("You may not enable both `defmt` and `log` features."); 6 | 7 | macro_rules! assert { 8 | ($($x:tt)*) => { 9 | { 10 | #[cfg(not(feature = "defmt"))] 11 | ::core::assert!($($x)*); 12 | #[cfg(feature = "defmt")] 13 | ::defmt::assert!($($x)*); 14 | } 15 | }; 16 | } 17 | 18 | macro_rules! assert_eq { 19 | ($($x:tt)*) => { 20 | { 21 | #[cfg(not(feature = "defmt"))] 22 | ::core::assert_eq!($($x)*); 23 | #[cfg(feature = "defmt")] 24 | ::defmt::assert_eq!($($x)*); 25 | } 26 | }; 27 | } 28 | 29 | macro_rules! assert_ne { 30 | ($($x:tt)*) => { 31 | { 32 | #[cfg(not(feature = "defmt"))] 33 | ::core::assert_ne!($($x)*); 34 | #[cfg(feature = "defmt")] 35 | ::defmt::assert_ne!($($x)*); 36 | } 37 | }; 38 | } 39 | 40 | macro_rules! debug_assert { 41 | ($($x:tt)*) => { 42 | { 43 | #[cfg(not(feature = "defmt"))] 44 | ::core::debug_assert!($($x)*); 45 | #[cfg(feature = "defmt")] 46 | ::defmt::debug_assert!($($x)*); 47 | } 48 | }; 49 | } 50 | 51 | macro_rules! debug_assert_eq { 52 | ($($x:tt)*) => { 53 | { 54 | #[cfg(not(feature = "defmt"))] 55 | ::core::debug_assert_eq!($($x)*); 56 | #[cfg(feature = "defmt")] 57 | ::defmt::debug_assert_eq!($($x)*); 58 | } 59 | }; 60 | } 61 | 62 | macro_rules! debug_assert_ne { 63 | ($($x:tt)*) => { 64 | { 65 | #[cfg(not(feature = "defmt"))] 66 | ::core::debug_assert_ne!($($x)*); 67 | #[cfg(feature = "defmt")] 68 | ::defmt::debug_assert_ne!($($x)*); 69 | } 70 | }; 71 | } 72 | 73 | macro_rules! todo { 74 | ($($x:tt)*) => { 75 | { 76 | #[cfg(not(feature = "defmt"))] 77 | ::core::todo!($($x)*); 78 | #[cfg(feature = "defmt")] 79 | ::defmt::todo!($($x)*); 80 | } 81 | }; 82 | } 83 | 84 | macro_rules! unreachable { 85 | ($($x:tt)*) => { 86 | { 87 | #[cfg(not(feature = "defmt"))] 88 | ::core::unreachable!($($x)*); 89 | #[cfg(feature = "defmt")] 90 | ::defmt::unreachable!($($x)*); 91 | } 92 | }; 93 | } 94 | 95 | macro_rules! panic { 96 | ($($x:tt)*) => { 97 | { 98 | #[cfg(not(feature = "defmt"))] 99 | ::core::panic!($($x)*); 100 | #[cfg(feature = "defmt")] 101 | ::defmt::panic!($($x)*); 102 | } 103 | }; 104 | } 105 | 106 | macro_rules! trace { 107 | ($s:literal $(, $x:expr)* $(,)?) => { 108 | { 109 | #[cfg(feature = "log")] 110 | ::log::trace!($s $(, $x)*); 111 | #[cfg(feature = "defmt")] 112 | ::defmt::trace!($s $(, $x)*); 113 | #[cfg(not(any(feature = "log", feature="defmt")))] 114 | let _ = ($( & $x ),*); 115 | } 116 | }; 117 | } 118 | 119 | macro_rules! debug { 120 | ($s:literal $(, $x:expr)* $(,)?) => { 121 | { 122 | #[cfg(feature = "log")] 123 | ::log::debug!($s $(, $x)*); 124 | #[cfg(feature = "defmt")] 125 | ::defmt::debug!($s $(, $x)*); 126 | #[cfg(not(any(feature = "log", feature="defmt")))] 127 | let _ = ($( & $x ),*); 128 | } 129 | }; 130 | } 131 | 132 | macro_rules! info { 133 | ($s:literal $(, $x:expr)* $(,)?) => { 134 | { 135 | #[cfg(feature = "log")] 136 | ::log::info!($s $(, $x)*); 137 | #[cfg(feature = "defmt")] 138 | ::defmt::info!($s $(, $x)*); 139 | #[cfg(not(any(feature = "log", feature="defmt")))] 140 | let _ = ($( & $x ),*); 141 | } 142 | }; 143 | } 144 | 145 | macro_rules! warn { 146 | ($s:literal $(, $x:expr)* $(,)?) => { 147 | { 148 | #[cfg(feature = "log")] 149 | ::log::warn!($s $(, $x)*); 150 | #[cfg(feature = "defmt")] 151 | ::defmt::warn!($s $(, $x)*); 152 | #[cfg(not(any(feature = "log", feature="defmt")))] 153 | let _ = ($( & $x ),*); 154 | } 155 | }; 156 | } 157 | 158 | macro_rules! error { 159 | ($s:literal $(, $x:expr)* $(,)?) => { 160 | { 161 | #[cfg(feature = "log")] 162 | ::log::error!($s $(, $x)*); 163 | #[cfg(feature = "defmt")] 164 | ::defmt::error!($s $(, $x)*); 165 | #[cfg(not(any(feature = "log", feature="defmt")))] 166 | let _ = ($( & $x ),*); 167 | } 168 | }; 169 | } 170 | 171 | #[cfg(feature = "defmt")] 172 | macro_rules! unwrap { 173 | ($($x:tt)*) => { 174 | ::defmt::unwrap!($($x)*) 175 | }; 176 | } 177 | 178 | #[cfg(not(feature = "defmt"))] 179 | macro_rules! unwrap { 180 | ($arg:expr) => { 181 | match $crate::fmt::Try::into_result($arg) { 182 | ::core::result::Result::Ok(t) => t, 183 | ::core::result::Result::Err(e) => { 184 | ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); 185 | } 186 | } 187 | }; 188 | ($arg:expr, $($msg:expr),+ $(,)? ) => { 189 | match $crate::fmt::Try::into_result($arg) { 190 | ::core::result::Result::Ok(t) => t, 191 | ::core::result::Result::Err(e) => { 192 | ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); 193 | } 194 | } 195 | } 196 | } 197 | 198 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 199 | pub struct NoneError; 200 | 201 | #[allow(dead_code)] 202 | pub trait Try { 203 | type Ok; 204 | type Error; 205 | fn into_result(self) -> Result; 206 | } 207 | 208 | impl Try for Option { 209 | type Ok = T; 210 | type Error = NoneError; 211 | 212 | #[inline] 213 | fn into_result(self) -> Result { 214 | self.ok_or(NoneError) 215 | } 216 | } 217 | 218 | impl Try for Result { 219 | type Ok = T; 220 | type Error = E; 221 | 222 | #[inline] 223 | fn into_result(self) -> Self { 224 | self 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /bm1370/src/fmt.rs: -------------------------------------------------------------------------------- 1 | #![macro_use] 2 | #![allow(unused_macros)] 3 | 4 | #[cfg(all(feature = "defmt", feature = "log"))] 5 | compile_error!("You may not enable both `defmt` and `log` features."); 6 | 7 | macro_rules! assert { 8 | ($($x:tt)*) => { 9 | { 10 | #[cfg(not(feature = "defmt"))] 11 | ::core::assert!($($x)*); 12 | #[cfg(feature = "defmt")] 13 | ::defmt::assert!($($x)*); 14 | } 15 | }; 16 | } 17 | 18 | macro_rules! assert_eq { 19 | ($($x:tt)*) => { 20 | { 21 | #[cfg(not(feature = "defmt"))] 22 | ::core::assert_eq!($($x)*); 23 | #[cfg(feature = "defmt")] 24 | ::defmt::assert_eq!($($x)*); 25 | } 26 | }; 27 | } 28 | 29 | macro_rules! assert_ne { 30 | ($($x:tt)*) => { 31 | { 32 | #[cfg(not(feature = "defmt"))] 33 | ::core::assert_ne!($($x)*); 34 | #[cfg(feature = "defmt")] 35 | ::defmt::assert_ne!($($x)*); 36 | } 37 | }; 38 | } 39 | 40 | macro_rules! debug_assert { 41 | ($($x:tt)*) => { 42 | { 43 | #[cfg(not(feature = "defmt"))] 44 | ::core::debug_assert!($($x)*); 45 | #[cfg(feature = "defmt")] 46 | ::defmt::debug_assert!($($x)*); 47 | } 48 | }; 49 | } 50 | 51 | macro_rules! debug_assert_eq { 52 | ($($x:tt)*) => { 53 | { 54 | #[cfg(not(feature = "defmt"))] 55 | ::core::debug_assert_eq!($($x)*); 56 | #[cfg(feature = "defmt")] 57 | ::defmt::debug_assert_eq!($($x)*); 58 | } 59 | }; 60 | } 61 | 62 | macro_rules! debug_assert_ne { 63 | ($($x:tt)*) => { 64 | { 65 | #[cfg(not(feature = "defmt"))] 66 | ::core::debug_assert_ne!($($x)*); 67 | #[cfg(feature = "defmt")] 68 | ::defmt::debug_assert_ne!($($x)*); 69 | } 70 | }; 71 | } 72 | 73 | macro_rules! todo { 74 | ($($x:tt)*) => { 75 | { 76 | #[cfg(not(feature = "defmt"))] 77 | ::core::todo!($($x)*); 78 | #[cfg(feature = "defmt")] 79 | ::defmt::todo!($($x)*); 80 | } 81 | }; 82 | } 83 | 84 | macro_rules! unreachable { 85 | ($($x:tt)*) => { 86 | { 87 | #[cfg(not(feature = "defmt"))] 88 | ::core::unreachable!($($x)*); 89 | #[cfg(feature = "defmt")] 90 | ::defmt::unreachable!($($x)*); 91 | } 92 | }; 93 | } 94 | 95 | macro_rules! panic { 96 | ($($x:tt)*) => { 97 | { 98 | #[cfg(not(feature = "defmt"))] 99 | ::core::panic!($($x)*); 100 | #[cfg(feature = "defmt")] 101 | ::defmt::panic!($($x)*); 102 | } 103 | }; 104 | } 105 | 106 | macro_rules! trace { 107 | ($s:literal $(, $x:expr)* $(,)?) => { 108 | { 109 | #[cfg(feature = "log")] 110 | ::log::trace!($s $(, $x)*); 111 | #[cfg(feature = "defmt")] 112 | ::defmt::trace!($s $(, $x)*); 113 | #[cfg(not(any(feature = "log", feature="defmt")))] 114 | let _ = ($( & $x ),*); 115 | } 116 | }; 117 | } 118 | 119 | macro_rules! debug { 120 | ($s:literal $(, $x:expr)* $(,)?) => { 121 | { 122 | #[cfg(feature = "log")] 123 | ::log::debug!($s $(, $x)*); 124 | #[cfg(feature = "defmt")] 125 | ::defmt::debug!($s $(, $x)*); 126 | #[cfg(not(any(feature = "log", feature="defmt")))] 127 | let _ = ($( & $x ),*); 128 | } 129 | }; 130 | } 131 | 132 | macro_rules! info { 133 | ($s:literal $(, $x:expr)* $(,)?) => { 134 | { 135 | #[cfg(feature = "log")] 136 | ::log::info!($s $(, $x)*); 137 | #[cfg(feature = "defmt")] 138 | ::defmt::info!($s $(, $x)*); 139 | #[cfg(not(any(feature = "log", feature="defmt")))] 140 | let _ = ($( & $x ),*); 141 | } 142 | }; 143 | } 144 | 145 | macro_rules! warn { 146 | ($s:literal $(, $x:expr)* $(,)?) => { 147 | { 148 | #[cfg(feature = "log")] 149 | ::log::warn!($s $(, $x)*); 150 | #[cfg(feature = "defmt")] 151 | ::defmt::warn!($s $(, $x)*); 152 | #[cfg(not(any(feature = "log", feature="defmt")))] 153 | let _ = ($( & $x ),*); 154 | } 155 | }; 156 | } 157 | 158 | macro_rules! error { 159 | ($s:literal $(, $x:expr)* $(,)?) => { 160 | { 161 | #[cfg(feature = "log")] 162 | ::log::error!($s $(, $x)*); 163 | #[cfg(feature = "defmt")] 164 | ::defmt::error!($s $(, $x)*); 165 | #[cfg(not(any(feature = "log", feature="defmt")))] 166 | let _ = ($( & $x ),*); 167 | } 168 | }; 169 | } 170 | 171 | #[cfg(feature = "defmt")] 172 | macro_rules! unwrap { 173 | ($($x:tt)*) => { 174 | ::defmt::unwrap!($($x)*) 175 | }; 176 | } 177 | 178 | #[cfg(not(feature = "defmt"))] 179 | macro_rules! unwrap { 180 | ($arg:expr) => { 181 | match $crate::fmt::Try::into_result($arg) { 182 | ::core::result::Result::Ok(t) => t, 183 | ::core::result::Result::Err(e) => { 184 | ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); 185 | } 186 | } 187 | }; 188 | ($arg:expr, $($msg:expr),+ $(,)? ) => { 189 | match $crate::fmt::Try::into_result($arg) { 190 | ::core::result::Result::Ok(t) => t, 191 | ::core::result::Result::Err(e) => { 192 | ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); 193 | } 194 | } 195 | } 196 | } 197 | 198 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 199 | pub struct NoneError; 200 | 201 | #[allow(dead_code)] 202 | pub trait Try { 203 | type Ok; 204 | type Error; 205 | fn into_result(self) -> Result; 206 | } 207 | 208 | impl Try for Option { 209 | type Ok = T; 210 | type Error = NoneError; 211 | 212 | #[inline] 213 | fn into_result(self) -> Result { 214 | self.ok_or(NoneError) 215 | } 216 | } 217 | 218 | impl Try for Result { 219 | type Ok = T; 220 | type Error = E; 221 | 222 | #[inline] 223 | fn into_result(self) -> Self { 224 | self 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /bm1397/src/fmt.rs: -------------------------------------------------------------------------------- 1 | #![macro_use] 2 | #![allow(unused_macros)] 3 | 4 | #[cfg(all(feature = "defmt", feature = "log"))] 5 | compile_error!("You may not enable both `defmt` and `log` features."); 6 | 7 | macro_rules! assert { 8 | ($($x:tt)*) => { 9 | { 10 | #[cfg(not(feature = "defmt"))] 11 | ::core::assert!($($x)*); 12 | #[cfg(feature = "defmt")] 13 | ::defmt::assert!($($x)*); 14 | } 15 | }; 16 | } 17 | 18 | macro_rules! assert_eq { 19 | ($($x:tt)*) => { 20 | { 21 | #[cfg(not(feature = "defmt"))] 22 | ::core::assert_eq!($($x)*); 23 | #[cfg(feature = "defmt")] 24 | ::defmt::assert_eq!($($x)*); 25 | } 26 | }; 27 | } 28 | 29 | macro_rules! assert_ne { 30 | ($($x:tt)*) => { 31 | { 32 | #[cfg(not(feature = "defmt"))] 33 | ::core::assert_ne!($($x)*); 34 | #[cfg(feature = "defmt")] 35 | ::defmt::assert_ne!($($x)*); 36 | } 37 | }; 38 | } 39 | 40 | macro_rules! debug_assert { 41 | ($($x:tt)*) => { 42 | { 43 | #[cfg(not(feature = "defmt"))] 44 | ::core::debug_assert!($($x)*); 45 | #[cfg(feature = "defmt")] 46 | ::defmt::debug_assert!($($x)*); 47 | } 48 | }; 49 | } 50 | 51 | macro_rules! debug_assert_eq { 52 | ($($x:tt)*) => { 53 | { 54 | #[cfg(not(feature = "defmt"))] 55 | ::core::debug_assert_eq!($($x)*); 56 | #[cfg(feature = "defmt")] 57 | ::defmt::debug_assert_eq!($($x)*); 58 | } 59 | }; 60 | } 61 | 62 | macro_rules! debug_assert_ne { 63 | ($($x:tt)*) => { 64 | { 65 | #[cfg(not(feature = "defmt"))] 66 | ::core::debug_assert_ne!($($x)*); 67 | #[cfg(feature = "defmt")] 68 | ::defmt::debug_assert_ne!($($x)*); 69 | } 70 | }; 71 | } 72 | 73 | macro_rules! todo { 74 | ($($x:tt)*) => { 75 | { 76 | #[cfg(not(feature = "defmt"))] 77 | ::core::todo!($($x)*); 78 | #[cfg(feature = "defmt")] 79 | ::defmt::todo!($($x)*); 80 | } 81 | }; 82 | } 83 | 84 | macro_rules! unreachable { 85 | ($($x:tt)*) => { 86 | { 87 | #[cfg(not(feature = "defmt"))] 88 | ::core::unreachable!($($x)*); 89 | #[cfg(feature = "defmt")] 90 | ::defmt::unreachable!($($x)*); 91 | } 92 | }; 93 | } 94 | 95 | macro_rules! panic { 96 | ($($x:tt)*) => { 97 | { 98 | #[cfg(not(feature = "defmt"))] 99 | ::core::panic!($($x)*); 100 | #[cfg(feature = "defmt")] 101 | ::defmt::panic!($($x)*); 102 | } 103 | }; 104 | } 105 | 106 | macro_rules! trace { 107 | ($s:literal $(, $x:expr)* $(,)?) => { 108 | { 109 | #[cfg(feature = "log")] 110 | ::log::trace!($s $(, $x)*); 111 | #[cfg(feature = "defmt")] 112 | ::defmt::trace!($s $(, $x)*); 113 | #[cfg(not(any(feature = "log", feature="defmt")))] 114 | let _ = ($( & $x ),*); 115 | } 116 | }; 117 | } 118 | 119 | macro_rules! debug { 120 | ($s:literal $(, $x:expr)* $(,)?) => { 121 | { 122 | #[cfg(feature = "log")] 123 | ::log::debug!($s $(, $x)*); 124 | #[cfg(feature = "defmt")] 125 | ::defmt::debug!($s $(, $x)*); 126 | #[cfg(not(any(feature = "log", feature="defmt")))] 127 | let _ = ($( & $x ),*); 128 | } 129 | }; 130 | } 131 | 132 | macro_rules! info { 133 | ($s:literal $(, $x:expr)* $(,)?) => { 134 | { 135 | #[cfg(feature = "log")] 136 | ::log::info!($s $(, $x)*); 137 | #[cfg(feature = "defmt")] 138 | ::defmt::info!($s $(, $x)*); 139 | #[cfg(not(any(feature = "log", feature="defmt")))] 140 | let _ = ($( & $x ),*); 141 | } 142 | }; 143 | } 144 | 145 | macro_rules! warn { 146 | ($s:literal $(, $x:expr)* $(,)?) => { 147 | { 148 | #[cfg(feature = "log")] 149 | ::log::warn!($s $(, $x)*); 150 | #[cfg(feature = "defmt")] 151 | ::defmt::warn!($s $(, $x)*); 152 | #[cfg(not(any(feature = "log", feature="defmt")))] 153 | let _ = ($( & $x ),*); 154 | } 155 | }; 156 | } 157 | 158 | macro_rules! error { 159 | ($s:literal $(, $x:expr)* $(,)?) => { 160 | { 161 | #[cfg(feature = "log")] 162 | ::log::error!($s $(, $x)*); 163 | #[cfg(feature = "defmt")] 164 | ::defmt::error!($s $(, $x)*); 165 | #[cfg(not(any(feature = "log", feature="defmt")))] 166 | let _ = ($( & $x ),*); 167 | } 168 | }; 169 | } 170 | 171 | #[cfg(feature = "defmt")] 172 | macro_rules! unwrap { 173 | ($($x:tt)*) => { 174 | ::defmt::unwrap!($($x)*) 175 | }; 176 | } 177 | 178 | #[cfg(not(feature = "defmt"))] 179 | macro_rules! unwrap { 180 | ($arg:expr) => { 181 | match $crate::fmt::Try::into_result($arg) { 182 | ::core::result::Result::Ok(t) => t, 183 | ::core::result::Result::Err(e) => { 184 | ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); 185 | } 186 | } 187 | }; 188 | ($arg:expr, $($msg:expr),+ $(,)? ) => { 189 | match $crate::fmt::Try::into_result($arg) { 190 | ::core::result::Result::Ok(t) => t, 191 | ::core::result::Result::Err(e) => { 192 | ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); 193 | } 194 | } 195 | } 196 | } 197 | 198 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 199 | pub struct NoneError; 200 | 201 | #[allow(dead_code)] 202 | pub trait Try { 203 | type Ok; 204 | type Error; 205 | fn into_result(self) -> Result; 206 | } 207 | 208 | impl Try for Option { 209 | type Ok = T; 210 | type Error = NoneError; 211 | 212 | #[inline] 213 | fn into_result(self) -> Result { 214 | self.ok_or(NoneError) 215 | } 216 | } 217 | 218 | impl Try for Result { 219 | type Ok = T; 220 | type Error = E; 221 | 222 | #[inline] 223 | fn into_result(self) -> Self { 224 | self 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /bm13xx-asic/src/fmt.rs: -------------------------------------------------------------------------------- 1 | #![macro_use] 2 | #![allow(unused_macros)] 3 | 4 | #[cfg(all(feature = "defmt", feature = "log"))] 5 | compile_error!("You may not enable both `defmt` and `log` features."); 6 | 7 | macro_rules! assert { 8 | ($($x:tt)*) => { 9 | { 10 | #[cfg(not(feature = "defmt"))] 11 | ::core::assert!($($x)*); 12 | #[cfg(feature = "defmt")] 13 | ::defmt::assert!($($x)*); 14 | } 15 | }; 16 | } 17 | 18 | macro_rules! assert_eq { 19 | ($($x:tt)*) => { 20 | { 21 | #[cfg(not(feature = "defmt"))] 22 | ::core::assert_eq!($($x)*); 23 | #[cfg(feature = "defmt")] 24 | ::defmt::assert_eq!($($x)*); 25 | } 26 | }; 27 | } 28 | 29 | macro_rules! assert_ne { 30 | ($($x:tt)*) => { 31 | { 32 | #[cfg(not(feature = "defmt"))] 33 | ::core::assert_ne!($($x)*); 34 | #[cfg(feature = "defmt")] 35 | ::defmt::assert_ne!($($x)*); 36 | } 37 | }; 38 | } 39 | 40 | macro_rules! debug_assert { 41 | ($($x:tt)*) => { 42 | { 43 | #[cfg(not(feature = "defmt"))] 44 | ::core::debug_assert!($($x)*); 45 | #[cfg(feature = "defmt")] 46 | ::defmt::debug_assert!($($x)*); 47 | } 48 | }; 49 | } 50 | 51 | macro_rules! debug_assert_eq { 52 | ($($x:tt)*) => { 53 | { 54 | #[cfg(not(feature = "defmt"))] 55 | ::core::debug_assert_eq!($($x)*); 56 | #[cfg(feature = "defmt")] 57 | ::defmt::debug_assert_eq!($($x)*); 58 | } 59 | }; 60 | } 61 | 62 | macro_rules! debug_assert_ne { 63 | ($($x:tt)*) => { 64 | { 65 | #[cfg(not(feature = "defmt"))] 66 | ::core::debug_assert_ne!($($x)*); 67 | #[cfg(feature = "defmt")] 68 | ::defmt::debug_assert_ne!($($x)*); 69 | } 70 | }; 71 | } 72 | 73 | macro_rules! todo { 74 | ($($x:tt)*) => { 75 | { 76 | #[cfg(not(feature = "defmt"))] 77 | ::core::todo!($($x)*); 78 | #[cfg(feature = "defmt")] 79 | ::defmt::todo!($($x)*); 80 | } 81 | }; 82 | } 83 | 84 | macro_rules! unreachable { 85 | ($($x:tt)*) => { 86 | { 87 | #[cfg(not(feature = "defmt"))] 88 | ::core::unreachable!($($x)*); 89 | #[cfg(feature = "defmt")] 90 | ::defmt::unreachable!($($x)*); 91 | } 92 | }; 93 | } 94 | 95 | macro_rules! panic { 96 | ($($x:tt)*) => { 97 | { 98 | #[cfg(not(feature = "defmt"))] 99 | ::core::panic!($($x)*); 100 | #[cfg(feature = "defmt")] 101 | ::defmt::panic!($($x)*); 102 | } 103 | }; 104 | } 105 | 106 | macro_rules! trace { 107 | ($s:literal $(, $x:expr)* $(,)?) => { 108 | { 109 | #[cfg(feature = "log")] 110 | ::log::trace!($s $(, $x)*); 111 | #[cfg(feature = "defmt")] 112 | ::defmt::trace!($s $(, $x)*); 113 | #[cfg(not(any(feature = "log", feature="defmt")))] 114 | let _ = ($( & $x ),*); 115 | } 116 | }; 117 | } 118 | 119 | macro_rules! debug { 120 | ($s:literal $(, $x:expr)* $(,)?) => { 121 | { 122 | #[cfg(feature = "log")] 123 | ::log::debug!($s $(, $x)*); 124 | #[cfg(feature = "defmt")] 125 | ::defmt::debug!($s $(, $x)*); 126 | #[cfg(not(any(feature = "log", feature="defmt")))] 127 | let _ = ($( & $x ),*); 128 | } 129 | }; 130 | } 131 | 132 | macro_rules! info { 133 | ($s:literal $(, $x:expr)* $(,)?) => { 134 | { 135 | #[cfg(feature = "log")] 136 | ::log::info!($s $(, $x)*); 137 | #[cfg(feature = "defmt")] 138 | ::defmt::info!($s $(, $x)*); 139 | #[cfg(not(any(feature = "log", feature="defmt")))] 140 | let _ = ($( & $x ),*); 141 | } 142 | }; 143 | } 144 | 145 | macro_rules! warn { 146 | ($s:literal $(, $x:expr)* $(,)?) => { 147 | { 148 | #[cfg(feature = "log")] 149 | ::log::warn!($s $(, $x)*); 150 | #[cfg(feature = "defmt")] 151 | ::defmt::warn!($s $(, $x)*); 152 | #[cfg(not(any(feature = "log", feature="defmt")))] 153 | let _ = ($( & $x ),*); 154 | } 155 | }; 156 | } 157 | 158 | macro_rules! error { 159 | ($s:literal $(, $x:expr)* $(,)?) => { 160 | { 161 | #[cfg(feature = "log")] 162 | ::log::error!($s $(, $x)*); 163 | #[cfg(feature = "defmt")] 164 | ::defmt::error!($s $(, $x)*); 165 | #[cfg(not(any(feature = "log", feature="defmt")))] 166 | let _ = ($( & $x ),*); 167 | } 168 | }; 169 | } 170 | 171 | #[cfg(feature = "defmt")] 172 | macro_rules! unwrap { 173 | ($($x:tt)*) => { 174 | ::defmt::unwrap!($($x)*) 175 | }; 176 | } 177 | 178 | #[cfg(not(feature = "defmt"))] 179 | macro_rules! unwrap { 180 | ($arg:expr) => { 181 | match $crate::fmt::Try::into_result($arg) { 182 | ::core::result::Result::Ok(t) => t, 183 | ::core::result::Result::Err(e) => { 184 | ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); 185 | } 186 | } 187 | }; 188 | ($arg:expr, $($msg:expr),+ $(,)? ) => { 189 | match $crate::fmt::Try::into_result($arg) { 190 | ::core::result::Result::Ok(t) => t, 191 | ::core::result::Result::Err(e) => { 192 | ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); 193 | } 194 | } 195 | } 196 | } 197 | 198 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 199 | pub struct NoneError; 200 | 201 | #[allow(dead_code)] 202 | pub trait Try { 203 | type Ok; 204 | type Error; 205 | fn into_result(self) -> Result; 206 | } 207 | 208 | impl Try for Option { 209 | type Ok = T; 210 | type Error = NoneError; 211 | 212 | #[inline] 213 | fn into_result(self) -> Result { 214 | self.ok_or(NoneError) 215 | } 216 | } 217 | 218 | impl Try for Result { 219 | type Ok = T; 220 | type Error = E; 221 | 222 | #[inline] 223 | fn into_result(self) -> Self { 224 | self 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /bm13xx-chain/src/fmt.rs: -------------------------------------------------------------------------------- 1 | #![macro_use] 2 | #![allow(unused_macros)] 3 | 4 | #[cfg(all(feature = "defmt", feature = "log"))] 5 | compile_error!("You may not enable both `defmt` and `log` features."); 6 | 7 | macro_rules! assert { 8 | ($($x:tt)*) => { 9 | { 10 | #[cfg(not(feature = "defmt"))] 11 | ::core::assert!($($x)*); 12 | #[cfg(feature = "defmt")] 13 | ::defmt::assert!($($x)*); 14 | } 15 | }; 16 | } 17 | 18 | macro_rules! assert_eq { 19 | ($($x:tt)*) => { 20 | { 21 | #[cfg(not(feature = "defmt"))] 22 | ::core::assert_eq!($($x)*); 23 | #[cfg(feature = "defmt")] 24 | ::defmt::assert_eq!($($x)*); 25 | } 26 | }; 27 | } 28 | 29 | macro_rules! assert_ne { 30 | ($($x:tt)*) => { 31 | { 32 | #[cfg(not(feature = "defmt"))] 33 | ::core::assert_ne!($($x)*); 34 | #[cfg(feature = "defmt")] 35 | ::defmt::assert_ne!($($x)*); 36 | } 37 | }; 38 | } 39 | 40 | macro_rules! debug_assert { 41 | ($($x:tt)*) => { 42 | { 43 | #[cfg(not(feature = "defmt"))] 44 | ::core::debug_assert!($($x)*); 45 | #[cfg(feature = "defmt")] 46 | ::defmt::debug_assert!($($x)*); 47 | } 48 | }; 49 | } 50 | 51 | macro_rules! debug_assert_eq { 52 | ($($x:tt)*) => { 53 | { 54 | #[cfg(not(feature = "defmt"))] 55 | ::core::debug_assert_eq!($($x)*); 56 | #[cfg(feature = "defmt")] 57 | ::defmt::debug_assert_eq!($($x)*); 58 | } 59 | }; 60 | } 61 | 62 | macro_rules! debug_assert_ne { 63 | ($($x:tt)*) => { 64 | { 65 | #[cfg(not(feature = "defmt"))] 66 | ::core::debug_assert_ne!($($x)*); 67 | #[cfg(feature = "defmt")] 68 | ::defmt::debug_assert_ne!($($x)*); 69 | } 70 | }; 71 | } 72 | 73 | macro_rules! todo { 74 | ($($x:tt)*) => { 75 | { 76 | #[cfg(not(feature = "defmt"))] 77 | ::core::todo!($($x)*); 78 | #[cfg(feature = "defmt")] 79 | ::defmt::todo!($($x)*); 80 | } 81 | }; 82 | } 83 | 84 | macro_rules! unreachable { 85 | ($($x:tt)*) => { 86 | { 87 | #[cfg(not(feature = "defmt"))] 88 | ::core::unreachable!($($x)*); 89 | #[cfg(feature = "defmt")] 90 | ::defmt::unreachable!($($x)*); 91 | } 92 | }; 93 | } 94 | 95 | macro_rules! panic { 96 | ($($x:tt)*) => { 97 | { 98 | #[cfg(not(feature = "defmt"))] 99 | ::core::panic!($($x)*); 100 | #[cfg(feature = "defmt")] 101 | ::defmt::panic!($($x)*); 102 | } 103 | }; 104 | } 105 | 106 | macro_rules! trace { 107 | ($s:literal $(, $x:expr)* $(,)?) => { 108 | { 109 | #[cfg(feature = "log")] 110 | ::log::trace!($s $(, $x)*); 111 | #[cfg(feature = "defmt")] 112 | ::defmt::trace!($s $(, $x)*); 113 | #[cfg(not(any(feature = "log", feature="defmt")))] 114 | let _ = ($( & $x ),*); 115 | } 116 | }; 117 | } 118 | 119 | macro_rules! debug { 120 | ($s:literal $(, $x:expr)* $(,)?) => { 121 | { 122 | #[cfg(feature = "log")] 123 | ::log::debug!($s $(, $x)*); 124 | #[cfg(feature = "defmt")] 125 | ::defmt::debug!($s $(, $x)*); 126 | #[cfg(not(any(feature = "log", feature="defmt")))] 127 | let _ = ($( & $x ),*); 128 | } 129 | }; 130 | } 131 | 132 | macro_rules! info { 133 | ($s:literal $(, $x:expr)* $(,)?) => { 134 | { 135 | #[cfg(feature = "log")] 136 | ::log::info!($s $(, $x)*); 137 | #[cfg(feature = "defmt")] 138 | ::defmt::info!($s $(, $x)*); 139 | #[cfg(not(any(feature = "log", feature="defmt")))] 140 | let _ = ($( & $x ),*); 141 | } 142 | }; 143 | } 144 | 145 | macro_rules! warn { 146 | ($s:literal $(, $x:expr)* $(,)?) => { 147 | { 148 | #[cfg(feature = "log")] 149 | ::log::warn!($s $(, $x)*); 150 | #[cfg(feature = "defmt")] 151 | ::defmt::warn!($s $(, $x)*); 152 | #[cfg(not(any(feature = "log", feature="defmt")))] 153 | let _ = ($( & $x ),*); 154 | } 155 | }; 156 | } 157 | 158 | macro_rules! error { 159 | ($s:literal $(, $x:expr)* $(,)?) => { 160 | { 161 | #[cfg(feature = "log")] 162 | ::log::error!($s $(, $x)*); 163 | #[cfg(feature = "defmt")] 164 | ::defmt::error!($s $(, $x)*); 165 | #[cfg(not(any(feature = "log", feature="defmt")))] 166 | let _ = ($( & $x ),*); 167 | } 168 | }; 169 | } 170 | 171 | #[cfg(feature = "defmt")] 172 | macro_rules! unwrap { 173 | ($($x:tt)*) => { 174 | ::defmt::unwrap!($($x)*) 175 | }; 176 | } 177 | 178 | #[cfg(not(feature = "defmt"))] 179 | macro_rules! unwrap { 180 | ($arg:expr) => { 181 | match $crate::fmt::Try::into_result($arg) { 182 | ::core::result::Result::Ok(t) => t, 183 | ::core::result::Result::Err(e) => { 184 | ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); 185 | } 186 | } 187 | }; 188 | ($arg:expr, $($msg:expr),+ $(,)? ) => { 189 | match $crate::fmt::Try::into_result($arg) { 190 | ::core::result::Result::Ok(t) => t, 191 | ::core::result::Result::Err(e) => { 192 | ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); 193 | } 194 | } 195 | } 196 | } 197 | 198 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 199 | pub struct NoneError; 200 | 201 | #[allow(dead_code)] 202 | pub trait Try { 203 | type Ok; 204 | type Error; 205 | fn into_result(self) -> Result; 206 | } 207 | 208 | impl Try for Option { 209 | type Ok = T; 210 | type Error = NoneError; 211 | 212 | #[inline] 213 | fn into_result(self) -> Result { 214 | self.ok_or(NoneError) 215 | } 216 | } 217 | 218 | impl Try for Result { 219 | type Ok = T; 220 | type Error = E; 221 | 222 | #[inline] 223 | fn into_result(self) -> Self { 224 | self 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /bm13xx-protocol/src/fmt.rs: -------------------------------------------------------------------------------- 1 | #![macro_use] 2 | #![allow(unused_macros)] 3 | 4 | #[cfg(all(feature = "defmt", feature = "log"))] 5 | compile_error!("You may not enable both `defmt` and `log` features."); 6 | 7 | macro_rules! assert { 8 | ($($x:tt)*) => { 9 | { 10 | #[cfg(not(feature = "defmt"))] 11 | ::core::assert!($($x)*); 12 | #[cfg(feature = "defmt")] 13 | ::defmt::assert!($($x)*); 14 | } 15 | }; 16 | } 17 | 18 | macro_rules! assert_eq { 19 | ($($x:tt)*) => { 20 | { 21 | #[cfg(not(feature = "defmt"))] 22 | ::core::assert_eq!($($x)*); 23 | #[cfg(feature = "defmt")] 24 | ::defmt::assert_eq!($($x)*); 25 | } 26 | }; 27 | } 28 | 29 | macro_rules! assert_ne { 30 | ($($x:tt)*) => { 31 | { 32 | #[cfg(not(feature = "defmt"))] 33 | ::core::assert_ne!($($x)*); 34 | #[cfg(feature = "defmt")] 35 | ::defmt::assert_ne!($($x)*); 36 | } 37 | }; 38 | } 39 | 40 | macro_rules! debug_assert { 41 | ($($x:tt)*) => { 42 | { 43 | #[cfg(not(feature = "defmt"))] 44 | ::core::debug_assert!($($x)*); 45 | #[cfg(feature = "defmt")] 46 | ::defmt::debug_assert!($($x)*); 47 | } 48 | }; 49 | } 50 | 51 | macro_rules! debug_assert_eq { 52 | ($($x:tt)*) => { 53 | { 54 | #[cfg(not(feature = "defmt"))] 55 | ::core::debug_assert_eq!($($x)*); 56 | #[cfg(feature = "defmt")] 57 | ::defmt::debug_assert_eq!($($x)*); 58 | } 59 | }; 60 | } 61 | 62 | macro_rules! debug_assert_ne { 63 | ($($x:tt)*) => { 64 | { 65 | #[cfg(not(feature = "defmt"))] 66 | ::core::debug_assert_ne!($($x)*); 67 | #[cfg(feature = "defmt")] 68 | ::defmt::debug_assert_ne!($($x)*); 69 | } 70 | }; 71 | } 72 | 73 | macro_rules! todo { 74 | ($($x:tt)*) => { 75 | { 76 | #[cfg(not(feature = "defmt"))] 77 | ::core::todo!($($x)*); 78 | #[cfg(feature = "defmt")] 79 | ::defmt::todo!($($x)*); 80 | } 81 | }; 82 | } 83 | 84 | macro_rules! unreachable { 85 | ($($x:tt)*) => { 86 | { 87 | #[cfg(not(feature = "defmt"))] 88 | ::core::unreachable!($($x)*); 89 | #[cfg(feature = "defmt")] 90 | ::defmt::unreachable!($($x)*); 91 | } 92 | }; 93 | } 94 | 95 | macro_rules! panic { 96 | ($($x:tt)*) => { 97 | { 98 | #[cfg(not(feature = "defmt"))] 99 | ::core::panic!($($x)*); 100 | #[cfg(feature = "defmt")] 101 | ::defmt::panic!($($x)*); 102 | } 103 | }; 104 | } 105 | 106 | macro_rules! trace { 107 | ($s:literal $(, $x:expr)* $(,)?) => { 108 | { 109 | #[cfg(feature = "log")] 110 | ::log::trace!($s $(, $x)*); 111 | #[cfg(feature = "defmt")] 112 | ::defmt::trace!($s $(, $x)*); 113 | #[cfg(not(any(feature = "log", feature="defmt")))] 114 | let _ = ($( & $x ),*); 115 | } 116 | }; 117 | } 118 | 119 | macro_rules! debug { 120 | ($s:literal $(, $x:expr)* $(,)?) => { 121 | { 122 | #[cfg(feature = "log")] 123 | ::log::debug!($s $(, $x)*); 124 | #[cfg(feature = "defmt")] 125 | ::defmt::debug!($s $(, $x)*); 126 | #[cfg(not(any(feature = "log", feature="defmt")))] 127 | let _ = ($( & $x ),*); 128 | } 129 | }; 130 | } 131 | 132 | macro_rules! info { 133 | ($s:literal $(, $x:expr)* $(,)?) => { 134 | { 135 | #[cfg(feature = "log")] 136 | ::log::info!($s $(, $x)*); 137 | #[cfg(feature = "defmt")] 138 | ::defmt::info!($s $(, $x)*); 139 | #[cfg(not(any(feature = "log", feature="defmt")))] 140 | let _ = ($( & $x ),*); 141 | } 142 | }; 143 | } 144 | 145 | macro_rules! warn { 146 | ($s:literal $(, $x:expr)* $(,)?) => { 147 | { 148 | #[cfg(feature = "log")] 149 | ::log::warn!($s $(, $x)*); 150 | #[cfg(feature = "defmt")] 151 | ::defmt::warn!($s $(, $x)*); 152 | #[cfg(not(any(feature = "log", feature="defmt")))] 153 | let _ = ($( & $x ),*); 154 | } 155 | }; 156 | } 157 | 158 | macro_rules! error { 159 | ($s:literal $(, $x:expr)* $(,)?) => { 160 | { 161 | #[cfg(feature = "log")] 162 | ::log::error!($s $(, $x)*); 163 | #[cfg(feature = "defmt")] 164 | ::defmt::error!($s $(, $x)*); 165 | #[cfg(not(any(feature = "log", feature="defmt")))] 166 | let _ = ($( & $x ),*); 167 | } 168 | }; 169 | } 170 | 171 | #[cfg(feature = "defmt")] 172 | macro_rules! unwrap { 173 | ($($x:tt)*) => { 174 | ::defmt::unwrap!($($x)*) 175 | }; 176 | } 177 | 178 | #[cfg(not(feature = "defmt"))] 179 | macro_rules! unwrap { 180 | ($arg:expr) => { 181 | match $crate::fmt::Try::into_result($arg) { 182 | ::core::result::Result::Ok(t) => t, 183 | ::core::result::Result::Err(e) => { 184 | ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); 185 | } 186 | } 187 | }; 188 | ($arg:expr, $($msg:expr),+ $(,)? ) => { 189 | match $crate::fmt::Try::into_result($arg) { 190 | ::core::result::Result::Ok(t) => t, 191 | ::core::result::Result::Err(e) => { 192 | ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); 193 | } 194 | } 195 | } 196 | } 197 | 198 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 199 | pub struct NoneError; 200 | 201 | #[allow(dead_code)] 202 | pub trait Try { 203 | type Ok; 204 | type Error; 205 | fn into_result(self) -> Result; 206 | } 207 | 208 | impl Try for Option { 209 | type Ok = T; 210 | type Error = NoneError; 211 | 212 | #[inline] 213 | fn into_result(self) -> Result { 214 | self.ok_or(NoneError) 215 | } 216 | } 217 | 218 | impl Try for Result { 219 | type Ok = T; 220 | type Error = E; 221 | 222 | #[inline] 223 | fn into_result(self) -> Self { 224 | self 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /bm13xx-asic/src/core_register/process_monitor.rs: -------------------------------------------------------------------------------- 1 | use crate::core_register::CoreRegister; 2 | 3 | /// Process Monitor SELect. 4 | /// 5 | /// This is used by [`ProcessMonitorCtrl::pm_sel`] and [`ProcessMonitorCtrl::start`] method. 6 | /// 7 | /// [`ProcessMonitorCtrl::pm_sel`]: crate::core_register::ProcessMonitorCtrl::pm_sel 8 | /// [`ProcessMonitorCtrl::start`]: crate::core_register::ProcessMonitorCtrl::start 9 | #[derive(Copy, Clone, Eq, PartialEq, Debug, PartialOrd, Ord, Hash)] 10 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 11 | #[repr(u8)] 12 | pub enum ProcessMonitorSelect { 13 | /// Process Monitor on LVT delay chain. 14 | LVTDelayChain = 0, 15 | /// Process Monitor on SVT delay chain. 16 | SVTDelayChain = 1, 17 | /// Process Monitor on HVT delay chain. 18 | HVTDelayChain = 2, 19 | /// Process Monitor on Critical path chain. 20 | CriticalPathChain = 3, 21 | } 22 | 23 | impl From for u8 { 24 | /// Get the register value from a buffer size. 25 | /// 26 | /// # Example 27 | /// 28 | /// ``` 29 | /// use bm13xx_asic::core_register::ProcessMonitorSelect; 30 | /// 31 | /// assert_eq!(u8::from(ProcessMonitorSelect::LVTDelayChain), 0); 32 | /// assert_eq!(u8::from(ProcessMonitorSelect::SVTDelayChain), 1); 33 | /// assert_eq!(u8::from(ProcessMonitorSelect::HVTDelayChain), 2); 34 | /// assert_eq!(u8::from(ProcessMonitorSelect::CriticalPathChain), 3); 35 | /// ``` 36 | fn from(val: ProcessMonitorSelect) -> u8 { 37 | val as u8 38 | } 39 | } 40 | 41 | impl TryFrom for ProcessMonitorSelect { 42 | type Error = u8; 43 | 44 | /// Get the buffer size given the register value. 45 | /// 46 | /// # Example 47 | /// 48 | /// ``` 49 | /// use bm13xx_asic::core_register::ProcessMonitorSelect; 50 | /// 51 | /// assert_eq!(ProcessMonitorSelect::try_from(0), Ok(ProcessMonitorSelect::LVTDelayChain)); 52 | /// assert_eq!(ProcessMonitorSelect::try_from(1), Ok(ProcessMonitorSelect::SVTDelayChain)); 53 | /// assert_eq!(ProcessMonitorSelect::try_from(2), Ok(ProcessMonitorSelect::HVTDelayChain)); 54 | /// assert_eq!(ProcessMonitorSelect::try_from(3), Ok(ProcessMonitorSelect::CriticalPathChain)); 55 | /// assert_eq!(ProcessMonitorSelect::try_from(4), Err(4)); 56 | /// ``` 57 | fn try_from(val: u8) -> Result { 58 | match val { 59 | x if x == ProcessMonitorSelect::LVTDelayChain as u8 => { 60 | Ok(ProcessMonitorSelect::LVTDelayChain) 61 | } 62 | x if x == ProcessMonitorSelect::SVTDelayChain as u8 => { 63 | Ok(ProcessMonitorSelect::SVTDelayChain) 64 | } 65 | x if x == ProcessMonitorSelect::HVTDelayChain as u8 => { 66 | Ok(ProcessMonitorSelect::HVTDelayChain) 67 | } 68 | x if x == ProcessMonitorSelect::CriticalPathChain as u8 => { 69 | Ok(ProcessMonitorSelect::CriticalPathChain) 70 | } 71 | _ => Err(val), 72 | } 73 | } 74 | } 75 | 76 | /// # Process Monitor Ctrl core register 77 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 78 | pub struct ProcessMonitorCtrl(pub u8); 79 | impl_boilerplate_for_core_reg!(ProcessMonitorCtrl); 80 | 81 | impl ProcessMonitorCtrl { 82 | pub const ID: u8 = 1; 83 | 84 | const PM_START_OFFSET: u8 = 2; 85 | const PM_SEL_OFFSET: u8 = 0; 86 | 87 | const PM_START_MASK: u8 = 0b1; 88 | const PM_SEL_MASK: u8 = 0b11; 89 | 90 | /// ## Handle the Started field. 91 | /// 92 | /// Get and set the Started state. 93 | /// 94 | /// ### Example 95 | /// 96 | /// ``` 97 | /// use bm13xx_asic::core_register::{ProcessMonitorCtrl, ProcessMonitorSelect}; 98 | /// 99 | /// let pmc = ProcessMonitorCtrl(ProcessMonitorCtrl::start(ProcessMonitorSelect::HVTDelayChain)); 100 | /// assert!(pmc.started()); 101 | /// assert_eq!(pmc.pm_sel(), ProcessMonitorSelect::HVTDelayChain); 102 | /// ``` 103 | pub const fn started(&self) -> bool { 104 | (self.0 >> Self::PM_START_OFFSET) & Self::PM_START_MASK == Self::PM_START_MASK 105 | } 106 | pub const fn start(pm_sel: ProcessMonitorSelect) -> u8 { 107 | (Self::PM_START_MASK << Self::PM_START_OFFSET) | ((pm_sel as u8) << Self::PM_SEL_OFFSET) 108 | } 109 | pub fn pm_sel(&self) -> ProcessMonitorSelect { 110 | ProcessMonitorSelect::try_from((self.0 & Self::PM_SEL_MASK) >> Self::PM_SEL_OFFSET).unwrap() 111 | } 112 | } 113 | 114 | impl ::core::fmt::Display for ProcessMonitorCtrl { 115 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 116 | f.debug_struct("ProcessMonitorCtrl") 117 | .field("started", &self.started()) 118 | .field("pm_sel", &self.pm_sel()) 119 | .finish() 120 | } 121 | } 122 | 123 | #[cfg(feature = "defmt")] 124 | impl defmt::Format for ProcessMonitorCtrl { 125 | fn format(&self, fmt: defmt::Formatter) { 126 | defmt::write!( 127 | fmt, 128 | "ProcessMonitorCtrl {{ started: {}, pm_sel: {} }}", 129 | self.started(), 130 | self.pm_sel() 131 | ); 132 | } 133 | } 134 | 135 | /// # Process Monitor Data core register 136 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 137 | pub struct ProcessMonitorData(pub u8); 138 | impl_boilerplate_for_core_reg!(ProcessMonitorData); 139 | 140 | impl ProcessMonitorData { 141 | pub const ID: u8 = 2; 142 | 143 | const DATA_OFFSET: u8 = 0; 144 | 145 | const DATA_MASK: u8 = 0xff; 146 | 147 | /// ## Get the Data. 148 | /// 149 | /// This returns an `u8` with the Data. 150 | /// 151 | /// ### Example 152 | /// 153 | /// ``` 154 | /// use bm13xx_asic::core_register::ProcessMonitorData; 155 | /// 156 | /// assert_eq!(ProcessMonitorData(0x00).data(), 0x00); 157 | /// ``` 158 | pub const fn data(&self) -> u8 { 159 | (self.0 >> Self::DATA_OFFSET) & Self::DATA_MASK 160 | } 161 | } 162 | 163 | impl ::core::fmt::Display for ProcessMonitorData { 164 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 165 | f.debug_struct("ProcessMonitorData") 166 | .field("data", &self.data()) 167 | .finish() 168 | } 169 | } 170 | 171 | #[cfg(feature = "defmt")] 172 | impl defmt::Format for ProcessMonitorData { 173 | fn format(&self, fmt: defmt::Formatter) { 174 | defmt::write!(fmt, "ProcessMonitorData {{ data: {} }}", self.data()); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /bm13xx-protocol/src/crc.rs: -------------------------------------------------------------------------------- 1 | use crc::{Algorithm, Crc}; 2 | 3 | const CRC5: Crc = Crc::::new(&Algorithm { 4 | width: 5, 5 | poly: 0x05, 6 | init: 0x1f, 7 | refin: false, 8 | refout: false, 9 | xorout: 0x00, 10 | check: 0x00, 11 | residue: 0x00, 12 | }); 13 | 14 | const CRC16: Crc = Crc::::new(&Algorithm { 15 | width: 16, 16 | poly: 0x1021, 17 | init: 0xffff, 18 | refin: false, 19 | refout: false, 20 | xorout: 0x0000, 21 | check: 0x29b1, 22 | residue: 0x0000, 23 | }); 24 | 25 | pub const fn crc5(data: &[u8]) -> u8 { 26 | CRC5.checksum(data) 27 | } 28 | 29 | pub const fn crc5_bits(data: &[u8]) -> u8 { 30 | let mut var1; 31 | let mut var2 = true; 32 | let mut var3 = true; 33 | let mut var4; 34 | let mut var5 = true; 35 | let mut crc5 = 0x80u8; 36 | let mut bit_cnt = 0usize; 37 | let mut total_bit_cnt = 0usize; 38 | let data_bit_len = if data.is_empty() { 39 | 0 40 | } else { 41 | data.len() * 8 - 5 42 | }; 43 | let mut data_cnt = 0usize; 44 | let mut set_bit_0 = true; 45 | let mut set_bit_1 = true; 46 | let mut set_bit_2 = true; 47 | 48 | if data_bit_len == 0 { 49 | crc5 = 0x10; 50 | } else { 51 | loop { 52 | var4 = set_bit_2; 53 | set_bit_1 = set_bit_0; 54 | var1 = var5; 55 | bit_cnt += 1; 56 | set_bit_0 = var2; 57 | if (data[data_cnt] & crc5) != 0 { 58 | set_bit_0 = var2 ^ true; 59 | } 60 | total_bit_cnt += 1; 61 | crc5 >>= 1; 62 | if bit_cnt == 8 { 63 | data_cnt += 1; 64 | } 65 | set_bit_2 = var3 ^ set_bit_0; 66 | if bit_cnt == 8 { 67 | bit_cnt = 0; 68 | crc5 = 0x80; 69 | } 70 | var5 = var4; 71 | var2 = var1; 72 | var3 = set_bit_1; 73 | if total_bit_cnt >= data_bit_len { 74 | break; 75 | } 76 | } 77 | if var1 { 78 | crc5 = 0x10; 79 | } else { 80 | crc5 = 0; 81 | } 82 | if !var4 { 83 | if set_bit_2 { 84 | crc5 |= 4; 85 | } 86 | if set_bit_1 { 87 | crc5 |= 2; 88 | } 89 | if set_bit_0 { 90 | crc5 |= 1; 91 | } 92 | return crc5; 93 | } 94 | } 95 | crc5 |= 8; 96 | if set_bit_2 { 97 | crc5 |= 4; 98 | } 99 | if set_bit_1 { 100 | crc5 |= 2; 101 | } 102 | if set_bit_0 { 103 | crc5 |= 1; 104 | } 105 | crc5 106 | } 107 | 108 | pub const fn crc16(data: &[u8]) -> u16 { 109 | CRC16.checksum(data) 110 | } 111 | 112 | #[cfg(test)] 113 | mod tests { 114 | use super::*; 115 | 116 | /// Test the byte-aligned CRC5. 117 | #[test] 118 | fn crc5_byte_aligned() { 119 | // Chain inactive 120 | assert_eq!(crc5(&[0x53, 0x05, 0x00, 0x00]), 0x03); 121 | // Read Register ChipIddentification 122 | assert_eq!(crc5(&[0x52, 0x05, 0x00, 0x00]), 0x0A); 123 | // Write Register ClockOrderControl0 124 | assert_eq!( 125 | crc5(&[0x51, 0x09, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00]), 126 | 0x1C 127 | ); 128 | // Response Register - check full frame only 129 | assert_eq!( 130 | crc5(&[0x13, 0x62, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E]), 131 | 0x00 132 | ); 133 | // Response Nonce - check full frame only 134 | assert_eq!( 135 | crc5(&[0x2F, 0xD5, 0x96, 0xCE, 0x02, 0x93, 0x94, 0xFB, 0x86]), 136 | 0x00 137 | ); 138 | } 139 | 140 | /// Test the bit-aligned CRC5. 141 | #[test] 142 | fn crc5_bit_aligned() { 143 | // on an empty slice - equivalent to byte-aligned crc5 144 | assert_eq!(crc5(&[]), crc5_bits(&[])); 145 | 146 | // Response Register - compute 147 | assert_eq!( 148 | crc5_bits(&[0x13, 0x62, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), 149 | 0x1E 150 | ); 151 | 152 | // Response Nonce - compute 153 | assert_eq!( 154 | crc5_bits(&[0x2F, 0xD5, 0x96, 0xCE, 0x02, 0x93, 0x94, 0xFB, 0x80]), 155 | 0x06 156 | ); 157 | } 158 | 159 | /// Test the byte-aligned CRC16. 160 | #[test] 161 | fn crc16_byte_aligned() { 162 | // Job example - compute 163 | assert_eq!( 164 | crc16(&[ 165 | 0x21, 0x96, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x15, 0x9E, 0x07, 0x17, 0x75, 0x32, 166 | 0x8E, 0x63, 0xA2, 0xB3, 0x6A, 0x70, 0xDE, 0x60, 0x4A, 0x09, 0xE9, 0x30, 0x1D, 0xE1, 167 | 0x25, 0x6D, 0x7E, 0xB8, 0x0E, 0xA1, 0xE6, 0x43, 0x82, 0xDF, 0x61, 0x14, 0x15, 0x03, 168 | 0x96, 0x6C, 0x18, 0x5F, 0x50, 0x2F, 0x55, 0x74, 0xD4, 0xBA, 0xAE, 0x2F, 0x3F, 0xC6, 169 | 0x02, 0xD9, 0xCD, 0x3B, 0x9E, 0x39, 0xAD, 0x97, 0x9C, 0xFD, 0xFF, 0x3A, 0x40, 0x49, 170 | 0x4D, 0xB6, 0xD7, 0x8D, 0xA4, 0x51, 0x34, 0x99, 0x29, 0xD1, 0xAD, 0x36, 0x66, 0x1D, 171 | 0xDF, 0xFF, 0xC1, 0xCC, 0x89, 0x33, 0xEA, 0xF3, 0xE8, 0x3A, 0x91, 0x58, 0xA6, 0xD6, 172 | 0xFA, 0x02, 0x0D, 0xCF, 0x60, 0xF8, 0xC1, 0x0E, 0x99, 0x36, 0xDE, 0x71, 0xDB, 0xD3, 173 | 0xF7, 0xD2, 0x86, 0xAF, 0xAD, 0x62, 0x59, 0x3A, 0x8D, 0xA3, 0x28, 0xAF, 0xEC, 0x09, 174 | 0x6D, 0x86, 0xB9, 0x8E, 0x30, 0xE5, 0x79, 0xAE, 0xA4, 0x35, 0xE1, 0x4B, 0xB5, 0xD7, 175 | 0x09, 0xCC, 0xE1, 0x74, 0x04, 0x3A, 0x7C, 0x2D 176 | ]), 177 | 0x1B5C 178 | ); 179 | // Job example - check full frame 180 | assert_eq!( 181 | crc16(&[ 182 | 0x21, 0x96, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x15, 0x9E, 0x07, 0x17, 0x75, 0x32, 183 | 0x8E, 0x63, 0xA2, 0xB3, 0x6A, 0x70, 0xDE, 0x60, 0x4A, 0x09, 0xE9, 0x30, 0x1D, 0xE1, 184 | 0x25, 0x6D, 0x7E, 0xB8, 0x0E, 0xA1, 0xE6, 0x43, 0x82, 0xDF, 0x61, 0x14, 0x15, 0x03, 185 | 0x96, 0x6C, 0x18, 0x5F, 0x50, 0x2F, 0x55, 0x74, 0xD4, 0xBA, 0xAE, 0x2F, 0x3F, 0xC6, 186 | 0x02, 0xD9, 0xCD, 0x3B, 0x9E, 0x39, 0xAD, 0x97, 0x9C, 0xFD, 0xFF, 0x3A, 0x40, 0x49, 187 | 0x4D, 0xB6, 0xD7, 0x8D, 0xA4, 0x51, 0x34, 0x99, 0x29, 0xD1, 0xAD, 0x36, 0x66, 0x1D, 188 | 0xDF, 0xFF, 0xC1, 0xCC, 0x89, 0x33, 0xEA, 0xF3, 0xE8, 0x3A, 0x91, 0x58, 0xA6, 0xD6, 189 | 0xFA, 0x02, 0x0D, 0xCF, 0x60, 0xF8, 0xC1, 0x0E, 0x99, 0x36, 0xDE, 0x71, 0xDB, 0xD3, 190 | 0xF7, 0xD2, 0x86, 0xAF, 0xAD, 0x62, 0x59, 0x3A, 0x8D, 0xA3, 0x28, 0xAF, 0xEC, 0x09, 191 | 0x6D, 0x86, 0xB9, 0x8E, 0x30, 0xE5, 0x79, 0xAE, 0xA4, 0x35, 0xE1, 0x4B, 0xB5, 0xD7, 192 | 0x09, 0xCC, 0xE1, 0x74, 0x04, 0x3A, 0x7C, 0x2D, 0x1B, 0x5C 193 | ]), 194 | 0 195 | ); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/io_driver_strenght.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// Driver Select. 4 | /// 5 | /// This is used by [`IoDriverStrenghtConfiguration::strenght`], [`IoDriverStrenghtConfiguration::set_strenght`] method 6 | /// 7 | /// [`IoDriverStrenghtConfiguration::strenght`]: crate::register::IoDriverStrenghtConfiguration::strenght 8 | // [`IoDriverStrenghtConfiguration::set_strenght`]: crate::register::IoDriverStrenghtConfiguration::set_strenght 9 | #[derive(Copy, Clone, Eq, PartialEq, Debug, PartialOrd, Ord, Hash)] 10 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 11 | pub enum DriverSelect { 12 | RF, 13 | RO, 14 | CLKO, 15 | NRSTO, 16 | BO, 17 | CO, 18 | } 19 | 20 | /// Driver Select. 21 | /// 22 | /// This is used by [`IoDriverStrenghtConfiguration::strenght`], [`IoDriverStrenghtConfiguration::set_strenght`] method 23 | /// 24 | /// [`IoDriverStrenghtConfiguration::strenght`]: crate::register::IoDriverStrenghtConfiguration::strenght 25 | // [`IoDriverStrenghtConfiguration::set_strenght`]: crate::register::IoDriverStrenghtConfiguration::set_strenght 26 | #[derive(Copy, Clone, Eq, PartialEq, Debug, PartialOrd, Ord, Hash)] 27 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 28 | pub enum DriverRSelect { 29 | D0R, 30 | D1R, 31 | D2R, 32 | D3R, 33 | } 34 | 35 | /// # Io Driver Strenght Configuration register 36 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 37 | pub struct IoDriverStrenghtConfiguration(pub u32); 38 | impl_boilerplate_for!(IoDriverStrenghtConfiguration); 39 | 40 | impl IoDriverStrenghtConfiguration { 41 | pub const ADDR: u8 = 0x58; 42 | 43 | const RF_DS_OFFSET: u8 = 24; 44 | const D3RS_EN_OFFSET: u8 = 23; 45 | const D2RS_EN_OFFSET: u8 = 22; 46 | const D1RS_EN_OFFSET: u8 = 21; 47 | const D0RS_EN_OFFSET: u8 = 20; 48 | const RO_DS_OFFSET: u8 = 16; 49 | const CLKO_DS_OFFSET: u8 = 12; 50 | const NRSTO_DS_OFFSET: u8 = 8; 51 | const BO_DS_OFFSET: u8 = 4; 52 | const CO_DS_OFFSET: u8 = 0; 53 | 54 | const RF_DS_MASK: u32 = 0b1111; 55 | const D3RS_EN_MASK: u32 = 0b1; 56 | const D2RS_EN_MASK: u32 = 0b1; 57 | const D1RS_EN_MASK: u32 = 0b1; 58 | const D0RS_EN_MASK: u32 = 0b1; 59 | const RO_DS_MASK: u32 = 0b1111; 60 | const CLKO_DS_MASK: u32 = 0b1111; 61 | const NRSTO_DS_MASK: u32 = 0b1111; 62 | const BO_DS_MASK: u32 = 0b1111; 63 | const CO_DS_MASK: u32 = 0b1111; 64 | 65 | /// ## Handle the xx_DS field. 66 | /// 67 | /// Get and set the xx_DS value. 68 | /// 69 | /// ### Example 70 | /// 71 | /// ``` 72 | /// use bm13xx_asic::register::{DriverSelect, IoDriverStrenghtConfiguration}; 73 | /// 74 | /// let mut io_conf = IoDriverStrenghtConfiguration(0x0001_2111); // BM1366 default value 75 | /// assert_eq!(io_conf.strenght(DriverSelect::RF), 0); 76 | /// assert_eq!(io_conf.strenght(DriverSelect::RO), 1); 77 | /// assert_eq!(io_conf.strenght(DriverSelect::CLKO), 2); 78 | /// assert_eq!(io_conf.strenght(DriverSelect::NRSTO), 1); 79 | /// assert_eq!(io_conf.strenght(DriverSelect::BO), 1); 80 | /// assert_eq!(io_conf.strenght(DriverSelect::CO), 1); 81 | /// assert_eq!(io_conf.set_strenght(DriverSelect::RF, 2).strenght(DriverSelect::RF), 2); // BM1366 init() value 82 | /// assert_eq!(io_conf.set_strenght(DriverSelect::RF, 0xf).strenght(DriverSelect::RF), 0xf); // max value 83 | /// assert_eq!(io_conf.set_strenght(DriverSelect::RF, 0x10).strenght(DriverSelect::RF), 0); // out of bound value 84 | /// ``` 85 | pub const fn strenght(&self, drv: DriverSelect) -> u8 { 86 | ((self.0 87 | >> match drv { 88 | DriverSelect::RF => Self::RF_DS_OFFSET, 89 | DriverSelect::RO => Self::RO_DS_OFFSET, 90 | DriverSelect::CLKO => Self::CLKO_DS_OFFSET, 91 | DriverSelect::NRSTO => Self::NRSTO_DS_OFFSET, 92 | DriverSelect::BO => Self::BO_DS_OFFSET, 93 | DriverSelect::CO => Self::CO_DS_OFFSET, 94 | }) 95 | & match drv { 96 | DriverSelect::RF => Self::RF_DS_MASK, 97 | DriverSelect::RO => Self::RO_DS_MASK, 98 | DriverSelect::CLKO => Self::CLKO_DS_MASK, 99 | DriverSelect::NRSTO => Self::NRSTO_DS_MASK, 100 | DriverSelect::BO => Self::BO_DS_MASK, 101 | DriverSelect::CO => Self::CO_DS_MASK, 102 | }) as u8 103 | } 104 | pub fn set_strenght(&mut self, drv: DriverSelect, strenght: u8) -> &mut Self { 105 | let offset = match drv { 106 | DriverSelect::RF => Self::RF_DS_OFFSET, 107 | DriverSelect::RO => Self::RO_DS_OFFSET, 108 | DriverSelect::CLKO => Self::CLKO_DS_OFFSET, 109 | DriverSelect::NRSTO => Self::NRSTO_DS_OFFSET, 110 | DriverSelect::BO => Self::BO_DS_OFFSET, 111 | DriverSelect::CO => Self::CO_DS_OFFSET, 112 | }; 113 | let mask = match drv { 114 | DriverSelect::RF => Self::RF_DS_MASK, 115 | DriverSelect::RO => Self::RO_DS_MASK, 116 | DriverSelect::CLKO => Self::CLKO_DS_MASK, 117 | DriverSelect::NRSTO => Self::NRSTO_DS_MASK, 118 | DriverSelect::BO => Self::BO_DS_MASK, 119 | DriverSelect::CO => Self::CO_DS_MASK, 120 | }; 121 | self.0 &= !(mask << offset); 122 | self.0 |= ((strenght as u32) & mask) << offset; 123 | self 124 | } 125 | 126 | /// ## Handle the DxRS_EN field. 127 | /// 128 | /// Get and set the DxRS_EN state. 129 | /// 130 | /// ### Example 131 | /// 132 | /// ``` 133 | /// use bm13xx_asic::register::{DriverRSelect, IoDriverStrenghtConfiguration}; 134 | /// 135 | /// let mut io_conf = IoDriverStrenghtConfiguration(0x0001_2111); // BM1366 default value 136 | /// assert!(!io_conf.enabled(DriverRSelect::D0R)); 137 | /// assert!(!io_conf.enabled(DriverRSelect::D1R)); 138 | /// assert!(!io_conf.enabled(DriverRSelect::D2R)); 139 | /// assert!(!io_conf.enabled(DriverRSelect::D3R)); 140 | /// assert!(io_conf.enable(DriverRSelect::D0R).enabled(DriverRSelect::D0R)); 141 | /// assert!(!io_conf.disable(DriverRSelect::D0R).enabled(DriverRSelect::D0R)); 142 | /// ``` 143 | pub const fn enabled(&self, drv: DriverRSelect) -> bool { 144 | let offset = match drv { 145 | DriverRSelect::D0R => Self::D0RS_EN_OFFSET, 146 | DriverRSelect::D1R => Self::D1RS_EN_OFFSET, 147 | DriverRSelect::D2R => Self::D2RS_EN_OFFSET, 148 | DriverRSelect::D3R => Self::D3RS_EN_OFFSET, 149 | }; 150 | let mask = match drv { 151 | DriverRSelect::D0R => Self::D0RS_EN_MASK, 152 | DriverRSelect::D1R => Self::D1RS_EN_MASK, 153 | DriverRSelect::D2R => Self::D2RS_EN_MASK, 154 | DriverRSelect::D3R => Self::D3RS_EN_MASK, 155 | }; 156 | (self.0 >> offset) & mask == mask 157 | } 158 | pub fn enable(&mut self, drv: DriverRSelect) -> &mut Self { 159 | let offset = match drv { 160 | DriverRSelect::D0R => Self::D0RS_EN_OFFSET, 161 | DriverRSelect::D1R => Self::D1RS_EN_OFFSET, 162 | DriverRSelect::D2R => Self::D2RS_EN_OFFSET, 163 | DriverRSelect::D3R => Self::D3RS_EN_OFFSET, 164 | }; 165 | let mask = match drv { 166 | DriverRSelect::D0R => Self::D0RS_EN_MASK, 167 | DriverRSelect::D1R => Self::D1RS_EN_MASK, 168 | DriverRSelect::D2R => Self::D2RS_EN_MASK, 169 | DriverRSelect::D3R => Self::D3RS_EN_MASK, 170 | }; 171 | self.0 |= mask << offset; 172 | self 173 | } 174 | pub fn disable(&mut self, drv: DriverRSelect) -> &mut Self { 175 | let offset = match drv { 176 | DriverRSelect::D0R => Self::D0RS_EN_OFFSET, 177 | DriverRSelect::D1R => Self::D1RS_EN_OFFSET, 178 | DriverRSelect::D2R => Self::D2RS_EN_OFFSET, 179 | DriverRSelect::D3R => Self::D3RS_EN_OFFSET, 180 | }; 181 | let mask = match drv { 182 | DriverRSelect::D0R => Self::D0RS_EN_MASK, 183 | DriverRSelect::D1R => Self::D1RS_EN_MASK, 184 | DriverRSelect::D2R => Self::D2RS_EN_MASK, 185 | DriverRSelect::D3R => Self::D3RS_EN_MASK, 186 | }; 187 | self.0 &= !(mask << offset); 188 | self 189 | } 190 | } 191 | 192 | impl core::fmt::Display for IoDriverStrenghtConfiguration { 193 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 194 | f.debug_struct("IoDriverStrenghtConfiguration") 195 | .field("RF_DS", &self.strenght(DriverSelect::RF)) 196 | .field("RO_DS", &self.strenght(DriverSelect::RO)) 197 | .field("CLKO_DS", &self.strenght(DriverSelect::CLKO)) 198 | .field("NRSTO_DS", &self.strenght(DriverSelect::NRSTO)) 199 | .field("BO_DS", &self.strenght(DriverSelect::BO)) 200 | .field("CO_DS", &self.strenght(DriverSelect::CO)) 201 | .finish() 202 | } 203 | } 204 | 205 | #[cfg(feature = "defmt")] 206 | impl defmt::Format for IoDriverStrenghtConfiguration { 207 | fn format(&self, fmt: defmt::Formatter) { 208 | defmt::write!( 209 | fmt, 210 | "IoDriverStrenghtConfiguration {{ RF_DS: {}, RO_DS: {}, CLKO_DS: {}, NRSTO_DS: {}, BO_DS: {}, CO_DS: {} }}", 211 | self.strenght(DriverSelect::RF), 212 | self.strenght(DriverSelect::RO), 213 | self.strenght(DriverSelect::CLKO), 214 | self.strenght(DriverSelect::NRSTO), 215 | self.strenght(DriverSelect::BO), 216 | self.strenght(DriverSelect::CO), 217 | ); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/fast_uart.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// # Fast UART Configuration register 4 | /// 5 | /// Used to configure UART settings. 6 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 7 | pub struct FastUARTConfiguration(pub u32); 8 | impl_boilerplate_for!(FastUARTConfiguration); 9 | 10 | impl FastUARTConfiguration { 11 | pub const ADDR: u8 = 0x28; 12 | 13 | // const DIV4_ODDSET_OFFSET: u8 = 30; 14 | const PLL3_DIV4_OFFSET: u8 = 24; 15 | // const USRC_ODDSET_OFFSET: u8 = 22; 16 | // const USRC_DIV_OFFSET: u8 = 16; 17 | // const FORCE_CORE_EN_OFFSET: u8 = 15; 18 | // const CLKO_SEL_OFFSET: u8 = 14; 19 | // const CLKO_ODDSET_OFFSET: u8 = 12; 20 | // const CLKO_DIV_OFFSET: u8 = 0; 21 | 22 | // const DIV4_ODDSET_MASK: u32 = 0b11; 23 | const PLL3_DIV4_MASK: u32 = 0b1111; 24 | // const USRC_ODDSET_MASK: u32 = 0b11; 25 | // const USRC_DIV_MASK: u32 = 0x3f; 26 | // const FORCE_CORE_EN_MASK: u32 = 0b1; 27 | // const CLKO_SEL_MASK: u32 = 0b1; 28 | // const CLKO_ODDSET_MASK: u32 = 0b11; 29 | // const CLKO_DIV_MASK: u32 = 0xff; 30 | 31 | /// ## Handle the PLL3_DIV4 field. 32 | /// 33 | /// This returns an `u8` with the PLL3_DIV4 value. 34 | /// 35 | /// ### Example 36 | /// 37 | /// ``` 38 | /// use bm13xx_asic::register::FastUARTConfiguration; 39 | /// 40 | /// let mut fast_uart_cfg = FastUARTConfiguration(0x0600_000F); // deafault BM1397 value 41 | /// assert_eq!(fast_uart_cfg.pll3_div4(), 6); 42 | /// assert_eq!(fast_uart_cfg.set_pll3_div4(0).pll3_div4(), 0); 43 | /// assert_eq!(fast_uart_cfg.set_pll3_div4(15).pll3_div4(), 15); 44 | /// assert_eq!(fast_uart_cfg.set_pll3_div4(16).pll3_div4(), 0); 45 | /// ``` 46 | pub const fn pll3_div4(&self) -> u8 { 47 | ((self.0 >> Self::PLL3_DIV4_OFFSET) & Self::PLL3_DIV4_MASK) as u8 48 | } 49 | pub fn set_pll3_div4(&mut self, pll3_div4: u8) -> &mut Self { 50 | self.0 &= !(Self::PLL3_DIV4_MASK << Self::PLL3_DIV4_OFFSET); 51 | self.0 |= ((pll3_div4 as u32) & Self::PLL3_DIV4_MASK) << Self::PLL3_DIV4_OFFSET; 52 | self 53 | } 54 | } 55 | 56 | impl core::fmt::Display for FastUARTConfiguration { 57 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 58 | f.debug_struct("FastUARTConfiguration") 59 | .field("pll3_div4", &self.pll3_div4()) 60 | .finish() 61 | } 62 | } 63 | 64 | #[cfg(feature = "defmt")] 65 | impl defmt::Format for FastUARTConfiguration { 66 | fn format(&self, fmt: defmt::Formatter) { 67 | defmt::write!( 68 | fmt, 69 | "FastUARTConfiguration {{ pll3_div4: {} }}", 70 | self.pll3_div4(), 71 | ); 72 | } 73 | } 74 | 75 | /// Baudrate CLocK SELect (second version) 76 | /// 77 | /// This is used by [`FastUARTConfigurationV2::bclk_sel`] method. 78 | /// 79 | /// [`FastUARTConfigurationV2::bclk_sel`]: crate::register::FastUARTConfigurationV2::bclk_sel 80 | #[derive(Copy, Clone, Eq, PartialEq, Debug, PartialOrd, Ord, Hash, Default)] 81 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 82 | #[repr(u8)] 83 | pub enum BaudrateClockSelectV2 { 84 | /// Baudrate base clock is CLKI (external clock). 85 | #[default] 86 | Clki = 0, 87 | /// Baudrate base clock is PLL1. 88 | Pll1 = 1, 89 | // /// Baudrate base clock is PLL2. 90 | // Pll2 = 2, 91 | // /// Baudrate base clock is PLL3. 92 | // Pll3 = 3, 93 | } 94 | 95 | impl From for BaudrateClockSelectV2 { 96 | fn from(val: u8) -> BaudrateClockSelectV2 { 97 | match val { 98 | 0 => BaudrateClockSelectV2::Clki, 99 | 1 => BaudrateClockSelectV2::Pll1, 100 | // 2 => BaudrateClockSelectV2::Pll2, 101 | // 3 => BaudrateClockSelectV2::Pll3, 102 | _ => unreachable!(), 103 | } 104 | } 105 | } 106 | 107 | impl From for u8 { 108 | fn from(val: BaudrateClockSelectV2) -> u8 { 109 | val as u8 110 | } 111 | } 112 | 113 | /// # Fast UART Configuration register (second version) 114 | /// 115 | /// Used to configure UART settings. 116 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 117 | pub struct FastUARTConfigurationV2(pub u32); 118 | impl_boilerplate_for!(FastUARTConfigurationV2); 119 | 120 | impl FastUARTConfigurationV2 { 121 | pub const ADDR: u8 = 0x28; 122 | 123 | // const B31_OFFSET: u8 = 31; 124 | // const B29_OFFSET: u8 = 30; 125 | // const B28_OFFSET: u8 = 29; 126 | const B28_OFFSET: u8 = 28; 127 | const BCK_SEL_OFFSET: u8 = 26; 128 | // const B24_OFFSET: u8 = 24; 129 | const PLL1_DIV4_OFFSET: u8 = 20; 130 | // const B16_19_OFFSET: u8 = 16; 131 | const BT8D_OFFSET: u8 = 8; 132 | // const CLKO_DIV_OFFSET: u8 = 0; 133 | 134 | // const B31_MASK: u32 = 0b1; 135 | // const B30_MASK: u32 = 0b1; 136 | // const B29_MASK: u32 = 0b1; 137 | const B28_MASK: u32 = 0b1; 138 | const BCK_SEL_MASK: u32 = 0b1; /* should be 0b11 but only 1 values are known for now */ 139 | // const B24_MASK: u32 = 0b1; 140 | const PLL1_DIV4_MASK: u32 = 0b1111; 141 | // const B16_19_MASK: u32 = 0b1111; 142 | const BT8D_MASK: u32 = 0xff; 143 | // const CLKO_DIV_MASK: u32 = 0xff; 144 | 145 | /// ## Handle the B28 field. 146 | /// 147 | /// Get and set the B28 state. 148 | /// 149 | /// ### Example 150 | /// 151 | /// ``` 152 | /// use bm13xx_asic::register::FastUARTConfigurationV2; 153 | /// 154 | /// let mut fast_uart_cfg = FastUARTConfigurationV2(0x0007_0000); // BM1366 default value 155 | /// assert!(!fast_uart_cfg.is_b28()); 156 | /// assert!(fast_uart_cfg.set_b28().is_b28()); 157 | /// assert!(!fast_uart_cfg.clr_b28().is_b28()); 158 | /// ``` 159 | pub const fn is_b28(&self) -> bool { 160 | (self.0 >> Self::B28_OFFSET) & Self::B28_MASK == Self::B28_MASK 161 | } 162 | pub fn set_b28(&mut self) -> &mut Self { 163 | self.0 |= Self::B28_MASK << Self::B28_OFFSET; 164 | self 165 | } 166 | pub fn clr_b28(&mut self) -> &mut Self { 167 | self.0 &= !(Self::B28_MASK << Self::B28_OFFSET); 168 | self 169 | } 170 | 171 | /// ## Handle the Baudrate Clock Select field. 172 | /// 173 | /// This returns an `BaudrateClockSelectV2` with the current Baudrate Clock Select. 174 | /// 175 | /// ### Example 176 | /// 177 | /// ``` 178 | /// use bm13xx_asic::register::{BaudrateClockSelectV2, FastUARTConfigurationV2}; 179 | /// 180 | /// let mut fast_uart_cfg = FastUARTConfigurationV2(0x0130_1A00); // BM1366 default value 181 | /// assert_eq!(fast_uart_cfg.bclk_sel(), BaudrateClockSelectV2::Clki); 182 | /// assert_eq!(fast_uart_cfg.set_bclk_sel(BaudrateClockSelectV2::Pll1).bclk_sel(), BaudrateClockSelectV2::Pll1); 183 | /// ``` 184 | pub fn bclk_sel(&self) -> BaudrateClockSelectV2 { 185 | (((self.0 >> Self::BCK_SEL_OFFSET) & Self::BCK_SEL_MASK) as u8).into() 186 | } 187 | pub fn set_bclk_sel(&mut self, bclk_sel: BaudrateClockSelectV2) -> &mut Self { 188 | self.0 &= !(Self::BCK_SEL_MASK << Self::BCK_SEL_OFFSET); 189 | self.0 |= ((bclk_sel as u32) & Self::BCK_SEL_MASK) << Self::BCK_SEL_OFFSET; 190 | self 191 | } 192 | 193 | /// ## Handle the PLL1_DIV4 field. 194 | /// 195 | /// This returns an `u8` with the PLL1_DIV4 value. 196 | /// 197 | /// ### Example 198 | /// 199 | /// ``` 200 | /// use bm13xx_asic::register::FastUARTConfigurationV2; 201 | /// 202 | /// let mut fast_uart_cfg = FastUARTConfigurationV2(0x0130_1A00); // BM1366 default value 203 | /// assert_eq!(fast_uart_cfg.pll1_div4(), 3); 204 | /// assert_eq!(fast_uart_cfg.set_pll1_div4(0).pll1_div4(), 0); 205 | /// assert_eq!(fast_uart_cfg.set_pll1_div4(15).pll1_div4(), 15); 206 | /// assert_eq!(fast_uart_cfg.set_pll1_div4(16).pll1_div4(), 0); 207 | /// ``` 208 | pub const fn pll1_div4(&self) -> u8 { 209 | ((self.0 >> Self::PLL1_DIV4_OFFSET) & Self::PLL1_DIV4_MASK) as u8 210 | } 211 | pub fn set_pll1_div4(&mut self, pll3_div4: u8) -> &mut Self { 212 | self.0 &= !(Self::PLL1_DIV4_MASK << Self::PLL1_DIV4_OFFSET); 213 | self.0 |= ((pll3_div4 as u32) & Self::PLL1_DIV4_MASK) << Self::PLL1_DIV4_OFFSET; 214 | self 215 | } 216 | /// ## Handle the BT8D field. 217 | /// 218 | /// This returns an `u8` with the BT8D value. 219 | /// 220 | /// ### Example 221 | /// 222 | /// ``` 223 | /// use bm13xx_asic::register::FastUARTConfigurationV2; 224 | /// 225 | /// let mut fast_uart_cfg = FastUARTConfigurationV2(0x0130_1A00); // BM1366 default value 226 | /// assert_eq!(fast_uart_cfg.bt8d(), 26); 227 | /// assert_eq!(fast_uart_cfg.set_bt8d(0).bt8d(), 0); // min value 228 | /// assert_eq!(fast_uart_cfg.set_bt8d(0xff).bt8d(), 255); // max value 229 | /// ``` 230 | pub const fn bt8d(&self) -> u8 { 231 | ((self.0 >> Self::BT8D_OFFSET) & Self::BT8D_MASK) as u8 232 | } 233 | pub fn set_bt8d(&mut self, bt8d: u8) -> &mut Self { 234 | self.0 &= !(Self::BT8D_MASK << Self::BT8D_OFFSET); 235 | self.0 |= (bt8d as u32 & Self::BT8D_MASK) << Self::BT8D_OFFSET; 236 | self 237 | } 238 | } 239 | 240 | impl core::fmt::Display for FastUARTConfigurationV2 { 241 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 242 | f.debug_struct("FastUARTConfigurationV2") 243 | .field("pll1_div4", &self.pll1_div4()) 244 | .finish() 245 | } 246 | } 247 | 248 | #[cfg(feature = "defmt")] 249 | impl defmt::Format for FastUARTConfigurationV2 { 250 | fn format(&self, fmt: defmt::Formatter) { 251 | defmt::write!( 252 | fmt, 253 | "FastUARTConfigurationV2 {{ pll1_div4: {} }}", 254 | self.pll1_div4(), 255 | ); 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /bm13xx-asic/src/register/misc.rs: -------------------------------------------------------------------------------- 1 | use crate::register::Register; 2 | 3 | /// Baudrate CLocK SELect. 4 | /// 5 | /// This is used by [`MiscControl::bclk_sel`] method. 6 | /// 7 | /// [`MiscControl::bclk_sel`]: crate::register::MiscControl::bclk_sel 8 | #[derive(Copy, Clone, Eq, PartialEq, Debug, PartialOrd, Ord, Hash, Default)] 9 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 10 | #[repr(u8)] 11 | pub enum BaudrateClockSelect { 12 | /// Baudrate base clock is CLKI (external clock). 13 | #[default] 14 | Clki = 0, 15 | /// Baudrate base clock is PLL3. 16 | Pll3 = 1, 17 | } 18 | 19 | impl From for BaudrateClockSelect { 20 | fn from(val: bool) -> BaudrateClockSelect { 21 | if val { 22 | BaudrateClockSelect::Clki 23 | } else { 24 | BaudrateClockSelect::Pll3 25 | } 26 | } 27 | } 28 | 29 | impl From for u8 { 30 | fn from(val: BaudrateClockSelect) -> u8 { 31 | val as u8 32 | } 33 | } 34 | 35 | /// # Misc Control register 36 | /// 37 | /// Used to control various settings. 38 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 39 | pub struct MiscControl(pub u32); 40 | impl_boilerplate_for!(MiscControl); 41 | 42 | impl MiscControl { 43 | pub const ADDR: u8 = 0x18; 44 | 45 | const BT8D_8_5_OFFSET: u8 = 24; 46 | const CORE_SRST_OFFSET: u8 = 22; 47 | // const SPAT_NOD_OFFSET: u8 = 21; 48 | // const RVS_K0_OFFSET: u8 = 20; 49 | // const DSCLK_SEL_OFFSET: u8 = 18; 50 | // const TOP_CLK_SEL_OFFSET: u8 = 17; 51 | const BCK_SEL_OFFSET: u8 = 16; 52 | // const RET_ERR_NONCE_OFFSET: u8 = 15; 53 | // const RFS_OFFSET: u8 = 14; 54 | // const INV_CLKO_OFFSET: u8 = 13; 55 | const BT8D_4_0_OFFSET: u8 = 8; 56 | // const RET_WORK_ERR_FLAG_OFFSET: u8 = 7; 57 | // const TFS_OFFSET: u8 = 4; 58 | // const HASHRATE_TWS_OFFSET: u8 = 0; 59 | 60 | const BT8D_8_5_MASK: u32 = 0b1111; 61 | const CORE_SRST_MASK: u32 = 0b1; 62 | // const SPAT_NOD_MASK: u32 = 0b1; 63 | // const RVS_K0_MASK: u32 = 0b1; 64 | // const DSCLK_SEL_MASK: u32 = 0b11; 65 | // const TOP_CLK_SEL_MASK: u32 = 0b1; 66 | const BCK_SEL_MASK: u32 = 0b1; 67 | // const RET_ERR_NONCE_MASK: u32 = 0b1; 68 | // const RFS_MASK: u32 = 0b1; 69 | // const INV_CLKO_MASK: u32 = 0b1; 70 | const BT8D_4_0_MASK: u32 = 0b11111; 71 | // const RET_WORK_ERR_FLAG_MASK: u32 = 0b1; 72 | // const TFS_MASK: u32 = 0xb111; 73 | // const HASHRATE_TWS_MASK: u32 = 0xb11; 74 | 75 | /// ## Handle the BT8D field. 76 | /// 77 | /// This returns an `u16` with the 9-bits BT8D value. 78 | /// 79 | /// ### Example 80 | /// 81 | /// ``` 82 | /// use bm13xx_asic::register::MiscControl; 83 | /// 84 | /// let mut misc = MiscControl(0x0000_3A01); 85 | /// assert_eq!(misc.bt8d(), 26); 86 | /// assert_eq!(misc.set_bt8d(0).bt8d(), 0); // min value 87 | /// assert_eq!(misc.set_bt8d(0x1ff).bt8d(), 511); // max value 88 | /// assert_eq!(misc.set_bt8d(0x200).bt8d(), 0); // out of bound value 89 | /// ``` 90 | pub const fn bt8d(&self) -> u16 { 91 | ((((self.0 >> Self::BT8D_8_5_OFFSET) & Self::BT8D_8_5_MASK) as u16) << 5) 92 | | (((self.0 >> Self::BT8D_4_0_OFFSET) & Self::BT8D_4_0_MASK) as u16) 93 | } 94 | pub fn set_bt8d(&mut self, bt8d: u16) -> &mut Self { 95 | self.0 &= !(Self::BT8D_8_5_MASK << Self::BT8D_8_5_OFFSET); 96 | self.0 |= ((bt8d >> 5) as u32 & Self::BT8D_8_5_MASK) << Self::BT8D_8_5_OFFSET; 97 | self.0 &= !(Self::BT8D_4_0_MASK << Self::BT8D_4_0_OFFSET); 98 | self.0 |= (bt8d as u32 & Self::BT8D_4_0_MASK) << Self::BT8D_4_0_OFFSET; 99 | self 100 | } 101 | 102 | /// ## Reset the Core. 103 | /// 104 | /// This returns an `bool` with the Core Reset state. 105 | /// 106 | /// ### Example 107 | /// 108 | /// ``` 109 | /// use bm13xx_asic::register::MiscControl; 110 | /// 111 | /// let misc = MiscControl(0x0000_3A01); 112 | /// assert!(!misc.core_srst()); 113 | /// ``` 114 | pub const fn core_srst(&self) -> bool { 115 | (self.0 >> Self::CORE_SRST_OFFSET) & Self::CORE_SRST_MASK == Self::CORE_SRST_MASK 116 | } 117 | 118 | /// ## Handle the Baudrate Clock Select field. 119 | /// 120 | /// This returns an `BaudrateClockSelect` with the current Baudrate Clock Select. 121 | /// 122 | /// ### Example 123 | /// 124 | /// ``` 125 | /// use bm13xx_asic::register::{BaudrateClockSelect, MiscControl}; 126 | /// 127 | /// let mut misc = MiscControl(0x0000_3A01); 128 | /// assert_eq!(misc.bclk_sel(), BaudrateClockSelect::Clki); 129 | /// assert_eq!(misc.set_bclk_sel(BaudrateClockSelect::Pll3).bclk_sel(), BaudrateClockSelect::Pll3); 130 | /// ``` 131 | pub const fn bclk_sel(&self) -> BaudrateClockSelect { 132 | match (self.0 >> Self::BCK_SEL_OFFSET) & Self::BCK_SEL_MASK == Self::BCK_SEL_MASK { 133 | true => BaudrateClockSelect::Pll3, 134 | false => BaudrateClockSelect::Clki, 135 | } 136 | } 137 | pub fn set_bclk_sel(&mut self, bclk_sel: BaudrateClockSelect) -> &mut Self { 138 | self.0 &= !(Self::BCK_SEL_MASK << Self::BCK_SEL_OFFSET); 139 | self.0 |= (bclk_sel as u32) << Self::BCK_SEL_OFFSET; 140 | self 141 | } 142 | } 143 | 144 | impl core::fmt::Display for MiscControl { 145 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 146 | f.debug_struct("MiscControl") 147 | .field("bt8d", &self.bt8d()) 148 | .field("core_srst", &self.core_srst()) 149 | .field("bclk_sel", &self.bclk_sel()) 150 | .finish() 151 | } 152 | } 153 | 154 | #[cfg(feature = "defmt")] 155 | impl defmt::Format for MiscControl { 156 | fn format(&self, fmt: defmt::Formatter) { 157 | defmt::write!( 158 | fmt, 159 | "MiscControl {{ bt8d: {}, core_srst: {}, bclk_sel: {} }}", 160 | self.bt8d(), 161 | self.core_srst(), 162 | self.bclk_sel(), 163 | ); 164 | } 165 | } 166 | 167 | /// # Misc Control register V2 168 | /// 169 | /// Used to control various settings. 170 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 171 | pub struct MiscControlV2(pub u32); 172 | impl_boilerplate_for!(MiscControlV2); 173 | 174 | impl MiscControlV2 { 175 | pub const ADDR: u8 = 0x18; 176 | 177 | const CORE_RETURN_NONCE_OFFSET: u8 = 28; 178 | const B27_26_OFFSET: u8 = 26; 179 | const B25_24_OFFSET: u8 = 24; 180 | const B19_16_OFFSET: u8 = 16; 181 | 182 | const CORE_RETURN_NONCE_MASK: u32 = 0b1111; 183 | const B27_26_MASK: u32 = 0b11; 184 | const B25_24_MASK: u32 = 0b11; 185 | const B19_16_MASK: u32 = 0b1111; 186 | 187 | /// ## Handle the Core Return Nonce field. 188 | /// 189 | /// Get and set the Core Return Nonce value. 190 | /// 191 | /// ### Example 192 | /// 193 | /// ``` 194 | /// use bm13xx_asic::register::MiscControlV2; 195 | /// 196 | /// let mut misc = MiscControlV2(0x0000_C100); // BM1366 default value 197 | /// assert_eq!(misc.core_return_nonce(), 0); 198 | /// assert_eq!(misc.set_core_return_nonce(0xf).core_return_nonce(), 0xf); // max value 199 | /// assert_eq!(misc.set_core_return_nonce(0x10).core_return_nonce(), 0); // out of bound value 200 | /// ``` 201 | pub const fn core_return_nonce(&self) -> u8 { 202 | ((self.0 >> Self::CORE_RETURN_NONCE_OFFSET) & Self::CORE_RETURN_NONCE_MASK) as u8 203 | } 204 | pub fn set_core_return_nonce(&mut self, core_return_nonce: u8) -> &mut Self { 205 | self.0 &= !(Self::CORE_RETURN_NONCE_MASK << Self::CORE_RETURN_NONCE_OFFSET); 206 | self.0 |= ((core_return_nonce as u32) & Self::CORE_RETURN_NONCE_MASK) 207 | << Self::CORE_RETURN_NONCE_OFFSET; 208 | self 209 | } 210 | 211 | /// ## Handle the B\[27:26\] field. 212 | /// 213 | /// Get and set the B\[27:26\] value. 214 | /// 215 | /// ### Example 216 | /// 217 | /// ``` 218 | /// use bm13xx_asic::register::MiscControlV2; 219 | /// 220 | /// let mut misc = MiscControlV2(0x0000_C100); // BM1366 default value 221 | /// assert_eq!(misc.b27_26(), 0); 222 | /// assert_eq!(misc.set_b27_26(0b11).b27_26(), 0b11); // max value 223 | /// assert_eq!(misc.set_b27_26(0b100).b27_26(), 0b00); // out of bound value 224 | /// ``` 225 | pub const fn b27_26(&self) -> u8 { 226 | ((self.0 >> Self::B27_26_OFFSET) & Self::B27_26_MASK) as u8 227 | } 228 | pub fn set_b27_26(&mut self, b27_26: u8) -> &mut Self { 229 | self.0 &= !(Self::B27_26_MASK << Self::B27_26_OFFSET); 230 | self.0 |= ((b27_26 as u32) & Self::B27_26_MASK) << Self::B27_26_OFFSET; 231 | self 232 | } 233 | 234 | /// ## Handle the B\[25:24\] field. 235 | /// 236 | /// Get and set the B\[25:24\] value. 237 | /// 238 | /// ### Example 239 | /// 240 | /// ``` 241 | /// use bm13xx_asic::register::MiscControlV2; 242 | /// 243 | /// let mut misc = MiscControlV2(0x0000_C100); // BM1366 default value 244 | /// assert_eq!(misc.b25_24(), 0); 245 | /// assert_eq!(misc.set_b25_24(0b11).b25_24(), 0b11); // max value 246 | /// assert_eq!(misc.set_b25_24(0b100).b25_24(), 0b0); // out of bound value 247 | /// ``` 248 | pub const fn b25_24(&self) -> u8 { 249 | ((self.0 >> Self::B25_24_OFFSET) & Self::B25_24_MASK) as u8 250 | } 251 | pub fn set_b25_24(&mut self, b25_24: u8) -> &mut Self { 252 | self.0 &= !(Self::B25_24_MASK << Self::B25_24_OFFSET); 253 | self.0 |= ((b25_24 as u32) & Self::B25_24_MASK) << Self::B25_24_OFFSET; 254 | self 255 | } 256 | 257 | /// ## Handle the B\[19:16\] field. 258 | /// 259 | /// Get and set the B\[19:16\] value. 260 | /// 261 | /// ### Example 262 | /// 263 | /// ``` 264 | /// use bm13xx_asic::register::MiscControlV2; 265 | /// 266 | /// let mut misc = MiscControlV2(0x0000_C100); // BM1366 default value 267 | /// assert_eq!(misc.b19_16(), 0); 268 | /// assert_eq!(misc.set_b19_16(0b1111).b19_16(), 0b1111); // max value 269 | /// assert_eq!(misc.set_b19_16(0b10000).b19_16(), 0b0000); // out of bound value 270 | /// ``` 271 | pub const fn b19_16(&self) -> u8 { 272 | ((self.0 >> Self::B19_16_OFFSET) & Self::B19_16_MASK) as u8 273 | } 274 | pub fn set_b19_16(&mut self, b19_16: u8) -> &mut Self { 275 | self.0 &= !(Self::B19_16_MASK << Self::B19_16_OFFSET); 276 | self.0 |= ((b19_16 as u32) & Self::B19_16_MASK) << Self::B19_16_OFFSET; 277 | self 278 | } 279 | } 280 | 281 | impl core::fmt::Display for MiscControlV2 { 282 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 283 | f.debug_struct("MiscControlV2").finish() 284 | } 285 | } 286 | 287 | #[cfg(feature = "defmt")] 288 | impl defmt::Format for MiscControlV2 { 289 | fn format(&self, fmt: defmt::Formatter) { 290 | defmt::write!(fmt, "MiscControlV2 {{ }}",); 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /bm13xx-protocol/src/response.rs: -------------------------------------------------------------------------------- 1 | //! BM13xx Protocol Responses. 2 | 3 | use crate::crc::{crc5, crc5_bits}; 4 | use crate::{Error, Result}; 5 | 6 | #[derive(Debug, PartialEq)] 7 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 8 | pub struct RegisterResponse { 9 | pub chip_addr: u8, 10 | pub reg_addr: u8, 11 | pub reg_value: u32, 12 | } 13 | 14 | #[derive(Debug, PartialEq)] 15 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 16 | pub struct JobResponse { 17 | pub nonce: u32, 18 | pub job_id: usize, 19 | pub midstate_id: usize, 20 | pub small_core_id: usize, 21 | } 22 | 23 | #[derive(Debug, PartialEq)] 24 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 25 | pub struct JobVersionResponse { 26 | pub nonce: u32, 27 | pub unknown: u8, 28 | pub job_id: usize, 29 | pub small_core_id: usize, 30 | pub version_bit: u32, 31 | } 32 | 33 | #[derive(Debug, PartialEq)] 34 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 35 | pub enum ResponseType { 36 | Reg(RegisterResponse), 37 | Job(JobResponse), 38 | JobVer(JobVersionResponse), 39 | } 40 | 41 | pub const FRAME_SIZE: usize = 9; 42 | pub const FRAME_SIZE_VER: usize = 11; 43 | 44 | #[derive(Debug)] 45 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 46 | pub struct Response; 47 | 48 | impl Response { 49 | /// # Parse Response 50 | /// 51 | /// Parse raw bytes from RO signal of BM13xx with Version Rolling disabled. 52 | /// 53 | /// The packet must have a lenght of 9 bytes. 54 | /// 55 | /// ## Return 56 | /// - `Err(Error::InvalidPreamble)` if it first 2 bytes are not `[0xAA, 0x55]`. 57 | /// - `Err(Error::UnsupportedCoreSmallCoreCnt)` if core_small_core_cnt is not 4, 8 or 16. 58 | /// - `Err(Error::InvalidCrc)` if the CRC5 is not valid. 59 | /// - `Ok(ResponseType::Reg(r))` with the `RegisterResponse`. 60 | /// - `Ok(ResponseType::Job(j))` with the `JobResponse`. 61 | /// 62 | /// ## Example 63 | /// 64 | /// ``` 65 | /// use bm13xx_protocol::Error; 66 | /// use bm13xx_protocol::response::{Response, ResponseType}; 67 | /// 68 | /// // Error::InvalidPreamble 69 | /// let resp = Response::parse(&[0x00,0x55,0x13,0x97,0x18,0x00,0x00,0x00,0x06], 4); 70 | /// assert!(resp.is_err()); 71 | /// assert_eq!(resp.unwrap_err(), Error::InvalidPreamble); 72 | /// 73 | /// let resp = Response::parse(&[0xAA,0x00,0x13,0x97,0x18,0x00,0x00,0x00,0x06], 4); 74 | /// assert!(resp.is_err()); 75 | /// assert_eq!(resp.unwrap_err(), Error::InvalidPreamble); 76 | /// 77 | /// let resp = Response::parse(&[0x00,0x00,0x13,0x97,0x18,0x00,0x00,0x00,0x06], 4); 78 | /// assert!(resp.is_err()); 79 | /// assert_eq!(resp.unwrap_err(), Error::InvalidPreamble); 80 | /// 81 | /// // Error::UnsupportedCoreSmallCoreCnt 82 | /// let resp = Response::parse(&[0xAA,0x55,0x13,0x97,0x18,0x00,0x00,0x00,0x06], 5); 83 | /// assert!(resp.is_err()); 84 | /// assert_eq!(resp.unwrap_err(), Error::UnsupportedCoreSmallCoreCnt); 85 | /// 86 | /// // Error::InvalidCrc 87 | /// let resp = Response::parse(&[0xAA,0x55,0x13,0x97,0x18,0x00,0x00,0x00,0x00], 4); // should be 0x06 88 | /// assert!(resp.is_err()); 89 | /// assert_eq!(resp.unwrap_err(), Error::InvalidCrc { expected: 0x06, actual: 0x00 }); 90 | /// 91 | /// // ChipIdentification == 0x13971800 92 | /// let resp = Response::parse(&[0xAA,0x55,0x13,0x97,0x18,0x00,0x00,0x00,0x06], 4); 93 | /// assert!(resp.is_ok()); 94 | /// match resp.unwrap() { 95 | /// ResponseType::Reg(r) => { 96 | /// assert_eq!(r.chip_addr, 0); 97 | /// assert_eq!(r.reg_addr, 0x00); 98 | /// assert_eq!(r.reg_value, 0x1397_1800); 99 | /// }, 100 | /// _ => panic!(), 101 | /// }; 102 | /// 103 | /// let resp = Response::parse(&[0xAA,0x55,0x97,0xC3,0x28,0xB6,0x01,0x63,0x9C], 4); 104 | /// assert!(resp.is_ok()); 105 | /// match resp.unwrap() { 106 | /// ResponseType::Job(j) => { 107 | /// assert_eq!(j.nonce, 0xB628_C397); 108 | /// assert_eq!(j.midstate_id, 1); 109 | /// assert_eq!(j.job_id, 24); 110 | /// assert_eq!(j.small_core_id, 3); 111 | /// }, 112 | /// _ => panic!(), 113 | /// }; 114 | /// ``` 115 | pub fn parse(data: &[u8; FRAME_SIZE], core_small_core_cnt: usize) -> Result { 116 | if data[0] != 0xAA || data[1] != 0x55 { 117 | return Err(Error::InvalidPreamble); 118 | } 119 | if core_small_core_cnt != 4 && core_small_core_cnt != 8 && core_small_core_cnt != 16 { 120 | return Err(Error::UnsupportedCoreSmallCoreCnt); 121 | } 122 | if crc5(&data[2..9]) != 0x00 { 123 | return Err(Error::InvalidCrc { 124 | expected: crc5_bits(&data[2..9]), 125 | actual: data[8] & 0x1f, 126 | }); 127 | } 128 | if data[8] & 0x80 == 0x80 { 129 | let small_core_mask = core_small_core_cnt - 1; 130 | let small_core_bits = small_core_mask.count_ones(); 131 | return Ok(ResponseType::Job(JobResponse { 132 | nonce: u32::from_le_bytes(data[2..6].try_into().unwrap()), 133 | midstate_id: data[6] as usize, 134 | job_id: ((data[7] as usize) >> small_core_bits) & 0b1_1111, 135 | small_core_id: (data[7] as usize) & small_core_mask, 136 | })); 137 | } 138 | Ok(ResponseType::Reg(RegisterResponse { 139 | chip_addr: data[6], 140 | reg_addr: data[7], 141 | reg_value: u32::from_be_bytes(data[2..6].try_into().unwrap()), 142 | })) 143 | } 144 | 145 | /// # Parse Version Response 146 | /// 147 | /// Parse raw bytes from RO signal of BM13xx with Version Rolling enabled. 148 | /// 149 | /// The packet must have a lenght of 11 bytes. 150 | /// 151 | /// ## Return 152 | /// - `Err(Error::InvalidPreamble)` if it first 2 bytes are not `[0xAA, 0x55]`. 153 | /// - `Err(Error::UnsupportedCoreSmallCoreCnt)` if core_small_core_cnt is not 8 or 16. 154 | /// - `Err(Error::InvalidCrc)` if the CRC5 is not valid. 155 | /// - `Ok(ResponseType::Reg(r))` with the `RegisterResponse`. 156 | /// - `Ok(ResponseType::JobVer(j))` with the `JobVersionResponse`. 157 | /// 158 | /// ## Example 159 | /// 160 | /// ``` 161 | /// use bm13xx_protocol::Error; 162 | /// use bm13xx_protocol::response::{Response, ResponseType}; 163 | /// 164 | /// // Error::InvalidPreamble 165 | /// let resp = Response::parse_version(&[0x00,0x55,0x13,0x97,0x18,0x00,0x00,0x00,0x00,0x00,0x06], 8); 166 | /// assert!(resp.is_err()); 167 | /// assert_eq!(resp.unwrap_err(), Error::InvalidPreamble); 168 | /// 169 | /// let resp = Response::parse_version(&[0xAA,0x00,0x13,0x97,0x18,0x00,0x00,0x00,0x00,0x00,0x06], 8); 170 | /// assert!(resp.is_err()); 171 | /// assert_eq!(resp.unwrap_err(), Error::InvalidPreamble); 172 | /// 173 | /// let resp = Response::parse_version(&[0x00,0x00,0x13,0x97,0x18,0x00,0x00,0x00,0x00,0x00,0x06], 8); 174 | /// assert!(resp.is_err()); 175 | /// assert_eq!(resp.unwrap_err(), Error::InvalidPreamble); 176 | /// 177 | /// // Error::UnsupportedCoreSmallCoreCnt 178 | /// let resp = Response::parse_version(&[0xAA,0x55,0x2F,0xD5,0x96,0xCE,0x02,0x93,0x94,0xFB,0x86], 9); 179 | /// assert!(resp.is_err()); 180 | /// assert_eq!(resp.unwrap_err(), Error::UnsupportedCoreSmallCoreCnt); 181 | /// 182 | /// // Error::InvalidCrc 183 | /// let resp = Response::parse_version(&[0xAA,0x55,0x13,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00], 8); // should be 0x05 184 | /// assert!(resp.is_err()); 185 | /// assert_eq!(resp.unwrap_err(), Error::InvalidCrc { expected: 0x05, actual: 0x00 }); 186 | /// 187 | /// // ChipIdentification == 0x13660000 188 | /// let resp = Response::parse_version(&[0xAA,0x55,0x13,0x62,0x03,0x00,0x00,0x00,0x00,0x00,0x1E], 8); 189 | /// assert!(resp.is_ok()); 190 | /// match resp.unwrap() { 191 | /// ResponseType::Reg(r) => { 192 | /// assert_eq!(r.chip_addr, 0); 193 | /// assert_eq!(r.reg_addr, 0x00); 194 | /// assert_eq!(r.reg_value, 0x1362_0300); 195 | /// }, 196 | /// _ => panic!(), 197 | /// }; 198 | /// 199 | /// let resp = Response::parse_version(&[0xAA,0x55,0x2F,0xD5,0x96,0xCE,0x02,0x93,0x94,0xFB,0x86], 8); 200 | /// assert!(resp.is_ok()); 201 | /// match resp.unwrap() { 202 | /// ResponseType::JobVer(j) => { 203 | /// assert_eq!(j.nonce, 0xCE96_D52F); 204 | /// assert_eq!(j.unknown, 2); 205 | /// assert_eq!(j.job_id, 18); 206 | /// assert_eq!(j.small_core_id, 3); 207 | /// assert_eq!(j.version_bit, 0x129F_6000); 208 | /// }, 209 | /// _ => panic!(), 210 | /// }; 211 | /// 212 | /// let resp = Response::parse_version(&[0xAA,0x55,0x07,0x35,0xCD,0xCF,0x02,0x5E,0x00,0x2E,0x96], 16); 213 | /// assert!(resp.is_ok()); 214 | /// match resp.unwrap() { 215 | /// ResponseType::JobVer(j) => { 216 | /// assert_eq!(j.nonce, 0xCFCD_3507); 217 | /// assert_eq!(j.unknown, 1); 218 | /// assert_eq!(j.job_id, 5); 219 | /// assert_eq!(j.small_core_id, 14); 220 | /// assert_eq!(j.version_bit, 0x0005_C000); 221 | /// }, 222 | /// _ => panic!(), 223 | /// }; 224 | /// ``` 225 | pub fn parse_version( 226 | data: &[u8; FRAME_SIZE_VER], 227 | core_small_core_cnt: usize, 228 | ) -> Result { 229 | if data[0] != 0xAA || data[1] != 0x55 { 230 | return Err(Error::InvalidPreamble); 231 | } 232 | if core_small_core_cnt != 8 && core_small_core_cnt != 16 { 233 | return Err(Error::UnsupportedCoreSmallCoreCnt); 234 | } 235 | if crc5(&data[2..11]) != 0x00 { 236 | return Err(Error::InvalidCrc { 237 | expected: crc5_bits(&data[2..11]), 238 | actual: data[10] & 0x1f, 239 | }); 240 | } 241 | if data[10] & 0x80 == 0x80 { 242 | let small_core_mask = core_small_core_cnt - 1; 243 | let small_core_bits = small_core_mask.count_ones(); 244 | let chunk = ((data[6] as u16) << 8) | data[7] as u16; 245 | return Ok(ResponseType::JobVer(JobVersionResponse { 246 | nonce: u32::from_le_bytes(data[2..6].try_into().unwrap()), 247 | unknown: (chunk >> (small_core_bits + 5)) as u8, 248 | job_id: ((chunk >> small_core_bits) as usize) & 0b1_1111, 249 | small_core_id: (data[7] as usize) & small_core_mask, 250 | version_bit: (u16::from_be_bytes(data[8..10].try_into().unwrap()) as u32) << 13, 251 | })); 252 | } 253 | Ok(ResponseType::Reg(RegisterResponse { 254 | chip_addr: data[6], 255 | reg_addr: data[7], 256 | reg_value: u32::from_be_bytes(data[2..6].try_into().unwrap()), 257 | })) 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /bm13xx-asic/src/core_register/clock_delay.rs: -------------------------------------------------------------------------------- 1 | use crate::core_register::CoreRegister; 2 | 3 | /// # Clock Delay Ctrl core register 4 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5 | pub struct ClockDelayCtrl(pub u8); 6 | impl_boilerplate_for_core_reg!(ClockDelayCtrl); 7 | 8 | impl ClockDelayCtrl { 9 | pub const ID: u8 = 0; 10 | 11 | const CCDLY_SEL_OFFSET: u8 = 6; 12 | const PWTH_SEL_OFFSET: u8 = 4; 13 | const HASH_CLKEN_OFFSET: u8 = 3; 14 | const MMEN_OFFSET: u8 = 2; 15 | const SWPF_MODE_OFFSET: u8 = 0; 16 | 17 | const CCDLY_SEL_MASK: u8 = 0b11; 18 | const PWTH_SEL_MASK: u8 = 0b11; 19 | const HASH_CLKEN_MASK: u8 = 0b1; 20 | const MMEN_MASK: u8 = 0b1; 21 | const SWPF_MODE_MASK: u8 = 0b1; 22 | 23 | /// ## Handle the CCdly field. 24 | /// 25 | /// Get and set the CCdly value. 26 | /// 27 | /// ### Example 28 | /// 29 | /// ``` 30 | /// use bm13xx_asic::core_register::ClockDelayCtrl; 31 | /// 32 | /// let mut cdc = ClockDelayCtrl(0x00); // BM1397 default value 33 | /// assert_eq!(cdc.ccdly(), 0); 34 | /// assert_eq!(cdc.set_ccdly(1).ccdly(), 1); // BM1397 init() value 35 | /// assert_eq!(cdc.set_ccdly(3).ccdly(), 3); // max value 36 | /// assert_eq!(cdc.set_ccdly(4).ccdly(), 0); // out of bound value 37 | /// ``` 38 | pub const fn ccdly(&self) -> u8 { 39 | (self.0 >> Self::CCDLY_SEL_OFFSET) & Self::CCDLY_SEL_MASK 40 | } 41 | pub fn set_ccdly(&mut self, ccdly: u8) -> &mut Self { 42 | self.0 &= !Self::CCDLY_SEL_MASK << Self::CCDLY_SEL_OFFSET; 43 | self.0 |= (ccdly & Self::CCDLY_SEL_MASK) << Self::CCDLY_SEL_OFFSET; 44 | self 45 | } 46 | 47 | /// ## Handle the PWth field. 48 | /// 49 | /// Get and set the PWth value. 50 | /// 51 | /// ### Example 52 | /// 53 | /// ``` 54 | /// use bm13xx_asic::core_register::ClockDelayCtrl; 55 | /// 56 | /// let mut cdc = ClockDelayCtrl(0x00); // BM1397 default value 57 | /// assert_eq!(cdc.pwth(), 0); 58 | /// assert_eq!(cdc.set_pwth(3).pwth(), 3); // BM1397 init() value 59 | /// assert_eq!(cdc.set_pwth(4).pwth(), 0); // out of bound value 60 | /// ``` 61 | pub const fn pwth(&self) -> u8 { 62 | (self.0 >> Self::PWTH_SEL_OFFSET) & Self::PWTH_SEL_MASK 63 | } 64 | pub fn set_pwth(&mut self, pwth: u8) -> &mut Self { 65 | self.0 &= !Self::PWTH_SEL_MASK << Self::PWTH_SEL_OFFSET; 66 | self.0 |= (pwth & Self::PWTH_SEL_MASK) << Self::PWTH_SEL_OFFSET; 67 | self 68 | } 69 | 70 | /// ## Handle the Hash Clock field. 71 | /// 72 | /// Get and set the Hash Clock state. 73 | /// 74 | /// ### Example 75 | /// 76 | /// ``` 77 | /// use bm13xx_asic::core_register::ClockDelayCtrl; 78 | /// 79 | /// let mut cdc = ClockDelayCtrl(0x00); // BM1397 default value 80 | /// assert!(!cdc.hash_clock_enabled()); 81 | /// assert!(cdc.enable_hash_clock().hash_clock_enabled()); 82 | /// assert!(!cdc.disable_hash_clock().hash_clock_enabled()); // BM1397 init() value 83 | /// ``` 84 | pub const fn hash_clock_enabled(&self) -> bool { 85 | (self.0 >> Self::HASH_CLKEN_OFFSET) & Self::HASH_CLKEN_MASK == Self::HASH_CLKEN_MASK 86 | } 87 | pub fn enable_hash_clock(&mut self) -> &mut Self { 88 | self.0 |= 1 << Self::HASH_CLKEN_OFFSET; 89 | self 90 | } 91 | pub fn disable_hash_clock(&mut self) -> &mut Self { 92 | self.0 &= !(1 << Self::HASH_CLKEN_OFFSET); 93 | self 94 | } 95 | 96 | /// ## Handle the Multi Midstate field. 97 | /// 98 | /// Get and set the Multi Midstate state. 99 | /// 100 | /// ### Example 101 | /// 102 | /// ``` 103 | /// use bm13xx_asic::core_register::ClockDelayCtrl; 104 | /// 105 | /// let mut cdc = ClockDelayCtrl(0x00); // BM1397 default value 106 | /// assert!(!cdc.multi_midstate_enabled()); 107 | /// assert!(cdc.enable_multi_midstate().multi_midstate_enabled()); // BM1397 init() value 108 | /// assert!(!cdc.disable_multi_midstate().multi_midstate_enabled()); 109 | /// ``` 110 | pub const fn multi_midstate_enabled(&self) -> bool { 111 | (self.0 >> Self::MMEN_OFFSET) & Self::MMEN_MASK == Self::MMEN_MASK 112 | } 113 | pub fn enable_multi_midstate(&mut self) -> &mut Self { 114 | self.0 |= 1 << Self::MMEN_OFFSET; 115 | self 116 | } 117 | pub fn disable_multi_midstate(&mut self) -> &mut Self { 118 | self.0 &= !(1 << Self::MMEN_OFFSET); 119 | self 120 | } 121 | 122 | /// ## Handle the Sweep Frequency Mode field. 123 | /// 124 | /// Get and set the Sweep Frequency Mode state. 125 | /// 126 | /// ### Example 127 | /// 128 | /// ``` 129 | /// use bm13xx_asic::core_register::ClockDelayCtrl; 130 | /// 131 | /// let mut cdc = ClockDelayCtrl(0x00); // BM1397 default value 132 | /// assert!(!cdc.sweep_frequency_mode_enabled()); 133 | /// assert!(cdc.enable_sweep_frequency_mode().sweep_frequency_mode_enabled()); 134 | /// assert!(!cdc.disable_sweep_frequency_mode().sweep_frequency_mode_enabled()); // BM1397 init() value 135 | /// ``` 136 | pub const fn sweep_frequency_mode_enabled(&self) -> bool { 137 | (self.0 >> Self::SWPF_MODE_OFFSET) & Self::SWPF_MODE_MASK == Self::SWPF_MODE_MASK 138 | } 139 | pub fn enable_sweep_frequency_mode(&mut self) -> &mut Self { 140 | self.0 |= 1 << Self::SWPF_MODE_OFFSET; 141 | self 142 | } 143 | pub fn disable_sweep_frequency_mode(&mut self) -> &mut Self { 144 | self.0 &= !(1 << Self::SWPF_MODE_OFFSET); 145 | self 146 | } 147 | } 148 | 149 | impl ::core::fmt::Display for ClockDelayCtrl { 150 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 151 | f.debug_struct("ClockDelayCtrl") 152 | .field("ccdly", &self.ccdly()) 153 | .field("pwth", &self.pwth()) 154 | .field("hash_clock_enabled", &self.hash_clock_enabled()) 155 | .field("multi_midstate_enabled", &self.multi_midstate_enabled()) 156 | .field( 157 | "sweep_frequency_mode_enabled", 158 | &self.sweep_frequency_mode_enabled(), 159 | ) 160 | .finish() 161 | } 162 | } 163 | 164 | #[cfg(feature = "defmt")] 165 | impl defmt::Format for ClockDelayCtrl { 166 | fn format(&self, fmt: defmt::Formatter) { 167 | defmt::write!( 168 | fmt, 169 | "ClockDelayCtrl {{ ccdly: {}, pwth: {}, hash_clock_enabled: {}, multi_midstate_enabled: {}, sweep_frequency_mode_enabled: {} }}", 170 | self.ccdly(), 171 | self.pwth(), 172 | self.hash_clock_enabled(), 173 | self.multi_midstate_enabled(), 174 | self.sweep_frequency_mode_enabled(), 175 | ); 176 | } 177 | } 178 | 179 | /// # Clock Delay Ctrl core register 180 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 181 | pub struct ClockDelayCtrlV2(pub u8); 182 | impl_boilerplate_for_core_reg!(ClockDelayCtrlV2); 183 | 184 | impl ClockDelayCtrlV2 { 185 | pub const ID: u8 = 0; 186 | 187 | const CCDLY_SEL_OFFSET: u8 = 6; 188 | const PWTH_SEL_OFFSET: u8 = 3; 189 | const SWPF_MODE_OFFSET: u8 = 0; 190 | 191 | const CCDLY_SEL_MASK: u8 = 0b11; 192 | const PWTH_SEL_MASK: u8 = 0b111; 193 | const SWPF_MODE_MASK: u8 = 0b1; 194 | 195 | /// ## Handle the CCdly field. 196 | /// 197 | /// Get and set the CCdly value. 198 | /// 199 | /// ### Example 200 | /// 201 | /// ``` 202 | /// use bm13xx_asic::core_register::ClockDelayCtrlV2; 203 | /// 204 | /// let mut cdc = ClockDelayCtrlV2(0x98); // BM1366 default value 205 | /// assert_eq!(cdc.ccdly(), 2); 206 | /// assert_eq!(cdc.set_ccdly(0).ccdly(), 0); // BM1366 init() value 207 | /// assert_eq!(cdc.set_ccdly(3).ccdly(), 3); // max value 208 | /// assert_eq!(cdc.set_ccdly(4).ccdly(), 0); // out of bound value 209 | /// ``` 210 | pub const fn ccdly(&self) -> u8 { 211 | (self.0 >> Self::CCDLY_SEL_OFFSET) & Self::CCDLY_SEL_MASK 212 | } 213 | pub fn set_ccdly(&mut self, ccdly: u8) -> &mut Self { 214 | self.0 &= !Self::CCDLY_SEL_MASK << Self::CCDLY_SEL_OFFSET; 215 | self.0 |= (ccdly & Self::CCDLY_SEL_MASK) << Self::CCDLY_SEL_OFFSET; 216 | self 217 | } 218 | 219 | /// ## Handle the PWth field. 220 | /// 221 | /// Get and set the PWth value. 222 | /// 223 | /// ### Example 224 | /// 225 | /// ``` 226 | /// use bm13xx_asic::core_register::ClockDelayCtrlV2; 227 | /// 228 | /// let mut cdc = ClockDelayCtrlV2(0x98); // BM1366 default value 229 | /// assert_eq!(cdc.pwth(), 3); 230 | /// assert_eq!(cdc.set_pwth(4).pwth(), 4); // BM1366 init() value 231 | /// assert_eq!(cdc.set_pwth(7).pwth(), 7); // max value 232 | /// assert_eq!(cdc.set_pwth(8).pwth(), 0); // out of bound value 233 | /// ``` 234 | pub const fn pwth(&self) -> u8 { 235 | (self.0 >> Self::PWTH_SEL_OFFSET) & Self::PWTH_SEL_MASK 236 | } 237 | pub fn set_pwth(&mut self, pwth: u8) -> &mut Self { 238 | self.0 &= !Self::PWTH_SEL_MASK << Self::PWTH_SEL_OFFSET; 239 | self.0 |= (pwth & Self::PWTH_SEL_MASK) << Self::PWTH_SEL_OFFSET; 240 | self 241 | } 242 | 243 | /// ## Handle the Sweep Frequency Mode field. 244 | /// 245 | /// Get and set the Sweep Frequency Mode state. 246 | /// 247 | /// ### Example 248 | /// 249 | /// ``` 250 | /// use bm13xx_asic::core_register::ClockDelayCtrlV2; 251 | /// 252 | /// let mut cdc = ClockDelayCtrlV2(0x98); // BM1366 default value 253 | /// assert!(!cdc.sweep_frequency_mode_enabled()); 254 | /// assert!(cdc.enable_sweep_frequency_mode().sweep_frequency_mode_enabled()); 255 | /// assert!(!cdc.disable_sweep_frequency_mode().sweep_frequency_mode_enabled()); // BM1366 init() value 256 | /// ``` 257 | pub const fn sweep_frequency_mode_enabled(&self) -> bool { 258 | (self.0 >> Self::SWPF_MODE_OFFSET) & Self::SWPF_MODE_MASK == Self::SWPF_MODE_MASK 259 | } 260 | pub fn enable_sweep_frequency_mode(&mut self) -> &mut Self { 261 | self.0 |= 1 << Self::SWPF_MODE_OFFSET; 262 | self 263 | } 264 | pub fn disable_sweep_frequency_mode(&mut self) -> &mut Self { 265 | self.0 &= !(1 << Self::SWPF_MODE_OFFSET); 266 | self 267 | } 268 | } 269 | 270 | impl ::core::fmt::Display for ClockDelayCtrlV2 { 271 | fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 272 | f.debug_struct("ClockDelayCtrlV2") 273 | .field("ccdly", &self.ccdly()) 274 | .field("pwth", &self.pwth()) 275 | .field( 276 | "sweep_frequency_mode_enabled", 277 | &self.sweep_frequency_mode_enabled(), 278 | ) 279 | .finish() 280 | } 281 | } 282 | 283 | #[cfg(feature = "defmt")] 284 | impl defmt::Format for ClockDelayCtrlV2 { 285 | fn format(&self, fmt: defmt::Formatter) { 286 | defmt::write!( 287 | fmt, 288 | "ClockDelayCtrlV2 {{ ccdly: {}, pwth: {}, sweep_frequency_mode_enabled: {} }}", 289 | self.ccdly(), 290 | self.pwth(), 291 | self.sweep_frequency_mode_enabled(), 292 | ); 293 | } 294 | } 295 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------