{"id":21590946,"url":"https://github.com/spaceteam/llserver_ecui_houbolt","last_synced_at":"2025-05-05T17:38:35.677Z","repository":{"id":198945586,"uuid":"210825927","full_name":"SpaceTeam/llserver_ecui_houbolt","owner":"SpaceTeam","description":"Low-Level Server for the Engine Control Unit Interface; talks to Mikrocontroller","archived":false,"fork":false,"pushed_at":"2025-04-10T19:10:02.000Z","size":227517,"stargazers_count":2,"open_issues_count":2,"forks_count":1,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-04-10T20:38:48.628Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SpaceTeam.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-09-25T11:15:26.000Z","updated_at":"2025-03-21T15:22:41.000Z","dependencies_parsed_at":null,"dependency_job_id":"2fff73ed-3362-4fff-9866-2f450c857de2","html_url":"https://github.com/SpaceTeam/llserver_ecui_houbolt","commit_stats":null,"previous_names":["spaceteam/llserver_ecui_houbolt"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpaceTeam%2Fllserver_ecui_houbolt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpaceTeam%2Fllserver_ecui_houbolt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpaceTeam%2Fllserver_ecui_houbolt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpaceTeam%2Fllserver_ecui_houbolt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SpaceTeam","download_url":"https://codeload.github.com/SpaceTeam/llserver_ecui_houbolt/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252543898,"owners_count":21765241,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-24T16:21:15.182Z","updated_at":"2025-05-05T17:38:35.669Z","avatar_url":"https://github.com/SpaceTeam.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1\u003eLow Level Server for the SpaceTeam Mission Control System\u003c/h1\u003e\n\n\u003ch2\u003eTable of Contents\u003c/h2\u003e\n\n\n- [Overview](#overview)\n- [Requirements](#requirements)\n- [Installation](#installation)\n  - [Build options](#build-options)\n  - [Supported CAN Drivers](#supported-can-drivers)\n- [CAN Protocol](#can-protocol)\n- [The importance of States](#the-importance-of-states)\n- [Events](#events)\n  - [State to CAN Command](#state-to-can-command)\n  - [State to State](#state-to-state)\n  - [Trigger Types](#trigger-types)\n- [Configuration](#configuration)\n  - [config.json](#configjson)\n  - [mapping.json](#mappingjson)\n    - [CANMapping](#canmapping)\n    - [DefaultEventMapping](#defaulteventmapping)\n    - [EventMapping](#eventmapping)\n    - [GUIMapping](#guimapping)\n- [Autonomous Control Test Sequence](#autonomous-control-test-sequence)\n  - [`globals` section](#globals-section)\n  - [`data` section](#data-section)\n  - [Abort Sequence Format](#abort-sequence-format)\n- [TCP Socket Message Types](#tcp-socket-message-types)\n- [UDP Socket Endpoint for LoRa](#udp-socket-endpoint-for-lora)\n  - [LoRa Config](#lora-config)\n- [Troubleshooting](#troubleshooting)\n\n## Overview\n\nThe SpaceTeam Mission Control System (STMC) Suite consists of multiple programms that\nform a system for Monitoring and Remote Control Purposes. Historically it was developed\nfor Testing Rocket Engines and has then been further extended to be usable as a MissionControl\nInterface. For further information follow [SpaceTeam Mission Control System](...)\n\n**The Low Level Server is responsible for handling and processing all time critical tasks**\n\nThis includes the implementation of \n- our own [CAN Protocol](https://github.com/SpaceTeam/can_houbolt)\n- a possible UDP endpoint for using our CAN Protocol in an optimized way using\n  our custom LoRa shield with a custom LoRa Driver (will get public soon)\n- the Database Interface (influxDB) \n- the Control Sequence Logic\n- the Interface to our own [Webserver](https://github.com/SpaceTeam/web_ecui_houbolt) \n  \nThe complexity of this program lies in the various configurable\noptions for initialization and during runtime. They are split into two files that \n**must** must reside in the same directory:\n\n- config.json - the config file for socket endpoints, sampling rates, CAN bus params, etc.\n- mapping.json \n  - [CANMapping](#canmapping)\n  - [DefaultEventMapping](#defaulteventmapping)\n  - [EventMapping](#eventmapping)\n  - [GUIMapping](#guimapping)\n\nIn our setup these files can be found in [config_ecui](https://github.com/SpaceTeam/config_ecui), but this is not mandatory.\nThe config file directory path can be set either by passing it on start as an argument\nor by setting the environment variable **ECUI_CONFIG_PATH**. The argument has\npriority over the environment variable.\n\n## Requirements\n\n\u003eNote: If you would like to use the llserver out of the box you also need to\ninstall our webserver and a bunch of other tools. But don't worry, **we've written\nan easy to setup guide in our [config_ecui](https://github.com/SpaceTeam/config_ecui)\nrepository.** Otherwise you first need to implement a tcp server with our communication\nprotocol in order to start receiving data.\n\nThe simplest way to use the llserver is by setting it up inside a docker container\nin that case docker engine needs to be preinstalled. \n\nFirst you need to install an influxdb (docker container recommended)\n\n## Installation\n\nTo install the llserver using docker you can run \n```\nsudo chmod +x install.sh\n./install.sh\n```\n\nThis script generates and mounts a config folder in the parent directory named\nconfig_ecui where the [config.json](#configjson) and [mapping.json](#mappingjson) files must be present.\n\n### Build options\nThe project uses cmake for compiling. You can provide different build options to\ncmake using the `-D` option:\n\n- `-D NO_PYTHON=[true | false]`\n- `-D NO_CANLIB=[true | false]`\n\nSetting one of these build flags result in not binding the corresponding libraries\nto avoid a compile error. If you would like to change one of these settings checkout\nthe Entrypoint line in the Dockerfile \n\n\u003eNOTE: different build modes require different config variables, make sure you\nhave definded all of them properly. See [config_ecui](https://github.com/SpaceTeam/config_ecui).\n\n### Supported CAN Drivers\nCurrently two drivers are supported namely\n- [Kvaser CANLIB](https://www.kvaser.com/canlib-webhelp/page_canlib.html)\n- [SocketCAN](https://docs.kernel.org/networking/can.html)\n  \nthe preferred driver can be selected inside the [config.json](#configjson).\nThe Dockerfile also installs all required kvaser canlib library files automatically.\n\n## CAN Protocol\nAs many terms from the [CAN Protocol](https://github.com/SpaceTeam/can_houbolt) \nare also used to describe many functionalities \nin the llserver, it is recommended to read through this documentation first before\nyou continue.\n\nThe llserver keeps a hashmap of all commands that are supported of the connected\nchannels. These are used in the event mapping and control sequences to\nsend commands to the hardware.\n\n## The importance of States\nThe llserver manages a hashmap filled with states which is called the\n**State Controller**. Basically every variable inside the system is represented \nas a double value inside the state controller. This includes user inputs.\n\nEach entry consists of a\n\n- state name - as key\n- value - as double\n- timestamp - 0 when uninitialized else timestamp of the last change\n- dirty flag - used for transmitting periodic status updates to the web server\n\nWe follow a naming convention which mostly boils down to\n\n`prefix:channel_name:state`\n\nas the `prefix` it is often used `gui` as all user inputs are also tracked in the\nstate controller and logged to the database. In case if something goes wrong we can \nanalyze whether a wrong user input was made or another event caused the trouble.\n**User inputs must be prefixed with `gui` in order to be processed correctly.**\n\nDespite our naming convetion of state names, one can input a state name\nwith as many `\":\"` dividers as desired. \n\n\u003eWARNING: Although a `:` is used to make the state names more readable and\nprocessable it shall be pointed out that this notation is not supported in \nhtml. Hence all `:` are translated to `-` when received at the web client.\n\n## Events\nAnother key feature of the llserver is the event system. An event can be triggered\nwhen a specific state changes its value. This is used for translating user inputs\nto CAN commands that are transmitted over the CAN bus for example. But it is also\npossible to trigger an event based on a sensor value or actuator state\nof a specific hardware channel (since they\nare all represented as states). For this behaviour to work there are two types of events\n\n### State to CAN Command\n\n```\n\"gui:Flash:Clear\": [\n    {\n        \"command\": \"ecu:RequestFlashClear\",\n        \"parameters\": []\n    },\n    {\n        \"command\": \"pmu:RequestFlashClear\",\n        \"parameters\": []\n    },\n    {\n        \"command\": \"rcu:RequestFlashClear\",\n        \"parameters\": []\n    }\n]\n```\nIn this example the `gui:Flash:Clear` state indicates a button press on the user interface. When it is pressed, a request to clear the flash of each electronics board\n(ecu, pmu, rcu) shall be transmitted. The `parameters` entry allows for additional\narguments that may be required depending on the specified command. When\na string is located inside the parameters list, the llserver tries to resolve it\nas a state inside the state controller and use its value instead. This is especially\nuseful for analog user inputs.\n\n### State to State\n```\n\"ecu:FlashStatus\": [\n    {\n        \"state\": \"gui:Flash:Clear\",\n        \"triggerType\": \"!=\",\n        \"triggerValue\": 0,\n        \"value\": 0\n    }       \t\n]\n```\n\nIn bot cases it is possible to trigger multiple actions in one go as seen in the\nexample of `gui:Flash:Clear`. Also in both cases it is possible to specify a triggerType.\n\n### Trigger Types\nEach event entry can include a `triggerType` with an additional `triggerValue`. \nThis is needed if the event shall only\nbe triggered when certain conditions are met, not everytime the state gets changed.\nPossible trigger types are:\n\n- `==` --\u003e triggers when the state value equals the `triggerValue`\n- `!=` --\u003e triggers when the state value not equals the `triggerValue`\n- `\u003e=` --\u003e triggers when the state value is greater or equal than the `triggerValue`\n- `\u003c=` --\u003e triggers when the state value is smaller or equal than the `triggerValue`\n- `\u003e` --\u003e triggers when the state value greater than the `triggerValue`\n- `\u003c` --\u003e triggers when the state value smaller than the `triggerValue`\n\n\u003eNOTE: An event with a triggerType is only triggered when the previous value\nwas outside the trigger range! In this way the event only gets triggered when\nthe value changes from outside the trigger range to the inside of the trigger range which\nmeans that if the value remains inside the trigger range over a long period the event\nonly gets triggered once. \n\nExample:\n```\n\"gui:fuel_main_valve:checkbox\": [\n    {\n        \"command\": \"fuel_main_valve:SetTargetPosition\",\n        \"triggerType\": \"==\",\n        \"triggerValue\": 0,\n        \"parameters\": [0]\n    },\n    {\n        \"command\": \"fuel_main_valve:SetTargetPosition\",\n        \"triggerType\": \"!=\",\n        \"triggerValue\": 0,\n        \"parameters\": [65535]\n    }\n]\n```\nIn this case the gui element for the fuel main valve is represented as a checkbox.\nwhen the checkbox gets pressed, the fuel main valve opens completely. Otherwise\nthe valve closes completely. When multiple actions per state exist, the program\nprocesses them step by step, as defined in the json array. **So be reminded that\na different order can cause different behaviours for more complex event mappings.**\n\n\u003eNOTE: the fuel_main_valve gui button and hardware channel have no relation at the\nbeginning. Only an entry in the EventMapping links them together.\n\n## Configuration\n\n### config.json\n\nIn the config.json file all variables are defined that are important for the\ninitialization process of the llserver. A complete example config file with\nall possible entries can be viewed in the [config_ecui](https://github.com/SpaceTeam/config_ecui) repo.\n\n### mapping.json\n\nThe mapping.json file consists of four different parts. Each one must be at least\ndeclared as an empty object, i.e.\n\n```\n{\n    \"CANMapping\": {},\n    \"DefaultEventMapping\": {},\n    \"EventMapping\": {},\n    \"GUIMapping\": {}\n}\n```\n#### CANMapping\n\n```\n\"CANMapping\": {\n    \"7\": {\n            \"0\": {\n                \"offset\": 0,\n                \"slope\": 0.00010071,\n                \"stringID\": \"pmu_5V_voltage\"\n            },\n            \"1\": {\n                \"offset\": 0,\n                \"slope\": 0.00010071,\n                \"stringID\": \"pmu_5V_high_load_voltage\"\n            },\n            \"2\": {\n                \"offset\": 0,\n                \"slope\": 0.00033234,\n                \"stringID\": \"pmu_12V_voltage\"\n            }\n            \"stringID\": \"pmu\"\n        }\n    },\n```\nSince in a CAN Network multiple **Nodes** comunicate with each other using IDs, \nwe want to assign readable names to each node and each channel, so we\ncan work with them more easily.\nA node entry starts with its unique identifier as a key and contains an object,\nwith arbitrary many channel entries. Each channel has a `\u003cchannel_name\u003e:sensor` state that\ncan be scaled with the two entries `offset` and `slope`. The readable name\nis defined with `stringID`.\nA specification of the channel type is not needed since this information is loaded\nwhen the nodes get initialized.\n\n\n#### DefaultEventMapping\n\nThe default event mapping can be used to define generic behaviour for gui elements\nacting on hardware channels.\n```\n\"DefaultEventMapping\": {\n    \"DigitalOut\": [\n        {\n            \"command\": \"DigitalOut:SetState\",\n            \"parameters\": [\n                \"DigitalOut\"\n            ]\n        }\n    ],\n    \"Servo\": [\n        {\n            \"command\": \"Servo:SetTargetPosition\",\n            \"parameters\": [\n                \"Servo\"\n            ]\n        }\n    ]\n}\n```\nThe default behaviour for a gui element can be overwritten by an entry\nin the event mapping. The key of an action may be an hardware channel type\nwhich defines an action for each hardware channel of this type. The \nchannel type name can be also used to describe the command and parameters.\nThis gets then replaced with the actual channel name that is currently processed.\n\n#### EventMapping\n```\n\"EventMapping\": {\n    \"gui:Flash:Clear\": [\n        {\n            \"command\": \"ecu:RequestFlashClear\",\n            \"parameters\": []\n        },\n        {\n            \"command\": \"pmu:RequestFlashClear\",\n            \"parameters\": []\n        },\n        {\n            \"command\": \"rcu:RequestFlashClear\",\n            \"parameters\": []\n        }\n    ]\n}\n```\nAn entry in the event mapping prevents default behaviours defined in the\nDefaultEventMapping from being triggered. For further information about\nevents go to the [Events](#events) section.\n#### GUIMapping\n```\n\"GUIMapping\": [\n    {\n        \"label\": \"Fuel Tank Pressure\",\n        \"state\": \"fuel_tank_pressure:sensor\"\n    },\n    {\n        \"label\": \"Ox Tank Pressure\",\n        \"state\": \"ox_tank_pressure:sensor\"\n    },\n    {\n        \"label\": \"Supercharge Valve\",\n        \"state\": \"supercharge_valve:sensor\"\n    }\n]\n```\n\nThe GUI Mapping is a config option to tell the user interface, how a gui element\nwith a certain state shall be named in an even more human readable way as state names.\nThis information only gets transmitted to the user interface and has no implications\non the llserver.\n\n## Autonomous Control Test Sequence\n\nTo be able to test a liquid engine it is normally required to execute multiple commands\nin a very short amount of time (pressurization, ignition, engine ramp-up, etc.).\n\nFor this purpose a sequence manager has been developed for automatic test sequences.\n\nTest Sequences are defined inside the `$ECUI_CONFIG_PATH/sequences/` folder.\nEach sequence uses the JSON format and consists of two main objects:\n- `globals` - general definitions used for the sequence processing\n- `data` - the actual sequence\n\n### `globals` section\nInside the `globals` section following entries are needed\n\n| key               | type   | value                                                                                                                      |\n| ----------------- | ------ | -------------------------------------------------------------------------------------------------------------------------- |\n| `\"startTime\"`     | float  | relative start of the squence (may also be negative)                                                                       |\n| `\"endTime\"`       | float  | relative end of the sequence                                                                                               |\n| `\"interpolation\"` | object | object with command name as key and either `\"none\"`(step function behaviour) or `\"linear\"`(linear interpolation) as values |\n| `\"interval\"`      | float  | time precision of each iteration step                                                                                      |\n| `\"ranges\"`        | array  | list of state names used for range checking                                                                                |\n\nThe interpolation entry specifies the behaviour between datapoints of the sequence.\nThe range entry is used to specify each state used for range checking. This means that at each datapoint a range can be\nset in which the specified sensor must reside. If the sensor value gets out of range and **autoabort** is active inside the config.json\nthe sequence gets aborted instantly.\n\n### `data` section\n\nThe data section includes a list of **command group**. These can be\nused to group multiple datapoints relatively to one timestamp in order\nto be moved more easily along the time axis if for example the burntime changes.\n\nEach group command includes\n | key           | type            | value                                                                                                                         |\n | ------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------- |\n | `\"timestamp\"` | string or float | if timestamp is string only `\"START\"` or `\"END\"` are allowed which get replace by `\"startTime\"` and `\"endTime\"` respectively. |\n | `\"name\"`      | string          | name of the command group                                                                                                     |\n | `\"desc\"`      | string          | description                                                                                                                   |\n | `\"actions\"`   | array           | list of datapoints with relative timestamp to command group                                                                   |\n |               |\n\n\nEach datapoint may include\n | key                    | type            | value                                                                                                            |\n | ---------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------- |\n | `\"timestamp\"`          | float           | timestamp relative to command group (here **only floats are valid!**)                                            |\n | `\"\u003ccommand_name\u003e\"`     | array of floats | parameters for the specific command                                                                              |\n | `\"sensorNominalRange\"` | object          | states as keys and array of two elements with range as values (must be defined in the global section `\"ranges\"`) |\n \n\nThe first datapoint of the first command group **HAS TO** include all commands used in the sequence for proper initialization!\nEach number in actions except the timestamp is double on the LLServer.\n\n\u003e Note: The keywords \"START\" or \"END\" are only allowed in the Group Commands (objects inside data array).\n\u003e\nExample:\n```\n{\n\t\"globals\":\n\t{\n\t\t\"endTime\": 15,\n\t\t\"interpolation\":\n\t\t{\n\t\t\t\"fuel_main_valve:SetTargetPosition\": \"linear\",\n\t\t\t\"ox_main_valve:SetTargetPosition\": \"linear\",\n\t\t\t\"igniter:SetState\": \"none\"\n\t\t},\n\t\t\"interval\": 0.01,\n\t\t\"ranges\":\n\t\t[\n\t\t\t\"chamberPressure:sensor\"\n\t\t],\n\t\t\"startTime\": -10\n\t},\n\t\"data\":\n\t[\n\t\t{\n\t\t\t\"timestamp\": \"START\",\n\t\t\t\"name\": \"start\",\n\t\t\t\"desc\": \"set all to initial state\",\n\t\t\t\"actions\":\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\t\"timestamp\": 0.0,\n\t\t\t\t\t\"fuel_main_valve:SetTargetPosition\": [0],\n                    \"ox_main_valve:SetTargetPosition\": [0],\n\t\t\t\t\t\"igniter:SetState\": [0], \n\t\t\t\t\t\"sensorsNominalRange\":\n\t\t\t\t\t{\n\t\t\t\t\t\t\"chamberPressure:sensor\": [-5, 20]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"timestamp\": -3.0,\n\t\t\t\"name\": \"ignition\",\n\t\t\t\"desc\": \"lets light this candle\",\n\t\t\t\"actions\":\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\t\"timestamp\": 0,\n\t\t\t\t\t\"igniter:SetState\": [100]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"timestamp\": 0.0,\n\t\t\t\"name\": \"engine startup\",\n\t\t\t\"desc\": \"ramp up engine\",\n\t\t\t\"actions\":\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\t\"timestamp\": 0,\n\t\t\t\t\t\"fuel_main_valve:SetTargetPosition\": [0],\n\t\t\t\t\t\"ox_main_valve:SetTargetPosition\": [0]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"timestamp\": 0.5,\n\t\t\t\t\t\"ox_main_valve:SetTargetPosition\": [15000],\n\t\t\t\t\t\"fuel_main_valve:SetTargetPosition\": [15000]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"timestamp\": 1.2,\n\t\t\t\t\t\"fuel_main_valve:SetTargetPosition\": [25000],\n\t\t\t\t\t\"ox_main_valve:SetTargetPosition\": [25000]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"timestamp\": 1.5,\n\t\t\t\t\t\"igniter:SetState\": [0]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"timestamp\": 1.7,\n\t\t\t\t\t\"fuel_main_valve:SetTargetPosition\": [100],\n\t\t\t\t\t\"ox_main_valve:SetTargetPosition\": [100]\t\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"timestamp\": 10.0,\n\t\t\t\"name\": \"shutdown\",\n\t\t\t\"desc\": \"engine shutdown\",\n\t\t\t\"actions\":\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\t\"timestamp\": 0,\n\t\t\t\t\t\"fuel_main_valve:SetTargetPosition\": [100],\n\t\t\t\t\t\"ox_main_valve:SetTargetPosition\": [100]\n\t\t\t\t},\n                {\n\t\t\t\t\t\"timestamp\": 0.7,\n\t\t\t\t\t\"fuel_main_valve:SetTargetPosition\": [0],\n\t\t\t\t\t\"ox_main_valve:SetTargetPosition\": [0]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"timestamp\": \"END\",\n\t\t\t\"name\": \"end\",\n\t\t\t\"desc\": \"the end\",\n\t\t\t\"actions\":\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\t\"timestamp\": 0.0,\n\t\t\t\t\t\"fuel_main_valve:SetTargetPosition\": [0],\n\t\t\t\t\t\"ox_main_valve:SetTargetPosition\": [0]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t]\n}\n```\n\n### Abort Sequence Format\n\nAnother feature is the ability to define a **\"safe state\"** to be\nexecuted in order the test control sequence fails or gets aborted.\n\nTest Abort Sequence is defined inside the `$ECUI_CONFIG_PATH/sequences/abort_sequences/` folder. Currently only one abort sequence is supported and\nmust be named `AbortSequence.json`.\n\nFor now exactly one object with all commands to be executed.\nThe `\"endTime\"` key in `\"globals\"` is used to describe for how long the logging should continue\nin case of an abort.\n\n\t{  \n\t    \"globals\": {\n            \"endTime\": 3.2                              //double\n        },\n\t    \"actions\" : {  \n\t        \"fuel_main_valve:SetTargetPosition\": [0],  \t//array[double]\n\t\t    \"igniter:SetState\": [0],  \t\t\t\t    //array[double]\n\t\t    \"ox_main_valve:SetTargetPosition\": [0]      //array[double]\n\t    }  \n\t}\n\n## TCP Socket Message Types\n\nIn order to communicate with the webserver, a tcp socket connection is \nestablished. **It is mandatory to send the llserver specific messages\nto initate state transmission and start test control sequences.**\n\nFor the whole API documentation refer to [Webserver](https://github.com/SpaceTeam/web_ecui_houbolt) \n\n## UDP Socket Endpoint for LoRa\n\nThis protocol is based on our [CAN Protocol](#can-protocol).\n\nThis implementation uses LoRa as an unidirectional method for receiving\ndata from the rocket during flight. For receiving LoRa messages a custom\nLoRa shield is used on a raspberry pi. (Repo coming soon)\nA UDP socket connection is used for data transmission between llserver and \nraspberry pi.\n\nAfter the internal control\nof the rocket takes over and no further commands are sent to the rocket\nthe only message type that the rocket sends automatically and periodically\nis the `DataMsg_t` of each Generic Channel. This means we can strip the LoRa\nmessage down to only data messages and can even combine them into one large\nmessage. This is done on our RCU (Radio Control Unit) which listens to the\nCAN FD bus for any data messages and updates a buffer which is split into\nas many regions as generic channels exists inside the rocket (number of CAN\nnodes). \n\nSince the data message length is highly variable and considered to be \nspecified within the channel_mask, the header alone takes up an unnessesary \nlarge amount of bytes that can be considered \"constant\" during \nflight. Therefore the CAN header + data message header gets removed \nfor the LoRa messages\nand is statically entered inside the [config.json](#configjson).\n\nThere is only one additional byte for each generic channel which indicates if the \nsection contains valid data. **THIS BYTE IS NOT INCLUDED IN THE CONFIG canMsgSize ENTRY!**\n\n### LoRa Config\n\nThe `LORA` section in the [config.json](#configjson) includes\n\n```\n\"LORA\": {\n    \"ip\": \"192.168.1.7\",\n    \"port\": 5001,\n    \"nodeIDsRef\": [6, 8],\n    \"nodeIDs\": [16, 18],\n    \"canMsgSizes\": [54, 39]\n}\n```\n\nThe `ip` and `port` describe the udp endpoint to the raspberry pi.\n\nThe `nodeIDsRef` array defines the corresponding node ids on the CAN FD bus. This\nis needed since the LoRa messages are injected in the CAN Manager as normal CAN messages\nand therefore need to load the correct CAN header before the message is injected. This\nmeans that the hardware **MUST** be connected over the CAN FD bus for the initialization \nof the llserver in order to initialize the nodes correctly. Otherwise the LoRa messages cannot\nbe decoded and are lost!\n\nThe `nodeIDs` array contains the node ids for the LoRa channels (in this case CAN FD bus node ids\nprepended with 1)\n\nThe `canMsgSizes` array contains the message size of each can data message (**HEADER BYTE EXCLUDED**)\n\n\n\u003eNOTE: that depending on the total message length, the LoRa driver on\nthe raspberrypi must be configured correctly as well. See (LoRa doc coming\nsoon...)\n\n\n## Troubleshooting\n\n- Every Sequence needs to define each device at the \"START\" timestamp\n- **Make sure every \"sensorsNominalRange\" object in the sequence contains ALL sensors, with a range\nspecified**\n\n\n- if the llserver fails to connect to the web server or carshes instantly try\nto check if the correct ip addresses are used in the config file with\n`sudo docker network inspect bridge`\n\n- if either or both web and llserver refuse to start, try and check the docker environment variable for the correct config path\n\n- if the llserver crashes instantly check if influx is correctly installed","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspaceteam%2Fllserver_ecui_houbolt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspaceteam%2Fllserver_ecui_houbolt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspaceteam%2Fllserver_ecui_houbolt/lists"}