tag_attach_cycle/
tag-attach-cycle.rs1use std::process::ExitCode;
27use std::sync::atomic::{AtomicBool, Ordering};
28use std::thread::sleep;
29use std::time::Duration;
30
31use clap::Parser;
32use tag_tools::{BaseArgs, init_logging, select_base, state_name};
33use tagcore::Tag;
34use tagcore::proto::Status;
35
36#[derive(Parser)]
38#[command(name = "tag-attach-cycle")]
39struct Cli {
40 #[command(flatten)]
42 base: BaseArgs,
43
44 #[arg(long, default_value_t = 5000)]
46 on_ms: u32,
47
48 #[arg(long, default_value_t = 5000)]
50 off_ms: u32,
51
52 #[arg(long, default_value_t = 0)]
54 cycles: u32,
55
56 #[arg(long)]
58 no_status: bool,
59}
60
61static STOP_REQUESTED: AtomicBool = AtomicBool::new(false);
63
64fn interruptible_sleep(ms: u32) {
66 let mut remaining = u64::from(ms);
67 while !STOP_REQUESTED.load(Ordering::SeqCst) && remaining > 0 {
68 let nap = remaining.min(100);
69 sleep(Duration::from_millis(nap));
70 remaining -= nap;
71 }
72}
73
74fn print_status(cycle: u32, status: &Status) {
78 println!(
79 "cycle {cycle}: state={} millis={} internal={} external={}",
80 state_name(status.state),
81 status.millis,
82 status.internal_data_count,
83 status.external_data_count
84 );
85 if !status.debug_message.is_empty() {
86 eprint!("{}", status.debug_message);
87 }
88}
89
90fn main() -> ExitCode {
92 let _ = ctrlc::set_handler(|| STOP_REQUESTED.store(true, Ordering::SeqCst));
93 let cli = Cli::parse();
94 init_logging(&cli.base);
95
96 let tag = Tag::new();
97 let dev = select_base::<Cli>(&tag, &cli.base);
98
99 let mut cycle: u32 = 1;
100 while !STOP_REQUESTED.load(Ordering::SeqCst) && (cli.cycles == 0 || cycle <= cli.cycles) {
101 println!("cycle {cycle}: attach");
102 if !tag.attach(&dev) {
103 eprintln!("cycle {cycle}: attach failed");
104 return ExitCode::FAILURE;
105 }
106
107 if !cli.no_status {
108 match tag.status() {
109 Ok(status) => print_status(cycle, &status),
110 Err(_) => eprintln!("cycle {cycle}: status failed: {}", tag.debug_message()),
111 }
112 }
113
114 interruptible_sleep(cli.on_ms);
115
116 println!("cycle {cycle}: detach");
117 tag.detach();
118
119 if cli.cycles == 0 || cycle < cli.cycles {
120 interruptible_sleep(cli.off_ms);
121 }
122 cycle = cycle.wrapping_add(1);
123 }
124
125 tag.detach();
126 ExitCode::SUCCESS
127}