コンポーネント間通信などをまとめる.
なお,地上局との通信関連や, 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 を可能な限り用いる.
Core Layer/Communication を参照のこと.
Common Packet ほどリッチな情報をやり取りしない通信に用いる. したがって, User Data Field 以外の Header には,
- Version ID
- Tlm / Cmd Count
- Tlm / Cmd ID
のみ,定義されている.
直接通信する2者を超え,ネットワークを構築するだけの能力はない.
また,通常データリンク層としては EB90 Frame が用いられる.
現在は Ver.1 のみ策定されており,その定義は以下を参照すること.
c2a-core/Drivers/Protocol/eb90_packet_for_driver_super.h
Lines 1 to 25 in 9f5154d
/** | |
* @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
- バイト単位で格納されたユーザーデータ
なお,すべてのフィールドのバイトオーダはビッグエンディアンとする.
UART などで接続されたコンポーネント間の通信といった,軽微な通信ノイズの誤り検出のみ必要な場合に用いる. ネットワーク層として EB90 Packet や Common Packet などが標準的に使用される.
c2a-core/Drivers/Protocol/eb90_frame_for_driver_super.h
Lines 1 to 33 in 9f5154d
/** | |
* @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 (ないしは互換の Common Packet を用いる FSW)を搭載したコンポーネント(主に OBC)間での通信について記す. C2A 間通信によって,以下のような機能が提供される.
- OBC 間の簡易な Driver 実装と自動コード生成
- c2a-tlm-cmd-code-generator 参照.
Examples/minimum_user/src/src_user/Drivers/Aocs
などの多くのコードが自動生成される.
- OBC と地上局でネットワークを形成.
- 地上局から MOBC をルーターとして, 2nd OBC へコマンド配送.
- 2nd OBC のテレメトリを MOBC を経由して地上局まで配送.
- OBC A から OBC B に対してコマンド発行 / テレメ送信.
- 他
C2A 間通信の具体的な実装については,本リポジトリに同封されている User Sample である Examples/minimum_user
と Examples/2nd_obc_user
での通信(前者が MOBC,後者が AOBC を想定)を参考にされたい.
具体的なドライバのコードは以下となる.
c2a-core/Examples/minimum_user/src/src_user/Drivers/Aocs/aobc.c
Lines 1 to 164 in 9f5154d
#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 c2a-core/Examples/2nd_obc_user/src/src_user/Drivers/Etc/mobc.c
Lines 1 to 150 in 9f5154d
#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#コマンド配送におけるルーティングについて などを参照すること.