1use crate::adc::{AdcDataRaw, AdcDataSimple};
2use crate::adcqueue::{AdcQueueData, AdcQueueRawData, GraphSampleRate};
3use crate::auth::{self, AuthCredential, StreamingAuthResult};
4use crate::constants::*;
5use crate::error::KMError;
6use crate::offline::{LogMetadata, LogMetadataResponse};
7use crate::packet::{
8 Attribute, AttributeSet, CtrlHeader, DataHeader, LogicalPacket, PacketType, RawPacket, StreamingAuthHeader,
9};
10use crate::pd::{PdEventStream, PdStatus, PdStatusRaw};
11use crate::pd_trace::PdTrace;
12use crate::settings::Settings;
13use bytes::Bytes;
14use num_enum::FromPrimitive;
15use zerocopy::{FromBytes, IntoBytes};
16
17const PD_MONITOR_ENABLED_PARAMETER: u16 = 1;
18const PD_MONITOR_DISABLED_PARAMETER: u16 = 0;
19
20#[derive(Debug, Clone, PartialEq)]
22#[cfg_attr(feature = "python", derive(pyo3::IntoPyObject))]
23pub enum PayloadData {
24 Adc(AdcDataSimple),
25 AdcQueue(AdcQueueData),
26 AdcQueueRaw(AdcQueueRawData),
27 PdStatus(PdStatus),
28 PdEvents(PdEventStream),
29 PdTrace(PdTrace),
30 Settings(Settings),
31 LogMetadata(LogMetadataResponse),
32 Unknown { attribute: Attribute, data: Vec<u8> },
33}
34
35#[derive(Debug, Clone, PartialEq)]
36pub enum Packet {
37 DataResponse { payloads: Vec<PayloadData> },
39 GetData { attributes: AttributeSet },
41 StartGraph { rate: GraphSampleRate },
48 StopGraph,
50 Accept { id: u8 },
52 Reject { id: u8 },
54 NotReadable { id: u8 },
56 Connect,
58 Disconnect,
60 EnablePdMonitor,
62 DisablePdMonitor,
64 MemoryRead {
66 address: u32,
68 size: u32,
70 },
71 StreamingAuth {
73 credential: AuthCredential,
75 },
76 StreamingAuthResponse(StreamingAuthResult),
78 Generic(RawPacket),
80}
81
82macro_rules! payload_accessor {
84 ($(#[$doc:meta])* $name:ident -> $target:ty, $variant:ident) => {
85 $(#[$doc])*
86 pub fn $name(&self) -> Option<&$target> {
87 self.find_payload(|payload| match payload {
88 PayloadData::$variant(inner) => Some(inner),
89 _ => None,
90 })
91 }
92 };
93}
94
95impl Packet {
96 pub fn find_payload<'a, T: ?Sized>(&'a self, select: impl Fn(&'a PayloadData) -> Option<&'a T>) -> Option<&'a T> {
101 match self {
102 Self::DataResponse { payloads } => payloads.iter().find_map(select),
103 _ => None,
104 }
105 }
106
107 payload_accessor!(
108 get_adc -> AdcDataSimple, Adc
110 );
111 payload_accessor!(
112 get_adc_queue -> AdcQueueData, AdcQueue
114 );
115 payload_accessor!(
116 get_adc_queue_raw -> AdcQueueRawData, AdcQueueRaw
118 );
119 payload_accessor!(
120 get_pd_status -> PdStatus, PdStatus
122 );
123 payload_accessor!(
124 get_pd_events -> PdEventStream, PdEvents
126 );
127 payload_accessor!(
128 get_pd_trace -> PdTrace, PdTrace
130 );
131 payload_accessor!(
132 get_settings -> Settings, Settings
134 );
135 payload_accessor!(
136 get_log_metadata -> LogMetadataResponse, LogMetadata
138 );
139
140 pub fn has_payload(&self, attr: Attribute) -> bool {
142 match self {
143 Self::DataResponse { payloads } => payloads.iter().any(|p| match p {
144 PayloadData::Adc(_) => attr == Attribute::Adc,
145 PayloadData::AdcQueue(_) => attr == Attribute::AdcQueue,
146 PayloadData::AdcQueueRaw(_) => attr == Attribute::AdcQueue,
147 PayloadData::PdStatus(_) | PayloadData::PdEvents(_) => attr == Attribute::PdPacket,
148 PayloadData::PdTrace(_) => attr == Attribute::PdTrace,
149 PayloadData::Settings(_) => attr == Attribute::Settings,
150 PayloadData::LogMetadata(_) => attr == Attribute::LogMetadata,
151 PayloadData::Unknown { attribute, .. } => *attribute == attr,
152 }),
153 _ => false,
154 }
155 }
156}
157
158impl TryFrom<RawPacket> for Packet {
159 type Error = KMError;
160
161 fn try_from(raw_packet: RawPacket) -> Result<Self, Self::Error> {
162 Self::from_raw(raw_packet, None)
163 }
164}
165
166impl Packet {
167 pub fn from_raw_with_graph_rate(raw_packet: RawPacket, rate: GraphSampleRate) -> Result<Self, KMError> {
172 Self::from_raw(raw_packet, Some(rate))
173 }
174
175 fn from_raw(raw_packet: RawPacket, graph_rate: Option<GraphSampleRate>) -> Result<Self, KMError> {
176 match raw_packet {
177 RawPacket::Ctrl { header, payload } => {
178 let packet_type = PacketType::from_primitive(header.packet_type());
179 let attribute_set = AttributeSet::from_raw(header.attribute());
180
181 match packet_type {
182 PacketType::GetData => Ok(Packet::GetData {
183 attributes: attribute_set,
184 }),
185 PacketType::StartGraph => match GraphSampleRate::try_from(attribute_set.raw()) {
188 Ok(rate) => Ok(Packet::StartGraph { rate }),
189 Err(_) => Ok(Packet::Generic(RawPacket::Ctrl { header, payload })),
190 },
191 PacketType::StopGraph => Ok(Packet::StopGraph),
192 PacketType::Accept => Ok(Packet::Accept { id: header.id() }),
193 PacketType::Rejected => Ok(Packet::Reject { id: header.id() }),
194 PacketType::NotReadable => Ok(Packet::NotReadable { id: header.id() }),
195 PacketType::Connect => Ok(Packet::Connect),
196 PacketType::Disconnect => Ok(Packet::Disconnect),
197 PacketType::EnablePdMonitor => Ok(Packet::EnablePdMonitor),
198 PacketType::DisablePdMonitor => Ok(Packet::DisablePdMonitor),
199 _ => Ok(Packet::Generic(RawPacket::Ctrl { header, payload })),
200 }
201 }
202 RawPacket::SimpleData { header, payload } => {
203 let packet_type = PacketType::from_primitive(header.packet_type());
204
205 match packet_type {
206 PacketType::MemoryRead => {
207 if !header.reserved_flag()
208 && header.into_bytes()[2..4] == [0x01, 0x01]
209 && let Some((address, size)) = auth::parse_memory_read_payload(&payload)
210 {
211 Ok(Packet::MemoryRead { address, size })
212 } else {
213 Ok(Packet::Generic(RawPacket::SimpleData { header, payload }))
214 }
215 }
216 PacketType::StreamingAuth => {
217 let auth_header = StreamingAuthHeader::from_bytes(header.into_bytes());
218 if auth_header.attribute() == 0x0200
219 && let Some(credential) = auth::parse_streaming_auth_request_payload(&payload)
220 {
221 Ok(Packet::StreamingAuth { credential })
222 } else if let Some(result) = auth::parse_streaming_auth_response_parts(auth_header, &payload) {
223 Ok(Packet::StreamingAuthResponse(result))
224 } else {
225 Ok(Packet::Generic(RawPacket::SimpleData { header, payload }))
226 }
227 }
228 _ => Ok(Packet::Generic(RawPacket::SimpleData { header, payload })),
229 }
230 }
231 RawPacket::Data { logical_packets, .. } => {
232 let mut payloads = Vec::new();
234
235 for lp in logical_packets {
236 let payload_data = match lp.attribute {
237 Attribute::Adc => {
238 if lp.payload.len() < ADC_DATA_SIZE {
240 return Err(KMError::InvalidPacket(format!(
241 "ADC payload too small: expected {}, got {}",
242 ADC_DATA_SIZE,
243 lp.payload.len()
244 )));
245 }
246
247 let adc_data_raw = AdcDataRaw::ref_from_bytes(&lp.payload[..ADC_DATA_SIZE])
248 .map_err(|_| KMError::InvalidPacket("Failed to parse ADC data".to_string()))?;
249 let adc_data = AdcDataSimple::from(*adc_data_raw);
250 PayloadData::Adc(adc_data)
251 }
252 Attribute::AdcQueue => {
253 if let Some(rate) = graph_rate {
257 PayloadData::AdcQueue(AdcQueueData::from_bytes_with_rate(lp.payload.as_ref(), rate)?)
258 } else {
259 PayloadData::AdcQueueRaw(AdcQueueRawData::from_bytes(lp.payload.as_ref())?)
260 }
261 }
262 Attribute::PdPacket => {
263 if lp.payload.len() == PD_STATUS_SIZE {
265 let pd_status_raw = PdStatusRaw::ref_from_bytes(lp.payload.as_ref())
267 .map_err(|_| KMError::InvalidPacket("Failed to parse PD status".to_string()))?;
268 PayloadData::PdStatus(PdStatus::from(*pd_status_raw))
269 } else {
270 let pd_events = PdEventStream::from_bytes(Bytes::from(lp.payload))?;
272 PayloadData::PdEvents(pd_events)
273 }
274 }
275 Attribute::PdTrace => PayloadData::PdTrace(PdTrace::from_bytes(&lp.payload)?),
276 Attribute::Settings => PayloadData::Settings(Settings::from_bytes(lp.payload.as_ref())?),
277 Attribute::LogMetadata => {
278 if lp.payload.is_empty() {
279 PayloadData::LogMetadata(LogMetadataResponse::Empty)
280 } else {
281 if !lp.payload.len().is_multiple_of(crate::offline::LOG_METADATA_SIZE) {
282 return Err(KMError::InvalidPacket(format!(
283 "LogMetadata payload length must be a multiple of {}, got {}",
284 crate::offline::LOG_METADATA_SIZE,
285 lp.payload.len()
286 )));
287 }
288 let entries = lp
289 .payload
290 .as_chunks::<{ crate::offline::LOG_METADATA_SIZE }>()
291 .0
292 .iter()
293 .map(|chunk| LogMetadata::from_bytes(chunk))
294 .collect::<Result<Vec<_>, _>>()?;
295 PayloadData::LogMetadata(LogMetadataResponse::Available(entries))
296 }
297 }
298 _ => PayloadData::Unknown {
299 attribute: lp.attribute,
300 data: lp.payload.to_vec(),
301 },
302 };
303
304 payloads.push(payload_data);
305 }
306
307 Ok(Packet::DataResponse { payloads })
308 }
309 }
310 }
311}
312
313impl Packet {
314 pub fn to_raw_packet(self, id: u8) -> Result<RawPacket, KMError> {
316 let raw_packet = match self {
317 Packet::DataResponse { payloads } => {
318 let mut logical_packets = Vec::new();
319
320 for payload in payloads {
321 match payload {
322 PayloadData::Adc(adc) => {
323 let adc_raw = AdcDataRaw::from(adc);
324 logical_packets.push(LogicalPacket {
325 attribute: Attribute::Adc,
326 next: false, chunk: 0,
328 size: ADC_DATA_SIZE as u16,
329 payload: adc_raw.as_bytes().to_vec(),
330 });
331 }
332 PayloadData::PdStatus(pd_status) => {
333 let raw = PdStatusRaw::from(pd_status);
334
335 logical_packets.push(LogicalPacket {
336 attribute: Attribute::PdPacket,
337 next: false, chunk: 0,
339 size: PD_STATUS_SIZE as u16,
340 payload: raw.as_bytes().to_vec(),
341 });
342 }
343 PayloadData::AdcQueue(_) => {
344 return Err(KMError::UnsupportedSerialization { packet: "AdcQueue" });
345 }
346 PayloadData::AdcQueueRaw(queue) => {
347 logical_packets.push(LogicalPacket {
348 attribute: Attribute::AdcQueue,
349 next: false,
350 chunk: 0,
351 size: 20,
352 payload: queue.to_bytes(),
353 });
354 }
355 PayloadData::PdEvents(_) => {
356 return Err(KMError::UnsupportedSerialization {
357 packet: "PdEventStream",
358 });
359 }
360 PayloadData::PdTrace(trace) => {
361 logical_packets.push(LogicalPacket {
362 attribute: Attribute::PdTrace,
363 next: false,
364 chunk: 0,
365 size: 0,
366 payload: trace.to_bytes()?,
367 });
368 }
369 PayloadData::Settings(settings) => {
370 logical_packets.push(LogicalPacket {
371 attribute: Attribute::Settings,
372 next: false,
373 chunk: 0,
374 size: crate::settings::SETTINGS_SIZE as u16,
375 payload: settings.to_bytes().to_vec(),
376 });
377 }
378 PayloadData::LogMetadata(response) => {
379 let payload = match response {
380 LogMetadataResponse::Empty => Vec::new(),
381 LogMetadataResponse::Available(metadata) => {
382 metadata.iter().flat_map(LogMetadata::to_bytes).collect()
383 }
384 };
385 logical_packets.push(LogicalPacket {
386 attribute: Attribute::LogMetadata,
387 next: false,
388 chunk: 0,
389 size: payload.len() as u16,
390 payload,
391 });
392 }
393 PayloadData::Unknown { attribute, data } => {
394 logical_packets.push(LogicalPacket {
395 attribute,
396 next: false, chunk: 0,
398 size: data.len() as u16,
399 payload: data,
400 });
401 }
402 }
403 }
404
405 if let Some((last, rest)) = logical_packets.split_last_mut() {
407 for lp in rest {
408 lp.next = true;
409 }
410 last.next = false;
411 }
412
413 let total_size: usize = logical_packets.iter().map(|lp| 4 + lp.payload.len()).sum();
415
416 let obj_count_words = if logical_packets.is_empty() {
420 0
421 } else {
422 ((4 + total_size) / 4).saturating_sub(3) as u16
423 };
424
425 let header = DataHeader::new()
426 .with_packet_type(PacketType::PutData.into())
427 .with_reserved_flag(false)
428 .with_id(id)
429 .with_obj_count_words(obj_count_words);
430
431 RawPacket::Data {
432 header,
433 logical_packets,
434 }
435 }
436 Packet::GetData { attributes } => RawPacket::Ctrl {
437 header: CtrlHeader::new()
438 .with_packet_type(PacketType::GetData.into())
439 .with_reserved_flag(false)
440 .with_id(id)
441 .with_attribute(attributes.raw()),
442 payload: Vec::new(),
443 },
444 Packet::StartGraph { rate } => RawPacket::Ctrl {
445 header: CtrlHeader::new()
446 .with_packet_type(PacketType::StartGraph.into())
447 .with_reserved_flag(false)
448 .with_id(id)
449 .with_attribute(rate as u16),
450 payload: Vec::new(),
451 },
452 Packet::StopGraph => RawPacket::Ctrl {
453 header: CtrlHeader::new()
454 .with_packet_type(PacketType::StopGraph.into())
455 .with_reserved_flag(false)
456 .with_id(id)
457 .with_attribute(0),
458 payload: Vec::new(),
459 },
460 Packet::Accept { id: accept_id } => RawPacket::Ctrl {
461 header: CtrlHeader::new()
462 .with_packet_type(PacketType::Accept.into())
463 .with_reserved_flag(false)
464 .with_id(accept_id)
465 .with_attribute(0),
466 payload: Vec::new(),
467 },
468 Packet::Reject { id: reject_id } => RawPacket::Ctrl {
469 header: CtrlHeader::new()
470 .with_packet_type(PacketType::Rejected.into())
471 .with_reserved_flag(false)
472 .with_id(reject_id)
473 .with_attribute(0),
474 payload: Vec::new(),
475 },
476 Packet::NotReadable { id: nr_id } => RawPacket::Ctrl {
477 header: CtrlHeader::new()
478 .with_packet_type(PacketType::NotReadable.into())
479 .with_reserved_flag(false)
480 .with_id(nr_id)
481 .with_attribute(0),
482 payload: Vec::new(),
483 },
484 Packet::Connect => RawPacket::Ctrl {
485 header: CtrlHeader::new()
486 .with_packet_type(PacketType::Connect.into())
487 .with_reserved_flag(false)
488 .with_id(id)
489 .with_attribute(0),
490 payload: Vec::new(),
491 },
492 Packet::Disconnect => RawPacket::Ctrl {
493 header: CtrlHeader::new()
494 .with_packet_type(PacketType::Disconnect.into())
495 .with_reserved_flag(false)
496 .with_id(id)
497 .with_attribute(0),
498 payload: Vec::new(),
499 },
500 Packet::EnablePdMonitor => RawPacket::Ctrl {
501 header: CtrlHeader::new()
502 .with_packet_type(PacketType::EnablePdMonitor.into())
503 .with_reserved_flag(false)
504 .with_id(id)
505 .with_attribute(PD_MONITOR_ENABLED_PARAMETER),
506 payload: Vec::new(),
507 },
508 Packet::DisablePdMonitor => RawPacket::Ctrl {
509 header: CtrlHeader::new()
510 .with_packet_type(PacketType::DisablePdMonitor.into())
511 .with_reserved_flag(false)
512 .with_id(id)
513 .with_attribute(PD_MONITOR_DISABLED_PARAMETER),
514 payload: Vec::new(),
515 },
516 Packet::MemoryRead { address, size } => {
517 let encrypted_payload = auth::build_memory_read_payload(address, size);
519 RawPacket::SimpleData {
520 header: DataHeader::from_bytes([PacketType::MemoryRead.into(), id, 0x01, 0x01]),
521 payload: encrypted_payload.to_vec(),
522 }
523 }
524 Packet::StreamingAuth { credential } => {
525 let encrypted_payload = auth::build_streaming_auth_payload(&credential);
527 RawPacket::SimpleData {
528 header: DataHeader::from_bytes([PacketType::StreamingAuth.into(), id, 0x00, 0x02]),
529 payload: encrypted_payload.to_vec(),
530 }
531 }
532 Packet::StreamingAuthResponse(result) => {
533 let encrypted_payload = auth::encrypt_streaming_auth_response_payload(&result.decrypted_payload);
535 let auth_header = StreamingAuthHeader::new()
536 .with_packet_type(PacketType::StreamingAuth.into())
537 .with_reserved_flag(false)
538 .with_id(auth::STREAMING_AUTH_RESPONSE_ID)
539 .with_attribute(result.attribute);
540 RawPacket::Ctrl {
541 header: CtrlHeader::from_bytes(auth_header.into_bytes()),
542 payload: encrypted_payload.to_vec(),
543 }
544 }
545 Packet::Generic(raw_packet) => raw_packet,
546 };
547
548 Ok(raw_packet)
549 }
550}
551
552#[cfg(feature = "python")]
554impl<'py> pyo3::IntoPyObject<'py> for Packet {
555 type Target = pyo3::PyAny;
556 type Output = pyo3::Bound<'py, Self::Target>;
557 type Error = pyo3::PyErr;
558
559 fn into_pyobject(self, py: pyo3::Python<'py>) -> Result<Self::Output, Self::Error> {
560 use pyo3::types::{PyDict, PyDictMethods};
561
562 let dict = PyDict::new(py);
563 match self {
564 Packet::DataResponse { payloads } => {
565 let inner = PyDict::new(py);
566 inner.set_item("payloads", payloads.into_pyobject(py)?)?;
567 dict.set_item("DataResponse", inner)?;
568 }
569 Packet::GetData { attributes } => {
570 let inner = PyDict::new(py);
571 inner.set_item("attribute_mask", attributes.raw())?;
572 dict.set_item("GetData", inner)?;
573 }
574 Packet::StartGraph { rate } => {
575 let inner = PyDict::new(py);
576 inner.set_item("rate_index", rate as u16)?;
577 dict.set_item("StartGraph", inner)?;
578 }
579 Packet::StopGraph => {
580 dict.set_item("StopGraph", py.None())?;
581 }
582 Packet::Accept { id } => {
583 let inner = PyDict::new(py);
584 inner.set_item("id", id)?;
585 dict.set_item("Accept", inner)?;
586 }
587 Packet::Reject { id } => {
588 let inner = PyDict::new(py);
589 inner.set_item("id", id)?;
590 dict.set_item("Reject", inner)?;
591 }
592 Packet::NotReadable { id } => {
593 let inner = PyDict::new(py);
594 inner.set_item("id", id)?;
595 dict.set_item("NotReadable", inner)?;
596 }
597 Packet::Connect => {
598 dict.set_item("Connect", py.None())?;
599 }
600 Packet::Disconnect => {
601 dict.set_item("Disconnect", py.None())?;
602 }
603 Packet::EnablePdMonitor => {
604 dict.set_item("EnablePdMonitor", py.None())?;
605 }
606 Packet::DisablePdMonitor => {
607 dict.set_item("DisablePdMonitor", py.None())?;
608 }
609 Packet::MemoryRead { address, size } => {
610 let inner = PyDict::new(py);
611 inner.set_item("address", address)?;
612 inner.set_item("size", size)?;
613 dict.set_item("MemoryRead", inner)?;
614 }
615 Packet::StreamingAuth { credential } => {
616 let inner = PyDict::new(py);
617 inner.set_item("credential", hex::encode(credential.as_bytes()))?;
618 dict.set_item("StreamingAuth", inner)?;
619 }
620 Packet::StreamingAuthResponse(result) => {
621 let inner = PyDict::new(py);
622 inner.set_item("success", result.success)?;
623 inner.set_item("auth_level", result.auth_level)?;
624 inner.set_item("attribute", result.attribute)?;
625 dict.set_item("StreamingAuthResponse", inner)?;
626 }
627 Packet::Generic(raw_packet) => {
628 dict.set_item("Generic", raw_packet.into_pyobject(py)?)?;
629 }
630 }
631 Ok(dict.into_any())
632 }
633}