diff --git a/tlm-cmd-code-generator/.flake8 b/tlm-cmd-code-generator/.flake8 new file mode 100644 index 000000000..1d1919b57 --- /dev/null +++ b/tlm-cmd-code-generator/.flake8 @@ -0,0 +1,8 @@ +[flake8] +max-line-length = 100 +ignore = + # black と競合するので + E203, + E501, + W503, + W504 diff --git a/tlm-cmd-code-generator/.github/ISSUE_TEMPLATE/action_item.md b/tlm-cmd-code-generator/.github/ISSUE_TEMPLATE/action_item.md new file mode 100644 index 000000000..5c06b8b52 --- /dev/null +++ b/tlm-cmd-code-generator/.github/ISSUE_TEMPLATE/action_item.md @@ -0,0 +1,26 @@ +--- +name: Action Item +about: AI 管理用テンプレート +title: '' +labels: '' +assignees: '' + +--- + +## 概要 +ひとことで + +## 詳細 +詳しく + +## close条件 +どうなったらcloseできるか + +## 備考 +なにかあれば + +## 注意 +- 関連する Projects が存在する場合,それの紐付けを行うこと +- 可能ならば `priority` ラベルを付けること +- 可能ならば Assignees を設定すること +- close するときは結論を明記すること diff --git a/tlm-cmd-code-generator/.github/ISSUE_TEMPLATE/bug_report.md b/tlm-cmd-code-generator/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..7c03c968a --- /dev/null +++ b/tlm-cmd-code-generator/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,37 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +## 概要 +ひとことで + +## 詳細 +### 詳細症状 +どういうバグか + +### 発生条件 +発生した環境,症状,パラメタなど + +### 追加資料 +あればリンクなどを貼る + +## 必要な作業 +- [ ] あれして +- [ ] これする + +## 影響範囲 +tool類が全部死ぬ... みたいな + +## 補足 +何かれば + +## 注意 +- 関連する Projects が存在する場合,それの紐付けを行うこと +- 可能ならば `priority` ラベルを付けること +- 可能ならば Assignees を設定すること +- close するときは結論を明記すること diff --git a/tlm-cmd-code-generator/.github/PULL_REQUEST_TEMPLATE.md b/tlm-cmd-code-generator/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..82728e779 --- /dev/null +++ b/tlm-cmd-code-generator/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,23 @@ +## 概要 +ひとことで + +## Issue +- 関連する issue + +## 詳細 +詳しく + +## 検証結果 +test へのリンクや,検証結果へのリンク + +## 影響範囲 +XX系の動作がガラッと変わる,とか. + +## 補足 +何かあれば + +## 注意 +- 関連する Projects が存在する場合,それの紐付けを行うこと +- Assignees を設定すること +- 可能ならば Reviewers を設定すること +- 可能ならば `priority` ラベルを付けること diff --git a/tlm-cmd-code-generator/.github/labels.yml b/tlm-cmd-code-generator/.github/labels.yml new file mode 100644 index 000000000..60ca01d51 --- /dev/null +++ b/tlm-cmd-code-generator/.github/labels.yml @@ -0,0 +1,55 @@ +- name: "bug" + color: "d73a4a" + description: "Something isn't working" + +- name: "documentation" + color: "0075ca" + description: "Improvements or additions to documentation" + +- name: "duplicate" + color: "cfd8d7" + description: "This issue or pull request already exists" + +- name: "enhancement" + description: "New feature or request" + color: "a2eeef" + +- name: "good first issue" + description: "Good for newcomers" + color: "7057ff" + +- name: "help wanted" + description: "Extra attention is needed" + color: "008672" + +- name: "invalid" + description: "This doesn't seem right" + color: "e4e669" + +- name: "question" + description: "Further information is requested" + color: "d876e3" + +- name: "wontfix" + description: "This will not be worked on" + color: "ffffff" + +- name: "icebox" + description: "icebox or pending" + color: "c5def5" + +- name: "priority::high" + description: "priorityg high" + color: "d93f0b" + +- name: "priority::low" + description: "priority low" + color: "9dcce0" + +- name: "priority::medium" + description: "priority medium" + color: "fbca04" + +- name: "tools" + description: "" + color: "510f70" diff --git a/tlm-cmd-code-generator/.github/workflows/actionlint.yml b/tlm-cmd-code-generator/.github/workflows/actionlint.yml new file mode 100644 index 000000000..4ef847aaf --- /dev/null +++ b/tlm-cmd-code-generator/.github/workflows/actionlint.yml @@ -0,0 +1,17 @@ +name: reviewdog / actionlint + +on: + pull_request: + paths: + - '.github/workflows/**' + +jobs: + actionlint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: reviewdog/action-actionlint@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-pr-review + fail_on_error: true diff --git a/tlm-cmd-code-generator/.github/workflows/labeler.yml b/tlm-cmd-code-generator/.github/workflows/labeler.yml new file mode 100644 index 000000000..82cb5d166 --- /dev/null +++ b/tlm-cmd-code-generator/.github/workflows/labeler.yml @@ -0,0 +1,25 @@ +name: labeler + +on: + push: + branches: + - main + pull_request: + paths: + - .github/workflows/labeler.yml + - .github/labels.yml + +jobs: + labeler: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Run Labeler + uses: crazy-max/ghaction-github-labeler@v4 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + yaml-file: .github/labels.yml + skip-delete: false + dry-run: ${{ github.ref != 'refs/heads/main' }} diff --git a/tlm-cmd-code-generator/.github/workflows/python_check_format.yml b/tlm-cmd-code-generator/.github/workflows/python_check_format.yml new file mode 100644 index 000000000..ca77e90f5 --- /dev/null +++ b/tlm-cmd-code-generator/.github/workflows/python_check_format.yml @@ -0,0 +1,25 @@ +name: reviewdog / python format check + +on: + push: + branches: + - main + pull_request: + +jobs: + black_format: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + # - name: check python format with black + # uses: psf/black@stable + + - uses: reviewdog/action-black@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + # reporter: github-pr-review # TODO: いい感じになったら直す + reporter: github-pr-check + filter_mode: nofilter + fail_on_error: true + level: warning diff --git a/tlm-cmd-code-generator/.github/workflows/python_lint.yml b/tlm-cmd-code-generator/.github/workflows/python_lint.yml new file mode 100644 index 000000000..e2c78d63a --- /dev/null +++ b/tlm-cmd-code-generator/.github/workflows/python_lint.yml @@ -0,0 +1,27 @@ +name: reviewdog / lint python + +on: + push: + branches: + - main + pull_request: + +jobs: + flake8_lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up python environment + uses: actions/setup-python@v4 + with: + python-version: "3.8" + + - name: flake8 Lint + uses: reviewdog/action-flake8@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-pr-review + filter_mode: nofilter + fail_on_error: true + level: warning diff --git a/tlm-cmd-code-generator/.github/workflows/validate-renovate.yml b/tlm-cmd-code-generator/.github/workflows/validate-renovate.yml new file mode 100644 index 000000000..84b52217e --- /dev/null +++ b/tlm-cmd-code-generator/.github/workflows/validate-renovate.yml @@ -0,0 +1,22 @@ +name: validate / renovate.json + +on: + pull_request: + paths: + - 'renovate.json' + - '.github/workflows/validate-renovate.yml' + +jobs: + validate-renovate: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + + - name: install + run: | + npm install -g renovate + - name: validate + run: | + renovate-config-validator diff --git a/tlm-cmd-code-generator/.gitignore b/tlm-cmd-code-generator/.gitignore new file mode 100644 index 000000000..abe7f23f5 --- /dev/null +++ b/tlm-cmd-code-generator/.gitignore @@ -0,0 +1,16 @@ +# OSX +.DS_Store +.AppleDouble +.LSOverride +Icon + +# Thumbnails +._* + +# Files that might appear on external disk +.Spotlight-V100 +.Trashes + +# others +*.pyc +gstos_files/* diff --git a/tlm-cmd-code-generator/GenerateC2ACode.py b/tlm-cmd-code-generator/GenerateC2ACode.py new file mode 100644 index 000000000..8ec163d10 --- /dev/null +++ b/tlm-cmd-code-generator/GenerateC2ACode.py @@ -0,0 +1,53 @@ +# coding: UTF-8 +""" +python 3.7以上を要求 +""" + +import json +import sys + +import my_mod.load_db +import my_mod.cmd_def +import my_mod.tlm_def +import my_mod.tlm_buffer + + +# import pprint +# import os.path +# import msvcrt # Enter不要な入力用 +# import subprocess + + +# 環境変数 +DEBUG = 0 +# 0 : Release +# 1 : all +SETTING_FILE_PATH = "settings.json" + + +def main(): + with open(SETTING_FILE_PATH, mode="r") as fh: + settings = json.load(fh) + # print(settings["path_to_src"]); + + cmd_db = my_mod.load_db.LoadCmdDb(settings) + tlm_db = my_mod.load_db.LoadTlmDb(settings) + # pprint.pprint(cmd_db) + # pprint.pprint(tlm_db) + # print(tlm_db) + + my_mod.cmd_def.GenerateCmdDef(settings, cmd_db["sgc"]) + my_mod.cmd_def.GenerateBctDef(settings, cmd_db["bct"]) + my_mod.tlm_def.GenerateTlmDef(settings, tlm_db["tlm"]) + + if settings["is_main_obc"]: + my_mod.cmd_def.GenerateOtherObcCmdDef(settings, cmd_db["other_obc"]) + my_mod.tlm_def.GenerateOtherObcTlmDef(settings, tlm_db["other_obc"]) + my_mod.tlm_buffer.GenerateTlmBuffer(settings, tlm_db["other_obc"]) + + print("Completed!") + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/tlm-cmd-code-generator/LICENSE b/tlm-cmd-code-generator/LICENSE new file mode 100644 index 000000000..89f748ff8 --- /dev/null +++ b/tlm-cmd-code-generator/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Intelligent Space Systems Laboratory, The University of Tokyo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tlm-cmd-code-generator/README.md b/tlm-cmd-code-generator/README.md new file mode 100644 index 000000000..e1fc2452e --- /dev/null +++ b/tlm-cmd-code-generator/README.md @@ -0,0 +1,106 @@ +# c2a-tlm-cmd-code-generator +[TlmCmd DB](https://github.com/ut-issl/tlm-cmd-db)からC2Aのコードを生成するためのスクリプト + +以下が自動生成される. +- command_definitions.c +- command_definitions.h +- telemetry_definitions.c +- telemetry_definitions.h +- block_command_definitions.h + +## 実行 +``` +$ python GenerateC2ACode.py +``` + +## 設定 +`settings.json` にて記述する. + +`is_main_obc` は,MOBC(地上局と通信するOBC.2nd OBCのtlm/cmdを取りまとめる)かそれ以外のOBC(2nd OBC.MOBCと通信するOBC)かを制御する. +`1` とした場合,MOBCを意図したコードが生成され,加えて以下が生成される. +- 2nd_obc_command_definitions.h +- 2nd_obc_telemetry_definitions.h +- 2nd_obc_telemetry_buffer.c +- 2nd_obc_telemetry_buffer.h +- 2nd_obc_telemetry_data_definitions.h + +``` +{ + # `src_core`, `src_user` のあるディレクトリへのパス + "path_to_src" : "../../c2a/src/", + # テレコマ DB のあるディレクトリへのパス + "path_to_db" : "../../c2a/database/", + # TlmCmdDBのファイル名の接頭辞 + "db_prefix" : "SAMPLE_MOBC", + # TLM ID の定義域 + "tlm_id_range" : ["0x00", "0x100"], + # Cmd DB の Name に "Cmd_" の接頭辞が含まれるか?(今後は含まれないのが基本とする) + "is_cmd_prefixed_in_db" : 0, + # 入力 Tlm Cmd DB のエンコーディング + "input_file_encoding" : "utf-8", + # 出力ファイルのエンコーディング + "output_file_encoding" : "utf-8", + # MOBCか?(他のOBCのtlm/cmdを取りまとめるか?) 0/1 + # 2nd OBCのコードを生成するときなどは 0 にする + # 0 の場合,以後のパラメタは無効 + "is_main_obc" : 1, + "other_obc_data" : [ + { + # OBC名 + "name" : "AOBC", + # コードを生成するか? + "is_enable" : 1, + "db_prefix" : "SAMPLE_AOBC", + "tlm_id_range" : ["0x90", "0xc0"], + "is_cmd_prefixed_in_db" : 0, + "input_file_encoding" : "utf-8", + # DBがあるディレクトリへのパス(絶対でも相対でもOK) + "path_to_db" : "../../c2a_sample_aobc/database/", + # MOBC で保持するテレメの TLM ID の最大値(=テレメ種類数) + "max_tlm_num" : 256, + "driver_path" : "Aocs/", + "driver_type" : "AOBC_Driver", + "driver_name" : "aobc", + "code_when_tlm_not_found" : "aobc_driver->info.comm.rx_err_code = AOBC_RX_ERR_CODE_TLM_NOT_FOUND;" + }, + { + # OBC名 + "name" : "TOBC", + # コードを生成するか? + "is_enable" : 1, + "db_prefix" : "SAMPLE_TOBC", + "tlm_id_range" : ["0xc0", "0xf0"], + "is_cmd_prefixed_in_db" : 0, + "input_file_encoding" : "utf-8", + # DBがあるディレクトリへのパス(絶対でも相対でもOK) + "path_to_db" : ""../../c2a_sample_tobc/database/", + # MOBC で保持するテレメの TLM ID の最大値(=テレメ種類数) + "max_tlm_num" : 256, + "driver_path" : "Thermal/", + "driver_type" : "TOBC_Driver", + "driver_name" : "tobc", + "code_when_tlm_not_found" : "tobc_driver->info.comm.rx_err_code = TOBC_RX_ERR_CODE_TLM_NOT_FOUND;" + } + ] +} +``` + +## 開発方針 +- `main`: リリース版 +- `feature/*` : 開発ブランチ + +というブランチを用いる. + +[C2A Core](https://github.com/ut-issl/c2a-core) との互換性などは,[Releases](https://github.com/ut-issl/c2a-tlm-cmd-code-generator/releases) を参照すること([詳細](https://github.com/ut-issl/c2a-core/tree/develop/Docs/.General/release.md)) + +## 要求 +- python 3.7 以上 +- 必要ライブラリは `./requirements.txt` に記載. + - なお,現在は標準ライブラリのみしか使っていない + - 以下で一括インストール可能 +``` +$ pip install -r requirements.txt +``` + +## その他 +- MOBCと2nd OBCのC2A間通信の例は (TBA). diff --git a/tlm-cmd-code-generator/my_mod/cmd_def.py b/tlm-cmd-code-generator/my_mod/cmd_def.py new file mode 100644 index 000000000..1b2f24b93 --- /dev/null +++ b/tlm-cmd-code-generator/my_mod/cmd_def.py @@ -0,0 +1,325 @@ +# coding: UTF-8 +""" +cmd def +""" + +import sys + +# import pprint + + +def GenerateCmdDef(settings, sgc_db): + output_file_path = settings["path_to_src"] + r"src_user/tlm_cmd/" + output_file_name_base = "command_definitions" + + DATA_SART_ROW = 3 + + body_c = "" + body_h = "" + # " cmd_table[Cmd_CODE_NOP].cmd_func = Cmd_NOP;" + # " Cmd_CODE_NOP = 0x0000," + for i in range(DATA_SART_ROW, len(sgc_db)): + comment = sgc_db[i][0] + name = sgc_db[i][1] + cmd_id = sgc_db[i][3] + if comment == "" and name == "": # CommentもNameも空白なら打ち切り + break + if comment != "": # Comment + continue + + cmd_name, cmd_code = GetCmdNameAndCmdCode_(name, settings["is_cmd_prefixed_in_db"]) + # print(cmd_name) + # print(cmd_code) + body_c += " cmd_table[" + cmd_code + "].cmd_func = " + cmd_name + ";\n" + body_h += " " + cmd_code + " = " + cmd_id + ",\n" + + body_c += "\n" + for i in range(DATA_SART_ROW, len(sgc_db)): + comment = sgc_db[i][0] + name = sgc_db[i][1] + cmd_id = sgc_db[i][3] + if comment == "" and name == "": # CommentもNameも空白なら打ち切り + break + if comment != "": # Comment + continue + + param_num = int(sgc_db[i][4]) + type_list = [ + sgc_db[i][5], + sgc_db[i][7], + sgc_db[i][9], + sgc_db[i][11], + sgc_db[i][13], + sgc_db[i][15], + ] + cmd_name, cmd_code = GetCmdNameAndCmdCode_(name, settings["is_cmd_prefixed_in_db"]) + + # パラメタ長の整合性チェック + for j in range(len(type_list)): + err_flag = 0 + if j < param_num and type_list[j] == "": + err_flag = 1 + if j >= param_num and type_list[j] != "": + err_flag = 1 + if err_flag: + print("Error: Cmd DB Err at " + name, file=sys.stderr) + sys.exit(1) + + # パラメタ長のカウント + conv_tpye_to_size = { + "int8_t": "CA_PARAM_SIZE_TYPE_1BYTE", + "int16_t": "CA_PARAM_SIZE_TYPE_2BYTE", + "int32_t": "CA_PARAM_SIZE_TYPE_4BYTE", + "uint8_t": "CA_PARAM_SIZE_TYPE_1BYTE", + "uint16_t": "CA_PARAM_SIZE_TYPE_2BYTE", + "uint32_t": "CA_PARAM_SIZE_TYPE_4BYTE", + "float": "CA_PARAM_SIZE_TYPE_4BYTE", + "double": "CA_PARAM_SIZE_TYPE_8BYTE", + "raw": "CA_PARAM_SIZE_TYPE_RAW", + } + for j in range(param_num): + index = j // 2 + subindex = "second" if j % 2 else "first" + body_c += ( + " cmd_table[" + + cmd_code + + "].param_size_infos[" + + str(index) + + "].packed_info.bit." + + subindex + + " = " + + conv_tpye_to_size[type_list[j]] + + ";\n" + ) + + OutputCmdDefC_(output_file_path + output_file_name_base + ".c", body_c, settings) + OutputCmdDefH_(output_file_path + output_file_name_base + ".h", body_h, settings) + + +def GenerateBctDef(settings, bct_db): + output_file_path = settings["path_to_src"] + r"src_user/tlm_cmd/" + output_file_name = "block_command_definitions.h" + + DATA_SART_ROW = 2 + + body_h = "" + for i in range(DATA_SART_ROW, len(bct_db)): + comment = bct_db[i][0] + name = bct_db[i][1] + bc_id = bct_db[i][3] + description = bct_db[i][10] + + # エスケープ解除 + name = name.replace("@@", ",") + description = description.replace("@@", ",") + + if comment == "" and name == "": # CommentもNameも空白なら打ち切り + break + + if comment == "**": # New Line Comment + body_h += "\n // " + name + "\n" + elif comment != "": # Comment + body_h += " // " + name + "\n" + else: + # " BC_SL_INITIAL_TO_INITIAL = 0," + if description == "": + body_h += " " + name + " = " + bc_id + ",\n" + else: + body_h += " " + name + " = " + bc_id + ", // " + description + "\n" + + OutputBctDef_(output_file_path + output_file_name, body_h, settings) + + +def GenerateOtherObcCmdDef(settings, other_obc_dbs): + # pprint.pprint(other_obc_dbs) + DATA_SART_ROW = 3 + for i in range(len(settings["other_obc_data"])): + if not settings["other_obc_data"][i]["is_enable"]: + continue + obc_name = settings["other_obc_data"][i]["name"] + name_upper = obc_name.upper() + name_lower = obc_name.lower() + # name_capit = obc_name.capitalize() + # print(name_upper) + # print(name_lower) + # print(name_capit) + sgc_db = other_obc_dbs[obc_name] + # pprint.pprint(sgc_db) + + body_h = "" + # " TOBC_Cmd_CODE_NOP = 0x0000," + for j in range(DATA_SART_ROW, len(sgc_db)): + comment = sgc_db[j][0] + name = sgc_db[j][1] + cmd_id = sgc_db[j][3] + if comment == "" and name == "": # CommentもNameも空白なら打ち切り + break + if comment != "": # Comment + continue + # print(name) + _, cmd_code = GetCmdNameAndCmdCode_( + name, settings["other_obc_data"][i]["is_cmd_prefixed_in_db"] + ) + cmd_code = name_upper + "_" + cmd_code + body_h += " " + cmd_code + " = " + cmd_id + ",\n" + # print(body_h) + output_file_path = ( + settings["path_to_src"] + + r"src_user/Drivers/" + + settings["other_obc_data"][i]["driver_path"] + + name_lower + + "_command_definitions.h" + ) + OutputOtherObcCmdDefH_(output_file_path, obc_name, body_h, settings) + + +def GetCmdNameAndCmdCode_(name, is_cmd_prefixed_in_db): + if is_cmd_prefixed_in_db: + cmd_name = name + else: + cmd_name = "Cmd_" + name + cmd_code = cmd_name.replace("Cmd_", "Cmd_CODE_") + return cmd_name, cmd_code + + +def OutputCmdDefC_(file_path, body, settings): + output = "" + output += """ +#pragma section REPRO +/** + * @file + * @brief コマンド定義 + * @note このコードは自動生成されています! + */ +#include +#include "command_definitions.h" +#include "command_source.h" + +void CA_load_cmd_table(CA_CmdInfo cmd_table[CA_MAX_CMDS]) +{ +"""[ + 1: + ] # 最初の改行を除く + + output += body + + output += """ +} + +#pragma section +"""[ + 1: + ] # 最初の改行を除く + + with open(file_path, mode="w", encoding=settings["output_file_encoding"]) as fh: + fh.write(output) + + +def OutputCmdDefH_(file_path, body, settings): + output = "" + output += """ +/** + * @file + * @brief コマンド定義 + * @note このコードは自動生成されています! + */ +#ifndef COMMAND_DEFINITIONS_H_ +#define COMMAND_DEFINITIONS_H_ + +typedef enum +{ +"""[ + 1: + ] # 最初の改行を除く + + output += body + + output += """ + + Cmd_CODE_MAX +} CMD_CODE; + +#endif +"""[ + 1: + ] # 最初の改行を除く + + with open(file_path, mode="w", encoding=settings["output_file_encoding"]) as fh: + fh.write(output) + + +def OutputBctDef_(file_path, body, settings): + output = "" + output += """ +/** + * @file + * @brief ブロックコマンド定義 + * @note このコードは自動生成されています! + */ +#ifndef BLOCK_COMMAND_DEFINITIONS_H_ +#define BLOCK_COMMAND_DEFINITIONS_H_ + +// 登録されるBlockCommandTableのblock番号を規定 +typedef enum +{ +"""[ + 1: + ] # 最初の改行を除く + + output += body + + output += """ + + BC_ID_MAX // BCT 自体のサイズは BCT_MAX_BLOCKS で規定 +} BC_DEFAULT_ID; + +void BC_load_defaults(void); + +#endif +"""[ + 1: + ] # 最初の改行を除く + + with open(file_path, mode="w", encoding=settings["output_file_encoding"]) as fh: + fh.write(output) + + +def OutputOtherObcCmdDefH_(file_path, name, body, settings): + name_upper = name.upper() + name_lower = name.lower() + name_capit = name.capitalize() + + output = "" + output += """ +/** + * @file + * @brief コマンド定義 + * @note このコードは自動生成されています! + */ +#ifndef {_obc_name_upper}_COMMAND_DEFINITIONS_H_ +#define {_obc_name_upper}_COMMAND_DEFINITIONS_H_ + +typedef enum +{{ +"""[ + 1: + ] # 最初の改行を除く + + output += body + + output += """ + + {_obc_name_upper}_Cmd_CODE_MAX +}} {_obc_name_upper}_CMD_CODE; + +#endif +"""[ + 1: + ] # 最初の改行を除く + + with open(file_path, mode="w", encoding=settings["output_file_encoding"]) as fh: + fh.write( + output.format( + _obc_name_upper=name_upper, _obc_name_lower=name_lower, _obc_name_capit=name_capit + ) + ) diff --git a/tlm-cmd-code-generator/my_mod/load_db.py b/tlm-cmd-code-generator/my_mod/load_db.py new file mode 100644 index 000000000..b5fb3f8de --- /dev/null +++ b/tlm-cmd-code-generator/my_mod/load_db.py @@ -0,0 +1,148 @@ +# coding: UTF-8 +""" +DB読み込み +""" + +import os +import sys +import csv +import re # 正規表現 + +# import pprint + + +def LoadCmdDb(settings): + cmd_db_path = settings["path_to_db"] + r"CMD_DB/" + + sgc_db, bct_db = LoadCmdCSV_( + cmd_db_path, settings["db_prefix"], settings["input_file_encoding"] + ) + + other_obc_dbs = {} + if settings["is_main_obc"]: + other_obc_dbs = LoadOtherObcCmd_(settings) + + # TODO: 重複チェックをする + + # print(sgc_db) + # print(bct_db) + return {"sgc": sgc_db, "bct": bct_db, "other_obc": other_obc_dbs} + + +def LoadCmdCSV_(cmd_db_path, db_prefix, encoding): + sgc_db_path = cmd_db_path + db_prefix + "_CMD_DB_CMD_DB.csv" # single cmd + bct_db_path = cmd_db_path + db_prefix + "_CMD_DB_BCT.csv" # block cmd table + + with open(sgc_db_path, mode="r", encoding=encoding) as fh: + reader = csv.reader(fh) + sgc_db = [row for row in reader] + with open(bct_db_path, mode="r", encoding=encoding) as fh: + reader = csv.reader(fh) + bct_db = [row for row in reader] + + return sgc_db, bct_db + + +def LoadTlmDb(settings): + tlm_db_path = settings["path_to_db"] + r"TLM_DB/calced_data/" + + tlm_db = LoadTlmCSV_( + tlm_db_path, + settings["db_prefix"], + settings["tlm_id_range"], + settings["input_file_encoding"], + ) + + other_obc_dbs = {} + if settings["is_main_obc"]: + other_obc_dbs = LoadOtherObcTlm(settings) + + # TODO: 重複チェックをする + + return {"tlm": tlm_db, "other_obc": other_obc_dbs} + + +def LoadTlmCSV_(tlm_db_path, db_prefix, tlm_id_range, encoding): + tlm_names = [file for file in os.listdir(tlm_db_path) if file.endswith(".csv")] + regex = r"^" + db_prefix + "_TLM_DB_" + tlm_names = [re.sub(regex, "", file) for file in tlm_names] + tlm_names = [re.sub(".csv$", "", file) for file in tlm_names] + # pprint.pprint(tlm_names) + # print(len(tlm_names)) + + tlm_db = [] + + for tlm_name in tlm_names: + tlm_sheet_path = tlm_db_path + db_prefix + "_TLM_DB_" + tlm_name + ".csv" + with open(tlm_sheet_path, mode="r", encoding=encoding) as fh: + reader = csv.reader(fh) + sheet = [row for row in reader] + # pprint.pprint(sheet) + # print(sheet) + enable_flag = sheet[2][2] # FIXME: Enable/Disable を取得.マジックナンバーで指定してしまってる. + if enable_flag != "ENABLE": + continue + tlm_id = sheet[1][2] # FIXME: テレメIDを取得.マジックナンバーで指定してしまってる. + if not int(tlm_id_range[0], 0) <= int(tlm_id, 0) < int(tlm_id_range[1], 0): + print( + "Error: TLM ID is invalid at " + db_prefix + "_TLM_DB_" + tlm_name + ".csv", + file=sys.stderr, + ) + sys.exit(1) + raw_local_vars = ( + sheet[1][3].replace("%%", "").split("##") + ) # FIXME: ローカル変数を取得.マジックナンバーで指定してしまってる. + local_vars = [] + for raw_local_var in raw_local_vars: + local_var = raw_local_var.strip().replace("@@", ",") + if len(local_var) > 0: + local_vars.append(local_var) + tlm_db.append( + {"tlm_id": tlm_id, "tlm_name": tlm_name, "local_vars": local_vars, "data": sheet} + ) + # tlm_db.append({'tlm_id': tlm_id, 'tlm_name': tlm_name, 'data': 1}) + + tlm_db.sort(key=lambda x: x["tlm_id"]) + + return tlm_db + + +def LoadOtherObcCmd_(settings): + other_obc_dbs = {} + + for i in range(len(settings["other_obc_data"])): + if not settings["other_obc_data"][i]["is_enable"]: + continue + cmd_db_path = settings["other_obc_data"][i]["path_to_db"] + r"CMD_DB/" + sgc_db, bct_db = LoadCmdCSV_( + cmd_db_path, + settings["other_obc_data"][i]["db_prefix"], + settings["other_obc_data"][i]["input_file_encoding"], + ) + # other_obc_dbs.append(sgc_db) + other_obc_dbs[settings["other_obc_data"][i]["name"]] = sgc_db + # print(i) + + # pprint.pprint(settings["other_obc_data"]) + # pprint.pprint(other_obc_dbs) + return other_obc_dbs + + +def LoadOtherObcTlm(settings): + other_obc_dbs = {} + + for i in range(len(settings["other_obc_data"])): + if not settings["other_obc_data"][i]["is_enable"]: + continue + tlm_db_path = settings["other_obc_data"][i]["path_to_db"] + r"TLM_DB/calced_data/" + + tlm_db = LoadTlmCSV_( + tlm_db_path, + settings["other_obc_data"][i]["db_prefix"], + settings["other_obc_data"][i]["tlm_id_range"], + settings["other_obc_data"][i]["input_file_encoding"], + ) + other_obc_dbs[settings["other_obc_data"][i]["name"]] = tlm_db + + # pprint.pprint(other_obc_dbs) + return other_obc_dbs diff --git a/tlm-cmd-code-generator/my_mod/tlm_buffer.py b/tlm-cmd-code-generator/my_mod/tlm_buffer.py new file mode 100644 index 000000000..c151770bf --- /dev/null +++ b/tlm-cmd-code-generator/my_mod/tlm_buffer.py @@ -0,0 +1,527 @@ +# coding: UTF-8 +""" +tlm buffer +""" + +import sys + +# from collections import OrderedDict +# import pprint + + +def GenerateTlmBuffer(settings, other_obc_dbs): + DATA_START_ROW = 8 + + for i in range(len(settings["other_obc_data"])): + if not settings["other_obc_data"][i]["is_enable"]: + continue + obc_name = settings["other_obc_data"][i]["name"] + driver_type = settings["other_obc_data"][i]["driver_type"] + driver_name = settings["other_obc_data"][i]["driver_name"] + max_tlm_num = settings["other_obc_data"][i]["max_tlm_num"] + + tlm_db = other_obc_dbs[obc_name] + + body_c = "" + body_h = "" + tlmdef_body_h = "" + + for tlm in tlm_db: + tlm_name = tlm["tlm_name"] + tlm_name_lower = tlm_name.lower() + body_c += ( + "static DS_ERR_CODE {_obc_name_upper}_analyze_tlm_" + + tlm_name_lower + + "_(const CommonTlmPacket* packet, {_obc_name_upper}_TLM_CODE tlm_id, " + + driver_type + + "* " + + driver_name + + ");\n" + ) + + body_c += "\n" + body_c += "static CommonTlmPacket {_obc_name_upper}_ctp_;\n" + body_c += "\n" + + body_h += "typedef struct " + driver_type + " " + driver_type + ";\n" + body_h += "\n" + body_h += "#define {_obc_name_upper}_MAX_TLM_NUM (" + str(max_tlm_num) + ")\n" + body_h += "\n" + body_h += "typedef struct\n" + body_h += "{{\n" + body_h += " CommonTlmPacket packet; //!< 最新のテレメパケットを保持\n" + body_h += " uint8_t is_null_packet; //!< 一度でもテレメを受信しているか?(空配列が読み出されるのを防ぐため)\n" + body_h += "}} {_obc_name_upper}_TlmBufferElem;\n" + body_h += "\n" + body_h += "typedef struct\n" + body_h += "{{\n" + body_h += " {_obc_name_upper}_TlmBufferElem tlm[{_obc_name_upper}_MAX_TLM_NUM]; //!< TLM ID ごとに保持\n" + body_h += "}} {_obc_name_upper}_TlmBuffer;\n" + body_h += "\n" + + tlmdef_body_h += "typedef struct\n" + tlmdef_body_h += "{{\n" + for tlm in tlm_db: + tlm_name = tlm["tlm_name"] + tlm_name_lower = tlm_name.lower() + + # pprint.pprint(tlm['data'][DATA_START_ROW:]) + last_var_type = "" + tlm_struct_tree = {} # python3.7以上を想定しているので,キーの順番は保存されていることが前提 + # tlm_struct_tree = collections.OrderedDict() # やっぱこっちで + for j in range(DATA_START_ROW, len(tlm["data"])): + comment = tlm["data"][j][0] + name = EscapeTlmElemName_(tlm["data"][j][1]) + var_type = tlm["data"][j][2] + if comment == "" and name == "": # CommentもNameも空白なら打ち切り + break + if comment != "": + continue + if name == "": + continue + if var_type == "": + var_type = last_var_type + last_var_type = var_type + if last_var_type == "": + continue + + # name_tree = name.lower().split(".")[2:] # OBC名.テレメ名.HOGE.FUGA を想定 + name_tree = name.lower().split(".") + name_path = "/".join(name_tree) + if SetStructTree_(tlm_struct_tree, name_path, var_type): + print("Error: Tlm DB Struct Parse Err at " + name, file=sys.stderr) + sys.exit(1) + + # pprint.pprint(tlm_struct_tree) + # for k, v in tlm_struct_tree.items(): + # print(k) + # print(v) + # print("") + + tlmdef_body_h += GenerateStructDef_(tlm_struct_tree, tlm_name_lower) + + tlmdef_body_h += "}} {_obc_name_upper}_TlmData;\n" + + body_h += ( + "void {_obc_name_upper}_init_tlm_buffer(" + driver_type + "* " + driver_name + ");\n" + ) + body_h += "\n" + body_h += ( + "DS_ERR_CODE {_obc_name_upper}_buffer_tlm_packet(DS_StreamConfig* p_stream_config, " + + driver_type + + "* " + + driver_name + + ");\n" + ) + body_h += "\n" + body_h += ( + "TF_TLM_FUNC_ACK {_obc_name_upper}_pick_up_tlm_buffer(const " + + driver_type + + "* " + + driver_name + + ", {_obc_name_upper}_TLM_CODE tlm_id, uint8_t* packet, uint16_t* len, uint16_t max_len);\n" + ) + + body_c += ( + "void {_obc_name_upper}_init_tlm_buffer(" + driver_type + "* " + driver_name + ")\n" + ) + body_c += "{{\n" + body_c += " // packet などは,上位の driver の初期化で driver もろとも memset 0x00 されていると期待して,ここではしない\n" + body_c += " int i = 0;\n" + body_c += " for (i = 0; i < {_obc_name_upper}_MAX_TLM_NUM; ++i)\n" + body_c += " {{\n" + body_c += " " + driver_name + "->tlm_buffer.tlm[i].is_null_packet = 1;\n" + body_c += " }}\n" + body_c += "}}\n" + body_c += "\n" + body_c += ( + "DS_ERR_CODE {_obc_name_upper}_buffer_tlm_packet(DS_StreamConfig* p_stream_config, " + + driver_type + + "* " + + driver_name + + ")\n" + ) + body_c += "{{\n" + + body_c += " {_obc_name_upper}_TLM_CODE tlm_id;\n" + body_c += " DS_ERR_CODE ret;\n" + body_c += "\n" + body_c += " ret = CTP_get_ctp_from_dssc(p_stream_config, &{_obc_name_upper}_ctp_);\n" + body_c += " if (ret != DS_ERR_CODE_OK) return ret;\n" + body_c += "\n" + body_c += " tlm_id = ({_obc_name_upper}_TLM_CODE)CTP_get_id(&{_obc_name_upper}_ctp_);\n" + body_c += "\n" + + body_c += " switch (tlm_id)\n" + body_c += " {{\n" + for tlm in tlm_db: + tlm_name = tlm["tlm_name"] + tlm_name_upper = tlm_name.upper() + tlm_name_lower = tlm_name.lower() + body_c += " case {_obc_name_upper}_Tlm_CODE_" + tlm_name_upper + ":\n" + body_c += ( + " return {_obc_name_upper}_analyze_tlm_" + + tlm_name_lower + + "_(&{_obc_name_upper}_ctp_, tlm_id, " + + driver_name + + ");\n" + ) + body_c += " default:\n" + body_c += " " + settings["other_obc_data"][i]["code_when_tlm_not_found"] + "\n" + body_c += " return DS_ERR_CODE_ERR;\n" + body_c += " }}\n" + body_c += "}}\n" + body_c += "\n" + for tlm in tlm_db: + conv_tpye_to_temp = { + "int8_t": "temp_i8", + "int16_t": "temp_i16", + "int32_t": "temp_i32", + "uint8_t": "temp_u8", + "uint16_t": "temp_u16", + "uint32_t": "temp_u32", + "float": "temp_f", + "double": "temp_d", + } + conv_tpye_to_size = { + "int8_t": 1, + "int16_t": 2, + "int32_t": 4, + "uint8_t": 1, + "uint16_t": 2, + "uint32_t": 4, + "float": 4, + "double": 8, + } + tlm_name = tlm["tlm_name"] + tlm_name_upper = tlm_name.upper() + tlm_name_lower = tlm_name.lower() + + body_c += ( + "static DS_ERR_CODE {_obc_name_upper}_analyze_tlm_" + + tlm_name_lower + + "_(const CommonTlmPacket* packet, {_obc_name_upper}_TLM_CODE tlm_id, " + + driver_type + + "* " + + driver_name + + ")\n" + ) + body_c += "{{\n" + body_c += " const uint8_t* f = packet->packet;\n" + for k, v in conv_tpye_to_temp.items(): + if k == "float": + body_c += " " + k + " " + v + " = 0.0f;\n" + elif k == "double": + body_c += " " + k + " " + v + " = 0.0;\n" + else: + body_c += " " + k + " " + v + " = 0;\n" + body_c += "\n" + body_c += " // GS へのテレメ中継のためのバッファーへのコピー\n" + body_c += ( + " CTP_copy_packet(&(" + + driver_name + + "->tlm_buffer.tlm[tlm_id].packet), packet);\n" + ) + body_c += " " + driver_name + "->tlm_buffer.tlm[tlm_id].is_null_packet = 0;\n" + body_c += " // TODO: CRC チェック\n" + body_c += "\n" + + body_c += " // MOBC 内部でテレメデータへアクセスしやすいようにするための構造体へのパース\n" + last_var_type = "" + for j in range(DATA_START_ROW, len(tlm["data"])): + comment = tlm["data"][j][0] + name = EscapeTlmElemName_(tlm["data"][j][1]) + var_type = tlm["data"][j][2] + if comment == "" and name == "": # CommentもNameも空白なら打ち切り + break + if comment != "": + continue + if name == "": + continue + if var_type == "": + var_type = last_var_type + last_var_type = var_type + if last_var_type == "": + continue + + oct_pos = int(tlm["data"][j][5]) + bit_pos = int(tlm["data"][j][6]) + bit_len = int(tlm["data"][j][7]) + is_compression = 0 # テレメ圧縮フラグ for ビットフィールドをつかってる奴ら + if tlm["data"][j][2] == "" or tlm["data"][j + 1][2] == "": + is_compression = 1 + if ( + tlm["data"][j + 1][0] == "" + and tlm["data"][j + 1][1] == "" + and tlm["data"][j][2] != "" + ): # 最終行の除外 + is_compression = 0 + + # name_tree = name.lower().split(".")[2:] # OBC名.テレメ名.HOGE.FUGA を想定 + name_tree = name.lower().split(".") + name_path = ".".join(name_tree) + var_name = driver_name + "->tlm_data." + tlm_name_lower + "." + name_path + if is_compression: + body_c += ( + " ENDIAN_memcpy(&" + + conv_tpye_to_temp[var_type] + + ", &(f[" + + str(oct_pos) + + "]), " + + str(conv_tpye_to_size[var_type]) + + ");\n" + ) + body_c += ( + " " + + conv_tpye_to_temp[var_type] + + " >>= " + + str(conv_tpye_to_size[var_type] * 8 - bit_pos - bit_len) + + ";\n" + ) + body_c += ( + " " + + conv_tpye_to_temp[var_type] + + " &= " + + hex(int("0b" + "1" * bit_len, 2)) + + ";\n" + ) + body_c += " " + var_name + " = " + conv_tpye_to_temp[var_type] + ";\n" + else: + body_c += ( + " ENDIAN_memcpy(&(" + + var_name + + "), &(f[" + + str(oct_pos) + + "]), " + + str(conv_tpye_to_size[var_type]) + + ");\n" + ) + + body_c += " // TODO: ビットフィールドをつかっている系は,様々なパターンがあり得るので,今後,バグが出ないか注視する\n" + body_c += "\n" + body_c += " // ワーニング回避\n" + for k, v in conv_tpye_to_temp.items(): + body_c += " (void)" + v + ";\n" + body_c += "\n" + body_c += " return DS_ERR_CODE_OK;\n" + body_c += "}}\n" + body_c += "\n" + + body_c += ( + "TF_TLM_FUNC_ACK {_obc_name_upper}_pick_up_tlm_buffer(const " + + driver_type + + "* " + + driver_name + + ", {_obc_name_upper}_TLM_CODE tlm_id, uint8_t* packet, uint16_t* len, uint16_t max_len)\n" + ) + body_c += "{{\n" + body_c += " const CommonTlmPacket* buffered_packet;\n" + body_c += "\n" + body_c += ( + " if (tlm_id >= {_obc_name_upper}_MAX_TLM_NUM) return TF_TLM_FUNC_ACK_NOT_DEFINED;\n" + ) + body_c += ( + " if (" + + driver_name + + "->tlm_buffer.tlm[tlm_id].is_null_packet) return TF_TLM_FUNC_ACK_NULL_PACKET;\n" + ) + body_c += "\n" + body_c += " buffered_packet = &(" + driver_name + "->tlm_buffer.tlm[tlm_id].packet);\n" + body_c += " *len = CTP_get_packet_len(buffered_packet);\n" + body_c += "\n" + body_c += " if (*len > max_len) return TF_TLM_FUNC_ACK_TOO_SHORT_LEN;\n" + body_c += "\n" + body_c += " memcpy(packet, &buffered_packet->packet, (size_t)(*len));\n" + body_c += " return TF_TLM_FUNC_ACK_SUCCESS;\n" + body_c += "}}\n" + body_c += "\n" + + output_file_path = ( + settings["path_to_src"] + + r"src_user/Drivers/" + + settings["other_obc_data"][i]["driver_path"] + ) + OutputTlmBufferC_( + output_file_path + obc_name.lower() + "_telemetry_buffer.c", obc_name, body_c, settings + ) + OutputTlmBufferH_( + output_file_path + obc_name.lower() + "_telemetry_buffer.h", obc_name, body_h, settings + ) + OutputTlmDataDefH_( + output_file_path + obc_name.lower() + "_telemetry_data_definitions.h", + obc_name, + tlmdef_body_h, + settings, + ) + + +def OutputTlmBufferC_(file_path, name, body, settings): + name_upper = name.upper() + name_lower = name.lower() + name_capit = name.capitalize() + + output = "" + output += """ +#pragma section REPRO +/** + * @file + * @brief テレメトリバッファー(テレメ中継) + * @note このコードは自動生成されています! + */ +#include +#include "./{_obc_name_lower}_telemetry_definitions.h" +#include "./{_obc_name_lower}_telemetry_buffer.h" +#include "./{_obc_name_lower}.h" +#include + +"""[ + 1: + ] # 最初の改行を除く + + output += body + + output += """ +#pragma section +"""[ + 1: + ] # 最初の改行を除く + + with open(file_path, mode="w", encoding=settings["output_file_encoding"]) as fh: + fh.write( + output.format( + _obc_name_upper=name_upper, _obc_name_lower=name_lower, _obc_name_capit=name_capit + ) + ) + + +def OutputTlmBufferH_(file_path, name, body, settings): + name_upper = name.upper() + name_lower = name.lower() + name_capit = name.capitalize() + + output = "" + output += """ +/** + * @file + * @brief テレメトリバッファー(テレメ中継) + * @note このコードは自動生成されています! + */ +#ifndef {_obc_name_upper}_TELEMETRY_BUFFER_H_ +#define {_obc_name_upper}_TELEMETRY_BUFFER_H_ + +#include "./{_obc_name_lower}_telemetry_definitions.h" +#include +#include +#include + +"""[ + 1: + ] # 最初の改行を除く + + output += body + + output += """ + +#endif +"""[ + 1: + ] # 最初の改行を除く + + with open(file_path, mode="w", encoding=settings["output_file_encoding"]) as fh: + fh.write( + output.format( + _obc_name_upper=name_upper, _obc_name_lower=name_lower, _obc_name_capit=name_capit + ) + ) + + +def OutputTlmDataDefH_(file_path, name, body, settings): + name_upper = name.upper() + name_lower = name.lower() + name_capit = name.capitalize() + + output = "" + output += """ +/** + * @file + * @brief バッファリングされているテレメをパースしてMOBC内でかんたんに利用できるようにするためのテレメデータ構造体定義 + * @note このコードは自動生成されています! + */ +#ifndef {_obc_name_upper}_TELEMETRY_DATA_DEFINITIONS_H_ +#define {_obc_name_upper}_TELEMETRY_DATA_DEFINITIONS_H_ + +"""[ + 1: + ] # 最初の改行を除く + + output += body + + output += """ + +#endif +"""[ + 1: + ] # 最初の改行を除く + + with open(file_path, mode="w", encoding=settings["output_file_encoding"]) as fh: + fh.write( + output.format( + _obc_name_upper=name_upper, _obc_name_lower=name_lower, _obc_name_capit=name_capit + ) + ) + + +def GetStructTree_(dict, path, sep="/", default=None): + path_list = path.split(sep) + + def _(dict, path_list, sep, default): + if len(path_list) == 0: + return default + if len(path_list) == 1: + return dict.get(path_list[0], default) + else: + return _(dict.get(path_list[0], {}), path_list[1:], sep, default) + + return _(dict, path_list, sep=sep, default=None) + + +def SetStructTree_(dict, path, val, sep="/"): + path_list = path.split(sep) + + def _(dict, path_list, val, sep): + if len(path_list) == 0: + return 1 # err + if len(path_list) == 1: + key = path_list[0] + if key in dict: + return 1 # 上書きエラー + else: + dict[key] = val + return 0 + else: + key = path_list[0] + if key not in dict: + dict[key] = {} + return _(dict[key], path_list[1:], val, sep) + + return _(dict, path_list, val, sep=sep) + + +def GenerateStructDef_(tree, name): + def _(tree, name, indent): + output = "" + output += " " * (indent) + "struct\n" + output += " " * (indent) + "{{\n" + for k, v in tree.items(): + if type(v) == dict: + output += _(v, k, indent + 2) + continue + output += " " * (indent + 2) + v + " " + k + ";\n" + output += " " * (indent) + "}} " + name + ";\n" + return output + + return _(tree, name, 2) + + +def EscapeTlmElemName_(name): + return name.replace("/", "_") diff --git a/tlm-cmd-code-generator/my_mod/tlm_def.py b/tlm-cmd-code-generator/my_mod/tlm_def.py new file mode 100644 index 000000000..4fa64719d --- /dev/null +++ b/tlm-cmd-code-generator/my_mod/tlm_def.py @@ -0,0 +1,250 @@ +# coding: UTF-8 +""" +tlm def +""" + +import sys + + +def GenerateTlmDef(settings, tlm_db): + output_file_path = settings["path_to_src"] + r"src_user/tlm_cmd/" + output_file_name_base = "telemetry_definitions" + + DATA_START_ROW = 8 + + body_c = "" + body_h = "" + + # "static TF_TLM_FUNC_ACK OBC_(uint8_t* packet, uint16_t* len, uint16_t max_len);" + # " OBC_ID = 0x00," + for tlm in tlm_db: + body_c += ( + "static TF_TLM_FUNC_ACK Tlm_" + + tlm["tlm_name"].upper() + + "_(uint8_t* packet, uint16_t* len, uint16_t max_len);\n" + ) + body_h += " Tlm_CODE_" + tlm["tlm_name"].upper() + " = " + tlm["tlm_id"] + ",\n" + + body_c += "\n" + body_c += "void TF_load_tlm_table(TF_TlmInfo tlm_table[TF_MAX_TLMS])\n" + body_c += "{\n" + for tlm in tlm_db: + # " tlm_table[OBC_ID].tlm_func = OBC_;" + body_c += ( + " tlm_table[Tlm_CODE_" + + tlm["tlm_name"].upper() + + "].tlm_func = Tlm_" + + tlm["tlm_name"].upper() + + "_;\n" + ) + body_c += "}\n" + + for tlm in tlm_db: + func_code = "" + max_pos = "" + for i in range(DATA_START_ROW, len(tlm["data"])): + comment = tlm["data"][i][0] + name = tlm["data"][i][1] + var_type = tlm["data"][i][2] + code = tlm["data"][i][3] + pos = tlm["data"][i][5] + if comment == "" and name == "": # CommentもNameも空白なら打ち切り + break + if comment != "": + continue + if name == "": + continue + if var_type == "": + continue + if code == "": + continue + if pos == "": + continue + + pos = int(pos) + code = code.replace("@@", ",") + func_code += " " + if var_type == "int8_t": + func_code += "TF_copy_i8" + max_pos = pos + 1 + elif var_type == "int16_t": + func_code += "TF_copy_i16" + max_pos = pos + 2 + elif var_type == "int32_t": + func_code += "TF_copy_i32" + max_pos = pos + 4 + elif var_type == "uint8_t": + func_code += "TF_copy_u8" + max_pos = pos + 1 + elif var_type == "uint16_t": + func_code += "TF_copy_u16" + max_pos = pos + 2 + elif var_type == "uint32_t": + func_code += "TF_copy_u32" + max_pos = pos + 4 + elif var_type == "float": + func_code += "TF_copy_float" + max_pos = pos + 4 + elif var_type == "double": + func_code += "TF_copy_double" + max_pos = pos + 8 + else: + print("Error: Tlm DB Err at " + tlm["tlm_name"].upper(), file=sys.stderr) + sys.exit(1) + func_code += "(&packet[" + str(pos) + "], " + code + ");\n" + + body_c += "\n" + body_c += ( + "static TF_TLM_FUNC_ACK Tlm_" + + tlm["tlm_name"].upper() + + "_(uint8_t* packet, uint16_t* len, uint16_t max_len)\n" + ) + body_c += "{\n" + for local_var in tlm["local_vars"]: + body_c += " " + local_var + "\n" + if len(tlm["local_vars"]) > 0: + body_c += "\n" + body_c += " if (" + str(max_pos) + " > max_len) return TF_TLM_FUNC_ACK_TOO_SHORT_LEN;\n" + body_c += "\n" + body_c += "#ifndef BUILD_SETTINGS_FAST_BUILD\n" + body_c += func_code + body_c += "#endif\n" + body_c += "\n" + body_c += " *len = " + str(max_pos) + ";\n" + body_c += " return TF_TLM_FUNC_ACK_SUCCESS;\n" + body_c += "}\n" + + OutputTlmDefC_(output_file_path + output_file_name_base + ".c", body_c, settings) + OutputTlmDefH_(output_file_path + output_file_name_base + ".h", body_h, settings) + + +def GenerateOtherObcTlmDef(settings, other_obc_dbs): + for i in range(len(settings["other_obc_data"])): + if not settings["other_obc_data"][i]["is_enable"]: + continue + obc_name = settings["other_obc_data"][i]["name"] + + tlm_db = other_obc_dbs[obc_name] + + body_h = "" + # " TOBC_Tlm_CODE_HK = 0xf0," + for tlm in tlm_db: + body_h += ( + " {_obc_name_upper}_Tlm_CODE_" + + tlm["tlm_name"].upper() + + " = " + + tlm["tlm_id"] + + ",\n" + ) + output_file_path = ( + settings["path_to_src"] + + r"src_user/Drivers/" + + settings["other_obc_data"][i]["driver_path"] + + obc_name.lower() + + "_telemetry_definitions.h" + ) + OutputOtherObcTlmDefH(output_file_path, obc_name, body_h, settings) + + +def OutputTlmDefC_(file_path, body, settings): + output = "" + output += """ +#pragma section REPRO +/** + * @file + * @brief テレメトリ定義 + * @note このコードは自動生成されています! + */ +#include +#include "telemetry_definitions.h" +#include "telemetry_source.h" + +"""[ + 1: + ] # 最初の改行を除く + + output += body + + output += """ + +#pragma section +"""[ + 1: + ] # 最初の改行を除く + + with open(file_path, mode="w", encoding=settings["output_file_encoding"]) as fh: + fh.write(output) + + +def OutputTlmDefH_(file_path, body, settings): + output = "" + output += """ +/** + * @file + * @brief テレメトリ定義 + * @note このコードは自動生成されています! + */ +#ifndef TELEMETRY_DEFINITIONS_H_ +#define TELEMETRY_DEFINITIONS_H_ + +typedef enum +{ +"""[ + 1: + ] # 最初の改行を除く + + output += body + + output += """ + + TLM_CODE_MAX +} TLM_CODE; + +#endif +"""[ + 1: + ] # 最初の改行を除く + + with open(file_path, mode="w", encoding=settings["output_file_encoding"]) as fh: + fh.write(output) + + +def OutputOtherObcTlmDefH(file_path, name, body, settings): + name_upper = name.upper() + name_lower = name.lower() + name_capit = name.capitalize() + + output = "" + output += """ +/** + * @file + * @brief テレメトリ定義 + * @note このコードは自動生成されています! + */ +#ifndef {_obc_name_upper}_TELEMETRY_DEFINITIONS_H_ +#define {_obc_name_upper}_TELEMETRY_DEFINITIONS_H_ + +typedef enum +{{ +"""[ + 1: + ] # 最初の改行を除く + + output += body + + output += """ + + {_obc_name_upper}_TLM_CODE_MAX +}} {_obc_name_upper}_TLM_CODE; + +#endif +"""[ + 1: + ] # 最初の改行を除く + + with open(file_path, mode="w", encoding=settings["output_file_encoding"]) as fh: + fh.write( + output.format( + _obc_name_upper=name_upper, _obc_name_lower=name_lower, _obc_name_capit=name_capit + ) + ) diff --git a/tlm-cmd-code-generator/pyproject.toml b/tlm-cmd-code-generator/pyproject.toml new file mode 100644 index 000000000..56ce77371 --- /dev/null +++ b/tlm-cmd-code-generator/pyproject.toml @@ -0,0 +1,8 @@ +[tool.black] +target-version = ['py38'] +line-length = 100 +include = '\.pyi?$' + +# TODO: .flake8 を消してこちらに移植する +# [tool.flake8] +# max-line-length = 100 diff --git a/tlm-cmd-code-generator/renovate.json b/tlm-cmd-code-generator/renovate.json new file mode 100644 index 000000000..9b053cf94 --- /dev/null +++ b/tlm-cmd-code-generator/renovate.json @@ -0,0 +1,8 @@ +{ + "extends": [ + "config:base" + ], + "labels": ["priority::medium", "tools"], + "additionalReviewers": ["meltingrabbit", "sksat"], + "assignees": ["meltingrabbit", "sksat"] +} diff --git a/tlm-cmd-code-generator/requirements.txt b/tlm-cmd-code-generator/requirements.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tlm-cmd-code-generator/settings.json b/tlm-cmd-code-generator/settings.json new file mode 100644 index 000000000..6ef5e13bf --- /dev/null +++ b/tlm-cmd-code-generator/settings.json @@ -0,0 +1,40 @@ +{ + "path_to_src" : "../../c2a/src/", + "path_to_db" : "../../c2a/database/", + "db_prefix" : "SAMPLE_MOBC", + "tlm_id_range" : ["0x00", "0x100"], + "is_cmd_prefixed_in_db" : 0, + "input_file_encoding" : "utf-8", + "output_file_encoding" : "utf-8", + "is_main_obc" : 1, + "other_obc_data" : [ + { + "name" : "AOBC", + "is_enable" : 1, + "db_prefix" : "SAMPLE_AOBC", + "tlm_id_range" : ["0x90", "0xc0"], + "is_cmd_prefixed_in_db" : 0, + "input_file_encoding" : "utf-8", + "path_to_db" : "C:/c2a_sample_aobc/database/", + "max_tlm_num" : 256, + "driver_path" : "Aocs/", + "driver_type" : "AOBC_Driver", + "driver_name" : "aobc_driver", + "code_when_tlm_not_found" : "aobc_driver->info.comm.rx_err_code = AOBC_RX_ERR_CODE_TLM_NOT_FOUND;" + }, + { + "name" : "TOBC", + "is_enable" : 1, + "db_prefix" : "SAMPLE_TOBC", + "tlm_id_range" : ["0xc0", "0xf0"], + "is_cmd_prefixed_in_db" : 0, + "input_file_encoding" : "utf-8", + "path_to_db" : "C:/c2a_sample_tobc/database/", + "max_tlm_num" : 256, + "driver_path" : "Thermal/", + "driver_type" : "TOBC_Driver", + "driver_name" : "tobc_driver", + "code_when_tlm_not_found" : "tobc_driver->info.comm.rx_err_code = TOBC_RX_ERR_CODE_TLM_NOT_FOUND;" + } + ] +}