C# Windows マルチシリアルポートバインディング

説明

作業テストでは、複数のシリアルポートを同時に焼き付けたり、複数のシリアルポートを持つデバイスを制御したり、コマンドを送信したりするなど、複数のシリアルポートをドラッグして通信する必要がある場合がありますが、通常、私が使用するシリアルポートツールは人為的な1対1の手動操作であり、コンピュータを使用して1対多のシリアルポート通信を同時に操作したことはありません。

これを行う前に、まずシリアル ポートについて理解する必要があります。主に、コンピュータの再起動後に COM ポートが変更されるかどうか、および複数のシリアル ポートを接続した後に COM ポートが変更されるかどうかを理解する必要があります。依存関係をバインドするには COM に依存する必要があるため、これらを理解してください。COM データの取得は簡単で便利です。テスト後、シリアル ポートを接続した後、USB スロットを交換すると、それに応じて COM ポートが変更されます。他のシリアル ポートを接続した後は、以前に接続されていたシリアル ポートの COM ポートは変更されず、再起動後も COM ポートは変更されません。したがって、シリアル ポートをバインドした後は、COM の変更を引き起こす可能性があるシリアル ポートの抜き差しを行わないでください。

レンダリング

目標

私たちがしなければならないことは、次の関数を実装することです

1. USB デバイス プラグインを監視し、USB デバイス プラグインがある場合に COM ポート リストを更新します。

2. バインドされたシリアル ポートは設定ファイルとして保存でき、次回の起動時に設定が直接ロードされ、設定ファイルに従ってバインドされます。

3. 複数のシリアル ポートをターゲット デバイスにバインドでき、バインドされた COM ポートを削除できます。バインド後、COM リストからバインドされた情報が削除されます。

4. どのバインドされたシリアル ポートが利用可能で、どのシリアル ポートが切断されているかを確認できます。

コードロジック

どのシリアル ポートがどのケーブルに接続されているかを把握し、対応するデバイスに合理的に接続するために、USB デバイス監視機能を追加しました。シリアル ポートが接続されると、新しい COM 情報がアンバインド リストに追加されます。シリアル ポートの COM 名を知ってからバインドするため、間違いが起こりにくくなります。

// 在生命周期loaded的时候初始化监听器
// 这里的代码适用与WPF,如果你是Winform,请查看我写的USB监听的博文
private void OnLayoutLoaded(object sender, RoutedEventArgs e)
{
	HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
	if (null != hwndSource)
		hwndSource.AddHook(new HwndSourceHook(DevieceChanged));
}

private IntPtr DevieceChanged(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
	if (msg == WM_DEVICECHANGE)
	{
		switch (wParam.ToInt32())
		{
			case DBT_DEVICEARRIVAL:
				Console.WriteLine("串口连接成功!");
				break;
			case DBT_DEVICEREMOVECOMPLETE:
				Console.WriteLine("串口断开!");
				break;
		}
		if(wParam.ToInt32() == DBT_DEVICEARRIVAL || wParam.ToInt32() == DBT_DEVICEREMOVECOMPLETE)
		{
			// 这里用线程主要事因为,有时一个串口设备有2个COM口,在线程里面等待两个口都连接
			// 上后,再刷新界面,只用刷新一次
			Thread thread = new Thread(new ThreadStart(OnDiveceChanged));
			thread.Start();
		}
	}
	return IntPtr.Zero;
}

private bool isUpdataComsList = false;
private object lockObj = new object();
private void OnDiveceChanged()
{
	lock (lockObj)
	{
		if (isUpdataComsList) return;
		isUpdataComsList = true;
	}
	Thread.Sleep(1000);
	m_SyncContext.Post(UpdataComsList, null);
}

デバイス バインディング: デバイスが 1 つの場合、COM ポートをデバイスに関連付け、キーと値のペアの形式で保存するだけです (例: ----->DUT1: COM3、DUT2: COM8)。シリアルポートを接続する必要がある場合は、自分の番号に応じて対応するCOMポートを選択できます。たとえば、自分の番号が「DUT2」の場合は、COM8のシリアルポートを接続できます。

複数のシリアルポートに接続し、複数のデバイスを制御する必要があるデバイスに対して、タグの概念を導入しました。たとえば、機能 1 のタグは CMS1、機能 2 のタグは CMS2 になります。データの保存形式はキーと値のペアのままですが、値がオブジェクトになり、そのオブジェクトに COM ポート情報と TAG 情報が格納されます。たとえば、DUT1: [{シリアル: COM3、タグ: CMS1}、{シリアル: COM5、タグ: CMS2}]、特定のデバイスが特定の機能を使用している場合、保存されたタグがわかれば、設定されたシリアル ポートを取得できます。

保存したシリアルポートはXML形式で保存されるので、お好みの方法で選択できます

保存された設定ファイルを少し解析します

public static  void SaveSerialsBindInfo(Dictionary<string,List<SerialsBindInfo>> infos)
{
	CheckSaveConfigFilesPath();
	XmlDocument xmlDoc = new XmlDocument();
	XmlElement root = xmlDoc.CreateElement("SerialsConfig");
	xmlDoc.AppendChild(root);
	XmlElement DutBindInfoElement;
	foreach (KeyValuePair<string, List<SerialsBindInfo>> kv in infos){
		if (kv.Value.Count == 0) continue;
		DutBindInfoElement = xmlDoc.CreateElement("DutBindInfo");
		DutBindInfoElement.SetAttribute("DutNum" , kv.Key);
		XmlElement SerialNameElement;
		XmlElement RemarkElement;
		foreach (SerialsBindInfo serialInfo in kv.Value)
		{
			if (serialInfo.SerialName.Trim().Length == 0 && serialInfo.Remark.Trim().Length == 0) continue;
			XmlElement BindInfoItemElement = xmlDoc.CreateElement("InfoItem");
			SerialNameElement = xmlDoc.CreateElement("SerialName");
			SerialNameElement.InnerText = serialInfo.SerialName;
			RemarkElement = xmlDoc.CreateElement("Remark");
			RemarkElement.InnerText = serialInfo.Remark;
			BindInfoItemElement.AppendChild(SerialNameElement);
			BindInfoItemElement.AppendChild(RemarkElement);
			DutBindInfoElement.AppendChild(BindInfoItemElement);
		}
		root.AppendChild(DutBindInfoElement);
	}
	xmlDoc.Save(FilePathConfig.SerialsBindConfigPath);
}

COM ポートをバインドした後、バインド対象のリストからバインドされたシリアル ポートを削除する必要があります。そうしないと、シリアル ポートが多すぎると混乱が生じます。

バインドを解除する場合は、バインドされていない COM をバインドするリストに追加する必要もあります

COM1 から COM2 に切り替える場合、追加と削除の両方が発生します。便宜上、また上記 3 つの要件を満たすために、まずすべての COM を取得し、次にすべての COM からバインドされたデータを削除し、バインドされていないデータのみを残します。

private void SerialsSelectionChanged(object sender, SelectionChangedEventArgs e)
{
	ComboBox comboBox = (ComboBox)sender;
	Label SelectItem = (Label)comboBox.SelectedItem;
	if (SelectItem == null) return;
	string content = (string)SelectItem.Content;
	if (ContentNone.Equals(content))
		comboBox.Items.Clear();
	else
		unBindSerials.Remove(content);
	DockPanel itemLayout = (DockPanel)comboBox.Parent;
	// 先刷新刚刚选中的COM口的UI
	UpdataBindData(itemLayout);
	// 再过滤未绑定的数据
	FilterUnbindComs();
	// 刷新未绑定列表的UI
	UpdateComsList();
}

private void FilterUnbindComs()
{
	// 清除历史数据
	unBindSerials.Clear();
	// 遍历所有的COM,包含绑定和未绑定的所有COM口
	foreach (string ComName in allComsList)
	{
		bool isContains = false;
		// 遍历查找是否该COM口已经绑定
		foreach (List<SerialsBindInfo> ComsInfos in bindData.Values)
		{
			foreach (SerialsBindInfo info in ComsInfos)
			{
				if (ComName.Equals(info.SerialName))
				{
					isContains = true;
					break;
				}
			}
		}
		// 如果没绑定,则添加进未绑定列表
		if(!isContains) unBindSerials.Add(ComName);
	}
}

これでバインドと保存ができるようになりましたが、場合によってはデバイスが異常になることがあります。まずシリアルデバイスが正常かどうかを確認する必要があります。シリアルポートが正しく接続されていない場合、正常に動作しないはずです。

検出方法は、現在のすべてのシリアル ポート (現在利用可能なすべてのシリアル ポート) を取得し、バインド データを比較し、バインドされたシリアル ポートが現在利用可能なシリアル ポートのリストにあるかどうかを確認することです。シリアル ポートのリストにない場合は、赤いアイコンでマークされ、エンジニアリング担当者がメンテナンス中に観察して修復するのに便利です。

//默认Image是显示的,当判断到符合条件时,将其隐藏
if (serialsBindInfo == null || serialsBindInfo.SerialName == null || serialsBindInfo.SerialName.Trim().Length == 0 || allComsList.Contains(serialsBindInfo.SerialName))
	EnableImage.Visibility = Visibility.Hidden;

まとめ

シリアル ポートのバインドは、1 対多にする方法を考える限り、実際には非常に簡単です。上記のロジックは、複数のシリアル ポートを接続し、複数のマシンを制御するのに役立ちます。

私の記事が気に入っていただけましたら、いいねを長押ししてください

おすすめ

転載: blog.csdn.net/baoolong/article/details/127390812