Skip to content

Latest commit

 

History

History
113 lines (82 loc) · 5.8 KB

communication_with_components.md

File metadata and controls

113 lines (82 loc) · 5.8 KB

Communication with Components

概要

コンポーネント間通信などをまとめる.
なお,地上局との通信関連や, CCSDS などについて,衛星内コンポーネントのネットワーク関連などについては Core Layer/Communication を参照のこと.

通信レイヤ

コンポーネント間通信などのための通信レイヤについてまとめる.

ネットワーク層

コンポーネントや地上局,その他のノードでのデータ配送において,エンド・ツー・エンドの配送に責任を持つ. CCSDS における APID によって制御されるデータ配送はネットワーク層である.

この層を流れるデータ単位を Packet と呼ぶ.

C2A では,地上局との通信や C2A 間通信において, Core Layer/Communication の Common Packet が標準的に使用される.
C2A を搭載した OBC と Common Packet に対応していないその他のコンポーネントでは,後述する EB90 Packet を可能な限り用いる.

データリンク層

隣接するコンポーネントや地上局,その他のノード間でのデータ転送を行う. 例えば,衛星内のコンポーネント A と B 間での UART での通信に対して責任を持つ. したがって,この場合は, UART 通信で発生しうるノイズへの耐性を提供することが期待される.

この層を流れるデータ単位を Frame と呼ぶ.

C2A では,CCSDS に準拠した地上局との通信では,それに準拠し Transfer Frame が使用される.
それ以外では,後述する EB90 Frame を可能な限り用いる.

ネットワーク層 (Packet)

Common Packet

Core Layer/Communication を参照のこと.

EB90 Packet

Common Packet ほどリッチな情報をやり取りしない通信に用いる. したがって, User Data Field 以外の Header には,

  • Version ID
  • Tlm / Cmd Count
  • Tlm / Cmd ID

のみ,定義されている.

直接通信する2者を超え,ネットワークを構築するだけの能力はない.
また,通常データリンク層としては EB90 Frame が用いられる.

現在は Ver.1 のみ策定されており,その定義は以下を参照すること.

/**
* @file
* @brief コンポ間通信などで標準的に使う ネットワーク層 の EB90 Packet
* @note 一般的には,データリンク層は EB90 Frame を使うことを想定
* @note Tlm か Cmd かはコンテキストで読み替える
* @note データリンク層は DS_StreamConfig.data_link_layer_ で規定する
* @note packet 構造
* |---------+-------+-------+------------------|
* | Pos | Pos | size | name |
* | [octet] | [bit] | [bit] | |
* |---------+-------+-------+------------------|
* | === Header =============================== |
* |---------+-------+-------+------------------|
* | 0 | 0 | 8 | Version ID |
* | 1 | 0 | 8 | Tlm / Cmd Count |
* | 2 | 0 | 16 | Tlm / Cmd ID |
* |---------+-------+-------+------------------|
* | === User Data Field ====================== |
* |---------+-------+-------+------------------|
* | 4 | 0 | * | User Data #0 |
* | * | 0 | * | User Data #1 |
* | * | 0 | * | User Data #2 |
* | * | 0 | * | ... |
* |---------+-------+-------+------------------|
*/

各フィールドの説明

  • Version ID
    • 0x00: バージョン不定
    • 0x01: Version 1
  • Tlm / Cmd Count
    • 送信 Packet 毎にインクリメントされていくカウンタ
  • Tlm / Cmd ID
    • Packet 種別を表す ID
  • User Data Field
    • バイト単位で格納されたユーザーデータ

なお,すべてのフィールドのバイトオーダはビッグエンディアンとする.

データリンク層 (Frame)

EB90 Frame

UART などで接続されたコンポーネント間の通信といった,軽微な通信ノイズの誤り検出のみ必要な場合に用いる. ネットワーク層として EB90 Packet や Common Packet などが標準的に使用される.

/**
* @file
* @brief コンポ間通信などで標準的に使う データリンク層 の EB90 Frame
* @note frame 構造
* |---------+-------+-------+------------------|
* | Pos | Pos | size | name |
* | [octet] | [bit] | [bit] | |
* |---------+-------+-------+------------------|
* | === Header =============================== |
* |---------+-------+-------+------------------|
* | 0 | 0 | 16 | STX |
* | 2 | 0 | 16 | Packet Length |
* |---------+-------+-------+------------------|
* | === Packet Field ========================= |
* |---------+-------+-------+------------------|
* | 4 | 0 | * | EB90 Packet や |
* | | | | Space Packet |
* | | | | など |
* | * | 0 | * | ... |
* |---------+-------+-------+------------------|
* | === Footer =============================== |
* |---------+-------+-------+------------------|
* | N - 4 | 0 | 16 | CRC |
* | N - 2 | 0 | 16 | ETX |
* |---------+-------+-------+------------------|
*
* Packet Length:
* Packet Field の長さ
* CRC
* CRC-16/CCITT-FALSE (CRC-16/AUTOSAR, CRC-16/IBM-3740 とも)
* Packet Field の CRC
* Header は含めない
*/

各フィールドの説明

  • STX
    • Frame 先頭識別子
    • 0xEB 0x90 固定
  • Packet Length
    • Packet Field の長さ
  • CRC
    • Packet Field 部分の CRC (Header は含めない)
    • 使用する CRC の種類は CRC-16/CCITT-FALSE (CRC-16/AUTOSAR, CRC-16/IBM-3740 とも)
    • width=16, poly=0x1021, init=0xffff, refin=false, refout=false, xorout=0x0000, check=0x29b1, residue=0x0000
  • ETX
    • Frame 終端識別子
    • 0xC5 0x79 固定
  • Packet Field
    • バイト単位で格納された送信 Packet
    • EB90 Packet や Common Packet などが格納される

なお,すべてのフィールドのバイトオーダはビッグエンディアンとする.

C2A 間通信

衛星内上の C2A (ないしは互換の Common Packet を用いる FSW)を搭載したコンポーネント(主に OBC)間での通信について記す. C2A 間通信によって,以下のような機能が提供される.

  • OBC 間の簡易な Driver 実装と自動コード生成
  • OBC と地上局でネットワークを形成.
    • 地上局から MOBC をルーターとして, 2nd OBC へコマンド配送.
    • 2nd OBC のテレメトリを MOBC を経由して地上局まで配送.
    • OBC A から OBC B に対してコマンド発行 / テレメ送信.

C2A 間通信の具体的な実装については,本リポジトリに同封されている User Sample である Examples/minimum_userExamples/2nd_obc_user での通信(前者が MOBC,後者が AOBC を想定)を参考にされたい. 具体的なドライバのコードは以下となる.

  • #pragma section REPRO
    /**
    * @file
    * @brief AOBC の Driver
    */
    #include "./aobc.h"
    #include "./aobc_command_definitions.h"
    #include "./aobc_telemetry_definitions.h"
    #include "./aobc_telemetry_buffer.h"
    #include <src_core/TlmCmd/common_tlm_cmd_packet.h>
    #include <src_core/TlmCmd/common_cmd_packet.h>
    #include <src_core/Library/endian_memcpy.h>
    #include <src_core/Drivers/Protocol/eb90_frame_for_driver_super.h>
    #include <src_core/Drivers/Protocol/common_tlm_cmd_packet_for_driver_super.h>
    #include <string.h>
    #define AOBC_STREAM_TLM_CMD (0) //!< テレコマで使うストリーム
    static DS_ERR_CODE AOBC_load_driver_super_init_settings_(DriverSuper* p_super);
    static DS_ERR_CODE AOBC_analyze_rec_data_(DS_StreamConfig* p_stream_config,
    void* p_driver);
    static uint8_t AOBC_tx_frame_[EB90_FRAME_HEADER_SIZE +
    CTCP_MAX_LEN +
    EB90_FRAME_FOOTER_SIZE];
    DS_INIT_ERR_CODE AOBC_init(AOBC_Driver* aobc_driver, uint8_t ch)
    {
    DS_ERR_CODE ret;
    memset(aobc_driver, 0x00, sizeof(*aobc_driver));
    AOBC_init_tlm_buffer(aobc_driver);
    aobc_driver->driver.uart_config.ch = ch;
    aobc_driver->driver.uart_config.baudrate = 115200;
    aobc_driver->driver.uart_config.parity_settings = PARITY_SETTINGS_NONE;
    aobc_driver->driver.uart_config.data_length = UART_DATA_LENGTH_8BIT;
    aobc_driver->driver.uart_config.stop_bit = UART_STOP_BIT_1BIT;
    ret = DS_init(&(aobc_driver->driver.super),
    &(aobc_driver->driver.uart_config),
    AOBC_load_driver_super_init_settings_);
    if (ret != DS_ERR_CODE_OK) return DS_INIT_DS_INIT_ERR;
    return DS_INIT_OK;
    }
    static DS_ERR_CODE AOBC_load_driver_super_init_settings_(DriverSuper* p_super)
    {
    DS_StreamConfig* p_stream_config;
    p_super->interface = UART;
    // stream は 0 のみ
    p_stream_config = &(p_super->stream_config[AOBC_STREAM_TLM_CMD]);
    CTCP_init_dssc(p_stream_config, AOBC_tx_frame_, sizeof(AOBC_tx_frame_), AOBC_analyze_rec_data_);
    // 定期 TLM の監視機能の有効化しない → ので設定上書きなし
    DSSC_enable(p_stream_config);
    return DS_ERR_CODE_OK;
    }
    DS_REC_ERR_CODE AOBC_rec(AOBC_Driver* aobc_driver)
    {
    DS_ERR_CODE ret;
    DS_StreamConfig* p_stream_config;
    ret = DS_receive(&(aobc_driver->driver.super));
    if (ret != DS_ERR_CODE_OK) return DS_REC_DS_RECEIVE_ERR;
    p_stream_config = &(aobc_driver->driver.super.stream_config[AOBC_STREAM_TLM_CMD]);
    if (DSSC_get_rec_status(p_stream_config)->status_code != DS_STREAM_REC_STATUS_FIXED_FRAME) return DS_REC_OK; // 受信せず([TODO] 詳細なエラー処理は一旦しない)
    ret = DS_analyze_rec_data(&(aobc_driver->driver.super), AOBC_STREAM_TLM_CMD, aobc_driver);
    if (ret != DS_ERR_CODE_OK) return DS_REC_ANALYZE_ERR;
    return DS_REC_OK;
    }
    static DS_ERR_CODE AOBC_analyze_rec_data_(DS_StreamConfig* p_stream_config,
    void* p_driver)
    {
    AOBC_Driver* aobc_driver = (AOBC_Driver*)p_driver;
    aobc_driver->info.comm.rx_err_code = AOBC_RX_ERR_CODE_OK;
    if (!EB90_FRAME_is_valid_crc_of_dssc(p_stream_config))
    {
    aobc_driver->info.comm.rx_err_code = AOBC_RX_ERR_CODE_CRC_ERR;
    return DS_ERR_CODE_ERR;
    }
    return AOBC_buffer_tlm_packet(p_stream_config, aobc_driver);
    }
    // TODO: DS protocol 改修にともなって古くなったので治す
    #if 0
    // 非C2A系列はこのように書く
    static DS_ERR_CODE AOBC_analyze_rec_data_(DS_StreamConfig* p_stream_config, void* p_driver)
    {
    AOBC_Driver* aobc_driver = (AOBC_Driver*)p_driver;
    uint32_t tlm_ver = DS_ISSLFMT_get_tlm_version(p_stream_config);
    uint32_t tlm_id = DS_ISSLFMT_get_tlm_id(tlm_ver, p_stream_config);
    aobc_driver->info.comm.rx_err_code = AOBC_RX_ERR_CODE_OK;
    // [TODO] ここ自動生成したい...
    switch (tlm_id)
    {
    case AOBC_Tlm_CODE_HK:
    return AOBC_analyze_tlm_hk_(p_stream_config, aobc_driver);
    default:
    aobc_driver->info.comm.rx_err_code = AOBC_RX_ERR_CODE_TLM_NOT_FOUND;
    return DS_ERR_CODE_OK;
    }
    }
    #endif
    DS_CMD_ERR_CODE AOBC_send_cmd(AOBC_Driver* aobc_driver, const CommonCmdPacket* packet)
    {
    DS_ERR_CODE ret;
    DS_StreamConfig* p_stream_config;
    AOBC_CMD_CODE cmd_code;
    p_stream_config = &(aobc_driver->driver.super.stream_config[AOBC_STREAM_TLM_CMD]);
    // tx_frameの設定
    CCP_set_tx_frame_to_dssc(p_stream_config, packet);
    cmd_code = (AOBC_CMD_CODE)CCP_get_id(packet);
    // [TODO] ここではコマンドが実際に存在するか,ということはフィルタしない!(でいいよね?)
    // 必要があれば,AOBC 側で弾くべき.
    if (cmd_code == AOBC_Cmd_CODE_GENERATE_TLM)
    {
    ret = DS_send_req_tlm_cmd(&(aobc_driver->driver.super), AOBC_STREAM_TLM_CMD);
    }
    else
    {
    ret = DS_send_general_cmd(&(aobc_driver->driver.super), AOBC_STREAM_TLM_CMD);
    }
    if (ret == DS_ERR_CODE_OK)
    {
    return DS_CMD_OK;
    }
    else
    {
    // TODO: エラー処理?
    return DS_CMD_DRIVER_SUPER_ERR;
    }
    }
    #pragma section
  • #pragma section REPRO
    /**
    * @file
    * @brief MOBC の Driver
    */
    // FIXME: DS 側の TCP が整理されたら, TCP 関連を撲滅し, CTCP に統一する
    #include "./mobc.h"
    #include <src_core/TlmCmd/common_tlm_cmd_packet.h>
    #include <src_core/Library/endian_memcpy.h>
    #include <src_core/Drivers/Protocol/eb90_frame_for_driver_super.h>
    #include <src_core/Drivers/Protocol/common_tlm_cmd_packet_for_driver_super.h>
    #include <string.h>
    #define MOBC_STREAM_TLM_CMD (0) //!< テレコマで使うストリーム
    static uint8_t MOBC_tx_frame_[EB90_FRAME_HEADER_SIZE +
    CTCP_MAX_LEN +
    EB90_FRAME_FOOTER_SIZE];
    static DS_ERR_CODE MOBC_load_driver_super_init_settings_(DriverSuper* p_super);
    static DS_ERR_CODE MOBC_analyze_rec_data_(DS_StreamConfig* p_stream_config,
    void* p_driver);
    DS_INIT_ERR_CODE MOBC_init(MOBC_Driver* mobc_driver, uint8_t ch)
    {
    DS_ERR_CODE ret;
    memset(mobc_driver, 0x00, sizeof(MOBC_Driver));
    mobc_driver->driver.uart_config.ch = ch;
    mobc_driver->driver.uart_config.baudrate = 115200;
    mobc_driver->driver.uart_config.parity_settings = PARITY_SETTINGS_NONE;
    mobc_driver->driver.uart_config.data_length = UART_DATA_LENGTH_8BIT;
    mobc_driver->driver.uart_config.stop_bit = UART_STOP_BIT_1BIT;
    ret = DS_init(&(mobc_driver->driver.super),
    &(mobc_driver->driver.uart_config),
    MOBC_load_driver_super_init_settings_);
    if (ret != DS_ERR_CODE_OK) return DS_INIT_DS_INIT_ERR;
    return DS_INIT_OK;
    }
    static DS_ERR_CODE MOBC_load_driver_super_init_settings_(DriverSuper* p_super)
    {
    DS_StreamConfig* p_stream_config;
    p_super->interface = UART;
    // stream は 0 のみ
    p_stream_config = &(p_super->stream_config[MOBC_STREAM_TLM_CMD]);
    CTCP_init_dssc(p_stream_config, MOBC_tx_frame_, sizeof(MOBC_tx_frame_), MOBC_analyze_rec_data_);
    // 定期 TLM の監視機能の有効化しない → ので設定上書きなし
    DSSC_enable(p_stream_config);
    return DS_ERR_CODE_OK;
    }
    DS_REC_ERR_CODE MOBC_rec(MOBC_Driver* mobc_driver)
    {
    DS_ERR_CODE ret;
    DS_StreamConfig* p_stream_config;
    ret = DS_receive(&(mobc_driver->driver.super));
    if (ret != DS_ERR_CODE_OK) return DS_REC_DS_RECEIVE_ERR;
    p_stream_config = &(mobc_driver->driver.super.stream_config[MOBC_STREAM_TLM_CMD]);
    if (DSSC_get_rec_status(p_stream_config)->status_code != DS_STREAM_REC_STATUS_FIXED_FRAME) return DS_REC_OK; // 受信せず(TODO: 詳細なエラー処理は一旦しない)
    ret = DS_analyze_rec_data(&(mobc_driver->driver.super), MOBC_STREAM_TLM_CMD, mobc_driver);
    if (ret != DS_ERR_CODE_OK) return DS_REC_ANALYZE_ERR;
    return DS_REC_OK;
    }
    static DS_ERR_CODE MOBC_analyze_rec_data_(DS_StreamConfig* p_stream_config, void* p_driver)
    {
    MOBC_Driver* mobc_driver = (MOBC_Driver*)p_driver;
    CommonCmdPacket packet; // FIXME: これは static にする?
    // static のほうがコンパイル時にアドレスが確定して安全. Out of stack space を回避できる
    // 一方でメモリ使用量は増える.
    DS_ERR_CODE ret = CCP_get_ccp_from_dssc(p_stream_config, &packet);
    if (ret != DS_ERR_CODE_OK)
    {
    mobc_driver->info.comm.rx_err_code = MOBC_RX_ERR_CODE_INVALID_PACKET;
    return ret;
    }
    mobc_driver->info.comm.rx_err_code = MOBC_RX_ERR_CODE_OK;
    if (!EB90_FRAME_is_valid_crc_of_dssc(p_stream_config))
    {
    mobc_driver->info.comm.rx_err_code = MOBC_RX_ERR_CODE_CRC_ERR;
    return DS_ERR_CODE_ERR;
    }
    // MOBC からのコマンドは以下のパターン
    // APID:
    // APID_AOBC_CMD
    // CCP_EXEC_TYPE:
    // CCP_EXEC_TYPE_GS <- GS から MOBC のキューに入らず直接転送されたもの
    // CCP_EXEC_TYPE_TL0 <- GS から MOBC のキューに入らず直接転送されたもの
    // CCP_EXEC_TYPE_MC <- GS から MOBC のキューに入らず直接転送されたもの
    // CCP_EXEC_TYPE_RT <- これが GS → MOBC との違いで, MOBC の TLC/BC キューに溜まって実行されたもの
    // CCP_DEST_TYPE:
    // CCP_DEST_TYPE_TO_ME (CCP_DEST_TYPE_TO_AOBC の可能性はなくはないが, ME に上書きされているはず)
    // FIXME: ここで返り値が NG だった場合,なにを return するかは議論の余地あり
    // 通信的には OK なので, OK を返すのでいいという認識
    // FIXME: CTCP 大工事が終わったら,返り値をちゃんと見るようにする
    mobc_driver->info.c2a.ph_ack = PH_analyze_cmd_packet(&packet);
    return DS_ERR_CODE_OK;
    }
    DS_CMD_ERR_CODE MOBC_send(MOBC_Driver* mobc_driver, const CommonTlmPacket* packet)
    {
    DS_ERR_CODE ret;
    DS_StreamConfig* p_stream_config;
    p_stream_config = &(mobc_driver->driver.super.stream_config[MOBC_STREAM_TLM_CMD]);
    // tx_frameの設定
    CTP_set_tx_frame_to_dssc(p_stream_config, packet);
    ret = DS_send_general_cmd(&(mobc_driver->driver.super), MOBC_STREAM_TLM_CMD);
    if (ret == DS_ERR_CODE_OK)
    {
    return DS_CMD_OK;
    }
    else
    {
    // TODO: エラー処理?
    return DS_CMD_DRIVER_SUPER_ERR;
    }
    }
    #pragma section

地上局からのコマンドルーティングについては Core Layer/Communication#コマンド配送におけるルーティングについて などを参照すること.