Day After Day
tsurezure naru mamani...
ANOTHER DECADE

from 2022 when it's begining after/with CORONA Virus.

C# TLMForwarder のバースト対応

12月
22
2024
Back
Alt+HOME


Burst Data をそのまま転送処理すると連続データが1パケットとして処理され正しいテレメトリーとならないためバッチ処理ですべて受信後に分解転送する仕様に変更してみた。




図中上半分が、幾つかのフレームが連なった、バーストデータである。1ファイル分読み込みと分割が終了すると・・・・





それぞれのフレームを通常転送するFORWARD PROCESSルーティンで個別に SatNOGS へ送信する。

Span<T>, Memory<T> (.NET 6.0以降) を使用してバイナリーを分割


    // バースト受信が有効になっている時
    if (ChkBurst.Checked == true) 
    {
    	// BurstとForwardingのラジオボタンが両方とも有効な場合
    	if (ChkForwarding.Checked == true)
    	{
    		// ファイルが存在するか確認
    		if (File.Exists(バイナリーデータのパス))
    		{
    			// ファイルからすべての行を読み込む
    			byte[] recvData = File.ReadAllBytes(バイナリーデータのパス);
    
    			// recvDataをseparatorで区切って分割 (SplitBinaryData関数へ)
    			List<byte[]> chunks = SplitBinaryData(recvData);
    
    			// 分割結果を転送(確認 Debug.WriteLine)
    			for (int i = 0; i < chunks.Count; i++)
    			{
    			
    				// Debug.WriteLine($"{i + 1}: {BitConverter.ToString(chunks[i])}");	// Debug用出力
    				通常の転送処理(chunks[i]);
    			}
    
    			// 1ファイルすべて転送終了したらバースト処理を終了する
    			UpdateCheckBox(ChkBurst, false);
    			UpdateCheckBox(ChkForwarding, false);
    			UpdateTextBox($"\r\nDone the FORWARD PROCESS.\r\n");
    		}
    	}
    			
    	// recvDataをスペース区切りの16進数テキストに変換
    	string hexString = string.Join(" ", data.Select(b => b.ToString("X2"))).ToLower();
    
    	// Telemetry Tabに表示
    	UpdateTextBox(hexString);
    }
    else
    // 通常の1パケットごとに受信する時
    {
    	通常の転送処理(recvData);
    }

    =MEMO= 運用操作としては、ラジオボタンの組み合わせで受信待機(Burst:ON = 自動的にForward:OFF)と受信後バッチ送信(Bust:ON + Forwarding:ON)となる。

    // Burst DATA をセパレータで分割して個々ののフレームにする
    static List<byte[]> SplitBinaryData(byte[] recvData)
    {
    	List<byte[]> result = [];
    	ReadOnlySpan<byte> dataSpan = recvData;
    	ReadOnlySpan<byte> separatorSpan = [0xC0, 0x00];
    
    	int startIndex = 0;		// statIndexの初期化
    
    	// 最初のセパレータをチェック
    	if (dataSpan.StartsWith(separatorSpan))
    	{
    		// 先頭セパレータをスキップ
    		startIndex = separatorSpan.Length;
    	}
    
    	while (startIndex < dataSpan.Length)
    	{
    		int separatorIndex = dataSpan[startIndex..].IndexOf(separatorSpan);
    		if (separatorIndex == -1)
    		{
    			// セパレーターが見つからなければ最後までを追加
    			result.Add(dataSpan[(startIndex - separatorSpan.Length)..].ToArray());
    			break;
    		}
    
    		// セパレーターを含めた範囲を取得
    		int endIndex = startIndex + separatorIndex;
    		result.Add(dataSpan[(startIndex - separatorSpan.Length)..endIndex].ToArray());
    
    		startIndex = endIndex + separatorSpan.Length; // セパレーターの次から開始
    	}
    
    	return result;
    }
    	

    上段のコードにある Debug.WriteLine を有効にして出力すると下のように分割されているのが分かる。

    1: C0-00-4A-47-36-59-42-57-30-4A-47-36-59-4D-58-30-3E-F0-FF-F0-FF-00-00-3B-33-33-22-39-02-00-06-AA-AA-AA-03-68-06-14-06-32-06-57-06-97-05-62-06-41-0C-D5-0D-5D-0D-46-0D-49-0C-C9-01-17-06-07-01-B3-A4-08-40-A4-0D-C4-01-85-00-00-BB-A0-06-00-04-00-00-F7-E0-CC-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-44-44-44-44-44-C0
    2: C0-00-4A-47-36-59-42-57-30-4A-47-36-59-4D-58-30-3E-F0-FF-F0-FF-00-00-3C-33-33-03-3B-02-00-06-AA-AA-AA-03-9F-06-12-06-26-06-46-06-92-05-76-06-39-0D-5F-0D-54-0D-0C-0D-44-0D-5B-0E-09-01-02-0A-B3-A4-08-48-A4-0D-C4-01-8C-00-00-BB-A0-06-00-05-00-00-F7-E0-CC-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-44-44-44-44-44-C0
    3: C0-00-4A-47-36-59-42-57-30-4A-47-36-59-4D-58-30-3E-F0-FF-F0-FF-00-00-49-33-33-21-12-03-00-06-AA-AA-AA-04-0D-05-EB-06-05-05-F9-05-F4-06-30-06-19-0D-79-0D-A5-0B-4E-0D-A0-0C-1E-02-13-00-0B-01-AF-A4-08-3A-A4-0D-C9-01-7F-00-00-BB-A0-06-00-0D-00-00-F7-E0-CC-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-44-44-44-44-44-C0
    		:
    		:
    これらのフレームを一つずつ、転送に対する応答の 201 を確認しながら、最後まで繰り返す事になる。

別スレッドからUIスレッドのコントロールを変更する


    UpdateTextBox() は、UI要素であるテキストボックスが作成されたスレッド以外から、安全に書き込める様にするために Invoke を使用して、別途作成した関数である。

    // UI要素(TxtTelemetry)が作成されたスレッド以外から安全に書き込める様にする
    private void UpdateTextBox(string text)
    {
    	if (TxtTelemetry.InvokeRequired)
    	{
    		TxtTelemetry.Invoke(new Action<string>(UpdateTextBox), text);
    	}
    	else
    	{
    		if (!TxtTelemetry.IsDisposed)
    		{
    			TxtTelemetry.AppendText(text);
    		}
    	}
    }	


    次に示す同様のUIスレッドに対する変更は、目的のコントロールと変更内容を指定して呼び出すことで、使い回しが出来るようにしたものである。

    // UIスレッドのChkBurstを変更する
    private static void UpdateCheckBox(CheckBox chkBox, bool isChecked)
    {
    	if (chkBox.InvokeRequired)
    	{
    		// UIスレッドにデリゲートを送る
    		chkBox.BeginInvoke((System.Windows.Forms.MethodInvoker)delegate {
    			chkBox.Checked = isChecked;				// 無効にする
    		});
    	}
    	else
    	{
    		// UIスレッドにいる場合はそのまま実行
    		ChkBox.Checked = isChecked;
    	}
    }	

    呼び出す時は UpdateCheckBox(ChkBoxName, true) のようになる。


Back
Alt+HOME