using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace StandardScene.Charge
{
///
/// 通讯监控窗体
///
public partial class CommunicationMonitorForm : Form
{
private readonly CommunicationMessageService messageService;
private bool isFormLoaded = false;
private bool isFormMessageStop = false;
private const int MaxDisplayRows = 100;
private const int UiBatchSize = 20;
private const int StatsRefreshMs = 500;
private readonly Queue pendingMessages = new Queue();
private readonly object pendingMessagesLock = new object();
private readonly Timer uiFlushTimer;
private readonly Timer statsRefreshTimer;
private bool pendingStatsRefresh = false;
private int lastDisplayCountForStats = 0;
public CommunicationMonitorForm()
{
InitializeComponent();
messageService = CommunicationMessageService.Instance;
uiFlushTimer = new Timer { Interval = 500 };
uiFlushTimer.Tick += UiFlushTimer_Tick;
statsRefreshTimer = new Timer { Interval = StatsRefreshMs };
statsRefreshTimer.Tick += StatsRefreshTimer_Tick;
// 订阅窗体关闭事件
this.FormClosing += CommunicationMonitorForm_FormClosing;
}
private void CommunicationMonitorForm_Load(object sender, EventArgs e)
{
try
{
InitializeForm();
LoadMessages();
// 标记窗体已加载完成
isFormLoaded = true;
uiFlushTimer.Start();
statsRefreshTimer.Start();
// 在窗体加载完成后再订阅报文添加事件(避免在初始化期间触发)
messageService.MessageAdded += OnMessageAdded;
}
catch (Exception ex)
{
MessageBox.Show($"窗体加载失败: {ex.Message}\r\n{ex.StackTrace}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void InitializeForm()
{
this.Text = "通讯监控";
this.Size = new Size(1400, 800);
this.StartPosition = FormStartPosition.CenterScreen;
this.MinimumSize = new Size(1200, 600);
// 初始化IP筛选下拉框
RefreshIpFilter();
}
///
/// 刷新IP筛选下拉框
///
private void RefreshIpFilter()
{
try
{
if (cmbIpFilter == null || messageService == null)
return;
var selectedIp = cmbIpFilter.SelectedItem?.ToString();
cmbIpFilter.Items.Clear();
cmbIpFilter.Items.Add("全部");
var ipAddresses = messageService.GetUniqueIpAddresses();
if (ipAddresses != null)
{
foreach (var ip in ipAddresses)
{
if (!string.IsNullOrEmpty(ip))
{
cmbIpFilter.Items.Add(ip);
}
}
}
// 恢复选中项
if (!string.IsNullOrEmpty(selectedIp) && cmbIpFilter.Items.Contains(selectedIp))
{
cmbIpFilter.SelectedItem = selectedIp;
}
else if (cmbIpFilter.Items.Count > 0)
{
cmbIpFilter.SelectedIndex = 0;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"刷新IP筛选失败: {ex.Message}");
}
}
///
/// 加载报文列表
///
private void LoadMessages()
{
var layoutSuspended = false;
try
{
if (dgvMessages == null|| isFormMessageStop)
return;
var selectedIp = cmbIpFilter?.SelectedItem?.ToString();
var messages = string.IsNullOrEmpty(selectedIp) || selectedIp == "全部"
? messageService.GetAllMessages()
: messageService.GetMessagesByIp(selectedIp);
dgvMessages.SuspendLayout();
layoutSuspended = true;
dgvMessages.Rows.Clear();
foreach (var msg in messages)
{
AddMessageRow(msg, false);
}
UpdateStatistics(messages.Count);
pendingStatsRefresh = false;
}
catch (Exception ex)
{
MessageBox.Show($"加载报文失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
if (layoutSuspended && dgvMessages != null)
{
dgvMessages.ResumeLayout();
}
}
}
///
/// 定时批量刷新UI,避免每条报文都抢占UI线程
///
private void UiFlushTimer_Tick(object sender, EventArgs e)
{
if (!isFormLoaded || isFormMessageStop)
return;
List batch = null;
lock (pendingMessagesLock)
{
if (pendingMessages.Count == 0)
return;
int count = Math.Min(UiBatchSize, pendingMessages.Count);
batch = new List(count);
for (int i = 0; i < count; i++)
{
batch.Add(pendingMessages.Dequeue());
}
}
if (batch == null || batch.Count == 0)
return;
dgvMessages.SuspendLayout();
try
{
var selectedIp = cmbIpFilter?.SelectedItem?.ToString();
bool displayChanged = false;
foreach (var message in batch)
{
EnsureIpInFilter(message.IpAddress);
if (string.IsNullOrEmpty(selectedIp) || selectedIp == "全部" || selectedIp == message.IpAddress)
{
AddMessageRow(message, true);
displayChanged = true;
}
}
if (displayChanged)
{
RequestStatisticsRefresh(dgvMessages.Rows.Count);
}
}
finally
{
dgvMessages.ResumeLayout();
}
}
///
/// 统计信息低频刷新(500ms)
///
private void StatsRefreshTimer_Tick(object sender, EventArgs e)
{
if (!isFormLoaded || isFormMessageStop || !pendingStatsRefresh)
return;
pendingStatsRefresh = false;
UpdateStatistics(lastDisplayCountForStats);
}
private void RequestStatisticsRefresh(int displayCount)
{
lastDisplayCountForStats = displayCount;
pendingStatsRefresh = true;
}
private void EnsureIpInFilter(string ipAddress)
{
if (cmbIpFilter == null || string.IsNullOrWhiteSpace(ipAddress))
return;
if (!cmbIpFilter.Items.Contains(ipAddress))
{
cmbIpFilter.Items.Add(ipAddress);
}
}
///
/// 向表格新增一条报文行(支持头部插入)
///
private void AddMessageRow(CommunicationMessage msg, bool insertAtTop = true)
{
if (msg == null || dgvMessages == null)
return;
DataGridViewRow row;
if (insertAtTop)
{
dgvMessages.Rows.Insert(0,
msg.Timestamp.ToString("HH:mm:ss.fff"),
msg.Direction == MessageDirection.Send ? "发送" : "接收",
msg.IpAddress,
msg.Port,
msg.Length,
msg.RawData,
msg.StationId ?? "-",
msg.Type);
row = dgvMessages.Rows[0];
}
else
{
var index = dgvMessages.Rows.Add(
msg.Timestamp.ToString("HH:mm:ss.fff"),
msg.Direction == MessageDirection.Send ? "发送" : "接收",
msg.IpAddress,
msg.Port,
msg.Length,
msg.RawData,
msg.StationId ?? "-",
msg.Type);
row = dgvMessages.Rows[index];
}
if (msg.Direction == MessageDirection.Send)
{
row.DefaultCellStyle.BackColor = Color.FromArgb(232, 245, 233);
row.DefaultCellStyle.ForeColor = Color.FromArgb(46, 125, 50);
}
else
{
row.DefaultCellStyle.BackColor = Color.FromArgb(227, 242, 253);
row.DefaultCellStyle.ForeColor = Color.FromArgb(13, 71, 161);
}
while (dgvMessages.Rows.Count > MaxDisplayRows)
{
dgvMessages.Rows.RemoveAt(dgvMessages.Rows.Count - 1);
}
}
///
/// 更新统计信息
///
private void UpdateStatistics(int displayCount)
{
try
{
if (lblStatistics == null || messageService == null)
return;
var allMessages = messageService.GetAllMessages();
if (allMessages == null)
return;
var sendCount = allMessages.Count(m => m.Direction == MessageDirection.Send);
var receiveCount = allMessages.Count(m => m.Direction == MessageDirection.Receive);
lblStatistics.Text = $"显示: {displayCount} | 总数: {allMessages.Count} | 发送: {sendCount} | 接收: {receiveCount}";
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"更新统计信息失败: {ex.Message}");
if (lblStatistics != null)
{
lblStatistics.Text = "统计信息加载失败";
}
}
}
///
/// 新报文添加事件处理(线程安全)
///
private void OnMessageAdded(object sender, CommunicationMessage message)
{
// 如果窗体还未加载完成,忽略此事件
if (!isFormLoaded || isFormMessageStop)
return;
try
{
if (message == null)
{
return;
}
lock (pendingMessagesLock)
{
pendingMessages.Enqueue(message);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"处理新报文失败: {ex.Message}");
}
}
///
/// 解析报文数据
///
private void ParseMessage(CommunicationMessage message)
{
if (message == null || txtParsedData == null)
return;
try
{
var parsed = new System.Text.StringBuilder();
parsed.AppendLine("=== 报文解析 ===");
parsed.AppendLine($"时间: {message.Timestamp:yyyy-MM-dd HH:mm:ss.fff}");
parsed.AppendLine($"方向: {(message.Direction == MessageDirection.Send ? "发送" : "接收")}");
parsed.AppendLine($"地址: {message.IpAddress}:{message.Port}");
parsed.AppendLine($"站点: {message.StationId ?? "未关联"}");
parsed.AppendLine($"长度: {message.Length} 字节");
parsed.AppendLine();
parsed.AppendLine("=== 原始数据 (HEX) ===");
parsed.AppendLine(message.RawData);
// parsed.AppendLine(FormatHexString(message.RawData));
parsed.AppendLine();
parsed.AppendLine("=== 数据解析 ===");
// TODO: 根据实际协议进行解析
parsed.AppendLine();
if (message.Direction== MessageDirection.Send)
{
var sendDate = messageService.ParseSendRawData(message.RawData, message.Type);
parsed.AppendLine("示例解析:");
parsed.AppendLine($"充电指令:{sendDate.ChargeCommand}");
parsed.AppendLine($"发送电压:{sendDate.SetVoltage}");
parsed.AppendLine($"发送电流:{sendDate.SetCurrent}");
parsed.AppendLine($"车辆ID:{sendDate.CurrentVehicleId}");
parsed.AppendLine($"车辆电量:{sendDate.BatteryLevel}");
parsed.AppendLine($"车辆电压:{sendDate.CarVoltage}");
parsed.AppendLine($"车辆电流:{sendDate.CarCurrent}");
}
else
{
var recDate = messageService.ParseReceiveRawData(message.RawData, message.Type);
string mechanismStatus = (int)recDate.MechanismStatus == 1 ? "伸出" : (int)recDate.MechanismStatus == 2 ? "缩回" : (int)recDate.MechanismStatus == 3 ? "运动中" : recDate.MechanismStatus.ToString();
parsed.AppendLine("示例解析:");
parsed.AppendLine($"机构状态:{mechanismStatus}");
parsed.AppendLine($"实时电压:{recDate.RealTimeVoltage}");
parsed.AppendLine($"实时电流:{recDate.RealTimeCurrent}");
parsed.AppendLine($"充电量: {recDate.BatteryAH}");
parsed.AppendLine($"是否报警:{recDate.HasAlarm}");
parsed.AppendLine($"充电状态:{recDate.Status.ToString()}");
}
txtParsedData.Text = parsed.ToString();
}
catch (Exception ex)
{
txtParsedData.Text = $"解析失败: {ex.Message}";
}
}
///
/// 格式化十六进制字符串
///
private string FormatHexString(string hexData)
{
if (string.IsNullOrEmpty(hexData))
return string.Empty;
var formatted = new System.Text.StringBuilder();
for (int i = 0; i < hexData.Length; i += 2)
{
if (i > 0 && i % 32 == 0)
formatted.AppendLine();
else if (i > 0)
formatted.Append(" ");
if (i + 1 < hexData.Length)
formatted.Append(hexData.Substring(i, 2));
else
formatted.Append(hexData[i]);
}
return formatted.ToString();
}
// ==================== 事件处理 ====================
private void cmbIpFilter_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
LoadMessages();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"筛选改变失败: {ex.Message}");
}
}
private void dgvMessages_SelectionChanged(object sender, EventArgs e)
{
try
{
if (dgvMessages.SelectedRows.Count > 0)
{
var row = dgvMessages.SelectedRows[0];
var rawData = row.Cells[5].Value?.ToString();
var ipAddress = row.Cells[2].Value?.ToString();
var port = int.Parse(row.Cells[3].Value?.ToString() ?? "0");
var timeStr = row.Cells[0].Value?.ToString();
var directionStr = row.Cells[1].Value?.ToString();
var stationId = row.Cells[6].Value?.ToString();
var type = row.Cells[7].Value?.ToString();
// 构造消息对象用于解析
var message = new CommunicationMessage
{
RawData = rawData,
IpAddress = ipAddress,
Port = port,
Direction = directionStr == "发送" ? MessageDirection.Send : MessageDirection.Receive,
StationId = stationId == "-" ? null : stationId,
Length = rawData.Split(' ')?.Length ?? 0,
Type=type,
};
if (DateTime.TryParse(timeStr, out DateTime timestamp))
{
message.Timestamp = timestamp;
}
ParseMessage(message);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"选择报文失败: {ex.Message}");
}
}
private void btnRefresh_Click(object sender, EventArgs e)
{
try
{
RefreshIpFilter();
LoadMessages();
RequestStatisticsRefresh(dgvMessages?.Rows.Count ?? 0);
}
catch (Exception ex)
{
MessageBox.Show($"刷新失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void btnClear_Click(object sender, EventArgs e)
{
try
{
var result = MessageBox.Show(
"确定要清空所有报文记录吗?",
"确认清空",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
messageService.Clear();
RefreshIpFilter();
LoadMessages();
if (txtParsedData != null)
{
txtParsedData.Clear();
}
dgvMessages.Rows.Clear();
RequestStatisticsRefresh(0);
}
}
catch (Exception ex)
{
MessageBox.Show($"清空报文失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
}
private void CommunicationMonitorForm_FormClosing(object sender, FormClosingEventArgs e)
{
// 取消订阅事件
messageService.MessageAdded -= OnMessageAdded;
uiFlushTimer.Stop();
uiFlushTimer.Dispose();
statsRefreshTimer.Stop();
statsRefreshTimer.Dispose();
}
private void button1_Click(object sender, EventArgs e)
{
isFormMessageStop = !isFormMessageStop;
if (sender is Button pauseButton)
{
pauseButton.Text = isFormMessageStop ? "继续" : "暂停";
}
}
}
}