I'm looking for a way to create a delay in my code without stopping the rest of the code in this time frame. It has to work as follows. If a condition is true for X amount of seconds, set the alarm bool High. The code below is a part of code where I set the alarms but there needs to be a delay.
I'm very new to C# so try to dumb it down a bit, maybe a small example or links.
if (Valve.Parameter.NormallyOpen == false)
{
if (Valve.Status.Output == true & Valve.Status.Opened == false)
{
Valve.Alarm.NotOpened = true;
}
if (Valve.Status.Output == false & Valve.Status.Closed == false)
{
Valve.Alarm.NotClosed = true;
}
}
Some background info: this will be a valve control block in PLCNext written in C#. The control block should give a alarm if the valve is send open but does not give open feedback within X seconds (takes time to open).
using System;
using System.Threading;
using System.Iec61131Lib;
using Iec61131.Engineering.Prototypes.Types;
using Iec61131.Engineering.Prototypes.Variables;
using Iec61131.Engineering.Prototypes.Methods;
using Iec61131.Engineering.Prototypes.Common;
namespace EclrFirmwareLibrary1
{
[FunctionBlock]
public class Valve_Test
{
[InOut]
public Valve Valve;
[Output]
public bool Output;
double seconds = 1.00; // 1 Second Interval
[Initialization]
public void __Init()
{
//
// TODO: Initialize the variables of the function block here
//
}
[Execution]
public void __Process()
{
Valve.Status.Interlock = Valve.Control.Interlock;
Valve.Status.Opened = Valve.Control.FB_Open;
Valve.Status.Closed = Valve.Control.FB_Closed;
if (Valve.Control.Manual_Mode == true){
Valve.Status.Manual_Mode = true;
Valve.Status.Auto_Mode = false;
}
if (Valve.Control.Auto_Mode == true & Valve.Control.Manual_Mode == false){
Valve.Status.Manual_Mode = false;
Valve.Status.Auto_Mode = true;
}
if(Valve.Status.Interlock == false & Valve.Alarm.General == false)
{
if (Valve.Status.Manual_Mode & Valve.Control.Manual_Control)
{
Output = true;
Valve.Status.Output = true;
}
else if (Valve.Status.Auto_Mode & Valve.Control.Auto_Control)
{
Output = true;
Valve.Status.Output = true;
}
else
{
Output = false;
Valve.Status.Output = false;
}
}
else
{
Output = false;
Valve.Status.Output = false;
}
//Alarms---------------------------------------------------
var startTimeSpan = TimeSpan.Zero;
var periodTimeSpan = TimeSpan.FromSeconds(seconds);
var timer = new System.Threading.Timer((e) =>
{
CheckValve();
}, null, startTimeSpan, periodTimeSpan);
}
private void CheckValve()
{
if (Valve.Parameter.NormallyOpen == false)
{
if (Valve.Status.Output == true & Valve.Status.Opened == false)
{
Valve.Alarm.NotOpened = true;
}
if (Valve.Status.Output == false & Valve.Status.Closed == false)
{
Valve.Alarm.NotClosed = true;
}
}
else
{
if (Valve.Status.Output == false & Valve.Status.Opened == false)
{
Valve.Alarm.NotOpened = true;
}
if (Valve.Status.Output == true & Valve.Status.Closed == false)
{
Valve.Alarm.NotClosed = true;
}
}
if (Valve.Status.Opened == true & Valve.Status.Closed == true)
{
Valve.Alarm.OpenedAndClosed = true;
}
if (Valve.Alarm.NotClosed || Valve.Alarm.NotOpened || Valve.Alarm.OpenedAndClosed)
{
Valve.Alarm.General = true;
}
}
}
}
The important thing to note in this case is that the device you are using includes a .NET runtime implementation that is a subset and specialisation of the complete .NET runtime. This "eCLR" (Embedded CLR) is designed to operate in the deterministic real-time context required for many industrial control applications.
The details of this implementation can be seen in the PLCnext Info Center
When you create a PLCnext C# project in Visual Studio, the project includes a Programming Reference (.chm file). You will see from this reference that the Timer class is not included in the eCLR.
To your question:
There are a number of ways you can implement a delay function in a PLCnext C# function. Perhaps the simplest is to use the DateTime.Now property to get the current system time when the alarm condition is first seen, and remember this value. Then, on each call to the Process method, you can compare the current time to the time when the alarm condition was first seen. When the time period exceeds the preset time, then the output is set.
For more help with questions related to PLCnext Control devices, you can visit the PLCnext Community. There is an active forum there, where you can discuss these sorts of issues with other PLCnext users.
To call a method each x seconds you can use the TimeSpan Method provided by C# and just pass a method called CheckValve, where you put all your code into.
TimeSpan Example:
double seconds = 1.00; // 1 Second Interval
var startTimeSpan = TimeSpan.Zero;
var periodTimeSpan = TimeSpan.FromSeconds(seconds);
var timer = new System.Threading.Timer((e) =>
{
CheckValve();
}, null, startTimeSpan, periodTimeSpan);
I would also advise you to refactor some of your code:
You can replace bool == true checks with just the bool and bool == false checks with just the bool and a ! before the name.
I would also add an else if so if the if is true you don't need to check the other statement.
CheckValve Method:
private void CheckValve() {
if (!Valve.Parameter.NormallyOpen) {
if (Valve.Status.Output && !Valve.Status.Opened) {
Valve.Alarm.NotOpened = true;
}
else if (!Valve.Status.Output && !Valve.Status.Closed)
{
Valve.Alarm.NotClosed = true;
}
}
}
Related
This question already has answers here:
Control cannot fall through from one case label
(8 answers)
Closed 2 years ago.
So I'm trying to code an escort command for my game using case switch. Basically I have tons of other commands but I've never done one where it makes a target user follow the session user. Basically the person using the command would type :escorts username and it would make the other user stand either in front of the person using the command. or behind them. Any help would be amazing.
#region Escorts User
case "escorting":
{
#region Generate Instances / Sessions / Vars
if (!RoleplayManager.ParamsMet(Params, 1))
{
Session.SendWhisper("Invalid syntax: :stun x");
return true;
}
string Target = Convert.ToString(Params[1]);
GameClient TargetSession = null;
RoomUser Actor = null;
RoomUser Targ = null;
TargetSession = RoleplayManager.GenerateSession(Target);
if (TargetSession == null)
{
Session.SendWhisper("The user was not found in this room!");
return true;
}
if (TargetSession.JobManager() == null)
{
Session.SendWhisper("The user was not found in this room!");
return true;
}
if (TargetSession.JobManager().GetRoomUser() == null)
{
Session.SendWhisper("The user was not found in this room!");
return true;
}
if (TargetSession.JobManager().GetRoomUser().RoomId != Session.JobManager().GetRoomUser().RoomId)
{
Session.SendWhisper("The user was not found in this room!");
return true;
}
Targ = TargetSession.JobManager().GetRoomUser();
Actor = Session.JobManager().GetRoomUser();
int MyJobId = Session.GetRoleplay().JobId;
int MyJobRank = Session.GetRoleplay().JobRank;
Vector2D Pos1 = new Vector2D(Actor.X, Actor.Y);
Vector2D Pos2 = new Vector2D(Targ.X, Targ.Y);
#endregion
#region Police Conditions
if (Params.Length == 1)
{
Session.SendWhisper("Opa, você esqueceu de inserir um nome de usuário!");
return true;
}
GameClient TargetClient = Plus.GetGame().GetClientManager().GetClientByUserName(Params[1]);
if (TargetClient == null)
{
Session.SendWhisper("Ocorreu um erro ao tentar encontrar esse usuário, talvez ele esteja offline.");
return true;
}
RoomUser RoomUser = Session.JobManager().CurrentRoom.GetRoomUserManager().GetRoomUserByHabbo(Session.JobManager().UserName);
if (!JobManager.validJob(Session.GetRoleplay().JobId, Session.GetRoleplay().JobRank) && Session.GetRoleplay().inCR == false)
{
Session.SendWhisper("Your job cannot do this!", false, 34);
return true;
}
bool isclose = false;
if (!Session.GetRoleplay().JobHasRights("police")
&& !Session.GetRoleplay().JobHasRights("gov")
&& !Session.GetRoleplay().JobHasRights("swat")
&& !Session.GetRoleplay().JobHasRights("service")
&& RoleplayManager.CR == false)
{
Session.SendWhisper("Your job cannot do this!");
return true;
}
if (!Session.GetRoleplay().Working && RoleplayManager.CR == false)
{
Session.SendWhisper("You must be working to do this!");
return true;
}
if (Session.GetRoleplay().Dead)
{
Session.SendWhisper("You cannot do this while you are dead!");
return true;
}
if (Session.GetRoleplay().Jailed)
{
Session.SendWhisper("You cannot do this while you are in jail!");
return true;
}
if (Targ.Frozen)
{
Session.SendWhisper("This user is already stunned!");
return true;
}
if (Session.JobManager().CurrentRoom.RoomData.Description.Contains("NOCOP"))
{
Session.SendWhisper("Can't do this in 'NOCOP' rooms.");
return true;
}
if (JobManager.validJob(Session.GetRoleplay().JobId, Session.GetRoleplay().JobRank))
{
if (Session.JobManager().CurrentRoom.RoomData.Description.Contains("WESTERN") && Session.GetRoleplay().JobHasRights("police"))
{
Session.SendWhisper("Can't do this in 'WESTERN' rooms.");
return true;
}
if (!Session.JobManager().CurrentRoom.RoomData.Description.Contains("WESTERN") && Session.GetRoleplay().JobHasRights("western"))
{
Session.SendWhisper("Can only do this in 'WESTERN' rooms.");
return true;
}
}
#endregion
#region Execute
Point ClientPos = new Point(RoomUser.X, RoomUser.Y);
double Distance = RoleplayManager.Distance(Pos1, Pos2);
if (Distance <= 1)
{
if (Session.GetRoleplay().Cop == true && Session.GetRoleplay().inCR == true)
{
RoleplayManager.Shout(Session, "*Fires their stun-gun at " + TargetSession.JobManager().UserName + "*");
TargetSession.GetRoleplay().EffectSeconds = 10;
TargetSession.GetRoleplay().StunnedSeconds = 10;
Targ.ApplyEffect(590);
Targ.CanWalk = true;
Targ.Frozen = false;
Targ.ClearMovement();
LevelManager.AddLevelEXP(Session, 30);
Session.GetRoleplay().SaveQuickStat("currentxp", +30);
return true;
}
}
else
{
Session.SendWhisper("Você deve se aproximar desse cidadão para escoltá-lo!");
return true;
}
}
#endregion
#endregion
The error says that each case block cannot fall through another one.
This means that each case must have a return or break at their ending.
Keep in mind that you may group multiple cases into one (technically this is falling through) when they contain no code.
For more information, see MSDN.
Your switch statement is massive and probably needs some refactoring.
this code is called upon a button click in a windows form and the values are stored after button click and disappear after the event ends and go back to default values but I want the values to remain as i have to use them somewhere else....any suggestions?Also I want to retain the current state of the form and not use a new instance each time
showval function called and the value of variable bitwise is changed there
class Profile{
public bool GetProfileFilter()
{
frmInactiveView frmInactive = new frmInactiveView();
if (frmInactive.btnApplyWasClicked == true || frmInactive.btnCancelWasClicked == false)
{
frmInactive.ShowVal();
MessageBox.Show("bit:" + IBitWise);
MessageBox.Show("ST:" + BegDate);
MessageBox.Show("ET:" + EndDate);
return true;
}
else
{
return false;
}
}
}
enter code here
public partial class FilterView : Form{
Profile profile = new Profile();
private void btnApply_Click(object sender, EventArgs e)
{
btnApplyWasClicked = true;
ShowVal();
status = profile.GetProfileFilter();
profile.ShowMe();
Btn_Enable();
this.Close();
}
public void ShowVal()
{
if (btnApplyWasClicked == true || btnCancelWasClicked == false)
{
if (chkCancel.Checked == true)
{
profile.IBitWise += 2;
}
if (chkDiscon.Checked == true)
{
profile.IBitWise += 1;
}
if (chkVoidwoRes.Checked == true)
{
profile.IBitWise += 4;
}
if (chkVoidwRes.Checked == true)
{
profile.IBitWise += 8;
}
}
}
}
The problem is your form getting instantiated every time when GetProfileFileter is called.
To avoid it, put instance of frmInactiveView under your Profile class. Then value of frmInactiveView would only be renewed when a new Profile is instantiated.
class Profile{
// Keep your form instance here
frmInactiveView frmInactive = new frmInactiveView();
public bool GetProfileFilter()
{
// Don't new it again!
//frmInactiveView frmInactive = new frmInactiveView();
DialogResult result = frmInactive.ShowDialog();
// You may need to take care of dialog result if someone clicked cancel.
if (frmInactive.btnApplyWasClicked == true || frmInactive.btnCancelWasClicked == false)
{
frmInactive.ShowVal();
MessageBox.Show("bit:" + IBitWise);
MessageBox.Show("ST:" + BegDate);
MessageBox.Show("ET:" + EndDate);
return true;
}
else
{
return false;
}
}
}
Sometimes I find myself writing a bool method that looks like this:
public bool isRunning()
{
if (!(move == Moving.None) && staminaRegan == true)
{
if (keyState.IsKeyDown(Keys.Space))
{
EntityAnimation.interval = 10;
return true;
}
else
{
EntityAnimation.interval = 65;
return false;
}
}
else
{
EntityAnimation.interval = 65;
return false;
}
}
(This is XNA by the way) As you can see, I have a bool isRunning in which I made an if statement where Im checking if (Player is moving) && (regains stamina, which is set to false once stamina reaches value lesser than 6.0f)
and then I simply check if Space is pressed, if yes then my Animation is faster(the smaller the interval, the faster is spritesheet changing), and then It sends true value, which means that Player is running, else Im not cause Space is not pressed.
And then I have to repeat this 'else' code outside of the first if statement so it sends that Player is not running if Player is not moving or his stamina Regan is false;
So I was just wondering is this kind of a bool method considered a bad practice(where you retrun true and false value in nested if, and then return false outside nested if and repeat the same code) ?
The method has a side effect, that's why it's a bad practice:
public bool isRunning()
When looking on method's signature we expect just true/false answer and nothing more. However, the method changes the instance's state:
...
if (!(move == Moving.None) && staminaRegan == true)
{
if (keyState.IsKeyDown(Keys.Space))
{
EntityAnimation.interval = 10; // <- Aaa! The interval is changed
return true;
}
...
I suggest splitting the initial method into a property and a method
// No side effect: just answer is running or not
public bool IsRunning {
get {
return (move != Moving.None) && staminaRegan && KeyState.IsKeyDown(Keys.Space);
}
}
// Put the right interval based on instance internal state
// (if it's running etc.)
public void AdjustInterval() {
if (IsRunning) // and may be other conditions
EntityAnimation.interval = 10; //TODO: move magic number into constant
else
EntityAnimation.interval = 65; //TODO: move magic number into constant
}
It is a good practice to have one return statement inside a method. Some argue about this, but it is an opinion.
it is also a good practice to make the if statement clear by removing unnecessary code:
public bool isRunning()
{
bool result = false;
if (move != Moving.None && staminaRegan)
{
if (keyState.IsKeyDown(Keys.Space))
{
EntityAnimation.interval = 10;
result = true;
}
else
{
EntityAnimation.interval = 65;
}
}
else
{
EntityAnimation.interval = 65;
}
return result;
}
You can rewrite the code as follows; then the code isn't repeated:
public bool isRunning()
{
if (move != Moving.None && staminaRegan && keyState.IsKeyDown(Keys.Space))
{
EntityAnimation.interval = 10;
return true;
}
else
{
EntityAnimation.interval = 65;
return false;
}
}
Or if you don't want the redundant else:
public bool isRunning()
{
if (move != Moving.None && staminaRegan && keyState.IsKeyDown(Keys.Space))
{
EntityAnimation.interval = 10;
return true;
}
EntityAnimation.interval = 65;
return false;
}
I would consider introducing a named boolean to self-document somewhat, and I'd rename staminaRegan to staminaIsRegenerating
public bool isRunning()
{
bool isMovingQuickly = (move != Moving.None) && staminaIsRegenerating && keyState.IsKeyDown(Keys.Space);
if (isMovingQuickly)
EntityAnimation.interval = 10;
else
EntityAnimation.interval = 65;
return isMovingQuickly;
}
Most importantly, though, you should rename the method to more accurately describe what it's doing:
public bool CheckIfRunningAndSetAnimationInterval()
I think we write code for people(other developers), of course machine execute a code but 80% of developer's work is reading the code.
Based on that I think flow of reading must be exactly same as flow of executing code - that's why I think multiply return statement not a bad thing, even better then only one return statement on the bottom of your method.
I like this style and i use it too. First, you can read the code more easily and second it has a debugging advantage as you can set breakpoints for the individual else cases. Otherwise you would need to use breakpoint conditions.
I have spent a fair few hours on this problem, it's quite basic but has gotten out of hand quickly.
Because it is rather confusing I'll post what I want it to do and what it actually does
Goal
If a supervisor is busy, it will move onto the next one, if they are all busy it will display a message "Sorry all supervisors are busy". Likewise with all employees.
Method
I want the method to read all the supervisors, if one is not busy it continues down, then I want it to read all of the employees, if one is not busy it continues down.
Then it reads if the employee has the appropriate skill and if the success has already been met, to avoid the same person being assigned the same job.
if this is all good so far, it checks if the supervisor is occupied, if it is, it reverts back and changes supervisor.
It then assigns the employee with the information, also assigning the supervisor with some and checking the 'success' condition.
From here it starts to get a bit sloppy, as you can see, I have put numerous boolean statements to simply get the program out of the loops and exit it.
After all of this, the program assigns the work, so far, it works to a reasonable degree, but I want there to be a message that states that if all of the supervisors are busy that no more work can be allocated.
I have in the past, used MessageBox.Show after foreach statements but if one supervisor is busy it will display the message which is not what I want.
Code
Method to distribute a job
bool finishLast = false;
bool successFirst = false;
while (successFirst != true)
{
foreach (Supervisor sup in supervisors)
{
bool failure = false;
while (failure != true)
{
foreach (Employee emp in employees)
{
if (emp.Busy == false && emp.Skills.HasFlag(_skillRequired) && successFirst == false)
{
if (sup.SupervisorOccupied == false)
{
successFirst = true;
emp.EmployeeWorkload = _jobName;
emp.ShiftsLeft = _shiftsLeft;
emp.Busy = true;
sup.EmployeeWorkload = "Supervising Employee: " + emp.EmployeeName + " to finish task: " + emp.EmployeeWorkload;
sup.ShiftsLeft = _shiftsLeft;
sup.SupervisorOccupied = true;
}
}
else if (emp.Busy == true)
{
failure = true;
}
}
}
if (failure == true)
{
finishLast = true;
}
}
if (finishLast == true)
{
successFirst = true;
}
}
Of course if anyone can think of a simpler way of having this I will be open to ideas.
EDIT 1
This is not a multi-threaded system, yes emp.Busy and sup.SupervisorOccupied are technically the same thing, they are both in the same class so yes sup could inherit emp.Busy.
I think something like this should work:
bool assigned = false;
foreach (Supervisor sup in supervisors)
{
if (!sup.SupervisorOccupied)
{
foreach (Employee emp in employees)
{
if (!emp.Busy && emp.Skills.HasFlag(_skillRequired))
{
assigned = true;
emp.EmployeeWorkload = _jobName;
emp.ShiftsLeft = _shiftsLeft;
emp.Busy = true;
sup.EmployeeWorkload = "Supervising Employee: " + emp.EmployeeName + " to finish task: " + emp.EmployeeWorkload;
sup.ShiftsLeft = _shiftsLeft;
sup.SupervisorOccupied = true;
break;
}
}
}
if (assigned)
break;
}
if at the end "assigned == false", no employee is available (actually there's some code missing so it can't run, but theoretically it should do what you want!).
Here's how you should write that code:
var availableSupervisor = supervisors
.FirstOrDefault(supervisor => !supervisor.SupervisorOccupied);
if (availableSupervisor == null)
return;
var availableEmployee = employees
.FirstOrDefault(employee => !employee.Busy && employee.Skills.HasFlag(_skillRequired));
if (availableEmployee == null)
return;
availableEmployee.EmployeeWorkload = _jobName;
availableEmployee.ShiftsLeft = _shiftsLeft;
availableEmployee.Busy = true;
availableSupervisor.EmployeeWorkload = "Supervising Employee: " + emp.EmployeeName + " to finish task: " + emp.EmployeeWorkload;
availableSupervisor.ShiftsLeft = _shiftsLeft;
availableSupervisor.SupervisorOccupied = true;
I've been thinking about this problem for some time, but i just can't think of a solution without having to write duplicate code. The problem in part c# and part pseudo-code:
bool test = true;
if (test == true)
{
if(first condition) {code}
}
else
{
if(different condition) {same code as above)
}
I have to use this part in a performance intensive part of my program and i'd have to transfer 3 big parameters, which is why i'd rather not use a method.
Is there another way to solve this?
if((test && firstCondition) || (!test && differentCondition)) {
//code
}
if ((test && first_condition) || (!test && different_condition)) {
callSomeFunction();
}
I'd do it like this:
// create an inline function to capture the
Action workAction = () => { //work; }
bool test = true;
if (test == true)
{
if(first condition) {workAction(); }
}
else
{
if(different condition) {workAction(); )
}
Depending on the complexity of the conditions, this approach can sometimes help:
bool doBigCall = false;
if (test1)
{
if (test2)
{
doBigCall = true;
}
else
{
// ...
}
}
else
{
// ...
}
if (doBigCall)
{
// write the big bit of code just once
}