Skip to content

Commit

Permalink
Merge pull request #57 from pmnxis/dev/support_cash_receipt
Browse files Browse the repository at this point in the history
#56 Support cash receipt
  • Loading branch information
pmnxis authored Sep 1, 2024
2 parents 98edbc3 + ac4e667 commit 504ccf9
Show file tree
Hide file tree
Showing 20 changed files with 389 additions and 79 deletions.
10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[package]
name = "billmock-app-rs"
edition = "2021"
version = "0.3.2"
version = "0.4.0"
authors = ["Jinwoo Park <[email protected]>"]
license = "MIT OR Apache-2.0"
description = "application side of billmock hardware, powered by rust-embedded"
Expand All @@ -24,20 +24,20 @@ hw_mini_0v4 = ["eeprom"]
hw_mini_0v5 = ["eeprom", "svc_button"]

[dependencies]
embassy-sync = { version = "0.5.0", features = ["defmt"] }
embassy-executor = { version = "0.5.0", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-sync = { version = "0.6.0", features = ["defmt"] }
embassy-executor = { version = "0.6.0", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-futures = { version = "0.1.0", features = ["defmt"] }
embassy-time = { version = "0.3.0", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g030c8", "memory-x", "unstable-pac", "exti", "time"] } # "unstable-traits" for use InputPin trait for gpio
embassy-embedded-hal = { version = "^0.1.0" }
embassy-embedded-hal = { version = "^0.2.0" }
defmt = "0.3.6"
defmt-rtt = "0.4"

cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } # 0.7.6
cortex-m-rt = "0.7.3" # 0.7.0
panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
static_cell = { version = "1.2", features = ["nightly"] }
static_cell = { version = "1.3", features = ["nightly"] }
num_enum = { version = "0.7.0", default-features = false } # Application specific import (only `no_std` crates alllowed)
bit_field = "0.10"
nonmax = { version = "0.5.3", default-features = false, features = [] } # to use common NonMax
Expand Down
3 changes: 1 addition & 2 deletions billmock-plug-card/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ card-terminal-adapter = { path = "../card-terminal-adapter" } # Import generic i

defmt = "0.3"
defmt-test = "0.3.0"
crc = "3.0.1"
crc = "3.2.1"

[dev-dependencies]
log = { version = "0.4", features = ["max_level_debug", "release_max_level_warn"] }

5 changes: 5 additions & 0 deletions billmock-plug-card/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ impl CardTerminalTxGen for KiccEd785Plug {
&buffer[0..0]
}

fn push_transaction_availability<'a>(&self, buffer: &'a mut [u8], _is_avail: bool) -> &'a [u8] {
// implement me for actual usage
&buffer[0..0]
}

fn request_sale_slot_info<'a>(&self, buffer: &'a mut [u8]) -> &'a [u8] {
// implement me for actual usage
&buffer[0..0]
Expand Down
13 changes: 12 additions & 1 deletion card-terminal-adapter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ pub enum CardTerminalRxCmd {
/// Detail pakcet data should be parsed with additional function call.
/// using additional function call for avoid queue size being huge.
ResponseTerminalInfo(TidStatus, TerminalVersion),
/// Set Pulse State
RequestKeepPulseState(PulseStateRequest),
}

#[derive(PartialEq, Eq, Clone, defmt::Format)]
Expand All @@ -89,10 +91,14 @@ pub enum CardTerminalTxCmd {
/// Overwrite sale slot info to card terminal
/// It's for rollback or treat as inihibit action
PushSaleSlotInfo,
/// [Deprecated]
/// Mixed request of PushSaleSlotInfo,
/// Unfortunately, this feature is still unstable due to sequence logic issues
/// in the real environment. Therefore, we do not recommend using it at this time.
PushSaleSlotInfoPartialInhibit(RawPlayersInhibit),
/// Set availability of transactions
/// New method instead of PushSaleSlotInfoPartialInhibit
SetTransactionAvailability(bool),
/// Request terminal info, include TID, terminal program version etc.
RequestTerminalInfo,
/// Display ROM (P1/P2 Card and Coin Meter)
Expand All @@ -117,7 +123,7 @@ pub const FW_VER_LEN: usize = 5;
pub const DEV_SN_LEN: usize = 12;
pub const GIT_HASH_LEN: usize = 9;

#[const_trait]
// #[const_trait]
pub trait CardTerminalConst {
fn is_nda() -> bool;
}
Expand Down Expand Up @@ -170,6 +176,7 @@ pub trait CardTerminalTxGen {
port_backup: &CardReaderPortBackup,
) -> &'a [u8];

/// [Deprecated]
/// Generate PushSaleSlotInfoPartialInhibit signal to send
/// This action send with modificated slots to inhibit sale slot for inhibit behavior
fn push_sale_slot_info_partial_inhibit<'a>(
Expand All @@ -178,6 +185,10 @@ pub trait CardTerminalTxGen {
port_backup: &CardReaderPortBackup,
) -> &'a [u8];

/// Generate SetTransactionAvailability signal to send
/// This is inversed boolean of SetInhibit
fn push_transaction_availability<'a>(&self, buffer: &'a mut [u8], is_avail: bool) -> &'a [u8];

/// Generate RequestSaleSlotInfo signal to send
fn request_sale_slot_info<'a>(&self, buffer: &'a mut [u8]) -> &'a [u8];

Expand Down
74 changes: 71 additions & 3 deletions card-terminal-adapter/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ impl RawU24IncomeArcade {
pub fn get_port_num(&self) -> u8 {
self.0[0] >> 4
}

pub fn get_pulse_count(&self) -> u16 {
(((self.0[0] & 0x0F) as u16) << 6) | (self.0[1] >> 2) as u16
}
}

#[derive(PartialEq, Eq, Clone, Copy, defmt::Format)]
Expand All @@ -98,6 +102,7 @@ pub struct RawPortPulseCountDuration {
pub inner: u32,
}

#[derive(defmt::Format)]
pub struct SlotPriceGameNum {
pub price: u32,
pub game_num: u16,
Expand All @@ -124,21 +129,28 @@ impl From<RawU32SlotPriceGameNum> for SlotPriceGameNum {
}
}

impl defmt::Format for RawU32SlotPriceGameNum {
fn format(&self, fmt: defmt::Formatter) {
let degrade = SlotPriceGameNum::from(self.clone());
defmt::write!(fmt, "{:?}", degrade);
}
}

impl RawU32SlotPriceGameNum {
pub fn get_game_num(&self) -> u16 {
(self.0 & ((1 << 10) - 1)) as u16
}
}

#[repr(u8)]
#[derive(Clone, Copy, Zeroable, PartialEq, PartialOrd)]
#[derive(Clone, Copy, Zeroable, PartialEq, PartialOrd, defmt::Format)]
pub enum SlotProperty {
Disabled,
Enabled,
TemporaryDisabled,
}

#[derive(Clone, Zeroable)]
#[derive(Clone, Zeroable, defmt::Format)]
pub struct RawCardPortBackup {
// is enabled?
pub property: SlotProperty,
Expand Down Expand Up @@ -167,7 +179,7 @@ impl RawCardPortBackup {
}
}

#[derive(Clone, Zeroable)]
#[derive(Clone, Zeroable, defmt::Format)]
pub struct CardReaderPortBackup {
pub raw_card_port_backup: [RawCardPortBackup; 4],
}
Expand All @@ -177,6 +189,23 @@ impl CardReaderPortBackup {
Self::zeroed()
}

pub fn is_zeroed(&self) -> bool {
unsafe {
let cast: &[u8] = core::slice::from_raw_parts(
(self as *const _) as *const u8,
core::mem::size_of::<CardReaderPortBackup>(),
);

for each in cast {
if *each != 0 {
return false;
}
}
}

true
}

// 0 is player 1, <- this is temporary decide,
// 1 is player 2, <- this is temporary decide,
pub fn guess_player_by_port_num(&self, port_num: u8) -> u8 {
Expand All @@ -194,6 +223,39 @@ impl CardReaderPortBackup {
0
}

// player 1 port is generally 1
// player 2 port is generally 2
pub fn guess_raw_income_by_player(&self, player: u8) -> Option<&RawU24IncomeArcade> {
for backup in &self.raw_card_port_backup {
if backup.property != SlotProperty::Enabled {
continue;
}

let game_num = backup.raw_extended.get_game_num();
if (game_num == player as u16) || (game_num == (player + 2) as u16) {
return Some(&backup.raw_minimum);
}
}

None
}

// index should be u8 but to reduce size use u8. Index gurantee less than 256.
pub fn guess_raw_income_index_by_player(&self, player: u8) -> Option<u8> {
for (pos, backup) in self.raw_card_port_backup.iter().enumerate() {
if backup.property != SlotProperty::Enabled {
continue;
}

let game_num = backup.raw_extended.get_game_num();
if (game_num == player as u16) || (game_num == (player + 2) as u16) {
return Some(pos as u8);
}
}

None
}

pub fn set_inhibit(&mut self, inhibit: RawPlayersInhibit) {
for i in 0..self.raw_card_port_backup.len() {
let is_disabled = self.raw_card_port_backup[i].property == SlotProperty::Disabled;
Expand All @@ -211,4 +273,10 @@ impl CardReaderPortBackup {
}
}

#[derive(Debug, Zeroable, defmt::Format, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct PulseStateRequest {
pub port: u8,
pub state: bool,
}

assert_eq_size!(CardReaderPortBackup, [u8; 32]);
3 changes: 2 additions & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
# https://rust-lang.github.io/rustup-components-history
[toolchain]
# channel = "nightly-2023-11-01"
channel = "nightly-2024-04-14"
# Since Nightly 2024-06-13 make_static doesn't work, https://github.com/embassy-rs/static-cell/issues/16
channel = "nightly-2024-06-12"
components = [ "rust-src", "rustfmt", "llvm-tools", "rust-analyzer" ]
targets = [
"thumbv6m-none-eabi",
Expand Down
2 changes: 1 addition & 1 deletion src/application/io_card.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl PaymentReceive {
pub async fn apply_output(self, board: &'static Board, override_druation_force: bool) -> Self {
let player = {
defmt::debug!("port 0x{:02X}", self.recv.port);
let temp = (self.recv.port.max(1).min(4) - 1) & 0x1;
let temp = (self.recv.port.clamp(1, 4) - 1) & 0x1;

match temp {
0 => Player::Player1,
Expand Down
57 changes: 25 additions & 32 deletions src/application/io_remap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

use super::io_bypass::io_bypass;
use super::pulse_meory_filter::PulseMemoryFilterMachine;
use crate::boards::*;
use crate::components::eeprom;
use crate::semi_layer::buffered_wait::InputEventKind;
Expand Down Expand Up @@ -129,41 +130,33 @@ impl InputEvent {
}
}

pub async fn apply_output(&self, board: &'static Board, override_druation_force: bool) -> Self {
match (self.port, self.event) {
(InputPortKind::Vend1P, InputEventKind::LongPressed(_)) => {
let count = board
.hardware
.eeprom
.lock_read(eeprom::select::P1_COIN_CNT)
.await;
let new_count = count + 1;
pub async fn apply_output(
&self,
board: &'static Board,
filter_state: &mut PulseMemoryFilterMachine,
override_druation_force: bool,
) -> Self {
if let Some((player_index, rom_sel, time_in_10ms)) = match (self.port, self.event) {
(InputPortKind::Vend1P, InputEventKind::LongPressed(time_in_10ms)) => Some((
PLAYER_1_INDEX as u8,
eeprom::select::P1_COIN_CNT,
time_in_10ms,
)),
(InputPortKind::Vend2P, InputEventKind::LongPressed(time_in_10ms)) => Some((
PLAYER_2_INDEX as u8,
eeprom::select::P2_COIN_CNT,
time_in_10ms,
)),
_ => None,
} {
let count = board.hardware.eeprom.lock_read(rom_sel).await;
let new_count = count + 1;

board
.hardware
.eeprom
.lock_write(eeprom::select::P1_COIN_CNT, new_count)
.await;
board.hardware.eeprom.lock_write(rom_sel, new_count).await;

defmt::info!("P1_COIN_CNT, {} -> {}", count, new_count);
}
(InputPortKind::Vend2P, InputEventKind::LongPressed(_)) => {
let count = board
.hardware
.eeprom
.lock_read(eeprom::select::P2_COIN_CNT)
.await;
let new_count = count + 1;

board
.hardware
.eeprom
.lock_write(eeprom::select::P2_COIN_CNT, new_count)
.await;
let timing_in_ms = (time_in_10ms as u16) * 10;

defmt::info!("P2_COIN_CNT, {} -> {}", count, new_count);
}
_ => {}
filter_state.player[player_index as usize].mark(timing_in_ms);
}

if self.port != InputPortKind::Nothing {
Expand Down
Loading

0 comments on commit 504ccf9

Please sign in to comment.