Compare commits
378
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 | ||
|
|
282f799203 | ||
|
|
46dbb4309b
|
||
|
|
42d1257e83
|
||
|
|
583f6ce4d2 | ||
|
|
408803fe86
|
||
|
|
9ffe4d0ae0 | ||
|
|
e37061dcf0
|
||
|
|
3a2ac11407 | ||
|
|
23327a7786
|
||
|
|
89d5a1022f | ||
|
|
a00c843698
|
||
|
|
c586fd7fef | ||
|
|
7e78e70a17
|
||
|
|
424dfc439c | ||
|
|
45eb2f1343
|
||
|
|
736eb74e66
|
||
|
|
29f71c2a57 | ||
|
|
f0d08b65a4 | ||
|
|
c7a74a844c | ||
|
|
9c60427f89 | ||
|
|
958ab9bab6
|
||
|
|
312849bddb | ||
|
|
b0159a3ba7
|
||
|
|
c477739f6d
|
||
|
|
b7ce039406
|
||
|
|
4736d40997 | ||
|
|
5ec5124ea3
|
||
|
|
5e43259d4f | ||
|
|
bfaddd0ebb | ||
|
|
423a068736 | ||
|
|
8022af1bf2 | ||
|
|
acd2260dfd | ||
|
|
e5ee698dc4 | ||
|
|
e8907c74d4
|
||
|
|
536051e05b | ||
|
|
701db659e9 | ||
|
|
4b8e54b91b
|
||
|
|
870d60cfd6 | ||
|
|
9e62e4292c
|
||
|
|
b2e77fbc09 | ||
|
|
5371928496
|
||
|
|
31cddbd99b | ||
|
|
7c00e13e70 | ||
|
|
aa72063454 | ||
|
|
7b37b76695 | ||
|
|
ea5d95c12d | ||
|
|
c62adbb300 | ||
|
|
9242b8a607 | ||
|
|
4a27d2605d
|
||
|
|
8195245481
|
||
|
|
f6f7519625 | ||
|
|
0f0fbc1a18
|
||
|
|
6e55e2ac95 | ||
|
|
2f96bfe992
|
||
|
|
52aafb3aab
|
||
|
|
6ce9cb5ead | ||
|
|
273f79d1e6
|
||
|
|
622221835e | ||
|
|
e396ad2e7a
|
||
|
|
772927d50b
|
||
|
|
be9a45e55f | ||
|
|
eee8a69550
|
||
|
|
f7a6d3ce47 | ||
|
|
df97a3a93e
|
||
|
|
42750e08c0
|
||
|
|
786671bbd7 | ||
|
|
63f37f0917 | ||
|
|
8cfe3b81e7 | ||
|
|
de50bec562
|
||
|
|
39ab9fa27b | ||
|
|
1dbc81a8f5
|
||
|
|
1ad74ee1d5 | ||
|
|
f96fe6bdc0
|
||
|
|
d43a8eb571 | ||
|
|
0bbada90ef | ||
|
|
3375780e00 | ||
|
|
de028ed827
|
||
|
|
d27ac5dfc9
|
||
|
|
c67b7cb93a
|
||
|
|
f71ba3e8d8 | ||
|
|
975cd927f4 | ||
|
|
3cc9dd3c48 | ||
|
|
0fec994028 | ||
|
|
226a134aff
|
||
|
|
aac59ec7c1 | ||
|
|
ce7eb8650f | ||
|
|
df2733a176
|
||
|
|
344fe6a4c0 | ||
|
|
a5941751d7
|
||
|
|
977e29894b | ||
|
|
dd1417a368
|
||
|
|
3195cf5111
|
||
|
|
8280c70682 | ||
|
|
19c5aa9b83
|
||
|
|
713b4e097b
|
||
|
|
9039c1b59a | ||
|
|
746b31ec5d | ||
|
|
2318cd4293
|
||
|
|
a6b57d3eb9 | ||
|
|
bddd3132d4 | ||
|
|
6a6ffba754 | ||
|
|
d27a41e4de | ||
|
|
972bf19188
|
||
|
|
9d711d2b73
|
||
|
|
d0005cdd63
|
||
|
|
f00e6cf50c
|
||
|
|
128df9a813 | ||
|
|
7387be3bc3
|
||
|
|
d3fb504545
|
||
|
|
ae8e39f626
|
||
|
|
ab3d907d4e | ||
|
|
3de5954898
|
||
|
|
5600aa576c | ||
|
|
88793cfa87
|
||
|
|
223b637eb8
|
||
|
|
cf9b115e1e | ||
|
|
eea9b11b39
|
||
|
|
f21ab0017e | ||
|
|
a7ca00317f
|
||
|
|
75fda42f4f
|
||
|
|
faf0f6f6c6 | ||
|
|
a690c7720d | ||
|
|
b48b5b8caa | ||
|
|
238c3a8d43 | ||
|
|
de8c0bc13e | ||
|
|
012eb82f42
|
||
|
|
d26f6cbe27 | ||
|
|
82d3215761
|
||
|
|
2b80244636
|
||
|
|
f1611cd5b8 | ||
|
|
808126ee41 | ||
|
|
05df24447b | ||
|
|
b229360233 | ||
|
|
52be26829b | ||
|
|
ca2c8aa359 | ||
|
|
ba03150178 | ||
|
|
4e45bfa7e6 | ||
|
|
93c01c8c22
|
||
|
|
2d062f3010 | ||
|
|
01d9a85976 | ||
|
|
fa7cd39f3e | ||
|
|
5bb37d8e87 | ||
|
|
813e221030 | ||
|
|
18cec8bcf0 | ||
|
|
d4a122e462 | ||
|
|
7af327d077 | ||
|
|
3a6cd6712d | ||
|
|
c4eba03043 | ||
|
|
e9e5c999ec | ||
|
|
f14a85cb84 | ||
|
|
c3902c2c06 | ||
|
|
24f82d4c5e | ||
|
|
44ff62e947 | ||
|
|
9cf80b44ea | ||
|
|
f4bc33aefa |
No files matched your search
@@ -0,0 +1,75 @@
|
||||
name: ci
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Check build
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- 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
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- 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 --all-features
|
||||
|
||||
cross-check:
|
||||
name: Check Cross-Compilation
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target:
|
||||
- armv7-unknown-linux-gnueabihf
|
||||
- thumbv7em-none-eabihf
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: "armv7-unknown-linux-gnueabihf, thumbv7em-none-eabihf"
|
||||
- run: cargo check -p satrs --target=${{matrix.target}} --no-default-features
|
||||
|
||||
fmt:
|
||||
name: Check formatting
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: rustfmt
|
||||
- run: cargo fmt --all -- --check
|
||||
|
||||
docs:
|
||||
name: Check Documentation Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- run: RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc -p satrs --all-features --no-deps
|
||||
|
||||
clippy:
|
||||
name: Clippy
|
||||
runs-on: ubuntu-latest
|
||||
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
|
||||
+6
-1
@@ -1,5 +1,10 @@
|
||||
/target
|
||||
target/
|
||||
|
||||
output.log
|
||||
/Cargo.lock
|
||||
output.log
|
||||
|
||||
output.log
|
||||
|
||||
/.idea/*
|
||||
!/.idea/runConfigurations
|
||||
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
-2
@@ -4,10 +4,16 @@ members = [
|
||||
"satrs",
|
||||
"satrs-mib",
|
||||
"satrs-example",
|
||||
"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,13 +1,23 @@
|
||||
<p align="center"> <img src="misc/satrs-logo.png" width="40%"> </p>
|
||||
<p align="center"> <img src="misc/satrs-logo-v2.png" width="40%"> </p>
|
||||
|
||||
[](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
|
||||
=========
|
||||
|
||||
This is the repository of the sat-rs framework. Its primary goal is to provide re-usable components
|
||||
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 documentation website](https://absatsw.irs.uni-stuttgart.de/sat-rs.html).
|
||||
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
|
||||
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
|
||||
[FSFW](https://egit.irs.uni-stuttgart.de/fsfw/fsfw) C++ framework which has flight heritage
|
||||
@@ -20,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):
|
||||
Example of a simple example on-board software using sat-rs components on a bare-metal system
|
||||
with constrained resources.
|
||||
* [`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. 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-core`](https://egit.irs.uni-stuttgart.de/rust/satrs-launchpad/src/branch/main/satrs-core)
|
||||
[`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
|
||||
|
||||
@@ -54,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
@@ -33,6 +33,7 @@ pipeline {
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh 'cargo nextest r --all-features'
|
||||
sh 'cargo test --doc --all-features'
|
||||
}
|
||||
}
|
||||
stage('Check with all features') {
|
||||
|
||||
+8
-4
@@ -18,15 +18,19 @@ def generate_cov_report(open_report: bool, format: str, package: str):
|
||||
out_path = "./target/debug/coverage"
|
||||
if format == "lcov":
|
||||
out_path = "./target/debug/lcov.info"
|
||||
os.system(
|
||||
grcov_cmd = (
|
||||
f"grcov . -s . --binary-path ./target/debug/ -t {format} --branch --ignore-not-existing "
|
||||
f"-o {out_path}"
|
||||
)
|
||||
print(f"Running: {grcov_cmd}")
|
||||
os.system(grcov_cmd)
|
||||
if format == "lcov":
|
||||
os.system(
|
||||
lcov_cmd = (
|
||||
"genhtml -o ./target/debug/coverage/ --show-details --highlight --ignore-errors source "
|
||||
"--legend ./target/debug/lcov.info"
|
||||
)
|
||||
print(f"Running: {lcov_cmd}")
|
||||
os.system(lcov_cmd)
|
||||
if open_report:
|
||||
coverage_report_path = os.path.abspath("./target/debug/coverage/index.html")
|
||||
webbrowser.open_new_tab(coverage_report_path)
|
||||
@@ -43,8 +47,8 @@ def main():
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--package",
|
||||
choices=["satrs-core"],
|
||||
default="satrs-core",
|
||||
choices=["satrs", "satrs-minisim", "satrs-example"],
|
||||
default="satrs",
|
||||
help="Choose project to generate coverage for",
|
||||
)
|
||||
parser.add_argument(
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
# uncomment ONE of these three option to make `cargo run` start a GDB session
|
||||
# which option to pick depends on your system
|
||||
# You can also replace openocd.gdb by jlink.gdb when using a J-Link.
|
||||
# runner = "arm-none-eabi-gdb -q -x openocd.gdb"
|
||||
# runner = "gdb-multiarch -q -x openocd.gdb"
|
||||
# runner = "gdb -q -x openocd.gdb"
|
||||
runner = "probe-rs run --chip STM32F303VCTx"
|
||||
|
||||
rustflags = [
|
||||
"-C", "linker=flip-link",
|
||||
# LLD (shipped with the Rust toolchain) is used as the default linker
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
"-C", "link-arg=-Tdefmt.x",
|
||||
|
||||
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
|
||||
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
|
||||
"-C", "link-arg=--nmagic",
|
||||
|
||||
# if you run into problems with LLD switch to the GNU linker by commenting out
|
||||
# this line
|
||||
# "-C", "linker=arm-none-eabi-ld",
|
||||
|
||||
# if you need to link to pre-compiled C libraries provided by a C toolchain
|
||||
# use GCC as the linker by commenting out both lines above and then
|
||||
# uncommenting the three lines below
|
||||
# "-C", "linker=arm-none-eabi-gcc",
|
||||
# "-C", "link-arg=-Wl,-Tlink.x",
|
||||
# "-C", "link-arg=-nostartfiles",
|
||||
]
|
||||
|
||||
[build]
|
||||
# comment out the following line if you intend to run unit tests on host machine
|
||||
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
||||
|
||||
[env]
|
||||
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.
@@ -0,0 +1,114 @@
|
||||
sat-rs example for the STM32F3-Discovery 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 STM32F3-Discovery device was picked because it is a cheap Cortex-M4 based device which is also
|
||||
used by the [Rust Embedded Book](https://docs.rust-embedded.org/book/intro/hardware.html) and the
|
||||
[Rust Discovery](https://docs.rust-embedded.org/discovery/f3discovery/) book as an introduction
|
||||
to embedded Rust.
|
||||
|
||||
## 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 STM32F303VCTx
|
||||
```
|
||||
|
||||
## 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.
|
||||
@@ -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.
+2
-2
@@ -5,8 +5,8 @@
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
"rust-lang.rust",
|
||||
"marus25.cortex-debug",
|
||||
"probe-rs.probe-rs-debugger"
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": []
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"preLaunchTask": "${defaultBuildTask}",
|
||||
"type": "probe-rs-debug",
|
||||
"request": "launch",
|
||||
"name": "probe-rs Debugging ",
|
||||
"flashingConfig": {
|
||||
"flashingEnabled": true
|
||||
},
|
||||
"chip": "STM32F303VCTx",
|
||||
"coreConfigs": [
|
||||
{
|
||||
"programBinary": "${workspaceFolder}/target/thumbv7em-none-eabihf/debug/satrs-stm32f3-disco-rtic",
|
||||
"rttEnabled": true,
|
||||
"svdFile": "STM32F303.svd"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+2
-1
@@ -11,7 +11,8 @@ proc CDSWOConfigure { CDCPUFreqHz CDSWOFreqHz CDSWOOutput } {
|
||||
# Alternative option: Pipe ITM output into itm.txt file
|
||||
# tpiu config internal itm.txt uart off $CDCPUFreqHz
|
||||
|
||||
# Default option so SWO display of VS code works.
|
||||
# Default option so SWO display of VS code works. Please note that this might not be required
|
||||
# anymore starting at openocd v0.12.0
|
||||
tpiu config internal $CDSWOOutput uart off $CDCPUFreqHz $CDSWOFreqHz
|
||||
itm port 0 on
|
||||
}
|
||||
File renamed without changes.
+2
-1
@@ -1,3 +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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
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
|
||||
// this prevents the panic message being printed *twice* when `defmt::panic` is invoked
|
||||
#[defmt::panic_handler]
|
||||
fn panic() -> ! {
|
||||
cortex_m::asm::udf()
|
||||
}
|
||||
|
||||
/// 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) -> ! {
|
||||
panic!("unexpected hard fault");
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
@@ -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 |
@@ -0,0 +1,650 @@
|
||||
<?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.23.2-->
|
||||
<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"/>
|
||||
<node id="n0">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="157.79999999999998" width="452.0" x="959.3461887999997" y="585.7236400000005"/>
|
||||
<y:Fill color2="#000000" 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="145.0" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="434.0" x="9.0" xml:space="preserve" y="6.399999999999977"><html>
|
||||
<center>
|
||||
<h4>ACS Mode Tree</h4>
|
||||
</center>
|
||||
|
||||
<table border="1">
|
||||
<tr>
|
||||
<th>Mode</th>
|
||||
<th>MGMs</th>
|
||||
<th>SUSs</th>
|
||||
<th>STR</th>
|
||||
<th>MGT</th>
|
||||
<th>RWs</th>
|
||||
<th>ACS CTRL</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>OFF</td>
|
||||
<td>OFF</td>
|
||||
<td>OFF</td>
|
||||
<td>OFF</td>
|
||||
<td>OFF</td>
|
||||
<td>OFF</td>
|
||||
<td>OFF</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>SAFE</td>
|
||||
<td>NORMAL</td>
|
||||
<td>NORMAL</td>
|
||||
<td>OFF</td>
|
||||
<td>OFF</td>
|
||||
<td>NORMAL</td>
|
||||
<td>SAFE</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>IDLE</td>
|
||||
<td>NORMAL</td>
|
||||
<td>NORMAL</td>
|
||||
<td>NORMAL</td>
|
||||
<td>NORMAL</td>
|
||||
<td>NORMAL</td>
|
||||
<td>IDLE</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</html><y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="-1.1102230246251565E-16" 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="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="134.60000000000014" width="452.0" x="959.3461887999997" y="757.2703199999999"/>
|
||||
<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="120.0" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="428.0" x="12.0" xml:space="preserve" y="7.300000000000068"><html>
|
||||
<center>
|
||||
<h4>ACS IDLE Sequence</h4>
|
||||
</center>
|
||||
|
||||
<table border="1">
|
||||
<tr>
|
||||
<th>Step</th>
|
||||
<th>MGMs</th>
|
||||
<th>SUS</th>
|
||||
<th>STR</th>
|
||||
<th>MGT</th>
|
||||
<th>RWs</th>
|
||||
<th>ACS CTRL</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>NORMAL</td>
|
||||
<td>NORMAL</td>
|
||||
<td>NORMAL</td>
|
||||
<td>NORMAL</td>
|
||||
<td>NORMAL</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>SAFE</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</html><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="n2">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="32.400000000000034" width="146.79999999999995" x="1128.4" y="313.94999999999993"/>
|
||||
<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="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.296875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="113.94921875" x="16.42539062500009" xml:space="preserve" y="6.0515625000000455">ACS Subsystem<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="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="40.0" width="80.39999999999998" x="910.7200000000004" y="407.20000000000005"/>
|
||||
<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="31.9375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="61.837890625" x="9.281054687499932" xml:space="preserve" y="4.03125">MGM
|
||||
Assembly<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="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="32.400000000000034" width="146.79999999999995" x="1133.6000000000001" y="243.3579999999999"/>
|
||||
<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="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.296875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="117.99609375" x="14.401953124999864" xml:space="preserve" y="6.051562499999989">Satellite System<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="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="40.0" width="72.40000000000009" x="1021.1200000000003" y="404.99560000000014"/>
|
||||
<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="31.9375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="61.837890625" x="5.2810546875000455" xml:space="preserve" y="4.03125">SUS
|
||||
Assembly<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="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="40.0" width="67.59999999999991" x="1124.92" y="404.99560000000014"/>
|
||||
<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="31.9375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="56.599609375" x="5.5001953124999545" xml:space="preserve" y="4.03125">STR
|
||||
Manager<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="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="40.0" width="67.59999999999991" x="1208.74" y="407.20000000000005"/>
|
||||
<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="31.9375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="56.599609375" x="5.5001953124999545" xml:space="preserve" y="4.03125">MGT
|
||||
Manager<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="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="40.0" width="72.40000000000009" x="1292.56" y="407.20000000000005"/>
|
||||
<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="31.9375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="61.837890625" x="5.2810546875000455" xml:space="preserve" y="4.03125">RW
|
||||
Assembly<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="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="40.0" width="67.59999999999991" x="1381.18" y="407.20000000000005"/>
|
||||
<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="31.9375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="34.732421875" x="16.433789062499955" xml:space="preserve" y="4.03125">ACS
|
||||
CTRL<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="n10">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="20.0" width="44.719999999999914" x="946.4000000000004" y="463.3000000000002"/>
|
||||
<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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="41.640625" x="1.5396874999999" xml:space="preserve" y="1.0156250000000568">MGM0<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="n11">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="20.0" width="44.719999999999914" x="946.4000000000004" y="491.32480000000066"/>
|
||||
<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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="41.640625" x="1.5396874999999" xml:space="preserve" y="1.015625">MGM1<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="n12">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="20.0" width="44.719999999999914" x="946.4000000000004" y="519.3496000000011"/>
|
||||
<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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="41.640625" x="1.5396874999999" xml:space="preserve" y="1.015625">MGM2<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="n13">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="20.0" width="44.719999999999914" x="1055.2600000000007" y="463.3000000000002"/>
|
||||
<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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="35.65234375" x="4.5338281249999" xml:space="preserve" y="1.015625">SUS0<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="n14">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="20.0" width="44.719999999999914" x="1055.2600000000007" y="491.32480000000066"/>
|
||||
<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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="15.443359375" x="14.6383203124999" xml:space="preserve" y="1.015625">...<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="n15">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="20.0" width="44.719999999999914" x="1055.2600000000007" y="519.3496000000011"/>
|
||||
<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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="43.287109375" x="0.7164453124999" xml:space="preserve" y="1.015625">SUS12<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="n16">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="40.0" width="50.0" x="1129.9800000000005" y="482.79120000000023"/>
|
||||
<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="31.9375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="45.0390625" x="2.48046875" xml:space="preserve" y="4.03125">STR
|
||||
Device<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="n17">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="40.0" width="50.0" x="1216.4400000000005" y="482.7912000000002"/>
|
||||
<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="31.9375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="45.0390625" x="2.48046875" xml:space="preserve" y="4.031249999999943">MGT
|
||||
Device<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="n18">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="20.0" width="44.719999999999914" x="1341.6661887999999" y="454.7884800000007"/>
|
||||
<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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="31.837890625" x="6.4410546874999" xml:space="preserve" y="1.015625">RW0<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="n19">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="20.0" width="44.719999999999914" x="1341.6661887999999" y="482.3769600000013"/>
|
||||
<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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="31.837890625" x="6.4410546874999" xml:space="preserve" y="1.015625">RW1<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="n20">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="20.0" width="44.719999999999914" x="1341.6661887999999" y="512.3769600000013"/>
|
||||
<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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="31.837890625" x="6.4410546874999" xml:space="preserve" y="1.015625">RW2<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="n21">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="20.0" width="44.719999999999914" x="1341.6661887999999" y="542.3769600000013"/>
|
||||
<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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="31.837890625" x="6.4410546874999" xml:space="preserve" y="1.015625">RW3<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="n22">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="32.400000000000034" width="59.75999999999999" x="1305.2" y="313.94999999999993"/>
|
||||
<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="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.296875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="17.3505859375" x="21.20470703125011" xml:space="preserve" y="6.051562499999989">...<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="n4" target="n2">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-5.199999999999818" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<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="n2" target="n3">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-1.1700000000000728" sy="0.0" tx="0.0" ty="0.0">
|
||||
<y:Point x="1200.63" y="379.7"/>
|
||||
<y:Point x="950.9200000000003" y="379.7"/>
|
||||
</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="n2" target="n5">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-1.1700000000000728" sy="0.0" tx="0.0" ty="0.0">
|
||||
<y:Point x="1200.63" y="379.7"/>
|
||||
<y:Point x="1057.3200000000004" y="379.7"/>
|
||||
</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="e3" source="n2" target="n6">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-1.1700000000000728" sy="0.0" tx="0.0" ty="0.0">
|
||||
<y:Point x="1200.63" y="379.7"/>
|
||||
<y:Point x="1158.72" y="379.7"/>
|
||||
</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="e4" source="n2" target="n7">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-1.1700000000000728" sy="0.0" tx="-11.29999999999859" ty="0.0">
|
||||
<y:Point x="1200.63" y="379.7"/>
|
||||
<y:Point x="1231.2400000000014" y="379.7"/>
|
||||
</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="n2" target="n8">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-1.1700000000000728" sy="0.0" tx="0.0" ty="0.0">
|
||||
<y:Point x="1200.63" y="379.7"/>
|
||||
<y:Point x="1328.76" y="379.7"/>
|
||||
</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="n9">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-1.1700000000000728" sy="0.0" tx="0.0" ty="0.0">
|
||||
<y:Point x="1200.63" y="379.7"/>
|
||||
<y:Point x="1414.98" y="379.7"/>
|
||||
</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="e7" source="n3" target="n10">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-28.009798234586242" sy="0.0" tx="13.11999999999989" ty="0.0">
|
||||
<y:Point x="922.9102017654141" y="473.3000000000002"/>
|
||||
</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="e8" source="n3" target="n11">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-28.009798234586242" sy="17.706497359551577" tx="0.0" ty="0.0">
|
||||
<y:Point x="922.9102017654141" y="501.32480000000066"/>
|
||||
</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="e9" source="n3" target="n12">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-28.009798234586242" sy="12.053248679775777" tx="0.0" ty="0.0">
|
||||
<y:Point x="922.9102017654141" y="529.3496000000011"/>
|
||||
</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="e10" source="n5" target="n13">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-24.18711646917177" sy="11.599696230174459" tx="-20.855199999999513" ty="-1.9751999999995178">
|
||||
<y:Point x="1033.1328835308286" y="471.32480000000066"/>
|
||||
</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="e11" source="n5" target="n14">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-24.18711646917177" sy="0.0" tx="-20.855199999999513" ty="-3.024800000000596">
|
||||
<y:Point x="1033.1328835308286" y="498.30000000000007"/>
|
||||
</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="e12" source="n6" target="n16">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="3.7399999999995543" ty="0.0"/>
|
||||
<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="e13" source="n7" target="n17">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="1.0999999999994543" ty="0.0"/>
|
||||
<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="e14" source="n8" target="n18">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-23.248152938343992" sy="14.026599270174415" tx="-13.026188800000227" ty="0.33167708069714763">
|
||||
<y:Point x="1305.511847061656" y="465.1201570806978"/>
|
||||
</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="e15" source="n8" target="n19">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-23.248152938343992" sy="0.0" tx="-13.026188800000227" ty="0.0">
|
||||
<y:Point x="1305.511847061656" y="492.3769600000013"/>
|
||||
</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="e16" source="n8" target="n20">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-23.248152938343992" sy="0.0" tx="-13.026188800000227" ty="0.0">
|
||||
<y:Point x="1305.511847061656" y="522.3769600000013"/>
|
||||
</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="e17" source="n8" target="n21">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-23.248152938343992" sy="0.0" tx="-13.026188800000227" ty="-1.1368683772161603E-13">
|
||||
<y:Point x="1305.511847061656" y="552.3769600000012"/>
|
||||
</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="e18" source="n4" target="n22">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-5.199999999999818" sy="16.200000000000045" tx="0.0" ty="0.0">
|
||||
<y:Point x="1201.8000000000002" y="290.43031999999994"/>
|
||||
<y:Point x="1335.08" y="290.43031999999994"/>
|
||||
</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="e19" source="n5" target="n15">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-24.18711646917177" sy="0.0" tx="-20.855199999999513" ty="0.0">
|
||||
<y:Point x="1033.1328835308286" y="529.3496000000011"/>
|
||||
</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>
|
||||
</graph>
|
||||
<data key="d7">
|
||||
<y:Resources/>
|
||||
</data>
|
||||
</graphml>
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,285 @@
|
||||
<?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.23.2-->
|
||||
<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="261.7582999999998" width="631.1152000000001" x="810.8848" y="142.00000000000003"/>
|
||||
<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="22.625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="296.09375" x="26.51035059931519" xml:space="preserve" y="9.42072533356739">satrs-example Component Structure<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="-0.5" labelRatioY="-0.5" nodeRatioX="-0.4579944349315068" nodeRatioY="-0.46400983146067415" 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" yfiles.foldertype="group">
|
||||
<data key="d4" xml:space="preserve"/>
|
||||
<data key="d6">
|
||||
<y:ProxyAutoBoundsNode>
|
||||
<y:Realizers active="0">
|
||||
<y:GroupNode>
|
||||
<y:Geometry height="217.68500000000003" width="166.9147999999998" x="819.9999999999999" y="180.434265625"/>
|
||||
<y:Fill hasColor="false" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="left" autoSizePolicy="node_width" borderDistance="5.0" 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="166.9147999999998" x="13.181757989188668" xml:space="preserve" y="6.728692946816665">Application
|
||||
Components<y:LabelModel><y:SmartNodeLabelModel distance="5.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.4210270270270303" labelRatioY="-0.5" nodeRatioX="0.5" nodeRatioY="-0.46908977216245173" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
|
||||
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
|
||||
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="39" topF="38.90500000000003"/>
|
||||
</y:GroupNode>
|
||||
<y:GroupNode>
|
||||
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
|
||||
<y:Fill color="#F5F5F5" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.4609375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="65.201171875" x="-7.6005859375" xml:space="preserve" y="0.0">Folder 3</y:NodeLabel>
|
||||
<y:Shape type="roundrectangle"/>
|
||||
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
|
||||
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
|
||||
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
|
||||
</y:GroupNode>
|
||||
</y:Realizers>
|
||||
</y:ProxyAutoBoundsNode>
|
||||
</data>
|
||||
<graph edgedefault="directed" id="n1:">
|
||||
<node id="n1::n0">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="30.0" width="136.9147999999998" x="834.9999999999999" y="234.33926562500002"/>
|
||||
<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="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.296875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="113.94921875" x="11.482790624999893" xml:space="preserve" y="4.851562500000028">ACS Subsystem<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::n1">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="30.0" width="136.9147999999998" x="834.9999999999999" y="270.5687968750001"/>
|
||||
<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="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.296875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="111.884765625" x="12.515017187499893" xml:space="preserve" y="4.8515625">EPS Subsystem<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::n2">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="30.0" width="136.9147999999998" x="834.9999999999999" y="306.84403125000006"/>
|
||||
<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="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.296875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="112.923828125" x="11.995485937499893" xml:space="preserve" y="4.8515625">TCS Subsystem<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::n3">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="40.0" width="136.9147999999998" x="834.9999999999999" y="343.119265625"/>
|
||||
<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="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.59375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="81.259765625" x="27.827517187499893" xml:space="preserve" y="1.703125">Payload
|
||||
Subsystem<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>
|
||||
</graph>
|
||||
</node>
|
||||
<node id="n2" yfiles.foldertype="group">
|
||||
<data key="d4" xml:space="preserve"/>
|
||||
<data key="d6">
|
||||
<y:ProxyAutoBoundsNode>
|
||||
<y:Realizers active="0">
|
||||
<y:GroupNode>
|
||||
<y:Geometry height="261.7582999999998" width="498.25116669136776" x="971.9147999999997" y="151.36096562500023"/>
|
||||
<y:Fill hasColor="false" transparent="false"/>
|
||||
<y:BorderStyle hasColor="false" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="right" autoSizePolicy="content" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" hasText="false" height="4.0" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="false" width="4.0" x="247.12558334568382" y="0.0"/>
|
||||
<y:Shape type="roundrectangle"/>
|
||||
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
|
||||
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
|
||||
<y:BorderInsets bottom="0" bottomF="0.0" left="7" leftF="7.00529999999992" right="3" rightF="3.313607121059931" top="14" topF="14.073299999999762"/>
|
||||
</y:GroupNode>
|
||||
<y:GroupNode>
|
||||
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
|
||||
<y:Fill color="#F5F5F5" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.4609375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="65.201171875" x="-7.6005859375" xml:space="preserve" y="0.0">Folder 4</y:NodeLabel>
|
||||
<y:Shape type="roundrectangle"/>
|
||||
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
|
||||
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
|
||||
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
|
||||
</y:GroupNode>
|
||||
</y:Realizers>
|
||||
</y:ProxyAutoBoundsNode>
|
||||
</data>
|
||||
<graph edgedefault="directed" id="n2:">
|
||||
<node id="n2::n0" yfiles.foldertype="group">
|
||||
<data key="d4" xml:space="preserve"/>
|
||||
<data key="d6">
|
||||
<y:ProxyAutoBoundsNode>
|
||||
<y:Realizers active="0">
|
||||
<y:GroupNode>
|
||||
<y:Geometry height="217.68500000000003" width="441.0158999999999" x="993.9200999999996" y="180.434265625"/>
|
||||
<y:Fill hasColor="false" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="left" autoSizePolicy="node_width" borderDistance="5.0" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="441.0158999999999" x="16.916359570308032" xml:space="preserve" y="5.969557999968089">Generic Components<y:LabelModel><y:SmartNodeLabelModel distance="5.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.46164229096885634" labelRatioY="-0.5" nodeRatioX="0.5" nodeRatioY="-0.4725770815629552" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
|
||||
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
|
||||
<y:BorderInsets bottom="22" bottomF="22.006468749999954" left="0" leftF="0.0" right="0" rightF="0.0" top="28" topF="27.68500000000006"/>
|
||||
</y:GroupNode>
|
||||
<y:GroupNode>
|
||||
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
|
||||
<y:Fill color="#F5F5F5" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.4609375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="65.201171875" x="-7.6005859375" xml:space="preserve" y="0.0">Folder 2</y:NodeLabel>
|
||||
<y:Shape type="roundrectangle"/>
|
||||
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
|
||||
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
|
||||
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
|
||||
</y:GroupNode>
|
||||
</y:Realizers>
|
||||
</y:ProxyAutoBoundsNode>
|
||||
</data>
|
||||
<graph edgedefault="directed" id="n2::n0:">
|
||||
<node id="n2::n0::n0">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<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="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>
|
||||
</node>
|
||||
<node id="n2::n0::n1">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="30.0" width="125.0" x="1151.9280499999995" y="330.5687968750001"/>
|
||||
<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="105.7119140625" x="9.64404296875" xml:space="preserve" y="4.8515625">TCP/IP Servers<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="n2::n0::n2">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="30.0" width="125.0" x="1294.9359999999995" 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="75.1689453125" x="24.91552734375" xml:space="preserve" y="4.8515625">TC Source<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="n2::n0::n3">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="30.0" width="125.0" x="1008.9200999999996" y="223.11926562500005"/>
|
||||
<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="109.9228515625" x="7.53857421875" xml:space="preserve" y="4.8515625">Event Manager<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="n2::n0::n4">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="30.0" width="125.0" x="1008.9200999999996" y="267.1160312500001"/>
|
||||
<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="117.7021484375" x="3.64892578125" xml:space="preserve" y="4.8515625">PUS Distribution<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="n2::n0::n5">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="40.0" width="125.0" x="1151.9280499999995" y="223.11926562500005"/>
|
||||
<y:Fill color="#CCFFFF" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" raised="false" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.59375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="84.1650390625" x="20.41748046875" xml:space="preserve" y="1.7031249999999716">Shared
|
||||
TMTC Pools<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="n2::n0::n6">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="50.0" width="125.0" x="1008.9200999999996" y="311.1127968750001"/>
|
||||
<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="36.59375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="78.12890625" x="23.435546875" xml:space="preserve" y="6.703125">Satellite
|
||||
Mode Tree<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="n2::n0::n7">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="30.0" width="125.0" x="1294.9359999999995" y="223.11926562500005"/>
|
||||
<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="74.7861328125" x="25.10693359375" xml:space="preserve" y="4.8515625"> PUS Stack<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>
|
||||
</graph>
|
||||
</node>
|
||||
</graph>
|
||||
</node>
|
||||
<node id="n3">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<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-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>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n4">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<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">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>
|
||||
</data>
|
||||
</node>
|
||||
</graph>
|
||||
<data key="d7">
|
||||
<y:Resources/>
|
||||
</data>
|
||||
</graphml>
|
||||
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/
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
@@ -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 framework 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,53 +2,94 @@
|
||||
|
||||
# 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-core/0.1.0-alpha.0/satrs_core/hal/host/udp_server/index.html).
|
||||
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-core/0.1.0-alpha.1/satrs_core/hal/std/tcp_server/index.html).
|
||||
TCP is a stream based protocol, so the framework provides building blocks to parse telemetry
|
||||
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 telecommands
|
||||
from an arbitrary bytestream. Two concrete implementations are provided:
|
||||
- [TCP spacepackets server](https://docs.rs/satrs-core/0.1.0-alpha.1/satrs_core/hal/std/tcp_server/struct.TcpSpacepacketsServer.html)
|
||||
- [TCP spacepackets server](https://docs.rs/satrs/latest/satrs/hal/std/tcp_server/struct.TcpSpacepacketsServer.html)
|
||||
to parse tightly packed CCSDS Spacepackets.
|
||||
- [TCP COBS server](https://docs.rs/satrs-core/0.1.0-alpha.1/satrs_core/hal/std/tcp_server/struct.TcpTmtcInCobsServer.html)
|
||||
- [TCP COBS server](https://docs.rs/satrs/latest/satrs/hal/std/tcp_server/struct.TcpTmtcInCobsServer.html)
|
||||
to parse generic frames wrapped with the
|
||||
[COBS protocol](https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing).
|
||||
|
||||
# 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 modern 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.
|
||||
|
||||
# Low-level protocols and the bridge to the communcation subsystem
|
||||
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 receivers only have to
|
||||
forward their generated or received packets to those handler objects.
|
||||
|
||||
# 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
|
||||
@@ -26,15 +32,17 @@ 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-core/0.1.0-alpha.3/satrs_core/pool/trait.PoolProvider.html).
|
||||
This trait specifies the general API a pool structure should have without making assumption
|
||||
of how the data is stored.
|
||||
[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 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:
|
||||
|
||||
```rust
|
||||
use satrs_core::pool::{StaticMemoryPool, StaticPoolConfig};
|
||||
<!-- Would be nice to test this code sample, but need to wait
|
||||
for https://github.com/rust-lang/mdBook/issues/706 to be merged.. -->
|
||||
```rust, ignore
|
||||
use satrs::pool::{StaticMemoryPool, StaticPoolConfig};
|
||||
|
||||
let tc_pool = StaticMemoryPool::new(StaticPoolConfig::new(vec
|
||||
- [`StaticMemoryPool` API](https://docs.rs/satrs-core/0.1.0-alpha.3/satrs_core/pool/struct.StaticMemoryPool.html)
|
||||
- [`StaticPoolConfig` API](https://docs.rs/satrs/latest/satrs/pool/struct.StaticPoolConfig.html)
|
||||
- [`StaticMemoryPool` API](https://docs.rs/satrs/latest/satrs/pool/struct.StaticMemoryPool.html)
|
||||
|
||||
for more details.
|
||||
|
||||
|
||||
+25
-20
@@ -1,39 +1,45 @@
|
||||
# Framework Design
|
||||
# Library Design
|
||||
|
||||
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 framework is centered
|
||||
around many light-weight components which try to impose as few restrictions as possible on how to
|
||||
solve certain problems.
|
||||
both the hardware and the software. Consequently, the general design of the library is centered
|
||||
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 framework tries to provide this
|
||||
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 framework 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`
|
||||
framework.
|
||||
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
|
||||
shorter development cycle and was built using cheaper COTS components. This framework also tries
|
||||
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.
|
||||
|
||||
@@ -42,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.
|
||||
|
||||
+91
-11
@@ -1,16 +1,96 @@
|
||||
# Events
|
||||
|
||||
Events can be an extremely important mechanism used for remote systems to monitor unexpected
|
||||
or expected anomalies and events occuring on these systems. They are oftentimes tied to
|
||||
Fault Detection, Isolation and Recovery (FDIR) operations, which need to happen autonomously.
|
||||
Events are an important mechanism used for remote systems to monitor unexpected
|
||||
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.
|
||||
|
||||
Events can also be used as a convenient Inter-Process Communication (IPC) mechansism, which is
|
||||
also observable for the Ground segment. 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 really need this service.
|
||||
|
||||
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:
|
||||
## Event Severity
|
||||
|
||||

|
||||
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>
|
||||
}
|
||||
```
|
||||
+72
-104
@@ -1,6 +1,6 @@
|
||||
# sat-rs Example Application
|
||||
|
||||
The `sat-rs` framework includes a monolithic example application which can be found inside
|
||||
The `sat-rs` library includes a monolithic example application which can be found inside
|
||||
the [`satrs-example`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example)
|
||||
subdirectory of the repository. The primary purpose of this example application is to show how
|
||||
the various components of the sat-rs framework could be used as part of a larger on-board
|
||||
@@ -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
|
||||
@@ -23,11 +72,11 @@ Some additional explanation is provided for the various components.
|
||||
The example includes a UDP and TCP server to receive telecommands and poll telemetry from. This
|
||||
might be an optional component for an OBSW which is only used during the development phase on
|
||||
ground. The UDP server is strongly based on the
|
||||
[UDP TC server](https://docs.rs/satrs-core/0.1.0-alpha.1/satrs_core/hal/std/udp_server/struct.UdpTcServer.html).
|
||||
[UDP TC server](https://docs.rs/satrs/latest/satrs/hal/std/udp_server/struct.UdpTcServer.html).
|
||||
This server component is wrapped by a TMTC server which handles all telemetry to the last connected
|
||||
client.
|
||||
|
||||
The TCP server is based on the [TCP Spacepacket Server](https://docs.rs/satrs-core/0.1.0-alpha.1/satrs_core/hal/std/tcp_server/struct.TcpSpacepacketsServer.html)
|
||||
The TCP server is based on the [TCP Spacepacket Server](https://docs.rs/satrs/latest/satrs/hal/std/tcp_server/struct.TcpSpacepacketsServer.html)
|
||||
class. It parses space packets by using the CCSDS space packet ID as the packet
|
||||
start delimiter. All available telemetry will be sent back to a client after having read all
|
||||
telecommands from the client.
|
||||
@@ -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-core/0.1.0-alpha.1/satrs_core/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-core/0.1.0-alpha.1/satrs_core/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-core/0.1.0-alpha.1/satrs_core/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-core/0.1.0-alpha.1/satrs_core/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 |
@@ -1,29 +1,48 @@
|
||||
The sat-rs book
|
||||
======
|
||||
|
||||
This book is the primary information resource for the [sat-rs framework](https://egit.irs.uni-stuttgart.de/rust/sat-rs)
|
||||
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
|
||||
|
||||
The primary goal of the sat-rs framework is to provide re-usable components
|
||||
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.
|
||||
|
||||
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/).
|
||||
@@ -1,26 +1,27 @@
|
||||
# Modes
|
||||
|
||||
Modes are an extremely useful concept for complex system in general. They also allow simplified
|
||||
system reasoning for both system operators and OBSW developers. They model the behaviour of a
|
||||
component and also provide observability of a system. A few examples of how to model
|
||||
different components of a space system with modes will be given.
|
||||
Modes are an extremely useful concept to model complex systems. They allow simplified
|
||||
system reasoning for both system operators and OBSW developers. They also provide a way to alter
|
||||
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.
|
||||
|
||||
## Modelling a pyhsical devices 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`
|
||||
- `NORMAL`
|
||||
|
||||
can be applied to a large number of simpler devices of a remote system, for example sensors.
|
||||
can be applied to a large number of simpler device controllers of a remote system, for example
|
||||
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
|
||||
@@ -31,7 +32,7 @@ for the majority of devices:
|
||||
2. `NORMAL` or `ON` to `OFF`: Any important shutdown configuration or handling must be performed
|
||||
before powering off the device.
|
||||
|
||||
## Modelling a controller with modes
|
||||
## Controller components with modes
|
||||
|
||||
Controller components are not modelling physical devices, but a mode scheme is still the best
|
||||
way to model most of these components.
|
||||
@@ -72,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.
|
||||
@@ -93,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.
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
{
|
||||
/*
|
||||
* Requires the Rust Language Server (RLS) and Cortex-Debug extensions
|
||||
* https://marketplace.visualstudio.com/items?itemName=rust-lang.rust
|
||||
* https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug
|
||||
*/
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
/* Launches debug session for currently open example */
|
||||
"type": "cortex-debug",
|
||||
"request": "launch",
|
||||
"name": "Debug",
|
||||
"servertype": "openocd",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "cargo build",
|
||||
"runToEntryPoint": "true",
|
||||
"executable": "./target/thumbv7em-none-eabihf/debug/satrs-example-stm32f3-disco",
|
||||
"preLaunchCommands": ["break rust_begin_unwind"],
|
||||
"device": "STM32F303VCT6",
|
||||
"configFiles": [
|
||||
"${workspaceRoot}/.vscode/openocd-helpers.tcl",
|
||||
"interface/stlink.cfg",
|
||||
"target/stm32f3x.cfg"
|
||||
],
|
||||
"svdFile": "${env:HOME}/.svd/STM32F303.svd",
|
||||
"swoConfig": {
|
||||
"enabled": true,
|
||||
"cpuFrequency": 8000000,
|
||||
"swoFrequency": 2000000,
|
||||
"source": "probe",
|
||||
"decoders": [
|
||||
{ "type": "console", "label": "ITM", "port": 0 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Launches debug session for currently open example */
|
||||
"type": "cortex-debug",
|
||||
"request": "launch",
|
||||
"name": "Release",
|
||||
"servertype": "openocd",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "cargo build",
|
||||
"runToEntryPoint": "true",
|
||||
"executable": "./target/thumbv7em-none-eabihf/release/satrs-example-stm32f3-disco",
|
||||
"preLaunchCommands": ["break rust_begin_unwind"],
|
||||
"device": "STM32F303VCT6",
|
||||
"configFiles": [
|
||||
"${workspaceRoot}/.vscode/openocd-helpers.tcl",
|
||||
"interface/stlink.cfg",
|
||||
"target/stm32f3x.cfg"
|
||||
],
|
||||
"svdFile": "${env:HOME}/.svd/STM32F303.svd",
|
||||
"swoConfig": {
|
||||
"enabled": true,
|
||||
"cpuFrequency": 8000000,
|
||||
"swoFrequency": 2000000,
|
||||
"source": "probe",
|
||||
"decoders": [
|
||||
{ "type": "console", "label": "ITM", "port": 0 }
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"cortex-debug.gdbPath.linux": "gdb-multiarch"
|
||||
}
|
||||
Generated
-762
@@ -1,762 +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 = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[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.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b13b4b2ea9ab2ba924063ebb86ad895cb79f4a79bf90f27949eb20c335b30f9"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"nb 1.0.0",
|
||||
"vcell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[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.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70858629a458fdfd39f9675c4dc309411f2a3f83bede76988d81bf1a0ecee9e0"
|
||||
dependencies = [
|
||||
"bare-metal 0.2.5",
|
||||
"bitfield",
|
||||
"embedded-hal",
|
||||
"volatile-register",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m-rt"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6d3328b8b5534f0c90acd66b68950f2763b37e0173cac4d8b4937c4a80761f9"
|
||||
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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m-rtic"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6b82f1c39acd6c3a35c2013b6110c20f5bc534522791fabadeed49ccada2dce"
|
||||
dependencies = [
|
||||
"bare-metal 1.0.0",
|
||||
"cortex-m",
|
||||
"cortex-m-rtic-macros",
|
||||
"heapless",
|
||||
"rtic-core",
|
||||
"rtic-monotonic",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m-rtic-macros"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e8e9645ef54bec1cf70ac33e9bf9566e6507ab5b41ae6baf3735662194e8607"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rtic-syntax",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[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-time"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7a4b4d10ac48d08bfe3db7688c402baadb244721f30a77ce360bd24c3dffe58"
|
||||
dependencies = [
|
||||
"num",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumset"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19be8061a06ab6f3a6cf21106c873578bf01bd42ad15e0311a9c76161cb1c753"
|
||||
dependencies = [
|
||||
"enumset_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumset_derive"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03e7b551eba279bf0fa88b83a46330168c1560a52a94f5126f892f0b364ab3e0"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[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.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ab17bb279def6720d058cb6c052249938e7f99260ab534879281a95367a87e5"
|
||||
dependencies = [
|
||||
"gcd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gcd"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4b1b088ad0a967aa29540456b82fc8903f854775d33f71e9709c4efb3dfbfd2"
|
||||
|
||||
[[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.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.7.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"hash32",
|
||||
"rustc_version 0.4.0",
|
||||
"spin",
|
||||
"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 = "1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itm_logger"
|
||||
version = "0.1.3-pre.0"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lsm303dlhc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e5d1a5c290951321d1b0d4a40edd828537de9889134a0e67c5146542ae57706"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"embedded-hal",
|
||||
"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.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
|
||||
dependencies = [
|
||||
"nb 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
|
||||
|
||||
[[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.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
||||
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.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "panic-itm"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d577d97d1b31268087b6dddf2470e6794ef5eee87d9dca7fcd0481695391a4c"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
|
||||
|
||||
[[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",
|
||||
"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.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtcc"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3623619ce77c09a7d87cf7c61c5c887b9c7dee8805f66af6c4aa5824be4d9930"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtic-core"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42"
|
||||
|
||||
[[package]]
|
||||
name = "rtic-monotonic"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb8b0b822d1a366470b9cea83a1d4e788392db763539dc4ba022bcc787fece82"
|
||||
|
||||
[[package]]
|
||||
name = "rtic-syntax"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ad3ae243dd8d0a1b064615f664d4fa7e63929939074c564cbe5efdc4c503065"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[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.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sat-rs-example-stm32f-disco"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"cortex-m-rtic",
|
||||
"embedded-hal",
|
||||
"enumset",
|
||||
"heapless",
|
||||
"itm_logger",
|
||||
"panic-itm",
|
||||
"stm32f3-discovery",
|
||||
"stm32f3xx-hal",
|
||||
"systick-monotonic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[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.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
|
||||
|
||||
[[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.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[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.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "265cda62ac13307414de4aca58dbbbd8038ddba85cffbb335823aa216f2e3200"
|
||||
dependencies = [
|
||||
"bare-metal 1.0.0",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"vcell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stm32f3-discovery"
|
||||
version = "0.8.0-pre.0"
|
||||
dependencies = [
|
||||
"accelerometer",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"lsm303dlhc",
|
||||
"stm32f3xx-hal",
|
||||
"switch-hal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stm32f3xx-hal"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e422c5c044e8f3a068b1e14b83c071449e27c9d4bc0e24f972b552d79f2be03"
|
||||
dependencies = [
|
||||
"bare-metal 1.0.0",
|
||||
"bxcan",
|
||||
"cfg-if",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"embedded-dma",
|
||||
"embedded-hal",
|
||||
"embedded-time",
|
||||
"enumset",
|
||||
"nb 1.0.0",
|
||||
"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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "systick-monotonic"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67fb822d5c615a0ae3a4795ee5b1d06381c7faf488d861c0a4fa8e6a88d5ff84"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"fugit",
|
||||
"rtic-monotonic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
|
||||
[[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.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6"
|
||||
dependencies = [
|
||||
"vcell",
|
||||
]
|
||||
@@ -1,59 +0,0 @@
|
||||
[package]
|
||||
name = "satrs-example-stm32f3-disco"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
cortex-m = "0.7"
|
||||
cortex-m-rt = "0.7"
|
||||
embedded-hal = "0.2.6"
|
||||
cortex-m-rtic = "1.0"
|
||||
enumset = "1.0"
|
||||
heapless = "0.7"
|
||||
systick-monotonic = "1.0"
|
||||
|
||||
[dependencies.cobs]
|
||||
git = "https://github.com/robamu/cobs.rs.git"
|
||||
branch = "all_features"
|
||||
default-features = false
|
||||
|
||||
[dependencies.panic-itm]
|
||||
version = "0.4"
|
||||
|
||||
[dependencies.itm_logger]
|
||||
git = "https://github.com/robamu/itm_logger.rs.git"
|
||||
branch = "all_features"
|
||||
version = "0.1.3-alpha.0"
|
||||
|
||||
[dependencies.stm32f3xx-hal]
|
||||
git = "https://github.com/robamu/stm32f3xx-hal"
|
||||
version = "0.10.0-alpha.0"
|
||||
features = ["stm32f303xc", "rt", "enumset"]
|
||||
branch = "all_features"
|
||||
# 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 = "all_features"
|
||||
# Can be used in workspace to develop and update BSP
|
||||
# path = "../stm32f3-discovery"
|
||||
|
||||
[dependencies.satrs-core]
|
||||
git = "https://egit.irs.uni-stuttgart.de/rust/satrs-core.git"
|
||||
version = "0.1.0-alpha.0"
|
||||
default-features = false
|
||||
|
||||
# this lets you use `cargo fix`!
|
||||
# [[bin]]
|
||||
# name = "stm32f3-blinky"
|
||||
# test = false
|
||||
# bench = false
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1 # better optimizations
|
||||
debug = true # symbols are nice and they don't increase the size on Flash
|
||||
lto = true # better optimizations
|
||||
@@ -1,75 +0,0 @@
|
||||
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)
|
||||
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.
|
||||
|
||||
The STM32F3-Discovery device was picked because it is a cheap Cortex-M4 based device which is also
|
||||
used by the [Rust Embedded Book](https://docs.rust-embedded.org/book/intro/hardware.html) and the
|
||||
[Rust Discovery](https://docs.rust-embedded.org/discovery/f3discovery/) book as an introduction
|
||||
to embedded Rust.
|
||||
|
||||
## 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 and Debugging from the command line
|
||||
|
||||
TODO
|
||||
|
||||
## 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 `openocd`
|
||||
and the VS Code [`Cortex-Debug` plugin](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug).
|
||||
|
||||
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.
|
||||
|
||||
If you would like to use a custom GDB application, you can specify the gdb binary in the following
|
||||
configuration variables in your `settings.json`:
|
||||
|
||||
- `"cortex-debug.gdbPath"`
|
||||
- `"cortex-debug.gdbPath.linux"`
|
||||
- `"cortex-debug.gdbPath.windows"`
|
||||
- `"cortex-debug.gdbPath.osx"`
|
||||
|
||||
## Commanding with Python
|
||||
|
||||
When the SW is running on the Discovery board, you can command the MCU via a serial interface,
|
||||
using COBS encoded CCSDS packets.
|
||||
|
||||
TODO:
|
||||
- How and where to connect serial interface on the MCU
|
||||
- How to set up Python venv (or at least strongly recommend it) and install deps
|
||||
- How to copy `def_tmtc_conf.json` to `tmtc_conf.json` and adapt it for custom serial port
|
||||
Loaded 100 of 300 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user