Refactor uplink / downlink GW <> NS messages.

This includes:

* Changing the modulation parameters to its own type.
* Changing the timing parameters to its own type.
* Change the gateway_id to string. As the json encoding for bytes fields
  is base64, this was confusing some users.
* Change the uplink / downlink id to uint32 from uuid. A string
  representation of the UUID field (for the same reason as the gateway
  id) would consome quite some additional bytes. An uint32 provides
  sufficient uniqueness for the purpose of uplink / downlink.
This commit is contained in:
Orne Brocaar
2022-04-21 11:42:28 +01:00
parent f033793f74
commit e649e75c8d
56 changed files with 6112 additions and 3661 deletions

274
api/rust/Cargo.lock generated vendored
View File

@ -2,15 +2,6 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.45"
@ -55,6 +46,49 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "axum"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47594e438a243791dba58124b6669561f5baa14cb12046641d8008bf035e5a25"
dependencies = [
"async-trait",
"axum-core",
"bitflags",
"bytes",
"futures-util",
"http",
"http-body",
"hyper",
"itoa 1.0.1",
"matchit",
"memchr",
"mime",
"percent-encoding",
"pin-project-lite",
"serde",
"sync_wrapper",
"tokio",
"tower",
"tower-http",
"tower-layer",
"tower-service",
]
[[package]]
name = "axum-core"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a671c9ae99531afdd5d3ee8340b8da547779430689947144c140fc74a740244"
dependencies = [
"async-trait",
"bytes",
"futures-util",
"http",
"http-body",
"mime",
]
[[package]]
name = "base64"
version = "0.13.0"
@ -73,6 +107,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -83,11 +123,13 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
name = "chirpstack_api"
version = "4.0.0"
dependencies = [
"hex",
"pbjson",
"pbjson-build",
"pbjson-types",
"prost",
"prost-types",
"rand",
"serde",
"tokio",
"tonic",
@ -100,11 +142,17 @@ version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"time",
"winapi",
]
[[package]]
name = "cmake"
version = "0.1.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a"
dependencies = [
"cc",
]
[[package]]
@ -173,7 +221,7 @@ checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
"libc",
"wasi",
"wasi 0.10.2+wasi-snapshot-preview1",
]
[[package]]
@ -191,7 +239,7 @@ dependencies = [
"indexmap",
"slab",
"tokio",
"tokio-util",
"tokio-util 0.6.9",
"tracing",
]
@ -203,12 +251,15 @@ checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "heck"
version = "0.3.3"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "http"
@ -218,7 +269,7 @@ checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
dependencies = [
"bytes",
"fnv",
"itoa",
"itoa 0.4.8",
]
[[package]]
@ -232,6 +283,12 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "http-range-header"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29"
[[package]]
name = "httparse"
version = "1.5.1"
@ -259,7 +316,7 @@ dependencies = [
"http-body",
"httparse",
"httpdate",
"itoa",
"itoa 0.4.8",
"pin-project-lite",
"socket2",
"tokio",
@ -305,6 +362,12 @@ version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "itoa"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -313,9 +376,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.107"
version = "0.2.124"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
[[package]]
name = "log"
@ -326,6 +389,12 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "matchit"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb"
[[package]]
name = "memchr"
version = "2.4.1"
@ -333,15 +402,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "mio"
version = "0.7.14"
name = "mime"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc"
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
[[package]]
name = "mio"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9"
dependencies = [
"libc",
"log",
"miow",
"ntapi",
"wasi 0.11.0+wasi-snapshot-preview1",
"winapi",
]
@ -390,9 +466,9 @@ dependencies = [
[[package]]
name = "pbjson"
version = "0.2.1"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12f64965beef9b7276dd811b81cce49569430a73ce1586aa121cb4ef9e0f498f"
checksum = "d86c0a61b93c50f35af5d8a4f134790f47cbebf8803a7219dd1e7238cd1af022"
dependencies = [
"base64",
"serde",
@ -400,9 +476,9 @@ dependencies = [
[[package]]
name = "pbjson-build"
version = "0.2.1"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d726efd7bfb8725c7100c29cb723eaa865b5e56cd41b723f193436e404c07f5"
checksum = "956a449e8a85fc040e9f8cd8fd4dd2e68059d179092401f0d8570ba059f76dae"
dependencies = [
"heck",
"itertools",
@ -412,9 +488,9 @@ dependencies = [
[[package]]
name = "pbjson-types"
version = "0.2.1"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d501adb5dc9774145e21cf497e62641d6b4c7f9db490c52388e26a0f966c7ea8"
checksum = "2c20bd6ec3b4ba0073e7e5a1a770abd95723b431bf0e1941d2dd8aace9ffb97f"
dependencies = [
"bytes",
"chrono",
@ -479,6 +555,16 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
[[package]]
name = "prettyplease"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b83ec2d0af5c5c556257ff52c9f98934e243b9fd39604bfb2a9b75ec2e97f18"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.32"
@ -490,9 +576,9 @@ dependencies = [
[[package]]
name = "prost"
version = "0.9.0"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001"
checksum = "a07b0857a71a8cb765763950499cae2413c3f9cede1133478c43600d9e146890"
dependencies = [
"bytes",
"prost-derive",
@ -500,11 +586,13 @@ dependencies = [
[[package]]
name = "prost-build"
version = "0.9.0"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5"
checksum = "120fbe7988713f39d780a58cf1a7ef0d7ef66c6d87e5aa3438940c05357929f4"
dependencies = [
"bytes",
"cfg-if",
"cmake",
"heck",
"itertools",
"lazy_static",
@ -520,9 +608,9 @@ dependencies = [
[[package]]
name = "prost-derive"
version = "0.9.0"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe"
checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc"
dependencies = [
"anyhow",
"itertools",
@ -533,9 +621,9 @@ dependencies = [
[[package]]
name = "prost-types"
version = "0.9.0"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a"
checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68"
dependencies = [
"bytes",
"prost",
@ -601,12 +689,10 @@ dependencies = [
[[package]]
name = "regex"
version = "1.5.4"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
@ -653,9 +739,9 @@ checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
[[package]]
name = "socket2"
version = "0.4.2"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516"
checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0"
dependencies = [
"libc",
"winapi",
@ -663,15 +749,21 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.81"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "sync_wrapper"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8"
[[package]]
name = "tempfile"
version = "3.2.0"
@ -686,28 +778,18 @@ dependencies = [
"winapi",
]
[[package]]
name = "time"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "tokio"
version = "1.14.0"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144"
checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee"
dependencies = [
"autocfg",
"bytes",
"libc",
"memchr",
"mio",
"pin-project-lite",
"socket2",
"tokio-macros",
"winapi",
]
@ -724,9 +806,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
version = "1.6.0"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9efc1aba077437943f7515666aa2b882dfabfbfdf89c819ea75a8d6e9eaba5e"
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
dependencies = [
"proc-macro2",
"quote",
@ -759,13 +841,28 @@ dependencies = [
]
[[package]]
name = "tonic"
version = "0.6.1"
name = "tokio-util"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24203b79cf2d68909da91178db3026e77054effba0c5d93deb870d3ca7b35afa"
checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite",
"tokio",
"tracing",
]
[[package]]
name = "tonic"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30fb54bf1e446f44d870d260d99957e7d11fb9d0a0f5bd1a662ad1411cc103f9"
dependencies = [
"async-stream",
"async-trait",
"axum",
"base64",
"bytes",
"futures-core",
@ -781,7 +878,7 @@ dependencies = [
"prost-derive",
"tokio",
"tokio-stream",
"tokio-util",
"tokio-util 0.7.1",
"tower",
"tower-layer",
"tower-service",
@ -791,10 +888,11 @@ dependencies = [
[[package]]
name = "tonic-build"
version = "0.6.0"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88358bb1dcfeb62dcce85c63006cafb964b7be481d522b7e09589d4d1e718d2a"
checksum = "4d17087af5c80e5d5fc8ba9878e60258065a0a757e35efe7a05b7904bece1943"
dependencies = [
"prettyplease",
"proc-macro2",
"prost-build",
"quote",
@ -803,9 +901,9 @@ dependencies = [
[[package]]
name = "tower"
version = "0.4.10"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c00e500fff5fa1131c866b246041a6bf96da9c965f8fe4128cb1421f23e93c00"
checksum = "9a89fd63ad6adf737582df5db40d286574513c69a11dac5214dc3b5603d6713e"
dependencies = [
"futures-core",
"futures-util",
@ -815,13 +913,31 @@ dependencies = [
"rand",
"slab",
"tokio",
"tokio-stream",
"tokio-util",
"tokio-util 0.7.1",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-http"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aba3f3efabf7fb41fae8534fc20a817013dd1c12cb45441efb6c82e6556b4cd8"
dependencies = [
"bitflags",
"bytes",
"futures-core",
"futures-util",
"http",
"http-body",
"http-range-header",
"pin-project-lite",
"tower",
"tower-layer",
"tower-service",
]
[[package]]
name = "tower-layer"
version = "0.3.1"
@ -883,12 +999,6 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]]
name = "unicode-xid"
version = "0.2.2"
@ -911,6 +1021,12 @@ version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "which"
version = "4.2.2"

2
api/rust/Cargo.toml vendored
View File

@ -18,6 +18,8 @@ prost = "0.10"
prost-types = "0.10"
pbjson = "0.3"
pbjson-types = "0.3"
hex = "0.4"
rand = "0.8"
tonic = { version = "0.7", features = ["codegen", "prost"], default-features = false }
tokio = { version = "1.17", features = ["macros"], optional = true }

View File

@ -16,10 +16,10 @@ message UplinkFrameLog {
bytes phy_payload = 1;
// TX meta-data.
gw.UplinkTXInfo tx_info = 2;
gw.UplinkTxInfo tx_info = 2;
// RX meta-data.
repeated gw.UplinkRXInfo rx_info = 3;
repeated gw.UplinkRxInfo rx_info = 3;
// Message type.
common.MType m_type = 4;
@ -42,10 +42,10 @@ message DownlinkFrameLog {
bytes phy_payload = 2;
// TX meta-data.
gw.DownlinkTXInfo tx_info = 3;
gw.DownlinkTxInfo tx_info = 3;
// Downlink ID (UUID).
string downlink_id = 4;
// Downlink ID.
uint32 downlink_id = 4;
// Gateway ID (EUI64).
string gateway_id = 5;

View File

@ -10,8 +10,17 @@ option java_outer_classname = "GatewayProto";
import "common/common.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/struct.proto";
enum CodeRate {
CR_UNDEFINED = 0;
CR_4_5 = 1;
CR_4_6 = 2;
CR_4_7 = 3;
CR_4_8 = 4;
}
enum DownlinkTiming {
// Send the downlink immediately.
IMMEDIATELY = 0;
@ -23,7 +32,6 @@ enum DownlinkTiming {
GPS_EPOCH = 2;
}
enum FineTimestampType {
// No fine-timestamp available.
NONE = 0;
@ -84,17 +92,17 @@ enum TxAckStatus {
message Modulation {
oneof parameters {
// LoRa modulation information.
LoRaModulationInfo lora = 3 [json_name = "loRa"];
LoraModulationInfo lora = 3;
// FSK modulation information.
FSKModulationInfo fsk = 4;
FskModulationInfo fsk = 4;
// LR-FHSS modulation information.
LRFHSSModulationInfo lr_fhss = 5 [json_name = "lrFHSS"];
LrFhssModulationInfo lr_fhss = 5;
}
}
message UplinkTXInfo {
message UplinkTxInfoLegacy {
// Frequency (Hz).
uint32 frequency = 1;
@ -103,17 +111,25 @@ message UplinkTXInfo {
oneof modulation_info {
// LoRa modulation information.
LoRaModulationInfo lora_modulation_info = 3 [json_name = "loRaModulationInfo"];
LoraModulationInfo lora_modulation_info = 3;
// FSK modulation information.
FSKModulationInfo fsk_modulation_info = 4;
FskModulationInfo fsk_modulation_info = 4;
// LR-FHSS modulation information.
LRFHSSModulationInfo lr_fhss_modulation_info = 5 [json_name = "lrFHSSModulationInfo"];
LrFhssModulationInfo lr_fhss_modulation_info = 5;
}
}
message LoRaModulationInfo {
message UplinkTxInfo {
// Frequency (Hz).
uint32 frequency = 1;
// Modulation.
Modulation modulation = 2;
}
message LoraModulationInfo {
// Bandwidth.
uint32 bandwidth = 1;
@ -121,13 +137,16 @@ message LoRaModulationInfo {
uint32 spreading_factor = 2;
// Code-rate.
string code_rate = 3;
string code_rate_legacy = 3;
// Code-rate.
CodeRate code_rate = 5;
// Polarization inversion.
bool polarization_inversion = 4;
}
message FSKModulationInfo {
message FskModulationInfo {
// Frequency deviation.
uint32 frequency_deviation = 1;
@ -135,7 +154,7 @@ message FSKModulationInfo {
uint32 datarate = 2;
}
message LRFHSSModulationInfo {
message LrFhssModulationInfo {
// Operating channel width (OCW) in Hz.
uint32 operating_channel_width = 1;
@ -151,10 +170,10 @@ message EncryptedFineTimestamp {
uint32 aes_key_index = 1;
// Encrypted 'main' fine-timestamp (ns precision part of the timestamp).
bytes encrypted_ns = 2 [json_name = "encryptedNS"];
bytes encrypted_ns = 2;
// FPGA ID.
bytes fpga_id = 3 [json_name = "fpgaID"];
bytes fpga_id = 3;
}
message PlainFineTimestamp {
@ -164,7 +183,7 @@ message PlainFineTimestamp {
message GatewayStats {
// Gateway ID.
bytes gateway_id = 1 [json_name = "gatewayID"];
bytes gateway_id = 1;
// Gateway IP.
string ip = 9;
@ -183,7 +202,7 @@ message GatewayStats {
uint32 rx_packets_received = 5;
// Number of radio packets received with valid PHY CRC.
uint32 rx_packets_received_ok = 6 [json_name = "rxPacketsReceivedOK"];
uint32 rx_packets_received_ok = 6;
// Number of downlink packets received for transmission.
uint32 tx_packets_received = 7;
@ -196,7 +215,7 @@ message GatewayStats {
// Stats ID (UUID).
// Unique identifier for the gateway stats.
bytes stats_id = 11 [json_name = "statsID"];
bytes stats_id = 11;
// Tx packets per frequency.
map<uint32, uint32> tx_packets_per_frequency = 12;
@ -222,21 +241,21 @@ message PerModulationCount {
uint32 count = 2;
}
message UplinkRXInfo {
message UplinkRxInfoLegacy {
// Gateway ID.
bytes gateway_id = 1 [json_name = "gatewayID"];
bytes gateway_id = 1;
// RX time (only set when the gateway has a GPS module).
google.protobuf.Timestamp time = 2;
// RX time since GPS epoch (only set when the gateway has a GPS module).
google.protobuf.Duration time_since_gps_epoch = 3 [json_name = "timeSinceGPSEpoch"];
google.protobuf.Duration time_since_gps_epoch = 3;
// RSSI.
int32 rssi = 5;
// LoRa SNR.
double lora_snr = 6 [json_name = "loRaSNR"];
double lora_snr = 6;
// Channel.
uint32 channel = 7;
@ -270,19 +289,60 @@ message UplinkRXInfo {
// Uplink ID (UUID bytes).
// Unique and random ID which can be used to correlate the uplink across multiple logs.
bytes uplink_id = 16 [json_name = "uplinkID"];
bytes uplink_id = 16;
// CRC status.
CRCStatus crc_status = 17 [json_name = "crcStatus"];
CRCStatus crc_status = 17;
// Optional meta-data map.
map<string, string> metadata = 18;
}
message DownlinkTXInfo {
message UplinkRxInfo {
// Gateway ID.
string gateway_id = 1;
// Uplink ID.
uint32 uplink_id = 2;
// RX time (only set when the gateway has a GPS module).
google.protobuf.Timestamp time = 3;
// RX time since GPS epoch (only set when the gateway has a GPS module).
google.protobuf.Duration time_since_gps_epoch = 4;
// Fine-timestamp.
// This timestamp can be used for TDOA based geolocation.
google.protobuf.Duration fine_time_since_gps_epoch = 5;
// RSSI.
int32 rssi = 6;
// SNR.
// Note: only available for LoRa modulation.
float snr = 7;
// Board.
uint32 board = 8;
// Antenna.
uint32 antenna = 9;
// Location.
common.Location location = 10;
// Gateway specific context.
// This value must be returned to the gateway on (Class-A) downlink.
bytes context = 11;
// Properties.
google.protobuf.Struct metadata = 12;
}
message DownlinkTxInfoLegacy {
// Gateway ID.
// Deprecated: replaced by gateway_id in DownlinkFrame.
bytes gateway_id = 1 [json_name = "gatewayID"];
bytes gateway_id = 1;
// TX frequency (in Hz).
uint32 frequency = 5;
@ -295,10 +355,10 @@ message DownlinkTXInfo {
oneof modulation_info {
// LoRa modulation information.
LoRaModulationInfo lora_modulation_info = 8 [json_name = "loRaModulationInfo"];
LoraModulationInfo lora_modulation_info = 8;
// FSK modulation information.
FSKModulationInfo fsk_modulation_info = 9;
FskModulationInfo fsk_modulation_info = 9;
}
// The board identifier for emitting the frame.
@ -326,6 +386,43 @@ message DownlinkTXInfo {
bytes context = 16;
}
message DownlinkTxInfo {
// TX frequency (in Hz).
uint32 frequency = 1;
// TX power (in dBm).
int32 power = 2;
// Modulation.
Modulation modulation = 3;
// The board identifier for emitting the frame.
uint32 board = 4;
// The antenna identifier for emitting the frame.
uint32 antenna = 5;
// Timing.
Timing timing = 6;
// Gateway specific context.
// In case of a Class-A downlink, this contains a copy of the uplink context.
bytes context = 7;
}
message Timing {
oneof parameters {
// Immediately timing information.
ImmediatelyTimingInfo immediately = 1;
// Context based delay timing information.
DelayTimingInfo delay = 2;
// GPS Epoch timing information.
GPSEpochTimingInfo gps_epoch = 3;
}
}
message ImmediatelyTimingInfo {
// Not implemented yet.
}
@ -339,18 +436,24 @@ message DelayTimingInfo {
message GPSEpochTimingInfo {
// Duration since GPS Epoch.
google.protobuf.Duration time_since_gps_epoch = 1 [json_name = "timeSinceGPSEpoch"];
google.protobuf.Duration time_since_gps_epoch = 1;
}
message UplinkFrame {
// PHYPayload.
bytes phy_payload = 1;
// TX meta-data.
UplinkTXInfo tx_info = 2;
// TX meta-data (deprecated).
UplinkTxInfoLegacy tx_info_legacy = 2;
// RX meta-data.
UplinkRXInfo rx_info = 3;
// RX meta-data (deprecated).
UplinkRxInfoLegacy rx_info_legacy = 3;
// Tx meta-data.
UplinkTxInfo tx_info = 4;
// Rx meta-data.
UplinkRxInfo rx_info = 5;
}
message UplinkFrameSet {
@ -358,27 +461,19 @@ message UplinkFrameSet {
bytes phy_payload = 1;
// TX meta-data.
UplinkTXInfo tx_info = 2;
UplinkTxInfo tx_info = 2;
// RX meta-data set.
repeated UplinkRXInfo rx_info = 3;
repeated UplinkRxInfo rx_info = 3;
}
message DownlinkFrame {
// PHYPayload.
// Deprecated: replaced by items.
bytes phy_payload = 1;
// TX meta-data.
// Deprecated: replaced by items.
DownlinkTXInfo tx_info = 2;
// Token (uint16 value).
// Deprecated: replaced by downlink_id.
uint32 token = 3;
// Downlink ID.
uint32 downlink_id = 3;
// Downlink ID (UUID).
bytes downlink_id = 4 [json_name = "downlinkID"];
// Deprecated: use downlink_id.
bytes downlink_id_legacy = 4;
// Downlink frame items.
// This makes it possible to send multiple downlink opportunities to the
@ -388,47 +483,52 @@ message DownlinkFrame {
repeated DownlinkFrameItem items = 5;
// Gateway ID.
bytes gateway_id = 6 [json_name = "gatewayID"];
// Deprecated: use gateway_id
bytes gateway_id_legacy = 6;
// Gateway ID.
string gateway_id = 7;
}
message DownlinkFrameItem {
// PHYPayload.
bytes phy_payload = 1;
// TX meta-data.
DownlinkTXInfo tx_info = 2;
// TX meta-data (deprecated).
DownlinkTxInfoLegacy tx_info_legacy = 2;
// Tx meta-data.
DownlinkTxInfo tx_info = 3;
}
message DownlinkTXAck {
message DownlinkTxAck {
// Gateway ID (deprecated).
bytes gateway_id_legacy = 1;
// Gateway ID.
bytes gateway_id = 1 [json_name = "gatewayID"];
string gateway_id = 6;
// Token (uint16 value).
// Deprecated: replaced by downlink_id.
uint32 token = 2;
// Downlink ID.
uint32 downlink_id = 2;
// Error.
// Deprecated: replaced by items.
string error = 3;
// Downlink ID (UUID).
bytes downlink_id = 4 [json_name = "downlinkID"];
// Downlink ID (deprecated).
bytes downlink_id_legacy = 4;
// Downlink frame items.
// This list has the same length as the request and indicates which
// downlink frame has been emitted of the requested list (or why it failed).
// Note that at most one item has a positive acknowledgement.
repeated DownlinkTXAckItem items = 5;
repeated DownlinkTxAckItem items = 5;
}
message DownlinkTXAckItem {
message DownlinkTxAckItem {
// The Ack status of this item.
TxAckStatus status = 1;
}
message GatewayConfiguration {
// Gateway ID.
bytes gateway_id = 1 [json_name = "gatewayID"];
bytes gateway_id = 1;
// Configuration version.
string version = 2;
@ -449,7 +549,7 @@ message ChannelConfiguration {
oneof modulation_config {
// LoRa modulation config.
LoRaModulationConfig lora_modulation_config = 3 [json_name = "loRaModulationConfig"];
LoRaModulationConfig lora_modulation_config = 3;
// FSK modulation config.
FSKModulationConfig fsk_modulation_config = 4;
@ -480,7 +580,7 @@ message FSKModulationConfig {
message GatewayCommandExecRequest {
// Gateway ID.
bytes gateway_id = 1 [json_name = "gatewayID"];
bytes gateway_id = 1;
// Command to execute.
// This command must be pre-configured in the LoRa Gateway Bridge configuration.
@ -489,7 +589,7 @@ message GatewayCommandExecRequest {
// Execution request ID (UUID).
// The same token will be returned when the execution of the command has
// completed.
bytes ExecId = 3 [json_name = "execID"];
bytes ExecId = 3;
// Standard input.
bytes stdin = 4;
@ -500,10 +600,10 @@ message GatewayCommandExecRequest {
message GatewayCommandExecResponse {
// Gateway ID.
bytes gateway_id = 1 [json_name = "gatewayID"];
bytes gateway_id = 1;
// Execution request ID (UUID).
bytes exec_id = 2 [json_name = "execID"];
bytes exec_id = 2;
// Standard output.
bytes stdout = 3;
@ -520,10 +620,10 @@ message GatewayCommandExecResponse {
// integrated with the ChirpStack Gateway Bridge.
message RawPacketForwarderEvent {
// Gateway ID.
bytes gateway_id = 1 [json_name = "gatewayID"];
bytes gateway_id = 1;
// Raw ID (UUID).
bytes raw_id = 2 [json_name = "rawID"];
bytes raw_id = 2;
// Payload contains the raw payload.
bytes payload = 3;
@ -534,10 +634,10 @@ message RawPacketForwarderEvent {
// integrated with the ChirpStack Gateway Bridge.
message RawPacketForwarderCommand {
// Gateway ID.
bytes gateway_id = 1 [json_name = "gatewayID"];
bytes gateway_id = 1;
// Raw ID (UUID).
bytes raw_id = 2 [json_name = "rawID"];
bytes raw_id = 2;
// Payload contains the raw payload.
bytes payload = 3;
@ -546,7 +646,7 @@ message RawPacketForwarderCommand {
// ConnState contains the connection state of a gateway.
message ConnState {
// Gateway ID.
bytes gateway_id = 1 [json_name = "gatewayID"];
bytes gateway_id = 1;
enum State {
OFFLINE = 0;

View File

@ -1,202 +0,0 @@
syntax = "proto3";
package gw;
option go_package = "github.com/chirpstack/chirpstack/api/go/v4/gw";
option java_package = "io.chirpstack.api.gw";
option java_multiple_files = true;
option java_outer_classname = "GatewayProto";
import "common/common.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/struct.proto";
enum CodeRate {
CR_UNDEFINED = 0;
CR_4_5 = 1;
CR_4_6 = 2;
CR_4_7 = 3;
CR_4_8 = 4;
}
message UplinkFrame {
// PHYPayload.
bytes phy_payload = 1;
// TX meta-data.
UplinkTxParams tx_params = 2;
// RX meta-data.
UplinkRxParams rx_params = 3;
}
message DownlinkFrame {
// Gateway ID.
string gateway_id = 1;
// Downlink ID.
uint32 downlink_id = 2;
// Downlink frame items.
// This makes it possible to send multiple downlink opportunities to the
// gateway at once (e.g. RX1 and RX2 in LoRaWAN). The first item has the
// highest priority, the last the lowest. The gateway will emit at most
// one item.
repeated DownlinkFrameItem items = 3;
}
message UplinkTxParams {
// Frequency (Hz).
uint32 frequency = 1;
// Modulation.
Modulation modulation = 2;
}
message Modulation {
oneof parameters {
// LoRa.
LoraModulationParams lora = 1;
// FSK.
FskModulationParams fsk = 2;
// LR-FHSS.
LrFhssModulationParams lr_fhss = 3;
}
}
message LoraModulationParams {
// Bandwidth (Hz).
uint32 bandwidth = 1;
// Spreading-factor.
uint32 spreading_factor = 2;
// Polarization inversion.
bool polarization_inversion = 3;
// Code-rate.
CodeRate code_rate = 4;
}
message FskModulationParams {
// Frequency deviation.
uint32 frequency_deviation = 1;
// FSK datarate (bits / sec).
uint32 datarate = 2;
}
message LrFhssModulationParams {
// Operating channel width (OCW) in Hz.
uint32 operating_channel_width = 1;
// Code-rate.
CodeRate code_rate = 2;
// Hopping grid number of steps.
uint32 grid_steps = 3;
}
message UplinkRxParams {
// Gateway ID (EUI).
string gateway_id = 1;
// Uplink ID (UUID).
uint32 uplink_id = 2;
// Rx time.
google.protobuf.Timestamp time = 3;
// RX time since GPS epoch (only set when the gateway has a GPS module).
google.protobuf.Duration time_since_gps_epoch = 4;
// Fine-timestamp.
// This timestamp can be used for TDOA based geolocation.
google.protobuf.Duration fine_time_since_gps_epoch = 5;
// RSSI.
int32 rssi = 6;
// SNR.
// Note: only available for LoRa modulation.
float snr = 7;
// Board.
uint32 board = 8;
// Antenna.
uint32 antenna = 9;
// Location.
common.Location location = 10;
// Gateway specific context.
// This value must be returned to the gateway on (Class-A) downlink.
bytes context = 11;
// Properties.
google.protobuf.Struct properties = 12;
}
message DownlinkFrameItem {
// PHYPayload.
bytes phy_payload = 1;
// Tx parameters.
DownlinkTxParams tx_params = 2;
}
message DownlinkTxParams {
// Tx frequency (Hz).
uint32 frequency = 1;
// Tx power (dBm).
int32 power = 2;
// Modulation.
Modulation modulation = 3;
// The board identifier for emitting the frame.
uint32 board = 4;
// The antenna identifier for emitting the frame.
uint32 antenna = 5;
// Downlink timing.
DownlinkTiming timing = 6;
// Gateway specific context.
// In case of a Class-A downlink, this must contain a copy of the uplink context.
bytes context = 7;
}
message DownlinkTiming {
oneof parameters {
// Immediately timing information.
DownlinkTimingImmediately immediately = 1;
// Delay timing information.
DownlinkTimingDelay delay = 2;
// GPS epoch timing information.
DownlinkTimingGpsEpoch gps_epoch = 3;
}
}
message DownlinkTimingImmediately {
// No fields implemented yet.
}
message DownlinkTimingDelay {
// Delay relative to provided context.
google.protobuf.Duration delay = 1;
}
message DownlinkTimingGpsEpoch {
// Duration since GPS epoch.
google.protobuf.Duration time_since_gps_epoch = 1;
}

View File

@ -119,10 +119,10 @@ message UplinkEvent {
google.protobuf.Struct object = 11;
// Receiving gateway RX info.
repeated gw.UplinkRXInfo rx_info = 12;
repeated gw.UplinkRxInfo rx_info = 12;
// TX info.
gw.UplinkTXInfo tx_info = 13;
gw.UplinkTxInfo tx_info = 13;
}
// JoinEvent is the message sent when a device joined the network.
@ -167,8 +167,8 @@ message AckEvent {
// for transmission. As a downlink can be scheduled in the future, this event
// does not confirm that the message has already been transmitted.
message TxAckEvent {
// Downlink ID (UUID).
string downlink_id = 1;
// Downlink ID.
uint32 downlink_id = 1;
// Timestamp.
google.protobuf.Timestamp time = 2;
@ -186,7 +186,7 @@ message TxAckEvent {
string gateway_id = 6;
// TX info.
gw.DownlinkTXInfo tx_info = 7;
gw.DownlinkTxInfo tx_info = 7;
}
// LogEvent is the message sent when a device-related log was sent.

View File

@ -199,8 +199,8 @@ message DeviceGatewayRxInfoItem {
}
message DownlinkFrame {
// Downlink ID (UUID).
bytes downlink_id = 1;
// Downlink ID.
uint32 downlink_id = 1;
// DevEUI.
bytes dev_eui = 2;
@ -231,5 +231,5 @@ message LoraCloudGeolocBuffer {
message LoraCloudGeolocBufferUplink {
// RxInfo set for a single uplink.
repeated gw.UplinkRXInfo rx_info = 1;
repeated gw.UplinkRxInfo rx_info = 1;
}

View File

@ -16,10 +16,10 @@ message UplinkMeta {
string dev_eui = 1;
// TX meta-data.
gw.UplinkTXInfo tx_info = 2;
gw.UplinkTxInfo tx_info = 2;
// RX meta-data.
repeated gw.UplinkRXInfo rx_info = 3;
repeated gw.UplinkRxInfo rx_info = 3;
// PHYPayload byte count.
uint32 phy_payload_byte_count = 4;
@ -42,7 +42,7 @@ message DownlinkMeta {
string multicast_group_id = 2;
// TX meta-data.
gw.DownlinkTXInfo tx_info = 3;
gw.DownlinkTxInfo tx_info = 3;
// PHYPayload byte count.
uint32 phy_payload_byte_count = 4;

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

@ -1,3 +1,5 @@
use rand::Rng;
tonic::include_proto!("gw/gw");
include!(concat!(env!("OUT_DIR"), "/gw/gw.serde.rs"));
@ -20,3 +22,216 @@ impl Into<String> for TxAckStatus {
.to_string()
}
}
impl UplinkFrame {
pub fn v4_migrate(&mut self) {
if let Some(tx_info) = &self.tx_info_legacy {
if self.tx_info.is_none() {
self.tx_info = Some(UplinkTxInfo {
frequency: tx_info.frequency,
modulation: Some(Modulation {
parameters: tx_info.modulation_info.as_ref().map(|v| match v {
uplink_tx_info_legacy::ModulationInfo::LoraModulationInfo(info) => {
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_legacy: "".into(),
polarization_inversion: info.polarization_inversion,
})
}
uplink_tx_info_legacy::ModulationInfo::FskModulationInfo(info) => {
modulation::Parameters::Fsk(info.clone())
}
uplink_tx_info_legacy::ModulationInfo::LrFhssModulationInfo(info) => {
modulation::Parameters::LrFhss(info.clone())
}
}),
}),
});
self.tx_info_legacy = None;
}
}
if let Some(rx_info) = &self.rx_info_legacy {
if self.rx_info.is_none() {
let mut rng = rand::thread_rng();
self.rx_info = Some(UplinkRxInfo {
gateway_id: hex::encode(&rx_info.gateway_id),
uplink_id: rng.gen::<u32>(),
time: rx_info.time.clone(),
time_since_gps_epoch: rx_info.time_since_gps_epoch.clone(),
fine_time_since_gps_epoch: None,
rssi: rx_info.rssi,
snr: rx_info.lora_snr as f32,
board: rx_info.board,
antenna: rx_info.antenna,
location: rx_info.location.clone(),
context: rx_info.context.clone(),
metadata: Some(pbjson_types::Struct {
fields: rx_info
.metadata
.iter()
.map(|(k, v)| {
(
k.to_string(),
pbjson_types::Value {
kind: Some(pbjson_types::value::Kind::StringValue(
v.to_string(),
)),
},
)
})
.collect(),
}),
});
}
}
}
}
impl UplinkRxInfo {
pub fn get_metadata_string(&self, k: &str) -> Option<String> {
if let Some(v) = &self.metadata {
if let Some(v) = v.fields.get(k) {
if let Some(pbjson_types::value::Kind::StringValue(v)) = &v.kind {
return Some(v.clone());
}
}
}
None
}
pub fn set_metadata_string(&mut self, k: &str, v: &str) {
if self.metadata.is_none() {
self.metadata = Some(pbjson_types::Struct {
..Default::default()
});
}
if let Some(md) = &mut self.metadata {
md.fields.insert(
k.to_string(),
pbjson_types::Value {
kind: Some(pbjson_types::value::Kind::StringValue(v.to_string())),
},
);
}
}
}
impl DownlinkFrame {
pub fn v4_migrate(&mut self) {
self.gateway_id_legacy = hex::decode(&self.gateway_id).unwrap();
self.downlink_id_legacy = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
self.downlink_id_legacy
.extend_from_slice(&self.downlink_id.to_be_bytes());
for i in self.items.iter_mut() {
if i.tx_info_legacy.is_none() {
if let Some(tx_info) = &i.tx_info {
let mut tx_info_legacy = DownlinkTxInfoLegacy {
frequency: tx_info.frequency,
power: tx_info.power,
board: tx_info.board,
antenna: tx_info.antenna,
context: tx_info.context.clone(),
..Default::default()
};
if let Some(modulation) = &tx_info.modulation {
match &modulation.parameters {
Some(modulation::Parameters::Lora(v)) => {
tx_info_legacy.modulation = crate::common::Modulation::Lora.into();
tx_info_legacy.modulation_info = Some(
downlink_tx_info_legacy::ModulationInfo::LoraModulationInfo(
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(),
polarization_inversion: v.polarization_inversion,
..Default::default()
},
),
);
}
Some(modulation::Parameters::Fsk(v)) => {
tx_info_legacy.modulation = crate::common::Modulation::Fsk.into();
tx_info_legacy.modulation_info = Some(
downlink_tx_info_legacy::ModulationInfo::FskModulationInfo(
FskModulationInfo {
frequency_deviation: v.frequency_deviation,
datarate: v.datarate,
},
),
);
}
_ => {}
}
}
if let Some(timing) = &tx_info.timing {
match &timing.parameters {
Some(timing::Parameters::Immediately(v)) => {
tx_info_legacy.timing = DownlinkTiming::Immediately.into();
tx_info_legacy.timing_info = Some(
downlink_tx_info_legacy::TimingInfo::ImmediatelyTimingInfo(
v.clone(),
),
);
}
Some(timing::Parameters::Delay(v)) => {
tx_info_legacy.timing = DownlinkTiming::Delay.into();
tx_info_legacy.timing_info = Some(
downlink_tx_info_legacy::TimingInfo::DelayTimingInfo(v.clone()),
);
}
Some(timing::Parameters::GpsEpoch(v)) => {
tx_info_legacy.timing = DownlinkTiming::GpsEpoch.into();
tx_info_legacy.timing_info =
Some(downlink_tx_info_legacy::TimingInfo::GpsEpochTimingInfo(
v.clone(),
));
}
_ => {}
}
}
i.tx_info_legacy = Some(tx_info_legacy);
}
}
}
}
}
impl DownlinkTxAck {
pub fn v4_migrate(&mut self) {
if self.gateway_id.is_empty() {
self.gateway_id = hex::encode(&self.gateway_id_legacy);
}
if self.downlink_id == 0 && self.downlink_id_legacy.len() == 16 {
self.downlink_id = u32::from_be_bytes([
self.downlink_id_legacy[12],
self.downlink_id_legacy[13],
self.downlink_id_legacy[14],
self.downlink_id_legacy[15],
])
}
}
}