Compare commits
30 Commits
satrs-shar
...
serializat
Author | SHA1 | Date | |
---|---|---|---|
2eaa78dfbc | |||
a6d9bee5df | |||
a77bbfa953 | |||
4c67bcdde1 | |||
a710b30013 | |||
29783b2b07 | |||
2a2a3a3eab
|
|||
2507469e68
|
|||
b4febefa33 | |||
fe60cb9ccf | |||
27e88ed7f7
|
|||
295fed9a72
|
|||
8e89c8dd66
|
|||
cb0a65c4d4 | |||
3db54da3df | |||
15fcb17363 | |||
8728c7ebea | |||
7606767f63 | |||
37b32a9008 | |||
9e096193dd | |||
43bd77eef0
|
|||
a4888bce01
|
|||
6e5b70af34
|
|||
d1476eb770
|
|||
783388aa6f
|
|||
4a8db6b26a
|
|||
b86c2eb1d1
|
|||
fe4126f7e2
|
|||
c20163b10a
|
|||
b970154488 |
@ -11,5 +11,6 @@ members = [
|
||||
exclude = [
|
||||
"embedded-examples/stm32f3-disco-rtic",
|
||||
"embedded-examples/stm32h7-rtic",
|
||||
"serialization-prototyping",
|
||||
]
|
||||
|
||||
|
11
README.md
11
README.md
@ -37,16 +37,13 @@ This project currently contains following crates:
|
||||
* [`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 [asynchronix](https://github.com/asynchronics/asynchronix) 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-stm32f3-disco-rtic`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/embedded-examples/stm32f3-disco-rtic):
|
||||
* [`satrs-stm32f3-disco-rtic`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/embedded-examples/satrs-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):
|
||||
* [`satrs-stm32h-nucleo-rtic`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/embedded-examples/satrs-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.
|
||||
@ -72,10 +69,6 @@ Currently this library has the following flight heritage:
|
||||
[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
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
sat-rs example for the STM32H73ZI-Nucleo board
|
||||
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)
|
||||
|
@ -1,260 +0,0 @@
|
||||
<?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="d5"/>
|
||||
<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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="67.919921875" 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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="37.638671875" x="23.380664062499818" xml:space="preserve" y="8.015625">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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="92.453125" x="13.973437499999818" xml:space="preserve" y="8.015625">Magnetometer<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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="88.83203125" x="15.783984374999818" xml:space="preserve" y="8.015625">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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="85.931640625" x="17.234179687499932" xml:space="preserve" y="8.015625">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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="105.05078125" x="7.674609374999932" xml:space="preserve" y="8.015625">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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="97.111328125" x="11.644335937499932" xml:space="preserve" y="8.015625">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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="38.740234375" x="40.82988281249993" xml:space="preserve" y="8.015625">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>
|
||||
<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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="97.955078125" x="12.686124396959713" xml:space="preserve" y="-22.50440429687478">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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="75.923828125" x="-87.89792405764274" xml:space="preserve" y="-40.606550292968564">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="n3" target="n7">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" 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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="60.4140625" x="-2.4087265765670054" xml:space="preserve" y="145.1356018470808">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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="119.751953125" x="-132.27600022951788" xml:space="preserve" y="-32.03587548828091">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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="104.2421875" x="-62.15307370122309" xml:space="preserve" y="34.80927001953137">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="17.96875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="29.95703125" x="73.38950633588263" xml:space="preserve" y="-62.699758016200235">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.
Before Width: | Height: | Size: 98 KiB |
@ -5,8 +5,10 @@ This book is the primary information resource for the [sat-rs library](https://e
|
||||
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
|
||||
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
|
||||
|
||||
@ -29,9 +31,7 @@ and [EIVE](https://www.irs.uni-stuttgart.de/en/research/satellitetechnology-and-
|
||||
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 [`satrs-minisim`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-minisim)
|
||||
applicatin complements the example application and can be used to simulate some physical devices
|
||||
for the `satrs-example` device handlers.
|
||||
the example application.
|
||||
|
||||
# Flight Heritage
|
||||
|
||||
@ -43,7 +43,3 @@ Currently this library has the following flight heritage:
|
||||
[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/).
|
||||
|
@ -7,13 +7,3 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
# [v0.1.1] 2024-02-21
|
||||
|
||||
satrs v0.2.0-rc.0
|
||||
satrs-mib v0.1.1
|
||||
|
||||
# [v0.1.0] 2024-02-13
|
||||
|
||||
satrs v0.1.1
|
||||
satrs-mib v0.1.0
|
||||
|
@ -73,22 +73,3 @@ the `simpleclient`:
|
||||
```
|
||||
|
||||
You can also simply call the script without any arguments to view the command tree.
|
||||
|
||||
## Adding the mini simulator application
|
||||
|
||||
This example application features a few device handlers. The
|
||||
[`satrs-minisim`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-minisim)
|
||||
can be used to simulate the physical devices managed by these device handlers.
|
||||
|
||||
The example application will attempt communication with the mini simulator on UDP port 7303.
|
||||
If this works, the device handlers will use communication interfaces dedicated to the communication
|
||||
with the mini simulator. Otherwise, they will be replaced by dummy interfaces which either
|
||||
return constant values or behave like ideal devices.
|
||||
|
||||
In summary, you can use the following command command to run the mini-simulator first:
|
||||
|
||||
```sh
|
||||
cargo run -p satrs-minisim
|
||||
```
|
||||
|
||||
and then start the example using `cargo run -p satrs-example`.
|
||||
|
@ -19,7 +19,7 @@ use satrs::mode::{
|
||||
};
|
||||
use satrs::pus::{EcssTmSender, PusTmVariant};
|
||||
use satrs::request::{GenericMessage, MessageMetadata, UniqueApidTargetId};
|
||||
use satrs_example::config::components::{NO_SENDER, PUS_MODE_SERVICE};
|
||||
use satrs_example::config::components::PUS_MODE_SERVICE;
|
||||
|
||||
use crate::hk::PusHkHelper;
|
||||
use crate::pus::hk::{HkReply, HkReplyVariant};
|
||||
@ -421,12 +421,9 @@ impl<
|
||||
self.mode_helpers.target = None;
|
||||
self.announce_mode(requestor, false);
|
||||
if let Some(requestor) = requestor {
|
||||
if requestor.sender_id() == NO_SENDER {
|
||||
return Ok(());
|
||||
}
|
||||
if requestor.sender_id() != PUS_MODE_SERVICE.id() {
|
||||
log::warn!(
|
||||
"can not send back mode reply to sender {:x}",
|
||||
"can not send back mode reply to sender {}",
|
||||
requestor.sender_id()
|
||||
);
|
||||
} else {
|
||||
@ -535,7 +532,7 @@ mod tests {
|
||||
hk_reply_rx,
|
||||
handler: MgmHandlerLis3Mdl::new(
|
||||
UniqueApidTargetId::new(Apid::Acs as u16, 1),
|
||||
"TEST_MGM",
|
||||
"test-mgm",
|
||||
mode_interface,
|
||||
composite_request_rx,
|
||||
hk_reply_tx,
|
||||
|
@ -122,7 +122,7 @@ pub mod mode_err {
|
||||
}
|
||||
|
||||
pub mod components {
|
||||
use satrs::{request::UniqueApidTargetId, ComponentId};
|
||||
use satrs::request::UniqueApidTargetId;
|
||||
use strum::EnumIter;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, EnumIter)]
|
||||
@ -184,7 +184,6 @@ pub mod components {
|
||||
UniqueApidTargetId::new(Apid::Tmtc as u16, TmtcId::UdpServer as u32);
|
||||
pub const TCP_SERVER: UniqueApidTargetId =
|
||||
UniqueApidTargetId::new(Apid::Tmtc as u16, TmtcId::TcpServer as u32);
|
||||
pub const NO_SENDER: ComponentId = ComponentId::MAX;
|
||||
}
|
||||
|
||||
pub mod pool {
|
||||
|
@ -15,10 +15,7 @@ use satrs::{
|
||||
request::{GenericMessage, MessageMetadata, UniqueApidTargetId},
|
||||
spacepackets::ByteConversionError,
|
||||
};
|
||||
use satrs_example::{
|
||||
config::components::{NO_SENDER, PUS_MODE_SERVICE},
|
||||
DeviceMode, TimestampHelper,
|
||||
};
|
||||
use satrs_example::{config::components::PUS_MODE_SERVICE, DeviceMode, TimestampHelper};
|
||||
use satrs_minisim::{
|
||||
eps::{
|
||||
PcduReply, PcduRequest, PcduSwitch, SwitchMap, SwitchMapBinaryWrapper, SwitchMapWrapper,
|
||||
@ -63,9 +60,9 @@ impl SerialInterface for SerialInterfaceToSim {
|
||||
type Error = ();
|
||||
|
||||
fn send(&self, data: &[u8]) -> Result<(), Self::Error> {
|
||||
let request: PcduRequest = serde_json::from_slice(data).expect("expected a PCDU request");
|
||||
let request: SimRequest = serde_json::from_slice(data).unwrap();
|
||||
self.sim_request_tx
|
||||
.send(SimRequest::new_with_epoch_time(request))
|
||||
.send(request)
|
||||
.expect("failed to send request to simulation");
|
||||
Ok(())
|
||||
}
|
||||
@ -104,7 +101,9 @@ impl SerialInterface for SerialInterfaceDummy {
|
||||
type Error = ();
|
||||
|
||||
fn send(&self, data: &[u8]) -> Result<(), Self::Error> {
|
||||
let pcdu_req: PcduRequest = serde_json::from_slice(data).unwrap();
|
||||
let sim_req: SimRequest = serde_json::from_slice(data).unwrap();
|
||||
let pcdu_req =
|
||||
PcduRequest::from_sim_message(&sim_req).expect("PCDU request creation failed");
|
||||
let switch_map_mut = &mut self.switch_map.borrow_mut().0;
|
||||
match pcdu_req {
|
||||
PcduRequest::SwitchDevice { switch, state } => {
|
||||
@ -120,7 +119,7 @@ impl SerialInterface for SerialInterfaceDummy {
|
||||
PcduRequest::RequestSwitchInfo => {
|
||||
let mut reply_deque_mut = self.reply_deque.borrow_mut();
|
||||
reply_deque_mut.push_back(SimReply::new(&PcduReply::SwitchInfo(
|
||||
switch_map_mut.clone(),
|
||||
self.switch_map.borrow().0.clone(),
|
||||
)));
|
||||
}
|
||||
};
|
||||
@ -131,13 +130,15 @@ impl SerialInterface for SerialInterfaceDummy {
|
||||
&self,
|
||||
mut f: ReplyHandler,
|
||||
) -> Result<(), Self::Error> {
|
||||
if self.reply_queue_empty() {
|
||||
if self.reply_deque.borrow().is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
loop {
|
||||
let reply = self.get_next_reply_as_string();
|
||||
let mut reply_deque_mut = self.reply_deque.borrow_mut();
|
||||
let next_reply = reply_deque_mut.pop_front().unwrap();
|
||||
let reply = serde_json::to_string(&next_reply).unwrap();
|
||||
f(reply.as_bytes());
|
||||
if self.reply_queue_empty() {
|
||||
if reply_deque_mut.is_empty() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -145,18 +146,6 @@ impl SerialInterface for SerialInterfaceDummy {
|
||||
}
|
||||
}
|
||||
|
||||
impl SerialInterfaceDummy {
|
||||
fn get_next_reply_as_string(&self) -> String {
|
||||
let mut reply_deque_mut = self.reply_deque.borrow_mut();
|
||||
let next_reply = reply_deque_mut.pop_front().unwrap();
|
||||
serde_json::to_string(&next_reply).unwrap()
|
||||
}
|
||||
|
||||
fn reply_queue_empty(&self) -> bool {
|
||||
self.reply_deque.borrow().is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SerialSimInterfaceWrapper {
|
||||
Dummy(SerialInterfaceDummy),
|
||||
Sim(SerialInterfaceToSim),
|
||||
@ -382,12 +371,10 @@ impl<ComInterface: SerialInterface, TmSender: EcssTmSender> PcduHandler<ComInter
|
||||
PcduReply::SwitchInfo(switch_info) => {
|
||||
let switch_map_wrapper =
|
||||
SwitchMapWrapper::from_binary_switch_map_ref(&switch_info);
|
||||
let mut shared_switch_map = self
|
||||
.shared_switch_map
|
||||
self.shared_switch_map
|
||||
.lock()
|
||||
.expect("failed to lock switch map");
|
||||
shared_switch_map.switch_map = switch_map_wrapper.0;
|
||||
shared_switch_map.valid = true;
|
||||
.expect("failed to lock switch map")
|
||||
.switch_map = switch_map_wrapper.0;
|
||||
}
|
||||
}
|
||||
}) {
|
||||
@ -440,9 +427,6 @@ impl<ComInterface: SerialInterface, TmSender: EcssTmSender> ModeRequestHandler
|
||||
) -> Result<(), Self::Error> {
|
||||
self.announce_mode(requestor, false);
|
||||
if let Some(requestor) = requestor {
|
||||
if requestor.sender_id() == NO_SENDER {
|
||||
return Ok(());
|
||||
}
|
||||
if requestor.sender_id() != PUS_MODE_SERVICE.id() {
|
||||
log::warn!(
|
||||
"can not send back mode reply to sender {}",
|
||||
@ -481,242 +465,3 @@ impl<ComInterface: SerialInterface, TmSender: EcssTmSender> ModeRequestHandler
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::mpsc;
|
||||
|
||||
use satrs::{
|
||||
mode::ModeRequest, power::SwitchStateBinary, request::GenericMessage, tmtc::PacketAsVec,
|
||||
};
|
||||
use satrs_example::config::components::{Apid, MGM_HANDLER_0};
|
||||
use satrs_minisim::eps::SwitchMapBinary;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SerialInterfaceTest {
|
||||
pub inner: SerialInterfaceDummy,
|
||||
pub send_queue: RefCell<VecDeque<Vec<u8>>>,
|
||||
pub reply_queue: RefCell<VecDeque<String>>,
|
||||
}
|
||||
|
||||
impl SerialInterface for SerialInterfaceTest {
|
||||
type Error = ();
|
||||
|
||||
fn send(&self, data: &[u8]) -> Result<(), Self::Error> {
|
||||
let mut send_queue_mut = self.send_queue.borrow_mut();
|
||||
send_queue_mut.push_back(data.to_vec());
|
||||
self.inner.send(data)
|
||||
}
|
||||
|
||||
fn try_recv_replies<ReplyHandler: FnMut(&[u8])>(
|
||||
&self,
|
||||
mut f: ReplyHandler,
|
||||
) -> Result<(), Self::Error> {
|
||||
if self.inner.reply_queue_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
loop {
|
||||
let reply = self.inner.get_next_reply_as_string();
|
||||
self.reply_queue.borrow_mut().push_back(reply.clone());
|
||||
f(reply.as_bytes());
|
||||
if self.inner.reply_queue_empty() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PcduTestbench {
|
||||
pub mode_request_tx: mpsc::Sender<GenericMessage<ModeRequest>>,
|
||||
pub mode_reply_rx_to_pus: mpsc::Receiver<GenericMessage<ModeReply>>,
|
||||
pub mode_reply_rx_to_parent: mpsc::Receiver<GenericMessage<ModeReply>>,
|
||||
pub composite_request_tx: mpsc::Sender<GenericMessage<CompositeRequest>>,
|
||||
pub hk_reply_rx: mpsc::Receiver<GenericMessage<HkReply>>,
|
||||
pub tm_rx: mpsc::Receiver<PacketAsVec>,
|
||||
pub switch_request_tx: mpsc::Sender<GenericMessage<SwitchRequest>>,
|
||||
pub handler: PcduHandler<SerialInterfaceTest, mpsc::Sender<PacketAsVec>>,
|
||||
}
|
||||
|
||||
impl PcduTestbench {
|
||||
pub fn new() -> Self {
|
||||
let (mode_request_tx, mode_request_rx) = mpsc::channel();
|
||||
let (mode_reply_tx_to_pus, mode_reply_rx_to_pus) = mpsc::channel();
|
||||
let (mode_reply_tx_to_parent, mode_reply_rx_to_parent) = mpsc::sync_channel(5);
|
||||
let mode_interface = MpscModeLeafInterface {
|
||||
request_rx: mode_request_rx,
|
||||
reply_to_pus_tx: mode_reply_tx_to_pus,
|
||||
reply_to_parent_tx: mode_reply_tx_to_parent,
|
||||
};
|
||||
let (composite_request_tx, composite_request_rx) = mpsc::channel();
|
||||
let (hk_reply_tx, hk_reply_rx) = mpsc::channel();
|
||||
let (tm_tx, tm_rx) = mpsc::channel::<PacketAsVec>();
|
||||
let (switch_request_tx, switch_reqest_rx) = mpsc::channel();
|
||||
let shared_switch_map = Arc::new(Mutex::new(SwitchSet::default()));
|
||||
Self {
|
||||
mode_request_tx,
|
||||
mode_reply_rx_to_pus,
|
||||
mode_reply_rx_to_parent,
|
||||
composite_request_tx,
|
||||
hk_reply_rx,
|
||||
tm_rx,
|
||||
switch_request_tx,
|
||||
handler: PcduHandler::new(
|
||||
UniqueApidTargetId::new(Apid::Eps as u16, 0),
|
||||
"TEST_PCDU",
|
||||
mode_interface,
|
||||
composite_request_rx,
|
||||
hk_reply_tx,
|
||||
switch_reqest_rx,
|
||||
tm_tx,
|
||||
SerialInterfaceTest::default(),
|
||||
shared_switch_map,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify_switch_info_req_was_sent(&self, expected_queue_len: usize) {
|
||||
// Check that there is now communication happening.
|
||||
let mut send_queue_mut = self.handler.com_interface.send_queue.borrow_mut();
|
||||
assert_eq!(send_queue_mut.len(), expected_queue_len);
|
||||
let packet_sent = send_queue_mut.pop_front().unwrap();
|
||||
drop(send_queue_mut);
|
||||
let pcdu_req: PcduRequest = serde_json::from_slice(&packet_sent).unwrap();
|
||||
assert_eq!(pcdu_req, PcduRequest::RequestSwitchInfo);
|
||||
}
|
||||
|
||||
pub fn verify_switch_req_was_sent(
|
||||
&self,
|
||||
expected_queue_len: usize,
|
||||
switch_id: PcduSwitch,
|
||||
target_state: SwitchStateBinary,
|
||||
) {
|
||||
// Check that there is now communication happening.
|
||||
let mut send_queue_mut = self.handler.com_interface.send_queue.borrow_mut();
|
||||
assert_eq!(send_queue_mut.len(), expected_queue_len);
|
||||
let packet_sent = send_queue_mut.pop_front().unwrap();
|
||||
drop(send_queue_mut);
|
||||
let pcdu_req: PcduRequest = serde_json::from_slice(&packet_sent).unwrap();
|
||||
assert_eq!(
|
||||
pcdu_req,
|
||||
PcduRequest::SwitchDevice {
|
||||
switch: switch_id,
|
||||
state: target_state
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub fn verify_switch_reply_received(
|
||||
&self,
|
||||
expected_queue_len: usize,
|
||||
expected_map: SwitchMapBinary,
|
||||
) {
|
||||
// Check that a switch reply was read back.
|
||||
let mut reply_received_mut = self.handler.com_interface.reply_queue.borrow_mut();
|
||||
assert_eq!(reply_received_mut.len(), expected_queue_len);
|
||||
let reply_received = reply_received_mut.pop_front().unwrap();
|
||||
let sim_reply: SimReply = serde_json::from_str(&reply_received).unwrap();
|
||||
let pcdu_reply = PcduReply::from_sim_message(&sim_reply).unwrap();
|
||||
assert_eq!(pcdu_reply, PcduReply::SwitchInfo(expected_map));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic_handler() {
|
||||
let mut testbench = PcduTestbench::new();
|
||||
assert_eq!(testbench.handler.com_interface.send_queue.borrow().len(), 0);
|
||||
assert_eq!(
|
||||
testbench.handler.com_interface.reply_queue.borrow().len(),
|
||||
0
|
||||
);
|
||||
assert_eq!(
|
||||
testbench.handler.mode_and_submode().mode(),
|
||||
DeviceMode::Off as u32
|
||||
);
|
||||
assert_eq!(testbench.handler.mode_and_submode().submode(), 0_u16);
|
||||
testbench.handler.periodic_operation(OpCode::RegularOp);
|
||||
testbench
|
||||
.handler
|
||||
.periodic_operation(OpCode::PollAndRecvReplies);
|
||||
// Handler is OFF, no changes expected.
|
||||
assert_eq!(testbench.handler.com_interface.send_queue.borrow().len(), 0);
|
||||
assert_eq!(
|
||||
testbench.handler.com_interface.reply_queue.borrow().len(),
|
||||
0
|
||||
);
|
||||
assert_eq!(
|
||||
testbench.handler.mode_and_submode().mode(),
|
||||
DeviceMode::Off as u32
|
||||
);
|
||||
assert_eq!(testbench.handler.mode_and_submode().submode(), 0_u16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_normal_mode() {
|
||||
let mut testbench = PcduTestbench::new();
|
||||
testbench
|
||||
.mode_request_tx
|
||||
.send(GenericMessage::new(
|
||||
MessageMetadata::new(0, PUS_MODE_SERVICE.id()),
|
||||
ModeRequest::SetMode(ModeAndSubmode::new(DeviceMode::Normal as u32, 0)),
|
||||
))
|
||||
.expect("failed to send mode request");
|
||||
let switch_map_shared = testbench.handler.shared_switch_map.lock().unwrap();
|
||||
assert!(!switch_map_shared.valid);
|
||||
drop(switch_map_shared);
|
||||
testbench.handler.periodic_operation(OpCode::RegularOp);
|
||||
testbench
|
||||
.handler
|
||||
.periodic_operation(OpCode::PollAndRecvReplies);
|
||||
// Check correctness of mode.
|
||||
assert_eq!(
|
||||
testbench.handler.mode_and_submode().mode(),
|
||||
DeviceMode::Normal as u32
|
||||
);
|
||||
assert_eq!(testbench.handler.mode_and_submode().submode(), 0);
|
||||
|
||||
testbench.verify_switch_info_req_was_sent(1);
|
||||
testbench.verify_switch_reply_received(1, SwitchMapBinaryWrapper::default().0);
|
||||
|
||||
let switch_map_shared = testbench.handler.shared_switch_map.lock().unwrap();
|
||||
assert!(switch_map_shared.valid);
|
||||
drop(switch_map_shared);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_switch_request_handling() {
|
||||
let mut testbench = PcduTestbench::new();
|
||||
testbench
|
||||
.mode_request_tx
|
||||
.send(GenericMessage::new(
|
||||
MessageMetadata::new(0, PUS_MODE_SERVICE.id()),
|
||||
ModeRequest::SetMode(ModeAndSubmode::new(DeviceMode::Normal as u32, 0)),
|
||||
))
|
||||
.expect("failed to send mode request");
|
||||
testbench
|
||||
.switch_request_tx
|
||||
.send(GenericMessage::new(
|
||||
MessageMetadata::new(0, MGM_HANDLER_0.id()),
|
||||
SwitchRequest::new(0, SwitchStateBinary::On),
|
||||
))
|
||||
.expect("failed to send switch request");
|
||||
testbench.handler.periodic_operation(OpCode::RegularOp);
|
||||
testbench
|
||||
.handler
|
||||
.periodic_operation(OpCode::PollAndRecvReplies);
|
||||
|
||||
testbench.verify_switch_req_was_sent(2, PcduSwitch::Mgm, SwitchStateBinary::On);
|
||||
testbench.verify_switch_info_req_was_sent(1);
|
||||
let mut switch_map = SwitchMapBinaryWrapper::default().0;
|
||||
*switch_map
|
||||
.get_mut(&PcduSwitch::Mgm)
|
||||
.expect("switch state setting failed") = SwitchStateBinary::On;
|
||||
testbench.verify_switch_reply_received(1, switch_map);
|
||||
|
||||
let switch_map_shared = testbench.handler.shared_switch_map.lock().unwrap();
|
||||
assert!(switch_map_shared.valid);
|
||||
drop(switch_map_shared);
|
||||
}
|
||||
}
|
||||
|
@ -22,14 +22,13 @@ use pus::test::create_test_service_dynamic;
|
||||
use satrs::hal::std::tcp_server::ServerConfig;
|
||||
use satrs::hal::std::udp_server::UdpTcServer;
|
||||
use satrs::pus::HandlingStatus;
|
||||
use satrs::request::{GenericMessage, MessageMetadata};
|
||||
use satrs::request::GenericMessage;
|
||||
use satrs::tmtc::{PacketSenderWithSharedPool, SharedPacketPool};
|
||||
use satrs_example::config::pool::{create_sched_tc_pool, create_static_pools};
|
||||
use satrs_example::config::tasks::{
|
||||
FREQ_MS_AOCS, FREQ_MS_PUS_STACK, FREQ_MS_UDP_TMTC, SIM_CLIENT_IDLE_DELAY_MS,
|
||||
};
|
||||
use satrs_example::config::{OBSW_SERVER_ADDR, PACKET_ID_VALIDATOR, SERVER_PORT};
|
||||
use satrs_example::DeviceMode;
|
||||
|
||||
use crate::acs::mgm::{
|
||||
MgmHandlerLis3Mdl, MpscModeLeafInterface, SpiDummyInterface, SpiSimInterface,
|
||||
@ -47,12 +46,10 @@ use crate::pus::scheduler::{create_scheduler_service_dynamic, create_scheduler_s
|
||||
use crate::pus::test::create_test_service_static;
|
||||
use crate::pus::{PusTcDistributor, PusTcMpscRouter};
|
||||
use crate::requests::{CompositeRequest, GenericRequestRouter};
|
||||
use satrs::mode::{Mode, ModeAndSubmode, ModeRequest};
|
||||
use satrs::mode::ModeRequest;
|
||||
use satrs::pus::event_man::EventRequestWithToken;
|
||||
use satrs::spacepackets::{time::cds::CdsTime, time::TimeWriter};
|
||||
use satrs_example::config::components::{
|
||||
MGM_HANDLER_0, NO_SENDER, PCDU_HANDLER, TCP_SERVER, UDP_SERVER,
|
||||
};
|
||||
use satrs_example::config::components::{MGM_HANDLER_0, PCDU_HANDLER, TCP_SERVER, UDP_SERVER};
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::sync::{mpsc, Mutex};
|
||||
use std::sync::{Arc, RwLock};
|
||||
@ -101,7 +98,7 @@ fn static_tmtc_pool_main() {
|
||||
.insert(PCDU_HANDLER.id(), pcdu_handler_composite_tx);
|
||||
request_map
|
||||
.mode_router_map
|
||||
.insert(PCDU_HANDLER.id(), pcdu_handler_mode_tx.clone());
|
||||
.insert(PCDU_HANDLER.id(), pcdu_handler_mode_tx);
|
||||
|
||||
// This helper structure is used by all telecommand providers which need to send telecommands
|
||||
// to the TC source.
|
||||
@ -275,7 +272,6 @@ fn static_tmtc_pool_main() {
|
||||
} else {
|
||||
SerialSimInterfaceWrapper::Dummy(SerialInterfaceDummy::default())
|
||||
};
|
||||
|
||||
let mut pcdu_handler = PcduHandler::new(
|
||||
PCDU_HANDLER,
|
||||
"PCDU",
|
||||
@ -287,13 +283,6 @@ fn static_tmtc_pool_main() {
|
||||
pcdu_serial_interface,
|
||||
shared_switch_set,
|
||||
);
|
||||
// The PCDU is a critical component which should be in normal mode immediately.
|
||||
pcdu_handler_mode_tx
|
||||
.send(GenericMessage::new(
|
||||
MessageMetadata::new(0, NO_SENDER),
|
||||
ModeRequest::SetMode(ModeAndSubmode::new(DeviceMode::Normal as Mode, 0)),
|
||||
))
|
||||
.expect("sending initial mode request failed");
|
||||
|
||||
info!("Starting TMTC and UDP task");
|
||||
let jh_udp_tmtc = thread::Builder::new()
|
||||
@ -431,7 +420,7 @@ fn dyn_tmtc_pool_main() {
|
||||
.insert(PCDU_HANDLER.id(), pcdu_handler_composite_tx);
|
||||
request_map
|
||||
.mode_router_map
|
||||
.insert(PCDU_HANDLER.id(), pcdu_handler_mode_tx.clone());
|
||||
.insert(PCDU_HANDLER.id(), pcdu_handler_mode_tx);
|
||||
|
||||
// Create event handling components
|
||||
// These sender handles are used to send event requests, for example to enable or disable
|
||||
@ -594,13 +583,6 @@ fn dyn_tmtc_pool_main() {
|
||||
pcdu_serial_interface,
|
||||
shared_switch_set,
|
||||
);
|
||||
// The PCDU is a critical component which should be in normal mode immediately.
|
||||
pcdu_handler_mode_tx
|
||||
.send(GenericMessage::new(
|
||||
MessageMetadata::new(0, NO_SENDER),
|
||||
ModeRequest::SetMode(ModeAndSubmode::new(DeviceMode::Normal as Mode, 0)),
|
||||
))
|
||||
.expect("sending initial mode request failed");
|
||||
|
||||
info!("Starting TMTC and UDP task");
|
||||
let jh_udp_tmtc = thread::Builder::new()
|
||||
|
@ -33,7 +33,6 @@ pub struct HkReply {
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub enum HkReplyVariant {
|
||||
Ack,
|
||||
Failed(ResultU16),
|
||||
|
@ -16,9 +16,9 @@ num_enum = "0.7"
|
||||
humantime = "2"
|
||||
|
||||
[dependencies.asynchronix]
|
||||
version = "0.2.2"
|
||||
# git = "https://github.com/asynchronics/asynchronix.git"
|
||||
# branch = "main"
|
||||
version = "0.2.1"
|
||||
git = "https://github.com/asynchronics/asynchronix.git"
|
||||
branch = "main"
|
||||
features = ["serde"]
|
||||
|
||||
[dependencies.satrs]
|
||||
|
@ -1,32 +0,0 @@
|
||||
sat-rs minisim
|
||||
======
|
||||
|
||||
This crate contains a mini-simulator based on the open-source discrete-event simulation framework
|
||||
[asynchronix](https://github.com/asynchronics/asynchronix).
|
||||
|
||||
Right now, this crate is primarily used together with the
|
||||
[`satrs-example` application](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example)
|
||||
to simulate the devices connected to the example application.
|
||||
|
||||
You can simply run this application using
|
||||
|
||||
```sh
|
||||
cargo run
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
cargo run -p satrs-minisim
|
||||
```
|
||||
|
||||
in the workspace. The mini simulator uses the UDP port 7303 to exchange simulation requests and
|
||||
simulation replies with any other application.
|
||||
|
||||
The simulator was designed in a modular way to be scalable and adaptable to other communication
|
||||
schemes. This might allow it to serve a mini-simulator for other example applications which
|
||||
still have similar device handlers.
|
||||
|
||||
The following graph shows the high-level architecture of the mini-simulator.
|
||||
|
||||
<img src="../images/minisim-arch/minisim-arch.png" alt="Mini simulator architecture" width="500" class="center"/>
|
@ -16,12 +16,10 @@ use crate::{
|
||||
eps::PcduModel,
|
||||
};
|
||||
|
||||
const WARNING_FOR_STALE_DATA: bool = false;
|
||||
|
||||
const SIM_CTRL_REQ_WIRETAPPING: bool = false;
|
||||
const MGM_REQ_WIRETAPPING: bool = false;
|
||||
const PCDU_REQ_WIRETAPPING: bool = false;
|
||||
const MGT_REQ_WIRETAPPING: bool = false;
|
||||
const SIM_CTRL_REQ_WIRETAPPING: bool = true;
|
||||
const MGM_REQ_WIRETAPPING: bool = true;
|
||||
const PCDU_REQ_WIRETAPPING: bool = true;
|
||||
const MGT_REQ_WIRETAPPING: bool = true;
|
||||
|
||||
// The simulation controller processes requests and drives the simulation.
|
||||
pub struct SimController {
|
||||
@ -74,7 +72,7 @@ impl SimController {
|
||||
loop {
|
||||
match self.request_receiver.try_recv() {
|
||||
Ok(request) => {
|
||||
if request.timestamp < old_timestamp && WARNING_FOR_STALE_DATA {
|
||||
if request.timestamp < old_timestamp {
|
||||
log::warn!("stale data with timestamp {:?} received", request.timestamp);
|
||||
}
|
||||
if let Err(e) = match request.component() {
|
||||
|
@ -236,7 +236,7 @@ pub mod eps {
|
||||
RequestSwitchInfo = 1,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
||||
pub enum PcduRequest {
|
||||
SwitchDevice {
|
||||
switch: PcduSwitch,
|
||||
|
@ -8,10 +8,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
# [v0.2.0] 2024-11-04
|
||||
|
||||
Semver bump, due to added features in v0.1.4
|
||||
|
||||
# [v0.1.4] 2024-04-24
|
||||
|
||||
## Added
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "satrs-shared"
|
||||
description = "Components shared by multiple sat-rs crates"
|
||||
version = "0.2.0"
|
||||
version = "0.1.4"
|
||||
edition = "2021"
|
||||
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
||||
homepage = "https://absatsw.irs.uni-stuttgart.de/projects/sat-rs/"
|
||||
@ -22,13 +22,12 @@ version = "0.3"
|
||||
optional = true
|
||||
|
||||
[dependencies.spacepackets]
|
||||
version = ">0.9, <=0.12"
|
||||
version = ">0.9, <=0.11"
|
||||
default-features = false
|
||||
|
||||
[features]
|
||||
serde = ["dep:serde", "spacepackets/serde"]
|
||||
defmt = ["dep:defmt", "spacepackets/defmt"]
|
||||
spacepackets = ["dep:defmt", "spacepackets/defmt"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
rustdoc-args = ["--cfg", "docs_rs", "--generate-link-to-definition"]
|
||||
|
@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
export RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options"
|
||||
cargo +nightly doc --all-features --open
|
@ -1,23 +0,0 @@
|
||||
Checklist for new releases
|
||||
=======
|
||||
|
||||
# Pre-Release
|
||||
|
||||
1. Make sure any new modules are documented sufficiently enough and check docs by running
|
||||
`docs.sh`.
|
||||
2. Bump version specifier in `Cargo.toml`.
|
||||
3. Update `CHANGELOG.md`: Convert `unreleased` section into version section with date and add new
|
||||
`unreleased` section.
|
||||
4. Run `cargo test --all-features` or `cargo nextest r --all-features` and `cargo test --doc`.
|
||||
5. Run `cargo fmt` and `cargo clippy`. Check `cargo msrv` against MSRV in `Cargo.toml`.
|
||||
6. Wait for CI/CD results for EGit and Github. These also check cross-compilation for bare-metal
|
||||
targets.
|
||||
|
||||
# Release
|
||||
|
||||
1. `cargo publish`
|
||||
|
||||
# Post-Release
|
||||
|
||||
1. Create a new release on `EGit` with the name `satrs-<version>`.
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! This crates contains modules shared among other sat-rs framework crates.
|
||||
#![no_std]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![cfg_attr(docs_rs, feature(doc_auto_cfg))]
|
||||
pub mod res_code;
|
||||
|
@ -20,14 +20,14 @@ smallvec = "1"
|
||||
crc = "3"
|
||||
|
||||
[dependencies.satrs-shared]
|
||||
version = ">=0.1.3, <=0.2"
|
||||
version = ">=0.1.3, <0.2"
|
||||
|
||||
[dependencies.num_enum]
|
||||
version = ">0.5, <=0.7"
|
||||
default-features = false
|
||||
|
||||
[dependencies.spacepackets]
|
||||
version = "0.12"
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
|
||||
[dependencies.cobs]
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! # sat-rs: A library to build on-board software for remote systems
|
||||
//! # sat-rs: A framework to build on-board software for remote systems
|
||||
//!
|
||||
//! You can find more information about the sat-rs framework on the
|
||||
//! [homepage](https://absatsw.irs.uni-stuttgart.de/projects/sat-rs/).
|
||||
|
1
serialization-prototyping/.gitignore
vendored
Normal file
1
serialization-prototyping/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
1242
serialization-prototyping/Cargo.lock
generated
Normal file
1242
serialization-prototyping/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
14
serialization-prototyping/Cargo.toml
Normal file
14
serialization-prototyping/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "msg-pack-test"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
satrs-minisim = { version = "0.1", path = "../satrs-minisim" }
|
||||
satrs = { version = "0.2", path = "../satrs" }
|
||||
rmp-serde = "1"
|
||||
rmpv = { version = "1", features = ["with-serde"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1"
|
1
serialization-prototyping/python-test/.gitignore
vendored
Normal file
1
serialization-prototyping/python-test/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/venv
|
51
serialization-prototyping/python-test/main.py
Executable file
51
serialization-prototyping/python-test/main.py
Executable file
@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env python3
|
||||
import enum
|
||||
from socket import AF_INET, SOCK_DGRAM, socket
|
||||
from pydantic import BaseModel
|
||||
import msgpack
|
||||
|
||||
|
||||
TEST_PERSON = {
|
||||
"age": 24,
|
||||
"name": "Nadine",
|
||||
}
|
||||
|
||||
|
||||
class Devices(str, enum.Enum):
|
||||
MGT = "Mgt"
|
||||
MGM = "Mgm"
|
||||
|
||||
|
||||
class SwitchState(str, enum.Enum):
|
||||
OFF = "Off"
|
||||
ON = "On"
|
||||
UNKNOWN = "Unknown"
|
||||
FAULTY = "Faulty"
|
||||
|
||||
|
||||
class SwitchMap(BaseModel):
|
||||
valid: bool
|
||||
switch_map: dict[Devices, SwitchState]
|
||||
|
||||
|
||||
def msg_pack_unloading(recv_back: bytes):
|
||||
unpacked = msgpack.unpackb(recv_back)
|
||||
print(f"unpacked: {unpacked}")
|
||||
loaded_back = msgpack.loads(recv_back)
|
||||
print(loaded_back)
|
||||
|
||||
|
||||
def main():
|
||||
server_socket = socket(AF_INET, SOCK_DGRAM)
|
||||
target_address = "localhost", 7301
|
||||
msg_pack_stuff = msgpack.packb(TEST_PERSON)
|
||||
assert msg_pack_stuff is not None
|
||||
_ = server_socket.sendto(msg_pack_stuff, target_address)
|
||||
recv_back = server_socket.recv(4096)
|
||||
print(f"recv back: {recv_back}")
|
||||
switch_map = SwitchMap.model_validate_json(recv_back)
|
||||
print(f"switch map: {switch_map}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
2
serialization-prototyping/python-test/requirements.txt
Normal file
2
serialization-prototyping/python-test/requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
msgpack==1.0.8
|
||||
pydantic==2.7
|
88
serialization-prototyping/src/archive.rs
Normal file
88
serialization-prototyping/src/archive.rs
Normal file
@ -0,0 +1,88 @@
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)]
|
||||
pub enum Color {
|
||||
Red = 0,
|
||||
Green = 1,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
struct Human {
|
||||
age: u16,
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
struct HumanAdvanced {
|
||||
id: u32,
|
||||
age: u16,
|
||||
name: String,
|
||||
fav_color: Color,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
struct HumanGroup {
|
||||
humans: Vec<HumanAdvanced>,
|
||||
bank: HashMap<u32, usize>,
|
||||
}
|
||||
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn random_testing() {
|
||||
let mut buf = Vec::new();
|
||||
let john = HumanAdvanced {
|
||||
id: 0,
|
||||
age: 42,
|
||||
name: "John".into(),
|
||||
fav_color: Color::Green,
|
||||
};
|
||||
|
||||
john.serialize(&mut Serializer::new(&mut buf)).unwrap();
|
||||
|
||||
println!("{:?}", buf);
|
||||
let new_val: HumanAdvanced = rmp_serde::from_slice(&buf).expect("deserialization failed");
|
||||
let rmpv_val: rmpv::Value = rmp_serde::from_slice(&buf).expect("serialization into val failed");
|
||||
println!("RMPV value: {:?}", rmpv_val);
|
||||
let json_str = serde_json::to_string(&rmpv_val).expect("creating json failed");
|
||||
assert_eq!(john, new_val);
|
||||
println!("JSON str: {}", json_str);
|
||||
let val_test: HumanAdvanced = serde_json::from_str(&json_str).expect("wild");
|
||||
println!("val test: {:?}", val_test);
|
||||
|
||||
let nadine = HumanAdvanced {
|
||||
id: 1,
|
||||
age: 24,
|
||||
name: "Nadine".into(),
|
||||
fav_color: Color::Red,
|
||||
};
|
||||
let mut bank = HashMap::default();
|
||||
bank.insert(john.id, 1000000);
|
||||
bank.insert(nadine.id, 1);
|
||||
|
||||
let human_group = HumanGroup {
|
||||
humans: vec![john, nadine.clone()],
|
||||
bank,
|
||||
};
|
||||
let json_str = serde_json::to_string(&nadine).unwrap();
|
||||
println!("Nadine as JSON: {}", json_str);
|
||||
|
||||
let nadine_is_back: HumanAdvanced = serde_json::from_str(&json_str).unwrap();
|
||||
println!("nadine deserialized: {:?}", nadine_is_back);
|
||||
|
||||
let human_group_json = serde_json::to_string(&human_group).unwrap();
|
||||
println!("human group: {}", human_group_json);
|
||||
println!("human group json size: {}", human_group_json.len());
|
||||
|
||||
let human_group_rmp_vec = rmp_serde::to_vec_named(&human_group_json).unwrap();
|
||||
println!("human group msg pack size: {:?}", human_group_rmp_vec.len());
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn send_back_weird_stuff(buf: &[u8], received: usize, socket: &UdpSocket, src: SocketAddr) {
|
||||
let human_from_python: rmpv::Value = rmp_serde::from_slice(&buf[..received]).expect("blablah");
|
||||
let human_attempt_2: Human = rmp_serde::from_slice(&buf[..received]).expect("blhfwhfw");
|
||||
println!("human from python: {}", human_from_python);
|
||||
println!("human 2 from python: {:?}", human_attempt_2);
|
||||
let send_back_human = rmp_serde::to_vec_named(&human_attempt_2).expect("k32k323k2");
|
||||
socket
|
||||
.send_to(&send_back_human, src)
|
||||
.expect("sending back failed");
|
||||
}
|
61
serialization-prototyping/src/main.rs
Normal file
61
serialization-prototyping/src/main.rs
Normal file
@ -0,0 +1,61 @@
|
||||
#![allow(unused_imports)]
|
||||
use rmp_serde::{Deserializer, Serializer};
|
||||
use satrs_minisim::eps::{SwitchMap, SwitchMapWrapper};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
net::{SocketAddr, UdpSocket},
|
||||
};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
|
||||
pub struct SwitchSet {
|
||||
pub valid: bool,
|
||||
pub switch_map: SwitchMap,
|
||||
}
|
||||
|
||||
pub struct UdpServer {
|
||||
socket: UdpSocket,
|
||||
last_sender: Option<SocketAddr>,
|
||||
}
|
||||
|
||||
impl Default for UdpServer {
|
||||
fn default() -> Self {
|
||||
UdpServer {
|
||||
socket: UdpSocket::bind("127.0.0.1:7301").expect("binding UDP socket failed"),
|
||||
last_sender: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UdpServer {
|
||||
pub fn send_back_reply(&self, reply: &[u8]) {
|
||||
self.socket
|
||||
.send_to(reply, self.last_sender.expect("last sender not set"))
|
||||
.expect("sending back failed");
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut udp_server = UdpServer::default();
|
||||
|
||||
loop {
|
||||
// Receives a single datagram message on the socket. If `buf` is too small to hold
|
||||
// the message, it will be cut off.
|
||||
let mut buf = [0; 4096];
|
||||
let (received, src) = udp_server
|
||||
.socket
|
||||
.recv_from(&mut buf)
|
||||
.expect("receive call failed");
|
||||
udp_server.last_sender = Some(src);
|
||||
println!("received {} bytes from {:?}", received, src);
|
||||
let switch_map_off = SwitchMapWrapper::default();
|
||||
let switch_set = SwitchSet {
|
||||
valid: true,
|
||||
switch_map: switch_map_off.0.clone(),
|
||||
};
|
||||
let switch_map_off_json =
|
||||
serde_json::to_string(&switch_set).expect("json serialization failed");
|
||||
println!("sending back reply: {}", switch_map_off_json);
|
||||
udp_server.send_back_reply(switch_map_off_json.as_bytes());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user