Why the number of threads is continuously increasing with SerialPort.CatchReceivedEvents() - c#

I´m running a C# application with .NET Framework 2.0 to read data from SerialPort to get the weight from a scale.
The application works fine, does what it is supposed to do, but the number of threads keeps increasing and more memory is consumed until the application crashes, usually after around 4 hours.
When running with a serialport simulator the number of threads is stable around 30. But when I use an actual scale it goes greater than 500 threads.
I used Microsoft Managed Stack Explorer 1.0 to take a dump of the threads and almost all of them have exactly the following stack:
0. System.IO.Ports.SerialPort.CatchReceivedEvents (Source Unavailable)
1. System.IO.Ports.SerialStream.EventLoopRunner.CallReceiveEvents (Source Unavailable)
2. System.Threading._ThreadPoolWaitCallback.WaitCallback_Context (Source Unavailable)
3. System.Threading.ExecutionContext.Run (Source Unavailable)
4. System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal (Source Unavailable)
5. System.Threading._ThreadPoolWaitCallback.PerformWaitCallback (Source Unavailable)
I'm not able to identify the reason these threads are being created. Does anybody have any idea of what I'm missing here? Thanks!
This is my code:
Scale.cs -> creates a thread when method open() is called. The thread reads the value from getWeight().
Scales.cs -> treats events from serial port in method SerialPort_DataReceived(...). It's where m_SerialPort.ReadLine() is called and ends up providing the value to getWeight().
Scale.cs:
using System;
using System.Collections.Generic;
using System.Threading;
using ScalesGSS;
using StateMachine.Exceptions;
using StateMachine.Log;
using StateMachine.MessageOutput;
namespace StateMachine.DriverImplementation
{
class Scale : AScale
{
private const int Scale_version = 1;
private Thread thread = null;
private IScales gScale = null;
//
private string m_Type;
private string m_PortName;
private int m_BaudRate;
private char m_Parity;
private int m_DataBits;
private string m_StopBits;
private int m_CommandReturnLength;
private string m_CommandType;
private string m_CommandValue;
private int m_ReadTimeOutInMilliseconds;
private int m_WeightInitialPosition;
private int m_WeightFinalPosition;
private int m_TimeBetweenReadsInMilliseconds;
private int m_StableReadQuantity;
private int m_MinimumWeight;
private int m_ScaleID;
//
private double m_OldWeight = 0.0;
private double m_Offset = 0.0;
private double m_CurrentWeight = 0.0;
int m_WeightEqualCount = 0;
//
byte m_Status = 3; // "NO COMMUNICATION"
//
private bool m_Closed = false;
private static LogFactory m_Log = new LogFactory(LogCategory.Device, "");
ErrorDialog m_ErrorDialog = new ErrorDialog();
public Scale()
{
this.setClassName("Scale");
this.setDeviceType(DeviceType.Scale);
}
public void run()
{
try
{
if (this.m_Type.ToUpper().Equals("GENERICSCALES")) // GENERICSCALES or MOCKSCALES
this.gScale = new ScalesGSS.GenericScales();
else
this.gScale = new ScalesGSS.MockScales();
this.gScale.PortName = this.m_PortName;
this.gScale.BaudRate = this.m_BaudRate;
this.gScale.Parity = this.m_Parity.ToString();
this.gScale.DataBits = this.m_DataBits;
this.gScale.StopBits = this.m_StopBits;
this.gScale.CommandReturnLength = this.m_CommandReturnLength;
this.gScale.CommandType = this.m_CommandType;
this.gScale.CommandValue = this.m_CommandValue;
this.gScale.ReadTimeOut = this.m_ReadTimeOutInMilliseconds;
this.gScale.WeightInitialPosition = this.m_WeightInitialPosition;
this.gScale.WeightFinalPosition = this.m_WeightFinalPosition;
this.gScale.setParameters();
this.gScale.configurePort();
while (true)
{
if (this.m_Closed)
{
if (this.OpenedPort())
this.gScale.closePort();
break;
}
Thread.Sleep(this.m_TimeBetweenReadsInMilliseconds);
if (!this.OpenedPort())
{
if (!this.OpenPort())
{
m_Log.writeLogWarning("Error opening serialport.", " Port: " + this.m_PortName, true);
}
}
if (this.ErrorReadingWeight())
{
m_Log.writeLogWarning("Invalid weight.", " Port: " + this.m_PortName, true);
}
this.m_CurrentWeight = getWeight();
if (!ReadingTimeout())
{
if (this.m_WeightEqualCount > m_StableReadQuantity)
{
if (m_CurrentWeight > m_MinimumWeight)
m_Status = 2; // "WEIGHT STABLE"
else
{
m_Status = 0; // "SCALE FREE"
m_WeightEqualCount = 0;
}
}
else
{
if (m_CurrentWeight > m_MinimumWeight)
{
m_Status = 1; // "STABILIZING"
if ((this.m_CurrentWeight >= (this.m_OldWeight - this.m_Offset)) && (this.m_CurrentWeight <= (this.m_OldWeight + this.m_Offset)))
this.m_WeightEqualCount++;
else
this.m_WeightEqualCount = 0;
this.m_OldWeight = this.m_CurrentWeight;
}
else
{
m_Status = 0; // "SCALE FREE"
m_WeightEqualCount = 0;
}
}
}
else
{
m_WeightEqualCount = 0;
m_Status = 3; // "NO COMMUNICATION"
string v_Message = "No communication with scale. Port: " + m_PortName;
m_Log.writeLogWarning(v_Message, "", true);
AutoClosingMessageBox.Show(v_Message, "Scale", 10000);
}
}
}
catch (Exception v_Exception)
{
m_Log.writeLogError("run()", v_Exception);
}
}
private bool OpenedPort()
{
return this.gScale.OpenedPort;
}
private bool OpenPort()
{
bool v_OpenPort;
v_OpenPort = this.gScale.openPort();
if (!v_OpenPort)
{
m_ErrorDialog.getScaleErrorMessage(gScale);
}
return v_OpenPort;
}
private bool ErrorReadingWeight()
{
return this.gScale.ErrorReadingWeight;
}
private double getWeight()
{
return this.gScale.getWeight();
}
private DateTime LastGoodReading()
{
return gScale.LastGoodReading;
}
private void setLastGoodReading(DateTime p_Value)
{
gScale.LastGoodReading = p_Value;
}
private bool ReadingTimeout()
{
if (m_ReadTimeOutInMilliseconds > 0)
{
DateTime v_LastGoodReading = LastGoodReading() == DateTime.MinValue ? DateTime.Now : LastGoodReading();
setLastGoodReading(DateTime.Now);
return DateTime.Now > v_LastGoodReading.AddMilliseconds(m_ReadTimeOutInMilliseconds);
}
else
return false;
}
#region "IDriverService"
public override byte getStatus()
{
return m_Status;
}
public override byte[] read()
{
return System.Text.ASCIIEncoding.ASCII.GetBytes(m_CurrentWeight.ToString());
}
public override byte[] read(int p_InitialPosition, int p_Size)
{
return read();
}
public override byte[] write(byte[] p_Data)
{
string v_Temp = System.Text.ASCIIEncoding.ASCII.GetString(p_Data);
if (v_Temp.Equals("getScaleNumber"))
return System.Text.ASCIIEncoding.ASCII.GetBytes(m_ScaleID.ToString());
else
throw new EDriverAccess(1, "Not implemented");
}
public override bool open()
{
this.thread = new Thread(run);
this.thread.Name = "SCALE";
this.thread.IsBackground = true;
this.thread.Start();
return true;
}
public override bool close()
{
try
{
this.release();
return true;
}
catch
{
return false;
}
}
public override int getVersion()
{
return Scale_version;
}
public override void setProperties(Dictionary<string, string> p_props)
{
try
{
this.m_Type = p_props["type"];
this.m_PortName = p_props["portName"];
this.m_BaudRate = Int32.Parse(p_props["baudRate"]);
this.m_Parity = char.Parse(p_props["parity"]);
this.m_DataBits = Int32.Parse(p_props["dataBits"]);
this.m_StopBits = p_props["stopBits"];
this.m_CommandReturnLength = Int32.Parse(p_props["returnLength"]);
this.m_CommandType = p_props["commandType"];
this.m_CommandValue = p_props["commandValue"];
this.m_ReadTimeOutInMilliseconds = Int32.Parse(p_props["readTimeout"]);
this.m_WeightInitialPosition = Int32.Parse(p_props["weightInitPos"]);
this.m_WeightFinalPosition = Int32.Parse(p_props["weightFinPos"]);
this.m_TimeBetweenReadsInMilliseconds = Int32.Parse(p_props["delayLeitura"]);
this.m_StableReadQuantity = Int32.Parse(p_props["qtdeLeituraEstavel"]);
this.m_MinimumWeight = Int32.Parse(p_props["pesoMinimo"]);
this.m_ScaleID = Int32.Parse(p_props["numBalanca"]);
if (p_props.ContainsKey("precision"))
this.m_Offset = Int32.Parse(p_props["precision"]);
}
catch (Exception)
{
throw new Exception();
}
}
public override void release()
{
this.m_Closed = true;
m_Status = 3; // "NO COMMUNICATION"
}
#endregion
}
}
Scales.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Reflection;
using System.Timers;
using Scales.Util;
namespace Scales.DLL
{
public class Scales : Status
{
public event EventHandler StableWeightChanged;
protected virtual void OnCountdownCompleted(EventArgs e)
{
if (StableWeightChanged != null)
StableWeightChanged(this, e);
}
System.Timers.Timer timerTimeWithoutSample;
private int m_IntervalsWithoutSample = 0;
private string m_EndOfWeightChar = "";
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
m_IntervalsWithoutSample++;
}
public int IntervalsWithoutSample { get { return m_IntervalsWithoutSample; } }
private SerialPort m_SerialPort;
public string PortName { get; set; }
public int BaudRate { get; set; }
public int DataBits { get; set; }
private Double m_Weight = 0;
public Double Weight
{
get
{
if (m_BufferWeights.Count > 0)
{
try
{
m_Weight = treatReceivedValue(m_BufferWeights[m_BufferWeights.Count - 1]);
}
catch
{
}
finally
{
ErrorReadingWeight = (m_Weight != -1 ? false : true);
}
}
else
{
m_Weight = 0;
}
return m_Weight;
}
}
public List<Double> getAndFlushPastWeights()
{
List<Double> v_FlushedValues = new List<double>();
Double v_WeightCursor;
while (m_BufferWeights.Count > 1 && v_FlushedValues.Count < 200)
{
v_WeightCursor = treatReceivedValue(m_BufferWeights[0]);
if (v_WeightCursor >= 0)
{
v_FlushedValues.Add(v_WeightCursor);
}
m_BufferWeights.RemoveAt(0);
}
return v_FlushedValues;
}
public void ResetWeights()
{
if (m_BufferWeights != null)
{
m_BufferWeights.Clear();
}
}
public string NewLineCommandType { get; set; }
public string NewLineCommand { get; set; }
public int ReturnLength { get; set; }
public int WeightInitialPosition { get; set; }
public int WeightFinalPosition { get; set; }
public int MotionBitPos { get; set; }
public int ReadTimeOut { get; set; }
public bool OpenedPort { get; private set; }
public bool ErrorReadingWeight { get; private set; }
public DateTime LastGoodReading { get; private set; }
public bool IsStable { get; private set; }
private Parity PortParity { get; set; }
public string SerialParity
{
get { return PortParity.ToString(); }
set
{
setParity(value);
}
}
public int WeightReadLength
{
get
{
if (WeightFinalPosition >= WeightInitialPosition)
{
return WeightFinalPosition - WeightInitialPosition + 1;
}
else
{
return 0;
}
}
}
private StopBits PortStopBits { get; set; }
public string SerialStopBits
{
get { return PortStopBits.ToString(); }
set
{
setStopBits(value);
}
}
private void setParity(string p_Parity)
{
if (p_Parity.Equals(Parity.Even.ToString()))
{
PortParity = Parity.Even;
}
else if (p_Parity.Equals(Parity.Mark.ToString()))
{
PortParity = Parity.Mark;
}
else if (p_Parity.Equals(Parity.Odd.ToString()))
{
PortParity = Parity.Odd;
}
else if (p_Parity.Equals(Parity.Space.ToString()))
{
PortParity = Parity.Space;
}
else
{
PortParity = Parity.None;
}
}
private void setStopBits(string p_StopBits)
{
if (p_StopBits.Equals(StopBits.One.ToString()))
{
PortStopBits = StopBits.One;
}
else if (p_StopBits.Equals(StopBits.OnePointFive.ToString()))
{
PortStopBits = StopBits.OnePointFive;
}
else if (p_StopBits.Equals(StopBits.Two.ToString()))
{
PortStopBits = StopBits.Two;
}
else if (p_StopBits.Equals("1"))
{
PortStopBits = StopBits.One;
}
else if (p_StopBits.Equals("1.5"))
{
PortStopBits = StopBits.OnePointFive;
}
else if (p_StopBits.Equals("2"))
{
PortStopBits = StopBits.Two;
}
else
{
PortStopBits = StopBits.None;
}
}
public Scales()
{
OpenedPort = false;
ErrorReadingWeight = false;
IsStable = false;
m_IntervalsWithoutSample = 999999;
timerTimeWithoutSample = new System.Timers.Timer(5);
timerTimeWithoutSample.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
}
private int ignoreNextXValues;
public void resetScale()
{
ErrorReadingWeight = false;
IsStable = false;
m_IntervalsWithoutSample = 999999;
ignoreNextXValues = 2;
m_BufferWeights.Clear();
m_BufferTime.Clear();
if (m_SerialPort != null && m_SerialPort.IsOpen)
{
m_SerialPort.Close();
m_SerialPort.Open();
m_SerialPort.DiscardInBuffer();
}
}
List<String> m_BufferWeights = new List<String>();
List<String> m_BufferTime = new List<String>();
public bool openPort()
{
try
{
if (m_SerialPort.IsOpen)
{
m_SerialPort.Close();
}
m_SerialPort.Open();
resetScale();
OpenedPort = true;
return true;
}
catch (Exception ex)
{
MessageDetail = ex.Message;
Return = -100;
OpenedPort = false;
return false;
}
}
public bool closePort()
{
try
{
if (m_SerialPort != null)
{
if (m_SerialPort.IsOpen)
{
m_SerialPort.Close();
}
}
OpenedPort = false;
return true;
}
catch (Exception ex)
{
MessageDetail = ex.Message;
Return = -101;
return false;
}
}
public bool configurePort()
{
try
{
m_SerialPort = new SerialPort();
m_SerialPort.PortName = PortName;
m_SerialPort.BaudRate = BaudRate;
m_SerialPort.Parity = PortParity;
m_SerialPort.DataBits = DataBits;
m_SerialPort.StopBits = PortStopBits;
m_SerialPort.ReadTimeout = ReadTimeOut > 0 ? ReadTimeOut : SerialPort.InfiniteTimeout;
m_SerialPort.NewLine = getNewLineCommand();
m_SerialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
return true;
}
catch (Exception ex)
{
MessageDetail = ex.Message;
Return = -102;
return false;
}
}
private string getNewLineCommand()
{
string v_Command = string.Empty;
if (NewLineCommandType.ToUpper().Equals(CommandTypes.CHAR.ToUpper()))
{
byte v_Char = Convert.ToByte(NewLineCommand);
v_Command = Convert.ToChar(v_Char).ToString();
}
else if (NewLineCommandType.ToUpper().Equals(CommandTypes.STRING.ToUpper()))
{
v_Command = NewLineCommand;
}
else
{
char[] v_delimiters = { '|' };
String[] v_Strings = NewLineCommand.Split(v_delimiters);
if (v_Strings.Length == 2)
{
v_Command = v_Strings[0];
m_EndOfWeightChar = v_Strings[1];
}
else
{
v_Command = NewLineCommand;
}
}
return v_Command;
}
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
LastGoodReading = DateTime.Now;
string ReadLine = m_SerialPort.ReadLine();
m_BufferWeights.Add(ReadLine);
}
catch (Exception)
{
m_Weight = 0;
LastGoodReading = DateTime.MinValue;
}
}
private Double treatReceivedValue(string p_ReceivedValue)
{
try
{
if (ignoreNextXValues > 0) ignoreNextXValues--;
if (ignoreNextXValues > 0) return 0;
double v_Value = double.MinValue;
p_ReceivedValue = p_ReceivedValue.Replace("\r", "").Replace("\n", "");
m_IntervalsWithoutSample = 0;
if (p_ReceivedValue.Length < WeightInitialPosition + WeightReadLength)
{
return -1;
}
if (MotionBitPos != -1 && p_ReceivedValue.Length < MotionBitPos - 1)
{
return -1;
}
string strValor = "";
if (NewLineCommandType.ToUpper().Equals(CommandTypes.VARIABLE_LENGTH.ToUpper()))
{
int v_EndCharPos = p_ReceivedValue.IndexOf(m_EndOfWeightChar);
if (v_EndCharPos != -1)
{
strValor = p_ReceivedValue.Substring(0, v_EndCharPos).Trim();
}
}
else
{
strValor = p_ReceivedValue.Substring(WeightInitialPosition, WeightReadLength).Trim();
}
bool IsDouble = double.TryParse(strValor, out v_Value);
if (IsDouble)
{
if (MotionBitPos != -1)
{
string bit = p_ReceivedValue.Substring(MotionBitPos, 1).Trim();
if (bit == "1")
{
IsStable = true;
}
else IsStable = false;
}
else
{
IsStable = true;
}
return v_Value;
}
else
{
return -1;
}
}
catch (Exception ex)
{
Return = -200;
MessageDetail = ex.Message + " - Fonte:readScales";
ErrorReadingWeight = true;
}
return -1;
}
}
}

I had a similar problem, using SerialPort.ReadExisting() insted of SerialPort.ReadLine() I was able to avoid the creation of infinite threads.

You should try to reduce your problematic code down to something more manageable, as it will make it easier for others to debug. There's a lot of application logic in there that's probably not relevant to the problem which can make it hard for people to see what's going on. You'll get a lot more answers if your example is shorter. You may even figure the problem out yourself in the process!
Having said that, I have a hunch about what's wrong but you'll need to do a little bit of the leg-work yourself to discover if I'm right or wrong:
The .NET serial port works by waiting for data to come in, and then firing the DataReceived event on a worker thread whenever it notices that there's new data. I believe you have 400 or 500 of these worker threads that never complete their work, so they never go away.
Your event handler for the SerialPort.DataReceived event looks like it's blocking waiting for a whole line to come in, but the event is going to be fired whenever there's some amount of new data on the serial port (not necessarily a whole line). If a long line of text comes in, the DataReceived event is going to fire many times, each on it's own worker thread. These worker threads are synchronized to each other, so they're all going to wait for the previous one to finish.
The first thread that gets queued up is going to wait for a while at m_SerialPort.ReadLine() until the whole line comes in.
A bunch of threads queue up behind the first thread as more characters come in. The rest of the threads will end up waiting for the first thread to finish running your event handler.
Finally, the whole line comes in. The first thread finishes, and one of the 5 or 6 that are queued up behind it gets to run and the process starts all over.
The running thread blocks on ReadLine, 5 or 6 more queue up behind it. (We're now back at 1)
Eventually you have so many threads queued up that you run into memory issues.
You probably have the read-timeout on m_SerialPort set to timeout.Infinite. If you set the timeout to something smaller, like 1 second (1000) and you get a lot of TimeoutExceptions in your SerialPort_DataReceived method, then I'm probably right
Side Note You should catch a more specific exception type in your DataReceived event handler. Catching exception can mask exactly this type of problem.
If I've correctly diagnosed the problem, you'll need to change the architecture of your program a little bit. The simplest thing to do is not subscribe to the DataReceived event and to have a single worker thread call m_SerialPort.ReadLine(); with an infinite timeout. When it reads a line, have that worker thread raise an event with the whole line of text received and subscribe to THAT event instead of the SerialPort.DataReceived(); event.
Alternatively, if you want to subscribe to the SerialPort.DataReceived(); event, then read individual characters out of the SerialPort until SerialPort.BytesToRead is zero and stick them in a buffer. Then, when you have a whole line raise some "LineReceived" event that you make yourself that returns the whole line at once as one of the EventArgs. This method is doesn't require you to spool up your own thread that persists for a really long time.

Related

Two identical multithreading scripts are causing memoryleak

I am working on my own multithreading for my algorithm independed pathfinding for unity. However, when I am executing two the same class I get a memory leak and when only executing one instance I am having no issues. I really want to use at least two threads if it is necessary.
Below is the class I have issues with. Keep in mind, that two independend threads will have to execute parts of this script. AddJob can be called from the main unity thread but will most likely be called from another update thread for the agents.
namespace Plugins.PathFinding.Threading
{
internal class PathFindingThread
{
private Thread m_Worker;
private volatile Queue<CompletedProcessingCallback> m_CallbackQueue;
private volatile Queue<IAlgorithm> m_QueuedTasks;
internal int GetTaskCount
{
get
{
return m_QueuedTasks.Count;
}
}
internal PathFindingThread()
{
m_Worker = new Thread(Run);
m_CallbackQueue = new Queue<CompletedProcessingCallback>();
m_QueuedTasks = new Queue<IAlgorithm>();
}
private void Run()
{
Debug.Log("<b><color=green> [ThreadInfo]:</color></b> PathFinding Thread Started ");
try
{
while(true)
{
if (m_QueuedTasks.Count > 0)
{
IAlgorithm RunningTask = m_QueuedTasks.Dequeue();
RunningTask.FindPath(new IAlgorithmCompleted(AddCallback));
}
else
break;
}
Debug.Log("<b><color=red> [ThreadInfo]:</color></b> PathFinding Worker is idle and has been Stopped");
}
catch(Exception)
{
Debug.Log("<b><color=red> [ThreadInfo]:</color></b> PathFinding thread encountred an error and has been aborted");
}
}
internal void AddJob(IAlgorithm AlgorithmToRun)
{
m_QueuedTasks.Enqueue(AlgorithmToRun);
//Debug.Log("Added Job To Queue");
}
private void AddCallback(CompletedProcessingCallback callback)
{
m_CallbackQueue.Enqueue(callback);
}
private void Update()
{
if (m_CallbackQueue.Count > 0)
{
if (m_CallbackQueue.Peek().m_Callback != null) { }
m_CallbackQueue.Peek().m_Callback.Invoke(m_CallbackQueue.Peek().m_Path);
m_CallbackQueue.Dequeue();
}
if (m_Worker.ThreadState != ThreadState.Running && m_QueuedTasks.Count != 0)
{
m_Worker = new Thread(Run);
m_Worker.Start();
}
}
}
internal delegate void IAlgorithmCompleted(CompletedProcessingCallback callback);
internal struct CompletedProcessingCallback
{
internal volatile FindPathCompleteCallback m_Callback;
internal volatile List<GridNode> m_Path;
}
}
namespace Plugins.PathFinding
{
internal enum TypeOfNode
{
Ground,
Air
}
//used to store location information since array can only take rounded numbers
internal struct Position
{
internal int x;
internal int y;
internal int z;
}
internal class GridNode
{
internal Position M_PostitionInGrid { get; private set; }
internal Vector3 M_PostitionInWorld { get; private set; }
internal TypeOfNode M_type { get; private set; }
internal bool m_IsWalkable = true;
internal GridNode m_ParrentNode;
internal int Hcost;
internal int Gcost;
internal int Fcost { get { return Hcost + Gcost; } }
internal GridNode(Position postion , Vector3 WorldPosition)
{
M_PostitionInGrid = postion;
m_IsWalkable = true;
M_PostitionInWorld = WorldPosition;
}
}
}
internal delegate void FindPathCompleteCallback(List<GridNode> Path);
internal abstract class IAlgorithm
{
protected GridNode m_SavedStart;
protected GridNode m_SavedTarget;
protected List<GridNode> m_LocatedPath;
protected FindPathCompleteCallback m_Callback;
internal FindPathCompleteCallback GetCallback
{
get
{
return m_Callback;
}
}
protected PathFindingGrid m_grid;
internal abstract void FindPath(IAlgorithmCompleted callback);
protected abstract List<GridNode> CreatePath(PathFindingGrid Grid, GridNode Start, GridNode Target);
protected abstract List<GridNode> RetracePath(GridNode start, GridNode target);
}
namespace Plugins.PathFinding.Astar
{
internal class AstarFinder : IAlgorithm
{
//construction of the Algorithm
internal AstarFinder(GridNode start, GridNode target, FindPathCompleteCallback Callback)
{
m_SavedStart = start;
m_SavedTarget = target;
m_Callback = Callback;
m_LocatedPath = new List<GridNode>();
m_grid = PathFindingGrid.GetInstance;
}
//function to start finding a path
internal override void FindPath(IAlgorithmCompleted callback)
{
//running Algorithm and getting the path
m_LocatedPath = CreatePath(PathFindingGrid.GetInstance, m_SavedStart, m_SavedTarget);
callback.Invoke(
new CompletedProcessingCallback()
{
m_Callback = m_Callback,
m_Path = m_LocatedPath
});
}
//Algorithm
protected override List<GridNode> CreatePath(PathFindingGrid Grid, GridNode Start, GridNode Target)
{
if(Grid == null ||
Start == null ||
Target == null)
{
UnityEngine.Debug.Log("Missing Parameter, might be outside of grid");
return new List<GridNode>();
}
List<GridNode> Path = new List<GridNode>();
List<GridNode> OpenSet = new List<GridNode>();
List<GridNode> ClosedSet = new List<GridNode>();
OpenSet.Add(Start);
int Retry = 0;
while (OpenSet.Count > 0)
{
if(Retry > 3000 || Grid == null)
{
UnityEngine.Debug.Log("Path Inpossible Exiting");
break;
}
GridNode CurrentNode = OpenSet[0];
for (int i = 0; i < OpenSet.Count; i++)
{
if(OpenSet[i].Fcost < CurrentNode.Fcost || OpenSet[i].Fcost == CurrentNode.Fcost && OpenSet[i].Hcost < CurrentNode.Hcost)
{
CurrentNode = OpenSet[i];
}
}
OpenSet.Remove(CurrentNode);
ClosedSet.Add(CurrentNode);
if(CurrentNode == Target)
{
Path = RetracePath(CurrentNode,Start);
break;
}
GridNode[] neighbour = Grid.GetNeighbouringNodes(CurrentNode);
for (int i = 0; i < neighbour.Length; i++)
{
if (!neighbour[i].m_IsWalkable || ClosedSet.Contains(neighbour[i]))
continue;
int CostToNeighbour = CurrentNode.Gcost + Grid.GetDistance(CurrentNode, neighbour[i]);
if(CostToNeighbour < neighbour[i].Gcost || !OpenSet.Contains(neighbour[i]))
{
neighbour[i].Gcost = CostToNeighbour;
neighbour[i].Hcost = Grid.GetDistance(neighbour[i], Target);
neighbour[i].m_ParrentNode = CurrentNode;
if (!OpenSet.Contains(neighbour[i]))
OpenSet.Add(neighbour[i]);
}
}
Retry++;
}
return Path;
}
//retracing the path out of a node map
protected override List<GridNode> RetracePath(GridNode start, GridNode target)
{
List<GridNode> Output = new List<GridNode>();
GridNode current = start;
while(current != target)
{
Output.Add(current);
current = current.m_ParrentNode;
}
Output.Reverse();
return Output;
}
}
}
This shows the core of your code made thread safe.
internal class PathFindingThread
{
Task m_Worker;
ConcurrentQueue<CompletedProcessingCallback> m_CallbackQueue;
ConcurrentQueue<IAlgorithm> m_QueuedTasks;
internal int GetTaskCount
{
get
{
return m_QueuedTasks.Count;
}
}
internal PathFindingThread()
{
m_CallbackQueue = new ConcurrentQueue<CompletedProcessingCallback>();
m_QueuedTasks = new ConcurrentQueue<IAlgorithm>();
m_Worker = Task.Factory.StartNew(() =>
{
while (true)
{
IAlgorithm head = null;
if (m_QueuedTasks.TryDequeue(out head))
{
head.FindPath(new IAlgorithmCompleted(AddCallback));
}
else
{
Task.Delay(0);
}
}
});
}
internal void AddJob(IAlgorithm AlgorithmToRun)
{
m_QueuedTasks.Enqueue(AlgorithmToRun);
}
private void AddCallback(CompletedProcessingCallback callback)
{
m_CallbackQueue.Enqueue(callback);
}
private void Update()
{
CompletedProcessingCallback cb = null;
if (m_CallbackQueue.TryDequeue(out cb))
{
cb.m_Callback.Invoke(cb.m_Path);
}
}
}
Volatile is only good for changing the value of the field - not calling methods on a collection that is referenced by the field.
You propably do not need to have Volatile in CompletedProcessingCallback, but it depends where else this is used. Certainly having volatile on a struct field is a bad smell.
Resolve these thread issues first, then see if you still have the problem.

UserAppDataReigistry not persisting

I have the following class to persist my camera settings.
using System;
using System.Drawing;
using System.Windows.Forms;
using DevExpress.XtraEditors.Camera;
public class CameraDeviceHelper
{
public string DeviceMoniker;
public string DeviceName;
public int DeviceResolutionWidth;
public int DeviceResolutionHeight;
const string kDeviceName = "CameraDeviceName";
const string kDeviceMoniker = "CameraDeviceMoniker";
const string kDeviceResolutionWidth = "CameraDeviceResolutionWidth";
const string kDeviceResolutionHeight = "CameraDeviceResolutionHeight";
public bool SaveCameraDevice(CameraControl cc)
{
try
{
DeviceMoniker = cc.Device.DeviceMoniker;
DeviceName = cc.Device.Name;
DeviceResolutionWidth = cc.Device.Resolution.Width;
DeviceResolutionHeight = cc.Device.Resolution.Height;
Application.UserAppDataRegistry.SetValue(kDeviceName, DeviceName);
Application.UserAppDataRegistry.SetValue(kDeviceMoniker, DeviceMoniker);
Application.UserAppDataRegistry.SetValue(kDeviceResolutionWidth, DeviceResolutionWidth);
Application.UserAppDataRegistry.SetValue(kDeviceResolutionHeight, DeviceResolutionHeight);
return true;
}
catch (Exception)
{
return false;
}
}
public bool RestoreCameraDevice(CameraControl cc)
{
try
{
DeviceName = Application.UserAppDataRegistry.GetValue(kDeviceName, DeviceName).ToString();
DeviceMoniker =Application.UserAppDataRegistry.GetValue(kDeviceMoniker, DeviceMoniker).ToString();
DeviceResolutionWidth = (int) Application.UserAppDataRegistry.GetValue(kDeviceResolutionWidth, DeviceResolutionWidth);
DeviceResolutionHeight = (int)Application.UserAppDataRegistry.GetValue(kDeviceResolutionHeight, DeviceResolutionHeight);
var moniker = new DevExpress.Data.Camera.CameraDeviceInfo(DeviceMoniker, DeviceName);
cc.Device = new CameraDevice(moniker);
var sz = new Size(DeviceResolutionWidth,DeviceResolutionHeight);
cc.Device.Resolution = sz;
if (cc.Device.Resolution.Width != sz.Width)
{ MessageBox.Show("Not set");}
cc.Start();
return true;
}
catch (Exception)
{
return false;
}
}
}
}
The persisting works while the application runs.
However when I restart the application the settings are lost.
I call the methods in my form's load and FormClosed events
private void Camera_Load(object sender, EventArgs e)
{
textEdit1.Text = PhotoCaption;
cameraDeviceHelper = new CameraDeviceHelper();
try
{
cameraDeviceHelper.RestoreCameraDevice(cameraControl1);
}
catch (Exception)
{
// probably first time... so just dont complain
throw;
}
}
private void Camera_FormClosed(object sender, FormClosedEventArgs e)
{
cameraDeviceHelper.SaveCameraDevice(cameraControl1);
}
The solution is not to have an * in the AssemblyVersion
otherwise every time the application is built the registry key will change.

Beep in C# .NET application on server side

To debug a firewall delay issue I need an application that will produce a beep on server side when it detects an HTTP GET request.
This code (test.ashx):
<%# WebHandler Language="C#" Class="TestHandler" %>
using System;
using System.Web;
public class TestHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
HttpResponse Response = context.Response;
try
{
Response.Write("Before beep");
Console.Beep();
Response.Write("After beep");
}
catch (Exception ex)
{
Response.Write(ex.Message + "<br />\n" + ex.InnerException.Message);
}
}
public bool IsReusable { get { return false; } }
}
produces sound only when debugging in IIS Express. After moving the web app to IIS, the sound disappears.
The three easy ways of producing a sound are System.Console.Beep(), System.Media.SoundPlayer, and System.Media.SystemSounds.Beep().
Unfortunately, these methods only work in desktop applications, and won't work in service applications. When ASP.Net apps are run under IIS Express (a desktop app), these sound methods work. However, when ASP.Net apps are run under the IIS service, the sound methods don't work.
System.Console.Beep() ultimately calls the kernel32.dll Beep() function. It's restricted to desktop apps only (scroll down to the Requirements section).
Same for System.Media.SoundPlayer and System.Media.SystemSounds.Beep(). They call the kernel32.dll MessageBeep() and the winmm.dll PlaySound() functions, respectively. They, too, are restricted to desktop apps.
One way to get sounds to play in a service is use NAudio. It's easy to install via NuGet.
This chunk of code is the only way I could get the sound to play. It has to be played on a separate worker thread, and the execution of the worker thread needs to be paused to let the .wav file finish playing.
using System;
using System.Diagnostics;
using System.Threading;
using NAudio.Dsp;
using NAudio.Wave;
...
protected void Button1_Click(object sender, EventArgs e)
{
var waveFilename = #"c:\Windows\Media\tada.wav";
/* Trying to play the .wav file on the main thread
doesn't seem to work. */
ThreadPool.QueueUserWorkItem(
(state) =>
{
using (var audioPlayback = new AudioPlayback())
{
audioPlayback.Load(waveFilename);
audioPlayback.Play(); // Asynchronous.
/* Need to sleep for the approximate length of .wav file,
otherwise no sound is produced because of the
asynchronous Play() call. */
Thread.Sleep(2000);
}
});
}
Here's the supporting code taken from code in NAudio's NAudioWPFDemo project:
public class MaxSampleEventArgs : EventArgs
{
[DebuggerStepThrough]
public MaxSampleEventArgs(float minValue, float maxValue)
{
this.MaxSample = maxValue;
this.MinSample = minValue;
}
public float MaxSample { get; private set; }
public float MinSample { get; private set; }
}
public class FftEventArgs : EventArgs
{
[DebuggerStepThrough]
public FftEventArgs(Complex[] result)
{
this.Result = result;
}
public Complex[] Result { get; private set; }
}
public class SampleAggregator : ISampleProvider
{
// volume
public event EventHandler<MaxSampleEventArgs> MaximumCalculated;
private float maxValue;
private float minValue;
public int NotificationCount { get; set; }
int count;
// FFT
public event EventHandler<FftEventArgs> FftCalculated;
public bool PerformFFT { get; set; }
private readonly Complex[] fftBuffer;
private readonly FftEventArgs fftArgs;
private int fftPos;
private readonly int fftLength;
private int m;
private readonly ISampleProvider source;
private readonly int channels;
public SampleAggregator(ISampleProvider source, int fftLength = 1024)
{
channels = source.WaveFormat.Channels;
if (!IsPowerOfTwo(fftLength))
throw new ArgumentException("FFT Length must be a power of two");
this.m = (int) Math.Log(fftLength, 2.0);
this.fftLength = fftLength;
this.fftBuffer = new Complex[fftLength];
this.fftArgs = new FftEventArgs(fftBuffer);
this.source = source;
}
private bool IsPowerOfTwo(int x)
{
return (x & (x - 1)) == 0;
}
public void Reset()
{
count = 0;
maxValue = minValue = 0;
}
private void Add(float value)
{
if (PerformFFT && FftCalculated != null)
{
fftBuffer[fftPos].X = (float) (value * FastFourierTransform.HammingWindow(fftPos, fftLength));
fftBuffer[fftPos].Y = 0;
fftPos++;
if (fftPos >= fftBuffer.Length)
{
fftPos = 0;
// 1024 = 2^10
FastFourierTransform.FFT(true, m, fftBuffer);
FftCalculated(this, fftArgs);
}
}
maxValue = Math.Max(maxValue, value);
minValue = Math.Min(minValue, value);
count++;
if (count >= NotificationCount && NotificationCount > 0)
{
if (MaximumCalculated != null)
MaximumCalculated(this, new MaxSampleEventArgs(minValue, maxValue));
Reset();
}
}
public WaveFormat WaveFormat { get { return source.WaveFormat; } }
public int Read(float[] buffer, int offset, int count)
{
var samplesRead = source.Read(buffer, offset, count);
for (int n = 0; n < samplesRead; n += channels)
Add(buffer[n + offset]);
return samplesRead;
}
}
public class AudioPlayback : IDisposable
{
private IWavePlayer _playbackDevice;
private WaveStream _fileStream;
public void Load(string fileName)
{
Stop();
CloseFile();
EnsureDeviceCreated();
OpenFile(fileName);
}
private void CloseFile()
{
if (_fileStream != null)
{
_fileStream.Dispose();
_fileStream = null;
}
}
private void OpenFile(string fileName)
{
try
{
var inputStream = new AudioFileReader(fileName);
_fileStream = inputStream;
var aggregator = new SampleAggregator(inputStream);
aggregator.NotificationCount = inputStream.WaveFormat.SampleRate / 100;
aggregator.PerformFFT = true;
_playbackDevice.Init(aggregator);
}
catch
{
CloseFile();
throw;
}
}
private void EnsureDeviceCreated()
{
if (_playbackDevice == null)
CreateDevice();
}
private void CreateDevice()
{
_playbackDevice = new WaveOut { DesiredLatency = 200 };
}
public void Play()
{
if (_playbackDevice != null && _fileStream != null && _playbackDevice.PlaybackState != PlaybackState.Playing)
_playbackDevice.Play();
}
public void Pause()
{
if (_playbackDevice != null)
_playbackDevice.Pause();
}
public void Stop()
{
if (_playbackDevice != null)
_playbackDevice.Stop();
if (_fileStream != null)
_fileStream.Position = 0;
}
public void Dispose()
{
Stop();
CloseFile();
if (_playbackDevice != null)
_playbackDevice.Dispose();
}
}
Try this System.Media.SystemSounds.Beep.Play();

C# Using SoundPlayer to Pause and Resume

I am another person dabbling with C# and wanting to create a simple audio application that plays wav files loaded into the program via an upload program. My issue is that I need to get whatever audio file currently being played to pause with the track timer of the audio file being used when I start the audio file again via my Play button. I already have a global timer, 'baseTimer', that I think I can use to set the audio file, that was stopped, track duration point. However I do not know how to accomplish this nor do I really know how to use all of the mci commands yet.
I have displayed all of my code for my main application... I also have read that I may need to utilize threading, but I've also read that it would be impossible to set an audio files track duration with a thread.
public partial class FrmMain : Form
{
public FrmMain()
{
InitializeComponent();
}
System.Timers.Timer baseTimer = new System.Timers.Timer();
List<string> PlayList = new List<string>();
List<byte> PlayList_byte;
int soundNum = 0;
private string music_PATH { get; set; }
private string talk_PATH { get; set; }
private byte Pause_TIME { get; set; }
private string Pause_RADIO { get; set; }
bool isStopped = new bool();
bool isPaused = new bool();
[DllImport("winmm.dll")]
private static extern uint mciSendString(string command, StringBuilder returnValue, int returnLength, IntPtr winHandle);
public static int GetSoundLength(string fileName)
{
StringBuilder lengthBuf = new StringBuilder(32);
mciSendString(string.Format("open \"{0}\" type waveaudio alias wave", fileName), null, 0, IntPtr.Zero);
mciSendString("status wave length", lengthBuf, lengthBuf.Capacity, IntPtr.Zero);
mciSendString("close wave", null, 0, IntPtr.Zero);
int length = 0;
int.TryParse(lengthBuf.ToString(), out length);
return length;
}
private void SetPath()
{
music_PATH = #"..\\..\\commercial\list.txt";
talk_PATH = #"..\\..\\main\list.txt";
StreamReader myReader;
using (myReader = new StreamReader(music_PATH))
{
while (myReader.Peek() != -1)
{
string read = myReader.ReadLine();
PlayList.Add(read);
}
}
using (myReader = new StreamReader(talk_PATH))
{
while (myReader.Peek() != -1)
{
string read = myReader.ReadLine();
PlayList.Add(read);
}
myReader.Close();
}
foreach (string sound in PlayList)
{
soundNum++;
}
}
private string CurrentSound()
{
try
{
Random _randx = new Random();
int pick = _randx.Next(0, soundNum);
string currentaudio = PlayList[pick];
Pause_RADIO = currentaudio;
return currentaudio;
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
return null;
}
string _SelectedSound = "";
private string _Sound(string currentradio, string pattern)
{
foreach (Match entry in Regex.Matches(currentradio, pattern))
{
_SelectedSound = entry.Value.ToString();
}
if (_SelectedSound == "music")
{
return "commercial";
}
else if (_SelectedSound == "talk")
{
return "main";
}
return null;
}
private void _SetTimer(string currentradio, string pattern)
{
baseTimer.Interval = GetSoundLength(#"..\\..\\" + pattern + #"\" + currentradio);
}
private bool isRepeat(string lastradio, string currentradio)
{
if (lastradio == currentradio)
{
return true;
}
else
{
return false;
}
}
private void baseTimerElasped(object sender, ElapsedEventArgs e)
{
Radio.FrmMain play = new Radio.FrmMain();
play.PlayPlayer();
}
private void PlayPlayer()
{
MediaPlayer wavplayer;
try
{
if (soundNum == 0)
{
SetPath();
PlayPlayer();
}
else
{
string currentradio = CurrentSound();
bool localcheck = isRepeat(_SelectedSound, currentradio);
if (localcheck == true)
{
PlayPlayer();
}
else
{
string Pattern = #"(music|talk)";
string selected = _Sound(currentradio, Pattern);
_SetTimer(currentradio, selected);
switch (selected)
{
case "commercial":
music_PATH = #"..\\..\\commercial\";
PlayList_byte = new List<byte>(File.ReadAllBytes(music_PATH + currentradio));
wavplayer = new MediaPlayer(PlayList_byte.GetRange(0, PlayList_byte.Count).ToArray());
wavplayer.Play();
baseTimer.Start();
break;
case "main":
talk_PATH = #"..\\..\\main\";
PlayList_byte = new List<byte>(File.ReadAllBytes(talk_PATH + currentradio));
wavplayer = new MediaPlayer(PlayList_byte.GetRange(0, PlayList_byte.Count).ToArray());
wavplayer.Play();
baseTimer.Start();
break;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message + ex.StackTrace + ex.Source);
}
}
private void PausePlayer()
{
MediaPlayer wavplayer = new MediaPlayer(PlayList_byte.GetRange(0, PlayList_byte.Count).ToArray());
baseTimer.Stop();
MessageBox.Show("Count: " + PlayList_byte.Count + "Pause_TIME: " + Pause_TIME + "\nPlaylist_byte" + PlayList_byte.ToString());
try
{
switch (isPaused)
{
case false:
isPaused = true;
wavplayer.Stop();
break;
case true:
isPaused = false;
string localcheck = _Sound(Pause_RADIO, #"(music|talk)");
switch (localcheck)
{
case "commercial":
music_PATH = #"..\\..\\commercial\";
wavplayer.Play(PlayList_byte.GetRange(PlayList_byte.Count - Pause_TIME, PlayList_byte.Count - Pause_TIME).ToArray());
break;
case "main":
talk_PATH = #"..\\..\\main\";
wavplayer.Play(PlayList_byte.GetRange(PlayList_byte.Count - Pause_TIME, PlayList_byte.Count - Pause_TIME).ToArray());
break;
}
break;
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message + ex.Data);
}
}
private void btnPlay_Click(object sender, EventArgs e)
{
switch (isStopped)
{
case false:
isStopped = true;
btnPlay.Image = Image.FromFile(#"..\\..\\Pause.png");
lblPlay.Text = "Pause";
if (isPaused == false)
{
PlayPlayer();
}
else
{
PausePlayer();
}
break;
case true:
isStopped = false;
btnPlay.Image = Image.FromFile(#"..\\..\\Play.png");
lblPlay.Text = "Play";
PausePlayer();
break;
}
baseTimer.Elapsed += new ElapsedEventHandler(baseTimerElasped);
}
private void btnNext_Click(object sender, EventArgs e)
{
PlayPlayer();
}
private void btnStop_Click(object sender, EventArgs e)
{
MediaPlayer wavplayer = new MediaPlayer();
wavplayer.Stop();
baseTimer.Stop();
}
private void btnQuit_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void btnGetUpload_Click(object sender, EventArgs e)
{
Uploader FrmUpload = new Uploader();
FrmUpload.Show();
this.Hide();
}
}
class MediaPlayer
{
SoundPlayer wavplayer;
public MediaPlayer()
{
Stop();
}
public MediaPlayer(byte[] buffer)
{
MemoryStream memStream = new MemoryStream(buffer, true);
wavplayer = new SoundPlayer(memStream);
}
public void Play()
{
wavplayer.Play();
}
public void Play(byte[] buffer)
{
wavplayer.Stream.Seek(0, SeekOrigin.Begin);
wavplayer.Stream.Write(buffer, 0, buffer.Length);
wavplayer.Play();
}
public void Stop()
{
wavplayer.Stop();
}
}
Edit:
For clarity currentaudio has a file as such "music3.wav" or "talk1.wav" in it.
Super old question but just for anyone looking here's what worked for me:
double currentPos = audioplayer.CurrentPosition;
audioplayer.Play();
audioplayer.Seek(currentPos);
SoundPlayer is extremely limited, and doesn't support Pause and Resume. Are you able to use the WPF MediaElement instead? You will find it is much more powerful, supporting playing files of many types, repositioning, setting volume, pausing and resuming. You can also use it to get the file length instead of mci.

Symbol.WPAN.Bluetooth example that transfers data

I am trying to use Symbol.WPAN.Bluetooth that comes with the EMDK for Symbol devices.
Does anyone happen to have a working example that transfers data?
Symbol's example just pairs the devices. (They apparently think that transfering data is not really needed in a Personal Area network example.)
Anyway, I know this is a long shot, but if anyone has gotten this to work I would love to see some code.
This is what I have tried. I have one device press button1 and another device press button2. The read value is always a zero length byte array.
using System.Text;
using System.Windows.Forms;
using Symbol.WPAN;
using Symbol.WPAN.Bluetooth;
namespace SmartDeviceProject1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Bluetooth bluetooth = new Bluetooth();
if (bluetooth.IsEnabled != true)
{
bluetooth.Enable();
bluetooth.RadioMode = BTH_RADIO_MODE.BTH_DISCOVERABLE_AND_CONNECTABLE;
}
RemoteDevice connectedDevice = null;
foreach (RemoteDevice remoteDevice in MakeEnumerable(bluetooth.RemoteDevices))
{
if ((remoteDevice.Name == "WM_Dan") && (remoteDevice.IsPaired == false))
{
remoteDevice.Pair();
connectedDevice = remoteDevice;
}
}
string test;
test = "Testing this out";
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] encTest = encoding.GetBytes(test);
if (connectedDevice != null)
{
connectedDevice.WriteTimeout = 20000;
connectedDevice.Write(encTest);
}
}
public static IEnumerable<RemoteDevice> MakeEnumerable(RemoteDevices devices)
{
for (var i = 0; i < devices.Length; i++)
{
yield return devices[i];
}
}
private void button2_Click(object sender, EventArgs e)
{
Bluetooth bluetooth = new Bluetooth();
if (bluetooth.IsEnabled != true)
{
bluetooth.Enable();
bluetooth.RadioMode = BTH_RADIO_MODE.BTH_DISCOVERABLE_AND_CONNECTABLE;
}
RemoteDevice connectedDevice = null;
foreach (RemoteDevice remoteDevice in MakeEnumerable(bluetooth.RemoteDevices))
{
if ((remoteDevice.Name == "WM_Dan2") && (remoteDevice.IsPaired == false))
{
remoteDevice.Pair();
connectedDevice = remoteDevice;
}
}
string test;
test = "Testing this out";
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] encTest = encoding.GetBytes(test);
byte[] encTest2;
string test2;
if (connectedDevice != null)
{
connectedDevice.ReadTimeout = 20000;
encTest2 = connectedDevice.Read(encTest.Length);
test2 = encoding.GetString(encTest2, 0, encTest2.Length);
MessageBox.Show(test2);
}
}
}
}
I gave up on using the built in com port connection and opened a SerialPort object on the connection.
SerialPort sp = new SerialPort();
sp.PortName = "COM" + connectedDevice.LocalComPort.ToString();
sp.BaudRate = 9600;
sp.DataBits = 8;
sp.Parity = Parity.None;
sp.StopBits = StopBits.One;
sp.Open();
sp.Open();
sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
sp.ErrorReceived += new SerialErrorReceivedEventHandler(sp_ErrorReceived);
sp.WriteLine(textBoxSend.Text);
I also found that even though their docs said that LocalComPort was auto assigned, this was not always the truth. It was best to use their BTExplorer to set it first.
As well, there OpenComPort would work in situations where is should not -- using Reflector it is pretty obviously wrong. There are checking the return of ::CreateFile("COM" + port...) against 0 instead of -1 (INVALID_HANDLE_VALUE)
I don't know if this can ever help anyone, but here is an old piece of code that I wrote a few years back.
You'll have to clean it up so that it works for your application. My app had a TextBox control that it read from and logged errors to a Global class. Change that to work with what you have, and it should basically be good.
static class Scanner {
const string _CODEFILE = "Scanner.cs - Scanner::";
static int _baud = 9600;
static int _bits = 8;
static string _dataIn = null;
static string _port = "COM1";
static Parity _parity = Parity.None;
static StopBits _stop = StopBits.One;
static SerialPort _com1 = null;
static TextBox _textbox = null;
public enum ControlType { None, BadgeID, PartNumber, SerialNumber, WorkOrder };
static ControlType _control;
public static bool Available { get { return ((_com1 != null) && (_com1.IsOpen)); } }
public static bool Close {
get {
if (_com1 == null) return true;
try {
if (_com1.IsOpen) {
_com1.Close();
}
return (!_com1.IsOpen);
} catch { }
return false;
}
}
public static string Open() {
const string na = "Not Available";
if (_com1 == null) {
string reset = Reset();
if (!String.IsNullOrEmpty(reset)) return reset;
}
try {
_com1.Open();
return (_com1.IsOpen) ? null : na;
} catch (Exception err) {
return err.Message;
}
}
static void ProcessData(string incoming) {
_dataIn += incoming;
if ((_control != ControlType.None) && (_textbox != null)) {
bool ok = false;
string testData = _dataIn.Trim();
switch (_control) {
case ControlType.BadgeID:
if (testData.Length == 6) {
if (testData != BarCode.LOGOFF) {
Regex pattern = new Regex(#"[0-9]{6}");
ok = (pattern.Matches(testData).Count == 1);
} else {
ok = true;
}
}
break;
case ControlType.PartNumber:
if (testData.Length == 7) {
Regex pattern = new Regex(#"[BCX][P057][0-9]{5}");
ok = (pattern.Matches(testData).Count == 1);
}
break;
case ControlType.SerialNumber:
if (testData.Length == 15) {
Regex pattern = new Regex(#"[BCX][P057][0-9]{5} [0-9]{4} [0-9]{2}");
ok = (pattern.Matches(testData).Count == 1);
}
break;
case ControlType.WorkOrder:
if (testData.Length == 6) {
Regex pattern = new Regex(#"[0-9]{6}");
ok = (pattern.Matches(testData).Count == 1);
}
break;
}
if (ok) {
_textbox.Text = testData;
_textbox.ScrollToCaret();
_dataIn = null;
}
}
}
static string Reset() {
if (_com1 != null) {
try {
if (_com1.IsOpen) {
_com1.DiscardInBuffer();
_com1.Close();
}
} catch (Exception err) {
return err.Message;
}
Global.Dispose(_com1);
_com1 = null;
}
try {
_com1 = new SerialPort(_port, _baud, _parity, _bits, _stop);
_com1.DataReceived += new SerialDataReceivedEventHandler(Serial_DataReceived);
_com1.Open();
} catch (Exception err) {
return err.Message;
}
return null;
}
public static void ScanSource(ref TextBox objTextBox, ControlType objType) {
_textbox = objTextBox;
_control = objType;
_dataIn = null;
}
static void Serial_DataReceived(object sender, SerialDataReceivedEventArgs e) {
ProcessData(_com1.ReadExisting());
}
public static void Settings(string ComPort, int BaudRate, Parity ParityValue, int Bits, StopBits StopBit) {
_port = ComPort;
_baud = BaudRate;
_parity = ParityValue;
_bits = Bits;
_stop = StopBit;
}
/// <summary>
/// Closes the COM Port
/// COM Port routines are ready to add as soon as I am
/// </summary>
static bool ComPortClose {
get {
if (_com1 == null) ComPortReset();
return ((_com1 == null) ? true : _com1.IsOpen ? false : true);
}
set {
if (_com1 == null) ComPortReset();
else if (_com1.IsOpen) {
_com1.DiscardInBuffer();
_com1.Close();
}
}
}
/// <summary>
/// Opens the COM Port
/// </summary>
static bool ComPortOpen {
get {
if (_com1 == null) ComPortReset();
return (_com1 == null) ? false : _com1.IsOpen;
}
set {
if (_com1 == null) ComPortReset();
if ((_com1 != null) && (!_com1.IsOpen)) _com1.Open();
}
}
/// <summary>
/// Initialized the Serial Port on COM1
/// </summary>
static void ComPortReset() {
if ((_com1 != null) && (_com1.IsOpen)) {
_com1.Close();
_com1 = null;
}
try {
_com1 = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
} catch (IOException err) {
Global.LogError(_CODEFILE + "ComPortReset", err);
}
}
}

Categories