Skip to content

Commit f1ab66d

Browse files
committed
Implement separate namespace for settings and samples.
1 parent 7470a56 commit f1ab66d

7 files changed

Lines changed: 296 additions & 61 deletions

File tree

rust/src/lib.rs

Lines changed: 96 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
use pyo3::prelude::*;
2-
use pyo3::exceptions::PyRuntimeError;
3-
use pyo3::types::{PyDict, PyBytes};
41
use ::twinleaf::tio::*;
52
use ::twinleaf::*;
3+
use pyo3::exceptions::PyRuntimeError;
4+
use pyo3::prelude::*;
5+
use pyo3::types::{PyBytes, PyDict};
66

77
#[pyclass(name = "DataIterator", subclass)]
88
struct 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

Comments
 (0)