Compare commits

...

50 Commits

Author SHA1 Message Date
aec51d2229 Bump tower-http from 0.6.4 to 0.6.6
Bumps [tower-http](https://github.com/tower-rs/tower-http) from 0.6.4 to 0.6.6.
- [Release notes](https://github.com/tower-rs/tower-http/releases)
- [Commits](https://github.com/tower-rs/tower-http/compare/tower-http-0.6.4...tower-http-0.6.6)

---
updated-dependencies:
- dependency-name: tower-http
  dependency-version: 0.6.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-09 03:59:29 +00:00
8804f774fb lrwn-filters: Update m_type > f_type.
Some checks failed
CI / tests (postgres) (push) Has been cancelled
CI / tests (sqlite) (push) Has been cancelled
CI / dist (postgres) (push) Has been cancelled
CI / dist (sqlite) (push) Has been cancelled
2025-06-02 12:13:51 +01:00
3a0de8196f Rename m_type > f_type to align with LW 1.0.4 naming. 2025-06-02 12:02:32 +01:00
46bb01ccdc Sort NULL values as smallest value (devices and gateways last seen).
Some checks failed
CI / tests (postgres) (push) Has been cancelled
CI / tests (sqlite) (push) Has been cancelled
CI / dist (postgres) (push) Has been cancelled
CI / dist (sqlite) (push) Has been cancelled
Fixes #683.
2025-05-26 14:50:26 +01:00
26cca09ce8 Fix custom root ca certificates not taken into account (#684) 2025-05-26 14:03:37 +01:00
c016cd1f7d Update dependencies. 2025-05-26 14:02:39 +01:00
1ead82e8a5 Bump golang.org/x/net from 0.36.0 to 0.38.0 in /api/go (#653)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.36.0 to 0.38.0.
- [Commits](https://github.com/golang/net/compare/v0.36.0...v0.38.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.38.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-26 13:51:30 +01:00
e8d001441c Bump version to 4.13.0-test.1
Some checks failed
CI / tests (postgres) (push) Has been cancelled
CI / tests (sqlite) (push) Has been cancelled
CI / dist (postgres) (push) Has been cancelled
CI / dist (sqlite) (push) Has been cancelled
2025-05-23 09:36:26 +01:00
10e7907251 Generate API code. 2025-05-23 09:30:16 +01:00
39df55afb4 MeshCommand does not need a timestamp. 2025-05-23 09:14:57 +01:00
038e45e8f0 api: Rename Mesh to MeshEvent.
This is needed as we are also adding commands, thus we need MeshEvent
and MeshCommand messages.
2025-05-23 09:14:57 +01:00
5cf1120f20 Update gw proto & refactor Mesh Heartbeat event.
This refactors the gateway protobuf payloads, such that the
Concentratord can publish an Event message, containing one of the
possible events published by the Concentratord (uplink, stats or mesh
event). It also combines the possible Concentratord commands into a
single Command message. This simplifies the ZMQ interface as it is no
longer needed to match the payload type by string.

This also refactors the MeshHeartbeat message into a Mesh message, which
can contain multiple events, of which the Heartbeat is one of the
possible events.

The future goal is to make it possible to send different types of events
from the Gateway Mesh Relay gateways (e.g. battery status, ...) and to
make it possible to also send proprietary event types.
2025-05-23 09:14:57 +01:00
b8e14058f2 Geplace GETDEL by pipelined GET and DEL commands. (#682)
Some checks failed
CI / tests (postgres) (push) Has been cancelled
CI / tests (sqlite) (push) Has been cancelled
CI / dist (postgres) (push) Has been cancelled
CI / dist (sqlite) (push) Has been cancelled
GETDEL was added in Redis 6.2, but is unfortunately not supported on all Azure Cache for Redis tiers.

Fixes #680.
2025-05-21 10:15:05 +01:00
10731c2be5 Make amqp integration exchange configurable (#677) 2025-05-21 09:45:19 +01:00
f1d46b1bc9 Update scheduler_run_after at device-session get.
Some checks failed
CI / tests (postgres) (push) Has been cancelled
CI / tests (sqlite) (push) Has been cancelled
CI / dist (postgres) (push) Has been cancelled
CI / dist (sqlite) (push) Has been cancelled
This moves the setting of the scheduler_run_after to the function to get
the device-session based on provided PHYPayload. This way we reduce the
risk of overlapping Class-B / -C downlinks with a Class-A downlink, as
we update the scheduler_run_after during the "FOR UPDATE" transaction.
This also reduces one SQL query, as we combine it with the updating of
the device-session query (to update the uplink FCnt value).
2025-05-12 11:05:02 +01:00
c954cd3645 Store temp. mac-command state in device-session.
Some checks failed
CI / tests (postgres) (push) Has been cancelled
CI / tests (sqlite) (push) Has been cancelled
CI / dist (postgres) (push) Has been cancelled
CI / dist (sqlite) (push) Has been cancelled
2025-05-09 14:27:25 +01:00
188ef3d8f3 Bump version to 4.12.1
Some checks failed
CI / tests (postgres) (push) Has been cancelled
CI / tests (sqlite) (push) Has been cancelled
CI / dist (postgres) (push) Has been cancelled
CI / dist (sqlite) (push) Has been cancelled
2025-05-02 11:16:19 +01:00
0cff864f60 ui: Remove CodeEditor reloadKey.
With the migration from codemirror to ace, this workaround is no longer
needed to correctly render the UI component.
2025-05-02 11:09:59 +01:00
156f42ab82 Bump version to 4.12.1-test.1
Some checks failed
CI / tests (postgres) (push) Has been cancelled
CI / tests (sqlite) (push) Has been cancelled
CI / dist (postgres) (push) Has been cancelled
CI / dist (sqlite) (push) Has been cancelled
2025-05-02 09:50:35 +01:00
c8b496d33f Update sqlite version in cross config. 2025-05-02 09:42:57 +01:00
8d2faf2d15 Update dependencies. 2025-05-02 09:42:24 +01:00
55d9ce0359 Bump vite from 6.2.6 to 6.2.7 in /ui (#668)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.6 to 6.2.7.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.2.7/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.7/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.2.7
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-02 08:52:27 +01:00
d002f5c97b ui: Format code.
Some checks failed
CI / tests (postgres) (push) Has been cancelled
CI / tests (sqlite) (push) Has been cancelled
CI / dist (postgres) (push) Has been cancelled
CI / dist (sqlite) (push) Has been cancelled
2025-04-28 10:18:44 +01:00
9cf12a187c ui: Clear tenant id after delete.
Fixes #635.
2025-04-28 10:18:05 +01:00
1b5e5972f4 ui: Fix JSON enqueue issue / code-editor render issue.
This fixes two issues:

- An error logged to the console when enqueueing a JSON downlink payload
(Q.Va is not a function).
- The codemirror editor has been replaced by ace, to solve a potential
rendering issue within ReactJS / Antd.

Closes #658.
2025-04-28 10:09:52 +01:00
330f5dcae0 Bump version to 4.12.0
Some checks failed
CI / tests (postgres) (push) Has been cancelled
CI / tests (sqlite) (push) Has been cancelled
CI / dist (postgres) (push) Has been cancelled
CI / dist (sqlite) (push) Has been cancelled
2025-04-22 09:01:31 +01:00
92b2439377 Bump version to 4.12.0-test.4
Some checks failed
CI / tests (postgres) (push) Has been cancelled
CI / tests (sqlite) (push) Has been cancelled
CI / dist (postgres) (push) Has been cancelled
CI / dist (sqlite) (push) Has been cancelled
2025-04-21 15:23:08 +01:00
6d084b3b21 Add option to pass auth. header to join-server.
Some checks failed
CI / tests (postgres) (push) Has been cancelled
CI / tests (sqlite) (push) Has been cancelled
CI / dist (postgres) (push) Has been cancelled
CI / dist (sqlite) (push) Has been cancelled
2025-04-16 10:55:08 +01:00
75e9106bbb Remove lazy_static dependency. 2025-04-16 09:51:49 +01:00
4ce4828a78 lrwn: Remove lazy_static dependency.
Some checks are pending
CI / tests (postgres) (push) Waiting to run
CI / tests (sqlite) (push) Waiting to run
CI / dist (postgres) (push) Blocked by required conditions
CI / dist (sqlite) (push) Blocked by required conditions
2025-04-15 16:06:03 +01:00
9ecf4fef1b ui: Update vite to v6.2.6. 2025-04-15 15:54:17 +01:00
8f9316af2c Bump golang.org/x/net from 0.33.0 to 0.36.0 in /examples/frame_log/go (#651)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.33.0 to 0.36.0.
- [Commits](https://github.com/golang/net/compare/v0.33.0...v0.36.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.36.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-15 15:28:32 +01:00
1f2a7d390a Bump vite from 5.4.12 to 5.4.18 in /ui (#652)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.4.12 to 5.4.18.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.4.18/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.18/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 5.4.18
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-15 15:28:19 +01:00
990bf57da5 Update dependencies. 2025-04-15 15:07:10 +01:00
b336690a65 Update tonic to 0.13. 2025-04-15 15:00:23 +01:00
7597bcaabf Replace tenant UUID by gen_random_uuid() in pg migration.
This should have been part of 5fd57de6ce.
2025-04-15 13:51:53 +01:00
0ae1294a63 Show origin in case of parse error.
Fixes #632.
2025-04-15 13:32:01 +01:00
8e0a29ed55 Update PostgreSQL to v13 in tests.
This is oldest version that is still supported.
2025-04-15 12:41:49 +01:00
5fd57de6ce Replace static UUID by gen_random_uuid() in pg migration.
Fixes #634.
2025-04-15 12:28:44 +01:00
d91fb77617 Install cargo-deb through shell.nix. 2025-04-15 11:29:01 +01:00
fa63c306fd Add default ADR example in JS. 2025-04-15 10:16:17 +01:00
7d1e85e575 Bump golang.org/x/net from 0.33.0 to 0.36.0 in /api/go (#639)
Some checks failed
CI / tests (postgres) (push) Has been cancelled
CI / tests (sqlite) (push) Has been cancelled
CI / dist (postgres) (push) Has been cancelled
CI / dist (sqlite) (push) Has been cancelled
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.33.0 to 0.36.0.
- [Commits](https://github.com/golang/net/compare/v0.33.0...v0.36.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-26 11:40:20 +00:00
e392f52444 Update prometheus-client dependency. 2025-03-26 11:34:22 +00:00
e30a2e0e77 Bump version to 4.12.0-test.3
Some checks are pending
CI / tests (postgres) (push) Waiting to run
CI / tests (sqlite) (push) Waiting to run
CI / dist (postgres) (push) Blocked by required conditions
CI / dist (sqlite) (push) Blocked by required conditions
2025-03-25 13:43:56 +00:00
b2adac5a49 Fix formatting (cargo fmt).
Some checks are pending
CI / tests (postgres) (push) Waiting to run
CI / tests (sqlite) (push) Waiting to run
CI / dist (postgres) (push) Blocked by required conditions
CI / dist (sqlite) (push) Blocked by required conditions
2025-03-25 13:13:41 +00:00
ca7b0a2e61 Fix sqlite migration typo. 2025-03-25 11:31:12 +00:00
849d27f148 Fix cargo clippy feedback. 2025-03-25 11:31:07 +00:00
5ce35eef5e ui: Disable start fuota deployment button once started.
Some checks are pending
CI / tests (postgres) (push) Waiting to run
CI / tests (sqlite) (push) Waiting to run
CI / dist (postgres) (push) Blocked by required conditions
CI / dist (sqlite) (push) Blocked by required conditions
2025-03-24 11:38:07 +00:00
236b468aa4 Store and increase TS004 session_cnt per device.
For TS004 v2.0.0, the session_cnt must be incremented for every
fragmentation-session.
2025-03-24 11:33:16 +00:00
c130be9dd0 Bump redis from 0.29.1 to 0.29.2 (#636)
Bumps [redis](https://github.com/redis-rs/redis-rs) from 0.29.1 to 0.29.2.
- [Release notes](https://github.com/redis-rs/redis-rs/releases)
- [Commits](https://github.com/redis-rs/redis-rs/compare/redis-0.29.1...redis-0.29.2)

---
updated-dependencies:
- dependency-name: redis
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-24 09:53:11 +00:00
143 changed files with 4622 additions and 3460 deletions

View File

@ -28,7 +28,7 @@ jobs:
name: Install Nix
uses: cachix/install-nix-action@v27
with:
nix_path: nixpkgs=channel:nixos-24.11
nix_path: nixpkgs=channel:nixos-25.05
-
name: Cargo cache
uses: actions/cache@v4
@ -69,7 +69,7 @@ jobs:
name: Install Nix
uses: cachix/install-nix-action@v27
with:
nix_path: nixpkgs=channel:nixos-24.11
nix_path: nixpkgs=channel:nixos-25.05
-
name: Cargo cache
uses: actions/cache@v4

1037
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -6,9 +6,7 @@ dist:
cd chirpstack && make dist
# Install dev dependencies
# TODO: test latest cargo-deb and move it to shell.nix.
dev-dependencies:
cargo install cargo-deb --version 1.43.1 --locked
cargo install cargo-generate-rpm --version 0.12.1 --locked
# Set the versions

7
api/go/go.mod vendored
View File

@ -1,6 +1,7 @@
module github.com/chirpstack/chirpstack/api/go/v4
go 1.21
toolchain go1.24.1
require (
google.golang.org/genproto/googleapis/api v0.0.0-20240325203815-454cdb8f5daa
@ -10,8 +11,8 @@ require (
require (
github.com/golang/protobuf v1.5.4 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/net v0.38.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240325203815-454cdb8f5daa // indirect
)

12
api/go/go.sum vendored
View File

@ -2,12 +2,12 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
google.golang.org/genproto/googleapis/api v0.0.0-20240325203815-454cdb8f5daa h1:Jt1XW5PaLXF1/ePZrznsh/aAUvI7Adfc3LY1dAKlzRs=
google.golang.org/genproto/googleapis/api v0.0.0-20240325203815-454cdb8f5daa/go.mod h1:K4kfzHtI0kqWA79gecJarFtDn/Mls+GxQcg3Zox91Ac=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240325203815-454cdb8f5daa h1:RBgMaUMP+6soRkik4VoN8ojR2nex2TqZwjSSogic+eo=

2532
api/go/gw/gw.pb.go vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,16 @@
{
"name": "@chirpstack/chirpstack-api-grpc-web",
"version": "4.12.0-test.2",
"version": "4.13.0-test.1",
"description": "Chirpstack gRPC-web API",
"license": "MIT",
"devDependencies": {
"grpc-tools": "^1.12.4",
"grpc-tools": "^1.13.0",
"ts-protoc-gen": "^0.15.0",
"typescript": "^5.1.6"
"typescript": "^5.8.3"
},
"dependencies": {
"@types/google-protobuf": "^3.15.12",
"google-protobuf": "^3.21.2",
"google-protobuf": "^3.21.4",
"grpc-web": "^1.5.0"
}
}

View File

@ -146,15 +146,20 @@ glob@^7.1.3:
once "^1.3.0"
path-is-absolute "^1.0.0"
google-protobuf@^3.15.5, google-protobuf@^3.21.2:
google-protobuf@^3.15.5:
version "3.21.2"
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4"
integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==
grpc-tools@^1.12.4:
version "1.12.4"
resolved "https://registry.yarnpkg.com/grpc-tools/-/grpc-tools-1.12.4.tgz#a044c9e8157941033ea7a5f144c2dc9dc4501de4"
integrity sha512-5+mLAJJma3BjnW/KQp6JBjUMgvu7Mu3dBvBPd1dcbNIb+qiR0817zDpgPjS7gRb+l/8EVNIa3cB02xI9JLToKg==
google-protobuf@^3.21.4:
version "3.21.4"
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.4.tgz#2f933e8b6e5e9f8edde66b7be0024b68f77da6c9"
integrity sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==
grpc-tools@^1.13.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/grpc-tools/-/grpc-tools-1.13.0.tgz#a4fea8eebce51fb9fec00055a3e52016dfd5af89"
integrity sha512-7CbkJ1yWPfX0nHjbYG58BQThNhbICXBZynzCUxCb3LzX5X9B3hQbRY2STiRgIEiLILlK9fgl0z0QVGwPCdXf5g==
dependencies:
"@mapbox/node-pre-gyp" "^1.0.5"
@ -376,10 +381,10 @@ ts-protoc-gen@^0.15.0:
dependencies:
google-protobuf "^3.15.5"
typescript@^5.1.6:
version "5.4.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.3.tgz#5c6fedd4c87bee01cd7a528a30145521f8e0feff"
integrity sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==
typescript@^5.8.3:
version "5.8.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e"
integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==
util-deprecate@^1.0.1:
version "1.0.2"

View File

@ -8,7 +8,7 @@ plugins {
}
group = "io.chirpstack"
version = "4.12.0-test.2"
version = "4.13.0-test.1"
repositories {
mavenCentral()

12
api/js/package.json vendored
View File

@ -1,17 +1,17 @@
{
"name": "@chirpstack/chirpstack-api",
"version": "4.12.0-test.2",
"version": "4.13.0-test.1",
"description": "Chirpstack JS and TS API",
"license": "MIT",
"devDependencies": {
"grpc-tools": "^1.12.4",
"grpc-tools": "^1.13.0",
"ts-protoc-gen": "^0.15.0",
"typescript": "^5.1.6"
"typescript": "^5.8.3"
},
"dependencies": {
"@grpc/grpc-js": "^1.10.4",
"@grpc/grpc-js": "^1.13.3",
"@mapbox/node-pre-gyp": "^1.0.11",
"@types/google-protobuf": "^3.15.6",
"google-protobuf": "^3.21.2"
"@types/google-protobuf": "^3.15.12",
"google-protobuf": "^3.21.4"
}
}

39
api/js/yarn.lock vendored
View File

@ -2,10 +2,10 @@
# yarn lockfile v1
"@grpc/grpc-js@^1.10.4":
version "1.10.9"
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.10.9.tgz#468cc1549a3fe37b760a16745fb7685d91f4f10c"
integrity sha512-5tcgUctCG0qoNyfChZifz2tJqbRbXVO9J7X6duFcOjY3HUNCxg5D0ZCK7EP9vIcZ0zRpLU9bWkyCqVCLZ46IbQ==
"@grpc/grpc-js@^1.13.3":
version "1.13.3"
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.13.3.tgz#6ad08d186c2a8651697085f790c5c68eaca45904"
integrity sha512-FTXHdOoPbZrBjlVLHuKbDZnsTxXv2BlHF57xw6LuThXacXvtkahEPED0CKMk6obZDf65Hv4k3z62eyPNpvinIg==
dependencies:
"@grpc/proto-loader" "^0.7.13"
"@js-sdsl/ordered-map" "^4.4.2"
@ -93,10 +93,10 @@
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
"@types/google-protobuf@^3.15.6":
version "3.15.6"
resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.15.6.tgz#674a69493ef2c849b95eafe69167ea59079eb504"
integrity sha512-pYVNNJ+winC4aek+lZp93sIKxnXt5qMkuKmaqS3WGuTq0Bw1ZDYNBgzG5kkdtwcv+GmYJGo3yEg6z2cKKAiEdw==
"@types/google-protobuf@^3.15.12":
version "3.15.12"
resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.15.12.tgz#eb2ba0eddd65712211a2b455dc6071d665ccf49b"
integrity sha512-40um9QqwHjRS92qnOaDpL7RmDK15NuZYo9HihiJRbYkMQZlWnuH8AdvbMy8/o6lgLmKbDUKa+OALCltHdbOTpQ==
"@types/node@>=13.7.0":
version "20.4.8"
@ -265,15 +265,20 @@ glob@^7.1.3:
once "^1.3.0"
path-is-absolute "^1.0.0"
google-protobuf@^3.15.5, google-protobuf@^3.21.2:
google-protobuf@^3.15.5:
version "3.21.2"
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4"
integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==
grpc-tools@^1.12.4:
version "1.12.4"
resolved "https://registry.yarnpkg.com/grpc-tools/-/grpc-tools-1.12.4.tgz#a044c9e8157941033ea7a5f144c2dc9dc4501de4"
integrity sha512-5+mLAJJma3BjnW/KQp6JBjUMgvu7Mu3dBvBPd1dcbNIb+qiR0817zDpgPjS7gRb+l/8EVNIa3cB02xI9JLToKg==
google-protobuf@^3.21.4:
version "3.21.4"
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.4.tgz#2f933e8b6e5e9f8edde66b7be0024b68f77da6c9"
integrity sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==
grpc-tools@^1.13.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/grpc-tools/-/grpc-tools-1.13.0.tgz#a4fea8eebce51fb9fec00055a3e52016dfd5af89"
integrity sha512-7CbkJ1yWPfX0nHjbYG58BQThNhbICXBZynzCUxCb3LzX5X9B3hQbRY2STiRgIEiLILlK9fgl0z0QVGwPCdXf5g==
dependencies:
"@mapbox/node-pre-gyp" "^1.0.5"
@ -523,10 +528,10 @@ ts-protoc-gen@^0.15.0:
dependencies:
google-protobuf "^3.15.5"
typescript@^5.1.6:
version "5.1.6"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274"
integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==
typescript@^5.8.3:
version "5.8.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e"
integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==
util-deprecate@^1.0.1:
version "1.0.2"

View File

@ -9,7 +9,7 @@ plugins {
}
group = "io.chirpstack"
version = "4.12.0-test.2"
version = "4.13.0-test.1"
repositories {
mavenCentral()

View File

@ -3,7 +3,7 @@
"description": "Chirpstack PHP API",
"license": "MIT",
"type": "library",
"version": "4.12.0-test.2",
"version": "4.13.0-test.1",
"require": {
"php": ">=7.0.0",
"grpc/grpc": "^v1.57.0",

View File

@ -67,7 +67,7 @@ enum Region {
ISM2400 = 11;
}
enum MType {
enum FType {
// JoinRequest.
JOIN_REQUEST = 0;

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

@ -104,6 +104,82 @@ enum TxAckStatus {
DUTY_CYCLE_OVERFLOW = 11;
}
// Gateway events as reported by the ChirpStack Concentratord ZMQ interface.
message Event {
oneof event {
// Uplink frame.
UplinkFrame uplink_frame = 1;
// Gateway stats.
GatewayStats gateway_stats = 2;
// Gateway Mesh Event.
MeshEvent mesh = 3;
}
}
// Commands that can be sent to the ChirpStack Concentratord ZMQ interface.
message Command {
oneof command {
// Downlink frame.
DownlinkFrame send_downlink_frame = 1;
// Gateway configuration.
GatewayConfiguration set_gateway_configuration = 2;
// Get Gateway ID.
GetGatewayIdRequest get_gateway_id = 3;
// Get location.
GetLocationRequest get_location = 4;
// Gateway Mesh Command.
MeshCommand mesh = 5;
}
}
message MeshEvent {
// Gateway ID (of the Border Gateway).
string gateway_id = 1;
// Relay ID.
string relay_id = 2;
// Timestamp (second precision).
google.protobuf.Timestamp time = 3;
// Mesh events.
repeated MeshEventItem events = 4;
}
message MeshEventItem {
oneof event {
// Proprietary Mesh event.
MeshEventProprietary proprietary = 1;
// Mesh heartbeat.
MeshEventHeartbeat heartbeat = 2;
}
}
message MeshCommand {
// Gateway ID (of the Border Gateway).
string gateway_id = 1;
// Relay ID.
string relay_id = 2;
// Mesh events.
repeated MeshCommandItem commands = 3;
}
message MeshCommandItem {
oneof command {
// Proprietary Mesh command.
MeshCommandProprietary proprietary = 1;
}
}
message Modulation {
oneof parameters {
// LoRa modulation information.
@ -611,6 +687,23 @@ message GatewayConfiguration {
google.protobuf.Duration stats_interval = 4;
}
message GetGatewayIdRequest {}
message GetGatewayIdResponse {
// Gateway ID.
string gateway_id = 1;
}
message GetLocationRequest {}
message GetLocationResponse {
// Location.
common.Location location = 1;
// Last updated at.
google.protobuf.Timestamp updated_at = 2;
}
message ChannelConfiguration {
// Frequency (Hz).
uint32 frequency = 1;
@ -751,21 +844,13 @@ message ConnState {
}
// Gateway Mesh heartbeat (sent periodically by the Relay Gateways).
message MeshHeartbeat {
// Gateway ID (of the Border Gateway).
string gateway_id = 1;
// Relay ID.
string relay_id = 2;
// Timestamp (second precision).
google.protobuf.Timestamp time = 3;
message MeshEventHeartbeat {
// Relay path.
repeated MeshHeartbeatRelayPath relay_path = 4;
repeated MeshEventHeartbeatRelayPath relay_path = 4;
}
message MeshHeartbeatRelayPath {
message MeshEventHeartbeatRelayPath {
// Relay ID.
string relay_id = 1;
@ -775,3 +860,21 @@ message MeshHeartbeatRelayPath {
// SNR.
int32 snr = 3;
}
// Proprietary mesh event.
message MeshEventProprietary {
// Event type.
uint32 event_type = 1;
// Payload.
bytes payload = 2;
}
// Proprietary mesh command.
message MeshCommandProprietary {
// Command type.
uint32 command_type = 1;
// Payload.
bytes payload = 2;
}

View File

@ -142,6 +142,9 @@ message DeviceSession {
// Relay state.
Relay relay = 41;
// Pending mac-commands.
map<uint32, bytes> mac_command_pending = 43;
}
message UplinkAdrHistory {

View File

@ -24,8 +24,8 @@ message UplinkFrameLog {
// RX meta-data.
repeated gw.UplinkRxInfo rx_info = 3;
// Message type.
common.MType m_type = 4;
// Frame type.
common.FType f_type = 4;
// Device address (optional).
string dev_addr = 5;
@ -59,8 +59,8 @@ message DownlinkFrameLog {
// Gateway ID (EUI64).
string gateway_id = 5;
// Message type.
common.MType m_type = 6;
// Frame type.
common.FType f_type = 6;
// Device address (optional).
string dev_addr = 7;

View File

@ -32,8 +32,8 @@ message UplinkMeta {
// Application payload byte count.
uint32 application_payload_byte_count = 6;
// Message type.
common.MType message_type = 7;
// Frame type.
common.FType frame_type = 7;
}
message DownlinkMeta {
@ -55,8 +55,8 @@ message DownlinkMeta {
// Application payload byte count.
uint32 application_payload_byte_count = 6;
// Message type.
common.MType message_type = 7;
// Frame type.
common.FType frame_type = 7;
// Gateway ID (EUI64).
string gateway_id = 8;

View File

@ -18,7 +18,7 @@ CLASSIFIERS = [
setup(
name='chirpstack-api',
version = "4.12.0-test.2",
version = "4.13.0-test.1",
url='https://github.com/brocaar/chirpstack-api',
author='Orne Brocaar',
author_email='info@brocaar.com',

6
api/rust/Cargo.toml vendored
View File

@ -1,7 +1,7 @@
[package]
name = "chirpstack_api"
description = "ChirpStack Protobuf / gRPC API definitions."
version = "4.12.0-test.2"
version = "4.13.0-test.1"
authors = ["Orne Brocaar <info@brocaar.com>"]
license = "MIT"
homepage = "https://www.chirpstack.io"
@ -19,7 +19,7 @@
prost-types = "0.13"
hex = "0.4"
rand = "0.9"
tonic = { version = "0.12", features = [
tonic = { version = "0.13", features = [
"codegen",
"prost",
], default-features = false, optional = true }
@ -29,7 +29,7 @@
serde = { version = "1.0", optional = true }
[build-dependencies]
tonic-build = { version = "0.12", features = [
tonic-build = { version = "0.13", features = [
"prost",
], default-features = false }
pbjson-build = "0.7"

View File

@ -67,7 +67,7 @@ enum Region {
ISM2400 = 11;
}
enum MType {
enum FType {
// JoinRequest.
JOIN_REQUEST = 0;

View File

@ -104,6 +104,82 @@ enum TxAckStatus {
DUTY_CYCLE_OVERFLOW = 11;
}
// Gateway events as reported by the ChirpStack Concentratord ZMQ interface.
message Event {
oneof event {
// Uplink frame.
UplinkFrame uplink_frame = 1;
// Gateway stats.
GatewayStats gateway_stats = 2;
// Gateway Mesh Event.
MeshEvent mesh = 3;
}
}
// Commands that can be sent to the ChirpStack Concentratord ZMQ interface.
message Command {
oneof command {
// Downlink frame.
DownlinkFrame send_downlink_frame = 1;
// Gateway configuration.
GatewayConfiguration set_gateway_configuration = 2;
// Get Gateway ID.
GetGatewayIdRequest get_gateway_id = 3;
// Get location.
GetLocationRequest get_location = 4;
// Gateway Mesh Command.
MeshCommand mesh = 5;
}
}
message MeshEvent {
// Gateway ID (of the Border Gateway).
string gateway_id = 1;
// Relay ID.
string relay_id = 2;
// Timestamp (second precision).
google.protobuf.Timestamp time = 3;
// Mesh events.
repeated MeshEventItem events = 4;
}
message MeshEventItem {
oneof event {
// Proprietary Mesh event.
MeshEventProprietary proprietary = 1;
// Mesh heartbeat.
MeshEventHeartbeat heartbeat = 2;
}
}
message MeshCommand {
// Gateway ID (of the Border Gateway).
string gateway_id = 1;
// Relay ID.
string relay_id = 2;
// Mesh events.
repeated MeshCommandItem commands = 3;
}
message MeshCommandItem {
oneof command {
// Proprietary Mesh command.
MeshCommandProprietary proprietary = 1;
}
}
message Modulation {
oneof parameters {
// LoRa modulation information.
@ -611,6 +687,23 @@ message GatewayConfiguration {
google.protobuf.Duration stats_interval = 4;
}
message GetGatewayIdRequest {}
message GetGatewayIdResponse {
// Gateway ID.
string gateway_id = 1;
}
message GetLocationRequest {}
message GetLocationResponse {
// Location.
common.Location location = 1;
// Last updated at.
google.protobuf.Timestamp updated_at = 2;
}
message ChannelConfiguration {
// Frequency (Hz).
uint32 frequency = 1;
@ -751,21 +844,13 @@ message ConnState {
}
// Gateway Mesh heartbeat (sent periodically by the Relay Gateways).
message MeshHeartbeat {
// Gateway ID (of the Border Gateway).
string gateway_id = 1;
// Relay ID.
string relay_id = 2;
// Timestamp (second precision).
google.protobuf.Timestamp time = 3;
message MeshEventHeartbeat {
// Relay path.
repeated MeshHeartbeatRelayPath relay_path = 4;
repeated MeshEventHeartbeatRelayPath relay_path = 4;
}
message MeshHeartbeatRelayPath {
message MeshEventHeartbeatRelayPath {
// Relay ID.
string relay_id = 1;
@ -775,3 +860,21 @@ message MeshHeartbeatRelayPath {
// SNR.
int32 snr = 3;
}
// Proprietary mesh event.
message MeshEventProprietary {
// Event type.
uint32 event_type = 1;
// Payload.
bytes payload = 2;
}
// Proprietary mesh command.
message MeshCommandProprietary {
// Command type.
uint32 command_type = 1;
// Payload.
bytes payload = 2;
}

View File

@ -142,6 +142,9 @@ message DeviceSession {
// Relay state.
Relay relay = 41;
// Pending mac-commands.
map<uint32, bytes> mac_command_pending = 43;
}
message UplinkAdrHistory {

View File

@ -24,8 +24,8 @@ message UplinkFrameLog {
// RX meta-data.
repeated gw.UplinkRxInfo rx_info = 3;
// Message type.
common.MType m_type = 4;
// Frame type.
common.FType f_type = 4;
// Device address (optional).
string dev_addr = 5;
@ -59,8 +59,8 @@ message DownlinkFrameLog {
// Gateway ID (EUI64).
string gateway_id = 5;
// Message type.
common.MType m_type = 6;
// Frame type.
common.FType f_type = 6;
// Device address (optional).
string dev_addr = 7;

View File

@ -32,8 +32,8 @@ message UplinkMeta {
// Application payload byte count.
uint32 application_payload_byte_count = 6;
// Message type.
common.MType message_type = 7;
// Frame type.
common.FType frame_type = 7;
}
message DownlinkMeta {
@ -55,8 +55,8 @@ message DownlinkMeta {
// Application payload byte count.
uint32 application_payload_byte_count = 6;
// Message type.
common.MType message_type = 7;
// Frame type.
common.FType frame_type = 7;
// Gateway ID (EUI64).
string gateway_id = 8;

View File

@ -7,17 +7,17 @@ include!(concat!(env!("OUT_DIR"), "/common/common.rs"));
include!(concat!(env!("OUT_DIR"), "/common/common.serde.rs"));
#[allow(clippy::from_over_into)]
impl Into<String> for MType {
impl Into<String> for FType {
fn into(self) -> String {
match self {
MType::JoinRequest => "JoinRequest",
MType::JoinAccept => "JoinAccept",
MType::UnconfirmedDataUp => "UnconfirmedDataUp",
MType::UnconfirmedDataDown => "UnconfirmedDataDown",
MType::ConfirmedDataUp => "ConfirmedDataUp",
MType::ConfirmedDataDown => "ConfirmedDataDown",
MType::RejoinRequest => "RejoinRequest",
MType::Proprietary => "Proprietary",
FType::JoinRequest => "JoinRequest",
FType::JoinAccept => "JoinAccept",
FType::UnconfirmedDataUp => "UnconfirmedDataUp",
FType::UnconfirmedDataDown => "UnconfirmedDataDown",
FType::ConfirmedDataUp => "ConfirmedDataUp",
FType::ConfirmedDataDown => "ConfirmedDataDown",
FType::RejoinRequest => "RejoinRequest",
FType::Proprietary => "Proprietary",
}
.to_string()
}

9
api/rust/src/lib.rs vendored
View File

@ -1,14 +1,17 @@
pub use prost;
pub use prost_types;
#[cfg(feature = "json")]
pub use pbjson_types;
pub use prost;
#[cfg(feature = "api")]
pub use tonic;
#[cfg(feature = "api")]
pub mod api;
#[cfg(feature = "internal")]
pub mod internal;
pub mod common;
pub mod gw;
pub mod integration;
#[cfg(feature = "internal")]
pub mod internal;
pub mod stream;

View File

@ -1,6 +1,6 @@
[package]
name = "backend"
version = "4.12.0-test.2"
version = "4.13.0-test.1"
authors = ["Orne Brocaar <info@brocaar.com>"]
edition = "2018"
publish = false

View File

@ -3,14 +3,14 @@
description = "Library for building external ChirpStack integrations"
homepage = "https://www.chirpstack.io/"
license = "MIT"
version = "4.12.0-test.2"
version = "4.13.0-test.1"
authors = ["Orne Brocaar <info@brocaar.com>"]
edition = "2021"
repository = "https://github.com/chirpstack/chirpstack"
[dependencies]
chirpstack_api = { path = "../api/rust", version = "4.12.0-test.2" }
redis = { version = "0.29", features = [
chirpstack_api = { path = "../api/rust", version = "4.13.0-test.1" }
redis = { version = "0.31", features = [
"cluster-async",
"tokio-rustls-comp",
] }
@ -24,6 +24,5 @@
async-trait = "0.1"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.44", features = ["macros", "rt-multi-thread"] }
lazy_static = "1.5"
serde_json = "1.0"
toml = "0.8"

View File

@ -1,8 +1,6 @@
#[macro_use]
extern crate lazy_static;
use std::io::Cursor;
use std::str::FromStr;
use std::sync::LazyLock;
use anyhow::Result;
use async_trait::async_trait;
@ -13,10 +11,8 @@ use tracing_subscriber::{filter, prelude::*};
use chirpstack_api::{integration as integration_pb, prost::Message};
lazy_static! {
static ref INTEGRATION: RwLock<Option<Box<dyn IntegrationTrait + Sync + Send>>> =
RwLock::new(None);
}
static INTEGRATION: LazyLock<RwLock<Option<Box<dyn IntegrationTrait + Sync + Send>>>> =
LazyLock::new(|| RwLock::new(None));
#[derive(Default, Deserialize, Clone)]
#[serde(default)]
@ -203,7 +199,7 @@ impl Integration {
for stream_key in &srr.keys {
for stream_id in &stream_key.ids {
redis::cmd("XACK")
let _: () = redis::cmd("XACK")
.arg(&key)
.arg(&self.consumer_group)
.arg(&stream_id.id)

View File

@ -3,7 +3,7 @@
description = "ChirpStack is an open-source LoRaWAN(TM) Network Server"
repository = "https://github.com/chirpstack/chirpstack"
homepage = "https://www.chirpstack.io/"
version = "4.12.0-test.2"
version = "4.13.0-test.1"
authors = ["Orne Brocaar <info@brocaar.com>"]
edition = "2021"
publish = false
@ -34,8 +34,8 @@
tokio-postgres = { version = "0.7", optional = true }
tokio-postgres-rustls = { version = "0.13", optional = true }
bigdecimal = "0.4"
redis = { version = "0.29", features = ["tls-rustls", "tokio-rustls-comp"] }
deadpool-redis = { version = "0.20", features = ["cluster", "serde"] }
redis = { version = "0.31", features = ["tls-rustls", "tokio-rustls-comp"] }
deadpool-redis = { version = "0.21", features = ["cluster", "serde"] }
# Logging
tracing = "0.1"
@ -78,9 +78,9 @@
] }
# gRPC and Protobuf
tonic = "0.12"
tonic-web = "0.12"
tonic-reflection = "0.12"
tonic = "0.13"
tonic-web = "0.13"
tonic-reflection = "0.13"
tokio = { version = "1.44", features = ["macros", "rt-multi-thread"] }
tokio-stream = "0.1"
prost-types = "0.13"
@ -95,7 +95,7 @@
futures-util = "0.3"
http = "1.3"
http-body = "1.0"
rust-embed = "8.6"
rust-embed = "8.7"
mime_guess = "2.0"
tower-http = { version = "0.6", features = ["trace", "auth"] }
@ -137,8 +137,7 @@
] }
# Misc
lazy_static = "1.5"
uuid = { version = "1.16", features = ["v4", "serde"] }
uuid = { version = "1.17", features = ["v4", "serde"] }
chrono = "0.4"
async-trait = "0.1"
aes = "0.8"
@ -146,8 +145,8 @@
base64 = "0.22"
async-recursion = "1.1"
regex = "1.11"
petgraph = "0.7"
prometheus-client = "0.22"
petgraph = "0.8"
prometheus-client = "0.23"
pin-project = "1.1"
scoped-futures = { version = "0.1", features = ["std"] }
signal-hook = "0.3"

View File

@ -26,7 +26,7 @@ insert into "user" (
password_hash,
note
) values (
'05244f12-6daf-4e1f-8315-c66783a0ab56',
gen_random_uuid(),
now(),
now(),
true,
@ -63,7 +63,7 @@ insert into "tenant" (
max_gateway_count,
private_gateways
) values (
'52f14cd4-c6f1-4fbd-8f87-4025e1d49242',
gen_random_uuid(),
now(),
now(),
'ChirpStack',

View File

@ -1,3 +1,6 @@
alter table device
drop column app_layer_params;
alter table device_keys
drop column gen_app_key;

View File

@ -73,3 +73,9 @@ alter table device_keys
alter table device_keys
alter column gen_app_key drop default;
alter table device
add column app_layer_params jsonb not null default '{}';
alter table device
alter column app_layer_params drop default;

View File

@ -1,3 +1,6 @@
alter table device
drop column app_layer_params;
alter table device_keys
drop column gen_app_key;

View File

@ -70,3 +70,6 @@ create index idx_fuota_deployment_job_scheduler_run_after on fuota_deployment_jo
alter table device_keys
add column gen_app_key blob not null default x'00000000000000000000000000000000';
alter table device
add column app_layer_params text not null default '{}';

View File

@ -1,4 +1,5 @@
use std::collections::HashMap;
use std::sync::LazyLock;
use anyhow::Result;
use async_trait::async_trait;
@ -14,10 +15,8 @@ pub mod lora_lr_fhss;
pub mod lr_fhss;
pub mod plugin;
lazy_static! {
static ref ADR_ALGORITHMS: RwLock<HashMap<String, Box<dyn Handler + Sync + Send>>> =
RwLock::new(HashMap::new());
}
static ADR_ALGORITHMS: LazyLock<RwLock<HashMap<String, Box<dyn Handler + Sync + Send>>>> =
LazyLock::new(|| RwLock::new(HashMap::new()));
pub async fn setup() -> Result<()> {
info!("Setting up adr algorithms");

View File

@ -2010,7 +2010,7 @@ pub mod test {
let mut create_req = Request::new(create_req);
create_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let create_resp = service.create(create_req).await.unwrap();
let create_resp = create_resp.get_ref();
@ -2021,7 +2021,7 @@ pub mod test {
let mut get_req = Request::new(get_req);
get_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let get_resp = service.get(get_req).await.unwrap();
assert_eq!(
Some(api::Application {
@ -2045,7 +2045,7 @@ pub mod test {
let mut up_req = Request::new(up_req);
up_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let _ = service.update(up_req).await.unwrap();
//get
@ -2055,7 +2055,7 @@ pub mod test {
let mut get_req = Request::new(get_req);
get_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let get_resp = service.get(get_req).await.unwrap();
assert_eq!(
Some(api::Application {
@ -2077,7 +2077,7 @@ pub mod test {
let mut list_req = Request::new(list_req);
list_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let list_resp = service.list(list_req).await.unwrap();
assert_eq!(1, list_resp.get_ref().total_count);
assert_eq!(1, list_resp.get_ref().result.len());
@ -2089,7 +2089,7 @@ pub mod test {
let mut del_req = Request::new(del_req);
del_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let _ = service.delete(del_req).await.unwrap();
let del_req = api::DeleteApplicationRequest {
@ -2098,7 +2098,7 @@ pub mod test {
let mut del_req = Request::new(del_req);
del_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let del_resp = service.delete(del_req).await;
assert!(del_resp.is_err());
}

View File

@ -2483,7 +2483,7 @@ pub mod test {
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_user.id.into(),
user_id: tenant_user.id,
..Default::default()
})
.await
@ -2491,7 +2491,7 @@ pub mod test {
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_admin.id.into(),
user_id: tenant_admin.id,
is_admin: true,
..Default::default()
})
@ -2727,7 +2727,7 @@ pub mod test {
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_admin.id.into(),
user_id: tenant_admin.id,
is_admin: true,
..Default::default()
})
@ -2735,21 +2735,21 @@ pub mod test {
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_user.id.into(),
user_id: tenant_user.id,
..Default::default()
})
.await
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: api_key_tenant.tenant_id.unwrap().into(),
user_id: tenant_user.id.into(),
tenant_id: api_key_tenant.tenant_id.unwrap(),
user_id: tenant_user.id,
..Default::default()
})
.await
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_user_other.id.into(),
user_id: tenant_user_other.id,
..Default::default()
})
.await
@ -3091,7 +3091,7 @@ pub mod test {
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_admin.id.into(),
user_id: tenant_admin.id,
is_admin: true,
..Default::default()
})
@ -3099,7 +3099,7 @@ pub mod test {
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_device_admin.id.into(),
user_id: tenant_device_admin.id,
is_device_admin: true,
..Default::default()
})
@ -3107,7 +3107,7 @@ pub mod test {
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_gateway_admin.id.into(),
user_id: tenant_gateway_admin.id,
is_gateway_admin: true,
..Default::default()
})
@ -3115,7 +3115,7 @@ pub mod test {
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_user.id.into(),
user_id: tenant_user.id,
..Default::default()
})
.await
@ -3538,7 +3538,7 @@ pub mod test {
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_admin.id.into(),
user_id: tenant_admin.id,
is_admin: true,
..Default::default()
})
@ -3546,7 +3546,7 @@ pub mod test {
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_device_admin.id.into(),
user_id: tenant_device_admin.id,
is_device_admin: true,
..Default::default()
})
@ -3554,7 +3554,7 @@ pub mod test {
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_gateway_admin.id.into(),
user_id: tenant_gateway_admin.id,
is_gateway_admin: true,
..Default::default()
})
@ -3562,7 +3562,7 @@ pub mod test {
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_user.id.into(),
user_id: tenant_user.id,
..Default::default()
})
.await
@ -3840,32 +3840,32 @@ pub mod test {
.await;
tenant::add_user(tenant::TenantUser {
tenant_id: api_key_tenant.tenant_id.unwrap().into(),
user_id: tenant_admin.id.into(),
tenant_id: api_key_tenant.tenant_id.unwrap(),
user_id: tenant_admin.id,
is_admin: true,
..Default::default()
})
.await
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: api_key_tenant.tenant_id.unwrap().into(),
user_id: tenant_device_admin.id.into(),
tenant_id: api_key_tenant.tenant_id.unwrap(),
user_id: tenant_device_admin.id,
is_device_admin: true,
..Default::default()
})
.await
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: api_key_tenant.tenant_id.unwrap().into(),
user_id: tenant_gateway_admin.id.into(),
tenant_id: api_key_tenant.tenant_id.unwrap(),
user_id: tenant_gateway_admin.id,
is_gateway_admin: true,
..Default::default()
})
.await
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: api_key_tenant.tenant_id.unwrap().into(),
user_id: tenant_user.id.into(),
tenant_id: api_key_tenant.tenant_id.unwrap(),
user_id: tenant_user.id,
..Default::default()
})
.await
@ -4093,8 +4093,8 @@ pub mod test {
.await;
tenant::add_user(tenant::TenantUser {
tenant_id: api_key_tenant.tenant_id.unwrap().into(),
user_id: tenant_user.id.into(),
tenant_id: api_key_tenant.tenant_id.unwrap(),
user_id: tenant_user.id,
..Default::default()
})
.await
@ -4237,7 +4237,7 @@ pub mod test {
let gw_api_key_tenant = gateway::create(gateway::Gateway {
name: "test-gw-tenant".into(),
gateway_id: EUI64::from_str("0202030405060708").unwrap(),
tenant_id: api_key_tenant.tenant_id.unwrap().into(),
tenant_id: api_key_tenant.tenant_id.unwrap(),
..Default::default()
})
.await
@ -4245,7 +4245,7 @@ pub mod test {
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_admin.id.into(),
user_id: tenant_admin.id,
is_admin: true,
..Default::default()
})
@ -4253,7 +4253,7 @@ pub mod test {
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_gateway_admin.id.into(),
user_id: tenant_gateway_admin.id,
is_gateway_admin: true,
..Default::default()
})
@ -4261,7 +4261,7 @@ pub mod test {
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: tenant_a.id,
user_id: tenant_user.id.into(),
user_id: tenant_user.id,
..Default::default()
})
.await
@ -4513,32 +4513,32 @@ pub mod test {
.await;
tenant::add_user(tenant::TenantUser {
tenant_id: api_key_tenant.tenant_id.unwrap().into(),
user_id: tenant_admin.id.into(),
tenant_id: api_key_tenant.tenant_id.unwrap(),
user_id: tenant_admin.id,
is_admin: true,
..Default::default()
})
.await
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: api_key_tenant.tenant_id.unwrap().into(),
user_id: tenant_device_admin.id.into(),
tenant_id: api_key_tenant.tenant_id.unwrap(),
user_id: tenant_device_admin.id,
is_device_admin: true,
..Default::default()
})
.await
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: api_key_tenant.tenant_id.unwrap().into(),
user_id: tenant_gateway_admin.id.into(),
tenant_id: api_key_tenant.tenant_id.unwrap(),
user_id: tenant_gateway_admin.id,
is_gateway_admin: true,
..Default::default()
})
.await
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: api_key_tenant.tenant_id.unwrap().into(),
user_id: tenant_user.id.into(),
tenant_id: api_key_tenant.tenant_id.unwrap(),
user_id: tenant_user.id,
..Default::default()
})
.await
@ -4901,7 +4901,7 @@ pub mod test {
.await
.unwrap();
tenant::add_user(tenant::TenantUser {
tenant_id: api_key_tenant.tenant_id.unwrap().into(),
tenant_id: api_key_tenant.tenant_id.unwrap(),
user_id: tenant_device_admin.id,
is_device_admin: true,
..Default::default()

View File

@ -252,7 +252,7 @@ async fn _handle_pr_start_req(b: &[u8]) -> Result<backend::PRStartAnsPayload> {
let pl: backend::PRStartReqPayload = serde_json::from_slice(b)?;
let phy = lrwn::PhyPayload::from_slice(&pl.phy_payload)?;
if phy.mhdr.m_type == lrwn::MType::JoinRequest {
if phy.mhdr.f_type == lrwn::FType::JoinRequest {
_handle_pr_start_req_join(pl, phy).await
} else {
_handle_pr_start_req_data(pl, phy).await

View File

@ -88,7 +88,7 @@ impl DeviceProfileService for DeviceProfile {
rx1_delay: req_dp.abp_rx1_delay as u8,
rx1_dr_offset: req_dp.abp_rx1_dr_offset as u8,
rx2_dr: req_dp.abp_rx2_dr as u8,
rx2_freq: req_dp.abp_rx2_freq as u32,
rx2_freq: req_dp.abp_rx2_freq,
})
},
class_b_params: if req_dp.supports_class_b {
@ -96,7 +96,7 @@ impl DeviceProfileService for DeviceProfile {
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,
ping_slot_freq: req_dp.class_b_ping_slot_freq,
})
} else {
None
@ -116,7 +116,7 @@ impl DeviceProfileService for DeviceProfile {
relay_enabled: req_dp.relay_enabled,
relay_cad_periodicity: req_dp.relay_cad_periodicity as u8,
default_channel_index: req_dp.relay_default_channel_index as u8,
second_channel_freq: req_dp.relay_second_channel_freq as u32,
second_channel_freq: req_dp.relay_second_channel_freq,
second_channel_dr: req_dp.relay_second_channel_dr as u8,
second_channel_ack_offset: req_dp.relay_second_channel_ack_offset as u8,
ed_activation_mode: req_dp.relay_ed_activation_mode().from_proto(),
@ -344,7 +344,7 @@ impl DeviceProfileService for DeviceProfile {
rx1_delay: req_dp.abp_rx1_delay as u8,
rx1_dr_offset: req_dp.abp_rx1_dr_offset as u8,
rx2_dr: req_dp.abp_rx2_dr as u8,
rx2_freq: req_dp.abp_rx2_freq as u32,
rx2_freq: req_dp.abp_rx2_freq,
})
},
class_b_params: if req_dp.supports_class_b {
@ -352,7 +352,7 @@ impl DeviceProfileService for DeviceProfile {
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,
ping_slot_freq: req_dp.class_b_ping_slot_freq,
})
} else {
None
@ -372,7 +372,7 @@ impl DeviceProfileService for DeviceProfile {
relay_enabled: req_dp.relay_enabled,
relay_cad_periodicity: req_dp.relay_cad_periodicity as u8,
default_channel_index: req_dp.relay_default_channel_index as u8,
second_channel_freq: req_dp.relay_second_channel_freq as u32,
second_channel_freq: req_dp.relay_second_channel_freq,
second_channel_dr: req_dp.relay_second_channel_dr as u8,
second_channel_ack_offset: req_dp.relay_second_channel_ack_offset as u8,
ed_activation_mode: req_dp.relay_ed_activation_mode().from_proto(),
@ -406,7 +406,6 @@ impl DeviceProfileService for DeviceProfile {
ts004_f_port: app_layer_params.ts004_f_port as u8,
ts005_version: app_layer_params.ts005_version().from_proto(),
ts005_f_port: app_layer_params.ts005_f_port as u8,
..Default::default()
}
},
..Default::default()

View File

@ -50,9 +50,9 @@ impl ToStatus for storage::error::Error {
storage::error::Error::ValidatorValidate(_) => {
Status::new(Code::InvalidArgument, format!("{:#}", self))
}
storage::error::Error::MultiError(errors) => {
storage::error::Error::Multi(errors) => {
let errors = errors
.into_iter()
.iter()
.map(|e| e.to_string())
.collect::<Vec<String>>()
.join(", ");

View File

@ -346,11 +346,11 @@ impl FuotaService for Fuota {
started_at: d
.started_at
.as_ref()
.map(|ts| helpers::datetime_to_prost_timestamp(ts)),
.map(helpers::datetime_to_prost_timestamp),
completed_at: d
.completed_at
.as_ref()
.map(|ts| helpers::datetime_to_prost_timestamp(ts)),
.map(helpers::datetime_to_prost_timestamp),
name: d.name.clone(),
})
.collect(),
@ -462,23 +462,23 @@ impl FuotaService for Fuota {
completed_at: d
.completed_at
.as_ref()
.map(|ts| helpers::datetime_to_prost_timestamp(ts)),
.map(helpers::datetime_to_prost_timestamp),
mc_group_setup_completed_at: d
.mc_group_setup_completed_at
.as_ref()
.map(|ts| helpers::datetime_to_prost_timestamp(ts)),
.map(helpers::datetime_to_prost_timestamp),
mc_session_completed_at: d
.mc_session_completed_at
.as_ref()
.map(|ts| helpers::datetime_to_prost_timestamp(ts)),
.map(helpers::datetime_to_prost_timestamp),
frag_session_setup_completed_at: d
.frag_session_setup_completed_at
.as_ref()
.map(|ts| helpers::datetime_to_prost_timestamp(ts)),
.map(helpers::datetime_to_prost_timestamp),
frag_status_completed_at: d
.frag_status_completed_at
.as_ref()
.map(|ts| helpers::datetime_to_prost_timestamp(ts)),
.map(helpers::datetime_to_prost_timestamp),
error_msg: d.error_msg.clone(),
})
.collect(),
@ -624,7 +624,7 @@ impl FuotaService for Fuota {
completed_at: j
.completed_at
.as_ref()
.map(|ts| helpers::datetime_to_prost_timestamp(ts)),
.map(helpers::datetime_to_prost_timestamp),
max_retry_count: j.max_retry_count as u32,
attempt_count: j.attempt_count as u32,
scheduler_run_after: Some(helpers::datetime_to_prost_timestamp(

View File

@ -1036,7 +1036,7 @@ pub mod test {
let mut create_req = Request::new(create_req);
create_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let _ = service.create(create_req).await.unwrap();
// get
@ -1046,7 +1046,7 @@ pub mod test {
let mut get_req = Request::new(get_req);
get_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let get_resp = service.get(get_req).await.unwrap();
assert_eq!(
Some(api::Gateway {
@ -1082,7 +1082,7 @@ pub mod test {
let mut up_req = Request::new(up_req);
up_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let _ = service.update(up_req).await.unwrap();
// get
@ -1092,7 +1092,7 @@ pub mod test {
let mut get_req = Request::new(get_req);
get_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let get_resp = service.get(get_req).await.unwrap();
assert_eq!(
Some(api::Gateway {
@ -1121,7 +1121,7 @@ pub mod test {
let mut list_req = Request::new(list_req);
list_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let list_resp = service.list(list_req).await.unwrap();
assert_eq!(1, list_resp.get_ref().total_count);
assert_eq!(1, list_resp.get_ref().result.len());
@ -1133,7 +1133,7 @@ pub mod test {
let mut del_req = Request::new(del_req);
del_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let _ = service.delete(del_req).await.unwrap();
let del_req = api::DeleteGatewayRequest {
@ -1142,7 +1142,7 @@ pub mod test {
let mut del_req = Request::new(del_req);
del_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let del_resp = service.delete(del_req).await;
assert!(del_resp.is_err());
}
@ -1220,7 +1220,7 @@ pub mod test {
let mut stats_req = Request::new(stats_req);
stats_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let stats_resp = service.get_metrics(stats_req).await.unwrap();
let stats_resp = stats_resp.get_ref();
assert_eq!(

View File

@ -193,17 +193,17 @@ impl FromProto<Aggregation> for common::Aggregation {
}
}
impl ToProto<common::MType> for lrwn::MType {
fn to_proto(self) -> common::MType {
impl ToProto<common::FType> for lrwn::FType {
fn to_proto(self) -> common::FType {
match self {
lrwn::MType::JoinRequest => common::MType::JoinRequest,
lrwn::MType::JoinAccept => common::MType::JoinAccept,
lrwn::MType::UnconfirmedDataUp => common::MType::UnconfirmedDataUp,
lrwn::MType::UnconfirmedDataDown => common::MType::UnconfirmedDataDown,
lrwn::MType::ConfirmedDataUp => common::MType::ConfirmedDataUp,
lrwn::MType::ConfirmedDataDown => common::MType::ConfirmedDataDown,
lrwn::MType::RejoinRequest => common::MType::RejoinRequest,
lrwn::MType::Proprietary => common::MType::Proprietary,
lrwn::FType::JoinRequest => common::FType::JoinRequest,
lrwn::FType::JoinAccept => common::FType::JoinAccept,
lrwn::FType::UnconfirmedDataUp => common::FType::UnconfirmedDataUp,
lrwn::FType::UnconfirmedDataDown => common::FType::UnconfirmedDataDown,
lrwn::FType::ConfirmedDataUp => common::FType::ConfirmedDataUp,
lrwn::FType::ConfirmedDataDown => common::FType::ConfirmedDataDown,
lrwn::FType::RejoinRequest => common::FType::RejoinRequest,
lrwn::FType::Proprietary => common::FType::Proprietary,
}
}
}

View File

@ -1,3 +1,4 @@
use std::sync::LazyLock;
use std::time::{Duration, Instant};
use std::{
future::Future,
@ -5,7 +6,7 @@ use std::{
task::{Context, Poll},
};
use anyhow::Result;
use anyhow::{Context as AnyhowContext, Result};
use axum::{response::IntoResponse, routing::get, Router};
use http::{
header::{self, HeaderMap, HeaderValue},
@ -67,33 +68,31 @@ pub mod relay;
pub mod tenant;
pub mod user;
lazy_static! {
static ref GRPC_COUNTER: Family<GrpcLabels, Counter> = {
let counter = Family::<GrpcLabels, Counter>::default();
prometheus::register(
"api_requests_handled",
"Number of API requests handled by service, method and status code",
counter.clone(),
);
counter
};
static ref GRPC_HISTOGRAM: Family<GrpcLabels, Histogram> = {
let histogram = Family::<GrpcLabels, Histogram>::new_with_constructor(|| {
Histogram::new(
[
0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0,
]
.into_iter(),
)
});
prometheus::register(
"api_requests_handled_seconds",
"Duration of API requests handled by service, method and status code",
histogram.clone(),
);
histogram
};
}
static GRPC_COUNTER: LazyLock<Family<GrpcLabels, Counter>> = LazyLock::new(|| {
let counter = Family::<GrpcLabels, Counter>::default();
prometheus::register(
"api_requests_handled",
"Number of API requests handled by service, method and status code",
counter.clone(),
);
counter
});
static GRPC_HISTOGRAM: LazyLock<Family<GrpcLabels, Histogram>> = LazyLock::new(|| {
let histogram = Family::<GrpcLabels, Histogram>::new_with_constructor(|| {
Histogram::new(
[
0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0,
]
.into_iter(),
)
});
prometheus::register(
"api_requests_handled_seconds",
"Duration of API requests handled by service, method and status code",
histogram.clone(),
);
histogram
});
#[derive(RustEmbed)]
#[folder = "../ui/build"]
@ -103,7 +102,7 @@ type BoxError = Box<dyn std::error::Error + Send + Sync>;
pub async fn setup() -> Result<()> {
let conf = config::get();
let bind = conf.api.bind.parse()?;
let bind = conf.api.bind.parse().context("Parse api.bind config")?;
info!(bind = %bind, "Setting up API interface");
@ -114,7 +113,7 @@ pub async fn setup() -> Result<()> {
.route("/auth/oauth2/callback", get(oauth2::callback_handler))
.fallback(service_static_handler)
.into_service()
.map_response(|r| r.map(tonic::body::boxed));
.map_response(|r| r.map(tonic::body::Body::new));
let grpc = TonicServer::builder()
.accept_http1(true)

View File

@ -484,7 +484,7 @@ pub mod test {
let mut create_req = Request::new(create_req);
create_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let create_resp = service.create(create_req).await.unwrap();
// get
@ -494,7 +494,7 @@ pub mod test {
let mut get_req = Request::new(get_req);
get_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let get_resp = service.get(get_req).await.unwrap();
assert_eq!(
Some(api::Tenant {
@ -524,7 +524,7 @@ pub mod test {
let mut up_req = Request::new(up_req);
up_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let _ = service.update(up_req).await.unwrap();
// get
@ -534,7 +534,7 @@ pub mod test {
let mut get_req = Request::new(get_req);
get_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let get_resp = service.get(get_req).await.unwrap();
assert_eq!(
Some(api::Tenant {
@ -559,7 +559,7 @@ pub mod test {
let mut list_req = Request::new(list_req);
list_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let list_resp = service.list(list_req).await.unwrap();
assert_eq!(1, list_resp.get_ref().total_count);
assert_eq!(1, list_resp.get_ref().result.len());
@ -571,7 +571,7 @@ pub mod test {
let mut del_req = Request::new(del_req);
del_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let _ = service.delete(del_req).await.unwrap();
let del_req = api::DeleteTenantRequest {
@ -580,7 +580,7 @@ pub mod test {
let mut del_req = Request::new(del_req);
del_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let del_resp = service.delete(del_req).await;
assert!(del_resp.is_err());
}

View File

@ -294,7 +294,7 @@ pub mod test {
let mut create_req = Request::new(create_req);
create_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let create_resp = service.create(create_req).await.unwrap();
// get
@ -304,7 +304,7 @@ pub mod test {
let mut get_req = Request::new(get_req);
get_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let get_resp = service.get(get_req).await.unwrap();
assert_eq!(
Some(api::User {
@ -332,7 +332,7 @@ pub mod test {
let mut up_req = Request::new(up_req);
up_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let _ = service.update(up_req).await.unwrap();
// get
@ -342,7 +342,7 @@ pub mod test {
let mut get_req = Request::new(get_req);
get_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let get_resp = service.get(get_req).await.unwrap();
assert_eq!(
Some(api::User {
@ -364,7 +364,7 @@ pub mod test {
let mut up_req = Request::new(up_req);
up_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let _ = service.update_password(up_req).await.unwrap();
// list
@ -375,7 +375,7 @@ pub mod test {
let mut list_req = Request::new(list_req);
list_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let list_resp = service.list(list_req).await.unwrap();
// * Admin from migrations
// * User that we created for auth
@ -390,7 +390,7 @@ pub mod test {
let mut del_req = Request::new(del_req);
del_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let _ = service.delete(del_req).await.unwrap();
let del_req = api::DeleteUserRequest {
@ -399,7 +399,7 @@ pub mod test {
let mut del_req = Request::new(del_req);
del_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let del_resp = service.delete(del_req).await;
assert!(del_resp.is_err());
@ -409,7 +409,7 @@ pub mod test {
let mut del_req = Request::new(del_req);
del_req
.extensions_mut()
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id).clone()));
.insert(AuthID::User(Into::<uuid::Uuid>::into(u.id)));
let del_resp = service.delete(del_req).await;
assert!(del_resp.is_err());
}

View File

@ -33,11 +33,8 @@ async fn handle_uplink_v100(
) -> Result<()> {
let pl = clocksync::v1::Payload::from_slice(true, data)?;
match pl {
clocksync::v1::Payload::AppTimeReq(pl) => {
handle_v1_app_time_req(dev, dp, rx_info, pl).await?
}
_ => {}
if let clocksync::v1::Payload::AppTimeReq(pl) = pl {
handle_v1_app_time_req(dev, dp, rx_info, pl).await?
}
Ok(())
@ -51,11 +48,8 @@ async fn handle_uplink_v200(
) -> Result<()> {
let pl = clocksync::v2::Payload::from_slice(true, data)?;
match pl {
clocksync::v2::Payload::AppTimeReq(pl) => {
handle_v2_app_time_req(dev, dp, rx_info, pl).await?
}
_ => {}
if let clocksync::v2::Payload::AppTimeReq(pl) = pl {
handle_v2_app_time_req(dev, dp, rx_info, pl).await?
}
Ok(())
@ -181,7 +175,7 @@ mod test {
Test {
name: "device synced".into(),
rx_info: gw::UplinkRxInfo {
time_since_gps_epoch: Some(Duration::from_secs(1234).try_into().unwrap()),
time_since_gps_epoch: Some(Duration::from_secs(1234).into()),
..Default::default()
},
req: clocksync::v1::AppTimeReqPayload {
@ -196,7 +190,7 @@ mod test {
Test {
name: "device synced - ans required".into(),
rx_info: gw::UplinkRxInfo {
time_since_gps_epoch: Some(Duration::from_secs(1234).try_into().unwrap()),
time_since_gps_epoch: Some(Duration::from_secs(1234).into()),
..Default::default()
},
req: clocksync::v1::AppTimeReqPayload {
@ -214,7 +208,7 @@ mod test {
Test {
name: "device not synced (positive correction)".into(),
rx_info: gw::UplinkRxInfo {
time_since_gps_epoch: Some(Duration::from_secs(1234).try_into().unwrap()),
time_since_gps_epoch: Some(Duration::from_secs(1234).into()),
..Default::default()
},
req: clocksync::v1::AppTimeReqPayload {
@ -232,7 +226,7 @@ mod test {
Test {
name: "device not synced (negative correction)".into(),
rx_info: gw::UplinkRxInfo {
time_since_gps_epoch: Some(Duration::from_secs(1200).try_into().unwrap()),
time_since_gps_epoch: Some(Duration::from_secs(1200).into()),
..Default::default()
},
req: clocksync::v1::AppTimeReqPayload {
@ -330,7 +324,7 @@ mod test {
Test {
name: "device synced".into(),
rx_info: gw::UplinkRxInfo {
time_since_gps_epoch: Some(Duration::from_secs(1234).try_into().unwrap()),
time_since_gps_epoch: Some(Duration::from_secs(1234).into()),
..Default::default()
},
req: clocksync::v2::AppTimeReqPayload {
@ -345,7 +339,7 @@ mod test {
Test {
name: "device synced - ans required".into(),
rx_info: gw::UplinkRxInfo {
time_since_gps_epoch: Some(Duration::from_secs(1234).try_into().unwrap()),
time_since_gps_epoch: Some(Duration::from_secs(1234).into()),
..Default::default()
},
req: clocksync::v2::AppTimeReqPayload {
@ -363,7 +357,7 @@ mod test {
Test {
name: "device not synced (positive correction)".into(),
rx_info: gw::UplinkRxInfo {
time_since_gps_epoch: Some(Duration::from_secs(1234).try_into().unwrap()),
time_since_gps_epoch: Some(Duration::from_secs(1234).into()),
..Default::default()
},
req: clocksync::v2::AppTimeReqPayload {
@ -381,7 +375,7 @@ mod test {
Test {
name: "device not synced (negative correction)".into(),
rx_info: gw::UplinkRxInfo {
time_since_gps_epoch: Some(Duration::from_secs(1200).try_into().unwrap()),
time_since_gps_epoch: Some(Duration::from_secs(1200).into()),
..Default::default()
},
req: clocksync::v2::AppTimeReqPayload {

View File

@ -397,6 +397,20 @@ impl Flow {
)
.to_vec()?,
Some(Ts004Version::V200) => {
let dev = device::get(&fuota_dev.dev_eui).await?;
let session_cnt = dev.app_layer_params.ts004_session_cnt[0];
let mut app_layer_params = dev.app_layer_params.clone();
app_layer_params.ts004_session_cnt[0] += 1;
device::partial_update(
fuota_dev.dev_eui,
&device::DeviceChangeset {
app_layer_params: Some(app_layer_params),
..Default::default()
},
)
.await?;
let dev_keys = device_keys::get(&fuota_dev.dev_eui).await?;
let data_block_int_key = match self.device_profile.mac_version {
MacVersion::LORAWAN_1_0_0
@ -412,7 +426,7 @@ impl Flow {
};
let mic = fragmentation::v2::calculate_mic(
data_block_int_key,
0,
session_cnt,
0,
[0, 0, 0, 0],
&self.fuota_deployment.payload,
@ -434,7 +448,7 @@ impl Flow {
},
descriptor: [0, 0, 0, 0],
mic,
session_cnt: 0,
session_cnt,
},
)
.to_vec()?
@ -500,7 +514,7 @@ impl Flow {
FuotaJob::Enqueue,
self.fuota_deployment
.multicast_session_start
.unwrap_or_else(|| Utc::now()),
.unwrap_or_else(Utc::now),
)));
}
@ -657,7 +671,7 @@ impl Flow {
FuotaJob::Enqueue,
self.fuota_deployment
.multicast_session_start
.unwrap_or_else(|| Utc::now()),
.unwrap_or_else(Utc::now),
)))
}
}
@ -756,7 +770,7 @@ impl Flow {
FuotaJob::DeleteMcGroup,
self.fuota_deployment
.multicast_session_end
.unwrap_or_else(|| Utc::now()),
.unwrap_or_else(Utc::now),
))),
RequestFragmentationSessionStatus::AfterFragEnqueue => {
Ok(Some((FuotaJob::FragStatus, Utc::now())))
@ -765,7 +779,7 @@ impl Flow {
FuotaJob::FragStatus,
self.fuota_deployment
.multicast_session_end
.unwrap_or_else(|| Utc::now()),
.unwrap_or_else(Utc::now),
))),
}
}
@ -852,7 +866,7 @@ impl Flow {
FuotaJob::DeleteMcGroup,
self.fuota_deployment
.multicast_session_end
.unwrap_or_else(|| Utc::now()),
.unwrap_or_else(Utc::now),
)))
}
}

View File

@ -1,4 +1,4 @@
use std::sync::Arc;
use std::sync::{Arc, LazyLock};
use anyhow::Result;
use tokio::sync::RwLock;
@ -8,9 +8,8 @@ use crate::{config, stream};
use backend::{Client, ClientConfig};
use lrwn::{EUI64Prefix, EUI64};
lazy_static! {
static ref CLIENTS: RwLock<Vec<(EUI64Prefix, Arc<Client>)>> = RwLock::new(vec![]);
}
static CLIENTS: LazyLock<RwLock<Vec<(EUI64Prefix, Arc<Client>)>>> =
LazyLock::new(|| RwLock::new(vec![]));
pub async fn setup() -> Result<()> {
info!("Setting up Join Server clients");
@ -30,6 +29,11 @@ pub async fn setup() -> Result<()> {
tls_key: js.tls_key.clone(),
async_timeout: js.async_timeout,
request_log_sender: stream::backend_interfaces::get_log_sender().await,
authorization: if js.authorization_header.is_empty() {
None
} else {
Some(js.authorization_header.clone())
},
..Default::default()
})?;

View File

@ -1,7 +1,7 @@
use std::collections::HashMap;
use std::io::Cursor;
use std::str::FromStr;
use std::sync::Arc;
use std::sync::{Arc, LazyLock};
use anyhow::Result;
use chrono::{Duration, DurationRound};
@ -15,9 +15,8 @@ use backend::{Client, ClientConfig, GWInfoElement, ULMetaData};
use chirpstack_api::{common, gw};
use lrwn::{region, DevAddr, NetID, EUI64};
lazy_static! {
static ref CLIENTS: RwLock<HashMap<NetID, Arc<Client>>> = RwLock::new(HashMap::new());
}
static CLIENTS: LazyLock<RwLock<HashMap<NetID, Arc<Client>>>> =
LazyLock::new(|| RwLock::new(HashMap::new()));
pub async fn setup() -> Result<()> {
info!("Setting up roaming clients");

View File

@ -797,6 +797,11 @@ pub fn run() {
# #
# # Set this to enable client-certificate authentication with the join-server.
# tls_key="/path/to/tls_key.pem"
# # Authorization header.
# #
# # Optional value of the Authorization header, e.g. token or password.
# authorization_header="Bearer sometoken"
{{#each join_server.servers}}
[[join_server.servers]]
@ -807,6 +812,7 @@ pub fn run() {
ca_cert="{{ this.ca_cert }}"
tls_cert="{{ this.tls_cert }}"
tls_key="{{ this.tls_key }}"
authorization_header="{{ this.authorization_header }}"
{{/each}}
@ -1000,7 +1006,7 @@ pub fn run() {
let conf = config::get();
println!(
"{}",
reg.render_template(&template, &conf)
reg.render_template(template, &conf)
.expect("render configfile error")
);
}

View File

@ -1,5 +1,5 @@
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::sync::{Arc, LazyLock, Mutex};
use std::time::Duration;
use std::{env, fs};
@ -9,9 +9,8 @@ use serde::{Deserialize, Serialize};
use lrwn::region::CommonName;
use lrwn::{AES128Key, DevAddrPrefix, EUI64Prefix, NetID};
lazy_static! {
static ref CONFIG: Mutex<Arc<Configuration>> = Mutex::new(Arc::new(Default::default()));
}
static CONFIG: LazyLock<Mutex<Arc<Configuration>>> =
LazyLock::new(|| Mutex::new(Arc::new(Default::default())));
#[derive(Default, Serialize, Deserialize, Clone)]
#[serde(default)]
@ -353,6 +352,7 @@ pub struct AmqpIntegration {
pub url: String,
pub json: bool,
pub event_routing_key: String,
pub exchange: String,
}
impl Default for AmqpIntegration {
@ -362,6 +362,7 @@ impl Default for AmqpIntegration {
json: true,
event_routing_key: "application.{{application_id}}.device.{{dev_eui}}.event.{{event}}"
.to_string(),
exchange: "amq.topic".to_string(),
}
}
}
@ -525,6 +526,7 @@ pub struct JoinServerServer {
pub ca_cert: String,
pub tls_cert: String,
pub tls_key: String,
pub authorization_header: String,
}
#[derive(Serialize, Deserialize, Default, Clone)]

View File

@ -1,3 +1,5 @@
use std::sync::LazyLock;
use aes::cipher::generic_array::GenericArray;
use aes::cipher::{BlockEncrypt, KeyInit};
use aes::{Aes128, Block};
@ -7,14 +9,11 @@ use tracing::debug;
use lrwn::DevAddr;
lazy_static! {
static ref BEACON_PERIOD: Duration = Duration::try_seconds(128).unwrap();
static ref BEACON_RESERVED: Duration = Duration::try_milliseconds(2120).unwrap();
static ref BEACON_GUARD: Duration = Duration::try_seconds(3).unwrap();
static ref BEACON_WINDOW: Duration = Duration::try_milliseconds(122880).unwrap();
static ref PING_PERIOD_BASE: usize = 1 << 12;
static ref SLOT_LEN: Duration = Duration::try_milliseconds(30).unwrap();
}
static BEACON_PERIOD: LazyLock<Duration> = LazyLock::new(|| Duration::try_seconds(128).unwrap());
static BEACON_RESERVED: LazyLock<Duration> =
LazyLock::new(|| Duration::try_milliseconds(2120).unwrap());
static PING_PERIOD_BASE: usize = 1 << 12;
static SLOT_LEN: LazyLock<Duration> = LazyLock::new(|| Duration::try_milliseconds(30).unwrap());
pub fn get_beacon_start(ts: Duration) -> Duration {
Duration::try_seconds(ts.num_seconds() - (ts.num_seconds() % BEACON_PERIOD.num_seconds()))
@ -26,7 +25,7 @@ pub fn get_ping_offset(beacon_ts: Duration, dev_addr: &DevAddr, ping_nb: usize)
return Err(anyhow!("ping_nb must be > 0"));
}
let ping_period = *PING_PERIOD_BASE / ping_nb;
let ping_period = PING_PERIOD_BASE / ping_nb;
let beacon_time = (beacon_ts.num_seconds() % (1 << 32)) as u32;
let key_bytes: [u8; 16] = [0x00; 16];
@ -54,7 +53,7 @@ pub fn get_next_ping_slot_after(
}
let mut beacon_start_ts = get_beacon_start(after_gps_epoch_ts);
let ping_period = *PING_PERIOD_BASE / ping_nb;
let ping_period = PING_PERIOD_BASE / ping_nb;
loop {
let ping_offset = get_ping_offset(beacon_start_ts, dev_addr, ping_nb)?;
@ -122,7 +121,7 @@ pub mod test {
for k in 0..8 {
let mut beacon_ts = Duration::zero();
let ping_nb: usize = 1 << k;
let ping_period = *PING_PERIOD_BASE / ping_nb;
let ping_period = PING_PERIOD_BASE / ping_nb;
let dev_addr = DevAddr::from_be_bytes([0, 0, 0, 0]);
for _ in 0..100000 {

View File

@ -707,7 +707,8 @@ impl Data {
fn set_phy_payloads(&mut self) -> Result<()> {
trace!("Setting downlink PHYPayloads");
let mut f_pending = self.more_device_queue_items;
let ds = self.device.get_device_session()?;
let dev_addr = self.device.get_dev_addr()?;
let ds = self.device.get_device_session_mut()?;
for item in self.downlink_frame_items.iter_mut() {
let mut mac_size: usize = 0;
@ -729,18 +730,20 @@ impl Data {
for mac in &**mac_set {
mac_commands.push(mac.clone());
}
mac_command::set_pending(ds, mac_set)?;
}
// LoRaWAN MHDR
let mut mhdr = lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
};
// LoRaWAN MAC payload
let mut mac_pl = lrwn::MACPayload {
fhdr: lrwn::FHDR {
devaddr: self.device.get_dev_addr()?,
devaddr: dev_addr,
f_cnt: ds.n_f_cnt_down,
f_ctrl: lrwn::FCtrl {
adr: !self.network_conf.adr_disabled,
@ -791,7 +794,7 @@ impl Data {
mac_pl.frm_payload = Some(lrwn::FRMPayload::Raw(qi.data.clone()));
if qi.confirmed {
mhdr.m_type = lrwn::MType::ConfirmedDataDown;
mhdr.f_type = lrwn::FType::ConfirmedDataDown;
}
item.remaining_payload_size -= qi.data.len();
@ -864,7 +867,7 @@ impl Data {
for item in self.downlink_frame.items.iter_mut() {
let mut relay_phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -912,7 +915,7 @@ impl Data {
for item in self.downlink_frame_items.iter_mut() {
let mut relay_phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -1196,8 +1199,6 @@ impl Data {
if let Some(block) =
maccommand::new_channel::request(3, &current_channels, &wanted_channels)
{
mac_command::set_pending(&self.device.dev_eui, lrwn::CID::NewChannelReq, &block)
.await?;
self.mac_commands.push(block);
}
@ -1207,7 +1208,7 @@ impl Data {
// Note: this must come before ADR!
async fn _request_channel_mask_reconfiguration(&mut self) -> Result<()> {
trace!("Requesting channel-mask reconfiguration");
let ds = self.device.get_device_session()?;
let ds = self.device.get_device_session_mut()?;
let enabled_uplink_channel_indices: Vec<usize> = ds
.enabled_uplink_channel_indices
@ -1239,7 +1240,6 @@ impl Data {
.collect(),
);
mac_command::set_pending(&self.device.dev_eui, lrwn::CID::LinkADRReq, &set).await?;
self.mac_commands.push(set);
Ok(())
@ -1257,12 +1257,15 @@ impl Data {
.get_data_rate(self.uplink_frame_set.as_ref().unwrap().dr)?;
let ufs = self.uplink_frame_set.as_ref().unwrap();
let ds = self.device.get_device_session()?;
let dev_eui = self.device.dev_eui;
let device_variables = self.device.variables.into_hashmap();
let ds = self.device.get_device_session_mut()?;
let req = adr::Request {
dev_eui,
device_variables,
region_config_id: ufs.region_config_id.clone(),
region_common_name: ufs.region_common_name,
dev_eui: self.device.dev_eui,
mac_version: self.device_profile.mac_version,
reg_params_revision: self.device_profile.reg_params_revision,
adr: ds.adr,
@ -1291,7 +1294,6 @@ impl Data {
max_dr: self.network_conf.max_dr,
uplink_history: ds.uplink_adr_history.clone(),
skip_f_cnt_check: ds.skip_f_cnt_check,
device_variables: self.device.variables.into_hashmap(),
};
let resp = adr::handle(&self.device_profile.adr_algorithm_id, &req).await;
@ -1304,24 +1306,14 @@ impl Data {
{
let mut adr_set = false;
for set in self.mac_commands.iter_mut() {
let mut is_link_adr_set = false;
for mac in &mut **set {
if let lrwn::MACCommand::LinkADRReq(pl) = mac {
pl.dr = resp.dr;
pl.tx_power = resp.tx_power_index;
pl.redundancy.nb_rep = resp.nb_trans;
adr_set = true;
is_link_adr_set = true;
}
}
if is_link_adr_set {
// We need to update the pending mac-command.
mac_command::set_pending(&self.device.dev_eui, lrwn::CID::LinkADRReq, set)
.await?;
}
}
// There was no existing LinkADRReq to be sent, we need to construct a new one.
@ -1358,7 +1350,6 @@ impl Data {
},
)]);
mac_command::set_pending(&self.device.dev_eui, lrwn::CID::LinkADRReq, &set).await?;
self.mac_commands.push(set);
}
}
@ -1406,7 +1397,7 @@ impl Data {
async fn _request_rejoin_param_setup(&mut self) -> Result<()> {
trace!("Requesting rejoin param setup");
let ds = self.device.get_device_session()?;
let ds = self.device.get_device_session_mut()?;
// Rejoin-request is disabled or device does not support LoRaWAN 1.1.
if !self.network_conf.rejoin_request.enabled
@ -1423,8 +1414,6 @@ impl Data {
self.network_conf.rejoin_request.max_time_n,
self.network_conf.rejoin_request.max_count_n,
);
mac_command::set_pending(&self.device.dev_eui, lrwn::CID::RejoinParamSetupReq, &set)
.await?;
self.mac_commands.push(set);
}
@ -1434,7 +1423,7 @@ impl Data {
async fn _set_ping_slot_parameters(&mut self) -> Result<()> {
trace!("Setting ping-slot parameters");
let ds = self.device.get_device_session()?;
let ds = self.device.get_device_session_mut()?;
if !self.device_profile.supports_class_b {
return Ok(());
@ -1447,8 +1436,6 @@ impl Data {
self.network_conf.class_b.ping_slot_dr,
self.network_conf.class_b.ping_slot_frequency,
);
mac_command::set_pending(&self.device.dev_eui, lrwn::CID::PingSlotChannelReq, &set)
.await?;
self.mac_commands.push(set);
}
@ -1457,7 +1444,7 @@ impl Data {
async fn _set_rx_parameters(&mut self) -> Result<()> {
trace!("Setting rx parameters");
let ds = self.device.get_device_session()?;
let ds = self.device.get_device_session_mut()?;
if ds.rx2_frequency != self.network_conf.rx2_frequency
|| ds.rx2_dr as u8 != self.network_conf.rx2_dr
@ -1468,8 +1455,6 @@ impl Data {
self.network_conf.rx2_frequency,
self.network_conf.rx2_dr,
);
mac_command::set_pending(&self.device.dev_eui, lrwn::CID::RxParamSetupReq, &set)
.await?;
self.mac_commands.push(set);
}
@ -1481,8 +1466,6 @@ impl Data {
if dev_rx1_delay != req_rx1_delay {
let set = maccommand::rx_timing_setup::request(req_rx1_delay);
mac_command::set_pending(&self.device.dev_eui, lrwn::CID::RxTimingSetupReq, &set)
.await?;
self.mac_commands.push(set);
}
@ -1491,7 +1474,7 @@ impl Data {
async fn _set_tx_parameters(&mut self) -> Result<()> {
trace!("Setting tx parameters");
let ds = self.device.get_device_session()?;
let ds = self.device.get_device_session_mut()?;
if !self
.region_conf
@ -1512,8 +1495,6 @@ impl Data {
self.network_conf.downlink_dwell_time_400ms,
uplink_eirp_index,
);
mac_command::set_pending(&self.device.dev_eui, lrwn::CID::TxParamSetupReq, &set)
.await?;
self.mac_commands.push(set);
}
@ -1567,8 +1548,8 @@ impl Data {
|| rd.uplink_limit_reload_rate
!= device.relay_ed_uplink_limit_reload_rate as u32
{
let d = device::get(&device.dev_eui).await?;
let ds = match d.get_device_session() {
let mut d = device::get(&device.dev_eui).await?;
let ds = match d.get_device_session_mut() {
Ok(v) => v,
Err(_) => {
// It is valid that the device is no longer activated.
@ -1595,13 +1576,17 @@ impl Data {
},
),
]);
mac_command::set_pending(
&dev_eui,
lrwn::CID::UpdateUplinkListReq,
&set,
self.mac_commands.push(set);
// Update device-session of device.
device::partial_update(
d.dev_eui,
&device::DeviceChangeset {
device_session: Some(d.device_session.clone()),
..Default::default()
},
)
.await?;
self.mac_commands.push(set);
rd.dev_addr = dev_addr.to_vec();
rd.root_wor_s_key = root_wor_s_key.to_vec();
@ -1651,8 +1636,6 @@ impl Data {
root_wor_s_key,
},
)]);
mac_command::set_pending(&dev_eui, lrwn::CID::UpdateUplinkListReq, &set)
.await?;
self.mac_commands.push(set);
ds.relay
@ -1788,8 +1771,6 @@ impl Data {
if !commands.is_empty() {
let set = lrwn::MACCommandSet::new(commands);
mac_command::set_pending(&self.device.dev_eui, lrwn::CID::CtrlUplinkListReq, &set)
.await?;
self.mac_commands.push(set);
}
@ -1799,7 +1780,6 @@ impl Data {
async fn _configure_fwd_limit_req(&mut self) -> Result<()> {
trace!("Configuring Relay Fwd Limit");
let dev_eui = self.device.dev_eui;
let ds = self.device.get_device_session_mut()?;
let relay_params = self.device_profile.relay_params.clone().unwrap_or_default();
@ -1827,24 +1807,22 @@ impl Data {
let set = lrwn::MACCommandSet::new(vec![lrwn::MACCommand::ConfigureFwdLimitReq(
lrwn::ConfigureFwdLimitReqPayload {
reload_rate: lrwn::FwdLimitReloadRatePL {
overall_reload_rate: relay_params.relay_overall_limit_reload_rate as u8,
overall_reload_rate: relay_params.relay_overall_limit_reload_rate,
global_uplink_reload_rate: relay_params
.relay_global_uplink_limit_reload_rate
as u8,
notify_reload_rate: relay_params.relay_notify_limit_reload_rate as u8,
join_req_reload_rate: relay_params.relay_join_req_limit_reload_rate as u8,
.relay_global_uplink_limit_reload_rate,
notify_reload_rate: relay_params.relay_notify_limit_reload_rate,
join_req_reload_rate: relay_params.relay_join_req_limit_reload_rate,
reset_limit_counter: lrwn::ResetLimitCounter::NoChange,
},
load_capacity: lrwn::FwdLimitLoadCapacityPL {
overall_limit_size: relay_params.relay_overall_limit_bucket_size as u8,
global_uplink_limit_size: relay_params.relay_global_uplink_limit_bucket_size
as u8,
notify_limit_size: relay_params.relay_notify_limit_bucket_size as u8,
join_req_limit_size: relay_params.relay_join_req_limit_bucket_size as u8,
overall_limit_size: relay_params.relay_overall_limit_bucket_size,
global_uplink_limit_size: relay_params
.relay_global_uplink_limit_bucket_size,
notify_limit_size: relay_params.relay_notify_limit_bucket_size,
join_req_limit_size: relay_params.relay_join_req_limit_bucket_size,
},
},
)]);
mac_command::set_pending(&dev_eui, lrwn::CID::ConfigureFwdLimitReq, &set).await?;
self.mac_commands.push(set);
}
@ -1916,7 +1894,6 @@ impl Data {
}
let set = lrwn::MACCommandSet::new(commands);
mac_command::set_pending(&self.device.dev_eui, lrwn::CID::FilterListReq, &set).await?;
self.mac_commands.push(set);
// The deletes needs to be processed before we can add new entries.
@ -1945,8 +1922,6 @@ impl Data {
filter_list_eui: vec![],
},
)]);
mac_command::set_pending(&self.device.dev_eui, lrwn::CID::FilterListReq, &set)
.await?;
self.mac_commands.push(set);
// Return because we can't add multiple sets and if we would combine
@ -1978,7 +1953,6 @@ impl Data {
filter_list_eui: eui,
},
)]);
mac_command::set_pending(&dev_eui, lrwn::CID::FilterListReq, &set).await?;
self.mac_commands.push(set);
f.join_eui = device.join_eui.to_vec();
@ -2010,7 +1984,6 @@ impl Data {
filter_list_eui: eui,
},
)]);
mac_command::set_pending(&dev_eui, lrwn::CID::FilterListReq, &set).await?;
self.mac_commands.push(set);
ds.relay
@ -2038,7 +2011,6 @@ impl Data {
async fn _update_relay_conf(&mut self) -> Result<()> {
trace!("Updating Relay Conf");
let dev_eui = self.device.dev_eui;
let ds = self.device.get_device_session_mut()?;
let relay_params = self.device_profile.relay_params.clone().unwrap_or_default();
@ -2052,7 +2024,7 @@ impl Data {
if relay.enabled != relay_params.relay_enabled
|| relay.cad_periodicity != relay_params.relay_cad_periodicity as u32
|| relay.default_channel_index != relay_params.default_channel_index as u32
|| relay.second_channel_freq != relay_params.second_channel_freq as u32
|| relay.second_channel_freq != relay_params.second_channel_freq
|| relay.second_channel_dr != relay_params.second_channel_dr as u32
|| relay.second_channel_ack_offset != relay_params.second_channel_ack_offset as u32
{
@ -2063,20 +2035,19 @@ impl Data {
true => 1,
false => 0,
},
cad_periodicity: relay_params.relay_cad_periodicity as u8,
default_ch_idx: relay_params.default_channel_index as u8,
cad_periodicity: relay_params.relay_cad_periodicity,
default_ch_idx: relay_params.default_channel_index,
second_ch_idx: if relay_params.second_channel_freq > 0 {
1
} else {
0
},
second_ch_dr: relay_params.second_channel_dr as u8,
second_ch_ack_offset: relay_params.second_channel_ack_offset as u8,
second_ch_dr: relay_params.second_channel_dr,
second_ch_ack_offset: relay_params.second_channel_ack_offset,
},
second_ch_freq: relay_params.second_channel_freq as u32,
second_ch_freq: relay_params.second_channel_freq,
},
)]);
mac_command::set_pending(&dev_eui, lrwn::CID::RelayConfReq, &set).await?;
self.mac_commands.push(set);
}
@ -2088,7 +2059,6 @@ impl Data {
async fn _update_end_device_conf(&mut self) -> Result<()> {
trace!("Updating End Device Conf");
let dev_eui = self.device.dev_eui;
let ds = self.device.get_device_session_mut()?;
let relay_params = self.device_profile.relay_params.clone().unwrap_or_default();
@ -2102,7 +2072,7 @@ impl Data {
if relay.ed_activation_mode != relay_params.ed_activation_mode.to_u8() as u32
|| relay.ed_smart_enable_level != relay_params.ed_smart_enable_level as u32
|| relay.ed_back_off != relay_params.ed_back_off as u32
|| relay.second_channel_freq != relay_params.second_channel_freq as u32
|| relay.second_channel_freq != relay_params.second_channel_freq
|| relay.second_channel_dr != relay_params.second_channel_dr as u32
|| relay.second_channel_ack_offset != relay_params.second_channel_ack_offset as u32
{
@ -2110,22 +2080,21 @@ impl Data {
lrwn::EndDeviceConfReqPayload {
activation_relay_mode: lrwn::ActivationRelayMode {
relay_mode_activation: relay_params.ed_activation_mode,
smart_enable_level: relay_params.ed_smart_enable_level as u8,
smart_enable_level: relay_params.ed_smart_enable_level,
},
channel_settings_ed: lrwn::ChannelSettingsED {
second_ch_ack_offset: relay_params.second_channel_ack_offset as u8,
second_ch_dr: relay_params.second_channel_dr as u8,
second_ch_ack_offset: relay_params.second_channel_ack_offset,
second_ch_dr: relay_params.second_channel_dr,
second_ch_idx: if relay_params.second_channel_freq > 0 {
1
} else {
0
},
backoff: relay_params.ed_back_off as u8,
backoff: relay_params.ed_back_off,
},
second_ch_freq: relay_params.second_channel_freq as u32,
second_ch_freq: relay_params.second_channel_freq,
},
)]);
mac_command::set_pending(&dev_eui, lrwn::CID::EndDeviceConfReq, &set).await?;
self.mac_commands.push(set);
}

View File

@ -466,7 +466,7 @@ impl JoinAccept<'_> {
let mut relay_phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {

View File

@ -199,7 +199,7 @@ impl Multicast {
let mut phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {

View File

@ -3,7 +3,7 @@ use chrono::{Duration, Utc};
use tracing::{error, info, span, trace, Instrument, Level};
use uuid::Uuid;
use lrwn::{AES128Key, MType, Payload, PhyPayload, EUI64};
use lrwn::{AES128Key, FType, Payload, PhyPayload, EUI64};
use crate::api::helpers::ToProto;
use crate::storage::{
@ -589,13 +589,13 @@ impl TxAck {
tx_info: dfi.tx_info.clone(),
downlink_id: gw_df.downlink_id,
gateway_id: gw_df.gateway_id.clone(),
m_type: match &phy.mhdr.m_type {
MType::JoinAccept => common::MType::JoinAccept,
MType::UnconfirmedDataDown => common::MType::UnconfirmedDataDown,
MType::ConfirmedDataDown => common::MType::ConfirmedDataDown,
MType::Proprietary => common::MType::Proprietary,
f_type: match &phy.mhdr.f_type {
FType::JoinAccept => common::FType::JoinAccept,
FType::UnconfirmedDataDown => common::FType::UnconfirmedDataDown,
FType::ConfirmedDataDown => common::FType::ConfirmedDataDown,
FType::Proprietary => common::FType::Proprietary,
_ => {
return Err(anyhow!("Unepxected MType: {}", phy.mhdr.m_type));
return Err(anyhow!("Unepxected FType: {}", phy.mhdr.f_type));
}
}
.into(),
@ -658,7 +658,7 @@ impl TxAck {
tx_info: dfl.tx_info.clone(),
downlink_id: dfl.downlink_id,
gateway_id: dfl.gateway_id.clone(),
m_type: dfl.m_type,
f_type: dfl.f_type,
dev_addr: dfl.dev_addr.clone(),
dev_eui: dfl.dev_eui.clone(),
plaintext_f_opts: true,
@ -719,7 +719,7 @@ impl TxAck {
} else {
0
} as u32,
message_type: phy.mhdr.m_type.to_proto().into(),
frame_type: phy.mhdr.f_type.to_proto().into(),
gateway_id: df.downlink_frame.as_ref().unwrap().gateway_id.clone(),
};
@ -803,15 +803,15 @@ impl TxAck {
}
fn is_unconfirmed_downlink(&self) -> bool {
if self.phy_payload.as_ref().unwrap().mhdr.m_type == lrwn::MType::UnconfirmedDataDown {
if self.phy_payload.as_ref().unwrap().mhdr.f_type == lrwn::FType::UnconfirmedDataDown {
return true;
}
false
}
fn is_unconfirmed_downlink_relayed(&self) -> bool {
if self.phy_payload_relayed.as_ref().unwrap().mhdr.m_type
== lrwn::MType::UnconfirmedDataDown
if self.phy_payload_relayed.as_ref().unwrap().mhdr.f_type
== lrwn::FType::UnconfirmedDataDown
{
return true;
}
@ -819,14 +819,14 @@ impl TxAck {
}
fn is_confirmed_downlink(&self) -> bool {
if self.phy_payload.as_ref().unwrap().mhdr.m_type == lrwn::MType::ConfirmedDataDown {
if self.phy_payload.as_ref().unwrap().mhdr.f_type == lrwn::FType::ConfirmedDataDown {
return true;
}
false
}
fn is_confirmed_downlink_relayed(&self) -> bool {
if self.phy_payload_relayed.as_ref().unwrap().mhdr.m_type == lrwn::MType::ConfirmedDataDown
if self.phy_payload_relayed.as_ref().unwrap().mhdr.f_type == lrwn::FType::ConfirmedDataDown
{
return true;
}

View File

@ -1,3 +1,5 @@
use std::sync::LazyLock;
use anyhow::Result;
use async_trait::async_trait;
use tokio::sync::RwLock;
@ -6,11 +8,10 @@ use chirpstack_api::gw;
use super::GatewayBackend;
lazy_static! {
static ref DOWNLINK_FRAMES: RwLock<Vec<gw::DownlinkFrame>> = RwLock::new(Vec::new());
static ref GATEWAY_CONFIGURATIONS: RwLock<Vec<gw::GatewayConfiguration>> =
RwLock::new(Vec::new());
}
static DOWNLINK_FRAMES: LazyLock<RwLock<Vec<gw::DownlinkFrame>>> =
LazyLock::new(|| RwLock::new(Vec::new()));
static GATEWAY_CONFIGURATIONS: LazyLock<RwLock<Vec<gw::GatewayConfiguration>>> =
LazyLock::new(|| RwLock::new(Vec::new()));
pub async fn reset() {
DOWNLINK_FRAMES.write().await.drain(..);

View File

@ -1,4 +1,5 @@
use std::collections::HashMap;
use std::sync::LazyLock;
use anyhow::{Context, Result};
use async_trait::async_trait;
@ -11,10 +12,8 @@ use crate::config;
pub mod mock;
mod mqtt;
lazy_static! {
static ref BACKENDS: RwLock<HashMap<String, Box<dyn GatewayBackend + Sync + Send>>> =
RwLock::new(HashMap::new());
}
static BACKENDS: LazyLock<RwLock<HashMap<String, Box<dyn GatewayBackend + Sync + Send>>>> =
LazyLock::new(|| RwLock::new(HashMap::new()));
#[async_trait]
pub trait GatewayBackend {

View File

@ -1,6 +1,5 @@
use std::collections::HashMap;
use std::io::Cursor;
use std::sync::RwLock;
use std::sync::{LazyLock, RwLock};
use std::time::Duration;
use anyhow::Result;
@ -38,27 +37,26 @@ struct CommandLabels {
command: String,
}
lazy_static! {
static ref EVENT_COUNTER: Family<EventLabels, Counter> = {
let counter = Family::<EventLabels, Counter>::default();
prometheus::register(
"gateway_backend_mqtt_events",
"Number of events received",
counter.clone(),
);
counter
};
static ref COMMAND_COUNTER: Family<CommandLabels, Counter> = {
let counter = Family::<CommandLabels, Counter>::default();
prometheus::register(
"gateway_backend_mqtt_commands",
"Number of commands sent",
counter.clone(),
);
counter
};
static ref GATEWAY_JSON: RwLock<HashMap<String, bool>> = RwLock::new(HashMap::new());
}
static EVENT_COUNTER: LazyLock<Family<EventLabels, Counter>> = LazyLock::new(|| {
let counter = Family::<EventLabels, Counter>::default();
prometheus::register(
"gateway_backend_mqtt_events",
"Number of events received",
counter.clone(),
);
counter
});
static COMMAND_COUNTER: LazyLock<Family<CommandLabels, Counter>> = LazyLock::new(|| {
let counter = Family::<CommandLabels, Counter>::default();
prometheus::register(
"gateway_backend_mqtt_commands",
"Number of commands sent",
counter.clone(),
);
counter
});
static GATEWAY_JSON: LazyLock<RwLock<HashMap<String, bool>>> =
LazyLock::new(|| RwLock::new(HashMap::new()));
pub struct MqttBackend<'a> {
client: AsyncClient,
@ -353,7 +351,7 @@ async fn message_callback(
.inc();
let mut event = match json {
true => serde_json::from_slice(&p.payload)?,
false => chirpstack_api::gw::UplinkFrame::decode(&mut Cursor::new(&p.payload))?,
false => chirpstack_api::gw::UplinkFrame::decode(p.payload.as_ref())?,
};
if v4_migrate {
@ -378,7 +376,7 @@ async fn message_callback(
.inc();
let mut event = match json {
true => serde_json::from_slice(&p.payload)?,
false => chirpstack_api::gw::GatewayStats::decode(&mut Cursor::new(&p.payload))?,
false => chirpstack_api::gw::GatewayStats::decode(p.payload.as_ref())?,
};
if v4_migrate {
@ -402,7 +400,7 @@ async fn message_callback(
.inc();
let mut event = match json {
true => serde_json::from_slice(&p.payload)?,
false => chirpstack_api::gw::DownlinkTxAck::decode(&mut Cursor::new(&p.payload))?,
false => chirpstack_api::gw::DownlinkTxAck::decode(p.payload.as_ref())?,
};
if v4_migrate {
@ -411,18 +409,18 @@ async fn message_callback(
set_gateway_json(&event.gateway_id, json);
tokio::spawn(downlink::tx_ack::TxAck::handle(event));
} else if topic.ends_with("/mesh-heartbeat") {
} else if topic.ends_with("/mesh") {
EVENT_COUNTER
.get_or_create(&EventLabels {
event: "mesh-heartbeat".to_string(),
event: "mesh".to_string(),
})
.inc();
let event = match json {
true => serde_json::from_slice(&p.payload)?,
false => chirpstack_api::gw::MeshHeartbeat::decode(&mut Cursor::new(&p.payload))?,
false => chirpstack_api::gw::MeshEvent::decode(p.payload.as_ref())?,
};
tokio::spawn(uplink::mesh::MeshHeartbeat::handle(event));
tokio::spawn(uplink::mesh::Mesh::handle(event));
} else {
return Err(anyhow!("Unknown event type"));
}

View File

@ -1,82 +1,85 @@
use std::sync::LazyLock;
use chrono::{DateTime, Duration, TimeZone, Utc};
lazy_static! {
static ref GPS_EPOCH_TIME: DateTime<Utc> = Utc.with_ymd_and_hms(1980, 1, 6, 0, 0, 0).unwrap();
static ref LEAP_SECONDS_TABLE: Vec<(DateTime<Utc>, Duration)> = vec![
static GPS_EPOCH_TIME: LazyLock<DateTime<Utc>> =
LazyLock::new(|| Utc.with_ymd_and_hms(1980, 1, 6, 0, 0, 0).unwrap());
static LEAP_SECONDS_TABLE: LazyLock<Vec<(DateTime<Utc>, Duration)>> = LazyLock::new(|| {
vec![
(
Utc.with_ymd_and_hms(1981, 6, 30, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(1982, 6, 30, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(1983, 6, 30, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(1985, 6, 30, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(1987, 12, 31, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(1989, 12, 31, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(1990, 12, 31, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(1992, 6, 30, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(1993, 6, 30, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(1994, 6, 30, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(1995, 12, 31, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(1997, 6, 30, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(1998, 12, 31, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(2005, 12, 31, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(2008, 12, 31, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(2012, 6, 30, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(2015, 6, 30, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
(
Utc.with_ymd_and_hms(2016, 12, 31, 23, 59, 59).unwrap(),
Duration::try_seconds(1).unwrap()
Duration::try_seconds(1).unwrap(),
),
];
}
]
});
pub trait ToGpsTime {
fn to_gps_time(&self) -> Duration;

View File

@ -1,4 +1,5 @@
use std::collections::HashMap;
use std::sync::LazyLock;
use anyhow::Result;
use async_trait::async_trait;
@ -19,15 +20,14 @@ use chirpstack_api::integration;
// implement re-connect on error. To reconnect within the Integration struct would require
// mutability of the Integration struct, which is not possible without changing the
// IntegrationTrait as we would need to change the (&self, ...) signatures to (&mut self, ...).
lazy_static! {
static ref CONNECTION: RwLock<Option<Connection>> = RwLock::new(None);
static ref CHANNEL: RwLock<Option<Channel>> = RwLock::new(None);
}
static CONNECTION: LazyLock<RwLock<Option<Connection>>> = LazyLock::new(|| RwLock::new(None));
static CHANNEL: LazyLock<RwLock<Option<Channel>>> = LazyLock::new(|| RwLock::new(None));
pub struct Integration<'a> {
templates: Handlebars<'a>,
json: bool,
url: String,
exchange: String,
}
#[derive(Serialize)]
@ -50,6 +50,7 @@ impl<'a> Integration<'a> {
templates,
url: conf.url.clone(),
json: conf.json,
exchange: conf.exchange.clone(),
};
i.connect().await?;
@ -91,7 +92,7 @@ impl<'a> Integration<'a> {
.as_ref()
.unwrap()
.basic_publish(
"amq.topic",
&self.exchange,
&routing_key,
BasicPublishOptions::default(),
b,
@ -128,7 +129,7 @@ impl<'a> Integration<'a> {
}
#[async_trait]
impl<'a> IntegrationTrait for Integration<'a> {
impl IntegrationTrait for Integration<'_> {
async fn uplink_event(
&self,
_vars: &HashMap<String, String>,

View File

@ -20,6 +20,7 @@ fn get_client() -> Client {
.get_or_init(|| {
Client::builder()
.timeout(Duration::from_secs(5))
.use_rustls_tls()
.build()
.unwrap()
})

View File

@ -107,7 +107,7 @@ impl<'a> Integration<'a> {
}
#[async_trait]
impl<'a> IntegrationTrait for Integration<'a> {
impl IntegrationTrait for Integration<'_> {
async fn uplink_event(
&self,
_vars: &HashMap<String, String>,

View File

@ -539,7 +539,7 @@ impl<'de> Deserialize<'de> for Eui64Wrapper {
struct Eui64WrapperVisitor;
impl<'de> Visitor<'de> for Eui64WrapperVisitor {
impl Visitor<'_> for Eui64WrapperVisitor {
type Value = Eui64Wrapper;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {

View File

@ -1,4 +1,5 @@
use std::collections::HashMap;
use std::sync::LazyLock;
use anyhow::Result;
use async_trait::async_trait;
@ -8,17 +9,22 @@ use chirpstack_api::integration;
use super::Integration as IntegrationTrait;
lazy_static! {
static ref UPLINK_EVENTS: RwLock<Vec<integration::UplinkEvent>> = RwLock::new(Vec::new());
static ref JOIN_EVENTS: RwLock<Vec<integration::JoinEvent>> = RwLock::new(Vec::new());
static ref ACK_EVENTS: RwLock<Vec<integration::AckEvent>> = RwLock::new(Vec::new());
static ref TXACK_EVENTS: RwLock<Vec<integration::TxAckEvent>> = RwLock::new(Vec::new());
static ref LOG_EVENTS: RwLock<Vec<integration::LogEvent>> = RwLock::new(Vec::new());
static ref STATUS_EVENTS: RwLock<Vec<integration::StatusEvent>> = RwLock::new(Vec::new());
static ref LOCATION_EVENTS: RwLock<Vec<integration::LocationEvent>> = RwLock::new(Vec::new());
static ref INTEGRATION_EVENTS: RwLock<Vec<integration::IntegrationEvent>> =
RwLock::new(Vec::new());
}
static UPLINK_EVENTS: LazyLock<RwLock<Vec<integration::UplinkEvent>>> =
LazyLock::new(|| RwLock::new(Vec::new()));
static JOIN_EVENTS: LazyLock<RwLock<Vec<integration::JoinEvent>>> =
LazyLock::new(|| RwLock::new(Vec::new()));
static ACK_EVENTS: LazyLock<RwLock<Vec<integration::AckEvent>>> =
LazyLock::new(|| RwLock::new(Vec::new()));
static TXACK_EVENTS: LazyLock<RwLock<Vec<integration::TxAckEvent>>> =
LazyLock::new(|| RwLock::new(Vec::new()));
static LOG_EVENTS: LazyLock<RwLock<Vec<integration::LogEvent>>> =
LazyLock::new(|| RwLock::new(Vec::new()));
static STATUS_EVENTS: LazyLock<RwLock<Vec<integration::StatusEvent>>> =
LazyLock::new(|| RwLock::new(Vec::new()));
static LOCATION_EVENTS: LazyLock<RwLock<Vec<integration::LocationEvent>>> =
LazyLock::new(|| RwLock::new(Vec::new()));
static INTEGRATION_EVENTS: LazyLock<RwLock<Vec<integration::IntegrationEvent>>> =
LazyLock::new(|| RwLock::new(Vec::new()));
pub async fn reset() {
UPLINK_EVENTS.write().await.drain(..);

View File

@ -1,5 +1,6 @@
use std::collections::HashMap;
use std::str::FromStr;
use std::sync::LazyLock;
use anyhow::{Context, Result};
use async_trait::async_trait;
@ -33,11 +34,11 @@ mod postgresql;
mod redis;
mod thingsboard;
lazy_static! {
static ref GLOBAL_INTEGRATIONS: RwLock<Vec<Box<dyn Integration + Sync + Send>>> =
RwLock::new(Vec::new());
static ref MOCK_INTEGRATION: RwLock<bool> = RwLock::new(false);
}
static GLOBAL_INTEGRATIONS: LazyLock<RwLock<Vec<Box<dyn Integration + Sync + Send>>>> =
LazyLock::new(|| RwLock::new(Vec::new()));
#[cfg(test)]
static MOCK_INTEGRATION: LazyLock<RwLock<bool>> = LazyLock::new(|| RwLock::new(false));
pub async fn setup() -> Result<()> {
info!("Setting up global integrations");

View File

@ -106,7 +106,7 @@ pub mod test {
ch: 0,
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {

View File

@ -53,7 +53,7 @@ pub mod test {
ch: 0,
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {

View File

@ -338,7 +338,7 @@ pub mod test {
ch: 0,
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {

View File

@ -77,7 +77,7 @@ pub mod test {
ch: 0,
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {

View File

@ -33,7 +33,7 @@ pub mod update_uplink_list;
// This returns the mac-commands which must be sent back to the device as response and a bool
// indicating if a downlink must be sent. For some mac-commands, no mac-command answer is required,
// but the device expects a downlink as confirmation, even if the downlink frame is empty.
pub async fn handle_uplink<'a>(
pub async fn handle_uplink(
uplink_frame_set: &UplinkFrameSet,
cmds: &lrwn::MACCommandSet,
tenant: &tenant::Tenant,
@ -77,7 +77,7 @@ pub async fn handle_uplink<'a>(
);
// Get pending mac-command block, this could return None.
let pending = match mac_command::get_pending(&dev.dev_eui, cid).await {
let pending = match mac_command::get_pending(dev.get_device_session_mut()?, cid).await {
Ok(v) => v,
Err(e) => {
error!(dev_eui = %dev.dev_eui, cid = %cid, error = %e, "Get pending mac-command block error");
@ -85,13 +85,6 @@ pub async fn handle_uplink<'a>(
}
};
// Delete the pending mac-command.
if pending.is_some() {
if let Err(e) = mac_command::delete_pending(&dev.dev_eui, cid).await {
error!(dev_eui = %dev.dev_eui, cid = %cid, error = %e, "Delete pending mac-command error");
}
}
// Handle the mac-command, which might return a block to answer the uplink mac-command
// request.
let res = match handle(
@ -182,7 +175,7 @@ pub mod test {
ch: 0,
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {

View File

@ -1,7 +1,5 @@
#![recursion_limit = "256"]
#[macro_use]
extern crate lazy_static;
extern crate diesel_migrations;
#[macro_use]
extern crate diesel;

View File

@ -1,12 +1,10 @@
use std::sync::RwLock;
use std::sync::{LazyLock, RwLock};
use anyhow::Result;
use prometheus_client::encoding::text::encode;
use prometheus_client::registry::{Metric, Registry};
lazy_static! {
static ref REGISTRY: RwLock<Registry> = RwLock::new(<Registry>::default());
}
static REGISTRY: LazyLock<RwLock<Registry>> = LazyLock::new(|| RwLock::new(<Registry>::default()));
pub fn encode_to_string() -> Result<String> {
let registry_r = REGISTRY.read().unwrap();

View File

@ -1,5 +1,5 @@
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use std::sync::{Arc, LazyLock, RwLock};
use anyhow::{Context, Result};
use tracing::{info, span, trace, Level};
@ -7,10 +7,8 @@ use tracing::{info, span, trace, Level};
use crate::config;
use lrwn::region;
lazy_static! {
static ref REGIONS: RwLock<HashMap<String, Arc<Box<dyn region::Region + Sync + Send>>>> =
RwLock::new(HashMap::new());
}
static REGIONS: LazyLock<RwLock<HashMap<String, Arc<Box<dyn region::Region + Sync + Send>>>>> =
LazyLock::new(|| RwLock::new(HashMap::new()));
pub fn setup() -> Result<()> {
info!("Setting up regions");

View File

@ -116,6 +116,7 @@ pub struct Device {
pub join_eui: EUI64,
pub secondary_dev_addr: Option<DevAddr>,
pub device_session: Option<fields::DeviceSession>,
pub app_layer_params: fields::device::AppLayerParams,
}
#[derive(AsChangeset, Debug, Clone, Default)]
@ -133,6 +134,7 @@ pub struct DeviceChangeset {
pub battery_level: Option<Option<fields::BigDecimal>>,
pub scheduler_run_after: Option<Option<DateTime<Utc>>>,
pub is_disabled: Option<bool>,
pub app_layer_params: Option<fields::device::AppLayerParams>,
}
impl Device {
@ -190,6 +192,7 @@ impl Default for Device {
join_eui: EUI64::default(),
secondary_dev_addr: None,
device_session: None,
app_layer_params: Default::default(),
}
}
}
@ -324,6 +327,15 @@ pub async fn get_for_phypayload_and_incr_f_cnt_up(
return Err(Error::InvalidPayload("MacPayload".to_string()));
};
// We calculate the scheduler_run_after timestamp, such that we can update
// it directly when updating the device-session (to update the frame-counter).
// This way, we limit the risk of overlapping Class-A downlinks with Class-B / -C
// downlinks.
let conf = config::get();
let scheduler_run_after = Utc::now()
+ Duration::from_std(conf.network.scheduler.class_a_lock_duration)
.map_err(anyhow::Error::new)?;
let mut c = get_async_db_conn().await?;
db_transaction::<ValidationStatus, Error, _>(&mut c, |c| {
@ -424,10 +436,20 @@ pub async fn get_for_phypayload_and_incr_f_cnt_up(
let ds_f_cnt_up = ds.f_cnt_up;
ds.f_cnt_up = full_f_cnt + 1;
let _ = diesel::update(device::dsl::device.find(d.dev_eui))
.set(device::device_session.eq(&ds.clone()))
.execute(c)
.await?;
if scheduler_run_after > d.scheduler_run_after.unwrap_or_default() {
let _ = diesel::update(device::dsl::device.find(d.dev_eui))
.set((
device::device_session.eq(&ds.clone()),
device::scheduler_run_after.eq(&scheduler_run_after),
))
.execute(c)
.await?;
} else {
let _ = diesel::update(device::dsl::device.find(d.dev_eui))
.set(device::device_session.eq(&ds.clone()))
.execute(c)
.await?;
}
// We do return the device-session with original frame-counter
ds.f_cnt_up = ds_f_cnt_up;
@ -552,6 +574,7 @@ pub async fn update(d: Device) -> Result<Device, Error> {
device::tags.eq(&d.tags),
device::variables.eq(&d.variables),
device::join_eui.eq(&d.join_eui),
device::app_layer_params.eq(&d.app_layer_params),
))
.get_result(&mut get_async_db_conn().await?)
.await
@ -707,17 +730,37 @@ pub async fn list(
true => match order_by {
OrderBy::Name => q.order_by(device::dsl::name.desc()),
OrderBy::DevEui => q.order_by(device::dsl::dev_eui.desc()),
OrderBy::LastSeenAt => q
.order_by(device::dsl::last_seen_at.desc())
.then_order_by(device::dsl::name),
OrderBy::LastSeenAt => {
#[cfg(feature = "postgres")]
{
q.order_by(device::dsl::last_seen_at.desc().nulls_last())
.then_order_by(device::dsl::name)
}
#[cfg(feature = "sqlite")]
{
q.order_by(device::dsl::last_seen_at.desc())
.then_order_by(device::dsl::name)
}
}
OrderBy::DeviceProfileName => q.order_by(device_profile::dsl::name.desc()),
},
false => match order_by {
OrderBy::Name => q.order_by(device::dsl::name),
OrderBy::DevEui => q.order_by(device::dsl::dev_eui),
OrderBy::LastSeenAt => q
.order_by(device::dsl::last_seen_at)
.then_order_by(device::dsl::name),
OrderBy::LastSeenAt => {
#[cfg(feature = "postgres")]
{
q.order_by(device::dsl::last_seen_at.asc().nulls_first())
.then_order_by(device::dsl::name)
}
#[cfg(feature = "sqlite")]
{
q.order_by(device::dsl::last_seen_at.asc())
.then_order_by(device::dsl::name)
}
}
OrderBy::DeviceProfileName => q.order_by(device_profile::dsl::name),
},
};
@ -1639,7 +1682,7 @@ pub mod test {
println!("> {}", tst.name);
let mut phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {

View File

@ -109,7 +109,7 @@ impl DeviceProfile {
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_freq = class_b_params.ping_slot_freq;
ds.class_b_ping_slot_nb = 1 << class_b_params.ping_slot_nb_k as u32;
}
@ -133,7 +133,7 @@ impl DeviceProfile {
ds.rx1_delay = abp_params.rx1_delay as u32;
ds.rx1_dr_offset = abp_params.rx1_dr_offset as u32;
ds.rx2_dr = abp_params.rx2_dr as u32;
ds.rx2_frequency = abp_params.rx2_freq as u32;
ds.rx2_frequency = abp_params.rx2_freq;
}
}
}

View File

@ -24,7 +24,10 @@ pub async fn save(df: &internal::DownlinkFrame) -> Result<()> {
pub async fn get_and_del(id: u32) -> Result<internal::DownlinkFrame, Error> {
let key = redis_key(format!("frame:{}", id));
let v: Vec<u8> = redis::cmd("GETDEL")
let (v, _): (Vec<u8>, u8) = redis::pipe()
.cmd("GET")
.arg(key.clone())
.cmd("DEL")
.arg(key)
.query_async(&mut get_async_redis_conn().await?)
.await?;

View File

@ -34,7 +34,7 @@ pub enum Error {
NotAllowed(String),
#[error("Multiple errors")]
MultiError(Vec<Error>),
Multi(Vec<Error>),
#[error(transparent)]
Diesel(#[from] diesel::result::Error),

View File

@ -0,0 +1,52 @@
use diesel::backend::Backend;
use diesel::{deserialize, serialize};
#[cfg(feature = "postgres")]
use diesel::{pg::Pg, sql_types::Jsonb};
#[cfg(feature = "sqlite")]
use diesel::{sql_types::Text, sqlite::Sqlite};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, AsExpression, FromSqlRow)]
#[cfg_attr(feature = "postgres", diesel(sql_type = Jsonb))]
#[cfg_attr(feature = "sqlite", diesel(sql_type = Text))]
#[serde(default)]
#[derive(Default)]
pub struct AppLayerParams {
pub ts004_session_cnt: [u16; 4],
}
#[cfg(feature = "postgres")]
impl deserialize::FromSql<Jsonb, Pg> for AppLayerParams {
fn from_sql(value: <Pg as Backend>::RawValue<'_>) -> deserialize::Result<Self> {
let value = <serde_json::Value as deserialize::FromSql<Jsonb, Pg>>::from_sql(value)?;
Ok(serde_json::from_value(value)?)
}
}
#[cfg(feature = "postgres")]
impl serialize::ToSql<Jsonb, Pg> for AppLayerParams {
fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, Pg>) -> serialize::Result {
let value = serde_json::to_value(self)?;
<serde_json::Value as serialize::ToSql<Jsonb, Pg>>::to_sql(&value, &mut out.reborrow())
}
}
#[cfg(feature = "sqlite")]
impl deserialize::FromSql<Text, Sqlite> for AppLayerParams
where
*const str: deserialize::FromSql<Text, Sqlite>,
{
fn from_sql(value: <Sqlite as Backend>::RawValue<'_>) -> deserialize::Result<Self> {
let s =
<*const str as deserialize::FromSql<diesel::sql_types::Text, Sqlite>>::from_sql(value)?;
Ok(serde_json::from_str(unsafe { &*s })?)
}
}
#[cfg(feature = "sqlite")]
impl serialize::ToSql<Text, Sqlite> for AppLayerParams {
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)
}
}

View File

@ -29,7 +29,7 @@ impl deserialize::FromSql<Jsonb, Pg> for AbpParams {
#[cfg(feature = "postgres")]
impl serialize::ToSql<Jsonb, Pg> for AbpParams {
fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, Pg>) -> serialize::Result {
let value = serde_json::to_value(&self)?;
let value = serde_json::to_value(self)?;
<serde_json::Value as serialize::ToSql<Jsonb, Pg>>::to_sql(&value, &mut out.reborrow())
}
}
@ -77,7 +77,7 @@ impl deserialize::FromSql<Jsonb, Pg> for ClassBParams {
#[cfg(feature = "postgres")]
impl serialize::ToSql<Jsonb, Pg> for ClassBParams {
fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, Pg>) -> serialize::Result {
let value = serde_json::to_value(&self)?;
let value = serde_json::to_value(self)?;
<serde_json::Value as serialize::ToSql<Jsonb, Pg>>::to_sql(&value, &mut out.reborrow())
}
}
@ -122,7 +122,7 @@ impl deserialize::FromSql<Jsonb, Pg> for ClassCParams {
#[cfg(feature = "postgres")]
impl serialize::ToSql<Jsonb, Pg> for ClassCParams {
fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, Pg>) -> serialize::Result {
let value = serde_json::to_value(&self)?;
let value = serde_json::to_value(self)?;
<serde_json::Value as serialize::ToSql<Jsonb, Pg>>::to_sql(&value, &mut out.reborrow())
}
}
@ -189,7 +189,7 @@ impl deserialize::FromSql<Jsonb, Pg> for RelayParams {
#[cfg(feature = "postgres")]
impl serialize::ToSql<Jsonb, Pg> for RelayParams {
fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, Pg>) -> serialize::Result {
let value = serde_json::to_value(&self)?;
let value = serde_json::to_value(self)?;
<serde_json::Value as serialize::ToSql<Jsonb, Pg>>::to_sql(&value, &mut out.reborrow())
}
}
@ -263,14 +263,9 @@ impl Default for AppLayerParams {
impl AppLayerParams {
pub fn is_app_layer_f_port(&self, f_port: u8) -> bool {
if (self.ts003_version.is_some() && self.ts003_f_port == f_port)
(self.ts003_version.is_some() && self.ts003_f_port == f_port)
|| (self.ts004_version.is_some() && self.ts004_f_port == f_port)
|| (self.ts005_version.is_some() && self.ts005_f_port == f_port)
{
true
} else {
false
}
}
}
@ -285,7 +280,7 @@ impl deserialize::FromSql<Jsonb, Pg> for AppLayerParams {
#[cfg(feature = "postgres")]
impl serialize::ToSql<Jsonb, Pg> for AppLayerParams {
fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, Pg>) -> serialize::Result {
let value = serde_json::to_value(&self)?;
let value = serde_json::to_value(self)?;
<serde_json::Value as serialize::ToSql<Jsonb, Pg>>::to_sql(&value, &mut out.reborrow())
}
}

View File

@ -1,5 +1,6 @@
mod big_decimal;
mod dev_nonces;
pub mod device;
pub mod device_profile;
mod device_session;
mod fuota;

View File

@ -336,7 +336,7 @@ pub async fn add_devices(fuota_deployment_id: Uuid, dev_euis: Vec<EUI64>) -> Res
if errors.is_empty() {
Ok(())
} else {
Err(Error::MultiError(errors))
Err(Error::Multi(errors))
}
}
@ -552,7 +552,7 @@ pub async fn add_gateways(fuota_deployment_id: Uuid, gateway_ids: Vec<EUI64>) ->
if errors.is_empty() {
Ok(())
} else {
Err(Error::MultiError(errors))
Err(Error::Multi(errors))
}
}
@ -789,7 +789,7 @@ pub fn get_multicast_timeout(d: &FuotaDeployment) -> Result<usize> {
conf.network.scheduler.multicast_class_c_margin.as_secs() as usize;
// Multiply by the number of fragments (+1 for additional margin).
let mc_class_c_duration_secs = mc_class_c_margin_secs * (total_fragments + 1 as usize);
let mc_class_c_duration_secs = mc_class_c_margin_secs * (total_fragments + 1);
// Calculate the timeout value. In case of Class-C, timeout is defined as seconds,
// where the number of seconds is 2^timeout.

View File

@ -365,16 +365,36 @@ pub async fn list(
true => match order_by {
OrderBy::Name => q.order_by(gateway::dsl::name.desc()),
OrderBy::GatewayId => q.order_by(gateway::dsl::gateway_id.desc()),
OrderBy::LastSeenAt => q
.order_by(gateway::dsl::last_seen_at.desc())
.then_order_by(gateway::dsl::name),
OrderBy::LastSeenAt => {
#[cfg(feature = "postgres")]
{
q.order_by(gateway::dsl::last_seen_at.desc().nulls_last())
.then_order_by(gateway::dsl::name)
}
#[cfg(feature = "sqlite")]
{
q.order_by(gateway::dsl::last_seen_at.desc())
.then_order_by(gateway::dsl::name)
}
}
},
false => match order_by {
OrderBy::Name => q.order_by(gateway::dsl::name),
OrderBy::GatewayId => q.order_by(gateway::dsl::gateway_id),
OrderBy::LastSeenAt => q
.order_by(gateway::dsl::last_seen_at)
.then_order_by(gateway::dsl::name),
OrderBy::LastSeenAt => {
#[cfg(feature = "postgres")]
{
q.order_by(gateway::dsl::last_seen_at.asc().nulls_first())
.then_order_by(gateway::dsl::name)
}
#[cfg(feature = "sqlite")]
{
q.order_by(gateway::dsl::last_seen_at.asc())
.then_order_by(gateway::dsl::name)
}
}
},
};

View File

@ -1,34 +1,24 @@
use anyhow::Result;
use tracing::info;
use super::{get_async_redis_conn, redis_key};
use crate::config;
use lrwn::EUI64;
use chirpstack_api::internal;
pub async fn set_pending(dev_eui: &EUI64, cid: lrwn::CID, set: &lrwn::MACCommandSet) -> Result<()> {
let conf = config::get();
let key = redis_key(format!("device:{}:mac:pending:{}", dev_eui, cid.to_u8()));
let ttl = conf.network.device_session_ttl.as_millis() as usize;
pub fn set_pending(ds: &mut internal::DeviceSession, set: &lrwn::MACCommandSet) -> Result<()> {
let cid = set.cid()?;
let b = set.to_vec()?;
() = redis::cmd("PSETEX")
.arg(key)
.arg(ttl)
.arg(b)
.query_async(&mut get_async_redis_conn().await?)
.await?;
info!(dev_eui = %dev_eui, cid = %cid, "Pending mac-command block set");
ds.mac_command_pending.insert(cid.to_u8().into(), b);
info!(cid = %cid, "Pending mac-command block set");
Ok(())
}
pub async fn get_pending(dev_eui: &EUI64, cid: lrwn::CID) -> Result<Option<lrwn::MACCommandSet>> {
let key = redis_key(format!("device:{}:mac:pending:{}", dev_eui, cid.to_u8()));
let b: Vec<u8> = redis::cmd("GET")
.arg(key)
.query_async(&mut get_async_redis_conn().await?)
.await?;
pub async fn get_pending(
ds: &mut internal::DeviceSession,
cid: lrwn::CID,
) -> Result<Option<lrwn::MACCommandSet>> {
let b = ds
.mac_command_pending
.remove(&cid.to_u8().into())
.unwrap_or_default();
let out = if !b.is_empty() {
let mut mac = lrwn::MACCommandSet::from_slice(&b);
@ -44,49 +34,3 @@ pub async fn get_pending(dev_eui: &EUI64, cid: lrwn::CID) -> Result<Option<lrwn:
Ok(out)
}
pub async fn delete_pending(dev_eui: &EUI64, cid: lrwn::CID) -> Result<()> {
let key = redis_key(format!("device:{}:mac:pending:{}", dev_eui, cid.to_u8()));
() = redis::cmd("DEL")
.arg(key)
.query_async(&mut get_async_redis_conn().await?)
.await?;
info!(dev_eui = %dev_eui, cid = %cid, "Pending mac-command block deleted");
Ok(())
}
#[cfg(test)]
pub mod test {
use super::*;
use crate::test;
#[tokio::test]
async fn test_mac_command() {
let _guard = test::prepare().await;
let dev_eui = EUI64::from_be_bytes([1, 2, 3, 4, 5, 6, 7, 8]);
let mac = lrwn::MACCommandSet::new(vec![lrwn::MACCommand::DevStatusReq]);
// set
set_pending(&dev_eui, lrwn::CID::DevStatusReq, &mac)
.await
.unwrap();
// get
let mac_get = get_pending(&dev_eui, lrwn::CID::DevStatusReq)
.await
.unwrap();
assert_eq!(mac, mac_get.unwrap());
// delete
delete_pending(&dev_eui, lrwn::CID::DevStatusReq)
.await
.unwrap();
let resp = get_pending(&dev_eui, lrwn::CID::DevStatusReq)
.await
.unwrap();
assert!(resp.is_none());
}
}

View File

@ -1,3 +1,4 @@
use std::sync::LazyLock;
use std::sync::RwLock;
use std::time::Instant;
@ -47,19 +48,18 @@ pub mod user;
use crate::monitoring::prometheus;
lazy_static! {
static ref ASYNC_REDIS_POOL: TokioRwLock<Option<AsyncRedisPool>> = TokioRwLock::new(None);
static ref REDIS_PREFIX: RwLock<String> = RwLock::new("".to_string());
static ref STORAGE_REDIS_CONN_GET: Histogram = {
let histogram = Histogram::new(exponential_buckets(0.001, 2.0, 12));
prometheus::register(
"storage_redis_conn_get_duration_seconds",
"Time between requesting a Redis connection and the connection-pool returning it",
histogram.clone(),
);
histogram
};
}
static ASYNC_REDIS_POOL: LazyLock<TokioRwLock<Option<AsyncRedisPool>>> =
LazyLock::new(|| TokioRwLock::new(None));
static REDIS_PREFIX: LazyLock<RwLock<String>> = LazyLock::new(|| RwLock::new("".to_string()));
static STORAGE_REDIS_CONN_GET: LazyLock<Histogram> = LazyLock::new(|| {
let histogram = Histogram::new(exponential_buckets(0.001, 2.0, 12));
prometheus::register(
"storage_redis_conn_get_duration_seconds",
"Time between requesting a Redis connection and the connection-pool returning it",
histogram.clone(),
);
histogram
});
#[cfg(feature = "postgres")]
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("./migrations_postgres");

View File

@ -1012,7 +1012,7 @@ pub mod test {
// invalid f_port
assert!(enqueue(
MulticastGroupQueueItem {
multicast_group_id: mg.id.into(),
multicast_group_id: mg.id,
gateway_id: gw.gateway_id,
f_cnt: 1,
f_port: 0,
@ -1026,7 +1026,7 @@ pub mod test {
assert!(enqueue(
MulticastGroupQueueItem {
multicast_group_id: mg.id.into(),
multicast_group_id: mg.id,
gateway_id: gw.gateway_id,
f_cnt: 1,
f_port: 256,
@ -1041,7 +1041,7 @@ pub mod test {
// Enqueue (Class-C) (delay)
let (ids, f_cnt) = enqueue(
MulticastGroupQueueItem {
multicast_group_id: mg.id.into(),
multicast_group_id: mg.id,
gateway_id: gw.gateway_id,
f_cnt: 1,
f_port: 2,
@ -1071,7 +1071,7 @@ pub mod test {
let mut mg = update(mg).await.unwrap();
let (ids, f_cnt) = enqueue(
MulticastGroupQueueItem {
multicast_group_id: mg.id.into(),
multicast_group_id: mg.id,
gateway_id: gw.gateway_id,
f_cnt: 1,
f_port: 2,
@ -1098,7 +1098,7 @@ pub mod test {
let mg = update(mg).await.unwrap();
let (ids, f_cnt) = enqueue(
MulticastGroupQueueItem {
multicast_group_id: mg.id.into(),
multicast_group_id: mg.id,
gateway_id: gw.gateway_id,
f_cnt: 1,
f_port: 2,

View File

@ -1,4 +1,4 @@
use std::sync::RwLock;
use std::sync::{LazyLock, RwLock};
use std::time::Instant;
use anyhow::Result;
@ -20,18 +20,16 @@ use crate::helpers::tls::get_root_certs;
pub type AsyncPgPool = DeadpoolPool<AsyncPgConnection>;
pub type AsyncPgPoolConnection = DeadpoolObject<AsyncPgConnection>;
lazy_static! {
static ref ASYNC_PG_POOL: RwLock<Option<AsyncPgPool>> = RwLock::new(None);
static ref STORAGE_PG_CONN_GET: Histogram = {
let histogram = Histogram::new(exponential_buckets(0.001, 2.0, 12));
prometheus::register(
"storage_pg_conn_get_duration_seconds",
"Time between requesting a PostgreSQL connection and the connection-pool returning it",
histogram.clone(),
);
histogram
};
}
static ASYNC_PG_POOL: LazyLock<RwLock<Option<AsyncPgPool>>> = LazyLock::new(|| RwLock::new(None));
static STORAGE_PG_CONN_GET: LazyLock<Histogram> = LazyLock::new(|| {
let histogram = Histogram::new(exponential_buckets(0.001, 2.0, 12));
prometheus::register(
"storage_pg_conn_get_duration_seconds",
"Time between requesting a PostgreSQL connection and the connection-pool returning it",
histogram.clone(),
);
histogram
});
pub fn setup(conf: &config::Postgresql) -> Result<()> {
info!("Setting up PostgreSQL connection pool");

View File

@ -65,6 +65,7 @@ diesel::table! {
join_eui -> Bytea,
secondary_dev_addr -> Nullable<Bytea>,
device_session -> Nullable<Bytea>,
app_layer_params -> Jsonb,
}
}

View File

@ -60,6 +60,7 @@ diesel::table! {
join_eui -> Binary,
secondary_dev_addr -> Nullable<Binary>,
device_session -> Nullable<Binary>,
app_layer_params -> Text,
}
}

View File

@ -1,4 +1,5 @@
use std::collections::HashMap;
use std::sync::LazyLock;
use anyhow::{Context, Result};
use diesel_async::RunQueryDsl;
@ -8,9 +9,7 @@ use uuid::Uuid;
use super::{error::Error, fields, get_async_db_conn};
use lrwn::EUI64;
lazy_static! {
static ref SEARCH_TAG_RE: Regex = Regex::new(r"([^ ]+):([^ ]+)").unwrap();
}
static SEARCH_TAG_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"([^ ]+):([^ ]+)").unwrap());
#[derive(QueryableByName, PartialEq, Debug)]
pub struct SearchResult {
@ -449,8 +448,8 @@ pub mod test {
let _d = device::create(device::Device {
dev_eui: EUI64::from_str("0203040506070809").unwrap(),
name: "test-device".into(),
application_id: a.id.clone(),
device_profile_id: dp.id.clone(),
application_id: a.id,
device_profile_id: dp.id,
tags: build_tags(&[("common_tag", "value"), ("mytag", "dev_value")]),
..Default::default()
})

View File

@ -1,4 +1,4 @@
use std::sync::RwLock;
use std::sync::{LazyLock, RwLock};
use std::time::Instant;
use anyhow::Result;
@ -19,18 +19,17 @@ use crate::config;
pub type AsyncSqlitePool = DeadpoolPool<SyncConnectionWrapper<SqliteConnection>>;
pub type AsyncSqlitePoolConnection = DeadpoolObject<SyncConnectionWrapper<SqliteConnection>>;
lazy_static! {
static ref ASYNC_SQLITE_POOL: RwLock<Option<AsyncSqlitePool>> = RwLock::new(None);
static ref STORAGE_SQLITE_CONN_GET: Histogram = {
let histogram = Histogram::new(exponential_buckets(0.001, 2.0, 12));
prometheus::register(
"storage_sqlite_conn_get_duration_seconds",
"Time between requesting a SQLite connection and the connection-pool returning it",
histogram.clone(),
);
histogram
};
}
static ASYNC_SQLITE_POOL: LazyLock<RwLock<Option<AsyncSqlitePool>>> =
LazyLock::new(|| RwLock::new(None));
static STORAGE_SQLITE_CONN_GET: LazyLock<Histogram> = LazyLock::new(|| {
let histogram = Histogram::new(exponential_buckets(0.001, 2.0, 12));
prometheus::register(
"storage_sqlite_conn_get_duration_seconds",
"Time between requesting a SQLite connection and the connection-pool returning it",
histogram.clone(),
);
histogram
});
pub fn setup(conf: &config::Sqlite) -> Result<()> {
info!("Setting up SQLite connection pool");

View File

@ -325,7 +325,6 @@ pub mod test {
use crate::storage::user::test::create_user;
use crate::test;
use chrono::SubsecRound;
use std::str::FromStr;
use uuid::Uuid;
struct FilterTest<'a> {
@ -357,10 +356,19 @@ pub mod test {
async fn test_tenant() {
let _guard = test::prepare().await;
// delete default tenant
delete(&Uuid::from_str("52f14cd4-c6f1-4fbd-8f87-4025e1d49242").unwrap())
.await
.unwrap();
// delete existing tenants.
let tenants = list(
10,
0,
&Filters {
..Default::default()
},
)
.await
.unwrap();
for t in &tenants {
delete(&t.id).await.unwrap();
}
let mut t = create_tenant().await;
@ -379,7 +387,7 @@ pub mod test {
let tu = TenantUser {
tenant_id: t.id,
user_id: user.id.into(),
user_id: user.id,
is_admin: true,
..Default::default()
};
@ -480,7 +488,7 @@ pub mod test {
let tu = TenantUser {
tenant_id: t.id,
user_id: user.id.into(),
user_id: user.id,
is_admin: true,
..Default::default()
};

View File

@ -14,7 +14,6 @@ use crate::storage::{get_async_redis_conn, redis_key};
use chirpstack_api::{api, integration};
#[allow(clippy::enum_variant_names)]
pub async fn log_event_for_device(typ: &str, dev_eui: &str, b: &[u8]) -> Result<()> {
let conf = config::get();

View File

@ -27,7 +27,7 @@ pub async fn log_uplink_for_gateways(ufl: &stream::UplinkFrameLog) -> Result<()>
phy_payload: ufl.phy_payload.clone(),
tx_info: ufl.tx_info.clone(),
rx_info: vec![rx_info.clone()],
m_type: ufl.m_type,
f_type: ufl.f_type,
dev_addr: ufl.dev_addr.clone(),
dev_eui: ufl.dev_eui.clone(),
time: ufl.time,
@ -299,7 +299,7 @@ async fn handle_stream(
seconds: t.seconds,
nanos: t.nanos,
}),
description: pl.m_type().into(),
description: pl.f_type().into(),
body: json!({
"phy_payload": phy,
"tx_info": pl.tx_info,
@ -340,7 +340,7 @@ async fn handle_stream(
seconds: t.seconds,
nanos: t.nanos,
}),
description: pl.m_type().into(),
description: pl.f_type().into(),
body: json!({
"phy_payload": phy,
"tx_info": pl.tx_info,

View File

@ -1,6 +1,7 @@
use std::future::Future;
use std::io::Cursor;
use std::pin::Pin;
use std::sync::LazyLock;
use std::time::Duration;
use prost::Message;
@ -17,9 +18,7 @@ use crate::storage::{
use chirpstack_api::{gw, integration as integration_pb, internal, stream};
use lrwn::EUI64;
lazy_static! {
static ref LAST_DOWNLINK_ID: RwLock<u32> = RwLock::new(0);
}
static LAST_DOWNLINK_ID: LazyLock<RwLock<u32>> = LazyLock::new(|| RwLock::new(0));
pub type Validator = Box<dyn Fn() -> Pin<Box<dyn Future<Output = ()>>>>;

View File

@ -80,7 +80,7 @@ async fn test_fns_uplink() {
let data_phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -150,7 +150,7 @@ async fn test_fns_uplink() {
// Simulate uplink
uplink::handle_uplink(
CommonName::EU868,
"eu868".into(),
"eu868",
Uuid::new_v4(),
gw::UplinkFrameSet {
phy_payload: data_phy.to_vec().unwrap(),
@ -266,7 +266,7 @@ async fn test_sns_uplink() {
let mut data_phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -508,7 +508,7 @@ async fn test_sns_roaming_not_allowed() {
let mut data_phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -631,7 +631,7 @@ async fn test_sns_dev_not_found() {
let data_phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {

View File

@ -150,7 +150,7 @@ async fn test_gateway_filtering() {
rx_info: rx_info_a.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -177,7 +177,7 @@ async fn test_gateway_filtering() {
rx_info: rx_info_b.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -292,7 +292,7 @@ async fn test_lorawan_10_errors() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -325,7 +325,7 @@ async fn test_lorawan_10_errors() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -357,7 +357,7 @@ async fn test_lorawan_10_errors() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -379,7 +379,7 @@ async fn test_lorawan_10_errors() {
rx_info: vec![rx_info.clone()],
dev_eui: "0000000000000000".into(),
dev_addr: "01020304".into(),
m_type: common::MType::UnconfirmedDataUp.into(),
f_type: common::FType::UnconfirmedDataUp.into(),
..Default::default()
}),
],
@ -489,7 +489,7 @@ async fn test_lorawan_11_errors() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -516,7 +516,7 @@ async fn test_lorawan_11_errors() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -633,7 +633,7 @@ async fn test_lorawan_10_skip_f_cnt() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -683,7 +683,7 @@ async fn test_lorawan_10_skip_f_cnt() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -821,7 +821,7 @@ async fn test_lorawan_10_device_disabled() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -949,7 +949,7 @@ async fn test_lorawan_10_uplink() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -1022,7 +1022,7 @@ async fn test_lorawan_10_uplink() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -1081,7 +1081,7 @@ async fn test_lorawan_10_uplink() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -1154,7 +1154,7 @@ async fn test_lorawan_10_uplink() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -1206,7 +1206,7 @@ async fn test_lorawan_10_uplink() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::ConfirmedDataUp,
f_type: lrwn::FType::ConfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -1319,7 +1319,7 @@ async fn test_lorawan_10_uplink() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::ConfirmedDataUp,
f_type: lrwn::FType::ConfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -1457,7 +1457,7 @@ async fn test_lorawan_10_uplink() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -1597,7 +1597,7 @@ async fn test_lorawan_10_end_to_end_enc() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -1649,7 +1649,7 @@ async fn test_lorawan_10_end_to_end_enc() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -1712,7 +1712,7 @@ async fn test_lorawan_10_end_to_end_enc() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -1761,7 +1761,7 @@ async fn test_lorawan_10_end_to_end_enc() {
assert::downlink_phy_payloads(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -1781,7 +1781,7 @@ async fn test_lorawan_10_end_to_end_enc() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -1912,7 +1912,7 @@ async fn test_lorawan_11_uplink() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -1971,7 +1971,7 @@ async fn test_lorawan_11_uplink() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2145,7 +2145,7 @@ async fn test_lorawan_10_rx_delay() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::ConfirmedDataUp,
f_type: lrwn::FType::ConfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2267,7 +2267,7 @@ async fn test_lorawan_10_rx_delay() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::ConfirmedDataUp,
f_type: lrwn::FType::ConfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2389,7 +2389,7 @@ async fn test_lorawan_10_rx_delay() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::ConfirmedDataUp,
f_type: lrwn::FType::ConfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2431,7 +2431,7 @@ async fn test_lorawan_10_rx_delay() {
assert::downlink_phy_payloads(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2455,7 +2455,7 @@ async fn test_lorawan_10_rx_delay() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2602,7 +2602,7 @@ async fn test_lorawan_10_mac_commands() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2622,7 +2622,7 @@ async fn test_lorawan_10_mac_commands() {
assert::downlink_phy_payloads(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2645,7 +2645,7 @@ async fn test_lorawan_10_mac_commands() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2701,7 +2701,7 @@ async fn test_lorawan_10_mac_commands() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2721,7 +2721,7 @@ async fn test_lorawan_10_mac_commands() {
assert::downlink_phy_payloads(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2744,7 +2744,7 @@ async fn test_lorawan_10_mac_commands() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2779,7 +2779,7 @@ async fn test_lorawan_10_mac_commands() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2803,7 +2803,7 @@ async fn test_lorawan_10_mac_commands() {
assert::downlink_phy_payloads(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2823,7 +2823,7 @@ async fn test_lorawan_10_mac_commands() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2937,7 +2937,7 @@ async fn test_lorawan_11_mac_commands() {
let mut phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -2984,7 +2984,7 @@ async fn test_lorawan_11_mac_commands() {
assert::downlink_phy_payloads(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3008,7 +3008,7 @@ async fn test_lorawan_11_mac_commands() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3141,7 +3141,7 @@ async fn test_lorawan_10_device_queue() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3161,7 +3161,7 @@ async fn test_lorawan_10_device_queue() {
assert::downlink_phy_payloads(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3181,7 +3181,7 @@ async fn test_lorawan_10_device_queue() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3228,7 +3228,7 @@ async fn test_lorawan_10_device_queue() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3248,7 +3248,7 @@ async fn test_lorawan_10_device_queue() {
assert::downlink_phy_payloads(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3270,7 +3270,7 @@ async fn test_lorawan_10_device_queue() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3311,7 +3311,7 @@ async fn test_lorawan_10_device_queue() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3331,7 +3331,7 @@ async fn test_lorawan_10_device_queue() {
assert::downlink_phy_payloads(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::ConfirmedDataDown,
f_type: lrwn::FType::ConfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3351,7 +3351,7 @@ async fn test_lorawan_10_device_queue() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::ConfirmedDataDown,
f_type: lrwn::FType::ConfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3389,7 +3389,7 @@ async fn test_lorawan_10_device_queue() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3426,7 +3426,7 @@ async fn test_lorawan_10_device_queue() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3450,7 +3450,7 @@ async fn test_lorawan_10_device_queue() {
assert::downlink_phy_payloads(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3476,7 +3476,7 @@ async fn test_lorawan_10_device_queue() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3613,7 +3613,7 @@ async fn test_lorawan_11_device_queue() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3633,7 +3633,7 @@ async fn test_lorawan_11_device_queue() {
assert::downlink_phy_payloads(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3653,7 +3653,7 @@ async fn test_lorawan_11_device_queue() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3700,7 +3700,7 @@ async fn test_lorawan_11_device_queue() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3720,7 +3720,7 @@ async fn test_lorawan_11_device_queue() {
assert::downlink_phy_payloads(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3742,7 +3742,7 @@ async fn test_lorawan_11_device_queue() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3783,7 +3783,7 @@ async fn test_lorawan_11_device_queue() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3803,7 +3803,7 @@ async fn test_lorawan_11_device_queue() {
assert::downlink_phy_payloads(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::ConfirmedDataDown,
f_type: lrwn::FType::ConfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3823,7 +3823,7 @@ async fn test_lorawan_11_device_queue() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::ConfirmedDataDown,
f_type: lrwn::FType::ConfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3861,7 +3861,7 @@ async fn test_lorawan_11_device_queue() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3898,7 +3898,7 @@ async fn test_lorawan_11_device_queue() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3924,7 +3924,7 @@ async fn test_lorawan_11_device_queue() {
assert::downlink_phy_payloads(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -3950,7 +3950,7 @@ async fn test_lorawan_11_device_queue() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4099,7 +4099,7 @@ async fn test_lorawan_10_adr() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4123,7 +4123,7 @@ async fn test_lorawan_10_adr() {
assert::downlink_phy_payloads_decoded_f_opts(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4157,7 +4157,7 @@ async fn test_lorawan_10_adr() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4203,7 +4203,7 @@ async fn test_lorawan_10_adr() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4230,38 +4230,35 @@ async fn test_lorawan_10_adr() {
name: "acknowledgement of pending adr request".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![],
before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui;
Box::pin(async move {
mac_command::set_pending(
&dev_eui,
lrwn::CID::LinkADRReq,
&lrwn::MACCommandSet::new(vec![lrwn::MACCommand::LinkADRReq(
lrwn::LinkADRReqPayload {
dr: 0,
tx_power: 3,
ch_mask: lrwn::ChMask::new([
true, true, true, false, false, false, false, false, false,
false, false, false, false, false, false, false,
]),
redundancy: lrwn::Redundancy {
ch_mask_cntl: 0,
nb_rep: 1,
},
},
)]),
)
.await
.unwrap();
})
})),
before_func: None,
after_func: None,
device_session: Some(ds.clone()),
device_session: Some({
let mut ds = ds.clone();
mac_command::set_pending(
&mut ds,
&lrwn::MACCommandSet::new(vec![lrwn::MACCommand::LinkADRReq(
lrwn::LinkADRReqPayload {
dr: 0,
tx_power: 3,
ch_mask: lrwn::ChMask::new([
true, true, true, false, false, false, false, false, false, false,
false, false, false, false, false, false,
]),
redundancy: lrwn::Redundancy {
ch_mask_cntl: 0,
nb_rep: 1,
},
},
)]),
)
.unwrap();
ds
}),
tx_info: tx_info.clone(),
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4298,38 +4295,35 @@ async fn test_lorawan_10_adr() {
name: "negative acknowledgement of pending adr request".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![],
before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui;
Box::pin(async move {
mac_command::set_pending(
&dev_eui,
lrwn::CID::LinkADRReq,
&lrwn::MACCommandSet::new(vec![lrwn::MACCommand::LinkADRReq(
lrwn::LinkADRReqPayload {
dr: 0,
tx_power: 3,
ch_mask: lrwn::ChMask::new([
true, true, true, false, false, false, false, false, false,
false, false, false, false, false, false, false,
]),
redundancy: lrwn::Redundancy {
ch_mask_cntl: 0,
nb_rep: 1,
},
},
)]),
)
.await
.unwrap();
})
})),
before_func: None,
after_func: None,
device_session: Some(ds.clone()),
device_session: Some({
let mut ds = ds.clone();
mac_command::set_pending(
&mut ds,
&lrwn::MACCommandSet::new(vec![lrwn::MACCommand::LinkADRReq(
lrwn::LinkADRReqPayload {
dr: 0,
tx_power: 3,
ch_mask: lrwn::ChMask::new([
true, true, true, false, false, false, false, false, false, false,
false, false, false, false, false, false,
]),
redundancy: lrwn::Redundancy {
ch_mask_cntl: 0,
nb_rep: 1,
},
},
)]),
)
.unwrap();
ds
}),
tx_info: tx_info.clone(),
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4373,7 +4367,7 @@ async fn test_lorawan_10_adr() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4398,7 +4392,7 @@ async fn test_lorawan_10_adr() {
assert::downlink_phy_payloads(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4418,7 +4412,7 @@ async fn test_lorawan_10_adr() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4450,7 +4444,7 @@ async fn test_lorawan_10_adr() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4470,7 +4464,7 @@ async fn test_lorawan_10_adr() {
assert::downlink_phy_payloads_decoded_f_opts(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4502,7 +4496,7 @@ async fn test_lorawan_10_adr() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4540,38 +4534,35 @@ async fn test_lorawan_10_adr() {
name: "new channel re-configuration ack-ed".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![],
before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui;
Box::pin(async move {
mac_command::set_pending(
&dev_eui,
lrwn::CID::LinkADRReq,
&lrwn::MACCommandSet::new(vec![lrwn::MACCommand::LinkADRReq(
lrwn::LinkADRReqPayload {
dr: 0,
tx_power: 1,
ch_mask: lrwn::ChMask::new([
true, true, true, false, false, false, false, false, false,
false, false, false, false, false, false, false,
]),
redundancy: lrwn::Redundancy {
ch_mask_cntl: 0,
nb_rep: 0,
},
},
)]),
)
.await
.unwrap();
})
})),
before_func: None,
after_func: None,
device_session: Some(ds_7chan.clone()),
device_session: Some({
let mut ds = ds_7chan.clone();
mac_command::set_pending(
&mut ds,
&lrwn::MACCommandSet::new(vec![lrwn::MACCommand::LinkADRReq(
lrwn::LinkADRReqPayload {
dr: 0,
tx_power: 1,
ch_mask: lrwn::ChMask::new([
true, true, true, false, false, false, false, false, false, false,
false, false, false, false, false, false,
]),
redundancy: lrwn::Redundancy {
ch_mask_cntl: 0,
nb_rep: 0,
},
},
)]),
)
.unwrap();
ds
}),
tx_info: tx_info.clone(),
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4606,38 +4597,35 @@ async fn test_lorawan_10_adr() {
name: "new channel re-configuration not ack-ed".into(),
dev_eui: dev.dev_eui,
device_queue_items: vec![],
before_func: Some(Box::new(move || {
let dev_eui = dev.dev_eui;
Box::pin(async move {
mac_command::set_pending(
&dev_eui,
lrwn::CID::LinkADRReq,
&lrwn::MACCommandSet::new(vec![lrwn::MACCommand::LinkADRReq(
lrwn::LinkADRReqPayload {
dr: 0,
tx_power: 1,
ch_mask: lrwn::ChMask::new([
true, true, true, false, false, false, false, false, false,
false, false, false, false, false, false, false,
]),
redundancy: lrwn::Redundancy {
ch_mask_cntl: 0,
nb_rep: 0,
},
},
)]),
)
.await
.unwrap();
})
})),
before_func: None,
after_func: None,
device_session: Some(ds_7chan.clone()),
device_session: Some({
let mut ds = ds_7chan.clone();
mac_command::set_pending(
&mut ds,
&lrwn::MACCommandSet::new(vec![lrwn::MACCommand::LinkADRReq(
lrwn::LinkADRReqPayload {
dr: 0,
tx_power: 1,
ch_mask: lrwn::ChMask::new([
true, true, true, false, false, false, false, false, false, false,
false, false, false, false, false, false,
]),
redundancy: lrwn::Redundancy {
ch_mask_cntl: 0,
nb_rep: 0,
},
},
)]),
)
.unwrap();
ds
}),
tx_info: tx_info.clone(),
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4678,7 +4666,7 @@ async fn test_lorawan_10_adr() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4703,7 +4691,7 @@ async fn test_lorawan_10_adr() {
assert::downlink_phy_payloads_decoded_f_opts(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4735,7 +4723,7 @@ async fn test_lorawan_10_adr() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4780,7 +4768,7 @@ async fn test_lorawan_10_adr() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4923,7 +4911,7 @@ async fn test_lorawan_10_device_status_request() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4942,7 +4930,7 @@ async fn test_lorawan_10_device_status_request() {
assert::downlink_phy_payloads_decoded_f_opts(vec![
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -4965,7 +4953,7 @@ async fn test_lorawan_10_device_status_request() {
},
lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataDown,
f_type: lrwn::FType::UnconfirmedDataDown,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -5000,7 +4988,7 @@ async fn test_lorawan_10_device_status_request() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -5031,7 +5019,7 @@ async fn test_lorawan_10_device_status_request() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -5193,7 +5181,7 @@ async fn test_lorawan_11_receive_window_selection() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -5263,7 +5251,7 @@ async fn test_lorawan_11_receive_window_selection() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -5333,7 +5321,7 @@ async fn test_lorawan_11_receive_window_selection() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -5432,7 +5420,7 @@ async fn test_lorawan_11_receive_window_selection() {
rx_info: rx_info.clone(),
phy_payload: lrwn::PhyPayload {
mhdr: lrwn::MHDR {
m_type: lrwn::MType::UnconfirmedDataUp,
f_type: lrwn::FType::UnconfirmedDataUp,
major: lrwn::Major::LoRaWANR1,
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
@ -5558,7 +5546,7 @@ async fn run_test(t: &Test) {
uplink::handle_uplink(
CommonName::EU868,
"eu868".into(),
"eu868",
Uuid::new_v4(),
gw::UplinkFrameSet {
phy_payload: t.phy_payload.to_vec().unwrap(),

Some files were not shown because too many files have changed in this diff Show More