#pragma section REPRO /** * @file * @brief 各制御センサ・アクチュエータ等とのインターフェースドライバ群のスーパークラス * * ComponentDriverSuper Class は * 各制御センサ・アクチュエータ等とのインターフェースを実現し, * 初期化,コマンド発行,テレメトリリクエスト,テレメトリ受信,テレメトリ解析などを行う,ドライバ群のスーパークラスです. * 個々の機器のインターフェースドライバに継承させて使用します. */ #include "driver_super.h" #include "../library/print.h" #include // for memset などの mem 系 #include // for NULL #include "../tlm_cmd/common_packet/common_cmd_packet_util.h" // #define CDS_DEBUG // 適切なときにコメントアウトする // #define CDS_DEBUG_SHOW_REC_DATA // 適切なときにコメントアウトする static uint8_t CDS_hal_rx_buffer_[CDS_HAL_RX_BUFFER_SIZE]; //!< HAL_rx_handlers で受信するときの一次バッファ // ###### 送受信関連 static 関数 ###### /** * @brief コマンド送信処理 * * CDS_send_general_cmd と CDS_send_req_tlm_cmdの共通部分 * @param p_super: ComponentDriverSuper 構造体へのポインタ * @param stream: どの config を使用するか.stream は 0-MAX なので,継承先で ENUM など宣言して使いやすくすればいいと思う. * @retval CDS_ERR_CODE_OK: 正常終了 * @retval CDS_ERR_CODE_ERR: HAL_tx_handlers でのエラーあり * @note 受信状況やエラー情報は send_status_ に格納されている */ static CDS_ERR_CODE CDS_send_cmd_(ComponentDriverSuper* p_super, uint8_t stream); /** * @brief 継承先の機器にコマンドを発行する * @note この関数の実行前に,tx_frame_, tx_frame_size_の設定が必要である * @param p_super: ComponentDriverSuper 構造体へのポインタ * @param stream: どの config を使用するか.stream は 0-MAX なので,継承先で ENUM など宣言して使いやすくすればいいと思う. * @retval CDS_ERR_CODE_OK (0): 正常終了 * @retval 0 以外: HAL_tx_handlers の戻り値 */ static int CDS_tx_(ComponentDriverSuper* p_super, uint8_t stream); /** * @brief 継承先の機器からの受信データがあるか確認し,受信する * @param p_super: ComponentDriverSuper 構造体へのポインタ * @retval 0: 受信データなし * @retval 正数: 受信データ長 [Byte] * @retval 負数: HAL_rx_handlers のエラー */ static int CDS_rx_(ComponentDriverSuper* p_super); /** * @brief 受信フレーム解析関数 * @param[in] p_stream_config: ComponentDriverSuper 構造体の CDS_StreamConfig * @param[in] rec_data_len: 今回新規に受信したデータ長 * @return void 詳細は CDS_StreamRecStatus */ static void CDS_analyze_rx_buffer_(CDS_StreamConfig* p_stream_config, uint16_t rec_data_len); /** * @brief 解析用受信バッファの準備 * * 繰り越されたデータと今回受信したデータの結合を行い,受信データ解析の準備をする * @param[in] p_stream_config: ComponentDriverSuper 構造体の CDS_StreamConfig * @param[in] rec_data_len: 今回新規に受信したデータ長 * @return void * @note 厳格なフレーム探索が有効かどうかで処理が変わることに注意 */ static void CDS_analyze_rx_buffer_prepare_buffer_(CDS_StreamConfig* p_stream_config, uint16_t rec_data_len); /** * @brief フレーム解析関数 * * 受信バッファを走査し,バイト単位でフレーム内データを確認していく * @param p_stream_config: ComponentDriverSuper 構造体の CDS_StreamConfig * @return void その他の詳細は CDS_StreamRecStatus */ static void CDS_analyze_rx_buffer_pickup_(CDS_StreamConfig* p_stream_config); /** * @brief フレーム解析関数後の繰越データの頭出し * @param p_stream_config: ComponentDriverSuper 構造体の CDS_StreamConfig * @return void */ static void CDS_analyze_rx_buffer_cueing_buffer_(CDS_StreamConfig* p_stream_config); /** * @brief 固定長フレーム解析関数(バイト列処理) * * 受信バッファのデータを走査し,必要なデータをフレームとして pickup する * @param p_stream_config: ComponentDriverSuper 構造体の CDS_StreamConfig * @return void その他の詳細は CDS_StreamRecStatus */ static void CDS_analyze_rx_buffer_fixed_pickup_(CDS_StreamConfig* p_stream_config); /** * @brief 可変フレーム解析関数(バイト列処理) * * 受信バッファのデータを走査し,必要なデータをフレームとして pickup する * @note 受信フレームにフレーム長データが存在していることを前提とする * @param p_stream_config: ComponentDriverSuper 構造体の CDS_StreamConfig * @return void その他の詳細は CDS_StreamRecStatus */ static void CDS_analyze_rx_buffer_variable_pickup_with_rx_frame_size_(CDS_StreamConfig* p_stream_config); /** * @brief 可変フレーム解析関数(バイト列処理) * * 受信バッファのデータを走査し,必要なデータをフレームとして pickup する * @note CDS_analyze_rx_buffer_variable_pickup_with_rx_frame_size_ との違いは,テレメ長データがフレームに含まれるか否か * @note フッタが存在していることを前提とする * @note ヘッダなしは認める.ただし,受信データ先頭からフレームとみなすので,ヘッダありを強く推奨する * @param p_stream_config: ComponentDriverSuper 構造体の CDS_StreamConfig * @return void その他の詳細は CDS_StreamRecStatus */ static void CDS_analyze_rx_buffer_variable_pickup_with_footer_(CDS_StreamConfig* p_stream_config); /** * @brief フレーム解析関数(ヘッダ探索) * @note ヘッダが見つかった場合,最初の 1 byte のみ処理する * @param p_stream_config: ComponentDriverSuper 構造体の CDS_StreamConfig * @return void その他の詳細は CDS_StreamRecStatus */ static void CDS_analyze_rx_buffer_finding_header_(CDS_StreamConfig* p_stream_config); /** * @brief フレーム解析関数(ヘッダ受信中) * @note 1 byte のみ処理する * @param p_stream_config: ComponentDriverSuper 構造体の CDS_StreamConfig * @return void その他の詳細は CDS_StreamRecStatus */ static void CDS_analyze_rx_buffer_receiving_header_(CDS_StreamConfig* p_stream_config); /** * @brief フレーム解析関数(フッタ受信中) * @note 1 byte のみ処理する * @note 現在,フレーム長が uint16_t を超えることは想定していない! * @param p_stream_config: ComponentDriverSuper 構造体の CDS_StreamConfig * @param rx_frame_size: フレームサイズ(可変長フレームの場合もあるので,引数に取る) * @return void その他の詳細は CDS_StreamRecStatus */ static void CDS_analyze_rx_buffer_receiving_footer_(CDS_StreamConfig* p_stream_config, uint16_t rx_frame_size); /** * @brief フレーム解析中に受信したフレームからフレーム長を取得する関数 * @note CDS_analyze_rx_buffer_variable_pickup_with_rx_frame_size_ から呼ばれることを想定 * @param p_stream_config: ComponentDriverSuper 構造体の CDS_StreamConfig * @return フレーム長 */ static uint32_t CDS_analyze_rx_buffer_get_framelength_(CDS_StreamConfig* p_stream_config); /** * @brief CDS_StreamConfig 構造体の初期化 * * CDS_StreamConfig 構造体を初期化し,デフォルト値で埋める. * @param p_stream_config: ComponentDriverSuper 構造体の CDS_StreamConfig * @return CDS_ERR_CODE */ static CDS_ERR_CODE CDS_reset_stream_config_(CDS_StreamConfig* p_stream_config); /** * @brief CDS_StreamConfig 構造体のバリデーション * @param p_super: ComponentDriverSuper 構造体へのポインタ * @param p_stream_config: ComponentDriverSuper 構造体の CDS_StreamConfig * @return CDS_ERR_CODE */ static CDS_ERR_CODE CDS_validate_stream_config_(const ComponentDriverSuper* p_super, CDS_StreamConfig* p_stream_config); // ダミー関数 // EQU だと関数ポインタの初期値を NULL にしていたためにぬるぽで事故ったので static CDS_ERR_CODE CDS_load_init_setting_dummy_(ComponentDriverSuper* p_super); static CDS_ERR_CODE CDS_data_analyzer_dummy_(CDS_StreamConfig* p_stream_config, void* p_driver); // ###### CDS_StreamRecBuffer 関連 static 関数 ###### /** * @brief CDS_StreamRecBuffer のクリア * @param[in,out] stream_rec_buffer: クリアする CDS_StreamRecBuffer * @return void */ void CDS_clear_stream_rec_buffer_(CDS_StreamRecBuffer* stream_rec_buffer); /** * @brief CDS_StreamRecBuffer の前方要素の削除 * @note stream_rec_buffer は NULL でないことを仮定する * @param[in,out] stream_rec_buffer: 削除する CDS_StreamRecBuffer * @param[in] size: 削除するバッファサイズ * @return void */ void CDS_drop_from_stream_rec_buffer_(CDS_StreamRecBuffer* stream_rec_buffer, uint16_t size); /** * @brief CDS_StreamRecBuffer の追記(後ろへの) * @note stream_rec_buffer は NULL でないことを仮定する * @param[in,out] stream_rec_buffer: 追記する CDS_StreamRecBuffer * @param[in] buffer: 追記するバッファ * @param[in] size: 追記するバッファサイズ * @retval CDS_ERR_CODE_OK: 正常終了 * @retval CDS_ERR_CODE_ERR: サイズ不足でコピーできず */ CDS_ERR_CODE CDS_push_to_stream_rec_buffer_(CDS_StreamRecBuffer* stream_rec_buffer, const uint8_t* buffer, uint16_t size); /** * @brief CDS_StreamRecBuffer の未処理バッファサイズの取得 * @note stream_rec_buffer は NULL でないことを仮定する * @param[in] stream_rec_buffer: CDS_StreamRecBuffer * @return 未処理バッファサイズ */ uint16_t CDS_get_unprocessed_size_from_stream_rec_buffer_(CDS_StreamRecBuffer* stream_rec_buffer); /** * @brief CDS_StreamRecBuffer で指定サイズだけバッファを確定させる * @note stream_rec_buffer は NULL でないことを仮定する * @param[in,out] stream_rec_buffer: 確定させる CDS_StreamRecBuffer * @param[in] size: 確定させるバッファサイズ * @return void */ void CDS_confirm_stream_rec_buffer_(CDS_StreamRecBuffer* stream_rec_buffer, uint16_t size); /** * @brief CDS_StreamRecBuffer で指定サイズだけフレーム開始点を前進させる * @note stream_rec_buffer は NULL でないことを仮定する * @param[in,out] stream_rec_buffer: 前進させる CDS_StreamRecBuffer * @param[in] size: 前進させるバッファサイズ * @return void */ void CDS_move_forward_frame_head_candidate_of_stream_rec_buffer_(CDS_StreamRecBuffer* stream_rec_buffer, uint16_t size); // ###### ComponentDriverSuper基本関数 ###### CDS_ERR_CODE CDS_init(ComponentDriverSuper* p_super, void* hal_config, CDS_StreamRecBuffer* rx_buffer, CDS_ERR_CODE (*load_init_setting)(ComponentDriverSuper* p_super)) { CDS_StreamRecBuffer* rx_buffers[CDS_STREAM_MAX]; CDS_nullify_stream_rec_buffers(rx_buffers); rx_buffers[0] = rx_buffer; return CDS_init_streams(p_super, hal_config, rx_buffers, load_init_setting); } CDS_ERR_CODE CDS_init_streams(ComponentDriverSuper* p_super, void* hal_config, CDS_StreamRecBuffer* rx_buffers[CDS_STREAM_MAX], CDS_ERR_CODE (*load_init_setting)(ComponentDriverSuper* p_super)) { uint8_t stream; if (CDS_reset(p_super) != CDS_ERR_CODE_OK) return CDS_ERR_CODE_ERR; p_super->hal_config = hal_config; // load_init_setting で上書きできるようにここで設定 for (stream = 0; stream < CDS_STREAM_MAX; ++stream) { if (rx_buffers[stream] != NULL) { CDSSC_set_rx_buffer(&(p_super->stream_config[stream]), rx_buffers[stream]); } } p_super->config.internal.load_init_setting = load_init_setting; if (p_super->config.internal.load_init_setting(p_super) != CDS_ERR_CODE_OK) return CDS_ERR_CODE_ERR; if (CDS_validate_config(p_super) != CDS_ERR_CODE_OK) return CDS_ERR_CODE_ERR; // HAL の初期化 // 一旦シンプルに HAL_init_handlers のエラーコードは無視する(実機でここでエラー出る場合はコードがおかしいので.必要があれば将来実装.) if (CDS_hal_init(p_super) != 0 ) return CDS_ERR_CODE_ERR; return CDS_ERR_CODE_OK; } CDS_ERR_CODE CDS_receive(ComponentDriverSuper* p_super) { uint8_t stream; uint16_t rec_data_len; int ret_rx; p_super->config.info.rx_call_count_++; // 各 ComponentDriver で物理的に接続されている wire は1本なので,それをここで受信する. // 後段の stream では,その受信したビット列に対して,複数のフレーム種類に対して,フレーム探索,確定処理を走らす. ret_rx = CDS_rx_(p_super); p_super->config.info.rec_status_.ret_from_hal_rx = ret_rx; if (ret_rx > 0) { // なにかしらの受信データあり p_super->config.info.rx_count_++; p_super->config.info.rx_time_ = TMGR_get_master_clock(); } // 受信途絶判定 // テレメなどで見るときにノイズになるので,判定しないときは OK にしておく p_super->config.info.rec_status_.rx_disruption_status = CDS_RX_DISRUPTION_STATUS_OK; if (p_super->config.settings.should_monitor_for_rx_disruption_) { ObcTime now = TMGR_get_master_clock(); uint32_t last_rx_ago = OBCT_diff_in_msec(&p_super->config.info.rx_time_, &now); if (last_rx_ago > p_super->config.settings.time_threshold_for_rx_disruption_) { p_super->config.info.rec_status_.rx_disruption_status = CDS_RX_DISRUPTION_STATUS_LOST; } } for (stream = 0; stream < CDS_STREAM_MAX; ++stream) { CDS_StreamConfig* p_stream_config = &(p_super->stream_config[stream]); if (!p_stream_config->settings.is_enabled_) { p_stream_config->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_DISABLE; continue; } // setter で validation かけると,初期化などで何度もかかることや, // そもそもこの validation は打ち上げ時というよりむしろ地上試験時に有用なので,ここに置く if (p_stream_config->internal.is_validation_needed_for_rec_) { CDS_ERR_CODE ret = CDS_validate_stream_config_(p_super, p_stream_config); if (ret != CDS_ERR_CODE_OK) { p_stream_config->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_VALIDATE_ERR; continue; } } if (ret_rx < 0) // この共通処理が for の中にあるの,若干キモい... { // RX失敗 p_stream_config->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_RX_ERR; // [TODO] ここに ComponentDriverSuper としての共通のアノマリ発行を入れるかは要議論 // 個別対応なので, ComponentDriver に実装する,ないしは, IF 側に実装するのが自然か? continue; } else if (ret_rx == 0) { // 受信データなし // 今回の受信はなくとも,バッファ内部に未処理データがあれば処理する if (CDS_get_unprocessed_size_from_stream_rec_buffer_(p_stream_config->settings.rx_buffer_) > 0) { // 繰越があるので,ここで continue せずへ次へ } else { // rec_status_.status_code 基本は更新せず // FIXED の場合はリセット if (p_stream_config->info.rec_status_.status_code == CDS_STREAM_REC_STATUS_FIXED_FRAME) { p_stream_config->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_FINDING_HEADER; } continue; } } else { // 何もしない } // ここまできたら受信データあり rec_data_len = (uint16_t)ret_rx; // ここまでくれば非負数 // 受信データ処理 CDS_analyze_rx_buffer_(p_stream_config, rec_data_len); // フレーム確定処理 if (p_stream_config->info.rec_status_.status_code == CDS_STREAM_REC_STATUS_FIXED_FRAME) { p_stream_config->info.rx_frame_fix_count_++; p_stream_config->info.rx_frame_fix_time_ = TMGR_get_master_clock(); p_stream_config->info.req_tlm_cmd_tx_count_after_last_tx_ = 0; } } // streamのテレメ途絶判定(テレメフレーム確定途絶判定) for (stream = 0; stream < CDS_STREAM_MAX; ++stream) { CDS_StreamConfig* p_stream_config = &(p_super->stream_config[stream]); ObcTime now; uint32_t last_tlm_fix_ago; // テレメなどで見るときにノイズになるので,判定しないときは OK にしておく p_stream_config->info.rec_status_.tlm_disruption_status = CDS_STREAM_TLM_DISRUPTION_STATUS_OK; if (!p_stream_config->settings.is_enabled_ || !p_stream_config->settings.should_monitor_for_tlm_disruption_) { continue; } now = TMGR_get_master_clock(); last_tlm_fix_ago = OBCT_diff_in_msec(&p_stream_config->info.rx_frame_fix_time_, &now); if (last_tlm_fix_ago > p_stream_config->settings.time_threshold_for_tlm_disruption_) { p_stream_config->info.rec_status_.tlm_disruption_status = CDS_STREAM_TLM_DISRUPTION_STATUS_LOST; } } return (ret_rx < 0) ? CDS_ERR_CODE_ERR : CDS_ERR_CODE_OK; } CDS_ERR_CODE CDS_analyze_rec_data(ComponentDriverSuper* p_super, uint8_t stream, void* p_driver) { CDS_StreamConfig* p_stream_config = &(p_super->stream_config[stream]); p_stream_config->info.ret_from_data_analyzer_ = p_stream_config->settings.data_analyzer_(p_stream_config, p_driver); return p_stream_config->info.ret_from_data_analyzer_; } CDS_ERR_CODE CDS_send_general_cmd(ComponentDriverSuper* p_super, uint8_t stream) { CDS_StreamConfig* p_stream_config = &(p_super->stream_config[stream]); if (!p_stream_config->settings.is_enabled_) { p_stream_config->info.send_status_.status_code = CDS_STREAM_SEND_STATUS_DISABLE; return CDS_ERR_CODE_OK; } p_stream_config->info.general_cmd_tx_count_++; p_stream_config->info.general_cmd_tx_time_ = TMGR_get_master_clock(); #ifdef CDS_DEBUG Printf("DS: send_general_cmd\n"); #endif return CDS_send_cmd_(p_super, stream); } CDS_ERR_CODE CDS_send_req_tlm_cmd(ComponentDriverSuper* p_super, uint8_t stream) { CDS_StreamConfig* p_stream_config = &(p_super->stream_config[stream]); if (!p_stream_config->settings.is_enabled_) { p_stream_config->info.send_status_.status_code = CDS_STREAM_SEND_STATUS_DISABLE; return CDS_ERR_CODE_OK; } p_stream_config->info.req_tlm_cmd_tx_count_++; p_stream_config->info.req_tlm_cmd_tx_count_after_last_tx_++; p_stream_config->info.req_tlm_cmd_tx_time_ = TMGR_get_master_clock(); #ifdef CDS_DEBUG Printf("DS: send_req_tlm_cmd\n"); #endif return CDS_send_cmd_(p_super, stream); } // ###### ComponentDriverSuper 低レベル関数(デバッグ用, ComponentDriverUtility 用など) ###### CDS_ERR_CODE CDS_reset(ComponentDriverSuper* p_super) { uint8_t stream; p_super->hal_handler_id = HAL_HANDLER_ID_MAX; // FIXME: (*HAL_init_handlers[p_super->hal_handler_id])(p_super->hal_config) の様な使い方をするのでセグフォが起こる可能性があり p_super->hal_config = NULL; // FIXME: NULL ポインタはこの関数が Reset 単体で使われるとマズい p_super->config.settings.hal_rx_buffer_size_ = CDS_HAL_RX_BUFFER_SIZE; p_super->config.settings.should_monitor_for_rx_disruption_ = 0; p_super->config.settings.time_threshold_for_rx_disruption_ = 60 * 1000; // この値はよく考えること p_super->config.info.rec_status_.ret_from_hal_rx = 0; p_super->config.info.rec_status_.rx_disruption_status = CDS_RX_DISRUPTION_STATUS_OK; p_super->config.info.rx_count_ = 0; p_super->config.info.rx_call_count_ = 0; p_super->config.info.rx_time_ = TMGR_get_master_clock(); p_super->config.internal.load_init_setting = CDS_load_init_setting_dummy_; for (stream = 0; stream < CDS_STREAM_MAX; ++stream) { CDS_ERR_CODE ret = CDS_reset_stream_config_(&p_super->stream_config[stream]); if (ret != CDS_ERR_CODE_OK) return ret; } CDS_clear_rx_buffer(p_super); return CDS_ERR_CODE_OK; } CDS_ERR_CODE CDS_validate_config(ComponentDriverSuper* p_super) { uint8_t stream; if (p_super->hal_handler_id < 0 || p_super->hal_handler_id >= HAL_HANDLER_ID_MAX) return CDS_ERR_CODE_ERR; if (p_super->hal_config == NULL) return CDS_ERR_CODE_ERR; if (p_super->config.settings.hal_rx_buffer_size_ > CDS_HAL_RX_BUFFER_SIZE) return CDS_ERR_CODE_ERR; for (stream = 0; stream < CDS_STREAM_MAX; ++stream) { CDS_ERR_CODE ret = CDS_validate_stream_config_(p_super, &p_super->stream_config[stream]); if (ret != CDS_ERR_CODE_OK) return ret; } return CDS_ERR_CODE_OK; } CDS_ERR_CODE CDS_clear_rx_buffer(ComponentDriverSuper* p_super) { uint8_t stream; for (stream = 0; stream < CDS_STREAM_MAX; ++stream) { CDS_clear_stream_rec_buffer_(p_super->stream_config[stream].settings.rx_buffer_); } // FIXME: すべての ComponentDriver の初期化で呼ばれ,無駄 memset(CDS_hal_rx_buffer_, 0x00, sizeof(CDS_hal_rx_buffer_)); return CDS_ERR_CODE_OK; } int CDS_hal_init(ComponentDriverSuper* p_super) { // HAL の初期化 // 一旦シンプルに HAL_init_handlers のエラーコードは無視する(実機でここでエラー出る場合はコードがおかしいので.必要があれば将来実装.) return (*HAL_init_handlers[p_super->hal_handler_id])(p_super->hal_config); } int CDS_hal_rx(ComponentDriverSuper* p_super, void* buffer, int buffer_size) { return (*HAL_rx_handlers[p_super->hal_handler_id])(p_super->hal_config, buffer, buffer_size); } int CDS_hal_tx(ComponentDriverSuper* p_super, const void* data, int data_size) { // FIXME; HAL_tx_handlers の第二引数は const つけるべき return (*HAL_tx_handlers[p_super->hal_handler_id])(p_super->hal_config, (void*)data, data_size); // FIXME: const_cast } int CDS_hal_reopen(ComponentDriverSuper* p_super, int reason) { return (*HAL_reopen_handlers[p_super->hal_handler_id])(p_super->hal_config, reason); } // ###### 送受信関連 static 関数 ###### static CDS_ERR_CODE CDS_send_cmd_(ComponentDriverSuper* p_super, uint8_t stream) { CDS_StreamConfig* p_stream_config = &(p_super->stream_config[stream]); // setter で validation かけると,初期化などで何度もかかることや, // そもそもこの validation は打ち上げじというよりむしろ地上試験時に有用なので,ここに置く if (p_stream_config->internal.is_validation_needed_for_send_) { CDS_ERR_CODE ret = CDS_validate_stream_config_(p_super, p_stream_config); if (ret != CDS_ERR_CODE_OK) { p_stream_config->info.send_status_.status_code = CDS_STREAM_SEND_STATUS_VALIDATE_ERR; return CDS_ERR_CODE_ERR; } } p_stream_config->info.send_status_.ret_from_hal_tx = CDS_tx_(p_super, stream); if (p_stream_config->info.send_status_.ret_from_hal_tx != 0) { p_stream_config->info.send_status_.status_code = CDS_STREAM_SEND_STATUS_TX_ERR; return CDS_ERR_CODE_ERR; } p_stream_config->info.send_status_.status_code = CDS_STREAM_SEND_STATUS_OK; return CDS_ERR_CODE_OK; } static int CDS_tx_(ComponentDriverSuper* p_super, uint8_t stream) { int ret; CDS_StreamConfig* p_stream_config = &(p_super->stream_config[stream]); if (p_stream_config->settings.tx_frame_size_ == 0) return CDS_ERR_CODE_OK; if (p_stream_config->settings.tx_frame_ == NULL) return CDS_ERR_CODE_OK; #ifdef CDS_DEBUG Printf("DS: tx_\n"); #endif ret = CDS_hal_tx(p_super, p_stream_config->settings.tx_frame_, (int)p_stream_config->settings.tx_frame_size_); if (ret != 0) return ret; return CDS_ERR_CODE_OK; } static int CDS_rx_(ComponentDriverSuper* p_super) { int flag; int rec_data_len; uint8_t stream; #ifdef CDS_DEBUG_SHOW_REC_DATA int16_t i; #endif // 少なくとも 1 つの stream が有効でかつ,rx_frame_size_ が 0 以外でないと受信処理はしない flag = 0; for (stream = 0; stream < CDS_STREAM_MAX; ++stream) { if (! (p_super->stream_config[stream].settings.is_enabled_) ) continue; if (p_super->stream_config[stream].settings.rx_frame_size_ != 0) { flag = 1; } } if (flag == 0) return 0; rec_data_len = CDS_hal_rx(p_super, CDS_hal_rx_buffer_, p_super->config.settings.hal_rx_buffer_size_); #ifdef CDS_DEBUG Printf("DS: rx_\n"); #endif if (rec_data_len <= 0) return rec_data_len; // 負数はエラーコード #ifdef CDS_DEBUG_SHOW_REC_DATA Printf("DS: Receive data size is %d bytes, as follow:\n", rec_data_len); for (i = 0; i < rec_data_len; i++) { Printf("%02x ", CDS_hal_rx_buffer_[i]); if (i % 4 == 3) Printf(" "); } Printf("\n"); #endif return rec_data_len; } static void CDS_analyze_rx_buffer_(CDS_StreamConfig* p_stream_config, uint16_t rec_data_len) { CDS_analyze_rx_buffer_prepare_buffer_(p_stream_config, rec_data_len); CDS_analyze_rx_buffer_pickup_(p_stream_config); // 次回のデータ受信に備えて,バッファの頭出し CDS_analyze_rx_buffer_cueing_buffer_(p_stream_config); } static void CDS_analyze_rx_buffer_prepare_buffer_(CDS_StreamConfig* p_stream_config, uint16_t rec_data_len) { // rx_buffer_ には,前回確定したフレームも残っているので,それは除く // したがって, DS の CDSSC_get_rx_frame した frame へのポインタは,次回受信時までしか有効ではない CDS_StreamRecBuffer* buffer = p_stream_config->settings.rx_buffer_; CDS_ERR_CODE ret; if (buffer->is_frame_fixed) { // ユーザー側ですでにデータを取得したと判断して,バッファから下ろす CDS_drop_from_stream_rec_buffer_(buffer, buffer->pos_of_frame_head_candidate); // 念のため if (p_stream_config->settings.is_strict_frame_search_) { // 厳格なフレーム探索なので,1 つの可能性も受信漏らさないように CDS_drop_from_stream_rec_buffer_(buffer, 1); } else { CDS_drop_from_stream_rec_buffer_(buffer, buffer->confirmed_frame_len); } buffer->is_frame_fixed = 0; } // 新規受信分をバッファへ buffer->pos_of_last_rec = buffer->size; // 最終更新地点を更新 ret = CDS_push_to_stream_rec_buffer_(buffer, CDS_hal_rx_buffer_, rec_data_len); if (ret != CDS_ERR_CODE_OK) { // バッファがあふれるので,一旦古いバッファのクリア // TODO: この仕様は検討してもよいかも?(ユーザー選択にするとか) CDS_clear_stream_rec_buffer_(buffer); CDS_push_to_stream_rec_buffer_(buffer, CDS_hal_rx_buffer_, rec_data_len); p_stream_config->info.rec_status_.count_of_carry_over_failures++; } } static void CDS_analyze_rx_buffer_pickup_(CDS_StreamConfig* p_stream_config) { CDS_StreamRecBuffer* buffer = p_stream_config->settings.rx_buffer_; // 受信バッファのデータを走査し,必要なデータをフレームとして pickup する関数 void (*pickup_func)(CDS_StreamConfig* p_stream_config); if (p_stream_config->settings.rx_frame_size_ == 0) return; if (p_stream_config->settings.rx_frame_size_ > 0) { pickup_func = CDS_analyze_rx_buffer_fixed_pickup_; } else if (p_stream_config->settings.rx_frame_size_ < 0) { // フレームにフレーム長データが含まれているか? if (p_stream_config->settings.rx_framelength_pos_ >= 0) { pickup_func = CDS_analyze_rx_buffer_variable_pickup_with_rx_frame_size_; } else { pickup_func = CDS_analyze_rx_buffer_variable_pickup_with_footer_; } } else { // TODO: ビッグデータ対応 pickup_func = NULL; return; } // 受信バッファからデータをピックアップしていく while (CDS_get_unprocessed_size_from_stream_rec_buffer_(buffer) > 0) { pickup_func(p_stream_config); if (p_stream_config->info.rec_status_.status_code == CDS_STREAM_REC_STATUS_FIXED_FRAME) { break; } // 不整合が起きたら,現在の frame 候補の先頭 + 1 バイト目に走査場所を戻す if (p_stream_config->info.rec_status_.status_code == CDS_STREAM_REC_STATUS_HEADER_MISMATCH || p_stream_config->info.rec_status_.status_code == CDS_STREAM_REC_STATUS_FOOTER_MISMATCH || p_stream_config->info.rec_status_.status_code == CDS_STREAM_REC_STATUS_RX_FRAME_TOO_LONG || p_stream_config->info.rec_status_.status_code == CDS_STREAM_REC_STATUS_RX_FRAME_TOO_SHORT) { CDS_move_forward_frame_head_candidate_of_stream_rec_buffer_(buffer, 1); // 他の部分での条件分岐のために,詳細エラー情報を現在のステータスに上書きする p_stream_config->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_FINDING_HEADER; } } if (p_stream_config->info.rec_status_.status_code == CDS_STREAM_REC_STATUS_FIXED_FRAME) { buffer->is_frame_fixed = 1; p_stream_config->info.rec_status_.fixed_frame_len = buffer->confirmed_frame_len; // FIXME: is_frame_fixed と CDS_STREAM_REC_STATUS_FIXED_FRAME あたいの混在がだるいので直す? // FIXME: confirmed_frame_len と fixed_frame_len も?(これはまあ最後のを残すという意味ではよさそう) } return; } static void CDS_analyze_rx_buffer_cueing_buffer_(CDS_StreamConfig* p_stream_config) { CDS_StreamConfig* p = p_stream_config; // ちょっと変数名が長すぎて配列 index などがみずらいので... CDS_StreamRecBuffer* buffer = p->settings.rx_buffer_; // pos_of_frame_head_candidate の頭出しをしておけば OK CDS_drop_from_stream_rec_buffer_(buffer, buffer->pos_of_frame_head_candidate); } static void CDS_analyze_rx_buffer_fixed_pickup_(CDS_StreamConfig* p_stream_config) { CDS_StreamConfig* p = p_stream_config; // ちょっと変数名が長すぎて配列 index などがみずらいので... CDS_StreamRecBuffer* buffer = p->settings.rx_buffer_; if (buffer->confirmed_frame_len == 0 && p->settings.rx_header_size_ != 0) { // まだヘッダの先頭すら未発見の場合(ヘッダなし時はここはスキップ) CDS_analyze_rx_buffer_finding_header_(p_stream_config); return; } else if (buffer->confirmed_frame_len < p->settings.rx_header_size_) { // ヘッダ受信中 CDS_analyze_rx_buffer_receiving_header_(p_stream_config); return; } else if (buffer->confirmed_frame_len < p->settings.rx_frame_size_ - p->settings.rx_footer_size_) { // データ受信中 // ここは高速化のために一括処理 // ヘッダなしの場合は,ここがフレーム先頭であることに注意 const uint16_t unprocessed_data_len = CDS_get_unprocessed_size_from_stream_rec_buffer_(buffer); uint16_t pickup_data_len = (uint16_t)(p->settings.rx_frame_size_ - p->settings.rx_footer_size_ - buffer->confirmed_frame_len); // 今回で全部受信しきらない場合 if (pickup_data_len > unprocessed_data_len) { pickup_data_len = unprocessed_data_len; } CDS_confirm_stream_rec_buffer_(buffer, pickup_data_len); // pickup_data_len byte 確定 p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_RECEIVING_DATA; // フッタがなく,data 受信仕切った場合はフレーム確定 // これがないと,CDS_analyze_rx_buffer_fixed_ で // 今まさに受信したデータ長がぴったりフレーム末だった場合に,フレーム確定が1周期遅れることになるので if (p->settings.rx_footer_size_ == 0 && buffer->confirmed_frame_len == p->settings.rx_frame_size_) { p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_FIXED_FRAME; } return; } else { // フッタ受信中 or フッタなしの場合はフレーム確定 CDS_analyze_rx_buffer_receiving_footer_(p_stream_config, (uint16_t)(p->settings.rx_frame_size_)); return; } } static void CDS_analyze_rx_buffer_variable_pickup_with_rx_frame_size_(CDS_StreamConfig* p_stream_config) { CDS_StreamConfig* p = p_stream_config; // ちょっと変数名が長すぎて配列 index などがみずらいので... CDS_StreamRecBuffer* buffer = p->settings.rx_buffer_; const uint16_t unprocessed_data_len = CDS_get_unprocessed_size_from_stream_rec_buffer_(buffer); uint32_t rx_frame_size = CDS_analyze_rx_buffer_get_framelength_(p_stream_config); // まだ受信していない場合は不定値が入ることに留意すること!! if (buffer->confirmed_frame_len == 0 && p->settings.rx_header_size_ != 0) { // まだヘッダの先頭すら未発見の場合(ヘッダなし時はここはスキップ) CDS_analyze_rx_buffer_finding_header_(p_stream_config); return; } else if (buffer->confirmed_frame_len < p->settings.rx_header_size_) { // ヘッダ受信中 CDS_analyze_rx_buffer_receiving_header_(p_stream_config); return; } else if (buffer->confirmed_frame_len < p->settings.rx_framelength_pos_ + p->settings.rx_framelength_type_size_) { // フレームサイズ探索中 // ここは高速化のために一括処理 // ヘッダなしの場合は,ここがフレーム先頭であることに注意 uint16_t pickup_data_len = (uint16_t)(p->settings.rx_framelength_pos_ + p->settings.rx_framelength_type_size_ - buffer->confirmed_frame_len); // 今回で全部受信しきらない場合 if (pickup_data_len > unprocessed_data_len) { pickup_data_len = unprocessed_data_len; } CDS_confirm_stream_rec_buffer_(buffer, pickup_data_len); // pickup_data_len byte 確定 p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_RECEIVING_FRAMELENGTH; // フレーム長を受信し終わった場合,チェックする if (buffer->confirmed_frame_len >= p->settings.rx_framelength_pos_ + p->settings.rx_framelength_type_size_) { rx_frame_size = CDS_analyze_rx_buffer_get_framelength_(p_stream_config); // バッファー超え or 上限値超えはエラーを出す! if (rx_frame_size > buffer->capacity || rx_frame_size > p->settings.max_rx_frame_size_) { p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_RX_FRAME_TOO_LONG; #ifdef CDS_DEBUG Printf("DS: RX frame size is too long\n"); #endif return; } // body サイズがは 0 以上を要請 if (rx_frame_size < p->settings.rx_header_size_ + p->settings.rx_footer_size_) { p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_RX_FRAME_TOO_SHORT; #ifdef CDS_DEBUG Printf("DS: RX frame size is too short\n"); #endif return; } } return; } else if (buffer->confirmed_frame_len < rx_frame_size - p->settings.rx_footer_size_) { // データ受信中 // ここは高速化のために一括処理 // TODO: 現在,フレーム長が uint16_t を超えることは想定していない! uint16_t pickup_data_len = (uint16_t)(rx_frame_size - p->settings.rx_footer_size_ - buffer->confirmed_frame_len); // 今回で全部受信しきらない場合 if (pickup_data_len > unprocessed_data_len) { pickup_data_len = unprocessed_data_len; } CDS_confirm_stream_rec_buffer_(buffer, pickup_data_len); // pickup_data_len byte 確定 p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_RECEIVING_DATA; // フッタがなく,data 受信仕切った場合はフレーム確定 // これがないと,CDS_analyze_rx_buffer_fixed_ で // 今まさに受信したデータ長がぴったりフレーム末だった場合に,フレーム確定が 1 周期遅れることになるので if (p->settings.rx_footer_size_ == 0 && buffer->confirmed_frame_len == rx_frame_size) { p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_FIXED_FRAME; } return; } else { // フッタ受信中 or フッタなしの場合はフレーム確定 CDS_analyze_rx_buffer_receiving_footer_(p_stream_config, (uint16_t)rx_frame_size); return; } } static void CDS_analyze_rx_buffer_variable_pickup_with_footer_(CDS_StreamConfig* p_stream_config) { CDS_StreamConfig* p = p_stream_config; // ちょっと変数名が長すぎて配列 index などがみずらいので... CDS_StreamRecBuffer* buffer = p->settings.rx_buffer_; if (buffer->confirmed_frame_len == 0 && p->settings.rx_header_size_ != 0) { // まだヘッダの先頭すら未発見の場合(ヘッダなし時はここはスキップ) CDS_analyze_rx_buffer_finding_header_(p_stream_config); return; } else if (buffer->confirmed_frame_len < p->settings.rx_header_size_) { // ヘッダ受信中 CDS_analyze_rx_buffer_receiving_header_(p_stream_config); return; } else { // 最後まで受信し,フッタの最終文字を探す.フッタなしはありえない. // ヘッダなしの場合は,ここがフレーム先頭 const uint16_t unprocessed_data_len = CDS_get_unprocessed_size_from_stream_rec_buffer_(buffer); uint8_t* p_footer_last; // inclusive int32_t body_data_len; // サイズ的には u16 でよいが,負数もとりたいので i32 としている uint16_t processed_data_len; uint16_t i; const uint16_t memchr_offset = buffer->pos_of_frame_head_candidate + buffer->confirmed_frame_len; uint16_t estimated_rx_frame_end_pos; // 届いているデータを受信フレームバッファに格納する // ここは高速化のために一括処理 // フッタ最終文字を探す p_footer_last = (uint8_t*)memchr(&(buffer->buffer[memchr_offset]), (int)(p->settings.rx_footer_[p->settings.rx_footer_size_ - 1]), (size_t)unprocessed_data_len); if (p_footer_last == NULL) { // まだフッタ候補まで受信していない → 受信データはすべて今回のフレームとして確定 processed_data_len = unprocessed_data_len; } else { // フッタ候補発見 → フッタ候補までフレーム確定 processed_data_len = (uint16_t)(p_footer_last - &(buffer->buffer[memchr_offset]) + 1); } // ↓ buffer->confirmed_frame_len が更新されることに注意! CDS_confirm_stream_rec_buffer_(buffer, processed_data_len); // processed_data_len byte 確定 if (buffer->confirmed_frame_len > p->settings.max_rx_frame_size_) { p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_RX_FRAME_TOO_LONG; #ifdef CDS_DEBUG Printf("DS: RX frame size is too long\n"); #endif return; } // フッタ候補未発見の場合はここで処理を返す if (p_footer_last == NULL) { p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_RECEIVING_DATA; return; } body_data_len = buffer->confirmed_frame_len - p->settings.rx_header_size_ - p->settings.rx_footer_size_; if (body_data_len < 0) { // これはフッタではないので受信続行 // まだまだ受信する p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_RECEIVING_DATA; return; } // フッタ候補発見 // フッタチェックする estimated_rx_frame_end_pos = buffer->pos_of_frame_head_candidate + buffer->confirmed_frame_len; for (i = 0; i < p->settings.rx_footer_size_; i++) { if (buffer->buffer[estimated_rx_frame_end_pos - i - 1] != p->settings.rx_footer_[p->settings.rx_footer_size_ - i - 1]) { // これはフッタではないので受信続行 // まだまだ受信する p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_RECEIVING_DATA; return; } } // フッタ確定 → フレーム確定 p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_FIXED_FRAME; return; } } static void CDS_analyze_rx_buffer_finding_header_(CDS_StreamConfig* p_stream_config) { CDS_StreamConfig* p = p_stream_config; // ちょっと変数名が長すぎて配列 index などがみずらいので... CDS_StreamRecBuffer* buffer = p->settings.rx_buffer_; const uint16_t unprocessed_data_len = CDS_get_unprocessed_size_from_stream_rec_buffer_(buffer); uint8_t* p_header; uint16_t found_header_offset; // コードが正しければ,ヘッダがないケースはここに到達し得ないが,ヌルポ回避をいれておく if (p_stream_config->settings.rx_header_ == NULL) { #ifdef CDS_DEBUG Printf("DS: RX header is invalid\n"); #endif p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_OTHER_ERR; CDS_move_forward_frame_head_candidate_of_stream_rec_buffer_(buffer, unprocessed_data_len); return; } // まだヘッダの先頭すら未発見の場合 // ここは高速化のために一括処理 p_header = (uint8_t*)memchr(&buffer->buffer[buffer->pos_of_frame_head_candidate], (int)(p->settings.rx_header_[0]), (size_t)unprocessed_data_len); if (p_header == NULL) { #ifdef CDS_DEBUG Printf("DS: RX header not found\n"); #endif p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_FINDING_HEADER; CDS_move_forward_frame_head_candidate_of_stream_rec_buffer_(buffer, unprocessed_data_len); return; } found_header_offset = (uint16_t)(p_header - &buffer->buffer[buffer->pos_of_frame_head_candidate]); CDS_move_forward_frame_head_candidate_of_stream_rec_buffer_(buffer, found_header_offset); CDS_confirm_stream_rec_buffer_(buffer, 1); // ヘッダ 1 byte 目が見つかった p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_RECEIVING_HEADER; return; } static void CDS_analyze_rx_buffer_receiving_header_(CDS_StreamConfig* p_stream_config) { CDS_StreamConfig* p = p_stream_config; // ちょっと変数名が長すぎて配列 index などがみずらいので... CDS_StreamRecBuffer* buffer = p->settings.rx_buffer_; const uint16_t buffer_offset = buffer->pos_of_frame_head_candidate + buffer->confirmed_frame_len; // ヘッダ受信中 // 受信が細切れのときなどの処理分岐がめんどくさいので, 1 byte ずつ処理させる // ヘッダが正しいか? if (buffer->buffer[buffer_offset] == p->settings.rx_header_[buffer->confirmed_frame_len]) { CDS_confirm_stream_rec_buffer_(buffer, 1); // ヘッダの次の 1 byte がみつかった p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_RECEIVING_HEADER; return; } else { // ヘッダが正しくなかった // CDS_STREAM_REC_STATUS_HEADER_MISMATCH になり,再びバッファを巻き戻してヘッダ探索を始める // その後 CDS_STREAM_REC_STATUS_FINDING_HEADER に戻る p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_HEADER_MISMATCH; #ifdef CDS_DEBUG Printf("DS: RX header is mismatch\n"); #endif return; } } static void CDS_analyze_rx_buffer_receiving_footer_(CDS_StreamConfig* p_stream_config, uint16_t rx_frame_size) { CDS_StreamConfig* p = p_stream_config; // ちょっと変数名が長すぎて配列 index などがみずらいので... CDS_StreamRecBuffer* buffer = p->settings.rx_buffer_; const uint16_t buffer_offset = buffer->pos_of_frame_head_candidate + buffer->confirmed_frame_len; uint16_t rec_footer_pos; // フッタなしの場合はフレーム確定 if (p->settings.rx_footer_size_ == 0) { // フッタなし p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_FIXED_FRAME; return; } // フッタ受信 // ここも条件分岐がめんどくさいので,1 byte ずつ処理する rec_footer_pos = (uint16_t)(buffer->confirmed_frame_len - (rx_frame_size - p->settings.rx_footer_size_)); // 期待されているフッタが受信できたか? // 受信できなかった場合, CDS_STREAM_REC_STATUS_FOOTER_MISMATCH になり,再びバッファを巻き戻してヘッダ探索を始める // その後 CDS_STREAM_REC_STATUS_FINDING_HEADER に戻る if (buffer->buffer[buffer_offset] != p->settings.rx_footer_[rec_footer_pos]) { p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_FOOTER_MISMATCH; #ifdef CDS_DEBUG Printf("DS: RX footer is mismatch\n"); #endif return; } // ここまできたら正しいフッタが受信されている CDS_confirm_stream_rec_buffer_(buffer, 1); // ヘッダの次の 1 byte がみつかった if (buffer->confirmed_frame_len == rx_frame_size) { // フレーム確定 p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_FIXED_FRAME; } else { // フレーム確定せず p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_RECEIVING_FOOTER; } return; } static uint32_t CDS_analyze_rx_buffer_get_framelength_(CDS_StreamConfig* p_stream_config) { CDS_StreamConfig* p = p_stream_config; // ちょっと変数名が長すぎて配列 index などがみずらいので... uint32_t len = 0; uint8_t i; const uint16_t pos = p->settings.rx_framelength_pos_ + p->settings.rx_buffer_->pos_of_frame_head_candidate; const uint16_t size = p->settings.rx_framelength_type_size_; if (p->settings.rx_framelength_endian_ == ENDIAN_TYPE_BIG) { for (i = 0; i < size; ++i) { if (i == 0) { len = p->settings.rx_buffer_->buffer[pos]; } else { len <<= 8; len |= p->settings.rx_buffer_->buffer[pos + i]; } } } else { for (i = 0; i < size; ++i) { if (i == 0) { len = p->settings.rx_buffer_->buffer[pos + size - 1]; } else { len <<= 8; len |= p->settings.rx_buffer_->buffer[pos + size - 1 - i]; } } } len += p->settings.rx_framelength_offset_; return len; } static CDS_ERR_CODE CDS_reset_stream_config_(CDS_StreamConfig* p_stream_config) { CDS_StreamConfig* p = p_stream_config; p->settings.is_enabled_ = 0; p->settings.is_strict_frame_search_ = 0; p->settings.tx_frame_ = NULL; p->settings.tx_frame_size_ = 0; p->settings.tx_frame_buffer_size_ = -1; p->settings.rx_buffer_ = NULL; p->settings.rx_header_ = NULL; p->settings.rx_header_size_ = 0; p->settings.rx_footer_ = NULL; p->settings.rx_footer_size_ = 0; p->settings.rx_frame_size_ = 0; p->settings.max_rx_frame_size_ = 0xffff; p->settings.rx_framelength_pos_ = -1; p->settings.rx_framelength_type_size_ = 0; p->settings.rx_framelength_offset_ = 0; p->settings.rx_framelength_endian_ = ENDIAN_TYPE_BIG; p->settings.should_monitor_for_tlm_disruption_ = 0; p->settings.time_threshold_for_tlm_disruption_ = 60 * 1000; // この値はよく考えること p->settings.data_analyzer_ = CDS_data_analyzer_dummy_; // CDS_StreamSendStatus の初期化 p->info.send_status_.status_code = CDS_STREAM_SEND_STATUS_DISABLE; p->info.send_status_.ret_from_hal_tx = 0; // CDS_StreamRecStatus の初期化 p->info.rec_status_.status_code = CDS_STREAM_REC_STATUS_DISABLE; p->info.rec_status_.fixed_frame_len = 0; p->info.rec_status_.tlm_disruption_status = CDS_STREAM_TLM_DISRUPTION_STATUS_OK; p->info.rec_status_.count_of_carry_over_failures = 0; p->info.general_cmd_tx_count_ = 0; p->info.req_tlm_cmd_tx_count_ = 0; p->info.req_tlm_cmd_tx_count_after_last_tx_ = 0; p->info.rx_frame_fix_count_ = 0; p->info.general_cmd_tx_time_ = TMGR_get_master_clock(); p->info.req_tlm_cmd_tx_time_ = TMGR_get_master_clock(); p->info.rx_frame_fix_time_ = TMGR_get_master_clock(); p->info.ret_from_data_analyzer_ = CDS_ERR_CODE_OK; p->internal.is_validation_needed_for_send_ = 0; p->internal.is_validation_needed_for_rec_ = 0; return CDS_ERR_CODE_OK; } static CDS_ERR_CODE CDS_validate_stream_config_(const ComponentDriverSuper* p_super, CDS_StreamConfig* p_stream_config) { CDS_StreamConfig* p = p_stream_config; if (!p->settings.is_enabled_) return CDS_ERR_CODE_OK; if (p->settings.tx_frame_size_ != 0 && p->settings.tx_frame_ == NULL) return CDS_ERR_CODE_ERR; if (p->settings.rx_header_size_ != 0 && p->settings.rx_header_ == NULL) return CDS_ERR_CODE_ERR; if (p->settings.rx_footer_size_ != 0 && p->settings.rx_footer_ == NULL) return CDS_ERR_CODE_ERR; if (p->settings.tx_frame_buffer_size_ >= 0) { if (p->settings.tx_frame_size_ > p->settings.tx_frame_buffer_size_) return CDS_ERR_CODE_ERR; } if (p->settings.rx_frame_size_ < 0) { // テレメトリ可変長 if (p->settings.rx_framelength_pos_ < 0) { // フレームサイズデータがない場合 // フッタの存在が必須 if (p->settings.rx_footer_size_ == 0) return CDS_ERR_CODE_ERR; } else { if (p->settings.rx_header_size_ == 0) return CDS_ERR_CODE_ERR; // 可変長かつヘッダなしは対応しない(固定長のようにして回避する.詳細はヘッダファイル参照) if (p->settings.rx_framelength_pos_ < p->settings.rx_header_size_) return CDS_ERR_CODE_ERR; // フレームサイズがヘッダ(つまり固定値)に含まれることはありえないので if (!(p->settings.rx_framelength_type_size_ == 1 || p->settings.rx_framelength_type_size_ == 2 || p->settings.rx_framelength_type_size_ == 3 || p->settings.rx_framelength_type_size_ == 4 )) return CDS_ERR_CODE_ERR; // 現在は uint8 to uint32 のみ対応 if (!(p->settings.rx_framelength_endian_ == ENDIAN_TYPE_BIG || p->settings.rx_framelength_endian_ == ENDIAN_TYPE_LITTLE )) return CDS_ERR_CODE_ERR; } } else if (p->settings.rx_frame_size_ == 0) { // テレメなし } else { // テレメトリ固定長 if ( p->settings.rx_frame_size_ < (p->settings.rx_header_size_ + p->settings.rx_footer_size_) ) { return CDS_ERR_CODE_ERR; } } if (p->settings.is_strict_frame_search_) { // ヘッダがあることが前提 if (p->settings.rx_header_size_ == 0) return CDS_ERR_CODE_ERR; } if (p->settings.rx_buffer_ == NULL) return CDS_ERR_CODE_ERR; if (p->settings.rx_buffer_->buffer == NULL) return CDS_ERR_CODE_ERR; if (p->settings.rx_buffer_->capacity < p_super->config.settings.hal_rx_buffer_size_) return CDS_ERR_CODE_ERR; if (p->settings.rx_buffer_->capacity < p->settings.rx_frame_size_) return CDS_ERR_CODE_ERR; if (p->settings.rx_buffer_->capacity < p->settings.rx_header_size_ + p->settings.rx_footer_size_) return CDS_ERR_CODE_ERR; p->internal.is_validation_needed_for_send_ = 0; p->internal.is_validation_needed_for_rec_ = 0; return CDS_ERR_CODE_OK; } static CDS_ERR_CODE CDS_load_init_setting_dummy_(ComponentDriverSuper* p_super) { (void)p_super; return CDS_ERR_CODE_OK; } static CDS_ERR_CODE CDS_data_analyzer_dummy_(CDS_StreamConfig* p_stream_config, void* p_driver) { (void)p_stream_config; (void)p_driver; return CDS_ERR_CODE_OK; } // ###### CDS_Config Getter/Setter of Settings ###### uint16_t CDSC_get_hal_rx_buffer_size(const ComponentDriverSuper* p_super) { return (uint16_t)p_super->config.settings.hal_rx_buffer_size_; } CDS_ERR_CODE CDSC_set_hal_rx_buffer_size(ComponentDriverSuper* p_super, const uint16_t hal_rx_buffer_size) { if (hal_rx_buffer_size > CDS_HAL_RX_BUFFER_SIZE) return CDS_ERR_CODE_ERR; p_super->config.settings.hal_rx_buffer_size_ = hal_rx_buffer_size; return CDS_ERR_CODE_OK; } uint8_t CDSC_get_should_monitor_for_rx_disruption(const ComponentDriverSuper* p_super) { return (uint8_t)p_super->config.settings.should_monitor_for_rx_disruption_; } void CDSC_enable_monitor_for_rx_disruption(ComponentDriverSuper* p_super) { p_super->config.settings.should_monitor_for_rx_disruption_ = 1; } void CDSC_disable_monitor_for_rx_disruption(ComponentDriverSuper* p_super) { p_super->config.settings.should_monitor_for_rx_disruption_ = 0; } uint32_t CDSC_get_time_threshold_for_rx_disruption(const ComponentDriverSuper* p_super) { return (uint32_t)p_super->config.settings.time_threshold_for_rx_disruption_; } void CDSC_set_time_threshold_for_rx_disruption(ComponentDriverSuper* p_super, const uint32_t time_threshold_for_rx_disruption) { p_super->config.settings.time_threshold_for_rx_disruption_ = time_threshold_for_rx_disruption; } // ###### CDS_Config Getter/Setter of Info ###### // FIXME: HEW で Warning が出てしまう(gcc ではでない)ので,キャストしている関数がいくつかある const CDS_RecStatus* CDSC_get_rec_status(const ComponentDriverSuper* p_super) { return &p_super->config.info.rec_status_; } uint32_t CDSC_get_rx_count(const ComponentDriverSuper* p_super) { return (uint32_t)p_super->config.info.rx_count_; } uint32_t CDSC_get_rx_call_count(const ComponentDriverSuper* p_super) { return (uint32_t)p_super->config.info.rx_call_count_; } const ObcTime* CDSC_get_rx_time(const ComponentDriverSuper* p_super) { return &p_super->config.info.rx_time_; } CDS_RX_DISRUPTION_STATUS_CODE CDSC_get_rx_disruption_status(const ComponentDriverSuper* p_super) { return (CDS_RX_DISRUPTION_STATUS_CODE)p_super->config.info.rec_status_.rx_disruption_status; } // ###### CDS_StreamConfig Getter/Setter of Settings ###### // FIXME: HEW で Warning が出てしまう(gcc ではでない)ので,キャストしている関数がいくつかある uint8_t CDSSC_get_is_enabled(const CDS_StreamConfig* p_stream_config) { return (uint8_t)p_stream_config->settings.is_enabled_; } void CDSSC_enable(CDS_StreamConfig* p_stream_config) { p_stream_config->settings.is_enabled_ = 1; p_stream_config->internal.is_validation_needed_for_send_ = 1; p_stream_config->internal.is_validation_needed_for_rec_ = 1; } void CDSSC_disable(CDS_StreamConfig* p_stream_config) { p_stream_config->settings.is_enabled_ = 0; } uint8_t CDSSC_get_is_strict_frame_search(const CDS_StreamConfig* p_stream_config) { return (uint8_t)p_stream_config->settings.is_strict_frame_search_; } void CDSSC_enable_strict_frame_search(CDS_StreamConfig* p_stream_config) { p_stream_config->settings.is_strict_frame_search_ = 1; p_stream_config->internal.is_validation_needed_for_rec_ = 1; } void CDSSC_disable_strict_frame_search(CDS_StreamConfig* p_stream_config) { p_stream_config->settings.is_strict_frame_search_ = 0; } const uint8_t* CDSSC_get_tx_frame(CDS_StreamConfig* p_stream_config) { return p_stream_config->settings.tx_frame_; } uint8_t* CDSSC_get_tx_frame_as_non_const_pointer(CDS_StreamConfig* p_stream_config) { return p_stream_config->settings.tx_frame_; } void CDSSC_set_tx_frame(CDS_StreamConfig* p_stream_config, uint8_t* tx_frame) { p_stream_config->settings.tx_frame_ = tx_frame; p_stream_config->internal.is_validation_needed_for_send_ = 1; } uint16_t CDSSC_get_tx_frame_size(const CDS_StreamConfig* p_stream_config) { return (uint16_t)p_stream_config->settings.tx_frame_size_; } void CDSSC_set_tx_frame_size(CDS_StreamConfig* p_stream_config, const uint16_t tx_frame_size) { p_stream_config->settings.tx_frame_size_ = tx_frame_size; p_stream_config->internal.is_validation_needed_for_send_ = 1; } int16_t CDSSC_get_tx_frame_buffer_size(CDS_StreamConfig* p_stream_config) { return (int16_t)p_stream_config->settings.tx_frame_buffer_size_; } void CDSSC_set_tx_frame_buffer_size(CDS_StreamConfig* p_stream_config, const int16_t tx_frame_buffer_size) { p_stream_config->settings.tx_frame_buffer_size_ = tx_frame_buffer_size; p_stream_config->internal.is_validation_needed_for_send_ = 1; } void CDSSC_set_rx_buffer(CDS_StreamConfig* p_stream_config, CDS_StreamRecBuffer* rx_buffer) { p_stream_config->settings.rx_buffer_ = rx_buffer; p_stream_config->internal.is_validation_needed_for_rec_ = 1; } void CDSSC_set_rx_header(CDS_StreamConfig* p_stream_config, const uint8_t* rx_header, const uint16_t rx_header_size) { p_stream_config->settings.rx_header_ = rx_header; p_stream_config->settings.rx_header_size_ = rx_header_size; p_stream_config->internal.is_validation_needed_for_rec_ = 1; } uint16_t CDSSC_get_rx_header_size(const CDS_StreamConfig* p_stream_config) { return (uint16_t)p_stream_config->settings.rx_header_size_; } void CDSSC_set_rx_footer(CDS_StreamConfig* p_stream_config, const uint8_t* rx_footer, const uint16_t rx_footer_size) { p_stream_config->settings.rx_footer_ = rx_footer; p_stream_config->settings.rx_footer_size_ = rx_footer_size; p_stream_config->internal.is_validation_needed_for_rec_ = 1; } uint16_t CDSSC_get_rx_footer_size(const CDS_StreamConfig* p_stream_config) { return (uint16_t)p_stream_config->settings.rx_footer_size_; } int16_t CDSSC_get_rx_frame_size(const CDS_StreamConfig* p_stream_config) { return (int16_t)p_stream_config->settings.rx_frame_size_; } void CDSSC_set_rx_frame_size(CDS_StreamConfig* p_stream_config, const int16_t rx_frame_size) { p_stream_config->settings.rx_frame_size_ = rx_frame_size; p_stream_config->internal.is_validation_needed_for_rec_ = 1; } uint16_t CDSSC_get_max_rx_frame_size(const CDS_StreamConfig* p_stream_config) { return (uint16_t)p_stream_config->settings.max_rx_frame_size_; } void CDSSC_set_max_rx_frame_size(CDS_StreamConfig* p_stream_config, const uint16_t max_rx_frame_size) { p_stream_config->settings.max_rx_frame_size_ = max_rx_frame_size; p_stream_config->internal.is_validation_needed_for_rec_ = 1; } void CDSSC_set_rx_framelength_pos(CDS_StreamConfig* p_stream_config, const int16_t rx_framelength_pos) { p_stream_config->settings.rx_framelength_pos_ = rx_framelength_pos; p_stream_config->internal.is_validation_needed_for_rec_ = 1; } void CDSSC_set_rx_framelength_type_size(CDS_StreamConfig* p_stream_config, const uint16_t rx_framelength_type_size) { p_stream_config->settings.rx_framelength_type_size_ = rx_framelength_type_size; p_stream_config->internal.is_validation_needed_for_rec_ = 1; } void CDSSC_set_rx_framelength_offset(CDS_StreamConfig* p_stream_config, const uint16_t rx_framelength_offset) { p_stream_config->settings.rx_framelength_offset_ = rx_framelength_offset; p_stream_config->internal.is_validation_needed_for_rec_ = 1; } void CDSSC_set_rx_framelength_endian(CDS_StreamConfig* p_stream_config, const ENDIAN_TYPE rx_framelength_endian) { p_stream_config->settings.rx_framelength_endian_ = rx_framelength_endian; p_stream_config->internal.is_validation_needed_for_rec_ = 1; } uint8_t CDSSC_get_should_monitor_for_tlm_disruption(const CDS_StreamConfig* p_stream_config) { return (uint8_t)p_stream_config->settings.should_monitor_for_tlm_disruption_; } void CDSSC_enable_monitor_for_tlm_disruption(CDS_StreamConfig* p_stream_config) { p_stream_config->settings.should_monitor_for_tlm_disruption_ = 1; p_stream_config->internal.is_validation_needed_for_rec_ = 1; } void CDSSC_disable_monitor_for_tlm_disruption(CDS_StreamConfig* p_stream_config) { p_stream_config->settings.should_monitor_for_tlm_disruption_ = 0; p_stream_config->internal.is_validation_needed_for_rec_ = 1; } uint32_t CDSSC_get_time_threshold_for_tlm_disruption(const CDS_StreamConfig* p_stream_config) { return (uint32_t)p_stream_config->settings.time_threshold_for_tlm_disruption_; } void CDSSC_set_time_threshold_for_tlm_disruption(CDS_StreamConfig* p_stream_config, const uint32_t time_threshold_for_tlm_disruption) { p_stream_config->settings.time_threshold_for_tlm_disruption_ = time_threshold_for_tlm_disruption; p_stream_config->internal.is_validation_needed_for_rec_ = 1; } void CDSSC_set_data_analyzer(CDS_StreamConfig* p_stream_config, CDS_ERR_CODE (*data_analyzer)(CDS_StreamConfig* p_stream_config, void* p_driver)) { p_stream_config->settings.data_analyzer_ = data_analyzer; p_stream_config->internal.is_validation_needed_for_rec_ = 1; } // ###### CDS_StreamConfig Getter/Setter of Info ###### const CDS_StreamSendStatus* CDSSC_get_send_status(const CDS_StreamConfig* p_stream_config) { return &p_stream_config->info.send_status_; } const CDS_StreamRecStatus* CDSSC_get_rec_status(const CDS_StreamConfig* p_stream_config) { return &p_stream_config->info.rec_status_; } uint32_t CDSSC_get_general_cmd_tx_count(const CDS_StreamConfig* p_stream_config) { return (uint32_t)p_stream_config->info.general_cmd_tx_count_; } uint32_t CDSSC_get_req_tlm_cmd_tx_count(const CDS_StreamConfig* p_stream_config) { return (uint32_t)p_stream_config->info.req_tlm_cmd_tx_count_; } uint32_t CDSSC_get_req_tlm_cmd_tx_count_after_last_tx(const CDS_StreamConfig* p_stream_config) { return (uint32_t)p_stream_config->info.req_tlm_cmd_tx_count_after_last_tx_; } uint32_t CDSSC_get_rx_frame_fix_count(const CDS_StreamConfig* p_stream_config) { return (uint32_t)p_stream_config->info.rx_frame_fix_count_; } const ObcTime* CDSSC_get_general_cmd_tx_time(const CDS_StreamConfig* p_stream_config) { return &p_stream_config->info.general_cmd_tx_time_; } const ObcTime* CDSSC_get_req_tlm_cmd_tx_time(const CDS_StreamConfig* p_stream_config) { return &p_stream_config->info.req_tlm_cmd_tx_time_; } const ObcTime* CDSSC_get_rx_frame_fix_time(const CDS_StreamConfig* p_stream_config) { return &p_stream_config->info.rx_frame_fix_time_; } CDS_STREAM_TLM_DISRUPTION_STATUS_CODE CDSSC_get_tlm_disruption_status(const CDS_StreamConfig* p_stream_config) { return (CDS_STREAM_TLM_DISRUPTION_STATUS_CODE)p_stream_config->info.rec_status_.tlm_disruption_status; } CDS_ERR_CODE CDSSC_get_ret_from_data_analyzer(const CDS_StreamConfig* p_stream_config) { return (CDS_ERR_CODE)p_stream_config->info.ret_from_data_analyzer_; } // ###### ComponentDriverSuper 汎用 Util 関数 ###### CDS_ERR_CODE CDS_init_stream_rec_buffer(CDS_StreamRecBuffer* stream_rec_buffer, uint8_t* buffer, const uint16_t buffer_capacity) { if (stream_rec_buffer == NULL) return CDS_ERR_CODE_ERR; if (buffer == NULL) return CDS_ERR_CODE_ERR; stream_rec_buffer->buffer = buffer; stream_rec_buffer->capacity = buffer_capacity; CDS_clear_stream_rec_buffer_(stream_rec_buffer); return CDS_ERR_CODE_OK; } void CDS_nullify_stream_rec_buffers(CDS_StreamRecBuffer* rx_buffers[CDS_STREAM_MAX]) { uint8_t stream; if (rx_buffers == NULL) return; for (stream = 0; stream < CDS_STREAM_MAX; ++stream) { rx_buffers[stream] = NULL; } } CCP_CmdRet CDS_conv_driver_err_to_ccp_cmd_ret(CDS_DRIVER_ERR_CODE code) { switch (code) { case CDS_DRIVER_ERR_CODE_ILLEGAL_CONTEXT: case CDS_DRIVER_ERR_CODE_UNKNOWN_ERR: // 全てこれでいいのかは,要検討 return CCP_make_cmd_ret(CCP_EXEC_ILLEGAL_CONTEXT, (uint32_t)code); case CDS_DRIVER_ERR_CODE_ILLEGAL_PARAMETER: return CCP_make_cmd_ret(CCP_EXEC_ILLEGAL_PARAMETER, (uint32_t)code); case CDS_DRIVER_ERR_CODE_ILLEGAL_LENGTH: return CCP_make_cmd_ret(CCP_EXEC_ILLEGAL_LENGTH, (uint32_t)code); default: // ここに来るのは以下 // CDS_DRIVER_ERR_CODE_OK return CCP_make_cmd_ret(CCP_EXEC_SUCCESS, (uint32_t)code); } } CCP_CmdRet CDS_conv_cmd_err_to_ccp_cmd_ret(CDS_CMD_ERR_CODE code) { switch (code) { case CDS_CMD_ILLEGAL_CONTEXT: return CCP_make_cmd_ret(CCP_EXEC_ILLEGAL_CONTEXT, (uint32_t)code); case CDS_CMD_ILLEGAL_PARAMETER: return CCP_make_cmd_ret(CCP_EXEC_ILLEGAL_PARAMETER, (uint32_t)code); case CDS_CMD_ILLEGAL_LENGTH: return CCP_make_cmd_ret(CCP_EXEC_ILLEGAL_LENGTH, (uint32_t)code); default: // ここに来るのは以下の 3 つ // CDS_CMD_OK // CDS_CMD_DRIVER_SUPER_ERR // CDS_CMD_UNKNOWN_ERR // 下 2 つのエラーは ComponentDriver 側の問題で,そちらでエラー情報を持つべき // ここでは SUCCESS を返す return CCP_make_cmd_ret(CCP_EXEC_SUCCESS, (uint32_t)code); } } // ###### ComponentDriverSuper Stream Config 汎用 Util 関数 ###### const uint8_t* CDSSC_get_rx_frame(const CDS_StreamConfig* p_stream_config) { CDS_StreamRecBuffer* buffer = p_stream_config->settings.rx_buffer_; return &(buffer->buffer[buffer->pos_of_frame_head_candidate]); } uint16_t CDSSC_get_fixed_rx_frame_size(const CDS_StreamConfig* p_stream_config) { CDS_StreamRecBuffer* buffer = p_stream_config->settings.rx_buffer_; if (buffer->is_frame_fixed) { return buffer->confirmed_frame_len; } else { return 0; } } // ###### CDS_StreamRecBuffer 関連 static 関数 ###### void CDS_clear_stream_rec_buffer_(CDS_StreamRecBuffer* stream_rec_buffer) { if (stream_rec_buffer == NULL) return; if (stream_rec_buffer->buffer == NULL) return; memset(stream_rec_buffer->buffer, 0x00, stream_rec_buffer->capacity); stream_rec_buffer->size = 0; stream_rec_buffer->pos_of_frame_head_candidate = 0; stream_rec_buffer->confirmed_frame_len = 0; stream_rec_buffer->is_frame_fixed = 0; stream_rec_buffer->pos_of_last_rec = 0; } void CDS_drop_from_stream_rec_buffer_(CDS_StreamRecBuffer* stream_rec_buffer, uint16_t size) { int32_t move_size = stream_rec_buffer->size - size; if (size == 0) return; if (move_size > 0) { memmove(&stream_rec_buffer->buffer[0], &stream_rec_buffer->buffer[size], move_size); } // データ整合 if (stream_rec_buffer->pos_of_frame_head_candidate < size) { stream_rec_buffer->confirmed_frame_len = 0; } if (stream_rec_buffer->size > size) { stream_rec_buffer->size -= size; } else { stream_rec_buffer->size = 0; } if (stream_rec_buffer->pos_of_frame_head_candidate >= size) { stream_rec_buffer->pos_of_frame_head_candidate -= size; } else { stream_rec_buffer->pos_of_frame_head_candidate = 0; stream_rec_buffer->is_frame_fixed = 0; } if (stream_rec_buffer->pos_of_last_rec > size) { stream_rec_buffer->pos_of_last_rec -= size; } else { stream_rec_buffer->pos_of_last_rec = 0; } } CDS_ERR_CODE CDS_push_to_stream_rec_buffer_(CDS_StreamRecBuffer* stream_rec_buffer, const uint8_t* buffer, uint16_t size) { uint16_t rest_size = stream_rec_buffer->capacity - stream_rec_buffer->size; if (rest_size < size) return CDS_ERR_CODE_ERR; memcpy(&stream_rec_buffer->buffer[stream_rec_buffer->size], buffer, size); stream_rec_buffer->size += size; return CDS_ERR_CODE_OK; } uint16_t CDS_get_unprocessed_size_from_stream_rec_buffer_(CDS_StreamRecBuffer* stream_rec_buffer) { int32_t len = stream_rec_buffer->size - stream_rec_buffer->pos_of_frame_head_candidate - stream_rec_buffer->confirmed_frame_len; if (len < 0) return 0; // まああり得ないが return (uint16_t)len; } void CDS_confirm_stream_rec_buffer_(CDS_StreamRecBuffer* stream_rec_buffer, uint16_t size) { stream_rec_buffer->confirmed_frame_len += size; if (stream_rec_buffer->confirmed_frame_len > stream_rec_buffer->size) { stream_rec_buffer->confirmed_frame_len = stream_rec_buffer->size; } } void CDS_move_forward_frame_head_candidate_of_stream_rec_buffer_(CDS_StreamRecBuffer* stream_rec_buffer, uint16_t size) { stream_rec_buffer->pos_of_frame_head_candidate += size; if (stream_rec_buffer->pos_of_frame_head_candidate > stream_rec_buffer->size) { stream_rec_buffer->pos_of_frame_head_candidate = stream_rec_buffer->size; } // head が動くということは,フレーム探索中ということ stream_rec_buffer->confirmed_frame_len = 0; } #pragma section