1use crate::messages::{CanId, CanMessage, MessageError, LSS_REQ_ID, LSS_RESP_ID};
8
9#[derive(Debug, Clone, Copy)]
11pub enum LssCommandSpecifier {
12 SwitchModeGlobal = 0x04,
14 ConfigureNodeId = 0x11,
16 ConfigureBitTiming = 0x13,
18 ActivateBitTiming = 0x15,
20 StoreConfiguration = 0x17,
22 SwitchStateVendor = 0x40,
24 SwitchStateProduct = 0x41,
26 SwitchStateRev = 0x42,
28 SwitchStateSerial = 0x43,
33 SwitchStateResponse = 0x44,
35 IdentifySlave = 0x4F,
37 FastScan = 0x51,
39 InquireVendor = 0x5A,
41 InquireProduct = 0x5B,
43 InquireRev = 0x5C,
45 InquireSerial = 0x5D,
47 InquireNodeId = 0x5E,
49}
50
51#[derive(Debug, Clone, Copy, PartialEq)]
54#[repr(u8)]
55pub enum LssConfigureError {
56 Ok = 0,
58 NodeIdOutOfRange = 1,
60 Manufacturer = 0xff,
62}
63
64pub const LSS_FASTSCAN_CONFIRM: u8 = 0x80;
66
67impl LssCommandSpecifier {
68 pub fn from_byte(b: u8) -> Result<Self, MessageError> {
70 match b {
71 0x04 => Ok(Self::SwitchModeGlobal),
72 0x11 => Ok(Self::ConfigureNodeId),
73 0x13 => Ok(Self::ConfigureBitTiming),
74 0x15 => Ok(Self::ActivateBitTiming),
75 0x17 => Ok(Self::StoreConfiguration),
76 0x40 => Ok(Self::SwitchStateVendor),
77 0x41 => Ok(Self::SwitchStateProduct),
78 0x42 => Ok(Self::SwitchStateRev),
79 0x43 => Ok(Self::SwitchStateSerial),
80 0x44 => Ok(Self::SwitchStateResponse),
81 0x4F => Ok(Self::IdentifySlave),
82 0x51 => Ok(Self::FastScan),
83 0x5A => Ok(Self::InquireVendor),
84 0x5B => Ok(Self::InquireProduct),
85 0x5C => Ok(Self::InquireRev),
86 0x5D => Ok(Self::InquireSerial),
87 0x5E => Ok(Self::InquireNodeId),
88 _ => Err(MessageError::UnexpectedLssCommand { value: b }),
89 }
90 }
91}
92
93#[derive(Clone, Copy, Debug)]
95#[cfg_attr(feature = "defmt", derive(defmt::Format))]
96pub enum LssRequest {
97 SwitchModeGlobal {
99 mode: u8,
101 },
102 ConfigureNodeId {
104 node_id: u8,
106 },
107 ConfigureBitTiming {
109 table: u8,
125 index: u8,
127 },
128 StoreConfiguration,
130 ActivateBitTiming {
132 delay: u16,
134 },
135 SwitchStateVendor {
137 vendor_id: u32,
139 },
140 SwitchStateProduct {
142 product_code: u32,
144 },
145 SwitchStateRevision {
147 revision: u32,
149 },
150 SwitchStateSerial {
155 serial: u32,
157 },
158 InquireVendor,
160 InquireProduct,
162 InquireRev,
164 InquireSerial,
166 InquireNodeId,
168
169 FastScan {
171 id: u32,
173 bit_check: u8,
175 sub: u8,
181 next: u8,
183 },
184}
185
186impl TryFrom<&[u8]> for LssRequest {
187 type Error = MessageError;
188
189 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
190 if value.is_empty() {
191 return Err(MessageError::MessageTooShort);
192 }
193 let cs = LssCommandSpecifier::from_byte(value[0])?;
194 match cs {
195 LssCommandSpecifier::SwitchModeGlobal => {
196 if value.len() < 2 {
197 return Err(MessageError::MessageTooShort);
198 }
199 Ok(Self::SwitchModeGlobal { mode: value[1] })
200 }
201 LssCommandSpecifier::ConfigureNodeId => {
202 if value.len() < 2 {
203 return Err(MessageError::MessageTooShort);
204 }
205 Ok(Self::ConfigureNodeId { node_id: value[1] })
206 }
207 LssCommandSpecifier::ConfigureBitTiming => {
208 if value.len() < 3 {
209 return Err(MessageError::MessageTooShort);
210 }
211 Ok(Self::ConfigureBitTiming {
212 table: value[1],
213 index: value[2],
214 })
215 }
216 LssCommandSpecifier::ActivateBitTiming => {
217 if value.len() < 3 {
218 return Err(MessageError::MessageTooShort);
219 }
220 Ok(Self::ActivateBitTiming {
221 delay: u16::from_le_bytes([value[1], value[2]]),
222 })
223 }
224 LssCommandSpecifier::StoreConfiguration => Ok(Self::StoreConfiguration),
225 LssCommandSpecifier::SwitchStateVendor => {
226 if value.len() < 5 {
227 return Err(MessageError::MessageTooShort);
228 }
229 Ok(Self::SwitchStateVendor {
230 vendor_id: u32::from_le_bytes(value[1..5].try_into().unwrap()),
231 })
232 }
233 LssCommandSpecifier::SwitchStateProduct => {
234 if value.len() < 5 {
235 return Err(MessageError::MessageTooShort);
236 }
237 Ok(Self::SwitchStateProduct {
238 product_code: u32::from_le_bytes(value[1..5].try_into().unwrap()),
239 })
240 }
241 LssCommandSpecifier::SwitchStateRev => {
242 if value.len() < 5 {
243 return Err(MessageError::MessageTooShort);
244 }
245 Ok(Self::SwitchStateRevision {
246 revision: u32::from_le_bytes(value[1..5].try_into().unwrap()),
247 })
248 }
249 LssCommandSpecifier::SwitchStateSerial => {
250 if value.len() < 5 {
251 return Err(MessageError::MessageTooShort);
252 }
253 Ok(Self::SwitchStateSerial {
254 serial: u32::from_le_bytes(value[1..5].try_into().unwrap()),
255 })
256 }
257 LssCommandSpecifier::SwitchStateResponse => {
258 if value.len() < 5 {
259 return Err(MessageError::MessageTooShort);
260 }
261 Ok(Self::SwitchStateVendor {
262 vendor_id: u32::from_le_bytes(value[1..5].try_into().unwrap()),
263 })
264 }
265 LssCommandSpecifier::IdentifySlave => {
267 Err(MessageError::UnexpectedLssCommand { value: value[0] })
268 }
269 LssCommandSpecifier::FastScan => {
270 if value.len() < 8 {
271 return Err(MessageError::MessageTooShort);
272 }
273 Ok(Self::FastScan {
274 id: u32::from_le_bytes([value[1], value[2], value[3], value[4]]),
275 bit_check: value[5],
276 sub: value[6],
277 next: value[7],
278 })
279 }
280 LssCommandSpecifier::InquireVendor => Ok(LssRequest::InquireVendor),
281 LssCommandSpecifier::InquireProduct => Ok(LssRequest::InquireProduct),
282 LssCommandSpecifier::InquireRev => Ok(LssRequest::InquireRev),
283 LssCommandSpecifier::InquireSerial => Ok(LssRequest::InquireSerial),
284 LssCommandSpecifier::InquireNodeId => Ok(LssRequest::InquireNodeId),
285 }
286 }
287}
288
289impl From<LssRequest> for CanMessage {
290 fn from(value: LssRequest) -> Self {
291 let mut data = [0u8; 8];
292 match value {
293 LssRequest::SwitchModeGlobal { mode } => {
294 data[0] = LssCommandSpecifier::SwitchModeGlobal as u8;
295 data[1] = mode;
296 }
297 LssRequest::ConfigureNodeId { node_id } => {
298 data[0] = LssCommandSpecifier::ConfigureNodeId as u8;
299 data[1] = node_id;
300 }
301 LssRequest::ConfigureBitTiming { table, index } => {
302 data[0] = LssCommandSpecifier::ConfigureBitTiming as u8;
303 data[1] = table;
304 data[2] = index;
305 }
306 LssRequest::StoreConfiguration => {
307 data[0] = LssCommandSpecifier::StoreConfiguration as u8;
308 }
309 LssRequest::ActivateBitTiming { delay } => {
310 data[0] = LssCommandSpecifier::ActivateBitTiming as u8;
311 let delay_bytes = delay.to_le_bytes();
312 data[1] = delay_bytes[0];
313 data[2] = delay_bytes[1];
314 }
315 LssRequest::SwitchStateVendor { vendor_id } => {
316 data[0] = LssCommandSpecifier::SwitchStateVendor as u8;
317 data[1..5].copy_from_slice(&vendor_id.to_le_bytes());
318 }
319 LssRequest::SwitchStateProduct { product_code } => {
320 data[0] = LssCommandSpecifier::SwitchStateProduct as u8;
321 data[1..5].copy_from_slice(&product_code.to_le_bytes());
322 }
323 LssRequest::SwitchStateRevision { revision } => {
324 data[0] = LssCommandSpecifier::SwitchStateRev as u8;
325 data[1..5].copy_from_slice(&revision.to_le_bytes());
326 }
327 LssRequest::SwitchStateSerial { serial } => {
328 data[0] = LssCommandSpecifier::SwitchStateSerial as u8;
329 data[1..5].copy_from_slice(&serial.to_le_bytes());
330 }
331 LssRequest::InquireVendor => {
332 data[0] = LssCommandSpecifier::InquireVendor as u8;
333 }
334 LssRequest::InquireProduct => {
335 data[0] = LssCommandSpecifier::InquireProduct as u8;
336 }
337 LssRequest::InquireRev => {
338 data[0] = LssCommandSpecifier::InquireRev as u8;
339 }
340 LssRequest::InquireSerial => {
341 data[0] = LssCommandSpecifier::InquireSerial as u8;
342 }
343 LssRequest::InquireNodeId => {
344 data[0] = LssCommandSpecifier::InquireNodeId as u8;
345 }
346 LssRequest::FastScan {
347 id,
348 bit_check,
349 sub,
350 next,
351 } => {
352 data[0] = LssCommandSpecifier::FastScan as u8;
353 data[1..5].copy_from_slice(&id.to_le_bytes());
354 data[5] = bit_check;
355 data[6] = sub;
356 data[7] = next;
357 }
358 }
359 CanMessage::new(LSS_REQ_ID, &data)
360 }
361}
362
363#[derive(Clone, Copy, Debug, PartialEq)]
365#[cfg_attr(feature = "defmt", derive(defmt::Format))]
366pub enum LssResponse {
367 IdentifySlave,
369 SwitchStateResponse,
372 ConfigureNodeIdAck {
374 error: u8,
376 spec_error: u8,
380 },
381 ConfigureBitTimingAck {
383 error: u8,
385 spec_error: u8,
389 },
390 StoreConfigurationAck {
392 error: u8,
394 spec_error: u8,
398 },
399 InquireVendorAck {
401 vendor_id: u32,
403 },
404 InquireProductAck {
406 product_code: u32,
408 },
409 InquireRevAck {
411 revision: u32,
413 },
414 InquireSerialAck {
416 serial_number: u32,
418 },
419 InquireNodeIdAck {
421 node_id: u8,
423 },
424}
425
426impl TryFrom<&[u8]> for LssResponse {
427 type Error = MessageError;
428
429 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
430 if value.is_empty() {
431 return Err(MessageError::MessageTooShort);
432 }
433 let cs = LssCommandSpecifier::from_byte(value[0])?;
434 match cs {
435 LssCommandSpecifier::IdentifySlave => Ok(Self::IdentifySlave {}),
436 LssCommandSpecifier::SwitchStateResponse => Ok(Self::SwitchStateResponse {}),
437 LssCommandSpecifier::ConfigureNodeId => {
438 if value.len() < 3 {
439 return Err(MessageError::MessageTooShort);
440 }
441 Ok(Self::ConfigureNodeIdAck {
442 error: value[1],
443 spec_error: value[2],
444 })
445 }
446 LssCommandSpecifier::ConfigureBitTiming => {
447 if value.len() < 3 {
448 return Err(MessageError::MessageTooShort);
449 }
450 Ok(Self::ConfigureBitTimingAck {
451 error: value[1],
452 spec_error: value[2],
453 })
454 }
455 LssCommandSpecifier::StoreConfiguration => {
456 if value.len() < 3 {
457 return Err(MessageError::MessageTooShort);
458 }
459 Ok(Self::StoreConfigurationAck {
460 error: value[1],
461 spec_error: value[2],
462 })
463 }
464 LssCommandSpecifier::InquireVendor => {
465 if value.len() < 5 {
466 return Err(MessageError::MessageTooShort);
467 }
468 Ok(Self::InquireVendorAck {
469 vendor_id: u32::from_le_bytes([value[1], value[2], value[3], value[4]]),
470 })
471 }
472 LssCommandSpecifier::InquireProduct => {
473 if value.len() < 5 {
474 return Err(MessageError::MessageTooShort);
475 }
476 Ok(Self::InquireProductAck {
477 product_code: u32::from_le_bytes([value[1], value[2], value[3], value[4]]),
478 })
479 }
480 LssCommandSpecifier::InquireRev => {
481 if value.len() < 5 {
482 return Err(MessageError::MessageTooShort);
483 }
484 Ok(Self::InquireRevAck {
485 revision: u32::from_le_bytes([value[1], value[2], value[3], value[4]]),
486 })
487 }
488 LssCommandSpecifier::InquireSerial => {
489 if value.len() < 5 {
490 return Err(MessageError::MessageTooShort);
491 }
492 Ok(Self::InquireSerialAck {
493 serial_number: u32::from_le_bytes([value[1], value[2], value[3], value[4]]),
494 })
495 }
496 LssCommandSpecifier::InquireNodeId => {
497 if value.len() < 2 {
498 return Err(MessageError::MessageTooShort);
499 }
500 Ok(Self::InquireNodeIdAck { node_id: value[1] })
501 }
502 _ => Err(MessageError::UnexpectedLssCommand { value: value[0] }),
503 }
504 }
505}
506
507impl TryFrom<CanMessage> for LssResponse {
508 type Error = MessageError;
509
510 fn try_from(value: CanMessage) -> Result<Self, Self::Error> {
511 if value.id != LSS_RESP_ID {
512 return Err(MessageError::UnexpectedId {
513 cob_id: value.id,
514 expected: LSS_RESP_ID,
515 });
516 }
517 LssResponse::try_from(&value.data[..])
518 }
519}
520
521impl LssResponse {
522 pub fn to_can_message(self: &LssResponse, id: CanId) -> CanMessage {
524 let mut msg = CanMessage::new(id, &[0; 8]);
526 match self {
527 LssResponse::IdentifySlave => {
528 msg.data[0] = LssCommandSpecifier::IdentifySlave as u8;
529 }
530 LssResponse::SwitchStateResponse => {
531 msg.data[0] = LssCommandSpecifier::SwitchStateResponse as u8;
532 }
533 LssResponse::ConfigureNodeIdAck { error, spec_error } => {
534 msg.data[0] = LssCommandSpecifier::ConfigureNodeId as u8;
535 msg.data[1] = *error;
536 msg.data[2] = *spec_error;
537 }
538 LssResponse::ConfigureBitTimingAck { error, spec_error } => {
539 msg.data[0] = LssCommandSpecifier::ConfigureBitTiming as u8;
540 msg.data[1] = *error;
541 msg.data[2] = *spec_error;
542 }
543 LssResponse::StoreConfigurationAck { error, spec_error } => {
544 msg.data[0] = LssCommandSpecifier::StoreConfiguration as u8;
545 msg.data[1] = *error;
546 msg.data[2] = *spec_error;
547 }
548 LssResponse::InquireVendorAck { vendor_id } => {
549 msg.data[0] = LssCommandSpecifier::InquireVendor as u8;
550 msg.data[1..5].copy_from_slice(&vendor_id.to_le_bytes());
551 }
552 LssResponse::InquireProductAck { product_code } => {
553 msg.data[0] = LssCommandSpecifier::InquireProduct as u8;
554 msg.data[1..5].copy_from_slice(&product_code.to_le_bytes());
555 }
556 LssResponse::InquireRevAck { revision } => {
557 msg.data[0] = LssCommandSpecifier::InquireRev as u8;
558 msg.data[1..5].copy_from_slice(&revision.to_le_bytes());
559 }
560 LssResponse::InquireSerialAck { serial_number } => {
561 msg.data[0] = LssCommandSpecifier::InquireSerial as u8;
562 msg.data[1..5].copy_from_slice(&serial_number.to_le_bytes());
563 }
564 LssResponse::InquireNodeIdAck { node_id } => {
565 msg.data[0] = LssCommandSpecifier::InquireNodeId as u8;
566 msg.data[1] = *node_id;
567 }
568 }
569 msg
570 }
571}
572
573#[derive(Debug, Clone, Copy, PartialEq)]
575#[repr(u8)]
576pub enum LssState {
577 Waiting = 0,
579 Configuring = 1,
582}
583
584impl LssState {
585 pub fn from_byte(b: u8) -> Result<Self, MessageError> {
587 match b {
588 0x00 => Ok(Self::Waiting),
589 0x01 => Ok(Self::Configuring),
590 _ => Err(MessageError::InvalidField),
591 }
592 }
593}
594
595#[derive(Debug, Clone, Copy, PartialEq)]
604pub struct LssIdentity {
605 pub vendor_id: u32,
607 pub product_code: u32,
609 pub revision: u32,
611 pub serial: u32,
614}
615
616impl LssIdentity {
617 pub fn new(vendor_id: u32, product_code: u32, revision: u32, serial: u32) -> Self {
619 Self {
620 vendor_id,
621 product_code,
622 revision,
623 serial,
624 }
625 }
626
627 pub fn by_addr(&self, addr: u8) -> u32 {
629 match addr {
630 0 => self.vendor_id,
631 1 => self.product_code,
632 2 => self.revision,
633 3 => self.serial,
634 _ => panic!("Invalid LSS identity address"),
635 }
636 }
637}