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