Skip to content

Commit 78c754f

Browse files
committed
types: Make QdlChan BufRead
The Read trait serves us well for the USB backend, but the serial backend doesn't provide incoming messages in packets. This becomes a problem when we're doing <read/> as the response and data can come in the same channel.read(). Switch the trait to BufRead, to allow the implementation to peek at the data and partially consume the channel. Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
1 parent 3024010 commit 78c754f

File tree

3 files changed

+102
-14
lines changed

3 files changed

+102
-14
lines changed

qdl/src/serial.rs

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,61 @@
22
// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
33
use anyhow::{Result, bail};
44
use serial2::{self, SerialPort};
5-
use std::io::{Read, Write};
5+
use std::io::{BufRead, Read, Write};
66

77
use crate::types::QdlReadWrite;
88

99
pub struct QdlSerialConfig {
1010
serport: SerialPort,
11+
buf: Vec<u8>,
12+
pos: usize,
13+
cap: usize,
1114
}
1215

1316
// TODO: timeouts?
1417
impl Write for QdlSerialConfig {
1518
fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
1619
self.serport.write(buf)
1720
}
18-
1921
fn flush(&mut self) -> Result<(), std::io::Error> {
2022
self.serport.flush()
2123
}
2224
}
2325

2426
impl Read for QdlSerialConfig {
25-
fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
26-
self.serport.read(buf)
27+
fn read(&mut self, out: &mut [u8]) -> Result<usize, std::io::Error> {
28+
// Drain internal buffer first
29+
if self.pos < self.cap {
30+
let n = std::cmp::min(out.len(), self.cap - self.pos);
31+
out[..n].copy_from_slice(&self.buf[self.pos..self.pos + n]);
32+
self.pos += n;
33+
return Ok(n);
34+
}
35+
// Otherwise, read directly from serial port
36+
self.serport.read(out)
37+
}
38+
}
39+
40+
impl BufRead for QdlSerialConfig {
41+
fn fill_buf(&mut self) -> Result<&[u8], std::io::Error> {
42+
if self.pos >= self.cap {
43+
self.pos = 0;
44+
self.cap = 0;
45+
if self.buf.is_empty() {
46+
self.buf.resize(4096, 0);
47+
}
48+
match self.serport.read(&mut self.buf) {
49+
Ok(n) => {
50+
self.cap = n;
51+
}
52+
Err(e) => return Err(e),
53+
}
54+
}
55+
Ok(&self.buf[self.pos..self.cap])
56+
}
57+
58+
fn consume(&mut self, amt: usize) {
59+
self.pos = std::cmp::min(self.pos + amt, self.cap);
2760
}
2861
}
2962

@@ -40,5 +73,10 @@ pub fn setup_serial_device(dev_path: Option<String>) -> Result<QdlSerialConfig>
4073
Ok(settings)
4174
})?;
4275

43-
Ok(QdlSerialConfig { serport })
76+
Ok(QdlSerialConfig {
77+
serport,
78+
buf: Vec::new(),
79+
pos: 0,
80+
cap: 0,
81+
})
4482
}

qdl/src/types.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
33
use std::{
44
fmt::Display,
5-
io::{ErrorKind, Read, Write},
5+
io::{BufRead, ErrorKind, Read, Write},
66
str::FromStr,
77
};
88

@@ -87,13 +87,12 @@ impl Default for FirehoseConfiguration {
8787
}
8888
}
8989
}
90-
91-
pub trait QdlChan: Read + Write {
90+
pub trait QdlChan: BufRead + Write {
9291
fn fh_config(&self) -> &FirehoseConfiguration;
9392
fn mut_fh_config(&mut self) -> &mut FirehoseConfiguration;
9493
}
9594

96-
pub trait QdlReadWrite: Read + Write + Send + Sync {}
95+
pub trait QdlReadWrite: BufRead + Write + Send + Sync {}
9796
impl<T> QdlReadWrite for &mut T where T: QdlReadWrite + ?Sized {}
9897

9998
pub struct QdlDevice<T>
@@ -127,6 +126,19 @@ where
127126
}
128127
}
129128

129+
impl<T> std::io::BufRead for QdlDevice<T>
130+
where
131+
T: QdlReadWrite + ?Sized,
132+
{
133+
fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
134+
self.rw.fill_buf()
135+
}
136+
137+
fn consume(&mut self, amt: usize) {
138+
self.rw.consume(amt);
139+
}
140+
}
141+
130142
impl<T> QdlChan for QdlDevice<T>
131143
where
132144
T: QdlReadWrite + ?Sized,

qdl/src/usb.rs

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use anyhow::{Context, Result, bail};
44
use rusb::{self, Device, DeviceHandle, GlobalContext};
55
use std::{
6-
io::{Error, ErrorKind, Read, Write},
6+
io::{BufRead, Error, ErrorKind, Read, Write},
77
time::Duration,
88
};
99

@@ -13,6 +13,9 @@ pub struct QdlUsbConfig {
1313
dev_handle: rusb::DeviceHandle<GlobalContext>,
1414
in_ep: u8,
1515
out_ep: u8,
16+
buf: Vec<u8>,
17+
pos: usize,
18+
cap: usize,
1619
}
1720

1821
// TODO: timeouts?
@@ -27,15 +30,48 @@ impl Write for QdlUsbConfig {
2730
Ok(())
2831
}
2932
}
30-
3133
impl Read for QdlUsbConfig {
32-
fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
34+
fn read(&mut self, out: &mut [u8]) -> Result<usize, std::io::Error> {
35+
// Drain internal buffer first
36+
if self.pos < self.cap {
37+
let n = std::cmp::min(out.len(), self.cap - self.pos);
38+
out[..n].copy_from_slice(&self.buf[self.pos..self.pos + n]);
39+
self.pos += n;
40+
return Ok(n);
41+
}
42+
// Otherwise, read directly from USB
3343
self.dev_handle
34-
.read_bulk(self.in_ep, buf, Duration::from_secs(10))
44+
.read_bulk(self.in_ep, out, Duration::from_secs(10))
3545
.map_err(rusb_err_xlate)
3646
}
3747
}
3848

49+
impl BufRead for QdlUsbConfig {
50+
fn fill_buf(&mut self) -> Result<&[u8], std::io::Error> {
51+
if self.pos >= self.cap {
52+
self.pos = 0;
53+
self.cap = 0;
54+
if self.buf.is_empty() {
55+
self.buf.resize(4096, 0);
56+
}
57+
match self
58+
.dev_handle
59+
.read_bulk(self.in_ep, &mut self.buf, Duration::from_secs(10))
60+
{
61+
Ok(n) => {
62+
self.cap = n;
63+
}
64+
Err(e) => return Err(rusb_err_xlate(e)),
65+
}
66+
}
67+
Ok(&self.buf[self.pos..self.cap])
68+
}
69+
70+
fn consume(&mut self, amt: usize) {
71+
self.pos = std::cmp::min(self.pos + amt, self.cap);
72+
}
73+
}
74+
3975
impl QdlReadWrite for QdlUsbConfig {}
4076

4177
const USB_VID_QCOM: u16 = 0x05c6;
@@ -122,11 +158,13 @@ pub fn setup_usb_device(serial_no: Option<String>) -> Result<QdlUsbConfig> {
122158
dev_handle
123159
.claim_interface(intf_desc.interface_number())
124160
.with_context(|| format!("Couldn't claim interface{}", intf_desc.interface_number()))?;
125-
126161
Ok(QdlUsbConfig {
127162
dev_handle,
128163
in_ep,
129164
out_ep,
165+
buf: Vec::new(),
166+
pos: 0,
167+
cap: 0,
130168
})
131169
}
132170

0 commit comments

Comments
 (0)