Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Review the implementation of Core Set Config and Core Get Config #82

Merged
merged 1 commit into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5,927 changes: 2,382 additions & 3,545 deletions py/pica/pica/packets/uci.py

Large diffs are not rendered by default.

149 changes: 92 additions & 57 deletions src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use crate::MacAddress;
use crate::PicaCommand;

use std::collections::HashMap;
use std::iter::Extend;
use std::time::Duration;

use tokio::sync::mpsc;
Expand Down Expand Up @@ -77,15 +76,36 @@ pub const DEFAULT_CAPS_INFO: &[(CapTlvType, &[u8])] = &[
),
];

/// [UCI] 8.2 Device Configuration Parameters
pub struct DeviceConfig {
device_state: DeviceState,
// This config is used to enable/disable the low power mode.
// 0x00 = Disable low power mode
// 0x01 = Enable low power mode (default)
low_power_mode: bool,
}

// [UCI] 6.3.1 Setting the Configuration
// All device configuration parameters within the UWBS are set to
// default values at Table 44 [..].
impl Default for DeviceConfig {
fn default() -> Self {
DeviceConfig {
device_state: DeviceState::DeviceStateError,
low_power_mode: true,
}
}
}

pub struct Device {
pub handle: usize,
pub mac_address: MacAddress,
config: DeviceConfig,
/// [UCI] 5. UWBS Device State Machine
state: DeviceState,
sessions: HashMap<u32, Session>,
pub tx: mpsc::UnboundedSender<UciPacket>,
pica_tx: mpsc::Sender<PicaCommand>,
config: HashMap<DeviceConfigId, Vec<u8>>,
country_code: [u8; 2],

pub n_active_sessions: usize,
Expand All @@ -101,11 +121,11 @@ impl Device {
Device {
handle,
mac_address,
config: Default::default(),
state: DeviceState::DeviceStateError, // Will be overwitten
sessions: Default::default(),
tx,
pica_tx,
config: HashMap::new(),
country_code: Default::default(),
n_active_sessions: 0,
}
Expand Down Expand Up @@ -236,72 +256,87 @@ impl Device {
log::debug!("[{}] SetConfig", self.handle);
assert_eq!(self.state, DeviceState::DeviceStateReady); // UCI 6.3

let (valid_parameters, invalid_config_status) = cmd.get_tlvs().iter().fold(
(HashMap::new(), Vec::new()),
|(mut valid_parameters, invalid_config_status), param| {
// TODO: DeviceState is a read only parameter
valid_parameters.insert(param.cfg_id, param.v.clone());

(valid_parameters, invalid_config_status)
},
);

let (status, parameters) = if invalid_config_status.is_empty() {
self.config.extend(valid_parameters);
(uci::Status::Ok, Vec::new())
} else {
(uci::Status::InvalidParam, invalid_config_status)
};
// [UCI] 6.3.1 Setting the Configuration
// The UWBS shall respond with CORE_SET_CONFIG_RSP setting the Status
// field of STATUS_INVALID_PARAM and including one or more invalid
// Parameter ID(s) If the Host tries to set a parameter that is not
// available in the UWBS. All other configuration parameters should
// have been set to the new values within the UWBS.
let mut invalid_parameters = vec![];
for parameter in cmd.get_parameters() {
match parameter.id {
uci::ConfigParameterId::DeviceState => {
invalid_parameters.push(uci::ConfigParameterStatus {
id: parameter.id,
status: uci::Status::ReadOnly,
})
}
uci::ConfigParameterId::LowPowerMode => {
self.config.low_power_mode = parameter.value.first().copied().unwrap_or(1) != 0;
}
uci::ConfigParameterId::Rfu(id) => {
log::warn!("unknown config parameter id 0x{:02x}", *id);
invalid_parameters.push(uci::ConfigParameterStatus {
id: parameter.id,
status: uci::Status::InvalidParam,
})
}
}
}

CoreSetConfigRspBuilder {
cfg_status: parameters,
status,
status: if invalid_parameters.is_empty() {
uci::Status::Ok
} else {
uci::Status::InvalidParam
},
parameters: invalid_parameters,
SilverBzH marked this conversation as resolved.
Show resolved Hide resolved
}
.build()
}

pub fn core_get_config(&self, cmd: CoreGetConfigCmd) -> CoreGetConfigRsp {
log::debug!("[{}] GetConfig", self.handle);

// TODO: do this config shall be set on device reset
let ids = cmd.get_cfg_id();
let (valid_parameters, invalid_parameters) = ids.iter().fold(
(Vec::new(), Vec::new()),
|(mut valid_parameters, mut invalid_parameters), id| {
// UCI Core Section 6.3.2 Table 8
// UCI Core Section 6.3.2 - Return the Configuration
// If the status code is ok, return the params
// If there is at least one invalid param, return the list of invalid params
// If the ID is not present in our config, return the Type with length = 0
match DeviceConfigId::try_from(*id) {
Ok(cfg_id) => match self.config.get(&cfg_id) {
Some(value) => valid_parameters.push(DeviceConfigTlv {
cfg_id,
v: value.clone(),
}),
None => invalid_parameters.push(DeviceConfigTlv {
cfg_id,
v: Vec::new(),
}),
},
Err(_) => log::error!("Failed to parse config id: {:?}", id),
}

(valid_parameters, invalid_parameters)
},
);
// [UCI] 6.3.2 Retrieve the Configuration
// If the Host tries to retrieve any Parameter(s) that are not available
// in the UWBS, the UWBS shall respond with a CORE_GET_CONFIG_RSP with
// a Status field of STATUS_INVALID_PARAM, containing each unavailable
// Device Configuration Parameter Type with Length field is zero. In
// this case, the CORE_GET_CONFIG_RSP shall not include any parameter(s)
// that are available in the UWBS.
let mut valid_parameters = vec![];
let mut invalid_parameters = vec![];
for id in cmd.get_parameter_ids() {
match id {
ConfigParameterId::DeviceState => valid_parameters.push(ConfigParameter {
id: *id,
value: vec![self.config.device_state.into()],
}),
ConfigParameterId::LowPowerMode => valid_parameters.push(ConfigParameter {
id: *id,
value: vec![self.config.low_power_mode.into()],
}),
ConfigParameterId::Rfu(_) => invalid_parameters.push(ConfigParameter {
id: *id,
value: vec![],
}),
}
}

let (status, parameters) = if invalid_parameters.is_empty() {
(uci::Status::Ok, valid_parameters)
if invalid_parameters.is_empty() {
CoreGetConfigRspBuilder {
status: uci::Status::Ok,
parameters: valid_parameters,
}
.build()
} else {
(uci::Status::InvalidParam, invalid_parameters)
};

CoreGetConfigRspBuilder {
status,
tlvs: parameters,
CoreGetConfigRspBuilder {
status: uci::Status::InvalidParam,
parameters: invalid_parameters,
}
.build()
}
.build()
}

fn session_init(&mut self, cmd: SessionInitCmd) -> SessionInitRsp {
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ impl Pica {
data_sequence_number: 0x01,
pbf: PacketBoundaryFlag::Complete,
session_handle: session_id,
source_address: device.mac_address.into(),
source_address: session.app_config.device_mac_address.unwrap().into(),
status: uci::Status::Ok,
}
.build()
Expand Down
14 changes: 10 additions & 4 deletions src/mac_address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,21 @@ impl MacAddress {
}
}

impl From<MacAddress> for u64 {
fn from(mac_address: MacAddress) -> Self {
impl From<&MacAddress> for u64 {
fn from(mac_address: &MacAddress) -> Self {
match mac_address {
MacAddress::Short(addr) => u16::from_le_bytes(addr) as u64,
MacAddress::Extended(addr) => u64::from_le_bytes(addr),
MacAddress::Short(addr) => u16::from_le_bytes(*addr) as u64,
MacAddress::Extended(addr) => u64::from_le_bytes(*addr),
}
}
}

impl From<MacAddress> for u64 {
fn from(mac_address: MacAddress) -> Self {
u64::from(&mac_address)
}
}

impl From<&MacAddress> for Vec<u8> {
fn from(mac_address: &MacAddress) -> Self {
match mac_address {
Expand Down
40 changes: 21 additions & 19 deletions src/uci_packets.pdl
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,6 @@ enum ResetConfig : 8 {
UWBS_RESET = 0x00,
}

enum DeviceConfigId : 8 {
DEVICE_STATE = 0x00,
LOW_POWER_MODE = 0x01,
}

// [UCI] Table 45: APP Configuration Parameters IDs
enum AppConfigTlvType : 8 {
DEVICE_TYPE = 0x00,
Expand Down Expand Up @@ -774,30 +769,37 @@ test CoreGetCapsInfoRsp {
"\x40\x03\x00\x05\x00\x00\x00\x00\x01\x00\x01\x01",
}

struct DeviceConfigTlv {
cfg_id: DeviceConfigId,
_count_(v): 8,
v: 8[],
// [UCI] Table 44: Device Configuration Parameters
enum ConfigParameterId : 8 {
DEVICE_STATE = 0x00,
LOW_POWER_MODE = 0x01,
RFU = ..,
}

struct ConfigParameter {
id: ConfigParameterId,
_size_(value): 8,
value: 8[],
}

packet CoreSetConfigCmd : CorePacket (mt = COMMAND, oid = SET_CONFIG) {
_count_(tlvs): 8,
tlvs: DeviceConfigTlv[],
_count_(parameters): 8,
parameters: ConfigParameter[],
}

test CoreSetConfigCmd {
"\x20\x04\x00\x03\x00\x00\x00\x01\x01\x00",
}

struct DeviceConfigStatus {
cfg_id: DeviceConfigId,
struct ConfigParameterStatus {
id: ConfigParameterId,
status: Status,
}

packet CoreSetConfigRsp : CorePacket (mt = RESPONSE, oid = SET_CONFIG) {
status: Status,
_count_(cfg_status): 8,
cfg_status: DeviceConfigStatus[],
_count_(parameters): 8,
parameters: ConfigParameterStatus[],
}

test CoreSetConfigRsp {
Expand All @@ -806,8 +808,8 @@ test CoreSetConfigRsp {
}

packet CoreGetConfigCmd : CorePacket (mt = COMMAND, oid = GET_CONFIG) {
_count_(cfg_id): 8,
cfg_id: 8[], // DeviceConfigId
_count_(parameter_ids): 8,
parameter_ids: ConfigParameterId[],
}

test CoreGetConfigCmd {
Expand All @@ -816,8 +818,8 @@ test CoreGetConfigCmd {

packet CoreGetConfigRsp : CorePacket (mt = RESPONSE, oid = GET_CONFIG) {
status: Status,
_count_(tlvs): 8,
tlvs: DeviceConfigTlv[]
_count_(parameters): 8,
parameters: ConfigParameter[]
}

test CoreGetConfigRsp {
Expand Down
Loading
Loading