@@ -318,23 +318,23 @@ pub struct CircBuffer<BUFFER, PAYLOAD>
318
318
where
319
319
BUFFER : ' static ,
320
320
{
321
- buffer : & ' static mut [ BUFFER ; 2 ] ,
321
+ buffer : & ' static mut BUFFER ,
322
322
payload : PAYLOAD ,
323
- readable_half : Half ,
324
- consumed_offset : usize ,
323
+ read_index : usize ,
324
+ write_previous : usize ,
325
325
}
326
326
327
327
impl < BUFFER , PAYLOAD > CircBuffer < BUFFER , PAYLOAD >
328
328
where
329
- & ' static mut [ BUFFER ; 2 ] : StaticWriteBuffer ,
329
+ & ' static mut BUFFER : StaticWriteBuffer ,
330
330
BUFFER : ' static ,
331
331
{
332
- pub ( crate ) fn new ( buf : & ' static mut [ BUFFER ; 2 ] , payload : PAYLOAD ) -> Self {
332
+ pub ( crate ) fn new ( buf : & ' static mut BUFFER , payload : PAYLOAD ) -> Self {
333
333
CircBuffer {
334
334
buffer : buf,
335
335
payload,
336
- readable_half : Half :: Second ,
337
- consumed_offset : 0 ,
336
+ read_index : 0 ,
337
+ write_previous : 0 ,
338
338
}
339
339
}
340
340
}
@@ -861,101 +861,117 @@ macro_rules! dma {
861
861
where
862
862
RxDma <PAYLOAD , $CX>: TransferPayload ,
863
863
{
864
-
865
- /// Return the partial contents of the buffer half being written
866
- pub fn partial_peek<R , F , T >( & mut self , f: F ) -> Result <R , Error >
867
- where
868
- F : FnOnce ( & [ T ] , Half ) -> Result <( usize , R ) , ( ) >,
869
- B : AsRef <[ T ] >,
870
- {
871
- // this inverts expectation and returns the half being _written_
872
- let buf = match self . readable_half {
873
- Half :: First => & self . buffer[ 1 ] ,
874
- Half :: Second => & self . buffer[ 0 ] ,
875
- } ;
876
- // ,- half-buffer
877
- // [ x x x x y y y y y z | z z z z z z z z z z ]
878
- // ^- pending=11
879
- let pending = self . payload. channel. get_cndtr( ) as usize ; // available transfers (= bytes) in _whole_ buffer
880
- let slice = buf. as_ref( ) ;
881
- let capacity = slice. len( ) ; // capacity of _half_ a buffer
882
- // <--- capacity=10 --->
883
- // [ x x x x y y y y y z | z z z z z z z z z z ]
884
- let pending = if pending > capacity {
885
- pending - capacity
886
- } else {
887
- pending
888
- } ;
889
- // ,- half-buffer
890
- // [ x x x x y y y y y z | z z z z z z z z z z ]
891
- // ^- pending=1
892
- let end = capacity - pending;
893
- // [ x x x x y y y y y z | z z z z z z z z z z ]
894
- // ^- end=9
895
- // ^- consumed_offset=4
896
- // [y y y y y] <-- slice
897
- let slice = & buf. as_ref( ) [ self . consumed_offset..end] ;
898
- match f( slice, self . readable_half) {
899
- Ok ( ( l, r) ) => { self . consumed_offset += l; Ok ( r) } ,
900
- Err ( _) => Err ( Error :: BufferError ) ,
864
+ /// Determines if the write index passed the given `mark` when it moved
865
+ /// from `previous` to `current` with wrapping behaviour at `wrap`.
866
+ /// When `current` reaches `mark` (`current == mark`), this method already
867
+ /// returns `true`.
868
+ fn passed_mark( & self , mut previous: usize , mut current: usize , mark: usize , wrap: usize ) -> bool {
869
+ // We have three indexes mark (m), previous (p) and current (c) so
870
+ // there are fac(3)=6 possibilities how those can be ordered. For both
871
+ // cases (passed, !passed), there are three wrapped variations each:
872
+ // !passed: 1. m <= p <= c, 2. c < m <= p, 3. p <= c < m
873
+ // passed: 1. m <= c < p, 2. p < m <= c, 3. c < p < m
874
+ // By enforcing p >= m and c >= m (reverting the wrap), we only have to
875
+ // check the first case.
876
+ if previous < mark {
877
+ previous += wrap;
901
878
}
879
+ if current < mark {
880
+ current += wrap;
881
+ }
882
+ current < previous && current >= mark
902
883
}
903
884
904
- /// Peeks into the readable half of the buffer
905
- /// Returns the result of the closure
906
- pub fn peek<R , F , T >( & mut self , f: F ) -> Result <R , Error >
885
+ /// Reads and removes the available contents of the dma buffer into `buf`.
886
+ /// Returns `Err(Error::Overrun)` if an overrun is detected but there is no
887
+ /// guarantee that every overrun can be detected.
888
+ /// On success, returns the number of words written to `buf`.
889
+ pub fn read<T >( & mut self , buf: & mut [ T ] ) -> Result <usize , Error >
907
890
where
908
- F : FnOnce ( & [ T ] , Half ) -> R ,
909
891
B : AsRef <[ T ] >,
892
+ T : Copy ,
910
893
{
911
- let half_being_read = self . readable_half( ) ?;
912
- let buf = match half_being_read {
913
- Half :: First => & self . buffer[ 0 ] ,
914
- Half :: Second => & self . buffer[ 1 ] ,
915
- } ;
916
- let slice = & buf. as_ref( ) [ self . consumed_offset..] ;
917
- self . consumed_offset = 0 ;
918
- Ok ( f( slice, half_being_read) )
919
- }
920
-
921
- /// Returns the `Half` of the buffer that can be read
922
- pub fn readable_half( & mut self ) -> Result <Half , Error > {
894
+ // We do our best to figure out when an overrun occurred but without
895
+ // risking false positives.
896
+ //
897
+ // One possibility to detect an overrun is by examining the read- and
898
+ // write-indexes: If the write-index passes the read-index, that is an
899
+ // overrun condition because an unread value is overwritten. This check
900
+ // can fail if the write-index passed the read-index but due to
901
+ // wrapping, this can not be detected. For example, this can happen if
902
+ // `capacity` many words were written since the last read which looks
903
+ // like no word has been written.
904
+ //
905
+ // Another possibility to detect overruns is by checking the
906
+ // TransferComplete and HalfTransferComplete flags. For example, the
907
+ // TransferComplete flag is set when the write-index wraps around so
908
+ // whenever we encounter this flag the new write-index should be
909
+ // smaller than the previous one. If it is not, more than `capacity`
910
+ // many words must have been written which definitely must be an
911
+ // overrun. Another possibility to formulate this condition is to check
912
+ // wheter the write-index passed index 0. A similar condition can be
913
+ // formulated for the HalfTransferComplete flag, i.e. check whether the
914
+ // write-index passed index capacity/2.
915
+ //
916
+ // Unfortunately, even both checks together can not guarantee that we
917
+ // detect all overruns.
918
+ // Example:
919
+ // read = 2, write = 3, 2*capacity-2 words written => write = 1.
920
+ let capacity = self . buffer. as_ref( ) . len( ) ;
921
+ // We read the flags before reading the current write-index because if
922
+ // another word is written between those two accesses, this ordering
923
+ // prevents a false positive overrun error.
923
924
let isr = self . payload. channel. isr( ) ;
924
- let first_half_is_done = isr. $htifX( ) . bit_is_set( ) ;
925
- let second_half_is_done = isr. $tcifX( ) . bit_is_set( ) ;
926
-
927
- if first_half_is_done && second_half_is_done {
928
- return Err ( Error :: Overrun ) ;
925
+ let half_complete_flag = isr. $htifX( ) . bit_is_set( ) ;
926
+ if half_complete_flag {
927
+ self . payload. channel. ifcr( ) . write( |w| w. $chtifX( ) . set_bit( ) ) ;
929
928
}
930
-
931
- let last_read_half = self . readable_half;
932
-
933
- Ok ( match last_read_half {
934
- Half :: First => {
935
- if second_half_is_done {
936
- self . payload. channel. ifcr( ) . write( |w| w. $ctcifX( ) . set_bit( ) ) ;
937
-
938
- self . readable_half = Half :: Second ;
939
- Half :: Second
940
- } else {
941
- last_read_half
942
- }
943
- }
944
- Half :: Second => {
945
- if first_half_is_done {
946
- self . payload. channel. ifcr( ) . write( |w| w. $chtifX( ) . set_bit( ) ) ;
947
-
948
- self . readable_half = Half :: First ;
949
- Half :: First
950
- } else {
951
- last_read_half
952
- }
929
+ let transfer_complete_flag = isr. $tcifX( ) . bit_is_set( ) ;
930
+ if transfer_complete_flag {
931
+ self . payload. channel. ifcr( ) . write( |w| w. $ctcifX( ) . set_bit( ) ) ;
932
+ }
933
+ let write_current = capacity - self . payload. channel. get_cndtr( ) as usize ;
934
+ // Copy the data before examining the overrun conditions. If the
935
+ // overrun happens shortly after the flags and write-index were read,
936
+ // we can not detect it anyways. So we can only hope that we have
937
+ // already read the word(s) that will be overwritten.
938
+ let available = if write_current >= self . read_index {
939
+ write_current - self . read_index
940
+ } else {
941
+ capacity + write_current - self . read_index
942
+ } ;
943
+ let read_len = core:: cmp:: min( available, buf. len( ) ) ;
944
+ if self . read_index + read_len <= capacity {
945
+ // non-wrapping read
946
+ buf[ ..read_len] . copy_from_slice( & self . buffer. as_ref( ) [ self . read_index..self . read_index+read_len] ) ;
947
+ } else {
948
+ // wrapping read
949
+ let first_read_len = capacity - self . read_index;
950
+ let second_read_len = read_len - first_read_len;
951
+ buf[ ..first_read_len] . copy_from_slice( & self . buffer. as_ref( ) [ self . read_index..] ) ;
952
+ buf[ first_read_len..read_len] . copy_from_slice( & self . buffer. as_ref( ) [ ..second_read_len] ) ;
953
+ }
954
+ // For checking the overrun conditions, it is important that we use the
955
+ // old read_index so do not increment it yet but check overrun
956
+ // conditions first.
957
+ // TODO When is the half-complete flag written exactly? Especially for
958
+ // odd buffer capacities.
959
+ let overrun = self . passed_mark( self . write_previous, write_current, self . read_index, capacity) || ( transfer_complete_flag && !self . passed_mark( self . write_previous, write_current, 0 , capacity) ) || ( half_complete_flag && !self . passed_mark( self . write_previous, write_current, capacity/2 , capacity) ) ;
960
+ self . write_previous = write_current;
961
+ if overrun {
962
+ self . read_index = write_current;
963
+ Err ( Error :: Overrun )
964
+ } else {
965
+ self . read_index += read_len;
966
+ if self . read_index >= capacity {
967
+ self . read_index -= capacity;
953
968
}
954
- } )
969
+ Ok ( read_len)
970
+ }
955
971
}
956
972
957
973
/// Stops the transfer and returns the underlying buffer and RxDma
958
- pub fn stop( mut self ) -> ( & ' static mut [ B ; 2 ] , RxDma <PAYLOAD , $CX>) {
974
+ pub fn stop( mut self ) -> ( & ' static mut B , RxDma <PAYLOAD , $CX>) {
959
975
self . payload. stop( ) ;
960
976
961
977
( self . buffer, self . payload)
@@ -1243,11 +1259,11 @@ pub trait ReceiveTransmit {
1243
1259
/// Trait for circular DMA readings from peripheral to memory.
1244
1260
pub trait CircReadDma < B , RS > : Receive
1245
1261
where
1246
- & ' static mut [ B ; 2 ] : StaticWriteBuffer < Word = RS > ,
1262
+ & ' static mut B : StaticWriteBuffer < Word = RS > ,
1247
1263
B : ' static ,
1248
1264
Self : core:: marker:: Sized ,
1249
1265
{
1250
- fn circ_read ( self , buffer : & ' static mut [ B ; 2 ] ) -> CircBuffer < B , Self > ;
1266
+ fn circ_read ( self , buffer : & ' static mut B ) -> CircBuffer < B , Self > ;
1251
1267
}
1252
1268
1253
1269
/// Trait for DMA readings from peripheral to memory.
0 commit comments