Receiving only different values from serial port - c#

I have a project like a registration system using RFID. When user enabled registration mode, each card shown should be saved only once. For this, I am using an array and then checking the same code in array to see if it exists already. But I have a problem with incrementing the array index.
in class Form1, i have the initializations:
string rx_data = "";
string last_data = "";
string[] availablePlayers = {""};
int plIndex = 0;
In the code below, if I use plIndex, it receives only the first card and seems like it stops calling this handler again.
public void WriteRxData(object sender, SerialDataReceivedEventArgs e)
{
if (connection.IsOpen && !cardSaveCon.IsOpen)
{
try
{
rx_data = connection.ReadLine(); // check how the data ends
if (!availablePlayers.Any(rx_data.Contains))
{
availablePlayers[plIndex] = rx_data;
receivedData.AppendText(rx_data);
plIndex++;
}
}
catch (Exception err)
{
connection.Close();
}
}
But instead, If I use a hardcoded index value, it works. I would like to know how to handle this since this had to work for other languages. I am new to c#, so there may be some parts that I am missing.

availablePlayers[plIndex] = rx_data;
This will crash your code the second time you receive a string. Unfortunately you are also catching the IndexOutOfRangeException and close the port. Which will completely deadlock the code, SerialPort.Close() can only complete when the event handler has returned.
Specific counter-measures:
use a List<string> instead of a string[]
remove try/catch from your code, it cannot ever do anything but make your program fail without a way to recover
write an event handler for AppDomain.CurrentDomain.UnhandledException to provide a diagnostic when your program dies on unexpected exceptions
get familiar with the Debug + Windows + Threads debugger window. It allows you to see what's going on in other threads, you would have seen the deadlock.

Related

Catch ArgumentOutOfRangeException

I have a function that is run once every second by a timer. The purpose of the function is to request data through an API and then update a list and some textboxes with the results. For the most part it runs like clockwork, but every couple of hours I get an ArgumentOutOfRangeException.
For whatever reason, either that one API request fails or the list doesn't update fast enough. Either way the function tries to update texboxes and variables using an empty list, hence the ArgumentOutOfRangeException.
Now this data is mostly not being stored for any length of time, and the function would just run again in another second anyway if not for the error popping up and stalling everything. I hadn't used C# before I made this program so I'm not sure how best to utilize the "catch" statement to just make the program ignore it and keep going. Actually it would be good if the number of failures was logged in an integer variable so that the program could determine if something was actually wrong instead of just a momentary glitch. How would you write the catch statement for this?
try
{
GetQuoteResponse resp = GetQuoteResponse.GetQuote(questradeToken, quotesSymbolIds);
List<Level1DataItem> quotes = resp.Quotes;
QuoteStream_Data.Clear();
for (int i = 0; i < quotes.Count; ++i)
{
Level1DataItem quote = quotes[i];
QuoteStream_Data.Add(new QuoteStream_Entry { lastTradePrice = Convert.ToDecimal(quote.m_lastTradePrice)});
}
XIVPriceBox.Invoke(new Action(() => XIVPriceBox.Text = QuoteStream_Data[0].lastTradePrice.ToString()));
HVIPriceBox.Invoke(new Action(() => HVIPriceBox.Text = QuoteStream_Data[1].lastTradePrice.ToString()));
TVIXPriceBox.Invoke(new Action(() => TVIXPriceBox.Text = QuoteStream_Data[2].lastTradePrice.ToString()));
XIVCurrentPrice = QuoteStream_Data[0].lastTradePrice;
TVIXCurrentPrice = QuoteStream_Data[2].lastTradePrice;
}
catch
{
}
try
{
// ...
}
catch(ArgumentOutOfRangeException ex)
{
LogException(ex);
}

C# BackgroundWorker Exiting Unexpectedly

I have thef ollowing background worker in my app which is meant to start a user's session automatically if there is not already one available.
This is done on a backgroundworker (backgroundInit) on initialisation. As you can see below, I have a while loop which continues to run as long as the var checker remains false:
var checker = false;
var i = 0;
while (checker == false)
{
_session = funcs.GetSession(_servers, _name);
_sessID = _session[0].Trim();
_servName = _session[1];
checker = funcs.CheckRunning("lync.exe");
i++;
if (i > 200)
{
break;
}
}
The CheckRunning method just checks if a specified program (in this case, "lync") is currently running and returns either true or false accordingly (This is done via a CMD command).
When I run the app in an empty session however, the while loop only iterates one time before breaking out, even though "Lync" is definitely not running.
Is there any reason why running a process or too many processes from within a Backgroundworker may cause it to exit?
As the comments mentioned, this was not an issue with the BackgroundWorker, but rather an exception occurring at _sessID = session[0].Trim(); where the session had not yet started, so there is no ID.
To resolve this, I simply placed a Try/Catch block around this assignment, and let the program silently ignore the exception:
try
{
_sessID = _session[0].Trim();
_servName = _session[1];
}
catch (Exception exp)
{
// MessageBox.Show(exp.Message);
}
This works for me, as the loop will continue checking until the counter i reaches the 200 limit, at which stage the program will accept failure.

Backgroundworker Stops Working

I have a WPF project that uses background workers to interfaces with some external hardware (Test & Measure equipment, etc), write to local files, and insert data into a database as it runs. Program flow is basically sequential, the background workers in use are to keep the GUI accessible for the user, and were chosen because I haven't had issues with using them before. We take measurements, do some stuff, log, then repeat. There is a status log on the GUI that displays messages as we go.
All of this works beautifully for hours on end, however, eventually, without fail, it appears that the background worker used to write to the database never calls DoWork.
BackgroundWorker DbLogWorker = new BackgroundWorker();
...
DbLogWorker.DoWork +=
new DoWorkEventHandler(DbLogWorker_DoWork);
DbLogWorker.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(
DbLogWorker_RunWorkerCompleted);
ProcessScanData is called when data has been retrieved from one of the pieces of hardware, setting a property and firing a generic property changed event
(disclaimer: some extra code everywhere as I was investigating to see whats going on):
private void Data_DataSetChanged(object pSender, EventArgs pArgs)
{
this.Test.ProcessScanData(OsaVm.Osa.Data.DataSet);
}
...
public void ProcessScanData(SortedList<double,double> pData)
{
...
RaiseLogEvent(MessageType.SystemGeneral, "Logging to database...");
DbLogWorker.RunWorkerAsync(new AsyncDbLogArgs(CurrentChannel, tempdate,
loss1, loss2, loss3,
CurrentTemperature, CurrentPressure, CurrentRoomTemp));
}
private void DbLogWorker_DoWork(object pSender, DoWorkEventArgs pArgs)
{
AsyncDbLogArgs args = (AsyncDbLogArgs)pArgs.Argument;
string filename = string.Empty;
try
{
long datakey = Db.LogScan(CurrentChannel, args.Time,
args.Temperature, args.Pressure, args.RoomTemperature,
args.Loss1, args.Loss2, args.Loss3);
filename = args.Time.ToString(FOLDER_DATETIME_FORMAT) + "_[" + datakey.ToString() + "]";
}
catch (Exception ex)
{
filename = args.Time.ToString(FOLDER_DATETIME_FORMAT) + "_{" + (fileindex++) + "}";
}
pArgs.Result = new Tuple<AsyncDbLogArgs, string>(args, filename);
}
Symptoms:
Everything works fine for anywhere between 1 hour and ~16 hours until eventually we get to a point where we see "Logging to database..." and nothing else ever happens. No more messages, no exceptions (release build on target machine), no database entry...etc. This happens consistently.
I've been scratching my head on this for a while. Any leads will help, I have some workarounds in mind but I'd really like to know whats going on so I can avoid this in the future.
Thanks
Edited back to original code...thought the most recent would help avoid some "how do you know its not firing" questions

Stack overflow error in console application

I currently have a console application written in C# for production server environment. It's quite simple, but I've been testing it for +- 3 months now on my own server (semi-production, but not a disaster if the program fails). I've been getting stack overflow errors every few weeks or so, though.
Of course, pasting my entire source code here would be quite a long piece, so I will try to explain it the best I can: the program is in an infinite while loop (this is probably the cause of the issue), and it checks every second a few small things and prints to the console every so often (if no activity, every 15min, otherwise up-to every second).
Now why and how can I fix the stack overflow errors? Being able to run it for a couple weeks without issue may seem like a lot, but it is obviously not in a server production environment. My guess is that it's the fact I'm using a while loop, but what alternatives do I have?
Edit: here's a portion of the code:
int timeLoop = 0;
while (true)
{
// If it has been +-10min since last read of messages file, read again
if (timeLoop > 599)
{
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss") + " Reading messages...");
messagesFile = File.ReadAllText(#"messages.cfg");
messages = messagesFile.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
timeLoop = 0;
}
// For each message, check if time specified equals current time, if so say message globally.
foreach (string x in messages)
{
string[] messageThis = x.Split('~');
int typeLoop = 0;
if (messageThis[2] != "no-loop")
typeLoop = Convert.ToInt16(messageThis[2].Remove(0, 5));
DateTime checkDateTime = DateTime.ParseExact(messageThis[0], "HH:mm:ss", null);
if (typeLoop == 0)
{
if (checkDateTime.ToString("HH:mm:ss") == DateTime.Now.ToString("HH:mm:ss"))
publicMethods.sayGlobal(messageThis[1]);
}
else
{
DateTime originalDateTime = checkDateTime;
do
{
checkDateTime = checkDateTime.AddHours(typeLoop);
if (checkDateTime.ToString("HH:mm:ss") == DateTime.Now.ToString("HH:mm:ss"))
publicMethods.sayGlobal(messageThis[1]);
} while (checkDateTime.ToString("HH:mm:ss") != originalDateTime.ToString("HH:mm:ss"));
}
}
timeLoop++;
Thread.Sleep(1000);
}
Also, I forgot that I actually have this code on Github, which probably helps a lot. I know you shouldn't be using any links to code and have them here, so that's why I included the snippet above - but if you are interested in helping me out the repository is located here. Another note - I know that doing it like this is not very accurate on timing - but this is not much of an issue at the moment.
BattleEyeClient.Connect can call itself in some (failing) circumstances, and this method can be called by sayGlobal - so you probably want to change this code block (from line 98):
catch
{
if (disconnectionType == BattlEyeDisconnectionType.ConnectionLost)
{
Disconnect(BattlEyeDisconnectionType.ConnectionLost);
Connect();
return BattlEyeConnectionResult.ConnectionFailed;
}
else
{
OnConnect(loginCredentials, BattlEyeConnectionResult.ConnectionFailed);
return BattlEyeConnectionResult.ConnectionFailed;
}
}
Maybe keep track of how many reconnection attempts you make or transform this section of code so that it is a while loop rather than a recursive call during this failure mode.
Even worse, of course, is if that recursive Connect call succeeds, this catch block then returns BattlEyeConnectionResult.ConnectionFailed which it probably shouldn't.

How to wait for an Autoreset event to occur before taking any other action?

This is about the AutoResetEvent in C#. I tried to read other answers but I could not make sense and apply to my scenario. I am not writing any threading application. Just a small application to read/validate a file and update.
So I have this requirement to write some code for reading a fixed length file, validating it and then if it is valid upload it to Database.
I got everything working until I got stuck with the AutoResetEvent. So here is what is happening. Once the data is parsed/read I validate it using Flat File Checker utility in C#. So I called the functions into my application. Here is the snippet.
private AutoResetEvent do_checks = new AutoResetEvent(false);
public bool ValidationComplete = false;
This part goes in initialization code:
this._files.Validated += new EventHandler<SchemaValidatedEventArgs>(FileSetValidated);
public bool ValidateFile()
{
try
{
RunValidation();
return true;
}
catch (Exception e)
{
log.Error("Data Validation failed because :" + e.Message);
return false;
}
}
private void RunValidation()
{
// Use Flat File Checker user interface to create Schema file.
do_checks = _files.RunChecks();
log.Debug("Validation Started");
}
This is the method that is getting called asnchronusly during the validation process:
public void FileSetValidated(Object sender, SchemaValidatedEventArgs e)
{
try
{
ValidationComplete = e.Result;
if (IsDataValid)
{
log.Debug("Data is validated and found to be valid.");
}
else
{
log.Debug("Data is validated and found to be Invalid");
}
}
finally
{
do_checks.Set();
}
}
What is happening is that even before I get any value set into ValidationComplete the code is checked for Validation complete and because it is set by default to false, it returns false. The code in the FileSetValidated gets executed after that so the database update never happens.
The reason is that I cannot change the code because the Flat File Checker only accepts an AutoResetEvent as a return variable in RunChecks method.
******Here is what I did now*******
private AutoResetEvent do_checks;
public bool ValidateFile()
{
try
{
string extFilePath = surveyFile.ExtFilePath;
File.Copy(extFilePath, localTempFolder + "ExtractFile.Dat");
RunValidation();
if (!do_checks.WaitOne(TimeSpan.FromSeconds(30))) {
// throw new ApplicationException("Validation took more than expected!");
}
return true;
}
catch (Exception e)
{
log.Error("Data Validation failed because :" + e.Message);
return false;
}
}
private void RunValidation()
{
// Use Flat File Checker user interface to create Schema file.
do_checks = _files.RunChecks();
do_checks.WaitOne();
log.Debug("Validation Started");
}
Also I moved the part where data about validation gets passed on towards the beginning of the event handler so atleast that part gets executed. This helped but I am not sure if it is correct.
I have never worked with that lib, so I just downloaded it and looked into the code.
First of all, as "500 - Internal Server Error" already mentioned, it seems that part of the code is missing, at least "try" in the FileSetValidated method. I don't see any place where you are waiting for the event via WaitOne.
You don't need to create do_checks by yourself, because _files.RunChecks() creates AutoResetEven for this particular file's processing. So if you are using the same field for that event - you will get issue if you will need to process few files at the same time. So keep separate event for each file, in any case I don't see reason to keep that references as members if you don't want to stop processing in the middle (if you will call do_checks.Set() during processing, it will cancel processing without finishing it).
As I see in the lib code, you should not call do_checks.Set() in the FileSetValidated method, because it will be set, once processing will be done, so you can just write:
var do_checks = _files.RunChecks();
do_checks.WaitOne();
Feel free to share if that helped.
UPDATE:
I am not able to check that lib now to undestand why do_checks is set after starting processing, but I can suggest you to use your initial code with next RunValidation method:
private void RunValidation()
{
do_checks.Reset(); //reset state
_files.RunChecks(); //don't store event from the lib
log.Debug("Validation Started");
do_checks.WaitOne(); //Wait for FileSetValidated to set this event
}
Before exiting the ValidateFile function you need to wait for the validation to complete (wait on the AutoResetEvent) and return the validation result.
Try something like this:
public bool ValidateFile()
{
//try
{
RunValidation();
//Allocate enough time for the validation to occur but make sure
// the application doesn't block if the _files.Validated event doesn't get fired
if(!do_checks.WaitOne(TimeSpan.FromSeconds(10)))
{
throw ApplicationException("Validation took more than expected!");
}
return ValidationComplete;
}
//I would not catch the exception since having an error doesn't mean that the file
//is invalid. Catch it upper in the call stack and inform the user that the validation
//could not be performed because of the error
//catch (Exception e)
//{
// log.Error("Data Validation failed because :" + e.Message);
// return false;
//}
}

Categories

Resources