Compare commits
230
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
830df80291 | ||
|
|
13325056f6 | ||
|
|
d22ee524ff | ||
|
|
03fa49341b | ||
|
|
93fcd44f13 | ||
|
|
7ae61a81e6 | ||
|
|
9ff6600920 | ||
|
|
32834920d1 | ||
|
|
b4869e0db4 | ||
|
|
db906565c8 | ||
|
|
ba9ea3a12c | ||
|
|
782f6c3936 | ||
|
|
3fa655da59 | ||
|
|
1aee1b8513 | ||
|
|
d791ca2a5f | ||
|
|
7a2a317d58 | ||
|
|
d9ead9516e | ||
|
|
7b74bee581 | ||
|
|
1c6e777d24 | ||
|
|
919f1aa65d | ||
|
|
883998e31d | ||
|
|
8d36fd3761 | ||
|
|
2a7b3796ec | ||
|
|
1c98f3772f | ||
|
|
76074d69e4 | ||
|
|
86d8528d21 | ||
|
|
7d6e4ca2f8 | ||
|
|
eeb6fe17cc | ||
|
|
9de9ce3131 | ||
|
|
87fc65fdd4 | ||
|
|
877312d3c3 | ||
|
|
1649306802 | ||
|
|
12824b2906 | ||
|
|
cbce7916c2 | ||
|
|
54971683bf | ||
|
|
4ba4d3e6a3 | ||
|
|
2d9b14e69e | ||
|
|
d2b8bc6afb | ||
|
|
2cf39a0e1c | ||
|
|
1e44b2d59f | ||
|
|
c40b8f32c9 | ||
|
|
f6a87cff28 | ||
|
|
8195dac587 | ||
|
|
5fffcc011f | ||
|
|
3e4c3c4e64 | ||
|
|
3f0937de83 | ||
|
|
d2db28468f | ||
|
|
3550026c00 | ||
|
|
ad4908feef | ||
|
|
20bc6c4fb6 | ||
|
|
e97e6f2a54 | ||
|
|
1c9ebe8a75 | ||
|
|
7a464843ed | ||
|
|
d58b1db55b | ||
|
|
b1253eaad4 | ||
|
|
ae4d26b8bd | ||
|
|
cfcfabb5e3 | ||
|
|
70f747ad86 | ||
|
|
f44aac6ea2 | ||
|
|
df517af85b | ||
|
|
ae9edf5888 | ||
|
|
512384026c | ||
|
|
42c7a3b9ee | ||
|
|
1e15e3d501 | ||
|
|
d7e6732888 | ||
|
|
c27569a526 | ||
|
|
b2bc87641c | ||
|
|
c8245772bb | ||
|
|
56d9cafa59 | ||
|
|
7de057aaf2
|
||
|
|
2f4a11a0bc | ||
|
|
0cd929a19c | ||
|
|
d54167837e | ||
|
|
ecce07a471 | ||
|
|
526254851a | ||
|
|
440e757141
|
||
|
|
02aa825783 | ||
|
|
bc9e0e4a94 | ||
|
|
06e713a557 | ||
|
|
778512d50e | ||
|
|
5d40638964 | ||
|
|
1b07b845f2 | ||
|
|
2e58a311c8 | ||
|
|
62d64e692a
|
||
|
|
3784f47b66 | ||
|
|
e1911f1b6e | ||
|
|
2e53ce1871 | ||
|
|
a6c460129b
|
||
|
|
d5ecefd683 | ||
|
|
2f9f3b8183 | ||
|
|
b28cff85de | ||
|
|
da3de9f22c | ||
|
|
aefdf0987d | ||
|
|
7ae9e62d66 | ||
|
|
fea1a9028b | ||
|
|
abc145fb2d
|
||
|
|
490635dfcf | ||
|
|
de3d22a022 | ||
|
|
cbe211fe8b | ||
|
|
e379bc3fd7 | ||
|
|
a61ee85796 | ||
|
|
81473b30f9
|
||
|
|
22675a73f9 | ||
|
|
c68e3d4f75
|
||
|
|
3deedfba17 | ||
|
|
533caea0fe
|
||
|
|
848fe6f207 | ||
|
|
cf64fea7d9 | ||
|
|
4948db3fa5 | ||
|
|
1920e4878c
|
||
|
|
f46bc94b04 | ||
|
|
fb45da1890
|
||
|
|
f600ee499a | ||
|
|
3f28f60c59 | ||
|
|
44b1f2b037 | ||
|
|
4b22958b34 | ||
|
|
a711c6acd9 | ||
|
|
99a954a1f5
|
||
|
|
4a4fd7ac2c
|
||
|
|
9bf08849a2
|
||
|
|
b8f7fefe26 | ||
|
|
a501832698
|
||
|
|
c7284d3f1c | ||
|
|
18263d4568 | ||
|
|
95519c1363
|
||
|
|
2ec32717d0 | ||
|
|
bfdd777685
|
||
|
|
b54c2b7863 | ||
|
|
19f3355283 | ||
|
|
4aeb28d2f1
|
||
|
|
ddc4544456 | ||
|
|
9ab36c0362 | ||
|
|
b95769c177 | ||
|
|
bb20533ae1 | ||
|
|
27cacd0f43
|
||
|
|
bd6488e87b | ||
|
|
52ec0d44aa | ||
|
|
4fa9f8d685 | ||
|
|
767cf6b1a5 | ||
|
|
5bf5518591
|
||
|
|
f3e0609910 | ||
|
|
05106354e3 | ||
|
|
719b70d834 | ||
|
|
d4082fa098 | ||
|
|
c9c9e4f735 | ||
|
|
2c92a95184
|
||
|
|
1a1d330814 | ||
|
|
ef7b5d66fe
|
||
|
|
b3497e0592 | ||
|
|
73286e36c2
|
||
|
|
ed266a11f6 | ||
|
|
af972e174f
|
||
|
|
3d12083c16
|
||
|
|
e8d2c020fa | ||
|
|
69e172b633 | ||
|
|
e1dda751bc
|
||
|
|
b01628d8ef | ||
|
|
31844e4fe2 | ||
|
|
738872f421 | ||
|
|
309e39999f
|
||
|
|
1c43c3adf9 | ||
|
|
d9e0abffa7 | ||
|
|
abec9dd448
|
||
|
|
c18fbb59ad | ||
|
|
c91ddcd658
|
||
|
|
c5fa1955d7 | ||
|
|
c9708810e6
|
||
|
|
79d0c2e222 | ||
|
|
8e87875c0e | ||
|
|
1ac6c02c06
|
||
|
|
6e7907522e | ||
|
|
f747a5efdc
|
||
|
|
6ffd55cec2 | ||
|
|
5e51b3de42
|
||
|
|
bd059a2541 | ||
|
|
1a4d764f25 | ||
|
|
b38c617fae | ||
|
|
edcd5491f1 | ||
|
|
b4cb034b73 | ||
|
|
47c86aea5c | ||
|
|
c8bba48e76 | ||
|
|
176da4838a
|
||
|
|
8114195bc6 | ||
|
|
1726e34fa7 | ||
|
|
1f2d6c9474 | ||
|
|
9960930339
|
||
|
|
cb270964a1 | ||
|
|
a45e634214
|
||
|
|
9e4132706c | ||
|
|
36d889a504
|
||
|
|
97a6510af7 | ||
|
|
2e5d6a5c41
|
||
|
|
29167736db
|
||
|
|
a4c433a7be | ||
|
|
472a8ce0f9 | ||
|
|
e753319dac | ||
|
|
99dddf36f3 | ||
|
|
a819feeaa2 | ||
|
|
46ce3fc772 | ||
|
|
8d27bdf3bf | ||
|
|
3d2a46f044 | ||
|
|
1f192af262
|
||
|
|
3f78c200ad
|
||
|
|
d73dfcdd67
|
||
|
|
5cae0f7036 | ||
|
|
832250d211
|
||
|
|
3c3b4349e8
|
||
|
|
acf73e93b1
|
||
|
|
0b2d4f6187 | ||
|
|
f7016b940a
|
||
|
|
397ecd0c40
|
||
|
|
422f2c11ab | ||
|
|
37e945fd91 | ||
|
|
45379858f0 | ||
|
|
7c194ab543 | ||
|
|
bca1d7292a
|
||
|
|
cdcb9cae1c | ||
|
|
9dcbd42862
|
||
|
|
da05efc16d
|
||
|
|
e38e25a998 | ||
|
|
14b381cf4a | ||
|
|
3746e9ebb0 | ||
|
|
d2fc783562 | ||
|
|
5e43259d4f | ||
|
|
975cd927f4 | ||
|
|
9039c1b59a | ||
|
|
972bf19188
|
||
|
|
9d711d2b73
|
||
|
|
d0005cdd63
|
||
|
|
f00e6cf50c
|
No files matched your search
@@ -11,7 +11,12 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: cargo check --release
|
||||
- name: Install libudev-dev on Ubuntu
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: sudo apt update && sudo apt install -y libudev-dev
|
||||
- run: cargo check
|
||||
# Check example with static pool configuration
|
||||
- run: cargo check -p satrs-example --no-default-features
|
||||
|
||||
test:
|
||||
name: Run Tests
|
||||
@@ -21,8 +26,9 @@ jobs:
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- name: Install nextest
|
||||
uses: taiki-e/install-action@nextest
|
||||
- run: sudo apt update && sudo apt install -y libudev-dev
|
||||
- run: cargo nextest run --all-features
|
||||
- run: cargo test --doc
|
||||
- run: cargo test --doc --all-features
|
||||
|
||||
cross-check:
|
||||
name: Check Cross-Compilation
|
||||
@@ -37,7 +43,7 @@ jobs:
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: "armv7-unknown-linux-gnueabihf, thumbv7em-none-eabihf"
|
||||
- run: cargo check -p satrs --release --target=${{matrix.target}} --no-default-features
|
||||
- run: cargo check -p satrs --target=${{matrix.target}} --no-default-features
|
||||
|
||||
fmt:
|
||||
name: Check formatting
|
||||
@@ -45,6 +51,8 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: rustfmt
|
||||
- run: cargo fmt --all -- --check
|
||||
|
||||
docs:
|
||||
@@ -53,7 +61,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- run: cargo +nightly doc --all-features --config 'build.rustdocflags=["--cfg", "docs_rs"]'
|
||||
- run: RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc -p satrs --all-features --no-deps
|
||||
|
||||
clippy:
|
||||
name: Clippy
|
||||
@@ -61,4 +69,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: clippy
|
||||
- run: sudo apt update && sudo apt install -y libudev-dev
|
||||
- run: cargo clippy -- -D warnings
|
||||
@@ -2,6 +2,7 @@ target/
|
||||
|
||||
output.log
|
||||
/Cargo.lock
|
||||
output.log
|
||||
|
||||
output.log
|
||||
|
||||
|
||||
Generated
-19
@@ -1,19 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Check" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="check" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="false" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="buildTarget" value="REMOTE" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
Generated
-19
@@ -1,19 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Clippy" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="clippy" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
<option name="allFeatures" value="true" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="buildTarget" value="REMOTE" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
Generated
-18
@@ -1,18 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Clippy Fix" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="clippy --fix" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
Generated
-19
@@ -1,19 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Docs" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="doc --all-features" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="buildTarget" value="REMOTE" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
Generated
-19
@@ -1,19 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Doctest" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="test --doc" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="buildTarget" value="REMOTE" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
Generated
-18
@@ -1,18 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Examples" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="run --example test" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
Generated
-19
@@ -1,19 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Format" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="fmt" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="buildTarget" value="REMOTE" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
Generated
-18
@@ -1,18 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="run" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run obsw example" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="run -p satrs-example --bin satrs-example" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="buildTarget" value="REMOTE" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run obsw simple client" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="run --package fsrc-example --bin client" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="buildTarget" value="REMOTE" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
Generated
-19
@@ -1,19 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Test" type="CargoCommandRunConfiguration" factoryName="Cargo Command" nameIsGenerated="true">
|
||||
<option name="command" value="test" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
<option name="allFeatures" value="true" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="buildTarget" value="REMOTE" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
Generated
-18
@@ -1,18 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Test All" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="test -- --include-ignored" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Test satrs-core" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
|
||||
<option name="command" value="test -p satrs-core --all-features" />
|
||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||
<option name="channel" value="DEFAULT" />
|
||||
<option name="requiredFeatures" value="true" />
|
||||
<option name="allFeatures" value="true" />
|
||||
<option name="emulateTerminal" value="false" />
|
||||
<option name="withSudo" value="false" />
|
||||
<option name="buildTarget" value="REMOTE" />
|
||||
<option name="backtrace" value="SHORT" />
|
||||
<envs />
|
||||
<option name="isRedirectInput" value="false" />
|
||||
<option name="redirectInputPath" value="" />
|
||||
<method v="2">
|
||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
+8
-3
@@ -4,11 +4,16 @@ members = [
|
||||
"satrs",
|
||||
"satrs-mib",
|
||||
"satrs-example",
|
||||
"satrs-minisim",
|
||||
"satrs-example/types",
|
||||
"satrs-example/client",
|
||||
"satrs-example/minisim",
|
||||
"satrs-shared",
|
||||
"tmtc-utils",
|
||||
"embedded-examples/embedded-client",
|
||||
"embedded-examples/types",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
"satrs-example-stm32f3-disco",
|
||||
"embedded-examples/stm32f3-disco-rtic",
|
||||
"embedded-examples/stm32h7-nucleo-rtic",
|
||||
]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<p align="center"> <img src="misc/satrs-logo-v2.png" width="40%"> </p>
|
||||
|
||||
[](https://absatsw.irs.uni-stuttgart.de/projects/sat-rs/)
|
||||
[](https://absatsw.irs.uni-stuttgart.de/projects/sat-rs/book/)
|
||||
[](https://documentation.irs.uni-stuttgart.de/projects/sat-rs/book/)
|
||||
[](https://crates.io/crates/satrs)
|
||||
[](https://docs.rs/satrs)
|
||||
[](https://matrix.to/#/#sat-rs:matrix.org)
|
||||
|
||||
sat-rs
|
||||
=========
|
||||
@@ -11,8 +11,8 @@ sat-rs
|
||||
This is the repository of the sat-rs library. Its primary goal is to provide re-usable components
|
||||
to write on-board software for remote systems like rovers or satellites. It is specifically written
|
||||
for the special requirements for these systems. You can find an overview of the project and the
|
||||
link to the [more high-level sat-rs book](https://absatsw.irs.uni-stuttgart.de/projects/sat-rs/)
|
||||
at the [IRS software projects website](https://absatsw.irs.uni-stuttgart.de/projects/sat-rs/).
|
||||
link to the [more high-level sat-rs book](https://documentation.irs.uni-stuttgart.de/projects/sat-rs/book/)
|
||||
at the [IRS software projects website](https://documentation.irs.uni-stuttgart.de/projects/sat-rs/).
|
||||
|
||||
This is early-stage software. Important features are missing. New releases
|
||||
with breaking changes are released regularly, with all changes documented inside respective
|
||||
@@ -30,29 +30,54 @@ This project currently contains following crates:
|
||||
|
||||
* [`satrs-book`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-book):
|
||||
Primary information resource in addition to the API documentation, hosted
|
||||
[here](https://documentation.irs.uni-stuttgart.de/projects/sat-rs/). It can be useful to read
|
||||
[here](https://documentation.irs.uni-stuttgart.de/projects/sat-rs/book/). It can be useful to read
|
||||
this first before delving into the example application and the API documentation.
|
||||
* [`satrs`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs):
|
||||
Primary crate.
|
||||
* [`satrs-example`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example):
|
||||
Example of a simple example on-board software using various sat-rs components which can be run
|
||||
on a host computer or on any system with a standard runtime like a Raspberry Pi.
|
||||
* [`satrs-minisim`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-minisim):
|
||||
Mini-Simulator based on [nexosim](https://github.com/asynchronics/nexosim) which
|
||||
simulates some physical devices for the `satrs-example` application device handlers.
|
||||
* [`satrs-mib`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-mib):
|
||||
Components to build a mission information base from the on-board software directly.
|
||||
* [`satrs-example-stm32f3-disco`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example-stm32f3-disco):
|
||||
* [`satrs-stm32f3-disco-rtic`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/embedded-examples/stm32f3-disco-rtic):
|
||||
Example of a simple example using low-level sat-rs components on a bare-metal system
|
||||
with constrained resources.
|
||||
with constrained resources. This example uses the [RTIC](https://github.com/rtic-rs/rtic)
|
||||
framework on the STM32F3-Discovery device.
|
||||
* [`satrs-stm32h-nucleo-rtic`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/embedded-examples/stm32h7-nucleo-rtic):
|
||||
Example of a simple example using sat-rs components on a bare-metal system
|
||||
with constrained resources. This example uses the [RTIC](https://github.com/rtic-rs/rtic)
|
||||
framework on the STM32H743ZIT device.
|
||||
|
||||
Each project has its own `CHANGELOG.md`.
|
||||
|
||||
# Related projects
|
||||
|
||||
|
||||
In addition to the crates in this repository, the sat-rs project also maintains other libraries.
|
||||
|
||||
* [`spacepackets`](https://egit.irs.uni-stuttgart.de/rust/spacepackets): Basic ECSS and CCSDS
|
||||
packet protocol implementations. This repository is re-exported in the
|
||||
[`satrs`](https://egit.irs.uni-stuttgart.de/rust/satrs/src/branch/main/satrs)
|
||||
crate.
|
||||
* [`cfdp`](https://egit.irs.uni-stuttgart.de/rust/cfdp): CCSDS File Delivery Protocol
|
||||
(CFDP) high-level library components.
|
||||
|
||||
# Flight Heritage
|
||||
|
||||
There is an active and continuous effort to get early flight heritage for the sat-rs library.
|
||||
Currently this library has the following flight heritage:
|
||||
|
||||
- Submission as an [OPS-SAT experiment](https://www.esa.int/Enabling_Support/Operations/OPS-SAT)
|
||||
which has also
|
||||
[flown on the satellite](https://blogs.esa.int/rocketscience/2024/05/21/ops-sat-reentry-tomorrow-final-experiments-continue/).
|
||||
The application is strongly based on the sat-rs example application. You can find the repository
|
||||
of the experiment [here](https://egit.irs.uni-stuttgart.de/rust/ops-sat-rs).
|
||||
- Development and use of a sat-rs-based [demonstration on-board software](https://egit.irs.uni-stuttgart.de/rust/eurosim-obsw)
|
||||
alongside a Flight System Simulator in the context of a
|
||||
[Bachelors Thesis](https://www.researchgate.net/publication/380785984_Design_and_Development_of_a_Hardware-in-the-Loop_EuroSim_Demonstrator)
|
||||
at [Airbus Netherlands](https://www.airbusdefenceandspacenetherlands.nl/).
|
||||
|
||||
# Coverage
|
||||
|
||||
@@ -64,5 +89,5 @@ rustup component add llvm-tools-preview
|
||||
cargo install grcov --locked
|
||||
```
|
||||
|
||||
After that, you can simply run `coverage.py` to test the `satrs-core` crate with coverage. You can
|
||||
After that, you can simply run `coverage.py` to test the `satrs` crate with coverage. You can
|
||||
optionally supply the `--open` flag to open the coverage report in your webbrowser.
|
||||
Vendored
+1
-1
@@ -33,7 +33,7 @@ pipeline {
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh 'cargo nextest r --all-features'
|
||||
sh 'cargo test --doc'
|
||||
sh 'cargo test --doc --all-features'
|
||||
}
|
||||
}
|
||||
stage('Check with all features') {
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
export RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options"
|
||||
cargo +nightly doc --all-features --open
|
||||
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "embedded-client"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
serialport = "4"
|
||||
toml = "0.9"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
spacepackets = { version = "0.18" }
|
||||
embedded-types = { path = "../types" }
|
||||
tmtc-utils = { path = "../../tmtc-utils" }
|
||||
postcard = { version = "1", features = ["alloc"] }
|
||||
anyhow = "1"
|
||||
cobs = "0.5"
|
||||
fern = "0.7"
|
||||
humantime = "2"
|
||||
log = "0.4"
|
||||
@@ -0,0 +1,3 @@
|
||||
[interface]
|
||||
serial_port = "/dev/ttyUSB0"
|
||||
# udp_addr = "192.168.XXX.XX:7301"
|
||||
@@ -0,0 +1,71 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::bail;
|
||||
use clap::Parser;
|
||||
use cobs::CobsDecoderOwned;
|
||||
use embedded_client::setup_logger;
|
||||
use embedded_types::stm32f3;
|
||||
use spacepackets::{CcsdsPacketCreatorOwned, CcsdsPacketReader, SpHeader};
|
||||
use tmtc_utils::transport::serial::PacketTransportSerialCobs;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
struct Cli {
|
||||
#[arg(short, long)]
|
||||
ping: bool,
|
||||
|
||||
/// Set frequency in milliseconds.
|
||||
#[arg(short, long)]
|
||||
set_led_frequency: Option<u32>,
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
setup_logger().expect("failed to initialize logger");
|
||||
println!("-- STM32F3 TMTC client --");
|
||||
let cli = Cli::parse();
|
||||
let config = embedded_client::Config::new_from_file();
|
||||
|
||||
if config.interface.serial_port.is_none() {
|
||||
bail!("Serial port not specified in configuration file.");
|
||||
}
|
||||
let serial_port = config.interface.serial_port.as_ref().unwrap();
|
||||
let serial = serialport::new(serial_port, 115200)
|
||||
.open()
|
||||
.expect("opening serial port failed");
|
||||
let mut transport = PacketTransportSerialCobs::new(serial, CobsDecoderOwned::new(1024));
|
||||
|
||||
if cli.ping {
|
||||
let tc = create_stm32f3_tc(&embedded_types::stm32f3::Request::Ping);
|
||||
log::info!(
|
||||
"Sending ping request with TC ID: {:#010x}",
|
||||
tc.ccsds_packet_id_and_psc().raw()
|
||||
);
|
||||
transport.send(&tc.to_vec()).unwrap();
|
||||
}
|
||||
|
||||
if let Some(freq_ms) = cli.set_led_frequency {
|
||||
let request = stm32f3::Request::ChangeBlinkFrequency(Duration::from_millis(freq_ms as u64));
|
||||
let tc = create_stm32f3_tc(&request);
|
||||
log::info!(
|
||||
"Sending change blink frequency request {:?} with TC ID: {:#010x}",
|
||||
request,
|
||||
tc.ccsds_packet_id_and_psc().raw()
|
||||
);
|
||||
transport.send(&tc.to_vec()).unwrap();
|
||||
}
|
||||
|
||||
log::info!("Waiting for response...");
|
||||
loop {
|
||||
transport
|
||||
.receive(|packet: &[u8]| {
|
||||
let reader = CcsdsPacketReader::new_with_checksum(packet);
|
||||
log::info!("Received packet: {:?}", reader);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn create_stm32f3_tc(request: &stm32f3::Request) -> CcsdsPacketCreatorOwned {
|
||||
let req_raw = postcard::to_allocvec(&request).unwrap();
|
||||
let sp_header = SpHeader::new_from_apid(embedded_types::stm32f3::PUS_APID);
|
||||
CcsdsPacketCreatorOwned::new_tc_with_checksum(sp_header, &req_raw).unwrap()
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
use std::{net::UdpSocket, time::Duration};
|
||||
|
||||
use anyhow::{Context as _, bail};
|
||||
use clap::Parser;
|
||||
use embedded_client::setup_logger;
|
||||
use embedded_types::{TmHeader, stm32h7};
|
||||
use spacepackets::{CcsdsPacketCreatorOwned, CcsdsPacketReader, SpHeader};
|
||||
use tmtc_utils::transport::udp::PacketTransportUdp;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
struct Cli {
|
||||
#[arg(short, long)]
|
||||
ping: bool,
|
||||
|
||||
/// Set frequency in milliseconds.
|
||||
#[arg(short, long)]
|
||||
set_led_frequency: Option<u32>,
|
||||
|
||||
/// UDP address to bind to.
|
||||
#[arg(short, long)]
|
||||
udp_addr: Option<std::net::SocketAddr>,
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
setup_logger().expect("failed to initialize logger");
|
||||
println!("-- STM32H7 TMTC client --");
|
||||
let cli = Cli::parse();
|
||||
let config = embedded_client::Config::new_from_file();
|
||||
let mut udp_addr = cli.udp_addr;
|
||||
if udp_addr.is_none() {
|
||||
udp_addr = config.interface.udp_addr;
|
||||
}
|
||||
if udp_addr.is_none() {
|
||||
bail!("UDP address not specified in config.toml or via command line");
|
||||
}
|
||||
let udp_addr = udp_addr.unwrap();
|
||||
log::info!("binding to UDP address: {}", udp_addr);
|
||||
let local_socket = UdpSocket::bind("0.0.0.0:0").expect("failed to bind UDP socket");
|
||||
let mut transport = PacketTransportUdp::new(local_socket, udp_addr)
|
||||
.with_context(|| "crateing UDP transport failed")?;
|
||||
|
||||
if cli.ping {
|
||||
let tc = create_stm32h7_tc(&embedded_types::stm32h7::Request::Ping);
|
||||
log::info!(
|
||||
"Sending ping request with TC ID: {:#010x}",
|
||||
tc.ccsds_packet_id_and_psc().raw()
|
||||
);
|
||||
transport.send(&tc.to_vec()).unwrap();
|
||||
}
|
||||
|
||||
if let Some(freq_ms) = cli.set_led_frequency {
|
||||
let request = stm32h7::Request::ChangeBlinkFrequency(Duration::from_millis(freq_ms as u64));
|
||||
let tc = create_stm32h7_tc(&request);
|
||||
log::info!(
|
||||
"Sending change blink frequency request {:?} with TC ID: {:#010x}",
|
||||
request,
|
||||
tc.ccsds_packet_id_and_psc().raw()
|
||||
);
|
||||
transport.send(&tc.to_vec()).unwrap();
|
||||
}
|
||||
|
||||
log::info!("Waiting for response...");
|
||||
loop {
|
||||
transport
|
||||
.receive(|packet: &[u8]| {
|
||||
let reader = CcsdsPacketReader::new_with_checksum(packet);
|
||||
log::debug!("Received packet: {:?}", reader);
|
||||
if let Ok(reader) = reader {
|
||||
let packet_data = reader.packet_data();
|
||||
let tm_header = postcard::take_from_bytes::<TmHeader>(packet_data);
|
||||
if let Ok((tm_header, remainder)) = tm_header {
|
||||
let response = postcard::from_bytes::<stm32h7::Response>(remainder);
|
||||
if let Ok(response) = response {
|
||||
log::info!(
|
||||
"Received TM with header: {:?} and response: {:?}",
|
||||
tm_header,
|
||||
response
|
||||
);
|
||||
} else {
|
||||
log::error!("Failed to deserialize response: {:?}", response.err());
|
||||
}
|
||||
} else {
|
||||
log::error!("Failed to deserialize TM header: {:?}", tm_header.err());
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn create_stm32h7_tc(request: &stm32h7::Request) -> CcsdsPacketCreatorOwned {
|
||||
let req_raw = postcard::to_allocvec(&request).unwrap();
|
||||
let sp_header = SpHeader::new_from_apid(embedded_types::stm32h7::PUS_APID);
|
||||
CcsdsPacketCreatorOwned::new_tc_with_checksum(sp_header, &req_raw).unwrap()
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
use std::{fs::File, io::Read as _, net::SocketAddr, path::Path, time::SystemTime};
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct Config {
|
||||
pub interface: Interface,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct Interface {
|
||||
pub serial_port: Option<String>,
|
||||
pub udp_addr: Option<SocketAddr>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new_from_file() -> Self {
|
||||
let mut config_file =
|
||||
File::open(Path::new("config.toml")).expect("opening config.toml file failed");
|
||||
let mut toml_str = String::new();
|
||||
config_file
|
||||
.read_to_string(&mut toml_str)
|
||||
.expect("reading config.toml file failed");
|
||||
let config: Config = toml::from_str(&toml_str).expect("parsing config.toml file failed");
|
||||
config
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_logger() -> Result<(), fern::InitError> {
|
||||
fern::Dispatch::new()
|
||||
.format(|out, message, record| {
|
||||
out.finish(format_args!(
|
||||
"[{} {} {}] {}",
|
||||
humantime::format_rfc3339_seconds(SystemTime::now()),
|
||||
record.level(),
|
||||
record.target(),
|
||||
message
|
||||
))
|
||||
})
|
||||
.level(log::LevelFilter::Info)
|
||||
.chain(std::io::stdout())
|
||||
.chain(fern::log_file("output.log")?)
|
||||
.apply()?;
|
||||
Ok(())
|
||||
}
|
||||
+1
-1
@@ -34,4 +34,4 @@ rustflags = [
|
||||
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "info"
|
||||
DEFMT_LOG = "info"
|
||||
@@ -0,0 +1,4 @@
|
||||
/target
|
||||
/itm.txt
|
||||
/.cargo/config.toml
|
||||
/.vscode
|
||||
+1532
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,64 @@
|
||||
[package]
|
||||
name = "satrs-stm32f3-disco-rtic"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
default-run = "satrs-stm32f3-disco-rtic"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
embedded-types = { path = "../types", features = ["defmt"] }
|
||||
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
||||
cortex-m-rt = "0.7"
|
||||
defmt = "1"
|
||||
defmt-rtt = { version = "1" }
|
||||
panic-probe = { version = "1", features = ["print-defmt"] }
|
||||
embedded-hal = "1"
|
||||
cortex-m-semihosting = "0.5.0"
|
||||
embassy-stm32 = { version = "0.6", features = ["defmt", "stm32f303vc", "memory-x", "unstable-pac", "time-driver-any"] }
|
||||
embassy-time = { version = "0.5", features = ["defmt", "generic-queue-16", "defmt-timestamp-uptime-ms"]}
|
||||
enumset = "1"
|
||||
heapless = "0.9"
|
||||
embassy-sync = "0.8"
|
||||
spacepackets = { version = "0.18", default-features = false, features = ["defmt", "serde"] }
|
||||
static_cell = "2"
|
||||
cobs = { version = "0.5", default-features = false, features = ["defmt"] }
|
||||
postcard = { version = "1" }
|
||||
arbitrary-int = "2"
|
||||
thiserror = { version = "2", default-features = false }
|
||||
serde = { version = "1", default-features = false, features = ["derive"] }
|
||||
|
||||
rtic = { version = "2", features = ["thumbv7-backend"] }
|
||||
rtic-sync = { version = "1" }
|
||||
|
||||
[dev-dependencies]
|
||||
defmt-test = "0.5"
|
||||
|
||||
# cargo test
|
||||
[profile.test]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = true # <-
|
||||
incremental = false
|
||||
opt-level = "s" # <-
|
||||
overflow-checks = true # <-
|
||||
|
||||
# cargo build/run --release
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = false # <-
|
||||
incremental = false
|
||||
lto = 'fat'
|
||||
opt-level = "s" # <-
|
||||
overflow-checks = false # <-
|
||||
|
||||
# cargo test --release
|
||||
[profile.bench]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = false # <-
|
||||
incremental = false
|
||||
lto = 'fat'
|
||||
opt-level = "s" # <-
|
||||
overflow-checks = false # <-
|
||||
File renamed without changes.
File renamed without changes.
+2
-2
@@ -1,10 +1,10 @@
|
||||
sat-rs example for the STM32F3-Discovery board
|
||||
=======
|
||||
|
||||
This example application shows how the [sat-rs framework](https://egit.irs.uni-stuttgart.de/rust/satrs-launchpad)
|
||||
This example application shows how the [sat-rs library](https://egit.irs.uni-stuttgart.de/rust/sat-rs)
|
||||
can be used on an embedded target.
|
||||
It also shows how a relatively simple OBSW could be built when no standard runtime is available.
|
||||
It uses [RTIC](https://rtic.rs/1/book/en/) as the concurrency framework and the
|
||||
It uses [RTIC](https://rtic.rs/2/book/en/) as the concurrency framework and the
|
||||
[defmt](https://defmt.ferrous-systems.com/) framework for logging.
|
||||
|
||||
The STM32F3-Discovery device was picked because it is a cheap Cortex-M4 based device which is also
|
||||
@@ -0,0 +1,56 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use panic_probe as _;
|
||||
use rtic::app;
|
||||
|
||||
#[app(device = embassy_stm32)]
|
||||
mod app {
|
||||
use embassy_time::Timer;
|
||||
use satrs_stm32f3_disco_rtic::{Direction, LedPinSet, Leds};
|
||||
|
||||
#[shared]
|
||||
struct Shared {}
|
||||
|
||||
#[local]
|
||||
struct Local {
|
||||
leds: Leds,
|
||||
current_dir: Direction,
|
||||
}
|
||||
|
||||
#[init]
|
||||
fn init(_cx: init::Context) -> (Shared, Local) {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
|
||||
defmt::info!("Starting sat-rs demo application for the STM32F3-Discovery using RTICv2");
|
||||
|
||||
let led_pin_set = LedPinSet {
|
||||
pin_n: p.PE8,
|
||||
pin_ne: p.PE9,
|
||||
pin_e: p.PE10,
|
||||
pin_se: p.PE11,
|
||||
pin_s: p.PE12,
|
||||
pin_sw: p.PE13,
|
||||
pin_w: p.PE14,
|
||||
pin_nw: p.PE15,
|
||||
};
|
||||
let leds = Leds::new(led_pin_set);
|
||||
|
||||
blinky::spawn().expect("failed to spawn blinky task");
|
||||
(
|
||||
Shared {},
|
||||
Local {
|
||||
leds,
|
||||
current_dir: Direction::North,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[task(local = [leds, current_dir])]
|
||||
async fn blinky(cx: blinky::Context) {
|
||||
loop {
|
||||
cx.local.leds.blink_next(cx.local.current_dir);
|
||||
Timer::after_millis(200).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use defmt_rtt as _;
|
||||
use panic_probe as _;
|
||||
|
||||
use arbitrary_int::u11;
|
||||
use embassy_stm32::gpio::Output;
|
||||
|
||||
pub const APID: u11 = u11::new(0x02);
|
||||
|
||||
#[derive(defmt::Format, serde::Serialize, serde::Deserialize, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum Direction {
|
||||
North,
|
||||
NorthEast,
|
||||
East,
|
||||
SouthEast,
|
||||
South,
|
||||
SouthWest,
|
||||
West,
|
||||
NorthWest,
|
||||
}
|
||||
|
||||
impl Direction {
|
||||
pub fn switch_to_next(&mut self) -> (Self, Self) {
|
||||
let curr = *self;
|
||||
*self = match self {
|
||||
Direction::North => Direction::NorthEast,
|
||||
Direction::NorthEast => Direction::East,
|
||||
Direction::East => Direction::SouthEast,
|
||||
Direction::SouthEast => Direction::South,
|
||||
Direction::South => Direction::SouthWest,
|
||||
Direction::SouthWest => Direction::West,
|
||||
Direction::West => Direction::NorthWest,
|
||||
Direction::NorthWest => Direction::North,
|
||||
};
|
||||
(curr, *self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Leds {
|
||||
pub north: Output<'static>,
|
||||
pub north_east: Output<'static>,
|
||||
pub east: Output<'static>,
|
||||
pub south_east: Output<'static>,
|
||||
pub south: Output<'static>,
|
||||
pub south_west: Output<'static>,
|
||||
pub west: Output<'static>,
|
||||
pub north_west: Output<'static>,
|
||||
}
|
||||
|
||||
impl Leds {
|
||||
pub fn blink_next(&mut self, current_dir: &mut Direction) {
|
||||
let (prev, curr) = current_dir.switch_to_next();
|
||||
self.set_dir_low(prev);
|
||||
self.set_dir_high(curr);
|
||||
}
|
||||
|
||||
pub fn set_dir(&mut self, dir: Direction, level: embassy_stm32::gpio::Level) {
|
||||
match dir {
|
||||
Direction::North => self.north.set_level(level),
|
||||
Direction::NorthEast => self.north_east.set_level(level),
|
||||
Direction::East => self.east.set_level(level),
|
||||
Direction::SouthEast => self.south_east.set_level(level),
|
||||
Direction::South => self.south.set_level(level),
|
||||
Direction::SouthWest => self.south_west.set_level(level),
|
||||
Direction::West => self.west.set_level(level),
|
||||
Direction::NorthWest => self.north_west.set_level(level),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_dir_low(&mut self, dir: Direction) {
|
||||
self.set_dir(dir, embassy_stm32::gpio::Level::Low);
|
||||
}
|
||||
|
||||
pub fn set_dir_high(&mut self, dir: Direction) {
|
||||
self.set_dir(dir, embassy_stm32::gpio::Level::High);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LedPinSet {
|
||||
pub pin_n: embassy_stm32::Peri<'static, embassy_stm32::peripherals::PE8>,
|
||||
pub pin_ne: embassy_stm32::Peri<'static, embassy_stm32::peripherals::PE9>,
|
||||
pub pin_e: embassy_stm32::Peri<'static, embassy_stm32::peripherals::PE10>,
|
||||
pub pin_se: embassy_stm32::Peri<'static, embassy_stm32::peripherals::PE11>,
|
||||
pub pin_s: embassy_stm32::Peri<'static, embassy_stm32::peripherals::PE12>,
|
||||
pub pin_sw: embassy_stm32::Peri<'static, embassy_stm32::peripherals::PE13>,
|
||||
pub pin_w: embassy_stm32::Peri<'static, embassy_stm32::peripherals::PE14>,
|
||||
pub pin_nw: embassy_stm32::Peri<'static, embassy_stm32::peripherals::PE15>,
|
||||
}
|
||||
|
||||
impl Leds {
|
||||
pub fn new(pin_set: LedPinSet) -> Self {
|
||||
let led_n = Output::new(
|
||||
pin_set.pin_n,
|
||||
embassy_stm32::gpio::Level::Low,
|
||||
embassy_stm32::gpio::Speed::Medium,
|
||||
);
|
||||
let led_ne = Output::new(
|
||||
pin_set.pin_ne,
|
||||
embassy_stm32::gpio::Level::Low,
|
||||
embassy_stm32::gpio::Speed::Medium,
|
||||
);
|
||||
let led_e = Output::new(
|
||||
pin_set.pin_e,
|
||||
embassy_stm32::gpio::Level::Low,
|
||||
embassy_stm32::gpio::Speed::Medium,
|
||||
);
|
||||
let led_se = Output::new(
|
||||
pin_set.pin_se,
|
||||
embassy_stm32::gpio::Level::Low,
|
||||
embassy_stm32::gpio::Speed::Medium,
|
||||
);
|
||||
let led_s = Output::new(
|
||||
pin_set.pin_s,
|
||||
embassy_stm32::gpio::Level::Low,
|
||||
embassy_stm32::gpio::Speed::Medium,
|
||||
);
|
||||
let led_sw = Output::new(
|
||||
pin_set.pin_sw,
|
||||
embassy_stm32::gpio::Level::Low,
|
||||
embassy_stm32::gpio::Speed::Medium,
|
||||
);
|
||||
let led_w = Output::new(
|
||||
pin_set.pin_w,
|
||||
embassy_stm32::gpio::Level::Low,
|
||||
embassy_stm32::gpio::Speed::Medium,
|
||||
);
|
||||
let led_nw = Output::new(
|
||||
pin_set.pin_nw,
|
||||
embassy_stm32::gpio::Level::Low,
|
||||
embassy_stm32::gpio::Speed::Medium,
|
||||
);
|
||||
Self {
|
||||
north: led_n,
|
||||
north_east: led_ne,
|
||||
east: led_e,
|
||||
south_east: led_se,
|
||||
south: led_s,
|
||||
south_west: led_sw,
|
||||
west: led_w,
|
||||
north_west: led_nw,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
use arbitrary_int::u14;
|
||||
use cortex_m_semihosting::debug::{self, EXIT_FAILURE, EXIT_SUCCESS};
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embedded_types::{create_tm_packet, stm32f3, tm_size, TmHeader};
|
||||
use spacepackets::{CcsdsPacketCreationError, CcsdsPacketIdAndPsc, SpHeader};
|
||||
|
||||
use defmt_rtt as _; // global logger
|
||||
use panic_probe as _;
|
||||
|
||||
use rtic::app;
|
||||
|
||||
const UART_BAUD: u32 = 115200;
|
||||
const DEFAULT_BLINK_FREQ_MS: u32 = 1000;
|
||||
const MAX_TC_LEN: usize = 128;
|
||||
const MAX_TM_LEN: usize = 128;
|
||||
|
||||
// This is the predictable maximum overhead of the COBS encoding scheme.
|
||||
// It is simply the maximum packet lenght dividied by 254 rounded up.
|
||||
const COBS_TM_OVERHEAD: usize = cobs::max_encoding_overhead(MAX_TM_LEN);
|
||||
|
||||
const TM_BUF_LEN: usize = MAX_TC_LEN + COBS_TM_OVERHEAD;
|
||||
|
||||
const TC_DMA_BUF_LEN: usize = 512;
|
||||
|
||||
type TmPacket = heapless::Vec<u8, MAX_TM_LEN>;
|
||||
|
||||
static TM_QUEUE: embassy_sync::channel::Channel<CriticalSectionRawMutex, TmPacket, 16> =
|
||||
embassy_sync::channel::Channel::new();
|
||||
|
||||
#[derive(Debug, defmt::Format, thiserror::Error)]
|
||||
pub enum TmSendError {
|
||||
#[error("packet creation error: {0}")]
|
||||
PacketCreation(#[from] CcsdsPacketCreationError),
|
||||
#[error("queue error")]
|
||||
Queue,
|
||||
}
|
||||
|
||||
#[derive(Debug, defmt::Format)]
|
||||
pub struct RequestWithTcId {
|
||||
pub request: stm32f3::Request,
|
||||
pub tc_id: CcsdsPacketIdAndPsc,
|
||||
}
|
||||
|
||||
#[app(device = embassy_stm32)]
|
||||
mod app {
|
||||
use core::time::Duration;
|
||||
|
||||
use super::*;
|
||||
use arbitrary_int::u14;
|
||||
use embassy_time::Timer;
|
||||
use embedded_types::stm32f3::{Request, Response};
|
||||
use rtic::Mutex;
|
||||
use rtic_sync::{
|
||||
channel::{Receiver, Sender},
|
||||
make_channel,
|
||||
};
|
||||
use satrs_stm32f3_disco_rtic::LedPinSet;
|
||||
use spacepackets::CcsdsPacketReader;
|
||||
|
||||
embassy_stm32::bind_interrupts!(struct Irqs {
|
||||
USART2 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART2>;
|
||||
DMA1_CHANNEL6 => embassy_stm32::dma::InterruptHandler<embassy_stm32::peripherals::DMA1_CH6>;
|
||||
DMA1_CHANNEL7 => embassy_stm32::dma::InterruptHandler<embassy_stm32::peripherals::DMA1_CH7>;
|
||||
});
|
||||
|
||||
#[shared]
|
||||
struct Shared {
|
||||
blink_freq: Duration,
|
||||
}
|
||||
|
||||
#[local]
|
||||
struct Local {
|
||||
leds: satrs_stm32f3_disco_rtic::Leds,
|
||||
current_dir: satrs_stm32f3_disco_rtic::Direction,
|
||||
seq_count: u14,
|
||||
tx: embassy_stm32::usart::UartTx<'static, embassy_stm32::mode::Async>,
|
||||
rx: embassy_stm32::usart::RingBufferedUartRx<'static>,
|
||||
}
|
||||
|
||||
#[init]
|
||||
fn init(_cx: init::Context) -> (Shared, Local) {
|
||||
static DMA_BUF: static_cell::ConstStaticCell<[u8; TC_DMA_BUF_LEN]> =
|
||||
static_cell::ConstStaticCell::new([0; TC_DMA_BUF_LEN]);
|
||||
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
|
||||
let (req_sender, req_receiver) = make_channel!(RequestWithTcId, 16);
|
||||
|
||||
defmt::info!("sat-rs demo application for the STM32F3-Discovery with RTICv2");
|
||||
let led_pin_set = LedPinSet {
|
||||
pin_n: p.PE8,
|
||||
pin_ne: p.PE9,
|
||||
pin_e: p.PE10,
|
||||
pin_se: p.PE11,
|
||||
pin_s: p.PE12,
|
||||
pin_sw: p.PE13,
|
||||
pin_w: p.PE14,
|
||||
pin_nw: p.PE15,
|
||||
};
|
||||
let leds = satrs_stm32f3_disco_rtic::Leds::new(led_pin_set);
|
||||
|
||||
let mut config = embassy_stm32::usart::Config::default();
|
||||
config.baudrate = UART_BAUD;
|
||||
let uart = embassy_stm32::usart::Uart::new(
|
||||
p.USART2, p.PA3, p.PA2, p.DMA1_CH7, p.DMA1_CH6, Irqs, config,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (tx, rx) = uart.split();
|
||||
defmt::info!("Spawning tasks");
|
||||
blinky::spawn().unwrap();
|
||||
serial_tx_handler::spawn().unwrap();
|
||||
serial_rx_handler::spawn(req_sender).unwrap();
|
||||
req_handler::spawn(req_receiver).unwrap();
|
||||
|
||||
(
|
||||
Shared {
|
||||
blink_freq: Duration::from_millis(DEFAULT_BLINK_FREQ_MS as u64),
|
||||
},
|
||||
Local {
|
||||
leds,
|
||||
tx,
|
||||
seq_count: u14::new(0),
|
||||
rx: rx.into_ring_buffered(DMA_BUF.take()),
|
||||
current_dir: satrs_stm32f3_disco_rtic::Direction::North,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[task(local = [leds, current_dir], shared=[blink_freq])]
|
||||
async fn blinky(mut cx: blinky::Context) {
|
||||
loop {
|
||||
cx.local.leds.blink_next(cx.local.current_dir);
|
||||
let current_blink_freq = cx.shared.blink_freq.lock(|current| *current);
|
||||
Timer::after_millis(current_blink_freq.as_millis() as u64).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[task(
|
||||
local = [
|
||||
tx,
|
||||
encoded_buf: [u8; TM_BUF_LEN] = [0; TM_BUF_LEN]
|
||||
],
|
||||
shared = [],
|
||||
)]
|
||||
async fn serial_tx_handler(cx: serial_tx_handler::Context) {
|
||||
loop {
|
||||
loop {
|
||||
let vec = TM_QUEUE.receive().await;
|
||||
let encoded_len =
|
||||
cobs::encode_including_sentinels(&vec[0..vec.len()], cx.local.encoded_buf);
|
||||
defmt::debug!("sending {} bytes over UART", encoded_len);
|
||||
cx.local
|
||||
.tx
|
||||
.write(&cx.local.encoded_buf[0..encoded_len])
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[task(
|
||||
local = [
|
||||
rx,
|
||||
read_buf: [u8; 128] = [0; 128],
|
||||
decode_buf: [u8; MAX_TC_LEN] = [0; MAX_TC_LEN],
|
||||
],
|
||||
shared = [blink_freq]
|
||||
)]
|
||||
async fn serial_rx_handler(
|
||||
cx: serial_rx_handler::Context,
|
||||
mut sender: Sender<'static, RequestWithTcId, 16>,
|
||||
) {
|
||||
let mut decoder = cobs::CobsDecoder::new(cx.local.decode_buf);
|
||||
loop {
|
||||
match cx.local.rx.read(cx.local.read_buf).await {
|
||||
Ok(bytes) => {
|
||||
defmt::debug!("received {} bytes over UART", bytes);
|
||||
for byte in cx.local.read_buf[0..bytes].iter() {
|
||||
match decoder.feed(*byte) {
|
||||
Ok(None) => (),
|
||||
Ok(Some(packet_size)) => {
|
||||
match CcsdsPacketReader::new_with_checksum(
|
||||
&decoder.dest()[0..packet_size],
|
||||
) {
|
||||
Ok(packet) => {
|
||||
let tc_packet_id =
|
||||
CcsdsPacketIdAndPsc::new_from_ccsds_packet(&packet);
|
||||
if let Ok(request) =
|
||||
postcard::from_bytes::<Request>(packet.packet_data())
|
||||
{
|
||||
sender
|
||||
.send(RequestWithTcId {
|
||||
request,
|
||||
tc_id: tc_packet_id,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
defmt::error!("error unpacking ccsds packet: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
defmt::error!("cobs decoding error: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
defmt::error!("uart read error: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[task(shared = [blink_freq], local = [seq_count])]
|
||||
async fn req_handler(
|
||||
mut cx: req_handler::Context,
|
||||
mut receiver: Receiver<'static, RequestWithTcId, 16>,
|
||||
) {
|
||||
loop {
|
||||
match receiver.recv().await {
|
||||
Ok(request_with_tc_id) => {
|
||||
let tm_send_result = match request_with_tc_id.request {
|
||||
Request::Ping => {
|
||||
handle_ping_request(&mut cx, request_with_tc_id.tc_id).await
|
||||
}
|
||||
Request::ChangeBlinkFrequency(duration) => {
|
||||
handle_change_blink_frequency_request(
|
||||
&mut cx,
|
||||
request_with_tc_id.tc_id,
|
||||
duration,
|
||||
)
|
||||
.await
|
||||
}
|
||||
};
|
||||
if let Err(e) = tm_send_result {
|
||||
defmt::error!("error sending TM response: {}", e);
|
||||
}
|
||||
}
|
||||
Err(_e) => defmt::error!("request receive error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_ping_request(
|
||||
cx: &mut req_handler::Context<'_>,
|
||||
tc_packet_id: CcsdsPacketIdAndPsc,
|
||||
) -> Result<(), TmSendError> {
|
||||
defmt::info!("Received PUS ping telecommand, sending ping reply");
|
||||
send_tm(tc_packet_id, Response::Ok, *cx.local.seq_count).await?;
|
||||
*cx.local.seq_count = cx.local.seq_count.wrapping_add(u14::new(1));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_change_blink_frequency_request(
|
||||
cx: &mut req_handler::Context<'_>,
|
||||
tc_packet_id: CcsdsPacketIdAndPsc,
|
||||
duration: Duration,
|
||||
) -> Result<(), TmSendError> {
|
||||
defmt::info!(
|
||||
"Received ChangeBlinkFrequency request, new frequency: {} ms",
|
||||
duration.as_millis()
|
||||
);
|
||||
cx.shared
|
||||
.blink_freq
|
||||
.lock(|blink_freq| *blink_freq = duration);
|
||||
send_tm(tc_packet_id, Response::Ok, *cx.local.seq_count).await?;
|
||||
*cx.local.seq_count = cx.local.seq_count.wrapping_add(u14::new(1));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_tm(
|
||||
tc_packet_id: CcsdsPacketIdAndPsc,
|
||||
response: stm32f3::Response,
|
||||
current_seq_count: u14,
|
||||
) -> Result<(), TmSendError> {
|
||||
let sp_header = SpHeader::new_for_unseg_tc(stm32f3::PUS_APID, current_seq_count, 0);
|
||||
let tm_header = TmHeader {
|
||||
tc_packet_id: Some(tc_packet_id),
|
||||
uptime_millis: embassy_time::Instant::now().as_millis(),
|
||||
};
|
||||
let mut tm_packet = TmPacket::new();
|
||||
let tm_size = tm_size(&tm_header, &response);
|
||||
tm_packet.resize(tm_size, 0).expect("vec resize failed");
|
||||
create_tm_packet(&mut tm_packet, sp_header, tm_header, response)?;
|
||||
TM_QUEUE.send(tm_packet).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// same panicking *behavior* as `panic-probe` but doesn't print a panic message
|
||||
// this prevents the panic message being printed *twice* when `defmt::panic` is invoked
|
||||
#[defmt::panic_handler]
|
||||
fn panic() -> ! {
|
||||
cortex_m::asm::udf()
|
||||
}
|
||||
|
||||
/// Terminates the application and makes a semihosting-capable debug tool exit
|
||||
/// with status code 0.
|
||||
pub fn exit() -> ! {
|
||||
loop {
|
||||
debug::exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
/// Hardfault handler.
|
||||
///
|
||||
/// Terminates the application and makes a semihosting-capable debug tool exit
|
||||
/// with an error. This seems better than the default, which is to spin in a
|
||||
/// loop.
|
||||
#[cortex_m_rt::exception]
|
||||
unsafe fn HardFault(_frame: &cortex_m_rt::ExceptionFrame) -> ! {
|
||||
loop {
|
||||
debug::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// defmt-test 0.3.0 has the limitation that this `#[tests]` attribute can only be used
|
||||
// once within a crate. the module can be in any file but there can only be at most
|
||||
// one `#[tests]` module in this library crate
|
||||
#[cfg(test)]
|
||||
#[defmt_test::tests]
|
||||
mod unit_tests {
|
||||
use defmt::assert;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert!(true)
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
+2
-2
@@ -12,11 +12,11 @@
|
||||
"chip": "STM32F303VCTx",
|
||||
"coreConfigs": [
|
||||
{
|
||||
"programBinary": "${workspaceFolder}/target/thumbv7em-none-eabihf/debug/satrs-example-stm32f3-disco",
|
||||
"programBinary": "${workspaceFolder}/target/thumbv7em-none-eabihf/debug/satrs-stm32f3-disco-rtic",
|
||||
"rttEnabled": true,
|
||||
"svdFile": "STM32F303.svd"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,4 +1,4 @@
|
||||
/target
|
||||
/itm.txt
|
||||
/.cargo/config*
|
||||
/.vscode
|
||||
/app.map
|
||||
+1332
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,75 @@
|
||||
[package]
|
||||
name = "satrs-stm32h7-nucleo-rtic"
|
||||
edition = "2021"
|
||||
version = "0.1.0"
|
||||
default-run = "satrs-stm32h7-nucleo-rtic"
|
||||
|
||||
[lib]
|
||||
harness = false
|
||||
|
||||
# needed for each integration test
|
||||
[[test]]
|
||||
name = "integration"
|
||||
harness = false
|
||||
|
||||
[dependencies]
|
||||
embedded-types = { path = "../types", features = ["defmt"] }
|
||||
|
||||
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
||||
arbitrary-int = "2"
|
||||
cortex-m-rt = "0.7"
|
||||
defmt = "1"
|
||||
defmt-rtt = "1"
|
||||
panic-probe = { version = "1", features = ["print-defmt"] }
|
||||
embedded-alloc = "0.7"
|
||||
static_cell = "2"
|
||||
rtic = { version = "2", features = ["thumbv7-backend"] }
|
||||
spacepackets = { version = "0.18", default-features = false, features = ["defmt"] }
|
||||
postcard = "1"
|
||||
|
||||
embassy-stm32 = { git = "https://github.com/embassy-rs/embassy.git", rev = "dd8e4c14e53f088bae27c5d841ab7a4fa338a52c", version = "0.6", features = ["stm32h743zi", "memory-x", "defmt", "time-driver-any"]}
|
||||
|
||||
embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "dd8e4c14e53f088bae27c5d841ab7a4fa338a52c", version = "0.5", features = ["defmt-timestamp-uptime-ms", "generic-queue-16"] }
|
||||
embassy-net = { git = "https://github.com/embassy-rs/embassy.git", rev = "dd8e4c14e53f088bae27c5d841ab7a4fa338a52c", version = "0.9", features = ["medium-ethernet", "proto-ipv4", "tcp", "udp", "auto-icmp-echo-reply", "dhcpv4", "defmt"] }
|
||||
embassy-sync = { git = "https://github.com/embassy-rs/embassy.git", rev = "dd8e4c14e53f088bae27c5d841ab7a4fa338a52c" }
|
||||
|
||||
[dev-dependencies]
|
||||
defmt-test = "0.5"
|
||||
|
||||
# cargo build/run
|
||||
[profile.dev]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = true # <-
|
||||
incremental = false
|
||||
opt-level = 's' # <-
|
||||
overflow-checks = true # <-
|
||||
|
||||
# cargo test
|
||||
[profile.test]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = true # <-
|
||||
incremental = false
|
||||
opt-level = 3 # <-
|
||||
overflow-checks = true # <-
|
||||
|
||||
# cargo build/run --release
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = false # <-
|
||||
incremental = false
|
||||
lto = 'fat'
|
||||
opt-level = 3 # <-
|
||||
overflow-checks = false # <-
|
||||
|
||||
# cargo test --release
|
||||
[profile.bench]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = false # <-
|
||||
incremental = false
|
||||
lto = 'fat'
|
||||
opt-level = 3 # <-
|
||||
overflow-checks = false # <-
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,118 @@
|
||||
sat-rs example for the STM32H73ZI-Nucleo board
|
||||
=======
|
||||
|
||||
This example application shows how the [sat-rs library](https://egit.irs.uni-stuttgart.de/rust/sat-rs)
|
||||
can be used on an embedded target.
|
||||
It also shows how a relatively simple OBSW could be built when no standard runtime is available.
|
||||
It uses [RTIC](https://rtic.rs/2/book/en/) as the concurrency framework and the
|
||||
[defmt](https://defmt.ferrous-systems.com/) framework for logging.
|
||||
|
||||
The STM32H743ZIT device was picked because it is one of the more powerful Cortex-M based devices
|
||||
available for STM with which also has a little bit more RAM available and also allows commanding
|
||||
via TCP/IP.
|
||||
|
||||
## Pre-Requisites
|
||||
|
||||
Make sure the following tools are installed:
|
||||
|
||||
1. [`probe-rs`](https://probe.rs/): Application used to flash and debug the MCU.
|
||||
2. Optional and recommended: [VS Code](https://code.visualstudio.com/) with
|
||||
[probe-rs plugin](https://marketplace.visualstudio.com/items?itemName=probe-rs.probe-rs-debugger)
|
||||
for debugging.
|
||||
|
||||
## Preparing Rust and the repository
|
||||
|
||||
Building an application requires the `thumbv7em-none-eabihf` cross-compiler toolchain.
|
||||
If you have not installed it yet, you can do so with
|
||||
|
||||
```sh
|
||||
rustup target add thumbv7em-none-eabihf
|
||||
```
|
||||
|
||||
A default `.cargo` config file is provided for this project, but needs to be copied to have
|
||||
the correct name. This is so that the config file can be updated or edited for custom needs
|
||||
without being tracked by git.
|
||||
|
||||
```sh
|
||||
cp def_config.toml config.toml
|
||||
```
|
||||
|
||||
The configuration file will also set the target so it does not always have to be specified with
|
||||
the `--target` argument.
|
||||
|
||||
## Building
|
||||
|
||||
After that, assuming that you have a `.cargo/config.toml` setting the correct build target,
|
||||
you can simply build the application with
|
||||
|
||||
```sh
|
||||
cargo build
|
||||
```
|
||||
|
||||
## Flashing from the command line
|
||||
|
||||
You can flash the application from the command line using `probe-rs`:
|
||||
|
||||
```sh
|
||||
probe-rs run --chip STM32H743ZITx
|
||||
```
|
||||
|
||||
## Debugging with VS Code
|
||||
|
||||
The STM32F3-Discovery comes with an on-board ST-Link so all that is required to flash and debug
|
||||
the board is a Mini-USB cable. The code in this repository was debugged using [`probe-rs`](https://probe.rs/docs/tools/debuggerA)
|
||||
and the VS Code [`probe-rs` plugin](https://marketplace.visualstudio.com/items?itemName=probe-rs.probe-rs-debugger).
|
||||
Make sure to install this plugin first.
|
||||
|
||||
Sample configuration files are provided inside the `vscode` folder.
|
||||
Use `cp vscode .vscode -r` to use them for your project.
|
||||
|
||||
Some sample configuration files for VS Code were provided as well. You can simply use `Run` and `Debug`
|
||||
to automatically rebuild and flash your application.
|
||||
|
||||
The `tasks.json` and `launch.json` files are generic and you can use them immediately by opening
|
||||
the folder in VS code or adding it to a workspace.
|
||||
|
||||
## Commanding with Python
|
||||
|
||||
When the SW is running on the Discovery board, you can command the MCU via a serial interface,
|
||||
using COBS encoded PUS packets.
|
||||
|
||||
It is recommended to use a virtual environment to do this. To set up one in the command line,
|
||||
you can use `python3 -m venv venv` on Unix systems or `py -m venv venv` on Windows systems.
|
||||
After doing this, you can check the [venv tutorial](https://docs.python.org/3/tutorial/venv.html)
|
||||
on how to activate the environment and then use the following command to install the required
|
||||
dependency:
|
||||
|
||||
```sh
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
The packets are exchanged using a dedicated serial interface. You can use any generic USB-to-UART
|
||||
converter device with the TX pin connected to the PA3 pin and the RX pin connected to the PA2 pin.
|
||||
|
||||
A default configuration file for the python application is provided and can be used by running
|
||||
|
||||
```sh
|
||||
cp def_tmtc_conf.json tmtc_conf.json
|
||||
```
|
||||
|
||||
After that, you can for example send a ping to the MCU using the following command
|
||||
|
||||
```sh
|
||||
./main.py -p /ping
|
||||
```
|
||||
|
||||
You can configure the blinky frequency using
|
||||
|
||||
```sh
|
||||
./main.py -p /change_blink_freq
|
||||
```
|
||||
|
||||
All these commands will package a PUS telecommand which will be sent to the MCU using the COBS
|
||||
format as the packet framing format.
|
||||
|
||||
## Resources
|
||||
|
||||
- [STM32H743ZI Ethernet link checker example](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/ethernet-nucleo-h743zi2.rs)
|
||||
- [smoltcp DHCP client](https://github.com/smoltcp-rs/smoltcp/blob/main/examples/dhcp_client.rs)
|
||||
@@ -0,0 +1,14 @@
|
||||
use std::path::PathBuf;
|
||||
use std::{env, fs};
|
||||
|
||||
fn main() {
|
||||
let manifest_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
|
||||
let cargo_dir = manifest_dir.parent().unwrap().join(".cargo");
|
||||
let config = cargo_dir.join("config.toml");
|
||||
let config_template = cargo_dir.join("config.toml.template");
|
||||
|
||||
if !config.exists() && config_template.exists() {
|
||||
fs::create_dir_all(&cargo_dir).unwrap();
|
||||
fs::copy(&config_template, &config).unwrap();
|
||||
}
|
||||
}
|
||||
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,119 @@
|
||||
/* Taken from https://github.com/stm32-rs/stm32h7xx-hal/pull/299, adapted slightly to work with */
|
||||
/* flip-link */
|
||||
MEMORY
|
||||
{
|
||||
/* This file is intended for parts in the STM32H743/743v/753/753v families (RM0433), */
|
||||
/* with the exception of the STM32H742/742v parts which have a different RAM layout. */
|
||||
/* - FLASH and RAM are mandatory memory sections. */
|
||||
/* - The sum of all non-FLASH sections must add to 1060K total device RAM. */
|
||||
/* - The FLASH section size must match your device, see table below. */
|
||||
|
||||
/* FLASH */
|
||||
/* Flash is divided in two independent banks (except 750xB). */
|
||||
/* Select the appropriate FLASH size for your device. */
|
||||
/* - STM32H750xB 128K (only FLASH1) */
|
||||
/* - STM32H750xB 1M (512K + 512K) */
|
||||
/* - STM32H743xI/753xI 2M ( 1M + 1M) */
|
||||
FLASH1 : ORIGIN = 0x08000000, LENGTH = 1M
|
||||
FLASH2 : ORIGIN = 0x08100000, LENGTH = 1M
|
||||
|
||||
/* Data TCM */
|
||||
/* - Two contiguous 64KB RAMs. */
|
||||
/* - Used for interrupt handlers, stacks and general RAM. */
|
||||
/* - Zero wait-states. */
|
||||
/* - The DTCM is taken as the origin of the base ram. (See below.) */
|
||||
/* This is also where the interrupt table and such will live, */
|
||||
/* which is required for deterministic performance. */
|
||||
/* Need a region called RAM */
|
||||
/* DTCM : ORIGIN = 0x20000000, LENGTH = 128K */
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 128K
|
||||
|
||||
/* Instruction TCM */
|
||||
/* - Used for latency-critical interrupt handlers etc. */
|
||||
/* - Zero wait-states. */
|
||||
ITCM : ORIGIN = 0x00000000, LENGTH = 64K
|
||||
|
||||
/* AXI SRAM */
|
||||
/* - AXISRAM is in D1 and accessible by all system masters except BDMA. */
|
||||
/* - Suitable for application data not stored in DTCM. */
|
||||
/* - Zero wait-states. */
|
||||
AXISRAM : ORIGIN = 0x24000000, LENGTH = 512K
|
||||
|
||||
/* AHB SRAM */
|
||||
/* - SRAM1-3 are in D2 and accessible by all system masters except BDMA. */
|
||||
/* Suitable for use as DMA buffers. */
|
||||
/* - SRAM4 is in D3 and additionally accessible by the BDMA. Used for BDMA */
|
||||
/* buffers, for storing application data in lower-power modes. */
|
||||
/* - Zero wait-states. */
|
||||
SRAM1 : ORIGIN = 0x30000000, LENGTH = 128K
|
||||
SRAM2 : ORIGIN = 0x30020000, LENGTH = 128K
|
||||
SRAM3 : ORIGIN = 0x30040000, LENGTH = 32K
|
||||
SRAM4 : ORIGIN = 0x38000000, LENGTH = 64K
|
||||
|
||||
/* Backup SRAM */
|
||||
BSRAM : ORIGIN = 0x38800000, LENGTH = 4K
|
||||
}
|
||||
|
||||
/*
|
||||
/* Assign the memory regions defined above for use. */
|
||||
/*
|
||||
|
||||
/* Provide the mandatory FLASH and RAM definitions for cortex-m-rt's linker script. */
|
||||
/* These do not work with flip-link */
|
||||
REGION_ALIAS(FLASH, FLASH1);
|
||||
/* REGION_ALIAS(RAM, DTCM); */
|
||||
|
||||
/* The location of the stack can be overridden using the `_stack_start` symbol. */
|
||||
/* - Set the stack location at the end of RAM, using all remaining space. */
|
||||
_stack_start = ORIGIN(RAM) + LENGTH(RAM);
|
||||
|
||||
/* The location of the .text section can be overridden using the */
|
||||
/* `_stext` symbol. By default it will place after .vector_table. */
|
||||
/* _stext = ORIGIN(FLASH) + 0x40c; */
|
||||
|
||||
/* Define sections for placing symbols into the extra memory regions above. */
|
||||
/* This makes them accessible from code. */
|
||||
/* - ITCM, DTCM and AXISRAM connect to a 64-bit wide bus -> align to 8 bytes. */
|
||||
/* - All other memories connect to a 32-bit wide bus -> align to 4 bytes. */
|
||||
SECTIONS {
|
||||
.flash2 (NOLOAD) : ALIGN(4) {
|
||||
*(.flash2 .flash2.*);
|
||||
. = ALIGN(4);
|
||||
} > FLASH2
|
||||
|
||||
.itcm (NOLOAD) : ALIGN(8) {
|
||||
*(.itcm .itcm.*);
|
||||
. = ALIGN(8);
|
||||
} > ITCM
|
||||
|
||||
.axisram (NOLOAD) : ALIGN(8) {
|
||||
*(.axisram .axisram.*);
|
||||
. = ALIGN(8);
|
||||
} > AXISRAM
|
||||
|
||||
.sram1 (NOLOAD) : ALIGN(8) {
|
||||
*(.sram1 .sram1.*);
|
||||
. = ALIGN(4);
|
||||
} > SRAM1
|
||||
|
||||
.sram2 (NOLOAD) : ALIGN(8) {
|
||||
*(.sram2 .sram2.*);
|
||||
. = ALIGN(4);
|
||||
} > SRAM2
|
||||
|
||||
.sram3 (NOLOAD) : ALIGN(4) {
|
||||
*(.sram3 .sram3.*);
|
||||
. = ALIGN(4);
|
||||
} > SRAM3
|
||||
|
||||
.sram4 (NOLOAD) : ALIGN(4) {
|
||||
*(.sram4 .sram4.*);
|
||||
. = ALIGN(4);
|
||||
} > SRAM4
|
||||
|
||||
.bsram (NOLOAD) : ALIGN(4) {
|
||||
*(.bsram .bsram.*);
|
||||
. = ALIGN(4);
|
||||
} > BSRAM
|
||||
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
[toolchain]
|
||||
targets = ["thumbv7em-none-eabihf"]
|
||||
@@ -0,0 +1,57 @@
|
||||
//! Blinks an LED
|
||||
//!
|
||||
//! This assumes that LD2 (blue) is connected to pb7 and LD3 (red) is connected
|
||||
//! to pb14. This assumption is true for the nucleo-h743zi board.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
use rtic::app;
|
||||
use satrs_stm32h7_nucleo_rtic as _;
|
||||
|
||||
#[app(device = embassy_stm32, peripherals = false, dispatchers = [SPI1])]
|
||||
mod app {
|
||||
use embassy_stm32::gpio;
|
||||
|
||||
#[shared]
|
||||
struct Shared {}
|
||||
|
||||
#[local]
|
||||
struct Local {}
|
||||
|
||||
#[init]
|
||||
fn init(_cx: init::Context) -> (Shared, Local) {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
defmt::info!("Hello World!");
|
||||
// Configure gpio B pin 0 as a push-pull output.
|
||||
let ld1 = gpio::Output::new(p.PB0, gpio::Level::High, gpio::Speed::Low);
|
||||
let ld2 = gpio::Output::new(p.PB7, gpio::Level::High, gpio::Speed::Low);
|
||||
let ld3 = gpio::Output::new(p.PB14, gpio::Level::High, gpio::Speed::Low);
|
||||
|
||||
// Schedule the blinking task
|
||||
blink::spawn(ld1, ld2, ld3).ok();
|
||||
|
||||
(Shared {}, Local {})
|
||||
}
|
||||
|
||||
#[task()]
|
||||
async fn blink(
|
||||
_cx: blink::Context,
|
||||
mut ld1: gpio::Output<'static>,
|
||||
mut ld2: gpio::Output<'static>,
|
||||
mut ld3: gpio::Output<'static>,
|
||||
) {
|
||||
loop {
|
||||
defmt::info!("high");
|
||||
ld1.set_high();
|
||||
ld2.set_high();
|
||||
ld3.set_high();
|
||||
embassy_time::Timer::after_millis(500).await;
|
||||
|
||||
defmt::info!("low");
|
||||
ld1.set_low();
|
||||
ld2.set_low();
|
||||
ld3.set_low();
|
||||
embassy_time::Timer::after_millis(500).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
// global logger + panicking-behavior + memory layout
|
||||
use satrs_stm32h7_nucleo_rtic as _;
|
||||
|
||||
#[cortex_m_rt::entry]
|
||||
fn main() -> ! {
|
||||
loop {
|
||||
defmt::println!("Hello, world!");
|
||||
cortex_m::asm::delay(100_000_000);
|
||||
}
|
||||
}
|
||||
+3
-17
@@ -1,12 +1,8 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use cortex_m_semihosting::debug;
|
||||
|
||||
use defmt_brtt as _; // global logger
|
||||
|
||||
use stm32f3xx_hal as _; // memory layout
|
||||
|
||||
use defmt_rtt as _;
|
||||
use embassy_stm32 as _;
|
||||
use panic_probe as _;
|
||||
|
||||
// same panicking *behavior* as `panic-probe` but doesn't print a panic message
|
||||
@@ -16,14 +12,6 @@ fn panic() -> ! {
|
||||
cortex_m::asm::udf()
|
||||
}
|
||||
|
||||
/// Terminates the application and makes a semihosting-capable debug tool exit
|
||||
/// with status code 0.
|
||||
pub fn exit() -> ! {
|
||||
loop {
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
/// Hardfault handler.
|
||||
///
|
||||
/// Terminates the application and makes a semihosting-capable debug tool exit
|
||||
@@ -31,9 +19,7 @@ pub fn exit() -> ! {
|
||||
/// loop.
|
||||
#[cortex_m_rt::exception]
|
||||
unsafe fn HardFault(_frame: &cortex_m_rt::ExceptionFrame) -> ! {
|
||||
loop {
|
||||
debug::exit(debug::EXIT_FAILURE);
|
||||
}
|
||||
panic!("unexpected hard fault");
|
||||
}
|
||||
|
||||
// defmt-test 0.3.0 has the limitation that this `#[tests]` attribute can only be used
|
||||
@@ -0,0 +1,386 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
extern crate alloc;
|
||||
|
||||
use rtic::app;
|
||||
// global logger + panicking-behavior + memory layout
|
||||
use embassy_stm32::bind_interrupts;
|
||||
use satrs_stm32h7_nucleo_rtic as _;
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
use embedded_alloc::LlffHeap as Heap;
|
||||
|
||||
const DEFAULT_BLINK_FREQ_MS: u32 = 1000;
|
||||
const PORT: u16 = 7301;
|
||||
|
||||
const HEAP_SIZE: usize = 131_072;
|
||||
|
||||
#[global_allocator]
|
||||
static HEAP: Heap = Heap::empty();
|
||||
|
||||
/// Locally administered MAC address
|
||||
const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44];
|
||||
|
||||
const TC_QUEUE_DEPTH: usize = 32;
|
||||
const TM_QUEUE_DEPTH: usize = 32;
|
||||
|
||||
#[app(device = embassy_stm32, peripherals = false)]
|
||||
mod app {
|
||||
|
||||
use super::*;
|
||||
use arbitrary_int::u14;
|
||||
use embassy_net::udp::UdpSocket;
|
||||
use embassy_net::StackResources;
|
||||
use embassy_stm32::eth;
|
||||
use embassy_stm32::gpio;
|
||||
use embassy_stm32::peripherals;
|
||||
use embassy_stm32::rng;
|
||||
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||
use embassy_time::Duration;
|
||||
use embassy_time::Timer;
|
||||
use embassy_time::WithTimeout as _;
|
||||
use embedded_types::create_tm_packet;
|
||||
use embedded_types::stm32h7;
|
||||
use embedded_types::tm_size;
|
||||
use embedded_types::TmHeader;
|
||||
use spacepackets::CcsdsPacketCreationError;
|
||||
use spacepackets::CcsdsPacketIdAndPsc;
|
||||
use spacepackets::CcsdsPacketReader;
|
||||
use spacepackets::SpHeader;
|
||||
use static_cell::StaticCell;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
ETH => eth::InterruptHandler;
|
||||
RNG => rng::InterruptHandler<peripherals::RNG>;
|
||||
});
|
||||
|
||||
type Device = eth::Ethernet<
|
||||
'static,
|
||||
peripherals::ETH,
|
||||
eth::GenericPhy<eth::Sma<'static, peripherals::ETH_SMA>>,
|
||||
>;
|
||||
|
||||
struct BlinkyLeds {
|
||||
led1: gpio::Output<'static>,
|
||||
led2: gpio::Output<'static>,
|
||||
}
|
||||
|
||||
#[local]
|
||||
struct Local {
|
||||
net_runner: embassy_net::Runner<'static, Device>,
|
||||
net_stack: embassy_net::Stack<'static>,
|
||||
leds: BlinkyLeds,
|
||||
link_led: gpio::Output<'static>,
|
||||
tc_rx: embassy_sync::channel::Receiver<
|
||||
'static,
|
||||
NoopRawMutex,
|
||||
alloc::vec::Vec<u8>,
|
||||
TC_QUEUE_DEPTH,
|
||||
>,
|
||||
tc_tx: embassy_sync::channel::Sender<
|
||||
'static,
|
||||
NoopRawMutex,
|
||||
alloc::vec::Vec<u8>,
|
||||
TC_QUEUE_DEPTH,
|
||||
>,
|
||||
tm_rx: embassy_sync::channel::Receiver<
|
||||
'static,
|
||||
NoopRawMutex,
|
||||
alloc::vec::Vec<u8>,
|
||||
TM_QUEUE_DEPTH,
|
||||
>,
|
||||
tm_tx: embassy_sync::channel::Sender<
|
||||
'static,
|
||||
NoopRawMutex,
|
||||
alloc::vec::Vec<u8>,
|
||||
TM_QUEUE_DEPTH,
|
||||
>,
|
||||
}
|
||||
|
||||
#[shared]
|
||||
struct Shared {
|
||||
sequence_count: u14,
|
||||
blink_freq: embassy_time::Duration,
|
||||
}
|
||||
|
||||
#[init]
|
||||
fn init(_cx: init::Context) -> (Shared, Local) {
|
||||
defmt::println!("Starting sat-rs demo application for the STM32H743ZIT");
|
||||
|
||||
let mut config = embassy_stm32::Config::default();
|
||||
{
|
||||
use embassy_stm32::rcc::*;
|
||||
config.rcc.hsi = Some(HSIPrescaler::Div1);
|
||||
config.rcc.csi = true;
|
||||
config.rcc.hsi48 = Some(Default::default()); // needed for RNG
|
||||
config.rcc.pll1 = Some(Pll {
|
||||
source: PllSource::Hsi,
|
||||
prediv: PllPreDiv::Div4,
|
||||
mul: PllMul::Mul50,
|
||||
fracn: None,
|
||||
divp: Some(PllDiv::Div2),
|
||||
divq: None,
|
||||
divr: None,
|
||||
});
|
||||
config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
|
||||
config.rcc.ahb_pre = AHBPrescaler::Div2; // 200 Mhz
|
||||
config.rcc.apb1_pre = APBPrescaler::Div2; // 100 Mhz
|
||||
config.rcc.apb2_pre = APBPrescaler::Div2; // 100 Mhz
|
||||
config.rcc.apb3_pre = APBPrescaler::Div2; // 100 Mhz
|
||||
config.rcc.apb4_pre = APBPrescaler::Div2; // 100 Mhz
|
||||
config.rcc.voltage_scale = VoltageScale::Scale1;
|
||||
}
|
||||
let periphs = embassy_stm32::init(config);
|
||||
|
||||
let link_led = gpio::Output::new(periphs.PB0, gpio::Level::Low, gpio::Speed::Medium);
|
||||
let mut led1 = gpio::Output::new(periphs.PB7, gpio::Level::Low, gpio::Speed::Medium);
|
||||
let mut led2 = gpio::Output::new(periphs.PB14, gpio::Level::Low, gpio::Speed::Medium);
|
||||
|
||||
// Criss-cross pattern looks cooler.
|
||||
led1.set_high();
|
||||
led2.set_low();
|
||||
let leds = BlinkyLeds { led1, led2 };
|
||||
|
||||
static PACKETS: StaticCell<eth::PacketQueue<4, 4>> = StaticCell::new();
|
||||
// warning: Not all STM32H7 devices have the exact same pins here
|
||||
// for STM32H747XIH, replace p.PB13 for PG12
|
||||
let device = eth::Ethernet::new(
|
||||
PACKETS.init(eth::PacketQueue::<4, 4>::new()),
|
||||
periphs.ETH,
|
||||
Irqs,
|
||||
periphs.PA1, // ref_clk
|
||||
periphs.PA7, // CRS_DV: Carrier Sense
|
||||
periphs.PC4, // RX_D0: Received Bit 0
|
||||
periphs.PC5, // RX_D1: Received Bit 1
|
||||
periphs.PG13, // TX_D0: Transmit Bit 0
|
||||
periphs.PB13, // TX_D1: Transmit Bit 1
|
||||
periphs.PG11, // TX_EN: Transmit Enable
|
||||
MAC_ADDRESS,
|
||||
periphs.ETH_SMA,
|
||||
periphs.PA2, // mdio
|
||||
periphs.PC1, // mdc
|
||||
);
|
||||
|
||||
let config = embassy_net::Config::dhcpv4(embassy_net::DhcpConfig::default());
|
||||
|
||||
// Generate random seed.
|
||||
let mut rng = rng::Rng::new(periphs.RNG, Irqs);
|
||||
let mut seed = [0; 8];
|
||||
rng.fill_bytes(&mut seed);
|
||||
let seed = u64::from_le_bytes(seed);
|
||||
|
||||
// Init network stack
|
||||
static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
|
||||
let (stack, runner) =
|
||||
embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
|
||||
|
||||
// Set up global allocator. Use AXISRAM for the heap.
|
||||
#[link_section = ".axisram"]
|
||||
static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
|
||||
unsafe { HEAP.init(&raw mut HEAP_MEM as usize, HEAP_SIZE) }
|
||||
|
||||
static TC_CHANNEL: static_cell::ConstStaticCell<
|
||||
embassy_sync::channel::Channel<NoopRawMutex, alloc::vec::Vec<u8>, TC_QUEUE_DEPTH>,
|
||||
> = static_cell::ConstStaticCell::new(embassy_sync::channel::Channel::new());
|
||||
let tc_channel = TC_CHANNEL.take();
|
||||
let tc_sender = tc_channel.sender();
|
||||
let tc_receiver = tc_channel.receiver();
|
||||
|
||||
static TM_CHANNEL: static_cell::ConstStaticCell<
|
||||
embassy_sync::channel::Channel<NoopRawMutex, alloc::vec::Vec<u8>, TM_QUEUE_DEPTH>,
|
||||
> = static_cell::ConstStaticCell::new(embassy_sync::channel::Channel::new());
|
||||
let tm_channel = TM_CHANNEL.take();
|
||||
let tm_sender = tm_channel.sender();
|
||||
let tm_receiver = tm_channel.receiver();
|
||||
|
||||
net_lib_task::spawn().expect("spawning net library task failed");
|
||||
net_app_task::spawn().expect("spawning net application task failed");
|
||||
blinky::spawn().expect("spawning blink task failed");
|
||||
tc_handler::spawn().expect("spawning TC handler task failed");
|
||||
|
||||
(
|
||||
Shared {
|
||||
blink_freq: Duration::from_millis(DEFAULT_BLINK_FREQ_MS as u64),
|
||||
sequence_count: u14::new(0),
|
||||
},
|
||||
Local {
|
||||
link_led,
|
||||
leds,
|
||||
net_runner: runner,
|
||||
net_stack: stack,
|
||||
tc_tx: tc_sender,
|
||||
tc_rx: tc_receiver,
|
||||
tm_tx: tm_sender,
|
||||
tm_rx: tm_receiver,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[task(local = [leds], shared=[blink_freq])]
|
||||
async fn blinky(mut cx: blinky::Context) {
|
||||
let leds = cx.local.leds;
|
||||
loop {
|
||||
leds.led1.toggle();
|
||||
leds.led2.toggle();
|
||||
let current_blink_freq = cx.shared.blink_freq.lock(|current| *current);
|
||||
Timer::after_millis(current_blink_freq.as_millis()).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[task(local=[net_runner])]
|
||||
async fn net_lib_task(cx: net_lib_task::Context) {
|
||||
cx.local.net_runner.run().await;
|
||||
}
|
||||
|
||||
#[task(local = [net_stack, link_led, tc_tx, tm_rx])]
|
||||
async fn net_app_task(cx: net_app_task::Context) {
|
||||
pub const MTU: usize = 1500;
|
||||
|
||||
// Ensure those are in the data section by making them static.
|
||||
static RX_UDP_META: static_cell::ConstStaticCell<[embassy_net::udp::PacketMetadata; 8]> =
|
||||
static_cell::ConstStaticCell::new([embassy_net::udp::PacketMetadata::EMPTY; 8]);
|
||||
static TX_UDP_META: static_cell::ConstStaticCell<[embassy_net::udp::PacketMetadata; 8]> =
|
||||
static_cell::ConstStaticCell::new([embassy_net::udp::PacketMetadata::EMPTY; 8]);
|
||||
static TX_UDP_BUFS: static_cell::ConstStaticCell<[u8; MTU]> =
|
||||
static_cell::ConstStaticCell::new([0; MTU]);
|
||||
static RX_UDP_BUFS: static_cell::ConstStaticCell<[u8; MTU]> =
|
||||
static_cell::ConstStaticCell::new([0; MTU]);
|
||||
|
||||
let rx_udp_meta = RX_UDP_META.take();
|
||||
let rx_udp_bufs = RX_UDP_BUFS.take();
|
||||
let tx_udp_meta = TX_UDP_META.take();
|
||||
let tx_udp_bufs = TX_UDP_BUFS.take();
|
||||
|
||||
let mut rx_buffer = [0; MTU];
|
||||
|
||||
loop {
|
||||
cx.local.net_stack.wait_link_up().await;
|
||||
cx.local.link_led.set_high();
|
||||
defmt::info!("Network link is up");
|
||||
|
||||
// Ensure DHCP configuration is up before trying connect
|
||||
cx.local.net_stack.wait_config_up().await;
|
||||
|
||||
let config = cx.local.net_stack.config_v4();
|
||||
defmt::info!("Network task initialized, config: {}", config);
|
||||
|
||||
let mut udp = UdpSocket::new(
|
||||
cx.local.net_stack.clone(),
|
||||
rx_udp_meta,
|
||||
rx_udp_bufs,
|
||||
tx_udp_meta,
|
||||
tx_udp_bufs,
|
||||
);
|
||||
defmt::info!("UDP socket bound to port {}", PORT);
|
||||
udp.bind(PORT).expect("failed to bind UDP socket");
|
||||
let mut remote_endpoint = None;
|
||||
loop {
|
||||
if !cx.local.net_stack.is_link_up() {
|
||||
defmt::warn!("Network link is down");
|
||||
cx.local.link_led.set_low();
|
||||
break;
|
||||
}
|
||||
match udp
|
||||
.recv_from(&mut rx_buffer)
|
||||
.with_timeout(Duration::from_millis(200))
|
||||
.await
|
||||
{
|
||||
Ok(result) => match result {
|
||||
Ok((data, meta)) => {
|
||||
remote_endpoint = Some(meta.endpoint);
|
||||
defmt::debug!("UDP RX {}, Meta: {}", data, meta);
|
||||
cx.local.tc_tx.send(rx_buffer[0..data].to_vec()).await;
|
||||
}
|
||||
Err(e) => {
|
||||
defmt::warn!("udp receive error: {}", e);
|
||||
Timer::after_millis(100).await;
|
||||
}
|
||||
},
|
||||
Err(_e) => (),
|
||||
}
|
||||
if let Some(endpoint) = remote_endpoint {
|
||||
while let Ok(packet) = cx.local.tm_rx.try_receive() {
|
||||
match udp.send_to(&packet, endpoint).await {
|
||||
Ok(_) => {
|
||||
defmt::debug!("UDP TX: {} bytes to: {}", packet.len(), endpoint)
|
||||
}
|
||||
Err(e) => defmt::warn!("udp send error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[task(local = [tc_rx, tm_tx], shared=[sequence_count, blink_freq])]
|
||||
async fn tc_handler(mut cx: tc_handler::Context) {
|
||||
loop {
|
||||
let tc = cx.local.tc_rx.receive().await;
|
||||
|
||||
match CcsdsPacketReader::new_with_checksum(&tc) {
|
||||
Ok(packet) => {
|
||||
let packet_id = packet.packet_id();
|
||||
let psc = packet.psc();
|
||||
let tc_packet_id = CcsdsPacketIdAndPsc { packet_id, psc };
|
||||
if let Ok(request) =
|
||||
postcard::from_bytes::<stm32h7::Request>(packet.packet_data())
|
||||
{
|
||||
let response = match request {
|
||||
stm32h7::Request::Ping => {
|
||||
defmt::info!("Received Ping request");
|
||||
stm32h7::Response::Ok
|
||||
}
|
||||
stm32h7::Request::ChangeBlinkFrequency(duration) => {
|
||||
defmt::info!(
|
||||
"Received blinky frequency change request: {} ms",
|
||||
duration.as_millis()
|
||||
);
|
||||
cx.shared.blink_freq.lock(|current| {
|
||||
*current = Duration::from_millis(duration.as_millis() as u64)
|
||||
});
|
||||
stm32h7::Response::Ok
|
||||
}
|
||||
};
|
||||
let sequence_count = cx.shared.sequence_count.lock(|v| {
|
||||
let current = *v;
|
||||
*v = v.wrapping_add(u14::new(1));
|
||||
current
|
||||
});
|
||||
|
||||
// Send Pong/OK response immediately.
|
||||
if let Err(e) =
|
||||
send_tm(tc_packet_id, response, sequence_count, cx.local.tm_tx).await
|
||||
{
|
||||
defmt::warn!("Failed to send TM response: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => defmt::warn!("Failed to parse received TC packet: {}", e,),
|
||||
}
|
||||
defmt::info!("Received from UDP client: {}", tc.as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_tm(
|
||||
tc_packet_id: CcsdsPacketIdAndPsc,
|
||||
response: stm32h7::Response,
|
||||
current_seq_count: u14,
|
||||
sender: &embassy_sync::channel::Sender<
|
||||
'static,
|
||||
NoopRawMutex,
|
||||
alloc::vec::Vec<u8>,
|
||||
TM_QUEUE_DEPTH,
|
||||
>,
|
||||
) -> Result<(), CcsdsPacketCreationError> {
|
||||
let sp_header = SpHeader::new_for_unseg_tc(stm32h7::PUS_APID, current_seq_count, 0);
|
||||
let tm_header = TmHeader {
|
||||
tc_packet_id: Some(tc_packet_id),
|
||||
uptime_millis: embassy_time::Instant::now().as_millis(),
|
||||
};
|
||||
let tm_size = tm_size(&tm_header, &response);
|
||||
let mut packet = alloc::vec![0; tm_size];
|
||||
create_tm_packet(&mut packet, sp_header, tm_header, response)?;
|
||||
sender.send(packet).await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use satrs_stm32h7_nucleo_rtic as _; // memory layout + panic handler
|
||||
|
||||
// See https://crates.io/crates/defmt-test/0.3.0 for more documentation (e.g. about the 'state'
|
||||
// feature)
|
||||
#[defmt_test::tests]
|
||||
mod tests {
|
||||
use defmt::assert;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert!(true)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "embedded-types"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1", default-features = false }
|
||||
defmt = { version = "1", optional = true }
|
||||
spacepackets = { version = "0.18", default-features = false, features = ["defmt", "serde"] }
|
||||
postcard = { version = "1", features = ["defmt"] }
|
||||
arbitrary-int = "2"
|
||||
@@ -0,0 +1,84 @@
|
||||
#![no_std]
|
||||
|
||||
use spacepackets::{
|
||||
CcsdsPacketCreationError, CcsdsPacketCreatorWithReservedData, CcsdsPacketIdAndPsc,
|
||||
SpacePacketHeader, ccsds_packet_len_for_user_data_len_with_checksum,
|
||||
};
|
||||
|
||||
pub mod stm32f3 {
|
||||
use arbitrary_int::u11;
|
||||
use core::time::Duration;
|
||||
|
||||
pub const PUS_APID: u11 = u11::new(0x02);
|
||||
|
||||
#[derive(Copy, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Request {
|
||||
Ping,
|
||||
ChangeBlinkFrequency(Duration),
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Response {
|
||||
Ok,
|
||||
}
|
||||
}
|
||||
|
||||
/// This might look like a duplication, but we intentionally keep those separate so they can
|
||||
/// change independently.
|
||||
pub mod stm32h7 {
|
||||
use arbitrary_int::u11;
|
||||
use core::time::Duration;
|
||||
|
||||
pub const PUS_APID: u11 = u11::new(0x03);
|
||||
|
||||
#[derive(Copy, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Request {
|
||||
Ping,
|
||||
ChangeBlinkFrequency(Duration),
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Response {
|
||||
Ok,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct TmHeader {
|
||||
pub tc_packet_id: Option<CcsdsPacketIdAndPsc>,
|
||||
pub uptime_millis: u64,
|
||||
}
|
||||
|
||||
pub fn tm_size<Response: serde::Serialize>(tm_header: &TmHeader, response: &Response) -> usize {
|
||||
ccsds_packet_len_for_user_data_len_with_checksum(
|
||||
postcard::experimental::serialized_size(tm_header).unwrap()
|
||||
+ postcard::experimental::serialized_size(response).unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn create_tm_packet<Response: serde::Serialize>(
|
||||
buf: &mut [u8],
|
||||
sp_header: SpacePacketHeader,
|
||||
tm_header: TmHeader,
|
||||
response: Response,
|
||||
) -> Result<usize, CcsdsPacketCreationError> {
|
||||
let packet_data_size = postcard::experimental::serialized_size(&tm_header).unwrap()
|
||||
+ postcard::experimental::serialized_size(&response).unwrap();
|
||||
let mut creator =
|
||||
CcsdsPacketCreatorWithReservedData::new_tm_with_checksum(sp_header, packet_data_size, buf)?;
|
||||
|
||||
let current_index = postcard::to_slice(&tm_header, creator.packet_data_mut())
|
||||
.unwrap()
|
||||
.len();
|
||||
postcard::to_slice(&response, &mut creator.packet_data_mut()[current_index..]).unwrap();
|
||||
Ok(creator.finish())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {}
|
||||
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "satrs-gen"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
toml = "0.8"
|
||||
heck = "0.5"
|
||||
@@ -0,0 +1,34 @@
|
||||
[apid]
|
||||
Sched = 1
|
||||
GenericPus = 2
|
||||
Acs = 3
|
||||
Cfdp = 4
|
||||
Tmtc = 5
|
||||
Eps = 6
|
||||
|
||||
|
||||
[ids]
|
||||
[ids.Eps]
|
||||
Pcdu = 0
|
||||
Subsystem = 1
|
||||
|
||||
[ids.Tmtc]
|
||||
UdpServer = 0
|
||||
TcpServer = 1
|
||||
|
||||
[ids.GenericPus]
|
||||
PusEventManagement = 0
|
||||
PusRouting = 1
|
||||
PusTest = 2
|
||||
PusAction = 3
|
||||
PusMode = 4
|
||||
PusHk = 5
|
||||
|
||||
[ids.Sched]
|
||||
PusSched = 0
|
||||
|
||||
[ids.Acs]
|
||||
Subsystem = 1
|
||||
Assembly = 2
|
||||
Mgm0 = 3
|
||||
Mgm1 = 4
|
||||
@@ -0,0 +1,91 @@
|
||||
use heck::{ToShoutySnakeCase, ToSnakeCase};
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
fs::{self, File},
|
||||
io::{self, Write},
|
||||
};
|
||||
|
||||
use toml::{Value, map::Map};
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
// Read the configuration file
|
||||
let config_str = fs::read_to_string("components.toml").expect("Unable to read file");
|
||||
let config: Value = toml::from_str(&config_str).expect("Unable to parse TOML");
|
||||
|
||||
let mut output = File::create("../satrs-example/src/ids.rs")?;
|
||||
|
||||
generate_rust_code(&config, &mut output);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sort_enum_table(table_map: &Map<String, Value>) -> BTreeMap<u64, &str> {
|
||||
// Collect entries into a BTreeMap to sort them by key
|
||||
let mut sorted_entries: BTreeMap<u64, &str> = BTreeMap::new();
|
||||
|
||||
for (key, value) in table_map {
|
||||
if let Some(value) = value.as_integer() {
|
||||
if !(0..=0x7FF).contains(&value) {
|
||||
panic!("Invalid APID value: {}", value);
|
||||
}
|
||||
sorted_entries.insert(value as u64, key);
|
||||
}
|
||||
}
|
||||
sorted_entries
|
||||
}
|
||||
|
||||
fn generate_rust_code(config: &Value, writer: &mut impl Write) {
|
||||
writeln!(
|
||||
writer,
|
||||
"//! This is an auto-generated configuration module."
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(writer, "use satrs::request::UniqueApidTargetId;").unwrap();
|
||||
writeln!(writer).unwrap();
|
||||
|
||||
// Generate the main module
|
||||
writeln!(
|
||||
writer,
|
||||
"#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::EnumIter)]"
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(writer, "pub enum Apid {{").unwrap();
|
||||
|
||||
// Generate constants for the main module
|
||||
if let Some(apid_table) = config.get("apid").and_then(Value::as_table) {
|
||||
let sorted_entries = sort_enum_table(apid_table);
|
||||
// Write the sorted entries to the writer
|
||||
for (value, key) in sorted_entries {
|
||||
writeln!(writer, " {} = {},", key, value).unwrap();
|
||||
}
|
||||
}
|
||||
writeln!(writer, "}}").unwrap();
|
||||
|
||||
// Generate ID tables.
|
||||
if let Some(id_tables) = config.get("ids").and_then(Value::as_table) {
|
||||
for (mod_name, table) in id_tables {
|
||||
let mod_name_as_snake = mod_name.to_snake_case();
|
||||
writeln!(writer).unwrap();
|
||||
writeln!(writer, "pub mod {} {{", mod_name_as_snake).unwrap();
|
||||
let sorted_entries = sort_enum_table(table.as_table().unwrap());
|
||||
writeln!(writer, " #[derive(Debug, Copy, Clone, PartialEq, Eq)]").unwrap();
|
||||
writeln!(writer, " pub enum Id {{").unwrap();
|
||||
// Write the sorted entries to the writer
|
||||
for (value, key) in &sorted_entries {
|
||||
writeln!(writer, " {} = {},", key, value).unwrap();
|
||||
}
|
||||
writeln!(writer, " }}").unwrap();
|
||||
writeln!(writer).unwrap();
|
||||
|
||||
for (_value, key) in sorted_entries {
|
||||
let key_shouting = key.to_shouty_snake_case();
|
||||
writeln!(
|
||||
writer,
|
||||
" pub const {}: super::UniqueApidTargetId = super::UniqueApidTargetId::new(super::Apid::{} as u16, Id::{} as u32);",
|
||||
key_shouting, mod_name, key
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
writeln!(writer, "}}").unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
|
||||
<!--Created by yEd 3.25.1-->
|
||||
<key attr.name="Description" attr.type="string" for="graph" id="d0"/>
|
||||
<key for="port" id="d1" yfiles.type="portgraphics"/>
|
||||
<key for="port" id="d2" yfiles.type="portgeometry"/>
|
||||
<key for="port" id="d3" yfiles.type="portuserdata"/>
|
||||
<key attr.name="url" attr.type="string" for="node" id="d4"/>
|
||||
<key attr.name="description" attr.type="string" for="node" id="d5"/>
|
||||
<key for="node" id="d6" yfiles.type="nodegraphics"/>
|
||||
<key for="graphml" id="d7" yfiles.type="resources"/>
|
||||
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
|
||||
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
|
||||
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
|
||||
<graph edgedefault="directed" id="G">
|
||||
<data key="d0" xml:space="preserve"/>
|
||||
<node id="n0">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="360.0" width="479.0" x="771.3047672479152" y="458.0"/>
|
||||
<y:Fill hasColor="false" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="4.0" x="237.5" y="178.0">
|
||||
<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n1">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="177.64799999999997" width="200.75199999999973" x="1037.5527672479152" y="470.15200000000027"/>
|
||||
<y:Fill hasColor="false" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="64.25241088867188" x="13.264464667588754" xml:space="preserve" y="8.302185845943427">Simulation<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="-0.5" labelRatioY="-0.5" nodeRatioX="-0.433926114471642" nodeRatioY="-0.45326608886143704" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n2">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="34.0" width="84.39999999999986" x="1068.8351781652768" y="508.2800000000002"/>
|
||||
<y:Fill color="#FFCC00" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="36.37623596191406" x="24.011882019042787" xml:space="preserve" y="6.827942848205566">PCDU<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n3">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="34.0" width="120.39999999999986" x="1068.8351781652768" y="550.4800000000001"/>
|
||||
<y:Fill color="#FFCC00" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="94.56465148925781" x="12.917674255370912" xml:space="preserve" y="6.827942848205566">Magnetometers<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n4">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="34.0" width="120.39999999999986" x="1068.8351781652768" y="594.9000000000001"/>
|
||||
<y:Fill color="#FFCC00" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="86.24858093261719" x="17.075709533691224" xml:space="preserve" y="6.827942848205566">Magnetorquer<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n5">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="34.0" width="120.39999999999986" x="783.4063563305535" y="545.2800000000002"/>
|
||||
<y:Fill color="#FFCC00" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="81.62857055664062" x="19.38571472167962" xml:space="preserve" y="6.827942848205566">SimController<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n6">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="34.0" width="120.39999999999986" x="840.5407126611072" y="677.8000000000002"/>
|
||||
<y:Fill color="#FFCC00" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="96.96467590332031" x="11.717662048339776" xml:space="preserve" y="6.827942848205566">UDP TC Receiver<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n7">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="34.0" width="120.39999999999986" x="1005.2814253222144" y="677.8000000000002"/>
|
||||
<y:Fill color="#FFCC00" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="92.46463012695312" x="13.96768493652337" xml:space="preserve" y="6.827942848205566">UDP TM Sender<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n8">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="34.0" width="120.39999999999986" x="931.6174253222144" y="775.5920000000002"/>
|
||||
<y:Fill color="#FFCC00" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="36.292236328125" x="42.05388183593743" xml:space="preserve" y="6.827942848205566">Client<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n9">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="34.0" width="120.39999999999986" x="1074.8237583924094" y="555.3663917525774"/>
|
||||
<y:Fill color="#FFCC00" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="94.56465148925781" x="12.917674255370912" xml:space="preserve" y="6.827942848205566">Magnetometers<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<edge id="e0" source="n5" target="n3">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="-5.199999999999932"/>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e1" source="n5" target="n2">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="60.19999999999993" sy="0.0" tx="0.0" ty="0.0">
|
||||
<y:Point x="1023.8695890826383" y="562.2800000000002"/>
|
||||
<y:Point x="1023.8695890826383" y="525.2800000000002"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e2" source="n5" target="n4">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="48.72964366944643" sy="0.0" tx="0.0" ty="0.0">
|
||||
<y:Point x="1023.8695890826383" y="562.2800000000002"/>
|
||||
<y:Point x="1023.8695890826383" y="611.9000000000001"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="91.06060791015625" x="13.086737058292329" xml:space="preserve" y="-23.692086448669215">schedule_event<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="13.519999999999978" distanceToCenter="true" position="left" ratio="0.11621274698385183" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e3" source="n6" target="n5">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="-5.329643669446341" ty="0.0">
|
||||
<y:Point x="900.7407126611072" y="628.5400000000002"/>
|
||||
<y:Point x="838.2767126611071" y="628.5400000000002"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="70.78047180175781" x="-85.32624589602165" xml:space="preserve" y="-42.388073520660214">SimRequest<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="49.935999999999936" distanceToCenter="true" position="left" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e4" source="n4" target="n7">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="60.200000000000045" sy="0.0" tx="0.0" ty="0.0">
|
||||
<y:Point x="1223.8814253222142" y="611.9000000000001"/>
|
||||
<y:Point x="1223.8814253222142" y="694.8000000000002"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e5" source="n9" target="n7">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="57.449660948066594" sy="-4.88639175257731" tx="0.0" ty="0.0">
|
||||
<y:Point x="1223.8814253222142" y="567.4800000000001"/>
|
||||
<y:Point x="1223.8814253222142" y="694.8000000000002"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e6" source="n2" target="n7">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="11.514125426161627" sy="-2.5781798912005343" tx="45.553752843062284" ty="0.0">
|
||||
<y:Point x="1223.8814253222142" y="522.7018201087997"/>
|
||||
<y:Point x="1223.8814253222142" y="694.8000000000002"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="55.73236083984375" x="-1.658628279667937" xml:space="preserve" y="143.94791969528637">SimReply<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="17.97817989120062" distanceToCenter="true" position="right" ratio="0.679561684469248" segment="-1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e7" source="n8" target="n6">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-25.212712661107275" sy="0.0" tx="-11.264000000000124" ty="0.0">
|
||||
<y:Point x="966.6047126611071" y="731.8000000000002"/>
|
||||
<y:Point x="889.4767126611071" y="731.8000000000002"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="112.32476806640625" x="-128.562407700221" xml:space="preserve" y="-33.22355764007534">SimRequest in UDP<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="20.73181250000017" distanceToCenter="true" position="left" ratio="0.9386993050513424" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e8" source="n7" target="n8">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="29.18399999999997" sy="0.0" tx="24.28800000000001" ty="0.0">
|
||||
<y:Point x="1094.6654253222143" y="731.8000000000002"/>
|
||||
<y:Point x="1016.1054253222144" y="731.8000000000002"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="97.27665710449219" x="-58.67030850346919" xml:space="preserve" y="33.62158786773705">SimReply in UDP<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="23.81218750000005" distanceToCenter="true" position="left" ratio="0.12769857433808468" segment="1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e9" source="n5" target="n1">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="23.921741802203996" sy="-3.0501798912007416" tx="0.0" ty="-56.27417989120056">
|
||||
<y:Point x="867.5280981327575" y="502.70182010879967"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.344114303588867" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="28.228179931640625" x="74.7630257963599" xml:space="preserve" y="-63.88744016799478">step<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="11.126187499999986" distanceToCenter="true" position="left" ratio="0.5889387894625147" segment="-1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
</graph>
|
||||
<data key="d7">
|
||||
<y:Resources/>
|
||||
</data>
|
||||
</graphml>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 98 KiB |
@@ -166,7 +166,7 @@ Subsystem<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:
|
||||
<y:Geometry height="30.0" width="125.0" x="1151.9280499999995" y="281.84403125000006"/>
|
||||
<y:Fill color="#CCFFFF" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.296875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="76.255859375" x="24.3720703125" xml:space="preserve" y="4.8515625">TM Funnel<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.296875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="58.837890625" x="33.0810546875" xml:space="preserve" y="4.8515625">TM Sink<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
@@ -260,7 +260,7 @@ Mode Tree<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:
|
||||
<y:Geometry height="57.265600000000006" width="631.1152" x="810.8847999999999" y="411.39428125"/>
|
||||
<y:Fill hasColor="false" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="41.25" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="261.8125" x="166.89412267941418" xml:space="preserve" y="3.144146301369915">satrs-satellite
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="41.25" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="261.8125" x="166.89412267941418" xml:space="preserve" y="3.144146301369915">satrs-minisim
|
||||
Simulator based on asynchronix<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="-0.028136269449041573" nodeRatioY="-0.08493150684931505" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
</y:ShapeNode>
|
||||
@@ -272,7 +272,7 @@ Simulator based on asynchronix<y:LabelModel><y:SmartNodeLabelModel distance="4.0
|
||||
<y:Geometry height="50.0" width="631.1152000000002" x="810.8847999999998" y="476.2958625000002"/>
|
||||
<y:Fill hasColor="false" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="41.25" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="374.8359375" x="110.3824039294143" xml:space="preserve" y="0.12842465753431043">satrs-tmtc
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="41.25" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="374.8359375" x="110.3824039294143" xml:space="preserve" y="0.12842465753431043">pytmtc
|
||||
Command-line interface based TMTC handling<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="-0.028136269449041573" nodeRatioY="-0.08493150684931505" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
</y:ShapeNode>
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,46 @@
|
||||
all: check build embedded test check-fmt clippy docs
|
||||
|
||||
check:
|
||||
cargo check
|
||||
cargo check -p satrs-example --no-default-features
|
||||
|
||||
build:
|
||||
cargo build
|
||||
|
||||
test:
|
||||
cargo nextest run --all-features
|
||||
cargo test --doc --all-features
|
||||
|
||||
embedded: embedded-stm32h7 embedded-stm32f3
|
||||
cargo check -p satrs --target=thumbv7em-none-eabihf --no-default-features
|
||||
|
||||
[working-directory:"embedded-examples/stm32h7-nucleo-rtic"]
|
||||
embedded-stm32h7:
|
||||
cargo build --target=thumbv7em-none-eabihf --release
|
||||
|
||||
[working-directory:"embedded-examples/stm32f3-disco-rtic"]
|
||||
embedded-stm32f3:
|
||||
cargo build --target=thumbv7em-none-eabihf --release
|
||||
|
||||
check-fmt:
|
||||
cargo fmt --all -- --check
|
||||
|
||||
fmt:
|
||||
cargo fmt --all
|
||||
|
||||
clippy:
|
||||
cargo clippy -- -D warnings
|
||||
|
||||
docs-satrs:
|
||||
RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" cargo +nightly doc -p satrs --all-features
|
||||
|
||||
docs: docs-satrs
|
||||
|
||||
[working-directory:"satrs-book"]
|
||||
book *args:
|
||||
mdbook build {{args}}
|
||||
|
||||
# Pass --dry-run to preview the changes first.
|
||||
[working-directory:"satrs-book"]
|
||||
deploy-book *args: book
|
||||
rsync -avz --delete {{args}} book/html/ numalfix@documentation.irs.uni-stuttgart.de:/home/numalfix/www/projects/sat-rs/book/
|
||||
@@ -1,7 +1,7 @@
|
||||
sat-rs book
|
||||
=========
|
||||
|
||||
High-level documentation of the [sat-rs project](https://absatsw.irs.uni-stuttgart.de/projects/sat-rs/).
|
||||
High-level documentation of the [sat-rs project](https://documentation.irs.uni-stuttgart.de/projects/sat-rs/).
|
||||
|
||||
## Building
|
||||
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
[book]
|
||||
authors = ["Robin Mueller"]
|
||||
language = "en"
|
||||
multilingual = false
|
||||
src = "src"
|
||||
title = "The sat-rs book"
|
||||
|
||||
[output.html]
|
||||
additional-js = ["mermaid.min.js", "mermaid-init.js"]
|
||||
|
||||
[output.linkcheck]
|
||||
command = "mdbook-linkcheck2"
|
||||
|
||||
[preprocessor]
|
||||
|
||||
[preprocessor.mermaid]
|
||||
command = "mdbook-mermaid"
|
||||
@@ -0,0 +1,39 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
(() => {
|
||||
const darkThemes = ['ayu', 'navy', 'coal'];
|
||||
const lightThemes = ['light', 'rust'];
|
||||
|
||||
const classList = document.getElementsByTagName('html')[0].classList;
|
||||
|
||||
let lastThemeWasLight = true;
|
||||
for (const cssClass of classList) {
|
||||
if (darkThemes.includes(cssClass)) {
|
||||
lastThemeWasLight = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const theme = lastThemeWasLight ? 'default' : 'dark';
|
||||
mermaid.initialize({ startOnLoad: true, theme });
|
||||
|
||||
// Simplest way to make mermaid re-render the diagrams in the new theme is via refreshing the page
|
||||
|
||||
for (const darkTheme of darkThemes) {
|
||||
document.getElementById('mdbook-theme-' + darkTheme).addEventListener('click', () => {
|
||||
if (lastThemeWasLight) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (const lightTheme of lightThemes) {
|
||||
document.getElementById('mdbook-theme-' + lightTheme).addEventListener('click', () => {
|
||||
if (!lastThemeWasLight) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
Vendored
+2609
File diff suppressed because it is too large.
Load diff
@@ -1,17 +1,22 @@
|
||||
# Summary
|
||||
|
||||
- [Introduction](./introduction.md)
|
||||
- [Design](./design.md)
|
||||
|
||||
# Basic concepts and components
|
||||
|
||||
- [Communication with Space Systems](./communication.md)
|
||||
- [TMTC modelling](./tmtc-modelling.md)
|
||||
- [Working with Constrained Systems](./constrained-systems.md)
|
||||
- [Actions](./actions.md)
|
||||
- [Modes and Health](./modes-and-health.md)
|
||||
- [Housekeeping Data](./housekeeping.md)
|
||||
- [Events](./events.md)
|
||||
|
||||
# Architecture
|
||||
|
||||
- [System View](./system-view.md)
|
||||
- [Design](./design.md)
|
||||
|
||||
# Example project
|
||||
|
||||
- [The satrs-example application](./example.md)
|
||||
@@ -7,3 +7,7 @@
|
||||
- [Modelling space systems](./modelling-space-systems.md)
|
||||
- [Ground Segments](./ground-segments.md)
|
||||
|
||||
Refer to new sections in the system view page:
|
||||
|
||||
- [Fault Detection, Isolation and Recovery (FDIR)](./fdir.md)
|
||||
- and the [mode tree](./mode-tree.md)
|
||||
@@ -3,40 +3,9 @@
|
||||
Space systems generally need to be commanded regularly. This can include commands periodically
|
||||
required to ensure a healthy system, or commands to reach the mission goals.
|
||||
|
||||
These commands can be modelled using the concept of Actions. the ECSS PUS standard also provides
|
||||
the PUS service 8 for actions, but provides few concrete subservices and specification on how
|
||||
action commanding could look like.
|
||||
|
||||
`sat-rs` proposes two recommended ways to perform action commanding:
|
||||
|
||||
1. Target ID and Action ID based. The target ID is a 32-bit unsigned ID for an OBSW object entity
|
||||
which can also accept Actions. The action ID is a 32-bit unsigned ID for each action that a
|
||||
target is able to perform.
|
||||
2. Target ID and Action String based. The target ID is the same as in the first proposal, but
|
||||
the unique action is identified by a string.
|
||||
|
||||
The library provides an `ActionRequest` abstraction to model both of these cases.
|
||||
|
||||
## Commanding with ECSS PUS 8
|
||||
|
||||
`sat-rs` provides a generic ECSS PUS 8 action command handler. This handler can convert PUS 8
|
||||
telecommands which use the commanding scheme 1 explained above to an `ActionRequest` which is
|
||||
then forwarded to the target specified by the Target ID.
|
||||
|
||||
There are 3 requirements for the PUS 8 telecommand:
|
||||
|
||||
1. The subservice 128 must be used
|
||||
2. Bytes 0 to 4 of application data must contain the target ID in `u32` big endian format.
|
||||
3. Bytes 4 to 8 of application data must contain the action ID in `u32` big endian format.
|
||||
4. The rest of the application data are assumed to be command specific additional parameters. They
|
||||
will be added to an IPC store and the corresponding store address will be sent as part of the
|
||||
`ActionRequest`.
|
||||
|
||||
## Sending back telemetry
|
||||
|
||||
There are some cases where the regular verification provided by PUS in response to PUS action
|
||||
commands is not sufficient and some additional telemetry needs to be sent to ground. In that
|
||||
case, it is recommended to chose some custom subservice for action TM data and then send the
|
||||
telemetry using the same scheme as shown above, where the first 8 bytes of the application
|
||||
data is reserved for the target ID and action ID.
|
||||
These commands can be modelled using the concept of Actions. If you have not read the
|
||||
[TMTC modelling](./tmtc-modelling.md) chapter yet, it is recommended to read it first.
|
||||
|
||||
For a low number of actions, it is recommended to add the actions as `enum` variants of your
|
||||
`Request` type. For a higher number of actions, you can create a dedicated `ActionRequest`
|
||||
structure.
|
||||
@@ -2,25 +2,20 @@
|
||||
|
||||
# Communication with sat-rs based software
|
||||
|
||||
Communication is a vital topic for remote system which are usually not (directly)
|
||||
Communication is a vital topic for remote systems which are usually not (directly)
|
||||
connected to the internet and only have 1-2 communication links during nominal operation. However,
|
||||
most of these systems have internet access during development cycle. There are various standards
|
||||
provided by CCSDS and ECSS which can be useful to determine how to communicate with the satellite
|
||||
most of these systems have internet access during the development cycle. There are various standards
|
||||
provided by CCSDS which can be useful to determine how to communicate with the satellite
|
||||
and the primary On-Board Software.
|
||||
|
||||
# Application layer
|
||||
|
||||
Most communication with space systems is usually packet based. For example, the CCSDS space
|
||||
packet standard only specifies a 6 byte header with at least 1 byte payload. The PUS packet
|
||||
standard is a subset of the space packet standard, which adds some fields and a 16 bit CRC, but
|
||||
it is still centered around small packets. `sat-rs` provides support for these ECSS and CCSDS
|
||||
standards and also attempts to fill the gap to the internet protocol by providing the following
|
||||
components.
|
||||
packet standard only specifies a 6 byte header with at least 1 byte payload. The `sat-rs` library
|
||||
provides some support for the [CCSDS space packet protocol](https://ccsds.org/Pubs/133x0b2e2.pdf).
|
||||
|
||||
1. [UDP TMTC Server](https://docs.rs/satrs/latest/satrs/hal/std/udp_server/index.html).
|
||||
UDP is already packet based which makes it an excellent fit for exchanging space packets.
|
||||
2. [TCP TMTC Server Components](https://docs.rs/satrs/latest/satrs/hal/std/tcp_server/index.html).
|
||||
TCP is a stream based protocol, so the library provides building blocks to parse telemetry
|
||||
TCP is a stream based protocol, so the library provides building blocks to parse telecommands
|
||||
from an arbitrary bytestream. Two concrete implementations are provided:
|
||||
- [TCP spacepackets server](https://docs.rs/satrs/latest/satrs/hal/std/tcp_server/struct.TcpSpacepacketsServer.html)
|
||||
to parse tightly packed CCSDS Spacepackets.
|
||||
@@ -31,28 +26,70 @@ components.
|
||||
# Working with telemetry and telecommands (TMTC)
|
||||
|
||||
The commands sent to a space system are commonly called telecommands (TC) while the data received
|
||||
from it are called telemetry (TM). Keeping in mind the previous section, the concept of a TC source
|
||||
and a TM sink can be applied to most satellites. The TM sink is the one entity where all generated
|
||||
telemetry arrives in real-time. The most important task of the TM sink usually is to send all
|
||||
arriving telemetry to the ground segment of a satellite mission immediately. Another important
|
||||
task might be to store all arriving telemetry persistently. This is especially important for
|
||||
space systems which do not have permanent contact like low-earth-orbit (LEO) satellites.
|
||||
from it are called telemetry (TM). One way to model the packet handling, which can be applied to most
|
||||
satellites, is to introduce the concept of a TC source and a TM sink. The TM sink is the one entity where
|
||||
all generated telemetry arrives in real-time. The most important task of the TM sink usually is to
|
||||
send all arriving telemetry to the ground segment of a satellite mission immediately.
|
||||
|
||||
Another important task might be to store all arriving telemetry persistently. This is especially
|
||||
important for space systems which do not have permanent contact like low-earth-orbit (LEO)
|
||||
satellites.
|
||||
|
||||
The diagram below shows one concrete example of what this could look like.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Dev[Device Handlers] --> Sink[TM Sink]
|
||||
Sub[Subsystem Handlers] --> Sink
|
||||
Sink --> Ground[Ground Link]
|
||||
Sink --> Store[Persistent Storage]
|
||||
Sink --> Udp[UDP Server]
|
||||
Sink --> Tcp[TCP Server]
|
||||
```
|
||||
|
||||
The most important task of a TC source is to deliver the telecommands to the correct recipients.
|
||||
For component oriented software using message passing, this usually includes staged demultiplexing
|
||||
components to determine where a command needs to be sent.
|
||||
For component oriented software using message passing, this usually includes demultiplexing
|
||||
to determine where a command needs to be sent.
|
||||
|
||||
The diagram below shows one concrete example of what this could look like.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Udp[UDP Server] --> Source[TC Source]
|
||||
Tcp[TCP Server] --> Source
|
||||
Radio[Radio Handler] --> Source
|
||||
Source --> Dev[Device Handlers]
|
||||
Source --> Sub[Subsystem Handlers]
|
||||
Source --> File[File Service Handler]
|
||||
```
|
||||
|
||||
Using a generic concept of a TC source and a TM sink as part of the software design simplifies
|
||||
the flexibility of the TMTC infrastructure: Newly added TM generators and TC receiver only have to
|
||||
the flexibility of the TMTC infrastructure: Newly added TM generators and TC receivers only have to
|
||||
forward their generated or received packets to those handler objects.
|
||||
|
||||
# Low-level protocols and the bridge to the communcation subsystem
|
||||
# Packet format
|
||||
|
||||
We talked about some basic support for the CCSDS space packet protocol. This is a really simple
|
||||
protocol which just specifies a header that every exchanged TMTC packet has:
|
||||
|
||||

|
||||
|
||||
This is a protocol which already provides us with some useful fields:
|
||||
|
||||
- ID field provided by the Application Process Identifier (APID). This can also be useful for packet
|
||||
multiplexing
|
||||
- Basic sequence counter which can be used to determine missed packets
|
||||
|
||||
However, what does the actual payload that we want to send to or from the satellite actually look
|
||||
like? We recommend a payload format which is created with the excellent [`serde`](https://serde.rs/)
|
||||
library. The [TMTC modelling](./tmtc-modelling.md) chapter provides more information.
|
||||
|
||||
# Low-level protocols and the bridge to the communication subsystem
|
||||
|
||||
Many satellite systems usually use the lower levels of the OSI layer in addition to the application
|
||||
layer covered by the PUS standard or the CCSDS space packets standard. This oftentimes requires
|
||||
special hardware like dedicated FPGAs to handle forward error correction fast enough. `sat-rs`
|
||||
might provide components to handle standard like the Unified Space Data Link Standard (USLP) in
|
||||
layer. This oftentimes requires special hardware like dedicated FPGAs to handle forward error
|
||||
correction fast enough. `sat-rs`
|
||||
might provide components to handle standards like the Unified Space Data Link Protocol (USLP) in
|
||||
software but most of the time the handling of communication is performed through custom
|
||||
software and hardware. Still, connecting this custom software and hardware to `sat-rs` can mostly
|
||||
be done by using the concept of TC sources and TM sinks mentioned previously.
|
||||
|
||||
@@ -3,20 +3,26 @@
|
||||
Software for space systems oftentimes has different requirements than the software for host
|
||||
systems or servers. Currently, most space systems are considered embedded systems.
|
||||
|
||||
For these systems, the computation power and the available heap are the most important resources
|
||||
which are constrained. This might make completeley heap based memory management schemes which
|
||||
are oftentimes used on host and server based systems unfeasable. Still, completely forbidding
|
||||
heap allocations might make software development unnecessarilly difficult, especially in a
|
||||
For these systems, the computation power and the available memory are important resources
|
||||
which are also constrained. This might make completely heap based memory management schemes which
|
||||
are oftentimes used on host and server based systems infeasible. Still, completely forbidding
|
||||
heap allocations might make software development unnecessarily difficult, especially in a
|
||||
time where the OBSW might be running on Linux based systems with hundreds of MBs of RAM.
|
||||
|
||||
A useful pattern used commonly in space systems is to limit heap allocations to program
|
||||
A useful pattern commonly used in space systems is to limit heap allocations to program
|
||||
initialization time and avoid frequent run-time allocations. This prevents issues like
|
||||
running out of memory (something even Rust can not protect from) or heap fragmentation on systems
|
||||
without a MMU.
|
||||
without an MMU.
|
||||
|
||||
# Using an embedded allocator
|
||||
|
||||
The [`embedded-alloc`](https://github.com/rust-embedded/embedded-alloc) library provides
|
||||
a global allocator based on statically sized memory blocks. It also exposes an API
|
||||
which allows run-time tracking of the memory usage.
|
||||
|
||||
# Using pre-allocated pool structures
|
||||
|
||||
A huge candidate for heap allocations is the TMTC and handling. TC, TMs and IPC data are all
|
||||
A candidate for heap allocations is the TMTC handling. TC, TMs and IPC data are all
|
||||
candidates where the data size might vary greatly. The regular solution for host systems
|
||||
might be to send around this data as a `Vec<u8>` until it is dropped. `sat-rs` provides
|
||||
another solution to avoid run-time allocations by offering pre-allocated static
|
||||
@@ -27,8 +33,8 @@ For example, a very small telecommand (TC) pool might look like this:
|
||||
|
||||
The core of the pool abstractions is the
|
||||
[PoolProvider trait](https://docs.rs/satrs/latest/satrs/pool/trait.PoolProvider.html).
|
||||
This trait specifies the general API a pool structure should have without making assumption
|
||||
of how the data is stored.
|
||||
This trait specifies the general API a pool structure should have without making assumptions
|
||||
about how the data is stored.
|
||||
|
||||
This trait is implemented by a static memory pool implementation.
|
||||
The code to generate this static pool would look like this:
|
||||
|
||||
+20
-16
@@ -2,38 +2,43 @@
|
||||
|
||||
Satellites and space systems in general are complex systems with a wide range of requirements for
|
||||
both the hardware and the software. Consequently, the general design of the library is centered
|
||||
around many light-weight components which try to impose as few restrictions as possible on how to
|
||||
solve certain problems. This is also the reason why sat-rs is explicitely called a library
|
||||
instead of a framework.
|
||||
around many light-weight components and a toolbox principle where you assemble everything
|
||||
you need instead of plugging something into a larger framework. This approach allows the largest
|
||||
amount of flexibility, including the operating system and platform choice. For example, `sat-rs`
|
||||
can be used both in `async` and regular synchronous platforms.
|
||||
|
||||
There are still a lot of common patterns and architectures across these systems where guidance
|
||||
of how to solve a problem and a common structure would still be extremely useful to avoid pitfalls
|
||||
which were already solved and to avoid boilerplate code. This library tries to provide this
|
||||
structure and guidance the following way:
|
||||
|
||||
1. Providing this book which explains the architecture and design patterns in respect to common
|
||||
1. Providing this book which explains the architecture and design patterns with respect to common
|
||||
issues and requirements of space systems.
|
||||
2. Providing an example application. Space systems still commonly have large monolithic
|
||||
primary On-Board Softwares, so the choice was made to provide one example software which
|
||||
primary On-Board Software, so the choice was made to provide one example software which
|
||||
contains the various features provided by sat-rs.
|
||||
3. Providing a good test suite. This includes both unittests and integration tests. The integration
|
||||
3. Providing a good test suite. This includes both unit tests and integration tests. The integration
|
||||
tests can also serve as smaller usage examples than the large `satrs-example` application.
|
||||
|
||||
This library has special support for standards used in the space industry. This especially
|
||||
includes standards provided by Consultative Committee for Space Data Systems (CCSDS) and European
|
||||
Cooperation for Space Standardization (ECSS). It does not enforce using any of those standards,
|
||||
but it is always recommended to use some sort of standard for interoperability.
|
||||
This library has special support for standards used in the space industry. The recommended
|
||||
standards are provided by the Consultative Committee for Space Data Systems (CCSDS):
|
||||
|
||||
- The CCSDS Space Packet Protocol as the basic packet format for telecommands and telemetry.
|
||||
- The CCSDS File Delivery Protocol (CFDP) for file transfers.
|
||||
|
||||
The library does not enforce using any of those standards, but it is always recommended to use
|
||||
some sort of standard for interoperability.
|
||||
|
||||
A lot of the modules and design considerations are based on the Flight Software Framework (FSFW).
|
||||
The FSFW has its own [documentation](https://documentation.irs.uni-stuttgart.de/fsfw/), which
|
||||
will be referred to when applicable. The FSFW was developed over a period of 10 years for the
|
||||
Flying Laptop Project by the University of Stuttgart with Airbus Defence and Space GmbH.
|
||||
It has flight heritage through the 2 mssions [FLP](https://www.irs.uni-stuttgart.de/en/research/satellitetechnology-and-instruments/smallsatelliteprogram/flying-laptop/)
|
||||
It has flight heritage through the 2 missions [FLP](https://www.irs.uni-stuttgart.de/en/research/satellitetechnology-and-instruments/smallsatelliteprogram/flying-laptop/)
|
||||
and [EIVE](https://www.irs.uni-stuttgart.de/en/research/satellitetechnology-and-instruments/smallsatelliteprogram/EIVE/).
|
||||
Therefore, a lot of the design concepts were ported more or less unchanged to the `sat-rs`
|
||||
library.
|
||||
FLP is a medium-size small satellite with a higher budget and longer development time than EIVE,
|
||||
which allowed to build a highly reliable system while EIVE is a smaller 6U+ cubesat which had a
|
||||
which allowed building a highly reliable system while EIVE is a smaller 6U+ cubesat which had a
|
||||
shorter development cycle and was built using cheaper COTS components. This library also tries
|
||||
to accumulate the knowledge of developing the OBSW and operating the satellite for both these
|
||||
different systems and provide a solution for a wider range of small satellite systems.
|
||||
@@ -43,16 +48,15 @@ engineering to provide a reliable and robust basis for space On-Board Software.
|
||||
of using the Rust programming language was made for the following reasons:
|
||||
|
||||
1. Rust has safety guarantees which are a perfect fit for space systems which generally have high
|
||||
robustness and reliablity guarantees.
|
||||
robustness and reliability guarantees.
|
||||
2. Rust is suitable for embedded systems. It can also be run on smaller embedded systems like the
|
||||
STM32 which have also become common in the space sector. All space systems are embedded systems,
|
||||
which makes using large languages like Python challenging even for OBCs with more performance.
|
||||
3. Rust has support for linking C APIs through its excellent FFI support. This is especially
|
||||
important because many vendor provided libaries are still C based.
|
||||
4. Modern tooling like a package managers and various development helper, which can further reduce
|
||||
important because many vendor provided libraries are still C based.
|
||||
4. Modern tooling like a package manager and various development helpers, which can further reduce
|
||||
development cycles for space systems. `cargo` provides tools like auto-formatters and linters
|
||||
which can immediately ensure a high software quality throughout each development cycle.
|
||||
5. A large ecosystem with excellent libraries which also leverages the excellent tooling provided
|
||||
previously. Integrating these libraries is a lot easier compared to languages like C/C++ where
|
||||
there is still no standardized way to use packages.
|
||||
|
||||
+89
-12
@@ -1,19 +1,96 @@
|
||||
# Events
|
||||
|
||||
Events are an important mechanism used for remote systems to monitor unexpected
|
||||
or expected anomalies and events occuring on these systems.
|
||||
or expected anomalies and events occurring on these systems.
|
||||
They can improve the observability of a system significantly and provide a
|
||||
"paper trail" of what is happening or has happened on a satellite where regular
|
||||
housekeeping packets might not be sufficient. They can also be used for fault
|
||||
detection, isolation and recovery (FDIR) purposes. For example, higher level
|
||||
system objects can listen on certain high criticality events to initiate
|
||||
custom system responses.
|
||||
|
||||
One common use case for events on remote systems is to offer a light-weight publish-subscribe
|
||||
mechanism and IPC mechanism for software and hardware events which are also packaged as telemetry
|
||||
(TM) or can trigger a system response. They can also be tied to
|
||||
Fault Detection, Isolation and Recovery (FDIR) operations, which need to happen autonomously.
|
||||
|
||||
The PUS Service 5 standardizes how the ground interface for events might look like, but does not
|
||||
specify how other software components might react to those events. There is the PUS Service 19,
|
||||
which might be used for that purpose, but the event components recommended by this framework do not
|
||||
rely on the present of this service.
|
||||
## Event Severity
|
||||
|
||||
The following images shows how the flow of events could look like in a system where components
|
||||
can generate events, and where other system components might be interested in those events:
|
||||
Generally, it also makes sense to classify events according to a severity system
|
||||
so operators can quickly judge the importance of an event. `sat-rs` does not
|
||||
constrain the severity classes or enforce their usage, but a severity
|
||||
classification like this can make sense:
|
||||
|
||||

|
||||
- INFO
|
||||
- LOW ERROR
|
||||
- MEDIUM ERROR
|
||||
- HIGH ERROR
|
||||
|
||||
## Modelling Events with Rust
|
||||
|
||||
Usually, events will be associated with certain software objects or handlers.
|
||||
Oftentimes, developers and operators want to supply parameters or metadata
|
||||
associated with an event. This can all be done using the Rust `enum` type.
|
||||
|
||||
Let's start with an example: a camera device
|
||||
handler might have the following events:
|
||||
|
||||
- Image taken event
|
||||
- Communication error event including an error classifier
|
||||
- Communication timeout event with the configured timeout
|
||||
- Overheating event
|
||||
|
||||
You can model these events using the following data structure, also including
|
||||
a `severity` method.
|
||||
|
||||
```rust
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
|
||||
pub enum Event {
|
||||
ImageTaken,
|
||||
CommunicationError(ErrorType),
|
||||
CommunicationTimeout(core::time::Duration),
|
||||
Overheating
|
||||
}
|
||||
|
||||
impl Event {
|
||||
pub fn severity(&self) -> Severity {
|
||||
match self {
|
||||
Event::ImageTaken => Severity::Info,
|
||||
Event::CommunicationError(_) => Severity::Low,
|
||||
Event::CommunicationTimeout(_) => Severity::Low,
|
||||
Event::Overheating => Severity::High,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Depending on the requirements of your system, you might want to filter which
|
||||
events are packaged and sent as telemetry. This requires an identification
|
||||
system. A simple scheme would be to add something like this:
|
||||
|
||||
```rust
|
||||
impl Event {
|
||||
pub fn id(&self) -> u32 {
|
||||
match self {
|
||||
Event::ImageTaken => 0,
|
||||
Event::CommunicationError(_) => 1,
|
||||
Event::CommunicationTimeout(_) => 2,
|
||||
Event::Overheating => 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Handling events
|
||||
|
||||
When an event occurs in the system, you want to trigger the event.
|
||||
This usually includes sending the event to a centralized event funnel. The funnel
|
||||
takes care of packing the event into a telemetry packet as well as forwarding
|
||||
the event to any other objects which are interested in the event. A message
|
||||
queue system is the best solution for this. For example, on an embedded Linux
|
||||
system, you might have an event sender handle like this inside your camera
|
||||
device handler:
|
||||
|
||||
```rust
|
||||
pub struct CameraHandler {
|
||||
// (...)
|
||||
event_sender: std::sync::mpsc::SyncSender<Event>
|
||||
}
|
||||
```
|
||||
+69
-101
@@ -12,10 +12,59 @@ The example project contains components which could also be expected to be part
|
||||
On-Board Software. A structural diagram of the example application is given to provide
|
||||
a brief high-level view of the components used inside the example application:
|
||||
|
||||

|
||||
```mermaid
|
||||
flowchart TD
|
||||
subgraph TMTC[TMTC Infrastructure]
|
||||
subgraph TMTCRow1[ ]
|
||||
direction LR
|
||||
Udp[UDP Server]
|
||||
Tcp[TCP Server]
|
||||
end
|
||||
subgraph TMTCRow2[ ]
|
||||
direction LR
|
||||
Source[TC Source]
|
||||
Sink[TM Sink]
|
||||
end
|
||||
end
|
||||
|
||||
The dotted lines are used to denote optional components. In this case, the static pool components
|
||||
are optional because the heap can be used as a simpler mechanism to store TMTC packets as well.
|
||||
subgraph AOCS[AOCS Stack]
|
||||
subgraph AOCSRow1[ ]
|
||||
direction LR
|
||||
Mgm0[MGM 0 Handler]
|
||||
Mgm1[MGM 1 Handler]
|
||||
Assy[MGM Assembly]
|
||||
end
|
||||
subgraph AOCSRow2[ ]
|
||||
direction LR
|
||||
AcsCtrl[ACS Controller]
|
||||
Mgt[MGT Handler]
|
||||
AcsSub[ACS Subsystem]
|
||||
end
|
||||
end
|
||||
|
||||
subgraph EPS[EPS Stack]
|
||||
Pcdu[PCDU Handler]
|
||||
end
|
||||
|
||||
subgraph Core[Core]
|
||||
direction LR
|
||||
Ctrl[Core Controller]
|
||||
Evt[Event Manager]
|
||||
end
|
||||
|
||||
Sim[Sim Client]:::optional
|
||||
|
||||
TMTC ~~~ EPS
|
||||
AOCS ~~~ Core
|
||||
Core ~~~ Sim
|
||||
|
||||
classDef optional stroke-dasharray: 5 5;
|
||||
classDef invisible fill:none,stroke:none;
|
||||
class TMTCRow1,TMTCRow2,AOCSRow1,AOCSRow2 invisible;
|
||||
```
|
||||
|
||||
The dotted lines are used to denote optional components. In this case, the simulation client is
|
||||
optional because a dummy interface can be used instead to run the example without the simulator.
|
||||
Some additional explanation is provided for the various components.
|
||||
|
||||
### TCP/IP server components
|
||||
@@ -37,116 +86,35 @@ telecommands from the client.
|
||||
The most important components of the TMTC infrastructure include the following components:
|
||||
|
||||
- A TC source component which demultiplexes and routes telecommands based on parameters like
|
||||
packet APID or PUS service and subservice type.
|
||||
- A TM sink sink component which is the target of all sent telemetry and sends it to downlink
|
||||
packet APID and a target ID which is part of the packet payload.
|
||||
- A TM sink component which is the target of all sent telemetry and sends it to downlink
|
||||
handlers like the UDP and TCP server.
|
||||
|
||||
You can read the [Communications chapter](./communication.md) for more
|
||||
background information on the chosen TMTC infrastructure approach.
|
||||
|
||||
### PUS Service Components
|
||||
|
||||
A PUS service stack is provided which exposes some functionality conformant with the ECSS PUS
|
||||
services. This currently includes the following services:
|
||||
|
||||
- Service 1 for telecommand verification. The verification handling is handled locally: Each
|
||||
component which generates verification telemetry in some shape or form receives a
|
||||
[reporter](https://docs.rs/satrs/latest/satrs/pus/verification/struct.VerificationReporterWithSender.html)
|
||||
object which can be used to send PUS 1 verification telemetry to the TM funnel.
|
||||
- Service 3 for housekeeping telemetry handling.
|
||||
- Service 5 for management and downlink of on-board events.
|
||||
- Service 8 for handling on-board actions.
|
||||
- Service 11 for scheduling telecommands to be released at a specific time. This component
|
||||
uses the [PUS scheduler class](https://docs.rs/satrs/latest/satrs/pus/scheduler/alloc_mod/struct.PusScheduler.html)
|
||||
which performs the core logic of scheduling telecommands. All telecommands released by the
|
||||
scheduler are sent to the central TC source using a message.
|
||||
- Service 17 for test purposes like pings.
|
||||
|
||||
### Event Management Component
|
||||
|
||||
An event manager based on the sat-rs
|
||||
[event manager component](https://docs.rs/satrs/latest/satrs/event_man/index.html)
|
||||
is provided to handle the event IPC and FDIR mechanism. The event message are converted to PUS 5
|
||||
telemetry by the
|
||||
[PUS event dispatcher](https://docs.rs/satrs/latest/satrs/pus/event_man/alloc_mod/struct.PusEventDispatcher.html).
|
||||
|
||||
You can read the [events](./events.md) chapter for more in-depth information about event management.
|
||||
|
||||
### Sample Application Components
|
||||
|
||||
These components are example mission specific. They provide an idea how mission specific modules
|
||||
would look like the sat-rs context. It currently includes the following components:
|
||||
|
||||
- An Attitute and Orbit Control (AOCS) example task which can also process some PUS commands.
|
||||
|
||||
## Dataflow
|
||||
|
||||
The interaction of the various components is provided in the following diagram:
|
||||
### TMTC component group
|
||||
|
||||

|
||||
|
||||
It should be noted that an arrow coming out of a component group refers to multiple components
|
||||
in that group. An explanation for important component groups will be given.
|
||||
|
||||
#### TMTC component group
|
||||
|
||||
This groups is the primary interface for clients to communicate with the on-board software
|
||||
using a standardized TMTC protocol. The example uses the
|
||||
[ECSS PUS protocol](https://ecss.nl/standard/ecss-e-st-70-41c-space-engineering-telemetry-and-telecommand-packet-utilization-15-april-2016/).
|
||||
This group is the primary interface for clients to communicate with the on-board software
|
||||
using the combination of CCSDS space packets and `serde` serialized payloads.
|
||||
In the future, this might be extended with the
|
||||
[CCSDS File Delivery Protocol](https://public.ccsds.org/Pubs/727x0b5.pdf).
|
||||
|
||||
A client can connect to the UDP or TCP server to send these PUS packets to the on-board software.
|
||||
These servers then forward the telecommads to a centralized TC source component using a dedicated
|
||||
message abstraction.
|
||||
A client can connect to the UDP or TCP server to send telecommands to the on-board software.
|
||||
These servers forward all telecommands to a centralized TC source component, which demultiplexes
|
||||
them and routes each one to its target component.
|
||||
|
||||
This TC source component then demultiplexes the message and forwards it to the relevant components.
|
||||
Right now, it forwards all PUS requests to the respective PUS service handlers using the PUS
|
||||
receiver component. The individual PUS services are running in a separate thread. In the future,
|
||||
additional forwarding to components like a CFDP handler might be added as well. It should be noted
|
||||
that PUS11 commands might contain other PUS commands which should be scheduled in the future.
|
||||
These wrapped commands are forwarded to the PUS11 handler. When the schedule releases those
|
||||
commands, it forwards the released commands to the TC source again. This allows the scheduler
|
||||
and the TC source to run in separate threads and keeps them cleanly separated.
|
||||
All telemetry generated by the on-board software is sent to a centralized TM sink. The core
|
||||
controller also forwards events to the event manager, which converts them into telemetry and
|
||||
sends it to the TM sink as well. The TM sink performs a demultiplexing step to forward all
|
||||
telemetry to the relevant recipients, which in the example case are the last connected UDP
|
||||
client and any connected TCP client.
|
||||
|
||||
All telemetry generated by the on-board software is sent to a centralized TM funnel. This component
|
||||
also performs a demultiplexing step to forward all telemetry to the relevant TM recipients.
|
||||
In the example case, this is the last UDP client, or a connected TCP client. In the future,
|
||||
forwarding to a persistent telemetry store and a simulated communication component might be
|
||||
added here as well. The centralized TM funnel also takes care of some packet processing steps which
|
||||
need to be applied for each ECSS PUS packet, for example CCSDS specific APID incrementation and
|
||||
PUS specific message counter incrementation.
|
||||
### Application Group
|
||||
|
||||
#### Application Group
|
||||
The application group contains some components you might also find in a real satellite software.
|
||||
This includes an AOCS stack with various device handlers and system level objects.
|
||||
|
||||
The application components generally do not receive raw PUS packets directly, even though
|
||||
this is certainly possible. Instead, they receive internalized messages from the PUS service
|
||||
handlers. For example, instead of receiving a PUS 8 Action Telecommand directly, an application
|
||||
component will receive a special `ActionRequest` message type reduced to the basic important
|
||||
information required to execute a request. These special requests are denoted by the blue arrow
|
||||
in the diagram.
|
||||
|
||||
It should be noted that the arrow pointing towards the event manager points in both directions.
|
||||
This is because the application components might be interested in events generated by other
|
||||
components as well. This mechanism is oftentimes used to implement the FDIR functionality on system
|
||||
and component level.
|
||||
|
||||
#### Shared components and functional interfaces
|
||||
|
||||
It should be noted that sometimes, a functional interface is used instead of a message. This
|
||||
is used for the generation of verification telemetry. The verification reporter is a clonable
|
||||
component which generates and sends PUS1 verification telemetry directly to the TM funnel. This
|
||||
introduces a loose coupling to the PUS standard but was considered the easiest solution for
|
||||
a project which utilizes PUS as the main communication protocol. In the future, a generic
|
||||
verification abstraction might be introduced to completely decouple the application layer from
|
||||
PUS.
|
||||
|
||||
The same concept is applied if the backing store of TMTC packets are shared pools. Every
|
||||
component which needs to read telecommands inside that shared pool or generate new telemetry
|
||||
into that shared pool will received a clonable shared handle to that pool.
|
||||
|
||||
The same concept could be extended to power or thermal handling. For example, a shared power helper
|
||||
component might be used to retrieve power state information and send power switch commands through
|
||||
a functional interface. The actual implementation of the functional interface might still use
|
||||
shared memory and/or messages, but the functional interface makes using and testing the interaction
|
||||
with these components easier.
|
||||
### Shared components and functional interfaces
|
||||
@@ -1 +1 @@
|
||||
# Fault Detecion, Isolation And Recovery (FDIR)
|
||||
# Fault Detection, Isolation And Recovery (FDIR)
|
||||
@@ -1,24 +1,107 @@
|
||||
# Housekeeping Data
|
||||
|
||||
Remote systems like satellites and rovers oftentimes generate data autonomously and periodically.
|
||||
The most common example for this is temperature or attitude data. Data like this is commonly
|
||||
referred to as housekeeping data, and is usually one of the most important and most resource heavy
|
||||
data sources received from a satellite. Standards like the PUS Service 3 make recommendation how to
|
||||
expose housekeeping data, but the applicability of the interface offered by PUS 3 has proven to be
|
||||
partially difficult and clunky for modular systems.
|
||||
If you have not read [the TMTC modelling chapter](./tmtc-modelling.md) yet, it is recommended to
|
||||
do that first.
|
||||
|
||||
First, we are going to list some assumption and requirements about Housekeeping (HK) data:
|
||||
Remote systems like satellites and rovers oftentimes generate data autonomously and periodically.
|
||||
An example for this could be temperature or attitude data. Data like this is commonly
|
||||
referred to as housekeeping data, and is usually one of the most important and most resource heavy
|
||||
data sources received from a satellite.
|
||||
|
||||
First, we are going to list some assumptions and requirements about Housekeeping (HK) data:
|
||||
|
||||
1. HK data is generated periodically by various system components throughout the
|
||||
systems.
|
||||
system.
|
||||
2. An autonomous and periodic sampling of that HK data to be stored and sent to Ground is generally
|
||||
required. A minimum interface consists of requesting a one-shot sample of HK, enabling and
|
||||
disabling the periodic autonomous generation of samples and modifying the collection interval
|
||||
of the periodic autonomous generation.
|
||||
3. HK data often needs to be shared to other software components. For example, a thermal controller
|
||||
3. HK data often needs to be shared with other software components. For example, a thermal controller
|
||||
wants to read the data samples of all sensor components.
|
||||
|
||||
A commonly required way to model HK data in a clean way is also to group related HK data into sets,
|
||||
which can then dumped via a similar interface.
|
||||
## Modelling our data
|
||||
|
||||
TODO: Write down `sat-rs` recommendations how to expose and work with HK data.
|
||||
Generally, it makes sense to model the data with Rust data structures for various reasons. For
|
||||
example, the sensor data received from a 3-axis magnetometer might be modelled like this:
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct MgmData {
|
||||
pub x: i16,
|
||||
pub y: i16,
|
||||
pub z: i16,
|
||||
}
|
||||
```
|
||||
|
||||
You can then re-use this data structure for various purposes. Also note the `serde` implementations,
|
||||
which are useful for generating the housekeeping data sent to ground.
|
||||
|
||||
We can model the housekeeping requests for a handler with a single data set like this:
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub enum HkRequest {
|
||||
OneShot,
|
||||
EnablePeriodic,
|
||||
DisablePeriodic,
|
||||
ModifyInterval(core::time::Duration)
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
which might then be a part of a top level request type, e.g.
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Request {
|
||||
Ping,
|
||||
Hk(HkRequest)
|
||||
}
|
||||
```
|
||||
|
||||
A corresponding `Response` type might just include a HK data variant:
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Response {
|
||||
Ok,
|
||||
Hk(MgmData)
|
||||
}
|
||||
```
|
||||
|
||||
If the software object managed multiple data sets, you could model it like this:
|
||||
|
||||
```rust
|
||||
/// Example set ID.
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub enum SetId {
|
||||
Data,
|
||||
Config
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Request {
|
||||
Ping,
|
||||
Hk {
|
||||
set_id: SetId,
|
||||
request: HkRequest
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Sometimes, you need to share the generated data as well. Furthermore, it might make sense to
|
||||
decouple the HK generation from the data acquisition and only return the latest snapshot
|
||||
of the data. In this case, you can put the `MgmData` inside an appropriate lock structure for your
|
||||
platform/runtime to share it safely with other software components. For example, in a `std` system,
|
||||
you might simply use an `Arc<Mutex<MgmData>>` or an `Arc<RwLock<MgmData>>` for this.
|
||||
|
||||
Now, you can update that shared data structure when acquiring new data, and other software objects
|
||||
or the HK generation routine can safely read from it.
|
||||
|
||||
## Helper components
|
||||
|
||||
You need some application logic to track whether periodic data generation is enabled, what
|
||||
the current generation interval is and whether a HK set needs to be generated if the interval
|
||||
period has elapsed.
|
||||
|
||||
`sat-rs` provides some simple helper components for this inside the [`hk`](https://docs.rs/satrs/latest/satrs/hk/index.html) module. The module documentation contains more information.
|
||||
@@ -0,0 +1 @@
|
||||
*.bkp
|
||||
@@ -0,0 +1,99 @@
|
||||
<mxfile host="Electron">
|
||||
<diagram name="Page-1" id="L7hDkg9csFOap1jIF0ey">
|
||||
<mxGraphModel dx="808" dy="1600" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="Et7Is9MkKvAT9IauE9_I-4" connectable="0" parent="1" style="group" value="" vertex="1">
|
||||
<mxGeometry height="114" width="443" x="482" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-27" parent="Et7Is9MkKvAT9IauE9_I-4" style="rounded=0;arcSize=20;strokeWidth=3;fillColor=#BFDCEC;strokeColor=#0072B2;fontSize=14;fontColor=#003A5D;labelBackgroundColor=none;fontStyle=1;labelPosition=center;verticalLabelPosition=middle;align=center;verticalAlign=top;spacingTop=0;perimeterSpacing=1;" value="Application" vertex="1">
|
||||
<mxGeometry height="117" width="430" y="-3" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-46" parent="Et7Is9MkKvAT9IauE9_I-4" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Mission Logic</span>" vertex="1">
|
||||
<mxGeometry height="22" width="113.16" x="13" y="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-47" parent="Et7Is9MkKvAT9IauE9_I-4" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;"><font face="Courier New">sat-rs</font></span>" vertex="1">
|
||||
<mxGeometry height="22" width="93" x="238" y="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="eFmRNKLwCo7I2zrsRzJH-1" parent="Et7Is9MkKvAT9IauE9_I-4" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;"><font face="Courier New">spacepackets</font></span>" vertex="1">
|
||||
<mxGeometry height="22" width="113.16" x="13" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wZbC1GPg-bVreQhl9PIS-1" parent="Et7Is9MkKvAT9IauE9_I-4" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Events</span>" vertex="1">
|
||||
<mxGeometry height="22" width="86.24" x="136" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Et7Is9MkKvAT9IauE9_I-3" parent="Et7Is9MkKvAT9IauE9_I-4" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;"><font face="Courier New">cfdp</font></span>" vertex="1">
|
||||
<mxGeometry height="22" width="93" x="231" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wZbC1GPg-bVreQhl9PIS-7" parent="Et7Is9MkKvAT9IauE9_I-4" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Device Drivers</span>" vertex="1">
|
||||
<mxGeometry height="22" width="115" x="12.999999999999968" y="85" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wZbC1GPg-bVreQhl9PIS-5" parent="Et7Is9MkKvAT9IauE9_I-4" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Mode Tree</span>" vertex="1">
|
||||
<mxGeometry height="22" width="105.48" x="135.99999999999997" y="85" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wZbC1GPg-bVreQhl9PIS-6" parent="Et7Is9MkKvAT9IauE9_I-4" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Controllers</span>" vertex="1">
|
||||
<mxGeometry height="22" width="86.24" x="333" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wZbC1GPg-bVreQhl9PIS-8" parent="Et7Is9MkKvAT9IauE9_I-4" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">TMTC</span>" vertex="1">
|
||||
<mxGeometry height="22" width="93" x="133.67" y="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="wZbC1GPg-bVreQhl9PIS-20" parent="Et7Is9MkKvAT9IauE9_I-4" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;"><font face="Courier New">FDIR</font></span>" vertex="1">
|
||||
<mxGeometry height="22" width="79" x="342" y="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-28" parent="1" style="rounded=0;arcSize=20;strokeWidth=3;fillColor=#E2E8F0;strokeColor=#475569;fontColor=#1E293B;labelBackgroundColor=none;fontStyle=1;fontSize=14;perimeterSpacing=1;" value="Hardware" vertex="1">
|
||||
<mxGeometry height="40" width="430" x="482" y="385" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-31" edge="1" parent="1" source="mcy6J03i3kvHfejOpHHr-16" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;labelBackgroundColor=none;strokeColor=#969696;fontColor=default;endArrow=classic;endFill=1;edgeStyle=orthogonalEdgeStyle;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.506;entryY=0.034;entryDx=0;entryDy=0;entryPerimeter=0;" target="mcy6J03i3kvHfejOpHHr-28">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="700" y="359" />
|
||||
<mxPoint x="700" y="370" />
|
||||
<mxPoint x="699.6" y="370" />
|
||||
</Array>
|
||||
<mxPoint x="700" y="370" as="sourcePoint" />
|
||||
<mxPoint x="700.16" y="420" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-32" edge="1" parent="1" source="mcy6J03i3kvHfejOpHHr-27" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=-0.006;entryDx=0;entryDy=0;entryPerimeter=0;strokeWidth=2;labelBackgroundColor=none;fontColor=default;exitX=0.502;exitY=0.992;exitDx=0;exitDy=0;exitPerimeter=0;edgeStyle=orthogonalEdgeStyle;curved=0;strokeColor=#969696;" target="mcy6J03i3kvHfejOpHHr-16">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="680" y="104.48999999999998" as="sourcePoint" />
|
||||
<mxPoint x="680.4399999999998" y="140.00000000000003" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-43" connectable="0" parent="1" style="group;fillColor=#FFF7ED;rounded=0;labelBackgroundColor=none;fontColor=#6B2F00;strokeColor=#D55E00;strokeWidth=3;perimeterSpacing=1;verticalAlign=middle;" value="" vertex="1">
|
||||
<mxGeometry height="219" width="432" x="482" y="140" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-16" parent="mcy6J03i3kvHfejOpHHr-43" style="whiteSpace=wrap;strokeWidth=2;verticalAlign=top;fillColor=#FED7AA;strokeColor=#EA580C;fontColor=#6B2F00;fontSize=14;rounded=0;labelBackgroundColor=none;fontStyle=1" value="System / platform
async-centric, embassy or RTICv2" vertex="1">
|
||||
<mxGeometry height="219" width="432" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-35" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Logging<br></span><div><span style="font-weight: normal;"><font face="Courier New" style="font-size: 12px;">defmt + defmt-rtt</font></span></div>" vertex="1">
|
||||
<mxGeometry height="40" width="133.52063580591187" x="9.000332775608848" y="56.73391304347825" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-36" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Serialization<br><font face="Courier New" style="font-size: 12px;">serde + postcard</font></span>" vertex="1">
|
||||
<mxGeometry height="40" width="128" x="155" y="57.34" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-37" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Containers<br><font face="Courier New" style="font-size: 12px;">heapless</font></span>" vertex="1">
|
||||
<mxGeometry height="40" width="122" x="295" y="57" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-38" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Time<br><font style="font-size: 12px;" face="Courier New">embassy-time</font></span>" vertex="1">
|
||||
<mxGeometry height="40" width="131.43389604559735" x="9.004190097896517" y="104.99833992094861" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-39" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">IPC / Sync<br><font face="Courier New" style="font-size: 12px;">embassy-sync</font></span>" vertex="1">
|
||||
<mxGeometry height="40" width="130.29" x="153" y="105" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-40" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Memory<br><font face="Courier New" style="font-size: 12px;">embedded-alloc</font></span>" vertex="1">
|
||||
<mxGeometry height="40" width="123.45" x="296" y="105" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-41" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Tasks<br><font style="font-size: 12px;" face="Courier New">embassy-executor </font><font style="font-size: 12px;" face="Helvetica">or&nbsp;</font><font style="font-size: 12px;" face="Courier New">rtic</font></span>" vertex="1">
|
||||
<mxGeometry height="55" width="130.29303773935672" x="8.99793084216397" y="153" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-42" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Hardware API</span><div><span style="font-weight: normal;"><font style="font-size: 12px;">BSP + HAL + PAC</font></span></div>" vertex="1">
|
||||
<mxGeometry height="40" width="130.5" x="152" y="153" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Et7Is9MkKvAT9IauE9_I-2" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Filesystem</span><div><span style="font-weight: normal;"><font style="font-size: 12px;"><font face="Courier New">embedded-sdmmc</font> or<br><font face="Courier New">embedded-fatfs</font></font></span></div>" vertex="1">
|
||||
<mxGeometry height="55" width="123.45" x="296" y="153" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 330 KiB |
@@ -0,0 +1,85 @@
|
||||
<mxfile host="Electron">
|
||||
<diagram name="Page-1" id="L7hDkg9csFOap1jIF0ey">
|
||||
<mxGraphModel dx="975" dy="1703" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-27" parent="1" style="rounded=0;arcSize=20;strokeWidth=3;fillColor=#BFDCEC;strokeColor=#0072B2;fontSize=14;fontColor=#003A5D;labelBackgroundColor=none;fontStyle=1;labelPosition=center;verticalLabelPosition=middle;align=center;verticalAlign=top;spacingTop=0;perimeterSpacing=1;" value="Application" vertex="1">
|
||||
<mxGeometry height="122" width="426.02" x="490.98" y="-10" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-28" parent="1" style="rounded=0;arcSize=20;strokeWidth=3;fillColor=#E2E8F0;strokeColor=#475569;fontColor=#1E293B;labelBackgroundColor=none;fontStyle=1;fontSize=14;perimeterSpacing=1;" value="Hardware" vertex="1">
|
||||
<mxGeometry height="40" width="420" x="490.5" y="290" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-32" edge="1" parent="1" source="mcy6J03i3kvHfejOpHHr-27" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=-0.006;entryDx=0;entryDy=0;entryPerimeter=0;strokeWidth=2;labelBackgroundColor=none;strokeColor=#969696;fontColor=default;exitX=0.496;exitY=0.984;exitDx=0;exitDy=0;exitPerimeter=0;edgeStyle=orthogonalEdgeStyle;curved=0;" target="mcy6J03i3kvHfejOpHHr-16">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="680" y="104.48999999999998" as="sourcePoint" />
|
||||
<mxPoint x="680.4399999999998" y="140.00000000000003" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-43" connectable="0" parent="1" style="group;fillColor=#FFF7ED;rounded=0;labelBackgroundColor=none;fontColor=#6B2F00;strokeColor=#D55E00;strokeWidth=3;perimeterSpacing=1;" value="" vertex="1">
|
||||
<mxGeometry height="124" width="423" x="490.5" y="140" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-16" parent="mcy6J03i3kvHfejOpHHr-43" style="whiteSpace=wrap;strokeWidth=2;verticalAlign=top;fillColor=#FED7AA;strokeColor=#EA580C;fontColor=#6B2F00;fontSize=14;rounded=0;labelBackgroundColor=none;fontStyle=1" value="System / platform" vertex="1">
|
||||
<mxGeometry height="124" width="423" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-35" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Logging<br></span>" vertex="1">
|
||||
<mxGeometry height="22" width="117.5" x="15" y="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-36" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Serialization</span>" vertex="1">
|
||||
<mxGeometry height="22" width="117.5" x="146.5" y="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-37" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Containers</span>" vertex="1">
|
||||
<mxGeometry height="22" width="117.5" x="278.5" y="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-39" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">IPC / Sync</span>" vertex="1">
|
||||
<mxGeometry height="22" width="117.5" x="14.5" y="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-40" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Memory</span>" vertex="1">
|
||||
<mxGeometry height="22" width="117.5" x="278" y="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-41" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Tasks</span>" vertex="1">
|
||||
<mxGeometry height="22" width="117.5" x="146.5" y="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-42" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Hardware API</span>" vertex="1">
|
||||
<mxGeometry height="22" width="117.5" x="15" y="90" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="QQywTSC8lEcqjhdOS4oo-1" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Filesystem</span>" vertex="1">
|
||||
<mxGeometry height="22" width="117.5" x="146.5" y="90" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-38" parent="mcy6J03i3kvHfejOpHHr-43" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;" value="<span style="font-weight: normal;">Time</span>" vertex="1">
|
||||
<mxGeometry height="22" width="117.5" x="278.5" y="90" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="_ne4E4OgUf3ctT-MU7S6-3" edge="1" parent="1" source="mcy6J03i3kvHfejOpHHr-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.506;entryY=0.031;entryDx=0;entryDy=0;fontColor=#000000;strokeColor=#969696;strokeWidth=2;exitX=0.503;exitY=1.009;exitDx=0;exitDy=0;entryPerimeter=0;exitPerimeter=0;" target="mcy6J03i3kvHfejOpHHr-28">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="702.54" y="281.12" as="sourcePoint" />
|
||||
<mxPoint x="701.46" y="303" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="_ne4E4OgUf3ctT-MU7S6-4" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Command Scheduling</span>" vertex="1">
|
||||
<mxGeometry height="22" width="171" x="499" y="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-46" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Mission Logic</span>" vertex="1">
|
||||
<mxGeometry height="22" width="105.48496240601504" x="498.9978345864661" y="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-47" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Events</span>" vertex="1">
|
||||
<mxGeometry height="22" width="94.67142857142858" x="719.0028571428571" y="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="nZ8_NfAIOoxuCbflcZYr-2" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">FDIR</span>" vertex="1">
|
||||
<mxGeometry height="22" width="80.57142857142857" x="824.0028571428571" y="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="nZ8_NfAIOoxuCbflcZYr-4" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">TMTC</span>" vertex="1">
|
||||
<mxGeometry height="22" width="94.67142857142858" x="614.0028571428571" y="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="932u3wCXrdYco77gi_Ax-1" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Mode Tree</span>" vertex="1">
|
||||
<mxGeometry height="22" width="105.48" x="680" y="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="932u3wCXrdYco77gi_Ax-2" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Controllers</span>" vertex="1">
|
||||
<mxGeometry height="22" width="104.57" x="800" y="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="932u3wCXrdYco77gi_Ax-5" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Device Drivers</span>" vertex="1">
|
||||
<mxGeometry height="22" width="115" x="499" y="80" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 205 KiB |
@@ -0,0 +1,100 @@
|
||||
<mxfile host="Electron">
|
||||
<diagram name="Page-1" id="L7hDkg9csFOap1jIF0ey">
|
||||
<mxGraphModel dx="571" dy="1434" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-43" connectable="0" parent="1" style="group;fillColor=#FFF7ED;rounded=0;labelBackgroundColor=none;fontColor=#6B2F00;strokeColor=#D55E00;strokeWidth=3;perimeterSpacing=1;container=0;" value="" vertex="1">
|
||||
<mxGeometry height="190" width="428" x="482" y="140" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-28" parent="1" style="rounded=0;arcSize=20;strokeWidth=3;fillColor=#E2E8F0;strokeColor=#475569;fontColor=#1E293B;labelBackgroundColor=none;fontStyle=1;fontSize=14;perimeterSpacing=1;" value="Hardware" vertex="1">
|
||||
<mxGeometry height="40" width="430" x="482" y="352" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-31" edge="1" parent="1" source="mcy6J03i3kvHfejOpHHr-16" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;labelBackgroundColor=none;strokeColor=#969696;fontColor=default;entryX=0.52;entryY=-0.019;entryDx=0;entryDy=0;entryPerimeter=0;endArrow=classic;endFill=1;edgeStyle=orthogonalEdgeStyle;exitX=0.518;exitY=1.002;exitDx=0;exitDy=0;exitPerimeter=0;" target="mcy6J03i3kvHfejOpHHr-28">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="703.6" y="330.4" />
|
||||
</Array>
|
||||
<mxPoint x="700" y="370" as="sourcePoint" />
|
||||
<mxPoint x="680.36" y="340.24" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="T22fa2qrIJ5I1ijH7CBO-27" connectable="0" parent="1" style="group" value=" " vertex="1">
|
||||
<mxGeometry height="139" width="443" x="481" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="T22fa2qrIJ5I1ijH7CBO-14" connectable="0" parent="T22fa2qrIJ5I1ijH7CBO-27" style="group" value="" vertex="1">
|
||||
<mxGeometry height="114" width="443" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="T22fa2qrIJ5I1ijH7CBO-15" parent="T22fa2qrIJ5I1ijH7CBO-14" style="rounded=0;arcSize=20;strokeWidth=3;fillColor=#BFDCEC;strokeColor=#0072B2;fontSize=14;fontColor=#003A5D;labelBackgroundColor=none;fontStyle=1;labelPosition=center;verticalLabelPosition=middle;align=center;verticalAlign=top;spacingTop=0;perimeterSpacing=1;" value="Application" vertex="1">
|
||||
<mxGeometry height="117" width="430" y="-3" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="T22fa2qrIJ5I1ijH7CBO-16" parent="T22fa2qrIJ5I1ijH7CBO-14" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Mission Logic</span>" vertex="1">
|
||||
<mxGeometry height="22" width="113.16" x="13" y="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="T22fa2qrIJ5I1ijH7CBO-17" parent="T22fa2qrIJ5I1ijH7CBO-14" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;"><font face="Courier New">sat-rs</font></span>" vertex="1">
|
||||
<mxGeometry height="22" width="93" x="238" y="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="T22fa2qrIJ5I1ijH7CBO-18" parent="T22fa2qrIJ5I1ijH7CBO-14" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;"><font face="Courier New">spacepackets</font></span>" vertex="1">
|
||||
<mxGeometry height="22" width="113.16" x="14" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="T22fa2qrIJ5I1ijH7CBO-19" parent="T22fa2qrIJ5I1ijH7CBO-14" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Events</span>" vertex="1">
|
||||
<mxGeometry height="22" width="86.24" x="136" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="T22fa2qrIJ5I1ijH7CBO-20" parent="T22fa2qrIJ5I1ijH7CBO-14" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;"><font face="Courier New">cfdp</font></span>" vertex="1">
|
||||
<mxGeometry height="22" width="93" x="231" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="T22fa2qrIJ5I1ijH7CBO-21" parent="T22fa2qrIJ5I1ijH7CBO-14" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Device Drivers</span>" vertex="1">
|
||||
<mxGeometry height="22" width="114.16" x="13" y="85" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="T22fa2qrIJ5I1ijH7CBO-22" parent="T22fa2qrIJ5I1ijH7CBO-14" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Mode Tree</span>" vertex="1">
|
||||
<mxGeometry height="22" width="105.48" x="135.99999999999997" y="85" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="T22fa2qrIJ5I1ijH7CBO-23" parent="T22fa2qrIJ5I1ijH7CBO-14" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">Controllers</span>" vertex="1">
|
||||
<mxGeometry height="22" width="86.24" x="333" y="55" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="T22fa2qrIJ5I1ijH7CBO-24" parent="T22fa2qrIJ5I1ijH7CBO-14" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;">TMTC</span>" vertex="1">
|
||||
<mxGeometry height="22" width="93" x="133.67" y="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="T22fa2qrIJ5I1ijH7CBO-25" parent="T22fa2qrIJ5I1ijH7CBO-14" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#BFDCEC;fontColor=#003A5D;strokeColor=#0072B2;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;spacingTop=0;arcSize=20;" value="<span style="font-weight: normal;"><font face="Courier New">FDIR</font></span>" vertex="1">
|
||||
<mxGeometry height="22" width="79" x="342" y="25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="T22fa2qrIJ5I1ijH7CBO-26" edge="1" parent="T22fa2qrIJ5I1ijH7CBO-27" source="T22fa2qrIJ5I1ijH7CBO-15" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=-0.006;entryDx=0;entryDy=0;entryPerimeter=0;strokeWidth=2;labelBackgroundColor=none;fontColor=default;exitX=0.502;exitY=0.992;exitDx=0;exitDy=0;exitPerimeter=0;edgeStyle=orthogonalEdgeStyle;curved=0;strokeColor=#969696;">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="198" y="104.49000000000001" as="sourcePoint" />
|
||||
<mxPoint x="216" y="139" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-16" parent="1" style="whiteSpace=wrap;strokeWidth=2;verticalAlign=top;fillColor=#FED7AA;strokeColor=#EA580C;fontColor=#6B2F00;fontSize=14;rounded=0;labelBackgroundColor=none;fontStyle=1" value="System / platform
Embedded Linux" vertex="1">
|
||||
<mxGeometry height="190" width="428" x="482" y="140" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-35" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;aspect=fixed;" value="<span style="font-weight: normal;">Logging<br></span><div><span style="font-weight: normal;"><font face="Courier New" style="font-size: 12px;">log + fern</font></span></div>" vertex="1">
|
||||
<mxGeometry height="40" width="125" x="495" y="189.49" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-36" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;aspect=fixed;" value="<span style="font-weight: normal;">Serialization<br><font face="Courier New" style="font-size: 12px;">serde + postcard</font></span>" vertex="1">
|
||||
<mxGeometry height="40" width="134.66" x="634" y="189.18367088607596" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-37" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;aspect=fixed;" value="<span style="font-weight: normal;">Containers<br><font face="Courier New" style="font-size: 12px;">heapless + std</font></span>" vertex="1">
|
||||
<mxGeometry height="40" width="115" x="782.79" y="189.18" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-38" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;aspect=fixed;" value="<span style="font-weight: normal;">Time<br><font style="font-size: 12px;" face="Courier New">std</font></span>" vertex="1">
|
||||
<mxGeometry height="40" width="125" x="494" y="236" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-39" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;aspect=fixed;" value="<span style="font-weight: normal;">IPC / Sync<br></span><div><span style="font-weight: normal;"><font style="font-size: 12px;" face="Courier New">std</font></span></div>" vertex="1">
|
||||
<mxGeometry height="40" width="135" x="633" y="236" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-40" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;aspect=fixed;" value="<span style="font-weight: normal;">Memory<br><font face="Courier New" style="font-size: 12px;">alloc</font></span>" vertex="1">
|
||||
<mxGeometry height="40" width="113.79" x="782" y="235.99628691983122" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-41" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;aspect=fixed;" value="<span style="font-weight: normal;">Tasks<br><font face="Courier New"><span style="font-size: 12px;">std</span></font></span>" vertex="1">
|
||||
<mxGeometry height="40" width="125" x="495" y="283" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="mcy6J03i3kvHfejOpHHr-42" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;aspect=fixed;" value="<span style="font-weight: normal;">Hardware API</span><div><span style="font-weight: normal;"><font style="font-size: 12px;">Linux + <font face="Courier New">uio</font></font></span></div>" vertex="1">
|
||||
<mxGeometry height="40" width="137.7" x="633" y="282.9989029535865" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="6sRxE-k6t311zxd993k4-5" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FED7AA;fontColor=#6B2F00;strokeColor=#EA580C;labelBackgroundColor=none;strokeWidth=2;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=14;fontStyle=1;aspect=fixed;" value="<span style="font-weight: normal;">Filesystem<br><font face="Courier New" style="font-size: 12px;">std</font></span>" vertex="1">
|
||||
<mxGeometry height="40" width="113.79" x="782" y="283" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 271 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
@@ -4,11 +4,9 @@ The sat-rs book
|
||||
This book is the primary information resource for the [sat-rs library](https://egit.irs.uni-stuttgart.de/rust/sat-rs)
|
||||
in addition to the regular API documentation. It contains the following resources:
|
||||
|
||||
1. Architecture informations and consideration which would exceeds the scope of the regular API.
|
||||
2. General information on how to build On-Board Software and how `sat-rs` can help to fulfill
|
||||
1. Architecture information and considerations which would exceed the scope of the regular API.
|
||||
2. General information on how to build on-board software and how `sat-rs` can help to fulfill
|
||||
the unique requirements of writing software for remote systems.
|
||||
2. A Getting-Started workshop where a small On-Board Software is built from scratch using
|
||||
sat-rs components.
|
||||
|
||||
# Introduction
|
||||
|
||||
@@ -16,19 +14,35 @@ The primary goal of the sat-rs library is to provide re-usable components
|
||||
to write on-board software for remote systems like rovers or satellites. It is specifically written
|
||||
for the special requirements for these systems.
|
||||
|
||||
It should be noted that sat-rs is early-stage software. Important features are missing. New releases
|
||||
with breaking changes are released regularly, with all changes documented inside respective
|
||||
changelog files. You should only use this library if your are willing to work in this
|
||||
environment.
|
||||
|
||||
A lot of the architecture and general design considerations are based on the
|
||||
Some architecture and general design considerations are based on the
|
||||
[FSFW](https://egit.irs.uni-stuttgart.de/fsfw/fsfw) C++ framework which has flight heritage
|
||||
through the 2 missions [FLP](https://www.irs.uni-stuttgart.de/en/research/satellitetechnology-and-instruments/smallsatelliteprogram/flying-laptop/)
|
||||
and [EIVE](https://www.irs.uni-stuttgart.de/en/research/satellitetechnology-and-instruments/smallsatelliteprogram/EIVE/).
|
||||
|
||||
However, `sat-rs` has a significantly reduced scope compared to those frameworks. Rust provides
|
||||
a great ecosystem and a powerful standard library which reduces the need for large and complex
|
||||
frameworks.
|
||||
|
||||
# Getting started with the example
|
||||
|
||||
The [`satrs-example`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example)
|
||||
provides various practical usage examples of the `sat-rs` framework. If you are more interested in
|
||||
the practical application of `sat-rs` inside an application, it is recommended to have a look at
|
||||
the example application.
|
||||
the example application. The [`satrs-minisim`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example/minisim)
|
||||
application complements the example application and can be used to simulate some physical devices
|
||||
for the `satrs-example` device handlers.
|
||||
|
||||
# Flight Heritage
|
||||
|
||||
There is an active and continuous effort to get early flight heritage for the sat-rs library.
|
||||
Currently this library has the following flight heritage:
|
||||
|
||||
- Submission as an [OPS-SAT experiment](https://www.esa.int/Enabling_Support/Operations/OPS-SAT)
|
||||
which has also
|
||||
[flown on the satellite](https://blogs.esa.int/rocketscience/2024/05/21/ops-sat-reentry-tomorrow-final-experiments-continue/).
|
||||
The application is strongly based on the sat-rs example application. You can find the repository
|
||||
of the experiment [here](https://egit.irs.uni-stuttgart.de/rust/ops-sat-rs).
|
||||
- Development and use of a sat-rs-based [demonstration on-board software](https://egit.irs.uni-stuttgart.de/rust/eurosim-obsw)
|
||||
alongside a Flight System Simulator in the context of a
|
||||
[Bachelor's thesis](https://www.researchgate.net/publication/380785984_Design_and_Development_of_a_Hardware-in-the-Loop_EuroSim_Demonstrator)
|
||||
at [Airbus Netherlands](https://www.airbusdefenceandspacenetherlands.nl/).
|
||||
@@ -5,9 +5,9 @@ system reasoning for both system operators and OBSW developers. They also provid
|
||||
the behaviour of a component and also provide observability of a system. A few examples of how to
|
||||
model the mode of different components within a space system with modes will be given.
|
||||
|
||||
## Pyhsical device component with modes
|
||||
## Physical device component with modes
|
||||
|
||||
The following simple mode scheme with the following three mode
|
||||
The following simple mode scheme with the following three modes
|
||||
|
||||
- `OFF`
|
||||
- `ON`
|
||||
@@ -18,10 +18,10 @@ sensors.
|
||||
|
||||
1. `OFF` means that a device is physically switched off, and the corresponding software component
|
||||
does not poll the device regularly.
|
||||
2. `ON` means that a device is pyhsically switched on, but the device is not polled perically.
|
||||
2. `ON` means that a device is physically switched on, but the device is not polled periodically.
|
||||
3. `NORMAL` means that a device is powered on and polled periodically.
|
||||
|
||||
If a devices is `OFF`, the device handler will deny commands which include physical communication
|
||||
If a device is `OFF`, the device handler will deny commands which include physical communication
|
||||
with the connected devices. In `NORMAL` mode, it will autonomously perform periodic polling
|
||||
of a connected physical device in addition to handling remote commands by the operator.
|
||||
Using these three basic modes, there are two important transitions which need to be taken care of
|
||||
@@ -73,8 +73,6 @@ In summary, a component which has modes has to expose the following 4 capabiliti
|
||||
3. Announce the mode
|
||||
4. Announce the mode recursively
|
||||
|
||||
## Using ECSS PUS to perform mode commanding
|
||||
|
||||
# Health
|
||||
|
||||
Health is an important concept for systems and components which might fail.
|
||||
@@ -94,10 +92,8 @@ use-cases:
|
||||
2. `FAULTY` means that a component does not work properly. This might also impact other system
|
||||
components, so the passivation and isolation of that component is desirable for FDIR purposes.
|
||||
3. `NEEDS RECOVERY` is used to attempt a recovery of a component. For example, a simple sensor
|
||||
could be power-cycled if there were multiple communication issues in the last time.
|
||||
could be power-cycled if there were multiple communication issues recently.
|
||||
4. `EXTERNAL CONTROL` is used to isolate an individual component from the rest of the system. For
|
||||
example, on operator might be interested in testing a component in isolation, and the interference
|
||||
example, an operator might be interested in testing a component in isolation, and the interference
|
||||
of the system is not desired. In that case, the `EXTERNAL CONTROL` health state might be used
|
||||
to prevent mode commands from the system while allowing external mode commands.
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
# Serialization
|
||||
@@ -0,0 +1,55 @@
|
||||
# System View
|
||||
|
||||
This chapter gives a system level view of how a typical flight software built with `sat-rs`,
|
||||
[`spacepackets`](https://egit.irs.uni-stuttgart.de/rust/spacepackets) and
|
||||
[`cfdp`](https://egit.irs.uni-stuttgart.de/rust/cfdp) is layered. It complements the previous
|
||||
chapters, which focus on individual components, by showing how those components fit together
|
||||
and where the line between application and platform is usually drawn.
|
||||
|
||||
## Generic layering
|
||||
|
||||
Flight software built with `sat-rs` is generally structured into three layers.
|
||||
|
||||

|
||||
|
||||
- **Application**: The mission specific logic. This is the code a developer writes for a
|
||||
particular mission.
|
||||
- **System / platform**: The set of services the application is built on. This covers
|
||||
concepts like logging, serialization, IPC, task and memory management, hardware
|
||||
access, filesystem access and time. Most of these components are provided by external libraries
|
||||
and APIs.
|
||||
- **Hardware**: The physical target the software runs on.
|
||||
|
||||
The application layer stays largely the same across missions and targets. The system / platform
|
||||
layer is where the target environment determines which concrete crates and mechanisms are used.
|
||||
|
||||
The book has dedicated chapters for some of the topics:
|
||||
|
||||
- [TMTC handling and Serialization](./tmtc-modelling.md)
|
||||
- [Events](./events.md)
|
||||
- [Modes](./modes-and-health.md)
|
||||
|
||||
## Embedded Linux
|
||||
|
||||
On an embedded Linux target, the platform layer is provided by the Rust standard library and a
|
||||
small set of additional crates.
|
||||
|
||||

|
||||
|
||||
The application layer uses `sat-rs` together with `spacepackets` for CCSDS packet handling
|
||||
and `cfdp` for file transfer. The platform layer relies on `std` for tasks, IPC, memory, time and
|
||||
filesystem access, `serde` and `postcard` for serialization and `log`/`fern` for logging. Hardware
|
||||
access typically goes through Linux mechanisms like `uio`.
|
||||
|
||||
## Embedded async targets (Embassy / RTIC)
|
||||
|
||||
On smaller microcontrollers without an operating system, the platform layer looks quite
|
||||
different, even though the application layer stays the same.
|
||||
|
||||

|
||||
|
||||
Here the platform layer is built around an async-centric executor, either
|
||||
[Embassy](https://embassy.dev/) or [RTICv2](https://rtic.rs/). `no_std` crates like
|
||||
`heapless` and `embedded-alloc` replace `std` collections and allocation, `defmt` replaces `log`
|
||||
for logging and hardware access goes through a board support package (BSP), a hardware
|
||||
abstraction layer (HAL) and a peripheral access crate (PAC) instead of the OS.
|
||||
@@ -0,0 +1,86 @@
|
||||
# TMTC modelling using Rust
|
||||
|
||||
Before we talk about how to model telecommand and telemetry data using Rust, we are going
|
||||
to present some basic concepts and useful libraries first.
|
||||
|
||||
## Serialization
|
||||
|
||||
Serialization and deserialization is the process of converting (Rust) data structures into
|
||||
some format which can be stored or transmitted. We can use this system for generating the payload
|
||||
of our telecommand and telemetry packets. This allows us to model our payloads with Rust data
|
||||
structures, fits perfectly into the data-driven approach that Rust programs tend to favor and
|
||||
allows us to use the excellent type system.
|
||||
|
||||
The Rust ecosystem provides the [`serde`](https://serde.rs/) library for this task. The library
|
||||
makes it trivial to add serialization support to custom data structures by providing a
|
||||
[`derive`](https://serde.rs/derive.html) macro. In almost all cases, you can just add this derive
|
||||
macro to a data structure to make it serializable with any `serde` compatible serializer.
|
||||
|
||||
There are various serializers available which are well suited to the requirements of space systems.
|
||||
|
||||
- Generally, we try to minimize the payload size to save data bandwidth.
|
||||
- The data does not necessarily have to be human-readable
|
||||
|
||||
We recommend the [`postcard`](https://github.com/jamesmunns/postcard) serializer, which fulfills
|
||||
these requirements and also works well for embedded systems.
|
||||
|
||||
## Modelling telecommands and telemetry
|
||||
|
||||
Using a serializer library like `serde` allows us to do some interesting things. For example,
|
||||
let's assume you have a `Camera` object in software that you want to send some commands to.
|
||||
This object should have the following capabilities:
|
||||
|
||||
- Process a ping command
|
||||
- Capture an image
|
||||
- Send back configuration data
|
||||
|
||||
You can now model a request to your `Camera` object using the following data structure
|
||||
|
||||
```rust
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub enum CameraRequest {
|
||||
Ping,
|
||||
CaptureImage,
|
||||
RequestConfig,
|
||||
}
|
||||
```
|
||||
|
||||
This data structure models all the requests that the `Camera` provides.
|
||||
On the telemetry side, you would have a similar object
|
||||
|
||||
```rust
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub enum CameraResponse {
|
||||
Ok,
|
||||
Config(ConfigStructure)
|
||||
}
|
||||
```
|
||||
|
||||
where `ConfigStructure` would be some other wrapped configuration structure, and the `Ok` response
|
||||
would be the reply for successful execution for all other commands which do not have additional
|
||||
telemetry information.
|
||||
|
||||
Rust makes it trivial to move components into a new shared library. You can now put these data
|
||||
structures in a shared `types` or `data` library which can be re-used by both a ground system
|
||||
library and by the on-board software.
|
||||
|
||||
On the ground system, you could use a function like [`postcard::to_allocvec`](https://docs.rs/postcard/latest/postcard/fn.to_allocvec.html)
|
||||
to generate the byte representation of a `CameraRequest`, which is then sent as the payload
|
||||
inside a CCSDS space packet. On the on-board software side, you can use
|
||||
[`postcard::from_bytes`](https://docs.rs/postcard/latest/postcard/fn.from_bytes.html) to deserialize
|
||||
the `CameraRequest` from the raw payload bytes. In both cases, you do not need to hand-write
|
||||
the serialization and deserialization code anymore. The only trade-off is that you need a Rust
|
||||
conversion layer if you want to create your telecommands in another language like Python.
|
||||
|
||||
Using Rust structures like this also has other advantages. Once you have the `CameraRequest`
|
||||
structure, you can `match` on it to cover **all** commands that the device handler needs to cover.
|
||||
If you add a new variant, you have to handle it as well and you can not forget to handle a
|
||||
variant.
|
||||
|
||||
One trade-off to keep in mind is that a Rust `enum` will always have the size of its largest variant
|
||||
in memory. If you need to send large payloads to and from the on-board software, you can also
|
||||
add this data as a secondary data blob behind the primary `serde` payload, and still send something
|
||||
like small metadata as part of the payload. `postcard` can tell you the size of the deserialized
|
||||
payload which helps with determining the size of any additional payload data.
|
||||
|
||||
We recommend this approach for all TMTC definitions where you control all sides of the communication.
|
||||
Generated
-995
@@ -1,995 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "accelerometer"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a4586d95cb0695e748760c9a751141eebb68265b1b20392a0f14db608679f7a"
|
||||
dependencies = [
|
||||
"micromath",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-polyfill"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
|
||||
|
||||
[[package]]
|
||||
name = "bare-metal"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
|
||||
dependencies = [
|
||||
"rustc_version 0.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bare-metal"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603"
|
||||
|
||||
[[package]]
|
||||
name = "bitfield"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bxcan"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ac3d0c0a542d0ab5521211f873f62706a7136df415676f676d347e5a41dd80"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"embedded-hal 0.2.7",
|
||||
"nb 1.1.0",
|
||||
"vcell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a"
|
||||
dependencies = [
|
||||
"rustc_version 0.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cobs"
|
||||
version = "0.2.3"
|
||||
source = "git+https://github.com/robamu/cobs.rs.git?branch=all_features#c70a7f30fd00a7cbdb7666dec12b437977385d40"
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
|
||||
dependencies = [
|
||||
"bare-metal 0.2.5",
|
||||
"bitfield",
|
||||
"critical-section",
|
||||
"embedded-hal 0.2.7",
|
||||
"volatile-register",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m-rt"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1"
|
||||
dependencies = [
|
||||
"cortex-m-rt-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m-rt-macros"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m-semihosting"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe"
|
||||
dependencies = [
|
||||
"crc-catalog",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc-catalog"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3939552907426de152b3c2c6f51ed53f98f448babd26f28694c95f5906194595"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"defmt-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-brtt"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2f0ac3635d0c89d12b8101fcb44a7625f5f030a1c0491124b74467eb5a58a78"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"defmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-macros"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18bdc7a7b92ac413e19e95240e75d3a73a8d8e78aa24a594c22cbb4d44b4bbda"
|
||||
dependencies = [
|
||||
"defmt-parser",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-parser"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff4a5fefe330e8d7f31b16a318f9ce81000d8e35e69b93eae154d16d2278f70f"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-test"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290966e8c38f94b11884877242de876280d0eab934900e9642d58868e77c5df1"
|
||||
dependencies = [
|
||||
"cortex-m-rt",
|
||||
"cortex-m-semihosting",
|
||||
"defmt",
|
||||
"defmt-test-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-test-macros"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "984bc6eca246389726ac2826acc2488ca0fe5fcd6b8d9b48797021951d76a125"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "delegate"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ee5df75c70b95bd3aacc8e2fd098797692fb1d54121019c4de481e42f04c8a1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-dma"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446"
|
||||
dependencies = [
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
|
||||
dependencies = [
|
||||
"nb 0.1.3",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-time"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7a4b4d10ac48d08bfe3db7688c402baadb244721f30a77ce360bd24c3dffe58"
|
||||
dependencies = [
|
||||
"num",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumset"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d"
|
||||
dependencies = [
|
||||
"enumset_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumset_derive"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "fugit"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7"
|
||||
dependencies = [
|
||||
"gcd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gcd"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "667f6ea017b297ec65b8a108c6e9ad6879460721fb3b6b23abf690970147fc28"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
|
||||
dependencies = [
|
||||
"hash32",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lsm303dlhc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e5d1a5c290951321d1b0d4a40edd828537de9889134a0e67c5146542ae57706"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"embedded-hal 0.2.7",
|
||||
"generic-array 0.11.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "micromath"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc4010833aea396656c2f91ee704d51a6f1329ec2ab56ffd00bfd56f7481ea94"
|
||||
dependencies = [
|
||||
"generic-array 0.14.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
|
||||
dependencies = [
|
||||
"nb 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f"
|
||||
dependencies = [
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845"
|
||||
dependencies = [
|
||||
"num_enum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "panic-probe"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa6fa5645ef5a760cd340eaa92af9c1ce131c8c09e7f8926d8a24b59d26652b9"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"defmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtcc"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95973c3a0274adc4f3c5b70d2b5b85618d6de9559a6737d3293ecae9a2fc0839"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtic"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c443db16326376bdd64377da268f6616d5f804aba8ce799bac7d1f7f244e9d51"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"bare-metal 1.0.0",
|
||||
"cortex-m",
|
||||
"critical-section",
|
||||
"rtic-core",
|
||||
"rtic-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtic-common"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0786b50b81ef9d2a944a000f60405bb28bf30cd45da2d182f3fe636b2321f35c"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtic-core"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42"
|
||||
|
||||
[[package]]
|
||||
name = "rtic-macros"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54053598ea24b1b74937724e366558412a1777eb2680b91ef646db540982789a"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtic-monotonics"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "058c2397dbd5bb4c5650a0e368c3920953e458805ff5097a0511b8147b3619d7"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"cfg-if",
|
||||
"cortex-m",
|
||||
"embedded-hal 1.0.0",
|
||||
"fugit",
|
||||
"rtic-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtic-time"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75b232e7aebc045cfea81cdd164bc2727a10aca9a4568d406d0a5661cdfd0f19"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"futures-util",
|
||||
"rtic-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
dependencies = [
|
||||
"semver 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||
dependencies = [
|
||||
"semver 1.0.22",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "satrs"
|
||||
version = "0.2.0-rc.0"
|
||||
dependencies = [
|
||||
"cobs",
|
||||
"crc",
|
||||
"delegate",
|
||||
"num-traits",
|
||||
"num_enum",
|
||||
"paste",
|
||||
"satrs-shared",
|
||||
"smallvec",
|
||||
"spacepackets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "satrs-example-stm32f3-disco"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cobs",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"cortex-m-semihosting",
|
||||
"defmt",
|
||||
"defmt-brtt",
|
||||
"defmt-test",
|
||||
"embedded-hal 0.2.7",
|
||||
"enumset",
|
||||
"heapless",
|
||||
"panic-probe",
|
||||
"rtic",
|
||||
"rtic-monotonics",
|
||||
"satrs",
|
||||
"stm32f3-discovery",
|
||||
"stm32f3xx-hal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "satrs-shared"
|
||||
version = "0.1.3"
|
||||
dependencies = [
|
||||
"spacepackets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
dependencies = [
|
||||
"semver-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "slice-group-by"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "spacepackets"
|
||||
version = "0.11.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2cfd5f9a4c7f10714d21f9bc61f2d176cb7ae092cdd687e7ade2d4e6f7d7125"
|
||||
dependencies = [
|
||||
"crc",
|
||||
"defmt",
|
||||
"delegate",
|
||||
"num-traits",
|
||||
"num_enum",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "stm32-usbd"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6c94998f166d66b210a164648a0b7866428d8f1e0740bf8a4c5edd89d4750c1"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"usb-device",
|
||||
"vcell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stm32f3"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b28b37228ef3fa47956af38c6abd756e912f244c1657f14e66d42fc8d74ea96f"
|
||||
dependencies = [
|
||||
"bare-metal 1.0.0",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"vcell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stm32f3-discovery"
|
||||
version = "0.8.0-alpha.0"
|
||||
source = "git+https://github.com/robamu/stm32f3-discovery?branch=complete-dma-update-hal#5ccacae07ceff02d7d3649df67a6a0ba2a144752"
|
||||
dependencies = [
|
||||
"accelerometer",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"lsm303dlhc",
|
||||
"stm32f3xx-hal",
|
||||
"switch-hal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stm32f3xx-hal"
|
||||
version = "0.11.0-alpha.0"
|
||||
source = "git+https://github.com/robamu/stm32f3xx-hal?branch=complete-dma-update#04fc76b7912649c84b57bd0ab803ea3ccf2aadae"
|
||||
dependencies = [
|
||||
"bxcan",
|
||||
"cfg-if",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"critical-section",
|
||||
"embedded-dma",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-time",
|
||||
"enumset",
|
||||
"nb 1.1.0",
|
||||
"num-traits",
|
||||
"paste",
|
||||
"rtcc",
|
||||
"slice-group-by",
|
||||
"stm32-usbd",
|
||||
"stm32f3",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "switch-hal"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90a4adc8cbd1726249b161898e48e0f3f1ce74d34dc784cbbc98fba4ed283fbf"
|
||||
dependencies = [
|
||||
"embedded-hal 0.2.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "usb-device"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508"
|
||||
|
||||
[[package]]
|
||||
name = "vcell"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "volatile-register"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc"
|
||||
dependencies = [
|
||||
"vcell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
@@ -1,83 +0,0 @@
|
||||
[package]
|
||||
name = "satrs-example-stm32f3-disco"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
default-run = "satrs-example-stm32f3-disco"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
||||
cortex-m-rt = "0.7"
|
||||
defmt = "0.3"
|
||||
defmt-brtt = { version = "0.1", default-features = false, features = ["rtt"] }
|
||||
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
||||
embedded-hal = "0.2.7"
|
||||
cortex-m-semihosting = "0.5.0"
|
||||
enumset = "1"
|
||||
heapless = "0.8"
|
||||
|
||||
[dependencies.rtic]
|
||||
version = "2"
|
||||
features = ["thumbv7-backend"]
|
||||
|
||||
[dependencies.rtic-monotonics]
|
||||
version = "1"
|
||||
features = ["cortex-m-systick"]
|
||||
|
||||
[dependencies.cobs]
|
||||
git = "https://github.com/robamu/cobs.rs.git"
|
||||
branch = "all_features"
|
||||
default-features = false
|
||||
|
||||
[dependencies.stm32f3xx-hal]
|
||||
git = "https://github.com/robamu/stm32f3xx-hal"
|
||||
version = "0.11.0-alpha.0"
|
||||
features = ["stm32f303xc", "rt", "enumset"]
|
||||
branch = "complete-dma-update"
|
||||
# Can be used in workspace to develop and update HAL
|
||||
# path = "../stm32f3xx-hal"
|
||||
|
||||
[dependencies.stm32f3-discovery]
|
||||
git = "https://github.com/robamu/stm32f3-discovery"
|
||||
version = "0.8.0-alpha.0"
|
||||
branch = "complete-dma-update-hal"
|
||||
# Can be used in workspace to develop and update BSP
|
||||
# path = "../stm32f3-discovery"
|
||||
|
||||
[dependencies.satrs]
|
||||
path = "../satrs"
|
||||
default-features = false
|
||||
features = ["defmt"]
|
||||
|
||||
[dev-dependencies]
|
||||
defmt-test = "0.3"
|
||||
|
||||
# cargo test
|
||||
[profile.test]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = true # <-
|
||||
incremental = false
|
||||
opt-level = "s" # <-
|
||||
overflow-checks = true # <-
|
||||
|
||||
# cargo build/run --release
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = false # <-
|
||||
incremental = false
|
||||
lto = 'fat'
|
||||
opt-level = "s" # <-
|
||||
overflow-checks = false # <-
|
||||
|
||||
# cargo test --release
|
||||
[profile.bench]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = false # <-
|
||||
incremental = false
|
||||
lto = 'fat'
|
||||
opt-level = "s" # <-
|
||||
overflow-checks = false # <-
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,10 +0,0 @@
|
||||
target extended-remote localhost:2331
|
||||
|
||||
monitor reset
|
||||
|
||||
# *try* to stop at the user entry point (it might be gone due to inlining)
|
||||
break main
|
||||
|
||||
load
|
||||
|
||||
continue
|
||||
@@ -1,12 +0,0 @@
|
||||
# Sample OpenOCD configuration for the STM32F3DISCOVERY development board
|
||||
|
||||
# Depending on the hardware revision you got you'll have to pick ONE of these
|
||||
# interfaces. At any time only one interface should be commented out.
|
||||
|
||||
# Revision C (newer revision)
|
||||
source [find interface/stlink.cfg]
|
||||
|
||||
# Revision A and B (older revisions)
|
||||
# source [find interface/stlink-v2.cfg]
|
||||
|
||||
source [find target/stm32f3x.cfg]
|
||||
@@ -1,42 +0,0 @@
|
||||
target extended-remote :3333
|
||||
|
||||
# print demangled symbols
|
||||
set print asm-demangle on
|
||||
|
||||
# set backtrace limit to not have infinite backtrace loops
|
||||
set backtrace limit 32
|
||||
|
||||
# detect unhandled exceptions, hard faults and panics
|
||||
break DefaultHandler
|
||||
break HardFault
|
||||
break rust_begin_unwind
|
||||
# # run the next few lines so the panic message is printed immediately
|
||||
# # the number needs to be adjusted for your panic handler
|
||||
# commands $bpnum
|
||||
# next 4
|
||||
# end
|
||||
|
||||
# *try* to stop at the user entry point (it might be gone due to inlining)
|
||||
break main
|
||||
|
||||
# monitor arm semihosting enable
|
||||
|
||||
# # send captured ITM to the file itm.fifo
|
||||
# # (the microcontroller SWO pin must be connected to the programmer SWO pin)
|
||||
# # 8000000 must match the core clock frequency
|
||||
# # 2000000 is the frequency of the SWO pin. This was added for newer
|
||||
# openocd versions like v0.12.0.
|
||||
# monitor tpiu config internal itm.txt uart off 8000000 2000000
|
||||
|
||||
# # OR: make the microcontroller SWO pin output compatible with UART (8N1)
|
||||
# # 8000000 must match the core clock frequency
|
||||
# # 2000000 is the frequency of the SWO pin
|
||||
# monitor tpiu config external uart off 8000000 2000000
|
||||
|
||||
# # enable ITM port 0
|
||||
# monitor itm port 0 on
|
||||
|
||||
load
|
||||
|
||||
# start the process but immediately halt the processor
|
||||
stepi
|
||||
@@ -1,33 +0,0 @@
|
||||
/* Linker script for the STM32F303VCT6 */
|
||||
MEMORY
|
||||
{
|
||||
/* NOTE 1 K = 1 KiBi = 1024 bytes */
|
||||
FLASH : ORIGIN = 0x08000000, LENGTH = 256K
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 40K
|
||||
}
|
||||
|
||||
/* This is where the call stack will be allocated. */
|
||||
/* The stack is of the full descending type. */
|
||||
/* You may want to use this variable to locate the call stack and static
|
||||
variables in different memory regions. Below is shown the default value */
|
||||
/* _stack_start = ORIGIN(RAM) + LENGTH(RAM); */
|
||||
|
||||
/* You can use this symbol to customize the location of the .text section */
|
||||
/* If omitted the .text section will be placed right after the .vector_table
|
||||
section */
|
||||
/* This is required only on microcontrollers that store some configuration right
|
||||
after the vector table */
|
||||
/* _stext = ORIGIN(FLASH) + 0x400; */
|
||||
|
||||
/* Example of putting non-initialized variables into custom RAM locations. */
|
||||
/* This assumes you have defined a region RAM2 above, and in the Rust
|
||||
sources added the attribute `#[link_section = ".ram2bss"]` to the data
|
||||
you want to place there. */
|
||||
/* Note that the section will not be zero-initialized by the runtime! */
|
||||
/* SECTIONS {
|
||||
.ram2bss (NOLOAD) : ALIGN(4) {
|
||||
*(.ram2bss);
|
||||
. = ALIGN(4);
|
||||
} > RAM2
|
||||
} INSERT AFTER .bss;
|
||||
*/
|
||||
@@ -1,8 +0,0 @@
|
||||
/venv
|
||||
/.tmtc-history.txt
|
||||
/log
|
||||
/.idea/*
|
||||
!/.idea/runConfigurations
|
||||
|
||||
/seqcnt.txt
|
||||
/tmtc_conf.json
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"com_if": "serial_cobs",
|
||||
"serial_baudrate": 115200
|
||||
}
|
||||
Loaded 100 of 273 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user