Skip to content

Commit 09e9811

Browse files
committed
RS-485 working
1 parent dff42d4 commit 09e9811

File tree

3 files changed

+111
-9
lines changed

3 files changed

+111
-9
lines changed

crates/bacnet-gateway/src/config.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,63 @@ pub struct MstpConfig {
138138
pub max_master: u8,
139139
/// Network number for this transport.
140140
pub network_number: u16,
141+
/// RS-485 direction control configuration (optional).
142+
/// If omitted, assumes the hardware handles direction automatically
143+
/// (USB RS-485 adapters, auto-direction transceivers).
144+
#[serde(default)]
145+
pub rs485: Option<Rs485Config>,
146+
}
147+
148+
/// RS-485 direction control configuration.
149+
#[derive(Debug, Clone, Deserialize)]
150+
#[serde(tag = "mode")]
151+
pub enum Rs485Config {
152+
/// Kernel RS-485 mode via TIOCSRS485 ioctl (Linux only).
153+
/// The kernel toggles the UART's RTS pin for direction control.
154+
/// Use when DE/RE is wired to the UART's RTS pin.
155+
#[serde(rename = "kernel-rts")]
156+
KernelRts {
157+
/// Invert RTS polarity (default: false).
158+
#[serde(default)]
159+
invert_rts: bool,
160+
/// Delay before send in microseconds (default: 0).
161+
#[serde(default)]
162+
delay_before_send_us: u32,
163+
/// Delay after send in microseconds (default: 0).
164+
#[serde(default)]
165+
delay_after_send_us: u32,
166+
},
167+
/// GPIO direction control via Linux GPIO character device.
168+
/// Toggles a GPIO pin for DE/RE control around each transmission.
169+
/// Use for RS-485 hats where DE/RE is wired to a GPIO pin.
170+
#[serde(rename = "gpio")]
171+
Gpio {
172+
/// GPIO chip device path (default: "/dev/gpiochip0").
173+
#[serde(default = "default_gpio_chip")]
174+
gpio_chip: String,
175+
/// GPIO line number for DE/RE control.
176+
gpio_line: u32,
177+
/// If true, GPIO HIGH enables transmitter (default: true).
178+
/// Most RS-485 transceivers (MAX485) use active-high DE.
179+
#[serde(default = "default_true")]
180+
active_high: bool,
181+
/// Post-TX delay in microseconds before switching to RX mode (default: 200).
182+
/// Covers the time for the last byte to leave the UART shift register.
183+
#[serde(default = "default_post_tx_delay")]
184+
post_tx_delay_us: u64,
185+
},
186+
}
187+
188+
fn default_gpio_chip() -> String {
189+
"/dev/gpiochip0".to_string()
190+
}
191+
192+
fn default_true() -> bool {
193+
true
194+
}
195+
196+
fn default_post_tx_delay() -> u64 {
197+
200
141198
}
142199

143200
fn default_baud_rate() -> u32 {

crates/bacnet-transport/src/mstp_serial.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,7 @@ impl TokioSerialPort {
107107
buf[2] = delay_after_send_us;
108108

109109
// TIOCSRS485 = 0x542F
110-
let ret =
111-
unsafe { libc::ioctl(stream.as_raw_fd(), 0x542F, buf.as_mut_ptr()) };
110+
let ret = unsafe { libc::ioctl(stream.as_raw_fd(), 0x542F, buf.as_mut_ptr()) };
112111
if ret < 0 {
113112
return Err(Error::Encoding(format!(
114113
"TIOCSRS485 ioctl failed: {}",
@@ -185,12 +184,7 @@ impl<S: SerialPort> GpioDirectionPort<S> {
185184
/// - `line`: GPIO line number for DE/RE control (e.g., 18).
186185
/// - `active_high`: If true, GPIO HIGH enables the transmitter (most
187186
/// common — MAX485 DE pin is active-high). If false, GPIO LOW enables TX.
188-
pub fn new(
189-
inner: S,
190-
gpio_chip: &str,
191-
line: u32,
192-
active_high: bool,
193-
) -> Result<Self, Error> {
187+
pub fn new(inner: S, gpio_chip: &str, line: u32, active_high: bool) -> Result<Self, Error> {
194188
Self::with_post_tx_delay(inner, gpio_chip, line, active_high, 0)
195189
}
196190

docs/gateway.md

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,32 @@ The gateway is configured via a TOML file (default: `gateway.toml`). The top-lev
148148
| `station_address` | `u8` | *(required)* | Station address (0--254). |
149149
| `max_master` | `u8` | `127` | Max master station address. |
150150
| `network_number` | `u16` | *(required)* | Network number for this transport. Must be 1--65534, unique. |
151+
| `rs485` | `Rs485Config?` | `None` | RS-485 direction control (see below). If omitted, assumes hardware auto-direction. |
152+
153+
### `[transports.mstp.rs485]` -- RS-485 Direction Control (optional)
154+
155+
Most USB RS-485 adapters handle direction switching automatically and need no configuration. For RS-485 hats or transceivers with manual DE/RE control, configure one of these modes:
156+
157+
**GPIO mode** -- for RS-485 hats with a GPIO direction pin (e.g., Seeed Studio RS-485 Shield):
158+
159+
```toml
160+
[transports.mstp.rs485]
161+
mode = "gpio"
162+
gpio_chip = "/dev/gpiochip0" # default
163+
gpio_line = 18 # GPIO pin number for DE/RE
164+
active_high = true # true = HIGH enables transmitter (default)
165+
post_tx_delay_us = 200 # microseconds after TX before switching to RX (default: 200)
166+
```
167+
168+
**Kernel RTS mode** -- for setups where DE/RE is wired to the UART's RTS pin:
169+
170+
```toml
171+
[transports.mstp.rs485]
172+
mode = "kernel-rts"
173+
invert_rts = false # true if DE is active-low (default: false)
174+
delay_before_send_us = 0 # microseconds delay before TX (default: 0)
175+
delay_after_send_us = 0 # microseconds delay after TX (default: 0)
176+
```
151177

152178
### `[bbmd]` -- BBMD Configuration
153179

@@ -1089,7 +1115,7 @@ bdt = [
10891115
]
10901116
```
10911117

1092-
### MS/TP on Linux
1118+
### MS/TP on Linux (USB RS-485 adapter)
10931119

10941120
```toml
10951121
[device]
@@ -1102,6 +1128,31 @@ baud_rate = 76800
11021128
station_address = 1
11031129
max_master = 127
11041130
network_number = 3
1131+
# No rs485 section needed — USB adapters handle direction automatically
1132+
1133+
[transports.bip]
1134+
broadcast = "192.168.1.255"
1135+
network_number = 1
1136+
```
1137+
1138+
### MS/TP on Raspberry Pi (RS-485 Hat with GPIO)
1139+
1140+
```toml
1141+
[device]
1142+
instance = 70002
1143+
name = "Pi MS/TP Gateway"
1144+
1145+
[transports.mstp]
1146+
serial_port = "/dev/ttyS0"
1147+
baud_rate = 76800
1148+
station_address = 1
1149+
max_master = 127
1150+
network_number = 3
1151+
1152+
# Seeed Studio RS-485 Shield: DE/RE on GPIO18
1153+
[transports.mstp.rs485]
1154+
mode = "gpio"
1155+
gpio_line = 18
11051156

11061157
[transports.bip]
11071158
broadcast = "192.168.1.255"

0 commit comments

Comments
 (0)