691 lines
22 KiB
C#
691 lines
22 KiB
C#
using GenesisCordonelInterface.API;
|
|
using GenesisCordonelInterface.UI;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using System.Linq;
|
|
using GciPublicModels = GenesisCordonelInterface.API.PublicModels;
|
|
|
|
namespace TBF.Rig.BridgeComponents.GciBridge.UI.StaraTuraAPI_GciBridge
|
|
{
|
|
public partial class SlotsComPortsRegistersActionsView : UserControl
|
|
{
|
|
private readonly GciBridge _bridge;
|
|
private readonly MainView _mainView;
|
|
private CancellationTokenSource _cts;
|
|
private readonly Action _addSlotAction;
|
|
private readonly Action _saveAction;
|
|
private readonly Dictionary<string, Type> _registerTypes =
|
|
new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
public SlotsComPortsRegistersActionsView(
|
|
MainView mainview,
|
|
GciBridge bridge,
|
|
Action addSlotAction,
|
|
Action saveAction)
|
|
{
|
|
_mainView = mainview ?? throw new ArgumentNullException(nameof(mainview));
|
|
_bridge = bridge ?? throw new ArgumentNullException(nameof(bridge));
|
|
|
|
_addSlotAction = addSlotAction;
|
|
_saveAction = saveAction;
|
|
|
|
InitializeComponent();
|
|
|
|
LoadRegisterComboBoxes();
|
|
|
|
_mainView._batchPanel.GetMeterRegistersClicked -= LoadRegisterComboBoxes;
|
|
_mainView._batchPanel.GetMeterRegistersClicked += LoadRegisterComboBoxes;
|
|
writeRegisterNameComboBox.SelectedIndexChanged -= writeRegisterNameComboBox_SelectedIndexChanged;
|
|
writeRegisterNameComboBox.SelectedIndexChanged += writeRegisterNameComboBox_SelectedIndexChanged;
|
|
writeRegisterNameComboBox.TextChanged -= writeRegisterNameComboBox_SelectedIndexChanged;
|
|
writeRegisterNameComboBox.TextChanged += writeRegisterNameComboBox_SelectedIndexChanged;
|
|
}
|
|
|
|
private void AddSlot()
|
|
{
|
|
_addSlotAction?.Invoke();
|
|
}
|
|
|
|
private void SaveSlots()
|
|
{
|
|
_saveAction?.Invoke();
|
|
}
|
|
|
|
private List<GciPublicModels.MeterBatchDebugStatus> GetSelectedSlots()
|
|
{
|
|
if (_mainView == null || _mainView._batchPanel == null)
|
|
{
|
|
Log("Meter batch grid is not available.");
|
|
|
|
return new List<GciPublicModels.MeterBatchDebugStatus>();
|
|
}
|
|
|
|
return _mainView._batchPanel.GetSelectedGridData()
|
|
?? new List<GciPublicModels.MeterBatchDebugStatus>();
|
|
}
|
|
|
|
private void RefreshGrid(int? removedSlot = null)
|
|
{
|
|
if (removedSlot.HasValue)
|
|
{
|
|
_mainView?._gciApi.SetSlotSelected(removedSlot.Value, false);
|
|
_mainView?._batchPanel?.RemoveSlotRow(removedSlot.Value);
|
|
}
|
|
|
|
if (_bridge?.gciExternalInterface != null)
|
|
_bridge.gciExternalInterface.RaiseMeterBatchStatusChanged();
|
|
}
|
|
|
|
private GciPublicModels.GciInitSlotRequest CreateSlotRequest(
|
|
GciPublicModels.MeterBatchDebugStatus slot)
|
|
{
|
|
return new GciPublicModels.GciInitSlotRequest
|
|
{
|
|
SlotId = slot.Slot,
|
|
ConfigSource = GciPublicModels.GciConfigSource.InterfaceInputConfig,
|
|
PasswordSource = GciPublicModels.GciPasswordSource.InterfaceInputPassword,
|
|
RequestPort = GciPublicModels.CreatePortConfig(
|
|
slot.RequestPort,
|
|
slot.RequestPortType),
|
|
StreamingPort = GciPublicModels.CreatePortConfig(
|
|
slot.StreamingPort,
|
|
string.Empty)
|
|
};
|
|
}
|
|
|
|
private void btnInitSlot_Click(object sender, EventArgs e)
|
|
{
|
|
ExecuteAsync(async token =>
|
|
{
|
|
var selectedSlots = _mainView._batchPanel.GetSelectedGridData();
|
|
|
|
if (selectedSlots.Count == 0)
|
|
{
|
|
int slotId = _mainView._batchPanel._gridManager.GetNextSlotId();
|
|
|
|
var request = new GciPublicModels.GciInitSlotRequest
|
|
{
|
|
SlotId = slotId,
|
|
ConfigSource = GciPublicModels.GciConfigSource.InterfaceInputConfig,
|
|
PasswordSource = GciPublicModels.GciPasswordSource.InterfaceInputPassword,
|
|
RequestPort = null,
|
|
StreamingPort = null
|
|
};
|
|
|
|
var result = await _bridge.InitSlotAsync(request, token);
|
|
|
|
LogResult($"InitSlotAsync new slot {slotId}", result);
|
|
|
|
RefreshGrid();
|
|
return;
|
|
}
|
|
|
|
var tasks = selectedSlots.Select(async slot =>
|
|
{
|
|
var request = CreateSlotRequest(slot);
|
|
|
|
//var result = await _bridge.InitSlotAsync(request, token);
|
|
var result = await _bridge.InitSlotWithRetryAsync(request, token);
|
|
|
|
return new
|
|
{
|
|
Slot = slot.Slot,
|
|
Result = result
|
|
};
|
|
}).ToList();
|
|
|
|
var results = await Task.WhenAll(tasks);
|
|
|
|
foreach (var item in results.OrderBy(x => x.Slot))
|
|
{
|
|
LogResult($"InitSlotAsync slot {item.Slot}", item.Result);
|
|
}
|
|
|
|
RefreshGrid();
|
|
});
|
|
}
|
|
|
|
private void btnUpdateSlot_Click(object sender, EventArgs e)
|
|
{
|
|
ExecuteAsync(async token =>
|
|
{
|
|
var selectedSlots = _mainView._batchPanel.GetSelectedGridData();
|
|
|
|
if (selectedSlots.Count == 0)
|
|
{
|
|
LogResult("UpdateSlotAsync", "No slot selected.");
|
|
return;
|
|
}
|
|
|
|
var tasks = selectedSlots.Select(async slot =>
|
|
{
|
|
var request = CreateSlotRequest(slot);
|
|
|
|
//var result = await _bridge.UpdateSlotAsync(request, token);
|
|
var result = await _bridge.UpdateSlotWithRetryAsync(request, token);
|
|
|
|
return new
|
|
{
|
|
Slot = slot.Slot,
|
|
Result = result
|
|
};
|
|
}).ToList();
|
|
|
|
var results = await Task.WhenAll(tasks);
|
|
|
|
foreach (var item in results.OrderBy(x => x.Slot))
|
|
{
|
|
LogResult($"UpdateSlotAsync slot {item.Slot}", item.Result);
|
|
}
|
|
|
|
RefreshGrid();
|
|
});
|
|
}
|
|
|
|
private void btnGetSlot_Click(object sender, EventArgs e)
|
|
{
|
|
ExecuteAsync(async token =>
|
|
{
|
|
var tasks = GetSelectedSlots()
|
|
.Select(async slot =>
|
|
{
|
|
//var result = await _bridge.GetSlotAsync(slot.Slot);
|
|
var result = await _bridge.GetSlotWithRetryAsync(slot.Slot);
|
|
|
|
return new
|
|
{
|
|
Slot = slot.Slot,
|
|
Result = result
|
|
};
|
|
})
|
|
.ToList();
|
|
|
|
var results = await Task.WhenAll(tasks);
|
|
|
|
foreach (var item in results.OrderBy(x => x.Slot))
|
|
{
|
|
LogResult($"GetSlotAsync slot {item.Slot}", item.Result);
|
|
}
|
|
|
|
RefreshGrid();
|
|
});
|
|
}
|
|
|
|
private void btnCleanSlot_Click(object sender, EventArgs e)
|
|
{
|
|
ExecuteAsync(async token =>
|
|
{
|
|
var tasks = GetSelectedSlots()
|
|
.Select(async slot =>
|
|
{
|
|
//var result = await _bridge.CleanSlotAsync(slot.Slot);
|
|
var result = await _bridge.CleanSlotWithRetryAsync(slot.Slot);
|
|
|
|
return new
|
|
{
|
|
Slot = slot.Slot,
|
|
Result = result
|
|
};
|
|
})
|
|
.ToList();
|
|
|
|
var results = await Task.WhenAll(tasks);
|
|
|
|
foreach (var item in results.OrderBy(x => x.Slot))
|
|
{
|
|
LogResult($"CleanSlotAsync slot {item.Slot}", item.Result);
|
|
|
|
RefreshGrid(item.Slot);
|
|
}
|
|
|
|
_mainView._batchPanel.ClearSelection();
|
|
});
|
|
}
|
|
|
|
private void btnCleanAllSlots_Click(object sender, EventArgs e)
|
|
{
|
|
ExecuteAsync(async token =>
|
|
{
|
|
//var result = await _bridge.CleanAllSlotsAsync();
|
|
var result = await _bridge.CleanAllSlotsWithRetryAsync();
|
|
|
|
_mainView._batchPanel.ClearSelection();
|
|
|
|
LogResult("CleanAllSlotsAsync", result);
|
|
|
|
RefreshGrid();
|
|
});
|
|
}
|
|
|
|
private void btnGetPcbId_Click(object sender, EventArgs e)
|
|
{
|
|
ExecuteAsync(async token =>
|
|
{
|
|
var slots = GetSelectedSlots().ToList();
|
|
|
|
var tasks = slots.Select(async slot =>
|
|
{
|
|
//var result = await _bridge.GetPcbIdAsync(slot.Slot, token);
|
|
var result = await _bridge.GetPcbIdWithRetryAsync(slot.Slot, token);
|
|
|
|
return new
|
|
{
|
|
Slot = slot.Slot,
|
|
Result = result
|
|
};
|
|
}).ToList();
|
|
|
|
var results = await Task.WhenAll(tasks);
|
|
|
|
foreach (var item in results.OrderBy(x => x.Slot))
|
|
{
|
|
LogResult($"GetPcbIdAsync slot {item.Slot}", item.Result);
|
|
}
|
|
|
|
RefreshGrid();
|
|
});
|
|
}
|
|
|
|
private void btnConnect_Click(object sender, EventArgs e)
|
|
{
|
|
ExecuteAsync(async token =>
|
|
{
|
|
var slots = GetSelectedSlots().ToList();
|
|
|
|
var tasks = slots.Select(async slot =>
|
|
{
|
|
//var result = await _bridge.ConnectAsyncc(slot.Slot, token);
|
|
var result = await _bridge.ConnectWithRetryAsync(slot.Slot, token);
|
|
|
|
return new
|
|
{
|
|
Slot = slot.Slot,
|
|
Result = result
|
|
};
|
|
}).ToList();
|
|
|
|
var results = await Task.WhenAll(tasks);
|
|
|
|
foreach (var item in results.OrderBy(x => x.Slot))
|
|
{
|
|
LogResult($"ConnectAsync slot {item.Slot}", item.Result);
|
|
}
|
|
|
|
RefreshGrid();
|
|
});
|
|
}
|
|
|
|
private void btnLogin_Click(object sender, EventArgs e)
|
|
{
|
|
ExecuteAsync(async token =>
|
|
{
|
|
var tasks = GetSelectedSlots()
|
|
.Select(async slot =>
|
|
{
|
|
//var result = await _bridge.LoginAsync(slot.Slot, token);
|
|
var result = await _bridge.LoginWithRetryAsync(slot.Slot, token);
|
|
|
|
return new
|
|
{
|
|
Slot = slot.Slot,
|
|
Result = result
|
|
};
|
|
})
|
|
.ToList();
|
|
|
|
var results = await Task.WhenAll(tasks);
|
|
|
|
foreach (var item in results.OrderBy(x => x.Slot))
|
|
{
|
|
LogResult($"LoginAsync slot {item.Slot}", item.Result);
|
|
}
|
|
|
|
RefreshGrid();
|
|
});
|
|
}
|
|
|
|
private void btnDisconnect_Click(object sender, EventArgs e)
|
|
{
|
|
ExecuteAsync(async token =>
|
|
{
|
|
var tasks = GetSelectedSlots()
|
|
.Select(async slot =>
|
|
{
|
|
//var result = await _bridge.DisconnectAsync(slot.Slot, token);
|
|
var result = await _bridge.DisconnectWithRetryAsync(slot.Slot, token);
|
|
|
|
return new
|
|
{
|
|
Slot = slot.Slot,
|
|
Result = result
|
|
};
|
|
})
|
|
.ToList();
|
|
|
|
var results = await Task.WhenAll(tasks);
|
|
|
|
foreach (var item in results.OrderBy(x => x.Slot))
|
|
{
|
|
LogResult($"DisconnectAsync slot {item.Slot}", item.Result);
|
|
}
|
|
|
|
RefreshGrid();
|
|
});
|
|
}
|
|
|
|
private void readRegisterButton_Click(object sender, EventArgs e)
|
|
{
|
|
ExecuteAsync(async token =>
|
|
{
|
|
string registerName = Convert.ToString(readRegisterNameComboBox.Text).Trim();
|
|
|
|
if (string.IsNullOrWhiteSpace(registerName))
|
|
throw new Exception("Read register name is empty.");
|
|
|
|
var tasks = GetSelectedSlots()
|
|
.Select(async slot =>
|
|
{
|
|
//var result = await _bridge.ReadRegisterAsync(slot.Slot, registerName, token);
|
|
var result = await _bridge.ReadRegisterWithRetryAsync(slot.Slot, registerName, token);
|
|
|
|
return new
|
|
{
|
|
Slot = slot.Slot,
|
|
Result = result
|
|
};
|
|
})
|
|
.ToList();
|
|
|
|
var results = await Task.WhenAll(tasks);
|
|
|
|
foreach (var item in results.OrderBy(x => x.Slot))
|
|
{
|
|
LogResult($"ReadRegisterAsync slot {item.Slot}, register {registerName}", item.Result);
|
|
}
|
|
|
|
RefreshGrid();
|
|
});
|
|
}
|
|
|
|
private void writeRegisterButton_Click(object sender, EventArgs e)
|
|
{
|
|
ExecuteAsync(async token =>
|
|
{
|
|
string registerName = Convert.ToString(writeRegisterNameComboBox.Text).Trim();
|
|
string valueText = writeRegisterValueTextBox.Text.Trim();
|
|
|
|
if (string.IsNullOrWhiteSpace(registerName))
|
|
throw new Exception("Write register name is empty.");
|
|
|
|
if (string.IsNullOrWhiteSpace(valueText))
|
|
throw new Exception("Write register value is empty.");
|
|
|
|
object value = ConvertTextToRegisterValue(registerName, valueText);
|
|
|
|
var tasks = GetSelectedSlots()
|
|
.Select(async slot =>
|
|
{
|
|
//var result = await _bridge.WriteRegisterAsync(slot.Slot, registerName, value, false, false, token);
|
|
var result = await _bridge.WriteRegisterWithRetryAsync(slot.Slot, registerName, value, false, false, token);
|
|
|
|
return new
|
|
{
|
|
Slot = slot.Slot,
|
|
Result = result
|
|
};
|
|
})
|
|
.ToList();
|
|
|
|
var results = await Task.WhenAll(tasks);
|
|
|
|
foreach (var item in results.OrderBy(x => x.Slot))
|
|
{
|
|
LogResult(
|
|
$"WriteRegisterAsync slot {item.Slot}, register {registerName}, value {value}",
|
|
item.Result);
|
|
}
|
|
|
|
RefreshGrid();
|
|
});
|
|
}
|
|
|
|
private void btnCancel_Click(object sender, EventArgs e)
|
|
{
|
|
_cts?.Cancel();
|
|
Log("Cancel requested.");
|
|
}
|
|
|
|
private async void ExecuteAsync(Func<CancellationToken, Task> action)
|
|
{
|
|
try
|
|
{
|
|
SetBusy(true);
|
|
|
|
_cts = new CancellationTokenSource();
|
|
|
|
await action(_cts.Token);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
Log("Operation canceled.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log("ERROR: " + ex);
|
|
|
|
MessageBox.Show(
|
|
ex.Message,
|
|
"GciBridge API call failed",
|
|
MessageBoxButtons.OK,
|
|
MessageBoxIcon.Error);
|
|
}
|
|
finally
|
|
{
|
|
_cts?.Dispose();
|
|
_cts = null;
|
|
|
|
SetBusy(false);
|
|
}
|
|
}
|
|
|
|
private void SetBusy(bool busy)
|
|
{
|
|
Cursor = busy ? Cursors.WaitCursor : Cursors.Default;
|
|
|
|
btnInitSlot.Enabled = !busy;
|
|
btnUpdateSlot.Enabled = !busy;
|
|
btnGetSlot.Enabled = !busy;
|
|
btnCleanAllSlots.Enabled = !busy;
|
|
btnGetPcbId.Enabled = !busy;
|
|
btnConnect.Enabled = !busy;
|
|
btnDisconnect.Enabled = !busy;
|
|
readRegisterButton.Enabled = !busy;
|
|
writeRegisterButton.Enabled = !busy;
|
|
readRegisterNameComboBox.Enabled = !busy;
|
|
writeRegisterNameComboBox.Enabled = !busy;
|
|
writeRegisterValueTextBox.Enabled = !busy;
|
|
btnLogin.Enabled = !busy;
|
|
btnCleanSlot.Enabled = !busy;
|
|
|
|
btnCancel.Enabled = busy;
|
|
}
|
|
|
|
private void LogResult(string methodName, object result)
|
|
{
|
|
Log(methodName + " result:");
|
|
Log(result == null ? "<null>" : result.ToString());
|
|
}
|
|
|
|
private void Log(string message)
|
|
{
|
|
txtLog.AppendText(
|
|
DateTime.Now.ToString("HH:mm:ss.fff") +
|
|
" " +
|
|
message +
|
|
Environment.NewLine);
|
|
}
|
|
|
|
private void LoadRegisterComboBoxes()
|
|
{
|
|
_registerTypes.Clear();
|
|
|
|
readRegisterNameComboBox.Items.Clear();
|
|
writeRegisterNameComboBox.Items.Clear();
|
|
|
|
var selectedSlots = GetSelectedSlots();
|
|
|
|
if (selectedSlots.Count == 0)
|
|
{
|
|
Log("No selected slot.");
|
|
return;
|
|
}
|
|
|
|
int slot = selectedSlots
|
|
.OrderBy(x => x.Slot)
|
|
.First()
|
|
.Slot;
|
|
|
|
var registers = _mainView._laatzenApi.GetRegistersDicForSlot(slot);
|
|
|
|
var uniqueRegisters = registers
|
|
.GroupBy(x => x.Key.GetIdent())
|
|
.Select(g => g.First())
|
|
.OrderBy(x => x.Key.GetIdent())
|
|
.ToList();
|
|
|
|
foreach (var item in uniqueRegisters)
|
|
{
|
|
string registerName = item.Key.GetIdent();
|
|
Type dataType = item.Key.DataType;
|
|
|
|
_registerTypes[registerName] = dataType;
|
|
|
|
readRegisterNameComboBox.Items.Add(registerName);
|
|
writeRegisterNameComboBox.Items.Add(registerName);
|
|
}
|
|
|
|
Log($"Loaded {uniqueRegisters.Count} unique registers from slot {slot}");
|
|
}
|
|
|
|
private void grpSlots_Enter(object sender, EventArgs e)
|
|
{
|
|
|
|
}
|
|
|
|
private void writeRegisterNameComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
string registerName = Convert.ToString(writeRegisterNameComboBox.Text).Trim();
|
|
|
|
if (_registerTypes.TryGetValue(registerName, out var type))
|
|
{
|
|
writeRegisterValueTypeLabel.Text = $"type: {type.Name}";
|
|
}
|
|
else
|
|
{
|
|
writeRegisterValueTypeLabel.Text = "type: -";
|
|
}
|
|
}
|
|
|
|
private object ConvertTextToRegisterValue(
|
|
string registerName,
|
|
string valueText)
|
|
{
|
|
if (!_registerTypes.TryGetValue(
|
|
registerName,
|
|
out var targetType))
|
|
{
|
|
throw new Exception(
|
|
$"Unknown register type for register '{registerName}'.");
|
|
}
|
|
|
|
return ConvertTextToType(
|
|
valueText,
|
|
targetType,
|
|
registerName);
|
|
}
|
|
|
|
private object ConvertTextToType(
|
|
string valueText,
|
|
Type targetType,
|
|
string registerName)
|
|
{
|
|
if (targetType == typeof(string))
|
|
return valueText;
|
|
|
|
if (targetType.IsEnum)
|
|
{
|
|
return Enum.Parse(
|
|
targetType,
|
|
valueText,
|
|
true);
|
|
}
|
|
|
|
if (targetType == typeof(byte[]))
|
|
{
|
|
return ParseByteArray(valueText);
|
|
}
|
|
|
|
if (targetType.Name == "Enum8")
|
|
{
|
|
return byte.Parse(valueText);
|
|
}
|
|
|
|
try
|
|
{
|
|
return Convert.ChangeType(
|
|
valueText,
|
|
targetType,
|
|
System.Globalization.CultureInfo.InvariantCulture);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new Exception(
|
|
$"Value '{valueText}' cannot be converted to '{targetType.Name}' for register '{registerName}'.",
|
|
ex);
|
|
}
|
|
}
|
|
|
|
private byte[] ParseByteArray(string valueText)
|
|
{
|
|
valueText = valueText.Trim();
|
|
|
|
if (valueText.Contains("-") ||
|
|
valueText.Contains(" "))
|
|
{
|
|
return valueText
|
|
.Split(
|
|
new[] { '-', ' ', ',', ';' },
|
|
StringSplitOptions.RemoveEmptyEntries)
|
|
.Select(x => x.Replace("0x", ""))
|
|
.Select(x => Convert.ToByte(x, 16))
|
|
.ToArray();
|
|
}
|
|
|
|
valueText =
|
|
valueText.Replace("0x", "");
|
|
|
|
if (valueText.Length % 2 != 0)
|
|
{
|
|
throw new Exception(
|
|
"Hex string length must be even.");
|
|
}
|
|
|
|
byte[] result =
|
|
new byte[valueText.Length / 2];
|
|
|
|
for (int i = 0; i < result.Length; i++)
|
|
{
|
|
string hex =
|
|
valueText.Substring(i * 2, 2);
|
|
|
|
result[i] =
|
|
Convert.ToByte(hex, 16);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
} |