1- use pyo3:: prelude:: * ;
2- use pyo3:: exceptions:: PyRuntimeError ;
3- use pyo3:: types:: { PyDict , PyBytes } ;
41use :: twinleaf:: tio:: * ;
52use :: twinleaf:: * ;
3+ use pyo3:: exceptions:: PyRuntimeError ;
4+ use pyo3:: prelude:: * ;
5+ use pyo3:: types:: { PyBytes , PyDict } ;
66
77#[ pyclass( name = "DataIterator" , subclass) ]
88struct PyIter {
99 port : data:: Device ,
1010 n : Option < usize > ,
11+ stream : String ,
1112 columns : Vec < String > ,
1213}
1314
@@ -19,35 +20,58 @@ impl PyIter {
1920
2021 fn __next__ ( mut slf : PyRefMut < ' _ , Self > ) -> PyResult < Option < PyObject > > {
2122 let dict = PyDict :: new ( slf. py ( ) ) ;
22-
23+
2324 if let Some ( ctr) = slf. n {
2425 if ctr == 0 {
2526 // TODO: drop port
2627 return Ok ( None ) ;
2728 } else {
28- slf. n = Some ( ctr- 1 ) ;
29+ slf. n = Some ( ctr - 1 ) ;
2930 }
3031 }
3132
3233 while dict. is_empty ( ) {
34+ // Check for keyboard interrupt
35+ slf. py ( ) . check_signals ( ) ?;
36+
3337 let sample = slf. port . next ( ) ;
38+
39+ if !slf. stream . is_empty ( ) && slf. stream != sample. stream . name {
40+ continue ;
41+ }
3442
35- for column in & sample. columns {
36- let name = column. desc . name . clone ( ) . into_pyobject ( slf. py ( ) ) ?;
37- let name_str: String = name. extract ( ) ?;
38- if slf. columns . is_empty ( ) || slf. columns . contains ( & name_str) {
43+ for sample_column in & sample. columns {
44+ let sample_column_name = sample_column. desc . name . clone ( ) ;
45+ let mut column_matches = slf. columns . is_empty ( ) || slf. columns . iter ( ) . any ( |c| {
46+ if c. ends_with ( "*" ) {
47+ // Remove * and check if sample_column_name starts with prefix
48+ let prefix = & c[ ..c. len ( ) -1 ] ;
49+ sample_column_name. starts_with ( prefix)
50+ } else {
51+ c. eq ( & sample_column_name)
52+ }
53+ } ) ;
54+ if column_matches {
3955 let time = sample. timestamp_end ( ) . into_pyobject ( slf. py ( ) ) ?;
56+ let stream_id = sample. stream . stream_id . into_pyobject ( slf. py ( ) ) ?;
57+ dict. set_item ( "stream" , stream_id) ?;
4058 dict. set_item ( "time" , time) ?;
41- match column. value {
42- data:: ColumnData :: Int ( x) => { dict. set_item ( name, x. into_pyobject ( slf. py ( ) ) ?) ?}
43- data:: ColumnData :: UInt ( x) => { dict. set_item ( name, x. into_pyobject ( slf. py ( ) ) ?) ?}
44- data:: ColumnData :: Float ( x) => { dict. set_item ( name, x. into_pyobject ( slf. py ( ) ) ?) ?}
45- _ => { dict. set_item ( name, "UNKNOWN" . into_pyobject ( slf. py ( ) ) ?) ? }
59+ match sample_column. value {
60+ data:: ColumnData :: Int ( x) => {
61+ dict. set_item ( sample_column_name. into_pyobject ( slf. py ( ) ) ?, x. into_pyobject ( slf. py ( ) ) ?) ?
62+ }
63+ data:: ColumnData :: UInt ( x) => {
64+ dict. set_item ( sample_column_name. into_pyobject ( slf. py ( ) ) ?, x. into_pyobject ( slf. py ( ) ) ?) ?
65+ }
66+ data:: ColumnData :: Float ( x) => {
67+ dict. set_item ( sample_column_name. into_pyobject ( slf. py ( ) ) ?, x. into_pyobject ( slf. py ( ) ) ?) ?
68+ }
69+ _ => dict. set_item ( sample_column_name. into_pyobject ( slf. py ( ) ) ?, "UNKNOWN" . into_pyobject ( slf. py ( ) ) ?) ?,
4670 } ;
4771 }
4872 }
4973 }
50-
74+
5175 Ok ( Some ( dict. into ( ) ) )
5276 }
5377}
@@ -76,19 +100,69 @@ impl PyDevice {
76100 } ;
77101 let proxy = proxy:: Interface :: new ( & root) ;
78102 let rpc = proxy. device_rpc ( route. clone ( ) ) . unwrap ( ) ;
79- Ok ( PyDevice { proxy, route, rpc} )
103+ Ok ( PyDevice { proxy, route, rpc } )
80104 }
81105
82- fn rpc < ' py > ( & self , py : Python < ' py > , name : & str , req : & [ u8 ] ) -> PyResult < Bound < ' py , PyBytes > > {
106+ fn _rpc < ' py > ( & self , py : Python < ' py > , name : & str , req : & [ u8 ] ) -> PyResult < Bound < ' py , PyBytes > > {
83107 match self . rpc . raw_rpc ( name, req) {
84- Ok ( ret) => Ok ( PyBytes :: new ( py, & ret[ ..] ) ) ,
85- _ => Err ( PyRuntimeError :: new_err ( "RPC failed" ) ) ,
108+ Ok ( ret) => Ok ( PyBytes :: new ( py, & ret[ ..] ) ) ,
109+ _ => Err ( PyRuntimeError :: new_err ( format ! ( "RPC '{}' failed" , name ) ) ) ,
86110 }
87111 }
88112
89- #[ pyo3( signature = ( n=1 , columns=None ) ) ]
90- fn samples < ' py > ( & self , _py : Python < ' py > , n : Option < usize > , columns : Option < Vec < String > > ) -> PyResult < PyIter > {
91- Ok ( PyIter { port : data:: Device :: new ( self . proxy . device_full ( self . route . clone ( ) ) . unwrap ( ) ) , n : n, columns : columns. unwrap_or_default ( ) } )
113+ #[ pyo3( signature = ( n=1 , stream=None , columns=None ) ) ]
114+ fn _samples < ' py > (
115+ & self ,
116+ _py : Python < ' py > ,
117+ n : Option < usize > ,
118+ stream : Option < String > ,
119+ columns : Option < Vec < String > > ,
120+ ) -> PyResult < PyIter > {
121+ Ok ( PyIter {
122+ port : data:: Device :: new ( self . proxy . device_full ( self . route . clone ( ) ) . unwrap ( ) ) ,
123+ n : n,
124+ stream : stream. unwrap_or_default ( ) ,
125+ columns : columns. unwrap_or_default ( ) ,
126+ } )
127+ }
128+
129+ fn _get_metadata < ' py > ( & self , py : Python < ' py > ) -> PyResult < PyObject > {
130+ let mut device = data:: Device :: new ( self . proxy . device_full ( self . route . clone ( ) ) . unwrap ( ) ) ;
131+ let meta = device. get_metadata ( ) ;
132+
133+ let dict = PyDict :: new ( py) ;
134+
135+ // Convert device metadata to dict
136+ let device_dict = PyDict :: new ( py) ;
137+ device_dict. set_item ( "serial_number" , meta. device . serial_number . to_string ( ) ) ?;
138+ device_dict. set_item ( "firmware_hash" , meta. device . firmware_hash . to_string ( ) ) ?;
139+ device_dict. set_item ( "session_id" , meta. device . session_id . to_string ( ) ) ?;
140+ device_dict. set_item ( "name" , meta. device . name . to_string ( ) ) ?;
141+ dict. set_item ( "device" , device_dict) ?;
142+
143+ // Convert streams to dict
144+ let streams_dict = PyDict :: new ( py) ;
145+ for ( id, stream) in meta. streams {
146+ let stream_dict = PyDict :: new ( py) ;
147+ stream_dict. set_item ( "stream_id" , stream. stream . stream_id . to_string ( ) ) ?;
148+ // stream_dict.set_item("name", stream.name.to_string())?;
149+
150+ let columns_dict = PyDict :: new ( py) ;
151+ for col in stream. columns {
152+ let col_dict = PyDict :: new ( py) ;
153+ col_dict. set_item ( "name" , col. name . to_string ( ) ) ?;
154+ col_dict. set_item ( "description" , col. description . to_string ( ) ) ?;
155+ col_dict. set_item ( "type" , format ! ( "{:?}" , col. data_type) ) ?;
156+ col_dict. set_item ( "units" , col. units . to_string ( ) ) ?;
157+
158+ columns_dict. set_item ( col. name . to_string ( ) , col_dict) ?;
159+ }
160+ stream_dict. set_item ( "columns" , columns_dict) ?;
161+ streams_dict. set_item ( stream. stream . name . to_string ( ) , stream_dict) ?;
162+ }
163+ dict. set_item ( "streams" , streams_dict) ?;
164+
165+ Ok ( dict. into ( ) )
92166 }
93167}
94168
@@ -100,4 +174,3 @@ fn _twinleaf(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
100174 m. add_class :: < PyDevice > ( ) ?;
101175 Ok ( ( ) )
102176}
103-
0 commit comments