UniCB cleanup, simulation improved, locking.

This commit is contained in:
Milan Hanajik
2021-03-20 07:20:36 +01:00
parent 0e8bbec3bc
commit 747195fc10
+78 -76
View File
@@ -83,57 +83,14 @@ namespace TBF.Rig.ControlBoard.Uni
const int BUFFER_SIZE = 4000; /// Size of input buffers
byte[] buffer; /// Buffer for data received in one attempt in RunDeviceBefore()
byte[] rcvdData; /// Buffer for all recevied but nut processed data. May contain data from several read attempts
int[] cumulativeSums;
int[] cumulativeSums; /// Cumulative sums to verify checksums easily
int rcvdBytesCount; /// Count of valid bytes in rcvdData buffer
int lastReceivedTime; /// StateMachine.Time time stamp of the last received valid frame
bool outputsInitialized; /// Flag indicating that outputs were sent at least once
///
/// Route / digital outputs / states of electromagnetic valves
///
readonly UInt128 routeMask; /// Set in the constructor, bits of outputs that can be controlled by Action.ChangeRoute are set.
/// Regulation valve control outputs and diverters cannot be controlled by Action.ChangeRoute
/// Depends on the control board configuration
ulong valvesToInvert; /// From configurations of valve and pump components. Inversion is applied when creating
/// Action.ChangeRoute an dafter obtaining RRoute from the control board
/// State of digital outputs obtained from the control board
public UInt128 RRoute
{
get
{
if ((StateMachine.Time - lastReceivedTime) < 5)
{
return (UInt128)(Data.Vystupy ^ valvesToInvert);
}
else
{
return ((UInt128)1) << cbCfg.BitNr; /// No connection to control board
}
}
}
UInt128 displayedRoute; /// A route displayed on the screen (inversions are not applied)
UInt128 bitsChangedByUI; /// Ones in this word indicate which valves/pumpes were changed in UI by mouse clicks
UInt128 displayedRoutePlusUI; /// A route displayed on the screen plus the modifications from UI (inversions are not applied)
UInt128 outputLatch; /// A copy of route sent to physical outputs
UInt128 benchModelRoute;
bool outputsInitialized;
int lastStateMachineTime = 0;
/// <summary>
/// Route: 128-bit word representing the current state of all valves and pumps
/// </summary>
public UInt128 Route { get { return benchModelRoute; } }
/// UI actions are blocked when true
public bool IsUIBlocked { get; set; }
/// Message queue
Queue<Action> actionQueue;
/// Received data
///
public GeneralData Data;
DivTransitionData divTransitionData;
ScopeAnalyzerData scopeAnalyzerData;
@@ -152,10 +109,36 @@ namespace TBF.Rig.ControlBoard.Uni
{
return Data.AnalogInput[channel];
}
return 0;
else return 0;
}
/// Values valid during a test
///
/// Digital outputs / Route / States of electromagnetic valves
///
readonly UInt128 routeMask; /// Set in the constructor, bits of outputs that can be controlled by Action.ChangeRoute are set.
/// Regulation valve control outputs and diverters cannot be controlled by Action.ChangeRoute
/// Depends on the control board configuration
ulong valvesToInvert; /// From configurations of valve and pump components. Inversion is applied when creating
/// a message to be sent by serial port
UInt128 displayedRoute; /// A route displayed on the screen (inversions are not applied)
UInt128 bitsChangedByUI; /// Ones in this word indicate which valves/pumpes were changed in UI by mouse clicks
UInt128 displayedRoutePlusUI; /// A route displayed on the screen plus the modifications from UI (inversions are not applied)
UInt128 outputLatch; /// A copy of data sent to physical digital outputs (inversions are not applied)
///
/// 128-bit word representing the current state of all valves and pumps (inversions are not applied)
///
UInt128 route;
public UInt128 Route { get { return route; } }
///
/// Queue of higher level commands for the control board
///
Queue<Action> actionQueue;
/// UI actions are blocked when true
public bool IsUIBlocked { get; set; }
/// Measured values valid during a test
public double RefFrequency { get { return Data.ReferenceFreq[0]; } }
public double RefFrequency1 { get { return Data.ReferenceFreq[1]; } }
public double RefFrequency2 { get { return Data.ReferenceFreq[2]; } }
@@ -254,16 +237,11 @@ namespace TBF.Rig.ControlBoard.Uni
TBF.UiBridge.Bridge.RouteChangeHandler += delegate(object sndr, TBF.UiBridge.RouteChangeArgs args)
{
UInt128 oneBitMask = ((UInt128)1) << args.BitNr;
lock (this)
{
bitsChangedByUI |= oneBitMask;
displayedRoutePlusUI = displayedRoutePlusUI ^ oneBitMask;
//if ((displayedRoutePlusUI & oneBitMask) == 0)
//{
// displayedRoutePlusUI |= oneBitMask;
//}
//else
//{
// displayedRoutePlusUI &= (~oneBitMask);
//}
}
};
log.FatalFormat("{0} - Device successfully initialized", Name);
@@ -274,6 +252,9 @@ namespace TBF.Rig.ControlBoard.Uni
/// </summary>
public void RunDeviceBefore()
{
///
/// Read data from the control board
///
if (cbCfg.DebugLevel == DebugMode.Normal && serialPort != null && serialPort.IsOpen)
{
/// Read new received bytes and append them to a buffer
@@ -357,15 +338,25 @@ namespace TBF.Rig.ControlBoard.Uni
rcvdBytesCount -= lastValidOffset;
}
benchModelRoute = RRoute;
///
/// Combine data from the current route, from digital outputs and from UI
///
lock (this)
{
route = (UInt128)(Data.Vystupy ^ valvesToInvert);
///
if (!IsUIBlocked && bitsChangedByUI != 0)
{
benchModelRoute = (benchModelRoute & ~bitsChangedByUI) | (displayedRoutePlusUI & bitsChangedByUI);
route = (route & ~bitsChangedByUI) | (displayedRoutePlusUI & bitsChangedByUI);
bitsChangedByUI = 0;
}
log.DebugFormat("Route synced with RRoute and UI changes, new route = {0}", Utils.RouteToStr(benchModelRoute));
if ((StateMachine.Time - lastReceivedTime) >= 5)
{
/// No connection to control board ... set indicator bit
route += ((UInt128)1) << cbCfg.BitNr;
}
}
log.DebugFormat("Route synced with RRoute and UI changes, new route = {0}", Utils.RouteToStr(route));
}
/// <summary>
@@ -373,15 +364,20 @@ namespace TBF.Rig.ControlBoard.Uni
/// </summary>
public void RunDeviceAfter()
{
/// Synchronize benchModelRoute with RRoute
///
/// Combine data from the current route and from UI
///
lock (this)
{
if (!IsUIBlocked && bitsChangedByUI != 0)
{
benchModelRoute = (benchModelRoute & ~bitsChangedByUI) | (displayedRoutePlusUI & bitsChangedByUI);
route = (route & ~bitsChangedByUI) | (displayedRoutePlusUI & bitsChangedByUI);
bitsChangedByUI = 0;
}
displayedRoute = Route;
displayedRoutePlusUI = Route;
displayedRoute = route;
displayedRoutePlusUI = route;
bitsChangedByUI = 0;
}
ProcessData.UpdateMeasuredValuesAndSetpoints();
Bridge.OnStateMachineTick(this, new StateMachineTickEventArgs(displayedRoute, ProcessData.MsrmntAvailableFlags, ProcessData.MeasuredValues,
ProcessData.AltStrings, ProcessData.Setpoints));
@@ -405,7 +401,7 @@ namespace TBF.Rig.ControlBoard.Uni
}
}
if (!outputsInitialized || (outputLatch & routeMask) != (benchModelRoute & routeMask)) /// || (StateMachine.Time - lastStateMachineTime) >= 15)
if (!outputsInitialized || (outputLatch & routeMask) != (route & routeMask)) /// || (StateMachine.Time - lastStateMachineTime) >= 15)
{
var actionsToModify = actionQueue.Where(x => (x.ActionId == ActionID.ChangeRoute));
bool oneModified = false;
@@ -418,14 +414,14 @@ namespace TBF.Rig.ControlBoard.Uni
}
oneModified = true;
a.Route = (ulong)benchModelRoute;
log.InfoFormat("ChangeRoute(route={0:X}) ... an action in the queue modified", benchModelRoute);
a.Route = (ulong)route;
log.InfoFormat("ChangeRoute(route={0:X}) ... an action in the queue modified", route);
}
if (!oneModified)
{
actionQueue.Enqueue(Action.ChangeRoute(false, (ulong)benchModelRoute));
log.InfoFormat("ChangeRoute(route={0:X}) ... a new action enqueued", (ulong)benchModelRoute);
actionQueue.Enqueue(Action.ChangeRoute(false, (ulong)route));
log.InfoFormat("ChangeRoute(route={0:X}) ... a new action enqueued", (ulong)route);
}
foreach (var a in actionQueue) log.DebugFormat(" {0}", a);
@@ -440,10 +436,16 @@ namespace TBF.Rig.ControlBoard.Uni
{
outputsInitialized = true;
outputLatch = combinedAction.Route;
lastStateMachineTime = StateMachine.Time;
if (cbCfg.DebugLevel != DebugMode.Normal)
{
Data.Vystupy = combinedAction.Route ^ valvesToInvert;
}
}
if (cbCfg.DebugLevel == DebugMode.Normal) serialPort.Write(outData, 0, outData.Length);
if (cbCfg.DebugLevel == DebugMode.Normal)
{
serialPort.Write(outData, 0, outData.Length);
}
string s = Telegram.LogTelegram("Sent: ", outData);
Debug.WriteLine(s);
@@ -506,11 +508,11 @@ namespace TBF.Rig.ControlBoard.Uni
/// <returns>Bits of changed valves are set in the return value</returns>
public UInt128 SetValves(UInt128 valvesToOpen, UInt128 valvesToClose, IList<BuiltIn.ValveEx.Valve> logicalFnValves)
{
UInt128 oldRoute = benchModelRoute;
benchModelRoute = (benchModelRoute | valvesToOpen) & (~valvesToClose);
foreach (var logFnV in logicalFnValves) logFnV.UpdateRoute(ref benchModelRoute);
log.DebugFormat("SetValves(x,x), new route = {0}", Utils.RouteToStr(benchModelRoute));
UInt128 retVal = oldRoute ^ benchModelRoute;
UInt128 oldRoute = route;
route = (route | valvesToOpen) & (~valvesToClose);
foreach (var logFnV in logicalFnValves) logFnV.UpdateRoute(ref route);
log.DebugFormat("SetValves(x,x), new route = {0}", Utils.RouteToStr(route));
UInt128 retVal = oldRoute ^ route;
log.DebugFormat("{0}.SetValves({1}, {2}) returns {3}", Name, valvesToOpen.ToString("X"), valvesToClose.ToString("X"), retVal.ToString("X"));
return retVal;