5个版本
0.0.12-alpha | 2024年5月3日 |
---|---|
0.0.11-alpha | 2024年4月15日 |
0.0.10-alpha | 2024年4月15日 |
0.0.9-alpha | 2024年4月10日 |
0.0.8-alpha | 2024年4月9日 |
#152 在 嵌入式开发
47 每月下载量
用于 dmx-rdm-ftdi
120KB
2.5K SLoC
dmx-rdm-rs
dmx-rdm-rs是一个Rust库,通过可互换的驱动器在RS485总线上进行DMX512(ANSI E1.11)和DMX-RDM(ANSI E1.20)通信。该库支持no-std以及no-alloc(无堆分配)功能,旨在支持嵌入式和操作系统平台。
请参阅ESTA发布的官方规范。
此库仍在开发中,尚未经过广泛的测试,API可能不是最终的。
用法
以下示例展示了使用dmx-rdm-ftdi驱动器的基本用法。这些示例是相互关联的。
控制器
use dmx_rdm::dmx_controller::{DmxController, DmxControllerConfig};
use dmx_rdm::unique_identifier::{PackageAddress, UniqueIdentifier};
use dmx_rdm::utils::run_full_discovery;
use dmx_rdm_ftdi::{FtdiDriver, FtdiDriverConfig};
fn main() {
let dmx_driver = FtdiDriver::new(FtdiDriverConfig::default()).unwrap();
let mut dmx_controller = DmxController::new(dmx_driver, &DmxControllerConfig::default());
let mut devices_found = vec![];
// Unmute all dmx responders.
dmx_controller
.rdm_disc_un_mute(PackageAddress::Broadcast)
.unwrap();
let mut uid_array = [UniqueIdentifier::new(1, 1).unwrap(); 512];
loop {
// Search for devices.
let amount_devices_found = run_full_discovery(&mut dmx_controller, &mut uid_array).unwrap();
// Add found devices to vector.
devices_found.extend_from_slice(&uid_array[..amount_devices_found]);
// Have all devices been found and muted?
if amount_devices_found != uid_array.len() {
break;
}
}
for device in devices_found {
match dmx_controller.rdm_set_identify(device, true) {
Ok(_) => println!("Activated identify for device_uid {device}"),
Err(error) => {
println!("Activating identify for device_uid {device} failed with {error}")
},
}
}
}
响应器
use dmx_rdm::command_class::RequestCommandClass;
use dmx_rdm::dmx_receiver::{
DmxReceiverContext, DmxResponderHandler, RdmResponder, RdmResponderConfig, RdmResult,
};
use dmx_rdm::rdm_data::RdmRequestData;
use dmx_rdm::types::{DataPack, NackReason};
use dmx_rdm::unique_identifier::UniqueIdentifier;
use dmx_rdm_ftdi::{FtdiDriver, FtdiDriverConfig};
struct RdmHandler {
identify: bool,
}
const PID_IDENTIFY_DEVICE: u16 = 0x1000;
impl RdmHandler {
fn handle_get_identify(&self) -> RdmResult {
RdmResult::Acknowledged(DataPack::from_slice(&[self.identify as u8]).unwrap())
}
fn handle_set_identify(&mut self, parameter_data: &[u8]) -> Result<RdmResult, std::fmt::Error> {
// Check if the parameter data has the correct size
if parameter_data.len() != 1 {
return Ok(RdmResult::NotAcknowledged(
NackReason::DataOutOfRange as u16,
));
}
// Convert identify flag to bool and set that in the state.
self.identify = parameter_data[0] != 0;
println!("Current identify is {}", self.identify);
// Acknowledge request with an empty response.
Ok(RdmResult::Acknowledged(DataPack::new()))
}
}
impl DmxResponderHandler for RdmHandler {
type Error = std::fmt::Error;
fn handle_rdm(
&mut self,
request: &RdmRequestData,
_: &mut DmxReceiverContext,
) -> Result<RdmResult, Self::Error> {
match request.parameter_id {
PID_IDENTIFY_DEVICE => match request.command_class {
RequestCommandClass::GetCommand => Ok(self.handle_get_identify()),
RequestCommandClass::SetCommand => {
self.handle_set_identify(&request.parameter_data)
},
_ => Ok(RdmResult::NotAcknowledged(
NackReason::UnsupportedCommandClass as u16,
)),
},
_ => Ok(RdmResult::NotAcknowledged(NackReason::UnknownPid as u16)),
}
}
}
fn main() {
let dmx_driver = FtdiDriver::new(FtdiDriverConfig::default()).unwrap();
// Create rdm_responder with space for 32 queued messages.
let mut dmx_responder = RdmResponder::<_, 32>::new(
dmx_driver,
RdmResponderConfig {
uid: UniqueIdentifier::new(0x7FF0, 1).unwrap(),
// Won't add PID_IDENTIFY_DEVICE since this is a required pid.
supported_pids: &[],
rdm_receiver_metadata: Default::default(),
},
);
let mut rdm_handler = RdmHandler { identify: false };
loop {
// poll for new packages using our handler
match dmx_responder.poll(&mut rdm_handler) {
Ok(_) => (),
Err(error) => println!("'{error}' during polling"),
}
}
}
缺点/问题
如果您有任何关于如何改进当前状态的想法,请贡献力量。
- 控制器目前会阻塞,直到收到请求的响应
- 将来可能会将其分离
- 目前必须由个人自己实现发现功能
- 我目前正在考虑在控制器上实现轮询系统
- 尚未支持子设备/代理设备
- SUPPORTED_PARAMETERS难以评估。
- 缺乏单元测试覆盖率
- 轮询,很多阻塞功能
- AckTimer难以处理
- 如果使用Enttec DMX Pro作为从设备,则必须支持它
- ola通过使用回调解决了这个问题,但这不是一个选项,因为我们不能使用线程
- 可能会尝试类似的方法,但我们将使用轮询而不是线程
- 这可能会使库的使用变得更加困难
- 由于大量使用heapless::Vec,因此存在大量的内存复制
- 为了支持no-alloc,存在一些奇特的堆类型
- 端到端测试很困难,而且大部分尚未进行
- 目前尚无适当的标准验证
- 有两种类型的设备,一种是需要计算机重复DMX包的设备(rp2040,ftdi),另一种是具有此功能内置的设备(enttec dmx pro)
- 目前对此没有任何处理,而是根据驱动器发送dmx函数的行为不同
许可证
根据您的选择,许可协议为Apache License,Version 2.0或MIT许可证。
除非您明确声明,否则根据Apache-2.0许可证定义的,您有意提交以包含在dmx-rdm-rs中的任何贡献,应如上所述双重许可,不附加任何额外条款或条件。
依赖关系
~2.5MB
~50K SLoC