mirror of
https://github.com/chirpstack/chirpstack.git
synced 2025-06-14 13:38:08 +00:00
Cleanup dead code warnings.
This commit is contained in:
@ -419,6 +419,7 @@ mod test {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for tst in &tests {
|
for tst in &tests {
|
||||||
|
println!("> {}", tst.name);
|
||||||
let (tx_power_index, dr) = Algorithm::get_ideal_tx_power_index_and_dr(
|
let (tx_power_index, dr) = Algorithm::get_ideal_tx_power_index_and_dr(
|
||||||
tst.n_step,
|
tst.n_step,
|
||||||
tst.tx_power_index,
|
tst.tx_power_index,
|
||||||
@ -571,6 +572,7 @@ mod test {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for tst in &tests {
|
for tst in &tests {
|
||||||
|
println!("> {}", tst.name);
|
||||||
let resp = a.handle(&tst.request).await.unwrap();
|
let resp = a.handle(&tst.request).await.unwrap();
|
||||||
assert_eq!(tst.response, resp);
|
assert_eq!(tst.response, resp);
|
||||||
}
|
}
|
||||||
|
@ -1079,16 +1079,11 @@ impl Validator for ValidateDeviceProfileTemplatesAccess {
|
|||||||
|
|
||||||
pub struct ValidateDeviceProfileTemplateAccess {
|
pub struct ValidateDeviceProfileTemplateAccess {
|
||||||
flag: Flag,
|
flag: Flag,
|
||||||
device_profile_template_id: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValidateDeviceProfileTemplateAccess {
|
impl ValidateDeviceProfileTemplateAccess {
|
||||||
pub fn new(flag: Flag, device_profile_template_id: &str) -> Self {
|
pub fn new(flag: Flag) -> Self {
|
||||||
let device_profile_template_id = device_profile_template_id.to_string();
|
ValidateDeviceProfileTemplateAccess { flag }
|
||||||
ValidateDeviceProfileTemplateAccess {
|
|
||||||
flag,
|
|
||||||
device_profile_template_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2238,8 +2233,7 @@ impl Validator for ValidateMulticastGroupQueueAccess {
|
|||||||
pub mod test {
|
pub mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
api_key, application, device, device_profile, device_profile_template, gateway, multicast,
|
api_key, application, device, device_profile, gateway, multicast, tenant, user,
|
||||||
tenant, user,
|
|
||||||
};
|
};
|
||||||
use crate::test;
|
use crate::test;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
@ -3233,16 +3227,6 @@ pub mod test {
|
|||||||
let api_key_admin = api_key::test::create_api_key(true, false).await;
|
let api_key_admin = api_key::test::create_api_key(true, false).await;
|
||||||
let api_key_tenant = api_key::test::create_api_key(false, true).await;
|
let api_key_tenant = api_key::test::create_api_key(false, true).await;
|
||||||
|
|
||||||
let dp = device_profile_template::create(device_profile_template::DeviceProfileTemplate {
|
|
||||||
id: "test-dp".to_string(),
|
|
||||||
name: "test-dp".to_string(),
|
|
||||||
vendor: "Test Vendor".to_string(),
|
|
||||||
firmware: "1.2.3".to_string(),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// device-profile templates with user
|
// device-profile templates with user
|
||||||
let tests = vec![
|
let tests = vec![
|
||||||
// admin user can create and list
|
// admin user can create and list
|
||||||
@ -3300,24 +3284,24 @@ pub mod test {
|
|||||||
// admin user can read, update and delete
|
// admin user can read, update and delete
|
||||||
ValidatorTest {
|
ValidatorTest {
|
||||||
validators: vec![
|
validators: vec![
|
||||||
ValidateDeviceProfileTemplateAccess::new(Flag::Read, &dp.id),
|
ValidateDeviceProfileTemplateAccess::new(Flag::Read),
|
||||||
ValidateDeviceProfileTemplateAccess::new(Flag::Update, &dp.id),
|
ValidateDeviceProfileTemplateAccess::new(Flag::Update),
|
||||||
ValidateDeviceProfileTemplateAccess::new(Flag::Delete, &dp.id),
|
ValidateDeviceProfileTemplateAccess::new(Flag::Delete),
|
||||||
],
|
],
|
||||||
id: AuthID::User(user_admin.id),
|
id: AuthID::User(user_admin.id),
|
||||||
ok: true,
|
ok: true,
|
||||||
},
|
},
|
||||||
// user can read
|
// user can read
|
||||||
ValidatorTest {
|
ValidatorTest {
|
||||||
validators: vec![ValidateDeviceProfileTemplateAccess::new(Flag::Read, &dp.id)],
|
validators: vec![ValidateDeviceProfileTemplateAccess::new(Flag::Read)],
|
||||||
id: AuthID::User(user_active.id),
|
id: AuthID::User(user_active.id),
|
||||||
ok: true,
|
ok: true,
|
||||||
},
|
},
|
||||||
// user can not update or delete
|
// user can not update or delete
|
||||||
ValidatorTest {
|
ValidatorTest {
|
||||||
validators: vec![
|
validators: vec![
|
||||||
ValidateDeviceProfileTemplateAccess::new(Flag::Update, &dp.id),
|
ValidateDeviceProfileTemplateAccess::new(Flag::Update),
|
||||||
ValidateDeviceProfileTemplateAccess::new(Flag::Delete, &dp.id),
|
ValidateDeviceProfileTemplateAccess::new(Flag::Delete),
|
||||||
],
|
],
|
||||||
id: AuthID::User(user_active.id),
|
id: AuthID::User(user_active.id),
|
||||||
ok: false,
|
ok: false,
|
||||||
@ -3330,24 +3314,24 @@ pub mod test {
|
|||||||
// admin api key can read, update and delete
|
// admin api key can read, update and delete
|
||||||
ValidatorTest {
|
ValidatorTest {
|
||||||
validators: vec![
|
validators: vec![
|
||||||
ValidateDeviceProfileTemplateAccess::new(Flag::Read, &dp.id),
|
ValidateDeviceProfileTemplateAccess::new(Flag::Read),
|
||||||
ValidateDeviceProfileTemplateAccess::new(Flag::Update, &dp.id),
|
ValidateDeviceProfileTemplateAccess::new(Flag::Update),
|
||||||
ValidateDeviceProfileTemplateAccess::new(Flag::Delete, &dp.id),
|
ValidateDeviceProfileTemplateAccess::new(Flag::Delete),
|
||||||
],
|
],
|
||||||
id: AuthID::Key(api_key_admin.id),
|
id: AuthID::Key(api_key_admin.id),
|
||||||
ok: true,
|
ok: true,
|
||||||
},
|
},
|
||||||
// tenant api key can read
|
// tenant api key can read
|
||||||
ValidatorTest {
|
ValidatorTest {
|
||||||
validators: vec![ValidateDeviceProfileTemplateAccess::new(Flag::Read, &dp.id)],
|
validators: vec![ValidateDeviceProfileTemplateAccess::new(Flag::Read)],
|
||||||
id: AuthID::Key(api_key_tenant.id),
|
id: AuthID::Key(api_key_tenant.id),
|
||||||
ok: true,
|
ok: true,
|
||||||
},
|
},
|
||||||
// tenant api key can not update or delete
|
// tenant api key can not update or delete
|
||||||
ValidatorTest {
|
ValidatorTest {
|
||||||
validators: vec![
|
validators: vec![
|
||||||
ValidateDeviceProfileTemplateAccess::new(Flag::Update, &dp.id),
|
ValidateDeviceProfileTemplateAccess::new(Flag::Update),
|
||||||
ValidateDeviceProfileTemplateAccess::new(Flag::Delete, &dp.id),
|
ValidateDeviceProfileTemplateAccess::new(Flag::Delete),
|
||||||
],
|
],
|
||||||
id: AuthID::Key(api_key_tenant.id),
|
id: AuthID::Key(api_key_tenant.id),
|
||||||
ok: false,
|
ok: false,
|
||||||
|
@ -104,7 +104,7 @@ impl DeviceProfileTemplateService for DeviceProfileTemplate {
|
|||||||
self.validator
|
self.validator
|
||||||
.validate(
|
.validate(
|
||||||
request.extensions(),
|
request.extensions(),
|
||||||
validator::ValidateDeviceProfileTemplateAccess::new(validator::Flag::Read, &req.id),
|
validator::ValidateDeviceProfileTemplateAccess::new(validator::Flag::Read),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -178,10 +178,7 @@ impl DeviceProfileTemplateService for DeviceProfileTemplate {
|
|||||||
self.validator
|
self.validator
|
||||||
.validate(
|
.validate(
|
||||||
request.extensions(),
|
request.extensions(),
|
||||||
validator::ValidateDeviceProfileTemplateAccess::new(
|
validator::ValidateDeviceProfileTemplateAccess::new(validator::Flag::Update),
|
||||||
validator::Flag::Update,
|
|
||||||
&req_dp.id,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -246,10 +243,7 @@ impl DeviceProfileTemplateService for DeviceProfileTemplate {
|
|||||||
self.validator
|
self.validator
|
||||||
.validate(
|
.validate(
|
||||||
request.extensions(),
|
request.extensions(),
|
||||||
validator::ValidateDeviceProfileTemplateAccess::new(
|
validator::ValidateDeviceProfileTemplateAccess::new(validator::Flag::Delete),
|
||||||
validator::Flag::Delete,
|
|
||||||
&req.id,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -2,10 +2,9 @@ use aes::cipher::generic_array::GenericArray;
|
|||||||
use aes::cipher::{BlockEncrypt, KeyInit};
|
use aes::cipher::{BlockEncrypt, KeyInit};
|
||||||
use aes::{Aes128, Block};
|
use aes::{Aes128, Block};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use chrono::{DateTime, Duration, Utc};
|
use chrono::Duration;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use crate::gpstime::ToGpsTime;
|
|
||||||
use lrwn::DevAddr;
|
use lrwn::DevAddr;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@ -17,11 +16,6 @@ lazy_static! {
|
|||||||
static ref SLOT_LEN: Duration = Duration::milliseconds(30);
|
static ref SLOT_LEN: Duration = Duration::milliseconds(30);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_beacon_start_for_time(ts: DateTime<Utc>) -> Duration {
|
|
||||||
let gps_time = ts.to_gps_time();
|
|
||||||
get_beacon_start(gps_time)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_beacon_start(ts: Duration) -> Duration {
|
pub fn get_beacon_start(ts: Duration) -> Duration {
|
||||||
Duration::seconds(ts.num_seconds() - (ts.num_seconds() % BEACON_PERIOD.num_seconds()))
|
Duration::seconds(ts.num_seconds() - (ts.num_seconds() % BEACON_PERIOD.num_seconds()))
|
||||||
}
|
}
|
||||||
@ -89,19 +83,19 @@ pub fn get_next_ping_slot_after(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod test {
|
pub mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::gpstime::ToDateTime;
|
use crate::gpstime::{ToDateTime, ToGpsTime};
|
||||||
use chrono::TimeZone;
|
use chrono::{DateTime, TimeZone, Utc};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_beacon_start_for_time() {
|
fn test_get_beacon_start() {
|
||||||
let gps_epoch_time: DateTime<Utc> = Utc.with_ymd_and_hms(1980, 1, 6, 0, 0, 0).unwrap();
|
let gps_epoch_time: DateTime<Utc> = Utc.with_ymd_and_hms(1980, 1, 6, 0, 0, 0).unwrap();
|
||||||
|
|
||||||
// For GPS epoch time
|
// For GPS epoch time
|
||||||
let start_ts = get_beacon_start_for_time(gps_epoch_time);
|
let start_ts = get_beacon_start(gps_epoch_time.to_gps_time());
|
||||||
assert_eq!(start_ts, Duration::zero());
|
assert_eq!(start_ts, Duration::zero());
|
||||||
|
|
||||||
// For now
|
// For now
|
||||||
let start_ts = get_beacon_start_for_time(Utc::now());
|
let start_ts = get_beacon_start(Utc::now().to_gps_time());
|
||||||
|
|
||||||
// > 0
|
// > 0
|
||||||
assert!(start_ts > Duration::zero());
|
assert!(start_ts > Duration::zero());
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use tracing::{span, trace, Instrument, Level};
|
use tracing::{span, trace, Instrument, Level};
|
||||||
@ -9,11 +7,9 @@ use crate::backend::roaming;
|
|||||||
use crate::storage::downlink_frame;
|
use crate::storage::downlink_frame;
|
||||||
use crate::{gateway, region};
|
use crate::{gateway, region};
|
||||||
use chirpstack_api::{gw, internal};
|
use chirpstack_api::{gw, internal};
|
||||||
use lrwn::region::CommonName;
|
|
||||||
|
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
region_config_id: String,
|
region_config_id: String,
|
||||||
region_common_name: CommonName,
|
|
||||||
xmit_data_req: backend::XmitDataReqPayload,
|
xmit_data_req: backend::XmitDataReqPayload,
|
||||||
dl_meta_data: backend::DLMetaData,
|
dl_meta_data: backend::DLMetaData,
|
||||||
uplink_rx_info: Vec<gw::UplinkRxInfo>,
|
uplink_rx_info: Vec<gw::UplinkRxInfo>,
|
||||||
@ -48,16 +44,8 @@ impl Data {
|
|||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let region_common_name = uplink_rx_info[0]
|
|
||||||
.metadata
|
|
||||||
.get("region_common_name")
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or_default();
|
|
||||||
let region_common_name = CommonName::from_str(®ion_common_name)?;
|
|
||||||
|
|
||||||
let mut ctx = Data {
|
let mut ctx = Data {
|
||||||
region_config_id,
|
region_config_id,
|
||||||
region_common_name,
|
|
||||||
uplink_rx_info,
|
uplink_rx_info,
|
||||||
xmit_data_req: pl,
|
xmit_data_req: pl,
|
||||||
dl_meta_data: dl_meta,
|
dl_meta_data: dl_meta,
|
||||||
|
@ -14,12 +14,6 @@ use crate::storage::{get_redis_conn, redis_key};
|
|||||||
use chirpstack_api::{api, integration};
|
use chirpstack_api::{api, integration};
|
||||||
|
|
||||||
#[allow(clippy::enum_variant_names)]
|
#[allow(clippy::enum_variant_names)]
|
||||||
pub enum Entry {
|
|
||||||
UplinkEvent(integration::UplinkEvent),
|
|
||||||
JoinEvent(integration::JoinEvent),
|
|
||||||
AckEvent(integration::AckEvent),
|
|
||||||
TxAckEvent(integration::TxAckEvent),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn log_event_for_device(typ: &str, dev_eui: &str, b: &[u8]) -> Result<()> {
|
pub async fn log_event_for_device(typ: &str, dev_eui: &str, b: &[u8]) -> Result<()> {
|
||||||
task::spawn_blocking({
|
task::spawn_blocking({
|
||||||
|
@ -17,11 +17,6 @@ use crate::config;
|
|||||||
use crate::storage::{get_redis_conn, redis_key};
|
use crate::storage::{get_redis_conn, redis_key};
|
||||||
use chirpstack_api::api;
|
use chirpstack_api::api;
|
||||||
|
|
||||||
pub enum Entry {
|
|
||||||
Uplink(api::UplinkFrameLog),
|
|
||||||
Downlink(api::DownlinkFrameLog),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn log_uplink_for_gateways(ufl: &api::UplinkFrameLog) -> Result<()> {
|
pub async fn log_uplink_for_gateways(ufl: &api::UplinkFrameLog) -> Result<()> {
|
||||||
task::spawn_blocking({
|
task::spawn_blocking({
|
||||||
let ufl = ufl.clone();
|
let ufl = ufl.clone();
|
||||||
|
@ -62,7 +62,6 @@ lazy_static! {
|
|||||||
|
|
||||||
struct MqttContext {
|
struct MqttContext {
|
||||||
region_config_id: String,
|
region_config_id: String,
|
||||||
region_common_name: CommonName,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MqttBackend<'a> {
|
pub struct MqttBackend<'a> {
|
||||||
@ -124,7 +123,6 @@ impl<'a> MqttBackend<'a> {
|
|||||||
.client_id(&client_id)
|
.client_id(&client_id)
|
||||||
.user_data(Box::new(MqttContext {
|
.user_data(Box::new(MqttContext {
|
||||||
region_config_id: region_config_id.to_string(),
|
region_config_id: region_config_id.to_string(),
|
||||||
region_common_name,
|
|
||||||
}))
|
}))
|
||||||
.persistence(mqtt::create_options::PersistenceType::FilePath(temp_dir()))
|
.persistence(mqtt::create_options::PersistenceType::FilePath(temp_dir()))
|
||||||
.finalize();
|
.finalize();
|
||||||
|
@ -19,7 +19,6 @@ use chirpstack_api::integration;
|
|||||||
pub struct Integration {
|
pub struct Integration {
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
json: bool,
|
json: bool,
|
||||||
publish_name: String,
|
|
||||||
uri: String,
|
uri: String,
|
||||||
key_name: String,
|
key_name: String,
|
||||||
key: String,
|
key: String,
|
||||||
@ -39,7 +38,6 @@ impl Integration {
|
|||||||
Encoding::Json => true,
|
Encoding::Json => true,
|
||||||
Encoding::Protobuf => false,
|
Encoding::Protobuf => false,
|
||||||
},
|
},
|
||||||
publish_name: conf.publish_name.clone(),
|
|
||||||
uri: format!(
|
uri: format!(
|
||||||
"https://{}{}",
|
"https://{}{}",
|
||||||
kv.get("Endpoint")
|
kv.get("Endpoint")
|
||||||
@ -311,7 +309,6 @@ pub mod test {
|
|||||||
let i = Integration {
|
let i = Integration {
|
||||||
timeout: Duration::from_secs(5),
|
timeout: Duration::from_secs(5),
|
||||||
json: true,
|
json: true,
|
||||||
publish_name: "test-bus".to_string(),
|
|
||||||
uri: server.url(""),
|
uri: server.url(""),
|
||||||
key_name: "key-name".to_string(),
|
key_name: "key-name".to_string(),
|
||||||
key: "foo-key".to_string(),
|
key: "foo-key".to_string(),
|
||||||
|
@ -130,72 +130,6 @@ impl Integration {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn modem_gnss(
|
|
||||||
&self,
|
|
||||||
vars: &HashMap<String, String>,
|
|
||||||
pl: &integration::UplinkEvent,
|
|
||||||
) -> Result<()> {
|
|
||||||
let di = pl.device_info.as_ref().unwrap();
|
|
||||||
|
|
||||||
info!(dev_eui = %di.dev_eui, "Forwarding gnss message");
|
|
||||||
let ts: DateTime<Utc> = pl.time.as_ref().unwrap().clone().try_into()?;
|
|
||||||
let dev_eui = EUI64::from_str(&di.dev_eui)?;
|
|
||||||
|
|
||||||
let req = client::UplinkRequest {
|
|
||||||
dev_eui: client::Eui64Wrapper::new(&dev_eui),
|
|
||||||
uplink: client::UplinkMsg::Gnss({
|
|
||||||
let mut msg_gnss = client::UplinkMsgGnss {
|
|
||||||
msg_type: "gnss".into(),
|
|
||||||
payload: hex::encode(&pl.data),
|
|
||||||
timestamp: ts.timestamp_millis() as f64 / 1000.0,
|
|
||||||
gnss_capture_time: match self.config.modem_geolocation_services.gnss_use_rx_time
|
|
||||||
{
|
|
||||||
false => None,
|
|
||||||
true => {
|
|
||||||
let ts = match get_time_since_gps_epoch_chrono(&pl.rx_info) {
|
|
||||||
Some(v) => v,
|
|
||||||
None => Utc::now().to_gps_time(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Compensate for gnss scanning time and uplink.
|
|
||||||
let ts = ts - Duration::seconds(6);
|
|
||||||
Some(ts.num_seconds() as f64)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
gnss_capture_time_accuracy: match self
|
|
||||||
.config
|
|
||||||
.modem_geolocation_services
|
|
||||||
.gnss_use_rx_time
|
|
||||||
{
|
|
||||||
false => None,
|
|
||||||
true => Some(15.0),
|
|
||||||
},
|
|
||||||
gnss_assist_position: None,
|
|
||||||
gnss_assist_altitude: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
if self
|
|
||||||
.config
|
|
||||||
.modem_geolocation_services
|
|
||||||
.gnss_use_gateway_location
|
|
||||||
{
|
|
||||||
if let Some(loc) = get_start_location(&pl.rx_info) {
|
|
||||||
msg_gnss.gnss_assist_position = Some(vec![loc.latitude, loc.longitude]);
|
|
||||||
msg_gnss.gnss_assist_altitude = Some(loc.altitude);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_gnss
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
let resp = self.client.uplink_send(&req).await?;
|
|
||||||
self.handle_modem_response(vars, pl, &resp, common::LocationSource::GeoResolverGnss)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn modem_metadata(
|
async fn modem_metadata(
|
||||||
&self,
|
&self,
|
||||||
vars: &HashMap<String, String>,
|
vars: &HashMap<String, String>,
|
||||||
|
@ -6,7 +6,7 @@ use async_trait::async_trait;
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use diesel::pg::PgConnection;
|
use diesel::pg::PgConnection;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use diesel::r2d2::{ConnectionManager, Pool, PooledConnection};
|
use diesel::r2d2::{ConnectionManager, Pool};
|
||||||
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
|
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
@ -26,7 +26,6 @@ pub const MIGRATIONS: EmbeddedMigrations =
|
|||||||
embed_migrations!("./src/integration/postgresql/migrations");
|
embed_migrations!("./src/integration/postgresql/migrations");
|
||||||
|
|
||||||
type PgPool = Pool<ConnectionManager<PgConnection>>;
|
type PgPool = Pool<ConnectionManager<PgConnection>>;
|
||||||
type PgPoolConnection = PooledConnection<ConnectionManager<PgConnection>>;
|
|
||||||
|
|
||||||
#[derive(Insertable)]
|
#[derive(Insertable)]
|
||||||
#[diesel(table_name = event_up)]
|
#[diesel(table_name = event_up)]
|
||||||
|
@ -7,14 +7,7 @@ use crate::api::helpers::ToProto;
|
|||||||
use crate::integration;
|
use crate::integration;
|
||||||
use crate::storage::{application, device, device_profile, tenant};
|
use crate::storage::{application, device, device_profile, tenant};
|
||||||
use crate::uplink::{helpers, UplinkFrameSet};
|
use crate::uplink::{helpers, UplinkFrameSet};
|
||||||
use chirpstack_api::{integration as integration_pb, internal};
|
use chirpstack_api::integration as integration_pb;
|
||||||
|
|
||||||
pub fn request(dev: &device::Device, ds: &mut internal::DeviceSession) -> lrwn::MACCommandSet {
|
|
||||||
ds.last_device_status_request = Some(Utc::now().into());
|
|
||||||
info!(dev_eui = %dev.dev_eui, "Requesting device-status");
|
|
||||||
|
|
||||||
lrwn::MACCommandSet::new(vec![lrwn::MACCommand::DevStatusReq])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn handle(
|
pub async fn handle(
|
||||||
uplink_frame_set: &UplinkFrameSet,
|
uplink_frame_set: &UplinkFrameSet,
|
||||||
@ -97,22 +90,6 @@ pub mod test {
|
|||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_request() {
|
|
||||||
let dev: device::Device = Default::default();
|
|
||||||
let mut ds: internal::DeviceSession = Default::default();
|
|
||||||
|
|
||||||
assert_eq!(true, ds.last_device_status_request.is_none());
|
|
||||||
|
|
||||||
let resp = request(&dev, &mut ds);
|
|
||||||
|
|
||||||
assert_eq!(true, ds.last_device_status_request.is_some());
|
|
||||||
assert_eq!(
|
|
||||||
lrwn::MACCommandSet::new(vec![lrwn::MACCommand::DevStatusReq]),
|
|
||||||
resp
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle() {
|
async fn test_handle() {
|
||||||
let _guard = test::prepare().await;
|
let _guard = test::prepare().await;
|
||||||
|
@ -330,6 +330,7 @@ pub mod test {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for tst in &tests {
|
for tst in &tests {
|
||||||
|
println!("> {}", tst.name);
|
||||||
let resp = request(3, &tst.current_channels, &tst.wanted_channels);
|
let resp = request(3, &tst.current_channels, &tst.wanted_channels);
|
||||||
assert_eq!(tst.expected_mac_commands, resp);
|
assert_eq!(tst.expected_mac_commands, resp);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
// Required by rust::table macro.
|
// Required by rust::table macro.
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
// TODO: remove this + all dead code.
|
|
||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
extern crate openssl;
|
extern crate openssl;
|
||||||
|
|
||||||
|
@ -63,21 +63,6 @@ pub async fn create(ak: ApiKey) -> Result<ApiKey, Error> {
|
|||||||
Ok(ak)
|
Ok(ak)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get(id: &Uuid) -> Result<ApiKey, Error> {
|
|
||||||
task::spawn_blocking({
|
|
||||||
let id = *id;
|
|
||||||
|
|
||||||
move || -> Result<ApiKey, Error> {
|
|
||||||
let mut c = get_db_conn()?;
|
|
||||||
api_key::dsl::api_key
|
|
||||||
.find(&id)
|
|
||||||
.first(&mut c)
|
|
||||||
.map_err(|e| error::Error::from_diesel(e, id.to_string()))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await?
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn delete(id: &Uuid) -> Result<(), Error> {
|
pub async fn delete(id: &Uuid) -> Result<(), Error> {
|
||||||
task::spawn_blocking({
|
task::spawn_blocking({
|
||||||
let id = *id;
|
let id = *id;
|
||||||
@ -157,6 +142,21 @@ pub mod test {
|
|||||||
offset: i64,
|
offset: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get(id: &Uuid) -> Result<ApiKey, Error> {
|
||||||
|
task::spawn_blocking({
|
||||||
|
let id = *id;
|
||||||
|
|
||||||
|
move || -> Result<ApiKey, Error> {
|
||||||
|
let mut c = get_db_conn()?;
|
||||||
|
api_key::dsl::api_key
|
||||||
|
.find(&id)
|
||||||
|
.first(&mut c)
|
||||||
|
.map_err(|e| error::Error::from_diesel(e, id.to_string()))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn create_api_key(is_admin: bool, is_tenant: bool) -> ApiKey {
|
pub async fn create_api_key(is_admin: bool, is_tenant: bool) -> ApiKey {
|
||||||
let ak = ApiKey {
|
let ak = ApiKey {
|
||||||
name: "test api key".into(),
|
name: "test api key".into(),
|
||||||
|
@ -95,23 +95,6 @@ pub async fn get_rx_info_for_dev_euis(
|
|||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_rx_info(dev_eui: &EUI64) -> Result<()> {
|
|
||||||
task::spawn_blocking({
|
|
||||||
let dev_eui = *dev_eui;
|
|
||||||
move || -> Result<()> {
|
|
||||||
let key = redis_key(format!("device:{{{}}}:gwrx", dev_eui));
|
|
||||||
let mut c = get_redis_conn()?;
|
|
||||||
redis::cmd("DEL").arg(key).query(&mut *c)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
info!(dev_eui = %dev_eui, "Gateway rx-info deleted");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod test {
|
pub mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -132,10 +115,5 @@ pub mod test {
|
|||||||
// get
|
// get
|
||||||
let res = get_rx_info(&dev_eui).await.unwrap();
|
let res = get_rx_info(&dev_eui).await.unwrap();
|
||||||
assert_eq!(rx_info, res);
|
assert_eq!(rx_info, res);
|
||||||
|
|
||||||
// delete
|
|
||||||
delete_rx_info(&dev_eui).await.unwrap();
|
|
||||||
let res = get_rx_info(&dev_eui).await;
|
|
||||||
assert_eq!(true, res.is_err());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,28 +136,6 @@ pub async fn set_dev_nonces(dev_eui: &EUI64, nonces: &[i32]) -> Result<DeviceKey
|
|||||||
Ok(dk)
|
Ok(dk)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn reset_nonces(dev_eui: &EUI64) -> Result<DeviceKeys, Error> {
|
|
||||||
let dk = task::spawn_blocking({
|
|
||||||
let dev_eui = *dev_eui;
|
|
||||||
move || -> Result<DeviceKeys, Error> {
|
|
||||||
let mut c = get_db_conn()?;
|
|
||||||
diesel::update(device_keys::dsl::device_keys.find(&dev_eui))
|
|
||||||
.set((
|
|
||||||
device_keys::dev_nonces.eq::<Vec<i32>>(Vec::new()),
|
|
||||||
device_keys::join_nonce.eq(0),
|
|
||||||
))
|
|
||||||
.get_result(&mut c)
|
|
||||||
.map_err(|e| Error::from_diesel(e, dev_eui.to_string()))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
info!(
|
|
||||||
dev_eui = %dev_eui,
|
|
||||||
"Nonces reset"
|
|
||||||
);
|
|
||||||
Ok(dk)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn validate_incr_join_and_store_dev_nonce(
|
pub async fn validate_incr_join_and_store_dev_nonce(
|
||||||
dev_eui: &EUI64,
|
dev_eui: &EUI64,
|
||||||
dev_nonce: i32,
|
dev_nonce: i32,
|
||||||
@ -203,6 +181,28 @@ pub mod test {
|
|||||||
use crate::storage;
|
use crate::storage;
|
||||||
use crate::test;
|
use crate::test;
|
||||||
|
|
||||||
|
pub async fn reset_nonces(dev_eui: &EUI64) -> Result<DeviceKeys, Error> {
|
||||||
|
let dk = task::spawn_blocking({
|
||||||
|
let dev_eui = *dev_eui;
|
||||||
|
move || -> Result<DeviceKeys, Error> {
|
||||||
|
let mut c = get_db_conn()?;
|
||||||
|
diesel::update(device_keys::dsl::device_keys.find(&dev_eui))
|
||||||
|
.set((
|
||||||
|
device_keys::dev_nonces.eq::<Vec<i32>>(Vec::new()),
|
||||||
|
device_keys::join_nonce.eq(0),
|
||||||
|
))
|
||||||
|
.get_result(&mut c)
|
||||||
|
.map_err(|e| Error::from_diesel(e, dev_eui.to_string()))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
info!(
|
||||||
|
dev_eui = %dev_eui,
|
||||||
|
"Nonces reset"
|
||||||
|
);
|
||||||
|
Ok(dk)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn create_device_keys(dev_eui: Option<EUI64>) -> DeviceKeys {
|
pub async fn create_device_keys(dev_eui: Option<EUI64>) -> DeviceKeys {
|
||||||
let dev_eui = match dev_eui {
|
let dev_eui = match dev_eui {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
|
@ -674,6 +674,7 @@ pub mod test {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for tst in &tests {
|
for tst in &tests {
|
||||||
|
println!("> {}", tst.name);
|
||||||
let mut phy = lrwn::PhyPayload {
|
let mut phy = lrwn::PhyPayload {
|
||||||
mhdr: lrwn::MHDR {
|
mhdr: lrwn::MHDR {
|
||||||
m_type: lrwn::MType::UnconfirmedDataUp,
|
m_type: lrwn::MType::UnconfirmedDataUp,
|
||||||
|
@ -616,20 +616,6 @@ pub async fn enqueue(
|
|||||||
Ok((ids, f_cnt))
|
Ok((ids, f_cnt))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_queue_item(id: &Uuid) -> Result<MulticastGroupQueueItem, Error> {
|
|
||||||
task::spawn_blocking({
|
|
||||||
let id = *id;
|
|
||||||
move || -> Result<MulticastGroupQueueItem, Error> {
|
|
||||||
let mut c = get_db_conn()?;
|
|
||||||
multicast_group_queue_item::dsl::multicast_group_queue_item
|
|
||||||
.find(&id)
|
|
||||||
.first(&mut c)
|
|
||||||
.map_err(|e| Error::from_diesel(e, id.to_string()))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await?
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn delete_queue_item(id: &Uuid) -> Result<(), Error> {
|
pub async fn delete_queue_item(id: &Uuid) -> Result<(), Error> {
|
||||||
task::spawn_blocking({
|
task::spawn_blocking({
|
||||||
let id = *id;
|
let id = *id;
|
||||||
@ -731,6 +717,20 @@ pub mod test {
|
|||||||
use crate::storage::{application, device, device_profile, gateway, tenant};
|
use crate::storage::{application, device, device_profile, gateway, tenant};
|
||||||
use crate::test;
|
use crate::test;
|
||||||
|
|
||||||
|
pub async fn get_queue_item(id: &Uuid) -> Result<MulticastGroupQueueItem, Error> {
|
||||||
|
task::spawn_blocking({
|
||||||
|
let id = *id;
|
||||||
|
move || -> Result<MulticastGroupQueueItem, Error> {
|
||||||
|
let mut c = get_db_conn()?;
|
||||||
|
multicast_group_queue_item::dsl::multicast_group_queue_item
|
||||||
|
.find(&id)
|
||||||
|
.first(&mut c)
|
||||||
|
.map_err(|e| Error::from_diesel(e, id.to_string()))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
|
||||||
struct FilterTest<'a> {
|
struct FilterTest<'a> {
|
||||||
filters: Filters,
|
filters: Filters,
|
||||||
groups: Vec<&'a MulticastGroup>,
|
groups: Vec<&'a MulticastGroup>,
|
||||||
|
@ -196,21 +196,6 @@ async fn get_sessions_for_dev_addr(
|
|||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_sessions_for_dev_eui(
|
|
||||||
dev_eui: EUI64,
|
|
||||||
) -> Result<Vec<internal::PassiveRoamingDeviceSession>> {
|
|
||||||
let mut out: Vec<internal::PassiveRoamingDeviceSession> = Vec::new();
|
|
||||||
let ids = get_session_ids_for_dev_eui(dev_eui).await?;
|
|
||||||
|
|
||||||
for id in ids {
|
|
||||||
if let Ok(v) = get(id).await {
|
|
||||||
out.push(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_session_ids_for_dev_addr(dev_addr: DevAddr) -> Result<Vec<Uuid>> {
|
async fn get_session_ids_for_dev_addr(dev_addr: DevAddr) -> Result<Vec<Uuid>> {
|
||||||
task::spawn_blocking({
|
task::spawn_blocking({
|
||||||
move || -> Result<Vec<Uuid>> {
|
move || -> Result<Vec<Uuid>> {
|
||||||
|
@ -156,7 +156,7 @@ async fn test_gateway_filtering() {
|
|||||||
before_func: Some(Box::new(move || {
|
before_func: Some(Box::new(move || {
|
||||||
let dev_eui = dev.dev_eui.clone();
|
let dev_eui = dev.dev_eui.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
device_keys::reset_nonces(&dev_eui).await.unwrap();
|
device_keys::test::reset_nonces(&dev_eui).await.unwrap();
|
||||||
})
|
})
|
||||||
})),
|
})),
|
||||||
after_func: None,
|
after_func: None,
|
||||||
@ -201,7 +201,7 @@ async fn test_gateway_filtering() {
|
|||||||
before_func: Some(Box::new(move || {
|
before_func: Some(Box::new(move || {
|
||||||
let dev_eui = dev.dev_eui.clone();
|
let dev_eui = dev.dev_eui.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
device_keys::reset_nonces(&dev_eui).await.unwrap();
|
device_keys::test::reset_nonces(&dev_eui).await.unwrap();
|
||||||
})
|
})
|
||||||
})),
|
})),
|
||||||
after_func: None,
|
after_func: None,
|
||||||
@ -390,7 +390,7 @@ async fn test_lorawan_10() {
|
|||||||
before_func: Some(Box::new(move || {
|
before_func: Some(Box::new(move || {
|
||||||
let dev_eui = dev.dev_eui.clone();
|
let dev_eui = dev.dev_eui.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
device_keys::reset_nonces(&dev_eui).await.unwrap();
|
device_keys::test::reset_nonces(&dev_eui).await.unwrap();
|
||||||
})
|
})
|
||||||
})),
|
})),
|
||||||
after_func: None,
|
after_func: None,
|
||||||
@ -579,7 +579,7 @@ async fn test_lorawan_10() {
|
|||||||
before_func: Some(Box::new(move || {
|
before_func: Some(Box::new(move || {
|
||||||
let dev_eui = dev.dev_eui.clone();
|
let dev_eui = dev.dev_eui.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
device_keys::reset_nonces(&dev_eui).await.unwrap();
|
device_keys::test::reset_nonces(&dev_eui).await.unwrap();
|
||||||
|
|
||||||
let mut dev = device::get(&dev_eui).await.unwrap();
|
let mut dev = device::get(&dev_eui).await.unwrap();
|
||||||
dev.skip_fcnt_check = true;
|
dev.skip_fcnt_check = true;
|
||||||
@ -636,7 +636,7 @@ async fn test_lorawan_10() {
|
|||||||
before_func: Some(Box::new(move || {
|
before_func: Some(Box::new(move || {
|
||||||
let dev_eui = dev.dev_eui.clone();
|
let dev_eui = dev.dev_eui.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
device_keys::reset_nonces(&dev_eui).await.unwrap();
|
device_keys::test::reset_nonces(&dev_eui).await.unwrap();
|
||||||
})
|
})
|
||||||
})),
|
})),
|
||||||
after_func: None,
|
after_func: None,
|
||||||
@ -790,7 +790,7 @@ async fn test_lorawan_10() {
|
|||||||
let dev_eui = dev.dev_eui.clone();
|
let dev_eui = dev.dev_eui.clone();
|
||||||
let dp_id = dp.id.clone();
|
let dp_id = dp.id.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
device_keys::reset_nonces(&dev_eui).await.unwrap();
|
device_keys::test::reset_nonces(&dev_eui).await.unwrap();
|
||||||
|
|
||||||
let mut dp = device_profile::get(&dp_id).await.unwrap();
|
let mut dp = device_profile::get(&dp_id).await.unwrap();
|
||||||
dp.supports_class_b = true;
|
dp.supports_class_b = true;
|
||||||
@ -817,7 +817,7 @@ async fn test_lorawan_10() {
|
|||||||
let dev_eui = dev.dev_eui.clone();
|
let dev_eui = dev.dev_eui.clone();
|
||||||
let dp_id = dp.id.clone();
|
let dp_id = dp.id.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
device_keys::reset_nonces(&dev_eui).await.unwrap();
|
device_keys::test::reset_nonces(&dev_eui).await.unwrap();
|
||||||
|
|
||||||
let mut dp = device_profile::get(&dp_id).await.unwrap();
|
let mut dp = device_profile::get(&dp_id).await.unwrap();
|
||||||
dp.supports_class_c = true;
|
dp.supports_class_c = true;
|
||||||
@ -843,7 +843,7 @@ async fn test_lorawan_10() {
|
|||||||
before_func: Some(Box::new(move || {
|
before_func: Some(Box::new(move || {
|
||||||
let dev_eui = dev.dev_eui.clone();
|
let dev_eui = dev.dev_eui.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
device_keys::reset_nonces(&dev_eui).await.unwrap();
|
device_keys::test::reset_nonces(&dev_eui).await.unwrap();
|
||||||
|
|
||||||
let mut dev = device::get(&dev_eui).await.unwrap();
|
let mut dev = device::get(&dev_eui).await.unwrap();
|
||||||
dev.is_disabled = true;
|
dev.is_disabled = true;
|
||||||
@ -1012,7 +1012,7 @@ async fn test_lorawan_11() {
|
|||||||
before_func: Some(Box::new(move || {
|
before_func: Some(Box::new(move || {
|
||||||
let dev_eui = dev.dev_eui.clone();
|
let dev_eui = dev.dev_eui.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
device_keys::reset_nonces(&dev_eui).await.unwrap();
|
device_keys::test::reset_nonces(&dev_eui).await.unwrap();
|
||||||
})
|
})
|
||||||
})),
|
})),
|
||||||
after_func: None,
|
after_func: None,
|
||||||
@ -1193,7 +1193,7 @@ async fn test_lorawan_11() {
|
|||||||
let dev_eui = dev.dev_eui.clone();
|
let dev_eui = dev.dev_eui.clone();
|
||||||
let dp_id = dp.id.clone();
|
let dp_id = dp.id.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
device_keys::reset_nonces(&dev_eui).await.unwrap();
|
device_keys::test::reset_nonces(&dev_eui).await.unwrap();
|
||||||
|
|
||||||
let mut dp = device_profile::get(&dp_id).await.unwrap();
|
let mut dp = device_profile::get(&dp_id).await.unwrap();
|
||||||
dp.supports_class_c = true;
|
dp.supports_class_c = true;
|
||||||
|
@ -12,14 +12,6 @@ use crate::{gateway::backend as gateway_backend, integration, test, uplink};
|
|||||||
use chirpstack_api::{common, gw, internal};
|
use chirpstack_api::{common, gw, internal};
|
||||||
use lrwn::{AES128Key, EUI64};
|
use lrwn::{AES128Key, EUI64};
|
||||||
|
|
||||||
struct Test {
|
|
||||||
name: String,
|
|
||||||
tx_info: gw::UplinkTxInfo,
|
|
||||||
rx_info: gw::UplinkRxInfo,
|
|
||||||
phy_payload: lrwn::PhyPayload,
|
|
||||||
assert: Vec<assert::Validator>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_lorawan_10() {
|
async fn test_lorawan_10() {
|
||||||
let _guard = test::prepare().await;
|
let _guard = test::prepare().await;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#[cfg(test)]
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
@ -47,49 +48,6 @@ pub fn get_uplink_dr(
|
|||||||
region_conf.get_data_rate_index(true, &dr_modulation)
|
region_conf.get_data_rate_index(true, &dr_modulation)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_uplink_modulation(
|
|
||||||
region_config_id: &str,
|
|
||||||
tx_info: &mut chirpstack_api::gw::UplinkTxInfo,
|
|
||||||
dr: u8,
|
|
||||||
) -> Result<()> {
|
|
||||||
let region_conf = region::get(region_config_id)?;
|
|
||||||
let params = region_conf.get_data_rate(dr)?;
|
|
||||||
|
|
||||||
tx_info.modulation = Some(gw::Modulation {
|
|
||||||
parameters: Some(match params {
|
|
||||||
lrwn::region::DataRateModulation::Lora(v) => {
|
|
||||||
gw::modulation::Parameters::Lora(gw::LoraModulationInfo {
|
|
||||||
bandwidth: v.bandwidth,
|
|
||||||
spreading_factor: v.spreading_factor as u32,
|
|
||||||
code_rate: gw::CodeRate::from_str(&v.coding_rate)
|
|
||||||
.map_err(|e| anyhow!("{}", e))?
|
|
||||||
.into(),
|
|
||||||
code_rate_legacy: "".into(),
|
|
||||||
polarization_inversion: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
lrwn::region::DataRateModulation::Fsk(v) => {
|
|
||||||
gw::modulation::Parameters::Fsk(gw::FskModulationInfo {
|
|
||||||
datarate: v.bitrate,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
lrwn::region::DataRateModulation::LrFhss(v) => {
|
|
||||||
gw::modulation::Parameters::LrFhss(gw::LrFhssModulationInfo {
|
|
||||||
operating_channel_width: v.occupied_channel_width,
|
|
||||||
code_rate: gw::CodeRate::from_str(&v.coding_rate)
|
|
||||||
.map_err(|e| anyhow!("{}", e))?
|
|
||||||
.into(),
|
|
||||||
// GridSteps: this value can't be derived from a DR?
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_uplink_ch(region_config_id: &str, frequency: u32, dr: u8) -> Result<usize> {
|
pub fn get_uplink_ch(region_config_id: &str, frequency: u32, dr: u8) -> Result<usize> {
|
||||||
let region_conf = region::get(region_config_id)?;
|
let region_conf = region::get(region_config_id)?;
|
||||||
region_conf.get_uplink_channel_index_for_freq_dr(frequency, dr)
|
region_conf.get_uplink_channel_index_for_freq_dr(frequency, dr)
|
||||||
@ -188,3 +146,47 @@ pub fn get_start_location(rx_info: &[gw::UplinkRxInfo]) -> Option<common::Locati
|
|||||||
.first()
|
.first()
|
||||||
.map(|i| i.location.as_ref().unwrap().clone())
|
.map(|i| i.location.as_ref().unwrap().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn set_uplink_modulation(
|
||||||
|
region_config_id: &str,
|
||||||
|
tx_info: &mut chirpstack_api::gw::UplinkTxInfo,
|
||||||
|
dr: u8,
|
||||||
|
) -> Result<()> {
|
||||||
|
let region_conf = region::get(region_config_id)?;
|
||||||
|
let params = region_conf.get_data_rate(dr)?;
|
||||||
|
|
||||||
|
tx_info.modulation = Some(gw::Modulation {
|
||||||
|
parameters: Some(match params {
|
||||||
|
lrwn::region::DataRateModulation::Lora(v) => {
|
||||||
|
gw::modulation::Parameters::Lora(gw::LoraModulationInfo {
|
||||||
|
bandwidth: v.bandwidth,
|
||||||
|
spreading_factor: v.spreading_factor as u32,
|
||||||
|
code_rate: gw::CodeRate::from_str(&v.coding_rate)
|
||||||
|
.map_err(|e| anyhow!("{}", e))?
|
||||||
|
.into(),
|
||||||
|
code_rate_legacy: "".into(),
|
||||||
|
polarization_inversion: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
lrwn::region::DataRateModulation::Fsk(v) => {
|
||||||
|
gw::modulation::Parameters::Fsk(gw::FskModulationInfo {
|
||||||
|
datarate: v.bitrate,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
lrwn::region::DataRateModulation::LrFhss(v) => {
|
||||||
|
gw::modulation::Parameters::LrFhss(gw::LrFhssModulationInfo {
|
||||||
|
operating_channel_width: v.occupied_channel_width,
|
||||||
|
code_rate: gw::CodeRate::from_str(&v.coding_rate)
|
||||||
|
.map_err(|e| anyhow!("{}", e))?
|
||||||
|
.into(),
|
||||||
|
// GridSteps: this value can't be derived from a DR?
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user