Skip to content

Commit e23f7d9

Browse files
committed
request with reply
1 parent 67aa61a commit e23f7d9

File tree

6 files changed

+150
-114
lines changed

6 files changed

+150
-114
lines changed

src/cc253x.rs

+103-85
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ use crate::{
33
serial::{simple_serial_port::SimpleSerialPort, SubscriptionSerial},
44
subscription::{Predicate, Subscription, SubscriptionService},
55
unpi::{
6-
commands::{get_command_by_name, ParameterValue},
7-
LenTypeInfo, MessageType, Subsystem, UnpiPacket,
6+
commands::{get_command_by_name, ParameterValue, ParametersValueMap},
7+
LenTypeInfo, MessageType, SUnpiPacket, Subsystem,
88
},
9+
utils::warnn,
910
};
1011
use futures::{
1112
channel::oneshot::{self, Receiver, Sender},
@@ -16,11 +17,9 @@ use std::{path::PathBuf, sync::Arc};
1617
//TODO: fix this
1718
const MAXIMUM_ZIGBEE_PAYLOAD_SIZE: usize = 255;
1819

19-
type Container = Vec<u8>;
20-
2120
pub struct CC253X<S: SubscriptionSerial> {
2221
_supports_led: Option<bool>,
23-
subscriptions: Arc<Mutex<SubscriptionService<UnpiPacket<Container>>>>,
22+
subscriptions: Arc<Mutex<SubscriptionService<SUnpiPacket>>>,
2423
serial: Arc<Mutex<S>>,
2524
}
2625

@@ -43,25 +42,65 @@ impl CC253X<SimpleSerialPort> {
4342
}
4443
}
4544

45+
impl<S: SubscriptionSerial> CC253X<S> {
46+
pub async fn request(
47+
&self,
48+
name: &str,
49+
subsystem: Subsystem,
50+
parameters: &[(&'static str, ParameterValue)],
51+
) -> Result<(), CoordinatorError> {
52+
let command =
53+
get_command_by_name(&subsystem, name).ok_or(CoordinatorError::NoCommandWithName)?;
54+
let packet = SUnpiPacket::from_command_owned(
55+
LenTypeInfo::OneByte,
56+
(command.command_type, subsystem),
57+
parameters,
58+
command,
59+
)?;
60+
self.serial.lock().await.write(&packet).await?;
61+
Ok(())
62+
}
63+
64+
pub async fn request_with_reply(
65+
&self,
66+
name: &str,
67+
subsystem: Subsystem,
68+
parameters: &[(&'static str, ParameterValue)],
69+
) -> Result<ParametersValueMap, CoordinatorError> {
70+
let command =
71+
get_command_by_name(&subsystem, name).ok_or(CoordinatorError::NoCommandWithName)?;
72+
let packet = SUnpiPacket::from_command_owned(
73+
LenTypeInfo::OneByte,
74+
(command.command_type, subsystem),
75+
parameters,
76+
command,
77+
)?;
78+
let wait = self.wait_for("version", MessageType::SRESP, Subsystem::Sys, None);
79+
let send = async {
80+
let mut lock = self.serial.lock().await;
81+
lock.write(&packet).await
82+
};
83+
futures::try_join!(send, wait)
84+
.map(|(_, packet)| command.read_and_fill(packet.payload.as_slice()))?
85+
}
86+
}
87+
4688
impl<S: SubscriptionSerial> CC253X<S> {
4789
pub async fn wait_for(
4890
&self,
4991
name: &str,
5092
message_type: MessageType,
5193
subsystem: Subsystem,
5294
_timeout: Option<std::time::Duration>,
53-
) -> Result<UnpiPacket<Container>, CoordinatorError> {
95+
) -> Result<SUnpiPacket, CoordinatorError> {
5496
let command =
5597
get_command_by_name(&subsystem, name).ok_or(CoordinatorError::NoCommandWithName)?;
5698
let subscriptions = self.subscriptions.clone();
57-
let (tx, rx): (
58-
Sender<UnpiPacket<Container>>,
59-
Receiver<UnpiPacket<Container>>,
60-
) = oneshot::channel();
99+
let (tx, rx): (Sender<SUnpiPacket>, Receiver<SUnpiPacket>) = oneshot::channel();
61100
{
62101
let mut s = subscriptions.lock().await;
63102
let subscription = Subscription::SingleShot(
64-
Predicate(Box::new(move |packet: &UnpiPacket<Container>| {
103+
Predicate(Box::new(move |packet: &SUnpiPacket| {
65104
packet.type_subsystem == (message_type, subsystem)
66105
&& packet.command == command.id
67106
})),
@@ -70,8 +109,7 @@ impl<S: SubscriptionSerial> CC253X<S> {
70109
s.subscribe(subscription);
71110
}
72111

73-
let packet = rx.await.map_err(|_| CoordinatorError::SubscriptionError)?;
74-
Ok(packet)
112+
rx.await.map_err(|_| CoordinatorError::SubscriptionError)
75113
}
76114
}
77115

@@ -90,56 +128,29 @@ impl<S: SubscriptionSerial> Coordinator for CC253X<S> {
90128
todo!()
91129
}
92130

93-
async fn permit_join(
94-
&self,
95-
_address: u16,
96-
_duration: std::time::Duration,
97-
) -> Result<(), CoordinatorError> {
98-
todo!()
131+
async fn is_inter_pan_mode(&self) -> bool {
132+
warnn!("is_inter_pan_mode not implemented, assuming false");
133+
false
99134
}
100135

101136
async fn version(&self) -> Result<Option<ParameterValue>, CoordinatorError> {
102-
let command = get_command_by_name(&Subsystem::Sys, "version")
103-
.ok_or(CoordinatorError::NoCommandWithName)?;
104-
let serial = self.serial.clone();
105-
let wait = self.wait_for("version", MessageType::SRESP, Subsystem::Sys, None);
106-
let send = async {
107-
let packet = UnpiPacket::from_command_owned(
108-
LenTypeInfo::OneByte,
109-
(MessageType::SREQ, Subsystem::Sys),
110-
&[],
111-
command,
112-
)?;
113-
serial.lock().await.write(&packet).await?;
114-
Ok::<(), CoordinatorError>(())
115-
};
116-
let (_s, packet) = futures::try_join!(send, wait)?;
117-
let r = command.read_and_fill(packet.payload.as_slice())?;
118-
Ok(r.get(&"majorrel").cloned())
137+
let version = self
138+
.request_with_reply("version", Subsystem::Sys, &[])
139+
.await?;
140+
Ok(version.get(&"majorrel").cloned())
119141
}
120142

121143
async fn reset(&self, reset_type: ResetType) -> Result<(), CoordinatorError> {
122-
let command = get_command_by_name(&Subsystem::Sys, "reset_req")
123-
.ok_or(CoordinatorError::NoCommandWithName)?;
124144
let parameters = match reset_type {
125145
ResetType::Soft => &[("type", ParameterValue::U8(1))],
126146
ResetType::Hard => &[("type", ParameterValue::U8(0))],
127147
};
128-
129-
let serial = self.serial.clone();
130-
let packet = UnpiPacket::from_command_owned(
131-
LenTypeInfo::OneByte,
132-
(MessageType::SREQ, Subsystem::Sys),
133-
parameters,
134-
command,
135-
)?;
136-
serial.lock().await.write(&packet).await?;
148+
self.request("reset_req", Subsystem::Sys, parameters)
149+
.await?;
137150
Ok::<(), CoordinatorError>(())
138151
}
139152

140153
async fn set_led(&self, led_status: LedStatus) -> Result<(), CoordinatorError> {
141-
let command = get_command_by_name(&Subsystem::Util, "led_control")
142-
.ok_or(CoordinatorError::NoCommandWithName)?;
143154
//TODO: const firmwareControlsLed = parseInt(this.version.revision) >= 20211029;
144155
let firmware_controls_led = true;
145156

@@ -167,22 +178,15 @@ impl<S: SubscriptionSerial> Coordinator for CC253X<S> {
167178
],
168179
};
169180

170-
let serial = self.serial.clone();
171-
let packet = UnpiPacket::from_command_owned(
172-
LenTypeInfo::OneByte,
173-
(MessageType::SREQ, Subsystem::Util),
174-
parameters,
175-
command,
176-
)?;
177-
serial.lock().await.write(&packet).await?;
178-
Ok(())
181+
self.request("led_control", Subsystem::Util, parameters)
182+
.await
179183
}
180184

181185
async fn change_channel(&self, channel: u8) -> Result<(), CoordinatorError> {
182186
let parameters = &[
183-
("dst_addr", ParameterValue::U16(0xffff)),
187+
("destination_address", ParameterValue::U16(0xffff)),
184188
(
185-
"dst_addr_mode",
189+
"destination_address_mode",
186190
ParameterValue::U16(AddressMode::AddrBroadcast as u16),
187191
),
188192
(
@@ -196,22 +200,15 @@ impl<S: SubscriptionSerial> Coordinator for CC253X<S> {
196200
),
197201
("scan_duration", ParameterValue::U8(0xfe)),
198202
("scan_count", ParameterValue::U8(0)),
199-
("nwk_manager_addr", ParameterValue::U16(0)),
203+
("network_manager_address", ParameterValue::U16(0)),
200204
];
201205

202-
let command = get_command_by_name(&Subsystem::Zdo, "management_network_update_request")
203-
.ok_or(CoordinatorError::NoCommandWithName)?;
204-
205-
let serial = self.serial.clone();
206-
let packet = UnpiPacket::from_command_owned(
207-
LenTypeInfo::OneByte,
208-
(MessageType::SREQ, Subsystem::Zdo),
206+
self.request(
207+
"management_network_update_request",
208+
Subsystem::Zdo,
209209
parameters,
210-
command,
211-
)?;
212-
serial.lock().await.write(&packet).await?;
213-
214-
Ok(())
210+
)
211+
.await
215212
}
216213

217214
async fn set_transmit_power(&self, power: i8) -> Result<(), CoordinatorError> {
@@ -220,18 +217,7 @@ impl<S: SubscriptionSerial> Coordinator for CC253X<S> {
220217
("value", ParameterValue::I8(power)),
221218
];
222219

223-
let command = get_command_by_name(&Subsystem::Zdo, "stack_tune")
224-
.ok_or(CoordinatorError::NoCommandWithName)?;
225-
226-
let serial = self.serial.clone();
227-
let packet = UnpiPacket::from_command_owned(
228-
LenTypeInfo::OneByte,
229-
(MessageType::SREQ, Subsystem::Zdo),
230-
parameters,
231-
command,
232-
)?;
233-
serial.lock().await.write(&packet).await?;
234-
Ok(())
220+
self.request("stack_tune", Subsystem::Zdo, parameters).await
235221
}
236222

237223
async fn request_network_address(_addr: &str) -> Result<(), CoordinatorError> {
@@ -251,4 +237,36 @@ impl<S: SubscriptionSerial> Coordinator for CC253X<S> {
251237
) -> Result<Option<Self::ZclPayload<'static>>, CoordinatorError> {
252238
Ok(None)
253239
}
240+
241+
async fn permit_join(
242+
&self,
243+
seconds: std::time::Duration,
244+
network_address: Option<u16>,
245+
) -> Result<(), CoordinatorError> {
246+
if self.is_inter_pan_mode().await {
247+
return Err(CoordinatorError::InterpanMode);
248+
}
249+
let address_mode =
250+
network_address.map_or(AddressMode::AddrBroadcast, |_| AddressMode::Addr16bit);
251+
let destination_address = network_address.unwrap_or(0xfffc);
252+
let parameters = &[
253+
("address_mode", ParameterValue::U16(address_mode as u16)),
254+
(
255+
"destination_address",
256+
ParameterValue::U16(destination_address),
257+
),
258+
(
259+
"duration",
260+
ParameterValue::U8(
261+
seconds
262+
.as_secs()
263+
.try_into()
264+
.map_err(|_| CoordinatorError::DurationTooLong)?,
265+
),
266+
),
267+
("tc_significance", ParameterValue::U8(0)),
268+
];
269+
self.request("management_permit_join_request", Subsystem::Zdo, parameters)
270+
.await
271+
}
254272
}

src/coordinator.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use crate::{unpi::commands::{ParameterError, ParameterValue}, utils::map::MapError};
1+
use crate::{
2+
unpi::commands::{ParameterError, ParameterValue},
3+
utils::map::MapError,
4+
};
25
use std::future::Future;
36

47
pub trait Coordinator {
@@ -11,9 +14,10 @@ pub trait Coordinator {
1114
fn version(&self) -> impl Future<Output = Result<Option<ParameterValue>, CoordinatorError>>;
1215
fn permit_join(
1316
&self,
14-
address: u16,
1517
duration: std::time::Duration,
18+
address: Option<u16>,
1619
) -> impl Future<Output = Result<(), CoordinatorError>>;
20+
fn is_inter_pan_mode(&self) -> impl Future<Output = bool>;
1721
fn reset(&self, reset_type: ResetType) -> impl Future<Output = Result<(), CoordinatorError>>;
1822
fn set_led(&self, led_status: LedStatus) -> impl Future<Output = Result<(), CoordinatorError>>;
1923
fn change_channel(&self, channel: u8) -> impl Future<Output = Result<(), CoordinatorError>>;
@@ -68,7 +72,9 @@ pub enum CoordinatorError {
6872
NoRequest,
6973
NoResponse,
7074
SerialChannelMissing,
71-
SubscriptionError
75+
SubscriptionError,
76+
InterpanMode,
77+
DurationTooLong,
7278
}
7379

7480
impl From<std::io::Error> for CoordinatorError {

src/serial/simple_serial_port.rs

+6-11
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::{SerialThreadError, SubscriptionSerial};
22
use crate::{
33
coordinator::CoordinatorError,
44
subscription::SubscriptionService,
5-
unpi::{LenTypeInfo, UnpiPacket},
5+
unpi::{LenTypeInfo, SUnpiPacket, UnpiPacket},
66
utils::log,
77
};
88
use futures::StreamExt;
@@ -13,29 +13,24 @@ use futures::{
1313
};
1414
use std::{sync::Arc, thread::JoinHandle};
1515

16-
type Container = Vec<u8>;
17-
1816
const DEFAULT_READ_TIMEOUT_MS: u64 = 10;
1917

2018
// Simplest possible serial port implementation
2119
pub struct SimpleSerialPort {
2220
path: String,
2321
baud_rate: u32,
2422
// from the coordinator to the serial port
25-
to_serial: (
26-
Option<Sender<UnpiPacket<Container>>>,
27-
Option<Receiver<UnpiPacket<Container>>>,
28-
),
23+
to_serial: (Option<Sender<SUnpiPacket>>, Option<Receiver<SUnpiPacket>>),
2924
read_thread: Option<JoinHandle<Result<(), SerialThreadError>>>,
3025
write_thread: Option<JoinHandle<Result<(), SerialThreadError>>>,
31-
subscription_service: Arc<Mutex<SubscriptionService<UnpiPacket<Container>>>>,
26+
subscription_service: Arc<Mutex<SubscriptionService<SUnpiPacket>>>,
3227
}
3328

3429
impl SimpleSerialPort {
3530
pub fn new(
3631
path: &str,
3732
baud_rate: u32,
38-
subscription_service: Arc<Mutex<SubscriptionService<UnpiPacket<Container>>>>,
33+
subscription_service: Arc<Mutex<SubscriptionService<SUnpiPacket>>>,
3934
) -> Result<Self, CoordinatorError> {
4035
let to_serial = mpsc::channel(10);
4136
let to_serial = (Some(to_serial.0), Some(to_serial.1));
@@ -51,8 +46,8 @@ impl SimpleSerialPort {
5146
}
5247

5348
impl SubscriptionSerial for SimpleSerialPort {
54-
type Sender = Sender<UnpiPacket<Container>>;
55-
type Receiver = Receiver<UnpiPacket<Container>>;
49+
type Sender = Sender<SUnpiPacket>;
50+
type Receiver = Receiver<SUnpiPacket>;
5651

5752
fn start(&mut self) -> Result<(), CoordinatorError> {
5853
let mut read = serialport::new(self.path.clone(), self.baud_rate)

src/unpi/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ pub struct UnpiPacket<T> {
2525
pub fcs: u8,
2626
}
2727

28+
pub type Container = Vec<u8>;
29+
/// Static UNPI packet type
30+
pub type SUnpiPacket = UnpiPacket<Container>;
31+
2832
impl<T: AsRef<[u8]>> std::fmt::Debug for UnpiPacket<T> {
2933
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3034
f.debug_struct("UnpiPacket")

0 commit comments

Comments
 (0)