diff --git a/chirpstack/migrations_postgres/2025-01-13-152218_refactor_device_profile_fields/down.sql b/chirpstack/migrations_postgres/2025-01-13-152218_refactor_device_profile_fields/down.sql index f8856929..6fb1ac0f 100644 --- a/chirpstack/migrations_postgres/2025-01-13-152218_refactor_device_profile_fields/down.sql +++ b/chirpstack/migrations_postgres/2025-01-13-152218_refactor_device_profile_fields/down.sql @@ -2,7 +2,11 @@ alter table device_profile add column abp_rx1_delay smallint not null default 0, add column abp_rx1_dr_offset smallint not null default 0, add column abp_rx2_dr smallint not null default 0, - add column abp_rx2_freq bigint not null default 0; + add column abp_rx2_freq bigint not null default 0, + add column class_b_timeout integer not null default 0, + add column class_b_ping_slot_nb_k integer not null default 0, + add column class_b_ping_slot_dr smallint not null default 0, + add column class_b_ping_slot_freq bigint not null default 0; update device_profile set @@ -13,6 +17,16 @@ update device_profile where abp_params is not null; -alter table device_profile - drop column abp_params; +update device_profile + set + class_b_timeout = (class_b_params->'timeout')::integer, + class_b_ping_slot_nb_k = (class_b_params->'ping_slot_nb_k')::integer, + class_b_ping_slot_dr = (class_b_params->'ping_slot_dr')::smallint, + class_b_ping_slot_freq = (class_b_params->'ping_slot_freq')::bigint + where + class_b_params is not null; + +alter table device_profile + drop column abp_params, + drop column class_b_params; diff --git a/chirpstack/migrations_postgres/2025-01-13-152218_refactor_device_profile_fields/up.sql b/chirpstack/migrations_postgres/2025-01-13-152218_refactor_device_profile_fields/up.sql index c5d2ae1b..9a8f477c 100644 --- a/chirpstack/migrations_postgres/2025-01-13-152218_refactor_device_profile_fields/up.sql +++ b/chirpstack/migrations_postgres/2025-01-13-152218_refactor_device_profile_fields/up.sql @@ -1,5 +1,6 @@ alter table device_profile - add column abp_params jsonb null; + add column abp_params jsonb null, + add column class_b_params jsonb null; update device_profile set abp_params = json_build_object( @@ -9,9 +10,21 @@ update device_profile 'rx2_freq', abp_rx2_freq) where supports_otaa = false; +update device_profile + set class_b_params = json_build_object( + 'timeout', class_b_timeout, + 'ping_slot_nb_k', class_b_ping_slot_nb_k, + 'ping_slot_dr', class_b_ping_slot_dr, + 'ping_slot_freq', class_b_ping_slot_freq) + where supports_class_b = false; + alter table device_profile drop column abp_rx1_delay, drop column abp_rx1_dr_offset, drop column abp_rx2_dr, - drop column abp_rx2_freq; + drop column abp_rx2_freq, + drop column class_b_timeout, + drop column class_b_ping_slot_nb_k, + drop column class_b_ping_slot_dr, + drop column class_b_ping_slot_freq; diff --git a/chirpstack/migrations_sqlite/2025-01-13-163304_refactor_device_profile_fields/down.sql b/chirpstack/migrations_sqlite/2025-01-13-163304_refactor_device_profile_fields/down.sql index 2d4ed06c..1b11d46d 100644 --- a/chirpstack/migrations_sqlite/2025-01-13-163304_refactor_device_profile_fields/down.sql +++ b/chirpstack/migrations_sqlite/2025-01-13-163304_refactor_device_profile_fields/down.sql @@ -2,6 +2,10 @@ alter table device_profile add column abp_rx1_delay smallint not null default 0; alter table device_profile add column abp_rx1_dr_offset smallint not null default 0; alter table device_profile add column abp_rx2_dr smallint not null default 0; alter table device_profile add column abp_rx2_freq bigint not null default 0; +alter table device_profile add column class_b_timeout integer not null default 0; +alter table device_profile add column class_b_ping_slot_nb_k integer not null default 0; +alter table device_profile add column class_b_ping_slot_dr smallint not null default 0; +alter table device_profile add column class_b_ping_slot_freq bigint not null default 0; update device_profile set @@ -12,5 +16,15 @@ update device_profile where abp_params is not null; -alter table device_profile drop column abp_params; +update device_profile + set + class_b_timeout = class_b_params->'timeout', + class_b_ping_slot_nb_k = class_b_params->'ping_slot_nb_k', + class_b_ping_slot_dr = class_b_params->'ping_slot_dr', + class_b_ping_slot_freq = class_b_params->'ping_slot_freq' + where + class_b_params is not null; + +alter table device_profile drop column abp_params; +alter table device_profile drop column class_b_params; diff --git a/chirpstack/migrations_sqlite/2025-01-13-163304_refactor_device_profile_fields/up.sql b/chirpstack/migrations_sqlite/2025-01-13-163304_refactor_device_profile_fields/up.sql index b3aceafc..fcf92d9c 100644 --- a/chirpstack/migrations_sqlite/2025-01-13-163304_refactor_device_profile_fields/up.sql +++ b/chirpstack/migrations_sqlite/2025-01-13-163304_refactor_device_profile_fields/up.sql @@ -1,5 +1,5 @@ -alter table device_profile - add column abp_params text null; +alter table device_profile add column abp_params text null; +alter table device_profile add column class_b_params text null; update device_profile set abp_params = json_object( @@ -9,8 +9,21 @@ update device_profile 'rx2_freq', abp_rx2_freq) where supports_otaa = false; +update device_profile + set class_b_params = json_object( + 'timeout', class_b_timeout, + 'ping_slot_nb_k', class_b_ping_slot_nb_k, + 'ping_slot_dr', class_b_ping_slot_dr, + 'ping_slot_freq', class_b_ping_slot_freq) + where supports_class_b = false; + alter table device_profile drop column abp_rx1_delay; alter table device_profile drop column abp_rx1_dr_offset; alter table device_profile drop column abp_rx2_dr; alter table device_profile drop column abp_rx2_freq; +alter table device_profile drop column class_b_timeout; +alter table device_profile drop column class_b_ping_slot_nb_k; +alter table device_profile drop column class_b_ping_slot_dr; +alter table device_profile drop column class_b_ping_slot_freq; + diff --git a/chirpstack/src/api/device_profile.rs b/chirpstack/src/api/device_profile.rs index 42f802f5..9d68eeaf 100644 --- a/chirpstack/src/api/device_profile.rs +++ b/chirpstack/src/api/device_profile.rs @@ -60,10 +60,6 @@ impl DeviceProfileService for DeviceProfile { supports_otaa: req_dp.supports_otaa, supports_class_b: req_dp.supports_class_b, supports_class_c: req_dp.supports_class_c, - class_b_timeout: req_dp.class_b_timeout as i32, - class_b_ping_slot_nb_k: req_dp.class_b_ping_slot_nb_k as i32, - class_b_ping_slot_dr: req_dp.class_b_ping_slot_dr as i16, - class_b_ping_slot_freq: req_dp.class_b_ping_slot_freq as i64, class_c_timeout: req_dp.class_c_timeout as i32, tags: fields::KeyValue::new(req_dp.tags.clone()), measurements: fields::Measurements::new( @@ -120,6 +116,16 @@ impl DeviceProfileService for DeviceProfile { rx2_freq: req_dp.abp_rx2_freq as u32, }) }, + class_b_params: if req_dp.supports_class_b { + Some(fields::ClassBParams { + timeout: req_dp.class_b_timeout as u16, + ping_slot_nb_k: req_dp.class_b_ping_slot_nb_k as u8, + ping_slot_dr: req_dp.class_b_ping_slot_dr as u8, + ping_slot_freq: req_dp.class_b_ping_slot_freq as u32, + }) + } else { + None + }, ..Default::default() }; @@ -152,6 +158,7 @@ impl DeviceProfileService for DeviceProfile { let dp = device_profile::get(&dp_id).await.map_err(|e| e.status())?; let abp_params = dp.abp_params.clone().unwrap_or_default(); + let class_b_params = dp.class_b_params.clone().unwrap_or_default(); let mut resp = Response::new(api::GetDeviceProfileResponse { device_profile: Some(api::DeviceProfile { @@ -171,10 +178,10 @@ impl DeviceProfileService for DeviceProfile { supports_otaa: dp.supports_otaa, supports_class_b: dp.supports_class_b, supports_class_c: dp.supports_class_c, - class_b_timeout: dp.class_b_timeout as u32, - class_b_ping_slot_nb_k: dp.class_b_ping_slot_nb_k as u32, - class_b_ping_slot_dr: dp.class_b_ping_slot_dr as u32, - class_b_ping_slot_freq: dp.class_b_ping_slot_freq as u32, + class_b_timeout: class_b_params.timeout as u32, + class_b_ping_slot_nb_k: class_b_params.ping_slot_nb_k as u32, + class_b_ping_slot_dr: class_b_params.ping_slot_dr as u32, + class_b_ping_slot_freq: class_b_params.ping_slot_freq as u32, class_c_timeout: dp.class_c_timeout as u32, abp_rx1_delay: abp_params.rx1_delay as u32, abp_rx1_dr_offset: abp_params.rx1_dr_offset as u32, @@ -269,10 +276,6 @@ impl DeviceProfileService for DeviceProfile { supports_otaa: req_dp.supports_otaa, supports_class_b: req_dp.supports_class_b, supports_class_c: req_dp.supports_class_c, - class_b_timeout: req_dp.class_b_timeout as i32, - class_b_ping_slot_nb_k: req_dp.class_b_ping_slot_nb_k as i32, - class_b_ping_slot_dr: req_dp.class_b_ping_slot_dr as i16, - class_b_ping_slot_freq: req_dp.class_b_ping_slot_freq as i64, class_c_timeout: req_dp.class_c_timeout as i32, tags: fields::KeyValue::new(req_dp.tags.clone()), measurements: fields::Measurements::new( @@ -329,6 +332,16 @@ impl DeviceProfileService for DeviceProfile { rx2_freq: req_dp.abp_rx2_freq as u32, }) }, + class_b_params: if req_dp.supports_class_b { + Some(fields::ClassBParams { + timeout: req_dp.class_b_timeout as u16, + ping_slot_nb_k: req_dp.class_b_ping_slot_nb_k as u8, + ping_slot_dr: req_dp.class_b_ping_slot_dr as u8, + ping_slot_freq: req_dp.class_b_ping_slot_freq as u32, + }) + } else { + None + }, ..Default::default() }) .await diff --git a/chirpstack/src/maccommand/reset.rs b/chirpstack/src/maccommand/reset.rs index c2f62783..c1548cdc 100644 --- a/chirpstack/src/maccommand/reset.rs +++ b/chirpstack/src/maccommand/reset.rs @@ -1,7 +1,7 @@ use anyhow::Result; use tracing::info; -use crate::storage::{device, device_profile, fields}; +use crate::storage::{device, device_profile}; const SERV_LORAWAN_VERSION: lrwn::Version = lrwn::Version::LoRaWAN1_1; @@ -42,6 +42,7 @@ pub fn handle( #[cfg(test)] pub mod test { use super::*; + use crate::storage::fields; use chirpstack_api::internal; use std::collections::HashMap; @@ -70,15 +71,18 @@ pub mod test { }; let dp = device_profile::DeviceProfile { supports_otaa: false, - class_b_ping_slot_dr: 2, - class_b_ping_slot_freq: 868100000, - class_b_ping_slot_nb_k: 1, abp_params: Some(fields::AbpParams { rx1_delay: 1, rx1_dr_offset: 0, rx2_dr: 0, rx2_freq: 868300000, }), + class_b_params: Some(fields::ClassBParams { + ping_slot_dr: 2, + ping_slot_freq: 868100000, + ping_slot_nb_k: 1, + timeout: 0, + }), ..Default::default() }; diff --git a/chirpstack/src/storage/device_profile.rs b/chirpstack/src/storage/device_profile.rs index 4c5ddb0c..0bf0b80d 100644 --- a/chirpstack/src/storage/device_profile.rs +++ b/chirpstack/src/storage/device_profile.rs @@ -34,10 +34,6 @@ pub struct DeviceProfile { pub supports_otaa: bool, pub supports_class_b: bool, pub supports_class_c: bool, - pub class_b_timeout: i32, - pub class_b_ping_slot_nb_k: i32, - pub class_b_ping_slot_dr: i16, - pub class_b_ping_slot_freq: i64, pub class_c_timeout: i32, pub tags: fields::KeyValue, pub payload_codec_script: String, @@ -71,6 +67,7 @@ pub struct DeviceProfile { pub allow_roaming: bool, pub rx1_delay: i16, pub abp_params: Option, + pub class_b_params: Option, } impl DeviceProfile { @@ -110,10 +107,6 @@ impl Default for DeviceProfile { supports_otaa: false, supports_class_b: false, supports_class_c: false, - class_b_timeout: 0, - class_b_ping_slot_nb_k: 0, - class_b_ping_slot_dr: 0, - class_b_ping_slot_freq: 0, class_c_timeout: 0, tags: fields::KeyValue::new(HashMap::new()), measurements: fields::Measurements::new(HashMap::new()), @@ -144,6 +137,7 @@ impl Default for DeviceProfile { allow_roaming: false, rx1_delay: 0, abp_params: None, + class_b_params: None, } } } @@ -151,11 +145,14 @@ impl Default for DeviceProfile { impl DeviceProfile { pub fn reset_session_to_boot_params(&self, ds: &mut internal::DeviceSession) { ds.mac_version = self.mac_version.to_proto().into(); - ds.class_b_ping_slot_dr = self.class_b_ping_slot_dr as u32; - ds.class_b_ping_slot_freq = self.class_b_ping_slot_freq as u32; - ds.class_b_ping_slot_nb = 1 << self.class_b_ping_slot_nb_k as u32; ds.nb_trans = 1; + if let Some(class_b_params) = &self.class_b_params { + ds.class_b_ping_slot_dr = class_b_params.ping_slot_dr as u32; + ds.class_b_ping_slot_freq = class_b_params.ping_slot_freq as u32; + ds.class_b_ping_slot_nb = 1 << class_b_params.ping_slot_nb_k as u32; + } + if self.is_relay_ed { ds.relay = Some(internal::Relay { ed_relay_only: self.relay_ed_relay_only, @@ -241,10 +238,6 @@ pub async fn update(dp: DeviceProfile) -> Result { device_profile::supports_otaa.eq(&dp.supports_otaa), device_profile::supports_class_b.eq(&dp.supports_class_b), device_profile::supports_class_c.eq(&dp.supports_class_c), - device_profile::class_b_timeout.eq(&dp.class_b_timeout), - device_profile::class_b_ping_slot_nb_k.eq(&dp.class_b_ping_slot_nb_k), - device_profile::class_b_ping_slot_dr.eq(&dp.class_b_ping_slot_dr), - device_profile::class_b_ping_slot_freq.eq(&dp.class_b_ping_slot_freq), device_profile::class_c_timeout.eq(&dp.class_c_timeout), device_profile::tags.eq(&dp.tags), device_profile::measurements.eq(&dp.measurements), @@ -281,6 +274,7 @@ pub async fn update(dp: DeviceProfile) -> Result { device_profile::allow_roaming.eq(&dp.allow_roaming), device_profile::rx1_delay.eq(&dp.rx1_delay), device_profile::abp_params.eq(&dp.abp_params), + device_profile::class_b_params.eq(&dp.class_b_params), )) .get_result(&mut get_async_db_conn().await?) .await diff --git a/chirpstack/src/storage/fields/device_profile.rs b/chirpstack/src/storage/fields/device_profile.rs index cc707468..2753e857 100644 --- a/chirpstack/src/storage/fields/device_profile.rs +++ b/chirpstack/src/storage/fields/device_profile.rs @@ -53,3 +53,51 @@ impl serialize::ToSql for AbpParams { Ok(serialize::IsNull::No) } } + +#[derive( + Default, Debug, Clone, PartialEq, Eq, Deserialize, Serialize, AsExpression, FromSqlRow, +)] +#[cfg_attr(feature = "postgres", diesel(sql_type = Jsonb))] +#[cfg_attr(feature = "sqlite", diesel(sql_type = Text))] +pub struct ClassBParams { + pub timeout: u16, + pub ping_slot_nb_k: u8, + pub ping_slot_dr: u8, + pub ping_slot_freq: u32, +} + +#[cfg(feature = "postgres")] +impl deserialize::FromSql for ClassBParams { + fn from_sql(value: ::RawValue<'_>) -> deserialize::Result { + let value = >::from_sql(value)?; + Ok(serde_json::from_value(value)?) + } +} + +#[cfg(feature = "postgres")] +impl serialize::ToSql for ClassBParams { + fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, Pg>) -> serialize::Result { + let value = serde_json::to_value(&self)?; + >::to_sql(&value, &mut out.reborrow()) + } +} + +#[cfg(feature = "sqlite")] +impl deserialize::FromSql for ClassBParams +where + *const str: deserialize::FromSql, +{ + fn from_sql(value: ::RawValue<'_>) -> deserialize::Result { + let s = + <*const str as deserialize::FromSql>::from_sql(value)?; + Ok(serde_json::from_str(unsafe { &*s })?) + } +} + +#[cfg(feature = "sqlite")] +impl serialize::ToSql for ClassBParams { + fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, Sqlite>) -> serialize::Result { + out.set_value(serde_json::to_string(&self)?); + Ok(serialize::IsNull::No) + } +} diff --git a/chirpstack/src/storage/fields/mod.rs b/chirpstack/src/storage/fields/mod.rs index ba89ba47..e2654d11 100644 --- a/chirpstack/src/storage/fields/mod.rs +++ b/chirpstack/src/storage/fields/mod.rs @@ -9,7 +9,7 @@ mod uuid; pub use big_decimal::BigDecimal; pub use dev_nonces::DevNonces; -pub use device_profile::AbpParams; +pub use device_profile::{AbpParams, ClassBParams}; pub use device_session::DeviceSession; pub use key_value::KeyValue; pub use measurements::*; diff --git a/chirpstack/src/storage/schema_postgres.rs b/chirpstack/src/storage/schema_postgres.rs index e1b11cd7..ec098a99 100644 --- a/chirpstack/src/storage/schema_postgres.rs +++ b/chirpstack/src/storage/schema_postgres.rs @@ -103,10 +103,6 @@ diesel::table! { supports_otaa -> Bool, supports_class_b -> Bool, supports_class_c -> Bool, - class_b_timeout -> Int4, - class_b_ping_slot_nb_k -> Int4, - class_b_ping_slot_dr -> Int2, - class_b_ping_slot_freq -> Int8, class_c_timeout -> Int4, tags -> Jsonb, payload_codec_script -> Text, @@ -141,6 +137,7 @@ diesel::table! { allow_roaming -> Bool, rx1_delay -> Int2, abp_params -> Nullable, + class_b_params -> Nullable, } } diff --git a/chirpstack/src/storage/schema_sqlite.rs b/chirpstack/src/storage/schema_sqlite.rs index 088b295b..66ee85b0 100644 --- a/chirpstack/src/storage/schema_sqlite.rs +++ b/chirpstack/src/storage/schema_sqlite.rs @@ -92,10 +92,6 @@ diesel::table! { supports_otaa -> Bool, supports_class_b -> Bool, supports_class_c -> Bool, - class_b_timeout -> Integer, - class_b_ping_slot_nb_k -> Integer, - class_b_ping_slot_dr -> SmallInt, - class_b_ping_slot_freq -> BigInt, class_c_timeout -> Integer, tags -> Text, payload_codec_script -> Text, @@ -129,6 +125,7 @@ diesel::table! { allow_roaming -> Bool, rx1_delay -> SmallInt, abp_params -> Nullable, + class_b_params -> Nullable, } } diff --git a/chirpstack/src/test/otaa_js_test.rs b/chirpstack/src/test/otaa_js_test.rs index ef913ee1..97e76944 100644 --- a/chirpstack/src/test/otaa_js_test.rs +++ b/chirpstack/src/test/otaa_js_test.rs @@ -164,7 +164,6 @@ async fn test_js() { enabled_uplink_channel_indices: vec![0, 1, 2], nb_trans: 1, region_config_id: "eu868".to_string(), - class_b_ping_slot_nb: 1, ..Default::default() }, ), @@ -229,7 +228,6 @@ async fn test_js() { enabled_uplink_channel_indices: vec![0, 1, 2], nb_trans: 1, region_config_id: "eu868".to_string(), - class_b_ping_slot_nb: 1, ..Default::default() }, ), @@ -303,7 +301,6 @@ async fn test_js() { enabled_uplink_channel_indices: vec![0, 1, 2], nb_trans: 1, region_config_id: "eu868".to_string(), - class_b_ping_slot_nb: 1, ..Default::default() }, ), diff --git a/chirpstack/src/test/otaa_test.rs b/chirpstack/src/test/otaa_test.rs index 5e2a3c22..a7da6f9e 100644 --- a/chirpstack/src/test/otaa_test.rs +++ b/chirpstack/src/test/otaa_test.rs @@ -186,7 +186,6 @@ async fn test_gateway_filtering() { enabled_uplink_channel_indices: vec![0, 1, 2], nb_trans: 1, region_config_id: "eu868".to_string(), - class_b_ping_slot_nb: 1, ..Default::default() }, )], @@ -425,7 +424,6 @@ async fn test_lorawan_10() { enabled_uplink_channel_indices: vec![0, 1, 2], nb_trans: 1, region_config_id: "eu868".to_string(), - class_b_ping_slot_nb: 1, ..Default::default() }, ), @@ -619,7 +617,6 @@ async fn test_lorawan_10() { nb_trans: 1, region_config_id: "eu868".to_string(), skip_f_cnt_check: true, - class_b_ping_slot_nb: 1, ..Default::default() }, )], @@ -710,7 +707,6 @@ async fn test_lorawan_10() { .collect(), nb_trans: 1, region_config_id: "eu868".to_string(), - class_b_ping_slot_nb: 1, ..Default::default() }, ), @@ -1044,7 +1040,6 @@ async fn test_lorawan_11() { enabled_uplink_channel_indices: vec![0, 1, 2], nb_trans: 1, region_config_id: "eu868".to_string(), - class_b_ping_slot_nb: 1, ..Default::default() }, ), diff --git a/chirpstack/src/test/relay_otaa_test.rs b/chirpstack/src/test/relay_otaa_test.rs index 90ec5bda..f162b541 100644 --- a/chirpstack/src/test/relay_otaa_test.rs +++ b/chirpstack/src/test/relay_otaa_test.rs @@ -289,7 +289,6 @@ async fn test_lorawan_10() { enabled_uplink_channel_indices: vec![0, 1, 2], nb_trans: 1, region_config_id: "eu868".to_string(), - class_b_ping_slot_nb: 1, ..Default::default() } .into(),