1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(test), no_std)]
3
4#[cfg(feature = "defmt")]
9use defmt::Format;
10
11mod crc;
12
13pub trait Sendable {
19 fn render_to_buffer(&self, buffer: &mut [u8]) -> Result<usize, Error>;
23}
24
25pub trait Receivable<'a>: Sized {
27 fn from_bytes(data: &'a [u8]) -> Result<Self, Error> {
31 let crc = calculate_crc(data);
32 Self::from_bytes_with_crc(data, crc)
33 }
34
35 fn from_bytes_with_crc(data: &'a [u8], calc_crc: u8) -> Result<Self, Error>;
39}
40
41#[derive(Debug, Copy, Clone, PartialEq, Eq)]
47#[cfg_attr(feature = "defmt", derive(Format))]
48pub enum Error {
49 BadCrc,
50 BadLength,
51 BadRequestType,
52 BufferTooSmall,
53 BadResponseResult,
54}
55
56#[derive(
58 Debug, Copy, Clone, PartialEq, Eq, num_enum::IntoPrimitive, num_enum::TryFromPrimitive,
59)]
60#[cfg_attr(feature = "defmt", derive(Format))]
61#[repr(u8)]
62pub enum RequestType {
63 Read = 0xC0,
64 ReadAlt = 0xC1,
65 ShortWrite = 0xC2,
66 ShortWriteAlt = 0xC3,
67 LongWrite = 0xC4,
68 LongWriteAlt = 0xC5,
69}
70
71#[derive(
74 Debug, Copy, Clone, PartialEq, Eq, num_enum::IntoPrimitive, num_enum::TryFromPrimitive,
75)]
76#[cfg_attr(feature = "defmt", derive(Format))]
77#[repr(u8)]
78pub enum ResponseResult {
79 Ok = 0xA0,
81 CrcFailure = 0xA1,
85 BadRequestType = 0xA2,
89 BadRegister = 0xA3,
93 BadLength = 0xA4,
98}
99
100#[derive(Debug, Clone, PartialEq, Eq)]
106#[cfg_attr(feature = "defmt", derive(Format))]
107pub struct Request {
108 pub request_type: RequestType,
109 pub register: u8,
110 pub length_or_data: u8,
111 crc: u8,
112}
113
114#[derive(Debug, Clone, PartialEq, Eq)]
116#[cfg_attr(feature = "defmt", derive(Format))]
117pub struct Response<'a> {
118 pub result: ResponseResult,
119 pub data: &'a [u8],
120 crc: u8,
121}
122
123#[derive(Debug, Copy, Clone, PartialEq, Eq)]
126#[cfg_attr(feature = "defmt", derive(Format))]
127pub struct ProtocolVersion {
128 major: u8,
129 minor: u8,
130 patch: u8,
131}
132
133impl RequestType {
138 pub fn flatten(self) -> Self {
142 match self {
143 RequestType::LongWrite | RequestType::LongWriteAlt => RequestType::LongWrite,
144 RequestType::ShortWrite | RequestType::ShortWriteAlt => RequestType::ShortWrite,
145 RequestType::Read | RequestType::ReadAlt => RequestType::Read,
146 }
147 }
148}
149
150impl Request {
151 pub fn new_read(use_alt: bool, register: u8, length: u8) -> Request {
158 let mut req = Request {
159 request_type: if use_alt {
160 RequestType::ReadAlt
161 } else {
162 RequestType::Read
163 },
164 register,
165 length_or_data: length,
166 crc: 0x00,
167 };
168 let bytes = req.as_bytes();
169 req.crc = calculate_crc(&bytes[0..=2]);
170 req
171 }
172
173 pub fn new_short_write(use_alt: bool, register: u8, data: u8) -> Request {
179 let mut req = Request {
180 request_type: if use_alt {
181 RequestType::ShortWriteAlt
182 } else {
183 RequestType::ShortWrite
184 },
185 register,
186 length_or_data: data,
187 crc: 0x00,
188 };
189 let bytes = req.as_bytes();
190 req.crc = calculate_crc(&bytes[0..=2]);
191 req
192 }
193
194 pub fn new_long_write(use_alt: bool, register: u8, length: u8) -> Request {
201 let mut req = Request {
202 request_type: if use_alt {
203 RequestType::LongWriteAlt
204 } else {
205 RequestType::LongWrite
206 },
207 register,
208 length_or_data: length,
209 crc: 0x00,
210 };
211 let bytes = req.as_bytes();
212 req.crc = calculate_crc(&bytes[0..=2]);
213 req
214 }
215
216 pub const fn as_bytes(&self) -> [u8; 4] {
220 [
221 self.request_type as u8,
222 self.register,
223 self.length_or_data,
224 self.crc,
225 ]
226 }
227}
228
229impl Sendable for Request {
230 fn render_to_buffer(&self, buffer: &mut [u8]) -> Result<usize, Error> {
234 let bytes = self.as_bytes();
235 if buffer.len() < bytes.len() {
236 return Err(Error::BufferTooSmall);
237 }
238 for (src, dest) in bytes.iter().zip(buffer.iter_mut()) {
239 *dest = *src;
240 }
241 Ok(bytes.len())
242 }
243}
244
245impl<'a> Receivable<'a> for Request {
246 fn from_bytes(data: &'a [u8]) -> Result<Request, Error> {
256 if data.len() < 4 {
257 return Err(Error::BadLength);
258 }
259 Request::from_bytes_with_crc(data, calculate_crc(&data[0..=3]))
260 }
261
262 fn from_bytes_with_crc(data: &'a [u8], calc_crc: u8) -> Result<Request, Error> {
275 if data.len() < 4 {
276 return Err(Error::BadLength);
277 }
278 if calc_crc != 0 {
279 return Err(Error::BadCrc);
282 }
283 Ok(Request {
284 request_type: data[0].try_into().map_err(|_| Error::BadRequestType)?,
285 register: data[1],
286 length_or_data: data[2],
287 crc: data[3],
288 })
289 }
290}
291
292impl<'a> Response<'a> {
293 pub fn new_ok_with_data(data: &'a [u8]) -> Response<'a> {
295 Response {
296 result: ResponseResult::Ok,
297 data,
298 crc: {
299 let mut crc = crc::init();
300 crc = crc::update(crc, &[ResponseResult::Ok as u8]);
301 crc = crc::update(crc, data);
302 crc::finalize(crc)
303 },
304 }
305 }
306
307 pub fn new_without_data(result: ResponseResult) -> Response<'a> {
309 Response {
310 result,
311 data: &[],
312 crc: calculate_crc(&[result as u8]),
313 }
314 }
315}
316
317impl<'a> Sendable for Response<'a> {
318 fn render_to_buffer(&self, buffer: &mut [u8]) -> Result<usize, Error> {
339 let len = 1 + self.data.len() + 1;
340 if buffer.len() < len {
341 return Err(Error::BufferTooSmall);
342 }
343 buffer[0] = self.result as u8;
344 for (src, dest) in self.data.iter().zip(buffer[1..].iter_mut()) {
345 *dest = *src;
346 }
347 buffer[len - 1] = self.crc;
348 Ok(len)
349 }
350}
351
352impl<'a> Receivable<'a> for Response<'a> {
353 fn from_bytes_with_crc(data: &'a [u8], calc_crc: u8) -> Result<Response<'a>, Error> {
364 if calc_crc != 0 {
365 return Err(Error::BadCrc);
368 }
369 Ok(Response {
370 result: data[0].try_into().map_err(|_| Error::BadResponseResult)?,
371 data: &data[1..=(data.len() - 2)],
372 crc: data[data.len() - 1],
373 })
374 }
375}
376
377impl ProtocolVersion {
378 pub const fn new(major: u8, minor: u8, patch: u8) -> ProtocolVersion {
386 ProtocolVersion {
387 major,
388 minor,
389 patch,
390 }
391 }
392
393 pub const fn is_compatible_with(&self, my_version: &ProtocolVersion) -> bool {
416 if self.major == my_version.major {
417 if self.minor > my_version.minor {
418 true
419 } else if self.minor == my_version.minor {
420 self.patch >= my_version.patch
421 } else {
422 false
423 }
424 } else {
425 false
426 }
427 }
428
429 pub const fn as_bytes(&self) -> [u8; 3] {
431 [self.major, self.minor, self.patch]
432 }
433}
434
435impl Sendable for ProtocolVersion {
436 fn render_to_buffer(&self, buffer: &mut [u8]) -> Result<usize, Error> {
437 let bytes = self.as_bytes();
438 if buffer.len() < bytes.len() {
439 return Err(Error::BufferTooSmall);
440 }
441 for (src, dest) in bytes.iter().zip(buffer.iter_mut()) {
442 *dest = *src;
443 }
444 Ok(bytes.len())
445 }
446}
447
448pub struct CrcCalc(u8);
454
455impl CrcCalc {
456 pub const fn new() -> CrcCalc {
458 CrcCalc(crc::init())
459 }
460
461 pub fn reset(&mut self) {
463 self.0 = crc::init();
464 }
465
466 pub fn add(&mut self, byte: u8) {
468 self.0 = crc::update(self.0, &[byte]);
469 }
470
471 pub fn add_buffer(&mut self, bytes: &[u8]) {
473 self.0 = crc::update(self.0, bytes);
474 }
475
476 pub fn get(&self) -> u8 {
478 crc::finalize(self.0)
479 }
480}
481
482pub fn calculate_crc(data: &[u8]) -> u8 {
491 let mut crc_calc = CrcCalc::new();
492 crc_calc.add_buffer(data);
493 crc_calc.get()
494}
495
496#[cfg(test)]
501mod test {
502 use super::*;
503
504 #[test]
505 fn read_request() {
506 let req = Request::new_read(false, 0x10, 0x20);
507 let bytes = req.as_bytes();
508 assert_eq!(bytes, [0xC0, 0x10, 0x20, 0x3A]);
509 let decoded_req = Request::from_bytes(&bytes).unwrap();
510 assert_eq!(req, decoded_req);
511 }
512
513 #[test]
514 fn read_request_alt() {
515 let req = Request::new_read(true, 0x10, 0x20);
516 let bytes = req.as_bytes();
517 assert_eq!(bytes, [0xC1, 0x10, 0x20, 0x51]);
518 let decoded_req = Request::from_bytes(&bytes).unwrap();
519 assert_eq!(req, decoded_req);
520 }
521
522 #[test]
523 fn short_write_request() {
524 let req = Request::new_short_write(false, 0x11, 0x22);
525 let bytes = req.as_bytes();
526 assert_eq!(bytes, [0xC2, 0x11, 0x22, 0xF7]);
527 let decoded_req = Request::from_bytes(&bytes).unwrap();
528 assert_eq!(req, decoded_req);
529 }
530
531 #[test]
532 fn short_write_request_alt() {
533 let req = Request::new_short_write(true, 0x11, 0x22);
534 let bytes = req.as_bytes();
535 assert_eq!(bytes, [0xC3, 0x11, 0x22, 0x9C]);
536 let decoded_req = Request::from_bytes(&bytes).unwrap();
537 assert_eq!(req, decoded_req);
538 }
539
540 #[test]
541 fn long_write_request() {
542 let req = Request::new_long_write(false, 0x0F, 0x50);
543 let bytes = req.as_bytes();
544 assert_eq!(bytes, [0xC4, 0x0F, 0x50, 0x52]);
545 let decoded_req = Request::from_bytes(&bytes).unwrap();
546 assert_eq!(req, decoded_req);
547 }
548
549 #[test]
550 fn long_write_request_alt() {
551 let req = Request::new_long_write(true, 0x0F, 0x50);
552 let bytes = req.as_bytes();
553 assert_eq!(bytes, [0xC5, 0x0F, 0x50, 0x39]);
554 let decoded_req = Request::from_bytes(&bytes).unwrap();
555 assert_eq!(req, decoded_req);
556 }
557}
558
559