1mod chessboard_device;
2
3use crate::chessboard_device::ChessboardDevice;
4use std::error::Error;
5use std::fmt::{Display, Formatter, Write};
6use std::sync::{Arc, Mutex};
7use std::thread;
8use std::thread::JoinHandle;
9
10const CHESS_PIECES: [char; 13] = [
11 '0', 'q', 'k', 'b', 'p', 'n', 'R', 'P', 'r', 'B', 'N', 'Q', 'K',
12];
13
14const BUFFER_SIZE: usize = 64;
15
16#[derive(Debug)]
17pub struct RlnError {
18 details: String,
19}
20
21impl Display for RlnError {
22 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
23 f.write_str(&self.details)
24 }
25}
26
27impl Error for RlnError {}
28
29#[derive(Debug, PartialEq, Eq)]
30pub enum Mode {
31 Default,
32 RealTime,
33 FileTransfer,
34}
35
36#[derive(Debug)]
37pub struct RustyLink {
38 device: Arc<Mutex<ChessboardDevice>>,
39 device_mode: Arc<Mutex<Mode>>,
40 rt_thread_handle: Option<JoinHandle<()>>,
41 fen: Arc<Mutex<String>>,
42 battery_state: Arc<Mutex<u8>>,
43 led_state: [u8; 8],
44}
45
46impl RustyLink {
49 pub fn connect(vendor_id: u16, product_id: u16) -> Result<RustyLink, RlnError> {
50 let c = ChessboardDevice::new(vendor_id, product_id)?;
51 Ok(RustyLink {
52 device: Arc::new(Mutex::new(c)),
53 device_mode: Arc::new(Mutex::new(Mode::Default)),
54 fen: Arc::new(Mutex::new(String::new())),
55 led_state: [0; 8],
56 rt_thread_handle: None,
57 battery_state: Arc::new(Mutex::new(0)),
58 })
59 }
60
61 pub fn default_mode(&mut self) -> Result<(), RlnError> {
64 *self.device_mode.lock().unwrap() = Mode::Default;
65 if self.rt_thread_handle.is_some() {
66 let r = self.rt_thread_handle.take().unwrap().join();
67 if r.is_err() {
68 Err(RlnError {
69 details: "Failed to join RT thread after ending RT mode".to_string(),
70 })
71 } else {
72 Ok(())
73 }
74 } else {
75 Err(RlnError {
76 details: "No thread handle to join".to_string(),
77 })
78 }
79 }
80
81 pub fn real_time_mode(&mut self) -> Result<(), RlnError> {
86 let device = self.device.clone();
87 let mut device_l = self.device.lock().unwrap();
88 let r = device_l.set_real_time_mode();
89 if r.is_err() {
90 return Err(RlnError {
91 details: format!("Failed to set real time mode: {}", r.unwrap_err()),
92 });
93 }
94 *self.device_mode.lock().unwrap() = Mode::RealTime;
95 let device_mode = self.device_mode.clone();
96 let battery_state = self.battery_state.clone();
97 let fen = self.fen.clone();
98 let handle = thread::spawn(move || {
100 while *device_mode.lock().unwrap() == Mode::RealTime {
101 let mut data: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
102 let _ = device.lock().unwrap().read(&mut data).unwrap();
103 if data[0] == 0x2a {
104 *battery_state.lock().unwrap() = data[2];
106 } else if data[0] == 0x01 {
107 let mut fen_data: [u8; 34] = [0; 34];
108 fen_data.copy_from_slice(&data[0..34]);
109 let fen_str = to_fen(&fen_data);
110 let mut f = fen.lock().unwrap();
111 f.clear();
112 f.push_str(&fen_str);
113 }
114 }
115 });
116 self.rt_thread_handle = Some(handle);
117 Ok(())
118 }
119
120 pub fn fen(&self) -> String {
123 self.fen.lock().unwrap().clone()
124 }
125
126 pub fn battery_state(&self) -> u8 {
128 if *self.device_mode.lock().unwrap() == Mode::RealTime {
130 *self.battery_state.lock().unwrap()
131 } else {
132 let mut data: [u8; 3] = [0x29, 0x01, 0x00];
133 let _ = self.device.lock().unwrap().write(&data);
134 self.device.lock().unwrap().read(&mut data).unwrap();
135 data[2]
136 }
137 }
138
139 pub fn update_led(&mut self, led_state: [u8; 8]) -> Result<(), RlnError> {
141 self.led_state = led_state;
142 let mut led_data: [u8; 10] = [0x0a, 0x08, 0, 0, 0, 0, 0, 0, 0, 0];
143 led_data[2..].copy_from_slice(&self.led_state);
144 let _ = self.device.lock().unwrap().write(&led_data)?;
145 Ok(())
146 }
147
148 pub fn led(&self) -> [u8; 8] {
150 self.led_state
151 }
152
153 pub fn beep(&mut self, frequency: u16, duration: u16) -> Result<(), RlnError> {
156 let data = [
157 0x0b,
158 0x04,
159 (frequency >> 8) as u8,
160 (frequency & 0xFF) as u8,
161 (duration >> 8) as u8,
162 (duration & 0xFF) as u8,
163 ];
164 let _ = self.device.lock().unwrap().write(&data)?;
165 Ok(())
166 }
167}
168
169fn to_fen(data: &[u8]) -> String {
170 let mut fen = String::new();
171 let mut empty = 0;
172 for i in 0..8 {
173 for j in (0..8).rev() {
174 let b = j % 2 == 0;
175 let c = match b {
176 true => {
177 let index = data[(i * 8 + j) / 2 + 2] & 0x0f;
178 CHESS_PIECES[index as usize]
179 }
180 false => {
181 let index = data[(i * 8 + j) / 2 + 2] >> 4;
182 CHESS_PIECES[index as usize]
183 }
184 };
185 if c == '0' {
186 empty += 1;
187 } else if empty > 0 {
188 fen.write_str(empty.to_string().as_str()).unwrap();
189 fen.write_str(c.to_string().as_str()).unwrap();
190 empty = 0;
191 } else {
192 fen.write_str(c.to_string().as_str()).unwrap();
193 }
194 }
195 if empty > 0 {
196 fen.write_str(empty.to_string().as_str()).unwrap();
197 }
198 if i < 7 {
199 fen.write_str("/").unwrap();
200 }
201 empty = 0;
202 }
203 fen
204}