#[cfg(any(
feature = "network-tcp",
feature = "serial-rtu",
feature = "serial-ascii"
))]
use mbus_client::services::coil::Coils;
#[cfg(any(
feature = "network-tcp",
feature = "serial-rtu",
feature = "serial-ascii"
))]
use mbus_core::transport::UnitIdOrSlaveAddr;
#[cfg(any(
feature = "network-tcp",
feature = "serial-rtu",
feature = "serial-ascii"
))]
use super::pool::MbusClientId;
#[cfg(feature = "network-tcp")]
use super::pool::with_tcp_client;
#[cfg(any(feature = "serial-rtu", feature = "serial-ascii"))]
use super::pool::with_serial_client_uniform;
#[cfg(any(
feature = "network-tcp",
feature = "serial-rtu",
feature = "serial-ascii"
))]
use crate::c::error::MbusStatusCode;
#[cfg(feature = "network-tcp")]
macro_rules! call_tcp {
($id:ident, $method:ident, $txn_id:ident, $unit_id:ident $(, $arg:ident)*) => {{
with_tcp_client($id, |inner| {
let uid = match UnitIdOrSlaveAddr::new($unit_id) {
Ok(u) => u,
Err(e) => return MbusStatusCode::from(e),
};
match inner.$method($txn_id, uid $(, $arg)*) {
Ok(()) => MbusStatusCode::MbusOk,
Err(e) => MbusStatusCode::from(e),
}
}).unwrap_or_else(|e| e)
}};
}
#[cfg(any(feature = "serial-rtu", feature = "serial-ascii"))]
macro_rules! call_serial {
($id:ident, $method:ident, $txn_id:ident, $unit_id:ident $(, $arg:ident)*) => {{
with_serial_client_uniform!($id, |inner| {
let uid = match UnitIdOrSlaveAddr::new($unit_id) {
Ok(u) => u,
Err(e) => return MbusStatusCode::from(e),
};
match inner.$method($txn_id, uid $(, $arg)*) {
Ok(()) => MbusStatusCode::MbusOk,
Err(e) => MbusStatusCode::from(e),
}
}).unwrap_or_else(|e| e)
}};
}
#[cfg(all(feature = "coils", feature = "network-tcp"))]
#[unsafe(no_mangle)]
pub extern "C" fn mbus_tcp_read_coils(
id: MbusClientId,
txn_id: u16,
unit_id: u8,
address: u16,
quantity: u16,
) -> MbusStatusCode {
call_tcp!(id, read_multiple_coils, txn_id, unit_id, address, quantity)
}
#[cfg(all(
feature = "coils",
any(feature = "serial-rtu", feature = "serial-ascii")
))]
#[unsafe(no_mangle)]
pub extern "C" fn mbus_serial_read_coils(
id: MbusClientId,
txn_id: u16,
unit_id: u8,
address: u16,
quantity: u16,
) -> MbusStatusCode {
call_serial!(id, read_multiple_coils, txn_id, unit_id, address, quantity)
}
#[cfg(all(feature = "coils", feature = "network-tcp"))]
#[unsafe(no_mangle)]
pub extern "C" fn mbus_tcp_read_single_coil(
id: MbusClientId,
txn_id: u16,
unit_id: u8,
address: u16,
) -> MbusStatusCode {
call_tcp!(id, read_single_coil, txn_id, unit_id, address)
}
#[cfg(all(
feature = "coils",
any(feature = "serial-rtu", feature = "serial-ascii")
))]
#[unsafe(no_mangle)]
pub extern "C" fn mbus_serial_read_single_coil(
id: MbusClientId,
txn_id: u16,
unit_id: u8,
address: u16,
) -> MbusStatusCode {
call_serial!(id, read_single_coil, txn_id, unit_id, address)
}
#[cfg(all(feature = "coils", feature = "network-tcp"))]
#[unsafe(no_mangle)]
pub extern "C" fn mbus_tcp_write_single_coil(
id: MbusClientId,
txn_id: u16,
unit_id: u8,
address: u16,
value: u8,
) -> MbusStatusCode {
with_tcp_client(id, |inner| {
let uid = match UnitIdOrSlaveAddr::new(unit_id) {
Ok(u) => u,
Err(e) => return MbusStatusCode::from(e),
};
match inner.write_single_coil(txn_id, uid, address, value != 0) {
Ok(()) => MbusStatusCode::MbusOk,
Err(e) => MbusStatusCode::from(e),
}
})
.unwrap_or_else(|e| e)
}
#[cfg(all(
feature = "coils",
any(feature = "serial-rtu", feature = "serial-ascii")
))]
#[unsafe(no_mangle)]
pub extern "C" fn mbus_serial_write_single_coil(
id: MbusClientId,
txn_id: u16,
unit_id: u8,
address: u16,
value: u8,
) -> MbusStatusCode {
with_serial_client_uniform!(id, |inner| {
let uid = match UnitIdOrSlaveAddr::new(unit_id) {
Ok(u) => u,
Err(e) => return MbusStatusCode::from(e),
};
match inner.write_single_coil(txn_id, uid, address, value != 0) {
Ok(()) => MbusStatusCode::MbusOk,
Err(e) => MbusStatusCode::from(e),
}
})
.unwrap_or_else(|e| e)
}
#[cfg(all(feature = "coils", feature = "network-tcp"))]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn mbus_tcp_write_multiple_coils(
id: MbusClientId,
txn_id: u16,
unit_id: u8,
address: u16,
values: *const u8,
quantity: u16,
) -> MbusStatusCode {
if values.is_null() {
return MbusStatusCode::MbusErrNullPointer;
}
with_tcp_client(id, |inner| {
let uid = match UnitIdOrSlaveAddr::new(unit_id) {
Ok(u) => u,
Err(e) => return MbusStatusCode::from(e),
};
let byte_count = quantity.div_ceil(8) as usize;
let value_slice = unsafe { core::slice::from_raw_parts(values, byte_count) };
let coils = match Coils::new(address, quantity) {
Ok(c) => c,
Err(e) => return MbusStatusCode::from(e),
};
let coils = match coils.with_values(value_slice, quantity) {
Ok(c) => c,
Err(e) => return MbusStatusCode::from(e),
};
match inner.write_multiple_coils(txn_id, uid, address, &coils) {
Ok(()) => MbusStatusCode::MbusOk,
Err(e) => MbusStatusCode::from(e),
}
})
.unwrap_or_else(|e| e)
}
#[cfg(all(
feature = "coils",
any(feature = "serial-rtu", feature = "serial-ascii")
))]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn mbus_serial_write_multiple_coils(
id: MbusClientId,
txn_id: u16,
unit_id: u8,
address: u16,
values: *const u8,
quantity: u16,
) -> MbusStatusCode {
if values.is_null() {
return MbusStatusCode::MbusErrNullPointer;
}
with_serial_client_uniform!(id, |inner| {
let uid = match UnitIdOrSlaveAddr::new(unit_id) {
Ok(u) => u,
Err(e) => return MbusStatusCode::from(e),
};
let byte_count = quantity.div_ceil(8) as usize;
let value_slice = unsafe { core::slice::from_raw_parts(values, byte_count) };
let coils = match Coils::new(address, quantity) {
Ok(c) => c,
Err(e) => return MbusStatusCode::from(e),
};
let coils = match coils.with_values(value_slice, quantity) {
Ok(c) => c,
Err(e) => return MbusStatusCode::from(e),
};
match inner.write_multiple_coils(txn_id, uid, address, &coils) {
Ok(()) => MbusStatusCode::MbusOk,
Err(e) => MbusStatusCode::from(e),
}
})
.unwrap_or_else(|e| e)
}