Skip to content

Commit 69134d6

Browse files
committed
added Rust LIN support
1 parent 023ecc4 commit 69134d6

File tree

4 files changed

+275
-2
lines changed

4 files changed

+275
-2
lines changed

clients/jabi-rs/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod peripherals {
77
pub mod dac;
88
pub mod gpio;
99
pub mod i2c;
10+
pub mod lin;
1011
pub mod metadata;
1112
pub mod pwm;
1213
pub mod spi;
@@ -25,8 +26,10 @@ pub use crate::peripherals::can::CANState;
2526
pub use crate::peripherals::gpio::GPIODir;
2627
pub use crate::peripherals::gpio::GPIOPull;
2728
pub use crate::peripherals::i2c::I2CFreq;
29+
pub use crate::peripherals::lin::LINChecksum;
30+
pub use crate::peripherals::lin::LINMessage;
31+
pub use crate::peripherals::lin::LINMode;
32+
pub use crate::peripherals::lin::LINStatus;
2833
pub use crate::peripherals::metadata::InstID;
2934
pub use crate::peripherals::uart::UARTParity;
3035
pub use crate::peripherals::uart::UARTStop;
31-
32-
// TODO re-export other enums, structs
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
use crate::interfaces::InterfaceRequest;
2+
use crate::Error;
3+
use deku::{DekuContainerRead, DekuContainerWrite, DekuRead, DekuUpdate, DekuWrite};
4+
5+
pub enum LINMode {
6+
Commander = 0,
7+
Responder = 1,
8+
}
9+
10+
#[derive(Debug, Copy, Clone)]
11+
pub enum LINChecksum {
12+
Classic = 0,
13+
Enhanced = 1,
14+
Auto = 2,
15+
}
16+
17+
pub struct LINStatus {
18+
pub id: u8,
19+
pub success: bool,
20+
}
21+
22+
pub struct LINMessage {
23+
pub id: u8,
24+
pub checksum_type: LINChecksum,
25+
pub data: Vec<u8>,
26+
}
27+
28+
impl std::fmt::Display for LINStatus {
29+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30+
write!(f, "LINStatus(id={}, success={})", self.id, self.success)
31+
}
32+
}
33+
34+
impl LINMessage {
35+
pub fn new(id: u8, data: Vec<u8>, checksum_type: LINChecksum) -> Self {
36+
Self {
37+
id,
38+
checksum_type,
39+
data,
40+
}
41+
}
42+
}
43+
44+
impl std::fmt::Display for LINMessage {
45+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46+
write!(
47+
f,
48+
"LINMessage(id={:#x}, type={:?}, data={:?})",
49+
self.id, self.checksum_type, self.data
50+
)
51+
}
52+
}
53+
54+
const LIN_DATA_MAX_LEN: usize = 8;
55+
56+
enum Func {
57+
SetMode = 0,
58+
SetRate = 1,
59+
SetFilter = 2,
60+
Mode = 3,
61+
Status = 4,
62+
Write = 5,
63+
Read = 6,
64+
}
65+
66+
fn gen_req(f: Func, idx: usize, payload: Vec<u8>) -> Result<InterfaceRequest, Error> {
67+
let mut r = InterfaceRequest {
68+
periph_id: crate::InstID::LIN as u16,
69+
periph_idx: idx as u16,
70+
periph_fn: f as u16,
71+
payload_len: 0,
72+
payload: payload,
73+
};
74+
r.update().map_or(Err(Error::PacketFormat), |_| Ok(r))
75+
}
76+
77+
impl crate::Device {
78+
pub fn lin_set_mode(&self, idx: usize, mode: LINMode) -> Result<(), Error> {
79+
#[derive(DekuWrite)]
80+
#[deku(endian = "little")]
81+
struct SetModeRequest {
82+
mode: u8,
83+
}
84+
let req = SetModeRequest { mode: mode as u8 };
85+
let resp = self.send(&gen_req(Func::SetMode, idx, req.to_bytes().unwrap())?)?;
86+
if resp.len() == 0 {
87+
Ok(())
88+
} else {
89+
Err(Error::PacketFormat)
90+
}
91+
}
92+
93+
pub fn lin_set_rate(&self, idx: usize, bitrate: u32) -> Result<(), Error> {
94+
#[derive(DekuWrite)]
95+
#[deku(endian = "little")]
96+
struct SetRateRequest {
97+
bitrate: u32,
98+
}
99+
let req = SetRateRequest { bitrate };
100+
let resp = self.send(&gen_req(Func::SetRate, idx, req.to_bytes().unwrap())?)?;
101+
if resp.len() == 0 {
102+
Ok(())
103+
} else {
104+
Err(Error::PacketFormat)
105+
}
106+
}
107+
108+
pub fn lin_set_filter(
109+
&self,
110+
idx: usize,
111+
id: u8,
112+
len: usize,
113+
checksum_type: LINChecksum,
114+
) -> Result<(), Error> {
115+
#[derive(DekuWrite)]
116+
#[deku(endian = "little")]
117+
struct SetFilterRequest {
118+
id: u8,
119+
checksum_type: u8,
120+
data_len: u8,
121+
}
122+
if len > LIN_DATA_MAX_LEN {
123+
return Err(Error::InvalidArgs);
124+
}
125+
let req = SetFilterRequest {
126+
id,
127+
checksum_type: checksum_type as u8,
128+
data_len: len as u8,
129+
};
130+
let resp = self.send(&gen_req(Func::SetFilter, idx, req.to_bytes().unwrap())?)?;
131+
if resp.len() == 0 {
132+
Ok(())
133+
} else {
134+
Err(Error::PacketFormat)
135+
}
136+
}
137+
138+
pub fn lin_mode(&self, idx: usize) -> Result<LINMode, Error> {
139+
#[derive(DekuRead)]
140+
#[deku(endian = "little")]
141+
struct ModeResponse {
142+
id: u8,
143+
}
144+
let resp = self.send(&gen_req(Func::Mode, idx, vec![])?)?;
145+
match ModeResponse::from_bytes((&resp, 0)) {
146+
Ok(((s, _), ret)) if s.len() == 0 => Ok(match ret.id {
147+
0 => LINMode::Commander,
148+
1 => LINMode::Responder,
149+
_ => return Err(Error::PacketFormat),
150+
}),
151+
_ => Err(Error::PacketFormat),
152+
}
153+
}
154+
155+
pub fn lin_status(&self, idx: usize) -> Result<LINStatus, Error> {
156+
#[derive(DekuRead)]
157+
#[deku(endian = "little")]
158+
struct StatusResponse {
159+
id: u8,
160+
retcode: i16,
161+
}
162+
let resp = self.send(&gen_req(Func::Status, idx, vec![])?)?;
163+
match StatusResponse::from_bytes((&resp, 0)) {
164+
Ok(((s, _), ret)) if s.len() == 0 => Ok(LINStatus {
165+
id: ret.id,
166+
success: ret.retcode == 0,
167+
}),
168+
_ => Err(Error::PacketFormat),
169+
}
170+
}
171+
172+
pub fn lin_write(&self, idx: usize, msg: &LINMessage) -> Result<(), Error> {
173+
#[derive(DekuWrite)]
174+
#[deku(endian = "little")]
175+
struct WriteRequest<'a> {
176+
id: u8,
177+
checksum_type: u8,
178+
data: &'a [u8],
179+
}
180+
if msg.data.len() > LIN_DATA_MAX_LEN {
181+
return Err(Error::InvalidArgs);
182+
}
183+
let req = WriteRequest {
184+
id: msg.id,
185+
checksum_type: msg.checksum_type as u8,
186+
data: &msg.data,
187+
};
188+
let resp = self.send(&gen_req(Func::Write, idx, req.to_bytes().unwrap())?)?;
189+
if resp.len() == 0 {
190+
Ok(())
191+
} else {
192+
Err(Error::PacketFormat)
193+
}
194+
}
195+
196+
pub fn lin_read(&self, idx: usize, id: u8) -> Result<Option<LINMessage>, Error> {
197+
#[derive(DekuWrite)]
198+
#[deku(endian = "little")]
199+
struct ReadRequest {
200+
id: u8,
201+
}
202+
#[derive(DekuRead)]
203+
#[deku(endian = "little")]
204+
struct ReadResponse {
205+
_num_left: u16, // "simple" interface, remains unused
206+
id: u8,
207+
checksum_type: u8,
208+
// data[]
209+
}
210+
let req = ReadRequest { id };
211+
let resp = self.send(&gen_req(Func::Read, idx, req.to_bytes().unwrap())?)?;
212+
if resp.len() == 0 {
213+
Ok(None)
214+
} else {
215+
match ReadResponse::from_bytes((&resp, 0)) {
216+
Ok(((s, _), ret)) => Ok(Some(LINMessage {
217+
id: ret.id,
218+
checksum_type: match ret.checksum_type {
219+
0 => LINChecksum::Classic,
220+
1 => LINChecksum::Enhanced,
221+
_ => return Err(Error::PacketFormat),
222+
},
223+
data: s.to_vec(),
224+
})),
225+
_ => Err(Error::PacketFormat),
226+
}
227+
}
228+
}
229+
}

examples/jabi-rs/src/main.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,46 @@ fn test_device(d: &jabi::Device) -> Result<(), jabi::Error> {
3131
}
3232
println!();
3333

34+
// LIN
35+
for i in 0..d.num_inst(jabi::InstID::LIN)? {
36+
println!("\tDoing some transactions as commander at 19.2kbps on LIN {i}");
37+
d.lin_set_mode(i, jabi::LINMode::Commander)?;
38+
d.lin_set_rate(i, 19200)?;
39+
for j in 0..64 {
40+
d.lin_set_filter(i, j, 0, jabi::LINChecksum::Auto)?;
41+
}
42+
d.lin_write(
43+
i,
44+
&jabi::LINMessage::new(42, vec![69, 42], jabi::LINChecksum::Enhanced),
45+
)?;
46+
println!("\t Sent a message");
47+
if let Ok(Some(msg)) = d.lin_read(i, 16) {
48+
println!("\t Received {}", msg);
49+
} else {
50+
println!("\t Didn't receive a message from 16");
51+
}
52+
53+
println!("\tListening to messages as responder on LIN {i}");
54+
d.lin_set_mode(i, jabi::LINMode::Responder)?;
55+
d.lin_write(
56+
i,
57+
&jabi::LINMessage::new(16, vec![69, 42], jabi::LINChecksum::Enhanced),
58+
)?;
59+
println!("\t Queued a message on ID 16");
60+
std::thread::sleep(Duration::from_secs(1));
61+
let status = d.lin_status(i)?;
62+
if status.id == 16 && status.success {
63+
println!("\t Successfully sent message");
64+
} else {
65+
println!("\t Failed to send message");
66+
}
67+
println!("\t Printing received messages");
68+
while let Some(msg) = d.lin_read(i, 0xFF)? {
69+
println!("\t{msg}");
70+
}
71+
}
72+
println!();
73+
3474
// SPI
3575
for i in 0..d.num_inst(jabi::InstID::SPI)? {
3676
println!("\tSetting SPI {i} to 250kHz, MODE0, LSB first");

examples/pyjabi/main.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def testDevice(d):
5757
print("\t Printing received messages")
5858
while (msg := d.can_read(i)):
5959
print("\t", msg)
60+
print()
6061

6162
# SPI
6263
for i in range(d.num_inst(jabi.InstID.SPI)):

0 commit comments

Comments
 (0)