1pub use roland_core::*;
7
8use roland_core::{Address, Command, Response, RolandError};
9use std::io::{Read, Write};
10use std::net::TcpStream;
11use std::time::Duration;
12
13#[derive(Debug)]
15pub enum TelnetError {
16 Protocol(RolandError),
18 Io(std::io::Error),
20 ConnectionClosed,
22}
23
24impl std::fmt::Display for TelnetError {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 match self {
27 TelnetError::Protocol(e) => write!(f, "Protocol error: {}", e),
28 TelnetError::Io(e) => write!(f, "I/O error: {}", e),
29 TelnetError::ConnectionClosed => write!(f, "Connection closed"),
30 }
31 }
32}
33
34impl std::error::Error for TelnetError {}
35
36impl From<RolandError> for TelnetError {
37 fn from(e: RolandError) -> Self {
38 TelnetError::Protocol(e)
39 }
40}
41
42impl From<std::io::Error> for TelnetError {
43 fn from(e: std::io::Error) -> Self {
44 TelnetError::Io(e)
45 }
46}
47
48pub struct TelnetClient {
50 stream: TcpStream,
51 buffer: Vec<u8>,
52}
53
54impl TelnetClient {
55 pub fn connect(host: &str, port: u16) -> Result<Self, TelnetError> {
64 let addr = format!("{}:{}", host, port);
65 let stream = TcpStream::connect(&addr)?;
66
67 stream.set_read_timeout(Some(Duration::from_secs(5)))?;
69
70 stream.set_write_timeout(Some(Duration::from_secs(5)))?;
72
73 Ok(Self {
74 stream,
75 buffer: Vec::new(),
76 })
77 }
78
79 pub fn send_command(&mut self, command: &Command) -> Result<Response, TelnetError> {
87 let cmd_str = command.encode();
89 let cmd_bytes = cmd_str.as_bytes();
90
91 self.stream.write_all(cmd_bytes)?;
93 self.stream.flush()?;
94
95 self.read_response()
97 }
98
99 fn read_response(&mut self) -> Result<Response, TelnetError> {
101 let mut buf = [0u8; 1024];
102
103 let n = self.stream.read(&mut buf)?;
105
106 if n == 0 {
107 return Err(TelnetError::ConnectionClosed);
108 }
109
110 self.buffer.extend_from_slice(&buf[..n]);
112
113 let response_str = String::from_utf8_lossy(&self.buffer);
116
117 if response_str.ends_with(';') ||
119 response_str.contains('\x06') || response_str.contains('\x11') || response_str.contains('\x13')
122 {
123 let response = Response::parse(&response_str)?;
125 self.buffer.clear();
126 Ok(response)
127 } else {
128 std::thread::sleep(Duration::from_millis(100));
130 self.read_response()
131 }
132 }
133
134 pub fn write_parameter(&mut self, address: &str, value: u8) -> Result<(), TelnetError> {
143 let addr = Address::from_hex(address)?;
144 let cmd = Command::WriteParameter {
145 address: addr,
146 value,
147 };
148 let response = self.send_command(&cmd)?;
149
150 match response {
151 Response::Acknowledge => Ok(()),
152 Response::Error(e) => Err(TelnetError::Protocol(e)),
153 _ => Err(TelnetError::Protocol(RolandError::InvalidResponse)),
154 }
155 }
156
157 pub fn read_parameter(&mut self, address: &str, size: u32) -> Result<u8, TelnetError> {
166 let addr = Address::from_hex(address)?;
167 let cmd = Command::ReadParameter {
168 address: addr,
169 size,
170 };
171 let response = self.send_command(&cmd)?;
172
173 match response {
174 Response::Data { value, .. } => Ok(value),
175 Response::Error(e) => Err(TelnetError::Protocol(e)),
176 _ => Err(TelnetError::Protocol(RolandError::InvalidResponse)),
177 }
178 }
179
180 pub fn get_version(&mut self) -> Result<(String, String), TelnetError> {
185 let cmd = Command::GetVersion;
186 let response = self.send_command(&cmd)?;
187
188 match response {
189 Response::Version { product, version } => Ok((product, version)),
190 Response::Error(e) => Err(TelnetError::Protocol(e)),
191 _ => Err(TelnetError::Protocol(RolandError::InvalidResponse)),
192 }
193 }
194}