Change LR-FHSS code_rate to CodeRate type.

This commit is contained in:
Orne Brocaar 2022-07-22 12:19:36 +01:00
parent e7432986cd
commit c0a450c8f8
15 changed files with 805 additions and 658 deletions

1097
api/go/gw/gw.pb.go vendored

File diff suppressed because it is too large Load Diff

15
api/js/gw/gw_pb.d.ts vendored
View File

@ -189,8 +189,11 @@ export class LrFhssModulationInfo extends jspb.Message {
getOperatingChannelWidth(): number;
setOperatingChannelWidth(value: number): void;
getCodeRate(): string;
setCodeRate(value: string): void;
getCodeRateLegacy(): string;
setCodeRateLegacy(value: string): void;
getCodeRate(): CodeRateMap[keyof CodeRateMap];
setCodeRate(value: CodeRateMap[keyof CodeRateMap]): void;
getGridSteps(): number;
setGridSteps(value: number): void;
@ -208,7 +211,8 @@ export class LrFhssModulationInfo extends jspb.Message {
export namespace LrFhssModulationInfo {
export type AsObject = {
operatingChannelWidth: number,
codeRate: string,
codeRateLegacy: string,
codeRate: CodeRateMap[keyof CodeRateMap],
gridSteps: number,
}
}
@ -1387,6 +1391,11 @@ export interface CodeRateMap {
CR_4_6: 2;
CR_4_7: 3;
CR_4_8: 4;
CR_3_8: 5;
CR_2_6: 6;
CR_1_4: 7;
CR_1_6: 8;
CR_5_6: 9;
}
export const CodeRate: CodeRateMap;

42
api/js/gw/gw_pb.js vendored
View File

@ -1393,6 +1393,7 @@ proto.gw.LrFhssModulationInfo.prototype.toObject = function(opt_includeInstance)
proto.gw.LrFhssModulationInfo.toObject = function(includeInstance, msg) {
var f, obj = {
operatingChannelWidth: msg.getOperatingChannelWidth(),
codeRateLegacy: msg.getCodeRateLegacy(),
codeRate: msg.getCodeRate(),
gridSteps: msg.getGridSteps()
};
@ -1437,6 +1438,10 @@ proto.gw.LrFhssModulationInfo.deserializeBinaryFromReader = function(msg, reader
break;
case 2:
var value = /** @type {string} */ (reader.readString());
msg.setCodeRateLegacy(value);
break;
case 4:
var value = /** @type {!proto.gw.CodeRate} */ (reader.readEnum());
msg.setCodeRate(value);
break;
case 3:
@ -1488,13 +1493,20 @@ proto.gw.LrFhssModulationInfo.prototype.serializeBinaryToWriter = function (writ
f
);
}
f = this.getCodeRate();
f = this.getCodeRateLegacy();
if (f.length > 0) {
writer.writeString(
2,
f
);
}
f = this.getCodeRate();
if (f !== 0.0) {
writer.writeEnum(
4,
f
);
}
f = this.getGridSteps();
if (f !== 0) {
writer.writeUint32(
@ -1530,20 +1542,35 @@ proto.gw.LrFhssModulationInfo.prototype.setOperatingChannelWidth = function(valu
/**
* optional string code_rate = 2;
* optional string code_rate_legacy = 2;
* @return {string}
*/
proto.gw.LrFhssModulationInfo.prototype.getCodeRate = function() {
proto.gw.LrFhssModulationInfo.prototype.getCodeRateLegacy = function() {
return /** @type {string} */ (jspb.Message.getFieldProto3(this, 2, ""));
};
/** @param {string} value */
proto.gw.LrFhssModulationInfo.prototype.setCodeRate = function(value) {
proto.gw.LrFhssModulationInfo.prototype.setCodeRateLegacy = function(value) {
jspb.Message.setField(this, 2, value);
};
/**
* optional CodeRate code_rate = 4;
* @return {!proto.gw.CodeRate}
*/
proto.gw.LrFhssModulationInfo.prototype.getCodeRate = function() {
return /** @type {!proto.gw.CodeRate} */ (jspb.Message.getFieldProto3(this, 4, 0));
};
/** @param {!proto.gw.CodeRate} value */
proto.gw.LrFhssModulationInfo.prototype.setCodeRate = function(value) {
jspb.Message.setField(this, 4, value);
};
/**
* optional uint32 grid_steps = 3;
* @return {number}
@ -10444,7 +10471,12 @@ proto.gw.CodeRate = {
CR_4_5: 1,
CR_4_6: 2,
CR_4_7: 3,
CR_4_8: 4
CR_4_8: 4,
CR_3_8: 5,
CR_2_6: 6,
CR_1_4: 7,
CR_1_6: 8,
CR_5_6: 9
};
/**

13
api/proto/gw/gw.proto vendored
View File

@ -15,10 +15,15 @@ import "google/protobuf/struct.proto";
enum CodeRate {
CR_UNDEFINED = 0;
CR_4_5 = 1;
CR_4_5 = 1; // LoRa
CR_4_6 = 2;
CR_4_7 = 3;
CR_4_8 = 4;
CR_3_8 = 5; // LR-FHSS
CR_2_6 = 6;
CR_1_4 = 7;
CR_1_6 = 8;
CR_5_6 = 9;
}
enum DownlinkTiming {
@ -159,7 +164,11 @@ message LrFhssModulationInfo {
uint32 operating_channel_width = 1;
// Code-rate.
string code_rate = 2;
// Deprecated: use code_rate.
string code_rate_legacy = 2;
// Code-rate.
CodeRate code_rate = 4;
// Hopping grid number of steps.
uint32 grid_steps = 3;

View File

@ -15,10 +15,15 @@ import "google/protobuf/struct.proto";
enum CodeRate {
CR_UNDEFINED = 0;
CR_4_5 = 1;
CR_4_5 = 1; // LoRa
CR_4_6 = 2;
CR_4_7 = 3;
CR_4_8 = 4;
CR_3_8 = 5; // LR-FHSS
CR_2_6 = 6;
CR_1_4 = 7;
CR_1_6 = 8;
CR_5_6 = 9;
}
enum DownlinkTiming {
@ -159,7 +164,11 @@ message LrFhssModulationInfo {
uint32 operating_channel_width = 1;
// Code-rate.
string code_rate = 2;
// Deprecated: use code_rate.
string code_rate_legacy = 2;
// Code-rate.
CodeRate code_rate = 4;
// Hopping grid number of steps.
uint32 grid_steps = 3;

File diff suppressed because one or more lines are too long

View File

@ -15,10 +15,15 @@ import "google/protobuf/struct.proto";
enum CodeRate {
CR_UNDEFINED = 0;
CR_4_5 = 1;
CR_4_5 = 1; // LoRa
CR_4_6 = 2;
CR_4_7 = 3;
CR_4_8 = 4;
CR_3_8 = 5; // LR-FHSS
CR_2_6 = 6;
CR_1_4 = 7;
CR_1_6 = 8;
CR_5_6 = 9;
}
enum DownlinkTiming {
@ -159,7 +164,11 @@ message LrFhssModulationInfo {
uint32 operating_channel_width = 1;
// Code-rate.
string code_rate = 2;
// Deprecated: use code_rate.
string code_rate_legacy = 2;
// Code-rate.
CodeRate code_rate = 4;
// Hopping grid number of steps.
uint32 grid_steps = 3;

70
api/rust/src/gw.rs vendored
View File

@ -1,8 +1,50 @@
use rand::Rng;
use std::error::Error;
use std::str::FromStr;
tonic::include_proto!("gw/gw");
include!(concat!(env!("OUT_DIR"), "/gw/gw.serde.rs"));
#[allow(clippy::from_over_into)]
impl Into<String> for CodeRate {
fn into(self) -> String {
match self {
CodeRate::CrUndefined => "",
CodeRate::Cr45 => "4/5",
CodeRate::Cr46 => "4/6",
CodeRate::Cr47 => "4/7",
CodeRate::Cr48 => "4/8",
CodeRate::Cr38 => "3/8",
CodeRate::Cr26 => "2/6",
CodeRate::Cr14 => "1/4",
CodeRate::Cr16 => "1/6",
CodeRate::Cr56 => "5/6",
}
.to_string()
}
}
impl FromStr for CodeRate {
type Err = Box<dyn Error>;
fn from_str(s: &str) -> Result<Self, Box<dyn Error>> {
Ok(match s {
"4/5" => CodeRate::Cr45,
"4/6" | "2/3" => CodeRate::Cr46,
"4/7" => CodeRate::Cr47,
"4/8" | "2/4" | "1/2" => CodeRate::Cr48,
"3/8" => CodeRate::Cr38,
"2/6" | "1/3" => CodeRate::Cr26,
"1/4" => CodeRate::Cr14,
"1/6" => CodeRate::Cr16,
"5/6" => CodeRate::Cr56,
_ => {
return Err("invalid code-rate".into());
}
})
}
}
#[allow(clippy::from_over_into)]
impl Into<String> for TxAckStatus {
fn into(self) -> String {
@ -35,14 +77,9 @@ impl UplinkFrame {
modulation::Parameters::Lora(LoraModulationInfo {
bandwidth: info.bandwidth * 1000,
spreading_factor: info.spreading_factor,
code_rate: match info.code_rate_legacy.as_ref() {
"4/5" => CodeRate::Cr45,
"2/3" | "4/6" => CodeRate::Cr46,
"4/7" => CodeRate::Cr47,
"1/2" | "2/4" | "4/8" => CodeRate::Cr48,
_ => CodeRate::CrUndefined,
}
.into(),
code_rate: CodeRate::from_str(&info.code_rate_legacy)
.unwrap_or(CodeRate::CrUndefined)
.into(),
code_rate_legacy: "".into(),
polarization_inversion: info.polarization_inversion,
})
@ -51,7 +88,13 @@ impl UplinkFrame {
modulation::Parameters::Fsk(info.clone())
}
uplink_tx_info_legacy::ModulationInfo::LrFhssModulationInfo(info) => {
modulation::Parameters::LrFhss(info.clone())
modulation::Parameters::LrFhss(LrFhssModulationInfo {
code_rate: CodeRate::from_str(&info.code_rate_legacy)
.unwrap_or(CodeRate::CrUndefined)
.into(),
code_rate_legacy: "".into(),
..info.clone()
})
}
}),
}),
@ -156,14 +199,7 @@ impl DownlinkFrame {
LoraModulationInfo {
bandwidth: v.bandwidth / 1000,
spreading_factor: v.spreading_factor,
code_rate_legacy: match v.code_rate() {
CodeRate::CrUndefined => "",
CodeRate::Cr45 => "4/5",
CodeRate::Cr46 => "4/6",
CodeRate::Cr47 => "4/7",
CodeRate::Cr48 => "4/8",
}
.into(),
code_rate_legacy: v.code_rate().into(),
polarization_inversion: v.polarization_inversion,
..Default::default()
},

View File

@ -52,10 +52,10 @@ impl Handler for Algorithm {
// Get median RSSI.
let med_rssi = get_median(&req.uplink_history);
// If the median RSSI is below -130, coding-rate 1/3 is recommended,
// If the median RSSI is below -130, coding-rate 2/6 is recommended,
// if we are on this coding-rate already, there is nothing to do.
if let lrwn::region::DataRateModulation::LrFhss(dr) = &current_dr {
if med_rssi < -130 && dr.coding_rate == "1/3" {
if med_rssi < -130 && dr.coding_rate == "2/6" {
return Ok(resp);
}
}
@ -85,7 +85,7 @@ impl Handler for Algorithm {
let mut drs: Vec<u8> = Vec::new();
// Select LR-FHSS data-rate with coding-rate 4/6 (if any available).
// Note: that for RSSI (median) < -130, coding-rate 1/3 is recommended.
// Note: that for RSSI (median) < -130, coding-rate 2/6 is recommended.
// As the median is taken from the uplink history, make sure that we
// take the median from a full history table.
if med_rssi >= -130 && req.uplink_history.len() == 20 {
@ -105,8 +105,8 @@ impl Handler for Algorithm {
);
}
// This either means coding-rate 1/3 must be used, or no data-rate with
// coding-rate 3/6 is enabled, and thus 1/3 is the only option.
// This either means coding-rate 2/6 must be used, or no data-rate with
// coding-rate 3/6 is enabled, and thus 2/6 is the only option.
if drs.is_empty() {
drs.extend_from_slice(
&lr_fhss_drs
@ -115,7 +115,7 @@ impl Handler for Algorithm {
.filter(|dr| {
let dr = region_conf.get_data_rate(*dr).unwrap();
if let lrwn::region::DataRateModulation::LrFhss(dr) = dr {
dr.coding_rate == "1/3"
dr.coding_rate == "2/6"
} else {
false
}

View File

@ -289,7 +289,9 @@ pub fn ul_meta_data_to_tx_info(ul_meta_data: &ULMetaData) -> Result<gw::UplinkTx
lrwn::region::DataRateModulation::LrFhss(v) => {
gw::modulation::Parameters::LrFhss(gw::LrFhssModulationInfo {
operating_channel_width: v.occupied_channel_width,
code_rate: v.coding_rate,
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()
})

View File

@ -1,3 +1,4 @@
use std::str::FromStr;
use std::time::{Duration, SystemTime};
use anyhow::Result;
@ -33,7 +34,7 @@ pub fn get_uplink_dr(region_name: &str, tx_info: &chirpstack_api::gw::UplinkTxIn
}
chirpstack_api::gw::modulation::Parameters::LrFhss(v) => {
lrwn::region::DataRateModulation::LrFhss(lrwn::region::LrFhssDataRate {
coding_rate: v.code_rate.clone(),
coding_rate: v.code_rate().into(),
occupied_channel_width: v.operating_channel_width,
})
}
@ -70,7 +71,9 @@ pub fn set_uplink_modulation(
lrwn::region::DataRateModulation::LrFhss(v) => {
gw::modulation::Parameters::LrFhss(gw::LrFhssModulationInfo {
operating_channel_width: v.occupied_channel_width,
code_rate: v.coding_rate,
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()
})

View File

@ -264,7 +264,7 @@ fn per_modultation_to_per_dr(
}
gw::modulation::Parameters::LrFhss(v) => {
lrwn::region::DataRateModulation::LrFhss(lrwn::region::LrFhssDataRate {
coding_rate: v.code_rate.clone(),
coding_rate: v.code_rate().into(),
occupied_channel_width: v.operating_channel_width,
})
}

View File

@ -103,7 +103,7 @@ impl Configuration {
uplink: true,
downlink: false,
modulation: DataRateModulation::LrFhss(LrFhssDataRate {
coding_rate: "1/3".to_string(),
coding_rate: "2/6".to_string(),
occupied_channel_width: 1523000,
}),
},

View File

@ -111,7 +111,7 @@ impl Configuration {
uplink: true,
downlink: false,
modulation: DataRateModulation::LrFhss(LrFhssDataRate {
coding_rate: "1/3".to_string(),
coding_rate: "2/6".to_string(),
occupied_channel_width: 137000,
}),
},
@ -133,7 +133,7 @@ impl Configuration {
uplink: true,
downlink: false,
modulation: DataRateModulation::LrFhss(LrFhssDataRate {
coding_rate: "1/3".to_string(),
coding_rate: "2/6".to_string(),
occupied_channel_width: 336000,
}),
},

View File

@ -81,7 +81,7 @@ impl Configuration {
uplink: true,
downlink: false,
modulation: DataRateModulation::LrFhss(LrFhssDataRate {
coding_rate: "1/3".to_string(),
coding_rate: "2/6".to_string(),
occupied_channel_width: 1523000,
}),
},