@@ -212,6 +212,7 @@ pub async fn set_simple_state_sensor_enables(
212212 Ok ( ( ) )
213213}
214214
215+ /// Get PDR Repository Info
215216pub async fn get_pdr_repository_info (
216217 comm : & mut impl mctp:: AsyncReqChannel ,
217218) -> Result < GetPDRRepositoryInfoResp > {
@@ -237,68 +238,127 @@ pub async fn get_pdr_repository_info(
237238 Ok ( ret)
238239}
239240
240- pub async fn get_pdr (
241- comm : & mut impl mctp:: AsyncReqChannel ,
242- record_handle : u32 ,
243- ) -> Result < PdrRecord > {
244- // TODO: callers pass a buffer? might be nice to
245- // reuse between tx/rx.
246- let mut rxbuf = [ 0 ; 200 ] ;
247-
248- let getpdr = GetPDRReq {
249- record_handle,
250- data_transfer_handle : 0 ,
251- transfer_operation_flag : TransferOperationFlag :: FirstPart ,
252- // subtract 4 bytes pldm header, 12 bytes PDR header/crc
253- request_count : ( rxbuf. len ( ) - 4 - 12 ) as u16 ,
254- record_change_number : 0 ,
255- } ;
256- let mut txdata = [ 0 ; 50 ] ;
257- let l = getpdr. to_slice ( & mut txdata) ?;
258- let txdata = & txdata[ ..l] ;
259- let req = PldmRequest :: new_borrowed (
260- PLDM_TYPE_PLATFORM ,
261- Cmd :: GetPDR as u8 ,
262- txdata,
263- ) ;
264-
265- let resp = pldm_xfer_buf_async ( comm, req, & mut rxbuf) . await ?;
266- let ( ( rest, _) , pdrrsp) =
267- GetPDRResp :: from_bytes ( ( & resp. data , 0 ) ) . map_err ( |e| {
268- trace ! ( "GetPDR parse error {e:?}" ) ;
269- proto_error ! ( "Bad GetPDR response" )
270- } ) ?;
271- if !rest. is_empty ( ) {
272- return Err ( proto_error ! ( "Extra response" ) ) ;
273- }
241+ /// An iterator over PDR records, returned by [`get_pdr`].
242+ pub struct GetPdrIter < ' a , C : mctp:: AsyncReqChannel > {
243+ next_handle : u32 ,
244+ done : bool ,
245+ comm : & ' a mut C ,
246+ }
274247
275- if pdrrsp. transfer_flag != xfer_flag:: START_AND_END {
276- return Err ( proto_error ! ( "Can't handle multipart" ) ) ;
248+ impl < ' a , C : mctp:: AsyncReqChannel > GetPdrIter < ' a , C > {
249+ fn new ( comm : & ' a mut C ) -> Self {
250+ Self {
251+ next_handle : 0 ,
252+ done : false ,
253+ comm,
254+ }
277255 }
278256
279- let ( ( rest , _ ) , pdr ) =
280- Pdr :: from_bytes ( ( & pdrrsp . record_data , 0 ) ) . map_err ( |e| {
281- trace ! ( "GetSensorReading parse error {e}" ) ;
282- proto_error ! ( "Bad GetSensorReading response" )
283- } ) ? ;
284- if !rest . is_empty ( ) {
285- return Err ( proto_error ! ( "Extra PDR response" ) ) ;
257+ /// Return the next PDR from the host.
258+ ///
259+ /// `None` will be returned after the last record.
260+ /// `Some(Err)` may be returned on error, further calls to next() may still
261+ /// return more records successfully.
262+ pub async fn next ( & mut self ) -> Option < Result < PdrRecord > > {
263+ self . next_inner ( ) . await . transpose ( )
286264 }
287265
288- if pdr. record_handle != record_handle {
289- return Err ( proto_error ! ( "PDR record handle mismatch" ) ) ;
290- }
291- if pdr. pdr_header_version != PDR_VERSION_1 {
292- return Err ( proto_error ! ( "PDR unknown version" ) ) ;
293- }
266+ // Inner function to use `?`.
267+ async fn next_inner ( & mut self ) -> Result < Option < PdrRecord > > {
268+ if self . done {
269+ return Ok ( None ) ;
270+ }
294271
295- let expect_len = pdrrsp. record_data . len ( ) - 10 ;
296- if pdr. data_length as usize != expect_len {
297- warn ! (
298- "Incorrect PDR data_length, got {}, expect {}" ,
299- pdr. data_length, expect_len
272+ // TODO: callers pass a buffer? might be nice to
273+ // reuse between tx/rx.
274+ let mut rxbuf = [ 0 ; 200 ] ;
275+
276+ let getpdr = GetPDRReq {
277+ record_handle : self . next_handle ,
278+ data_transfer_handle : 0 ,
279+ transfer_operation_flag : TransferOperationFlag :: FirstPart ,
280+ // subtract 4 bytes pldm header, 12 bytes PDR header/crc
281+ request_count : ( rxbuf. len ( ) - 4 - 12 ) as u16 ,
282+ record_change_number : 0 ,
283+ } ;
284+ let mut txdata = [ 0 ; 13 ] ;
285+ let l = getpdr. to_slice ( & mut txdata) ?;
286+ let txdata = & txdata[ ..l] ;
287+ let req = PldmRequest :: new_borrowed (
288+ PLDM_TYPE_PLATFORM ,
289+ Cmd :: GetPDR as u8 ,
290+ txdata,
300291 ) ;
292+
293+ // Failure prior to parsing a next_handle should stop the iterator,
294+ // setting self.done and returning the failure Result.
295+ // Other errors don't stop the iterator, they are just returned as a Result.
296+
297+ let resp = pldm_xfer_buf_async ( self . comm , req, & mut rxbuf)
298+ . await
299+ . inspect_err ( |_| self . done = true ) ?;
300+ let ( ( rest, _) , pdrrsp) = GetPDRResp :: from_bytes ( ( & resp. data , 0 ) )
301+ . map_err ( |e| {
302+ trace ! ( "GetPDR parse error {e:?}" ) ;
303+ self . done = true ;
304+ proto_error ! ( "Bad GetPDR response" )
305+ } ) ?;
306+ if !rest. is_empty ( ) {
307+ self . done = true ;
308+ return Err ( proto_error ! ( "Extra response" ) ) ;
309+ }
310+
311+ if pdrrsp. next_record_handle == 0 {
312+ // Last handle
313+ self . done = true
314+ }
315+ self . next_handle = pdrrsp. next_record_handle ;
316+
317+ if pdrrsp. record_data . len ( ) > getpdr. request_count as usize {
318+ return Err ( proto_error ! (
319+ "Get PDR returned extra record data" ,
320+ "Requested {}, got {}" ,
321+ getpdr. request_count,
322+ pdrrsp. record_data. len( )
323+ ) ) ;
324+ }
325+
326+ // This is a current limitation of this implementation,
327+ // not a problem with the response. We can't attempt
328+ // to parse the record_data since it will be incomplete.
329+ if pdrrsp. transfer_flag != xfer_flag:: START_AND_END {
330+ return Err ( proto_error ! ( "Can't handle multipart" ) ) ;
331+ }
332+
333+ let ( ( rest, _) , pdr) = Pdr :: from_bytes ( ( & pdrrsp. record_data , 0 ) )
334+ . map_err ( |e| {
335+ trace ! ( "GetPDR parse error {e}" ) ;
336+ proto_error ! ( "Bad GetPDR response" )
337+ } ) ?;
338+ if !rest. is_empty ( ) {
339+ return Err ( proto_error ! ( "Extra PDR response" ) ) ;
340+ }
341+
342+ let expect_len = pdrrsp. record_data . len ( ) - 10 ;
343+ if pdr. data_length as usize != expect_len {
344+ warn ! (
345+ "Incorrect PDR data_length, got {}, expect {}" ,
346+ pdr. data_length, expect_len
347+ ) ;
348+ }
349+
350+ if pdr. pdr_header_version != PDR_VERSION_1 {
351+ return Err ( proto_error ! ( "PDR unknown version" ) ) ;
352+ }
353+
354+ Ok ( Some ( pdr. record ) )
301355 }
356+ }
302357
303- Ok ( pdr. record )
358+ /// Return a `GetPdrIter` to iterate over Get PDR requests.
359+ pub fn get_pdr < C > ( comm : & mut C ) -> GetPdrIter < ' _ , C >
360+ where
361+ C : mctp:: AsyncReqChannel ,
362+ {
363+ GetPdrIter :: new ( comm)
304364}
0 commit comments