c# Serialport data received event handler - multithreading

I am currently reading data from serialport using WPF. I am able to read data from serialport & write it in File using Binarywriter.
What Problem I am facing right now is:
I want to Analyse this data. I have developed one function which contains Use case structures to split the data which i read in serialport datahandler. Purpose is to Analyse captured data. But my program is just hanging on in receiving data from Serialport. Its not approaching down to Analyse the data.
This are few Options which i read from some Posts which may be a solution for my problem:
Backgroundworker: If yes then how i can fetch in my current program?
Threading: I tried it but its not working. My program is handing on writing the Bytes in the file & not going down to start the thread which i declared.
So can anybody suggest me a better option?
My code:
private void port_DataReceived(Object sender, SerialDataReceivedEventArgs e) {
BinaryWriter writer=new BinaryWriter(File.Open("c:\\temp\\lbus2snifflog1.txt", FileMode.Append));
int bytes=comport.Read(buffer, 0, 4096);
for (int i=0;
i < bytes;
i++) {
//writer.Write(buffer, 0, bytes); // Write the data to the file on temp folder
data.Enqueue(buffer[i]); // Enqueue data from the buffer
writer.Write(buffer, 0, bytes);
}
//writer.Write(buffer, 0, bytes);
writer.Flush(); // Send all remaining data to the writer
writer.Close(); // Close the writer
/*Initilaise the Thread for the Analysis*/
Thread Analyser=new Thread(datacollection);
Analyser.Start();
}

I think you should run thread with setting IsBackground = true;
I use it like that
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
//Do what you want to Run in background here
}).Start();
or maybe simple setting will do the job :
Analyser.IsBackground = true;
Analyser.Start();

Edit
For your case, don't know if this is best approach, but this may work.
You have a ConcurrentDictionary in main thread. In BackgroundWorker thread you get the data from the ConcurrentDictionary. Then you report to main thread the processed data.
Here is a working scenario.
Example:
class MyClass
{
private ConcurrentDictionary<int, string> serialPortsQueue =
new ConcurrentDictionary<int, string>();
private BackgroundWorker _worker;
public MyClass()
{
_worker = new BackgroundWorker()
{
WorkerSupportsCancellation = true,
WorkerReportsProgress = true
};
_worker.DoWork += DeviceDataAcquisition_DoWork;
_worker.ProgressChanged += DeviceDataAcquisition_ProgressChanged;
_worker.RunWorkerCompleted += DeviceDataAcquisition_RunWorkerCompleted;
_worker.RunWorkerAsync();
System.Diagnostics.Debug.WriteLine($"{DateTime.Now}: begin add first data");
serialPortsQueue.TryAdd(1, "data 1");
serialPortsQueue.TryAdd(2, "data 2");
serialPortsQueue.TryAdd(3, "data 3");
serialPortsQueue.TryAdd(4, "data 4");
serialPortsQueue.TryAdd(5, "data 5");
serialPortsQueue.TryAdd(6, "data 6");
serialPortsQueue.TryAdd(7, "data 7");
System.Diagnostics.Debug.WriteLine($"{DateTime.Now}: end add first data");
Thread.Sleep(2000);
System.Diagnostics.Debug.WriteLine($"{DateTime.Now}: begin add second data");
serialPortsQueue.TryAdd(8, "data 8");
System.Diagnostics.Debug.WriteLine($"{DateTime.Now}: end add second data");
}
private void DeviceDataAcquisition_DoWork(object sender, DoWorkEventArgs e)
{
// backgroundworker thread
if (sender is BackgroundWorker worker)
{
//just demo propose
int cnt = 0;
while (true)
{
if (worker.CancellationPending)
break;
if (serialPortsQueue.Count > 0)
{
KeyValuePair<int, string> kv = serialPortsQueue.ElementAt(0);
serialPortsQueue.TryRemove(kv.Key, out string value);
//just demo propose
// Simulate some processing
Thread.Sleep(1000);
worker.ReportProgress(0, kv);
//just demo propose
cnt++;
}
//just demo propose
if (cnt == 8)
break;
}
}
}
private void DeviceDataAcquisition_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// main thread
if (e.UserState is KeyValuePair<int, string> kv)
{
System.Diagnostics.Debug.WriteLine($"{DateTime.Now}: {kv.Key} -> {kv.Value}");
}
}
private void DeviceDataAcquisition_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (sender is BackgroundWorker worker)
{
worker.DoWork -= DeviceDataAcquisition_DoWork;
worker.ProgressChanged -= DeviceDataAcquisition_ProgressChanged;
worker.RunWorkerCompleted -= DeviceDataAcquisition_RunWorkerCompleted;
worker.Dispose(); // i think this does nothing...
System.Diagnostics.Debug.WriteLine($"{DateTime.Now}: end backgroundworker");
}
}
}
You can see in the window Output -> Debug the results.
Hope this helps.

Related

Multiple Backgroundworker threads in a single Backgroundworker thread

I have an issue here with multi-threading. Tried using both backgroundworker and threads.
Objective: Select an item from a combo-box and click a button to trigger multiple backup file restores into the MSSQL Server. The intention is to popup as many popups as there are Backup files to restore. The main window starts a backgroundworker, showing the overall progress, while the child threads result in non-modal child popups representing each restoration process with progress. This works fine if run serially (without threads/backgroundworker). My intention is to run a bunch of parallel popups, so that the restoration is much more quick.
Problem Statement: My intention is to run a bunch of parallel popups, so that the restoration is much more quick instead of running serially. While trying to debug, its a chaotic break-point show that the Visual Studio shows up (perhaps to represent multiple threads in parallel). But the ultimate goal is not being achieved. Can anybody help me in this regard?
- Code Extracts
Here is the code extract, which I've done and this works in a serial fashion. But as soon as I put the code for multi-threading, nothing works. Only the popups appear, but no processing happens.
This is the button click event, which starts the whole process
private void btnSnapshot_Click(object sender, EventArgs e)
{
this.SetPanelEnabledProperty(false); // Disable All Controls on the main window
// Select the text against which the DATABASE Backup Files are to be picked
// Start the main background worker process, which in turn will trigger few other child threads
BGWrk.RunWorkerAsync(2000);
BGWrk.DoWork += new DoWorkEventHandler(BGWrk_DoWork);
BGWrk.ProgressChanged += new ProgressChangedEventHandler(BGWrk_ProgressChanged);
BGWrk.RunWorkerCompleted += new RunWorkerCompletedEventHandler
(BGWrk_RunWorkerCompleted);
BackgroundWorker helperBW = sender as BackgroundWorker;
BGWrk.WorkerReportsProgress = true;
BGWrk.WorkerSupportsCancellation = true;
}
private void BGWrk_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker helperBW = sender as BackgroundWorker;
int arg = (int)e.Argument;
//Call the method that invokes the popup window instances in a loop, for each file found for the SnapShotName selected in the combobox
ParallelRestoreSnapshot();
if (helperBW.CancellationPending)
{
e.Cancel = true;
}
}
// This method will create backgroundworker instances and in turn the Do_Work events of those backgroundworkers will call the popup against each backup file.
private bool ParallelRestoreSnapshot()
{
FileOperations FIO = new FileOperations();
if (SelectedSnapShot != null && SelectedSnapShot != "None")
{
string[] sBakFiles;
sBakFiles = FIO.GetListOfBackupFiles(sEntireBackupFilePath);
try
{
progressPopupsList = new List<FrmProgressPopup>();
for (int aIndex = 0; aIndex < sBakFiles.Length; aIndex++)
{
BackgroundWorker bgPopups = new BackgroundWorker();
BAKFileName = sBakFiles[aIndex];
bgPopups.RunWorkerAsync(2000);
bgPopups.DoWork += new DoWorkEventHandler(bgPopups_DoWork);
bgPopups.ProgressChanged += new ProgressChangedEventHandler(bgPopups_ProgressChanged);
bgPopups.RunWorkerCompleted += new RunWorkerCompletedEventHandler
(bgPopups_RunWorkerCompleted);
bgPopups.WorkerReportsProgress = true;
bgPopups.WorkerSupportsCancellation = true;
}
retVal = true;
}
catch (Exception exc)
{
MessageBox.Show("Error while Restoring: " + exc.Message, "Exception encountered", MessageBoxButtons.OK, MessageBoxIcon.Error);
//goto NextDB;
return false;
}
}
FIO = null;
return retVal;
}
// This DoWork event calls a method GeneratePopupInstances which makes copies of a window, which is shown as non-modal
private void bgPopups_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker helperBW = sender as BackgroundWorker;
int arg = (int)e.Argument;
//BackgroundProcessLogicMethod(helperBW, arg);
GeneratePopupInstances();
if (helperBW.CancellationPending)
{
e.Cancel = true;
}
}

Speech recognition using SetInputToWaveFile ends prematurely

I want to do speech recognition of an audio file.
My code is pretty basic and derived from here. The problem is that it stops with every wave file prematurely after a few seconds even though some wave files are hours long.
How to make it scan the whole file?
namespace Stimmenerkennung
{
public partial class Form1 : Form
{
//...
Thread erkennung;
bool completed;
private void Form1_Load(object sender, EventArgs e)
{
erkennung = new Thread(erkennen);
erkennung.Start();
}
void erkennen()
{
using (SpeechRecognitionEngine recognizer =
new SpeechRecognitionEngine())
{
// Create and load a grammar.
Grammar dictation = new DictationGrammar();
dictation.Name = "Dictation Grammar";
recognizer.LoadGrammar(dictation);
// Configure the input to the recognizer.
recognizer.SetInputToWaveFile(#"REC01.wav");
// Attach event handlers for the results of recognition.
recognizer.SpeechRecognized +=
new EventHandler<SpeechRecognizedEventArgs>(recognizer_SpeechRecognized);
recognizer.RecognizeCompleted +=
new EventHandler<RecognizeCompletedEventArgs>(recognizer_RecognizeCompleted);
// Perform recognition on the entire file.
db("Starting asynchronous recognition...");
recognizer.RecognizeAsync();
while (!completed)
{
//fs((int)(100 / recognizer.AudioPosition.TotalSeconds * recognizer.AudioPosition.Seconds));
db(recognizer.AudioState.ToString());
Thread.Sleep(100);
}
}
}
// Handle the SpeechRecognized event.
void recognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
if (e.Result != null && e.Result.Text != null)
{
db(e.Result.Text);
}
else
{
db(" Recognized text not available.");
}
}
// Handle the RecognizeCompleted event.
void recognizer_RecognizeCompleted(object sender, RecognizeCompletedEventArgs e)
{
if (e.Cancelled)
{
db(" Operation cancelled.");
}
if (e.InputStreamEnded)
{
db(" End of stream encountered.");
}
completed = true;
}
void db(string t)
{
this.textBox1.Invoke((MethodInvoker)delegate
{
textBox1.Text = textBox1.Text + Environment.NewLine + t;
//textBox1.Text = t;
});
}
}
}
You can split the file on few seconds chunks by the silences and feed the chunk to the recognizer separately. Then you can combine results into a single string.
You can use any voice activity detection implementation to perform the split, a simple energy-based VAD which calculate frame energy will be sufficient.
You can find some existing implementations of the VAD in CMUSphinx projet

E_SCN_READINCOMPATIBLE Notification error thrown while scanning bar code on MC9090G

I'm using EMDK 2.5 (VS2008 and VC# and .NetCF3.5) Barcode2 class from the library to write a sample application to scan bar codes. I followed the samples available in EMDK namely CS_Barcode2Sample1 project.Every time I hardware trigger the scan the notification "E_SCN_READINCOMPATIBLE" is thrown and not able to retrieve the scanned data. The documentation doesn't say much about the cause of E_SCN_READINCOMPATIBLE notification and no luck from Google search. I tried several options including making use of Symbol.Barcode and the outcome is same.
I also tried EMDK 2.3 but the result is same.
I've pasted the whole code here....
public partial class Form1 : Form
{
private Barcode2 myBarcode2 = null;
public Form1()
{
InitializeComponent();
InitBarcode();
}
public bool InitBarcode()
{
// If the Barcode2 object is already initialized then fail the initialization.
if (myBarcode2 != null)
{
return false;
}
else // Else initialize the reader.
{
try
{
Symbol.Barcode2.Device[] AvailableDevices = Symbol.Barcode2.Devices.SupportedDevices;
if (AvailableDevices.Length == 0)
{
return false;
}
if (AvailableDevices.Length == 1)
{
//get the first available scanner in the list
Symbol.Barcode2.Device MyDevice = AvailableDevices[0];
// Create the reader, based on selected device.
myBarcode2 = new Barcode2(MyDevice);
// Attach a scan notification handler.
//this.myScanNotifyHandler = new Barcode2.OnScanHandler(myBarcode2_ScanNotify);
myBarcode2.OnScan += myBarcode2_ScanNotify;
// Attach a status notification handler.
//this.myStatusNotifyHandler = new Barcode2.OnStatusHandler(myBarcode2_StatusNotify);
myBarcode2.OnStatus += myBarcode2_StatusNotify;
myBarcode2.Config.TriggerMode = TRIGGERMODES.HARD;
// Submit a scan.
myBarcode2.Scan(5000);
}
}
catch (OperationFailureException ex)
{
MessageBox.Show("Exception Raised 1");
return false;
}
catch (InvalidRequestException ex)
{
MessageBox.Show("Exception Raised 2");
return false;
}
catch (InvalidIndexerException ex)
{
MessageBox.Show("Exception Raised 3");
return false;
}
}
return false;
}
private void myBarcode2_ScanNotify(ScanDataCollection scanDataCollection)
{
// Checks if the BeginInvoke method is required because the OnScan delegate is called by a different thread
if (this.InvokeRequired)
{
// Executes the OnScan delegate asynchronously on the main thread
this.BeginInvoke(new Barcode2.OnScanHandler(myBarcode2_ScanNotify), new object[] { scanDataCollection });
}
else
{
// Get ScanData
ScanData scanData = scanDataCollection.GetFirst;
int i;
switch (scanData.Result)
{
case Symbol.Barcode2.Results.SUCCESS:
String str = scanData.Text;
myBarcode2.Config.TriggerMode = TRIGGERMODES.HARD;
myBarcode2.Scan(5000);
break;
case Symbol.Barcode2.Results.E_SCN_READTIMEOUT:
break;
case Symbol.Barcode2.Results.CANCELED:
break;
case Symbol.Barcode2.Results.E_SCN_DEVICEFAILURE:
i = 93;
break;
default:
if (scanData.Result == Symbol.Barcode2.Results.E_SCN_READINCOMPATIBLE)
{
// If the failure is E_SCN_READINCOMPATIBLE, exit the application.
MessageBox.Show("Fatal Error");
this.Close();
return;
}
break;
}
}
}
private void myBarcode2_StatusNotify(StatusData statusData)
{
// Checks if the Invoke method is required because the OnStatus delegate is called by a different thread
if (this.InvokeRequired)
{
// Executes the OnStatus delegate on the main thread
this.Invoke(new Barcode2.OnStatusHandler(myBarcode2_StatusNotify), new object[] { statusData });
}
else
{
int i;
switch (statusData.State)
{
case States.IDLE:
break;
case States.READY:
break;
default:
break;
}
}
}
}
}
I've went thru this recently also, as I observed, it probably due to the scanner device is occupied by other application, where the scan request has been queued already, you can go to memory management, and kill the suspect app, and try your app again.
Refer to the Symbol FAQ

How to grab value from a thread?

Hi i am trying to grab a value from my threading but it seem work not so find to me course i found that my code structure are unstable enough..here is my code i name my thread class as "clsThreadCount" and below is my implementation
public volatile bool Grab = false;
public volatile int count = 0;
public void Initialization(int i)
{
count = i;
}
public void Play()
{
Grab = false;
_shouldStop = false;
ThreadTest();
}
public void Stop()
{
_shouldStop = true;
workerThread.Join(1);
workerThread.Abort();
}
private void ThreadTest()
{
workerThread = new Thread(DoWork);
workerThread.Start();
while (!workerThread.IsAlive) ;
}
private void DoWork()
{
try
{
while (!_shouldStop)
{
if (Grab)
{
count++;
Grab = false;
}
}
}
catch (Exception)
{
Play();
}
finally
{
}
}
when my program(main menu) are starting to run i will trigger the initialize function at pass the parameter as 7
ObjThreadCount.Initialization(7); // count = 7
ObjThreadCount.Play(); // the thread are running
ObjThreadCount.Grab = true; // the grab equal to true, count++ are trigger
Thread.Sleep(100); // wait awhile
lblResult.Text = ObjThreadCount.count.ToString(); // sometime i can get count++ result (e.g. 8)
ObjThreadCount.Stop(); // thread stop
sometime my program can able to get a right counting from the thread but sometime are not.
i realize at my while loop implementation there are something are missing..
something like waitone or waitautoevent..can i ignore Thread.Sleep(100) ?? what are the suitable code should i add in the while loop ?
Please help me~ :S
** sorry in the first upload i forgot to write down "volatile" into the variable
thank you..
If C# (and C and java, and probably C++), you need to declare _shouldStop and Grab as volatile.

C# powershell output reader iterator getting modified when pipeline closed and disposed

I'm calling a powershell script from C#. The script is pretty small and is "gps;$host.SetShouldExit(9)", which list process, and then send back an exit code to be captured by the PSHost object.
The problem I have is when the pipeline has been stopped and disposed, the output reader PSHost collection still seems to be written to, and is filling up. So when I try and copy it to my own output object, it craps out with a OutOfMemoryException when I try to iterate over it. Sometimes it will except with a Collection was modified message. Here is the code.
private void ProcessAndExecuteBlock(ScriptBlock Block)
{
Collection<PSObject> PSCollection = new Collection<PSObject>();
Collection<Object> PSErrorCollection = new Collection<Object>();
Boolean Error = false;
int ExitCode=0;
//Send for exection.
ExecuteScript(Block.Script);
// Process the waithandles.
while (PExecutor.PLine.PipelineStateInfo.State == PipelineState.Running)
{
// Wait for either error or data waithandle.
switch (WaitHandle.WaitAny(PExecutor.Hand))
{
// Data
case 0:
Collection<PSObject> data = PExecutor.PLine.Output.NonBlockingRead();
if (data.Count > 0)
{
for (int cnt = 0; cnt <= (data.Count-1); cnt++)
{
PSCollection.Add(data[cnt]);
}
}
// Check to see if the pipeline has been closed.
if (PExecutor.PLine.Output.EndOfPipeline)
{
// Bring back the exit code.
ExitCode = RHost.ExitCode;
}
break;
case 1:
Collection<object> Errordata = PExecutor.PLine.Error.NonBlockingRead();
if (Errordata.Count > 0)
{
Error = true;
for (int count = 0; count <= (Errordata.Count - 1); count++)
{
PSErrorCollection.Add(Errordata[count]);
}
}
break;
}
}
PExecutor.Stop();
// Create the Execution Return block
ExecutionResults ER = new ExecutionResults(Block.RuleGuid,Block.SubRuleGuid, Block.MessageIdentfier);
ER.ExitCode = ExitCode;
// Add in the data results.
lock (ReadSync)
{
if (PSCollection.Count > 0)
{
ER.DataAdd(PSCollection);
}
}
// Add in the error data if any.
if (Error)
{
if (PSErrorCollection.Count > 0)
{
ER.ErrorAdd(PSErrorCollection);
}
else
{
ER.InError = true;
}
}
// We have finished, so enque the block back.
EnQueueOutput(ER);
}
and this is the PipelineExecutor class which setups the pipeline for execution.
public class PipelineExecutor
{
private Pipeline pipeline;
private WaitHandle[] Handles;
public Pipeline PLine
{
get { return pipeline; }
}
public WaitHandle[] Hand
{
get { return Handles; }
}
public PipelineExecutor(Runspace runSpace, string command)
{
pipeline = runSpace.CreatePipeline(command);
Handles = new WaitHandle[2];
Handles[0] = pipeline.Output.WaitHandle;
Handles[1] = pipeline.Error.WaitHandle;
}
public void Start()
{
if (pipeline.PipelineStateInfo.State == PipelineState.NotStarted)
{
pipeline.Input.Close();
pipeline.InvokeAsync();
}
}
public void Stop()
{
pipeline.StopAsync();
}
}
An this is the DataAdd method, where the exception arises.
public void DataAdd(Collection<PSObject> Data)
{
foreach (PSObject Ps in Data)
{
Data.Add(Ps);
}
}
I put a for loop around the Data.Add, and the Collection filled up with 600k+ so feels like the gps command is still running, but why. Any ideas.
Thanks in advance.
Found the problem. Named the resultant collection and the iterator the same, so as it was iterating, it was adding to the collection, and back into the iterator, and so forth. Doh!.

Resources