ocaccy
asked on
Clear the buffer in serial port comunication on C#
How to clear the buffer.
using System;
using System.IO;
using System.IO.Ports;
using System.Threading;
namespace NanoFX
{
/// <summary> CommPort class creates a singleton instance
/// of SerialPort (System.IO.Ports) </summary>
/// <remarks> When ready, you open the port.
/// <code>
/// CommPort com = CommPort.Instance;
/// com.StatusChanged += OnStatusChanged;
/// com.DataReceived += OnDataReceived;
/// com.Open();
/// </code>
/// Notice that delegates are used to handle status and data events.
/// When settings are changed, you close and reopen the port.
/// <code>
/// CommPort com = CommPort.Instance;
/// com.Close();
/// com.PortName = "COM4";
/// com.Open();
/// </code>
/// </remarks>
public sealed class CommPort
{
SerialPort _serialPort;
Thread _readThread;
volatile bool _keepReading;
//begin Singleton pattern
static readonly CommPort instance = new CommPort();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static CommPort()
{
}
CommPort()
{
_serialPort = new SerialPort();
_readThread = null;
_keepReading = false;
}
public static CommPort Instance
{
get
{
return instance;
}
}
//end Singleton pattern
//begin Observer pattern
public delegate void EventHandler(string param);
public EventHandler StatusChanged;
public EventHandler DataReceived;
//end Observer pattern
private void StartReading()
{
if (!_keepReading)
{
_keepReading = true;
_readThread = new Thread(ReadPort);
_readThread.Start();
}
}
private void StopReading()
{
if (_keepReading)
{
_keepReading = false;
_readThread.Join(); //block until exits
_readThread = null;
}
}
/// <summary> Get the data and pass it on. </summary>
private void ReadPort()
{
while (_keepReading)
{
if (_serialPort.IsOpen)
{
byte[] readBuffer = new byte[_serialPort.ReadBufferSize + 1];
try
{
// If there are bytes available on the serial port,
// Read returns up to "count" bytes, but will not block (wait)
// for the remaining bytes. If there are no bytes available
// on the serial port, Read will block until at least one byte
// is available on the port, up until the ReadTimeout milliseconds
// have elapsed, at which time a TimeoutException will be thrown.
int count = _serialPort.Read(readBuffer, 0, _serialPort.ReadBufferSize);
String SerialIn = System.Text.Encoding.Default.GetString(readBuffer,0,count);
DataReceived(SerialIn);
}
catch (TimeoutException) { }
}
else
{
TimeSpan waitTime = new TimeSpan(0, 0, 0, 0, 50);
Thread.Sleep(waitTime);
}
}
}
/// <summary> Open the serial port with current settings. </summary>
public void Open()
{
Close();
try
{
_serialPort.PortName = Settings.Port.PortName;
_serialPort.BaudRate = Settings.Port.BaudRate;
_serialPort.Parity = Settings.Port.Parity;
_serialPort.DataBits = Settings.Port.DataBits;
_serialPort.StopBits = Settings.Port.StopBits;
_serialPort.Handshake = Settings.Port.Handshake;
// Set the read/write timeouts
_serialPort.ReadTimeout = 50;
_serialPort.WriteTimeout = 50;
_serialPort.Open();
StartReading();
}
catch (IOException)
{
StatusChanged(String.Format("{0} does not exist", Settings.Port.PortName));
}
catch (UnauthorizedAccessException)
{
StatusChanged(String.Format("{0} already in use", Settings.Port.PortName));
}
catch (Exception ex)
{
StatusChanged(String.Format("{0}", ex.ToString()));
}
// Update the status
if (_serialPort.IsOpen)
{
string p = _serialPort.Parity.ToString().Substring(0, 1); //First char
string h = _serialPort.Handshake.ToString();
if (_serialPort.Handshake == Handshake.None)
h = "no handshake"; // more descriptive than "None"
StatusChanged(String.Format("{0}: {1} bps, {2}{3}{4}, {5}",
_serialPort.PortName, _serialPort.BaudRate,
_serialPort.DataBits, p, (int)_serialPort.StopBits, h));
}
else
{
StatusChanged(String.Format("{0} already in use", Settings.Port.PortName));
}
}
/// <summary> Close the serial port. </summary>
public void Close()
{
StopReading();
_serialPort.Close();
StatusChanged("connection closed");
}
/// <summary> Get the status of the serial port. </summary>
public bool IsOpen
{
get
{
return _serialPort.IsOpen;
}
}
/// <summary> Get a list of the available ports. Already opened ports
/// are not returend. </summary>
public string[] GetAvailablePorts()
{
return SerialPort.GetPortNames();
}
/// <summary>Send data to the serial port after appending line ending. </summary>
/// <param name="data">An string containing the data to send. </param>
public void Send(string data)
{
if (IsOpen)
{
string lineEnding = "";
switch (Settings.Option.AppendToSend)
{
case Settings.Option.AppendType.AppendCR:
lineEnding = "\r"; break;
case Settings.Option.AppendType.AppendLF:
lineEnding = "\n"; break;
case Settings.Option.AppendType.AppendCRLF:
lineEnding = "\r\n"; break;
}
_serialPort.Write(data + lineEnding);
}
}
}
}
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Hi, AndyAinscow and mcs0506.
No, I don´t create another buffer.
My question is wrong!
Having the 6 devices.
ID01, ID02, ID03, ID04, ID05, ID06.
I need to send the command to access the devices at intervals of 10 seconds.
The button is up. XX or YY
I get the data in: RECEIVING DATA below.
Through the code and the problem is:
I think the logic, or event triggered by the button, to send commands and receive data, are wrong.
Sometimes I get no data.
Or because the devices did not receive the command, or collided, still do not know.
Thread.Sleep(150);
If Thread.Sleep(20);
Receive error message .....Length....
And the pointer stop in this line.
if (InvokeRequired)
{
Invoke(new StringDelegate(OnDataRecei ved), new object[] { dataIn });
return;
}
No, I don´t create another buffer.
My question is wrong!
Having the 6 devices.
ID01, ID02, ID03, ID04, ID05, ID06.
I need to send the command to access the devices at intervals of 10 seconds.
The button is up. XX or YY
I get the data in: RECEIVING DATA below.
Through the code and the problem is:
I think the logic, or event triggered by the button, to send commands and receive data, are wrong.
Sometimes I get no data.
Or because the devices did not receive the command, or collided, still do not know.
Thread.Sleep(150);
If Thread.Sleep(20);
Receive error message .....Length....
And the pointer stop in this line.
if (InvokeRequired)
{
Invoke(new StringDelegate(OnDataRecei
return;
}
RECEIVING DATA
#region Event handling - data received and status changed
/// <summary>
/// Prepare a string for output by converting non-printable characters.
/// </summary>
/// <param name="StringIn">input string to prepare.</param>
/// <returns>output string.</returns>
private String PrepareData(String StringIn)
{
// The names of the first 32 characters
string[] charNames = {
// "NUL", "SOH", "STX", "ETX", "EOT",
//"ENQ", "ACK", "BEL", "BS", "TAB", "LF", "VT", "FF", "CR", "SO", "SI",
//"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB",
//"ESC", "FS", "GS", "RS", "US", "Space"
};
string StringOut = "";
foreach (char c in StringIn)
{
if (Settings.Option.HexOutput)
{
StringOut = StringOut + String.Format("{0:X2} ", (int)c);
}
else if (c < 32 && c != 9)
{
StringOut = StringOut + "";// +"<"+charNames[c]+">";
//Uglier "Termite" style
//StringOut = StringOut + String.Format("[{0:X2}]", (int)c);
}
else
{
StringOut = StringOut + c;
}
}
return StringOut;
}
/// <summary>
/// Partial line for AddData().
/// </summary>
private Line partialLine = null;
/// <summary>
/// Add data to the output.
/// </summary>
/// <param name="StringIn"></param>
/// <returns></returns>
private Line AddData(String StringIn)
{
String StringOut = PrepareData(StringIn);
// if we have a partial line, add to it.
if (partialLine != null)
{
// tack it on
partialLine.Str = partialLine.Str + StringOut;
outputList_Update(partialLine);
return partialLine;
}
return outputList_Add(StringOut, receivedColor);
}
// delegate used for Invoke
internal delegate void StringDelegate(string data);
/// <summary>
/// Handle data received event from serial port.
/// </summary>
/// <param name="data">incoming data</param>
public void OnDataReceived(string dataIn)
{
//Handle multi-threading
if (InvokeRequired)
{
Invoke(new StringDelegate(OnDataReceived), new object[] { dataIn });
return;
}
// pause scrolling to speed up output of multiple lines
bool saveScrolling = scrolling;
scrolling = false;
// if we detect a line terminator, add line to output
int index;
while (dataIn.Length > 0 &&
((index = dataIn.IndexOf("\r")) != -1 ||
(index = dataIn.IndexOf("\n")) != -1))
{
String StringIn = dataIn.Substring(0, index);
dataIn = dataIn.Remove(0, index + 1);
logFile_writeLine(AddData(StringIn).Str);
logFile_writeLine1(AddData(StringIn).Str);
//listBox3.Items.Add(AddData(StringIn).Str);
partialLine = null; // terminate partial line
}
// if we have data remaining, add a partial line
if (dataIn.Length > 0)
{
partialLine = AddData(dataIn);
}
// restore scrolling
scrolling = saveScrolling;
outputList_Scroll();
listBox1_Scroll();
}
ASKER
We had a problem of not receiving data, and receive duplicate data from the serial port with 6 devices RS485/USB, connected to the pc by a converter USB/RS485.
We solve the problem.
I used the code below.
Best Regards,
ocaccy.
We solve the problem.
I used the code below.
Best Regards,
ocaccy.
// timer-10 interval= 10000ms
// timer-01 interval= 200ms
// timer-02 interval= 200ms
// timer-03 interval= 200ms
// timer-04 interval= 200ms
// timer-05 interval= 200ms
// timer-06 interval= 200ms
private void GetData_Click(object sender, EventArgs e)
{
timer_10.Enabled = true;
}
private void timer_10_Tick(object sender, EventArgs e)
{
timer_01.Enabled = true;
}
#region timer_01_Tick
private void timer_01_Tick(object sender, EventArgs e)
{
#region WORKING ID01
this.dataReceived = false;
send_t = 0;
free1.Enabled = true;
#endregion
}
private void free1_Tick(object sender, EventArgs e)
{
if (send_t == 3)
{
this.dataReceived = true;
}
if (this.dataReceived == false)
{
string s_ID01_c = "id01";
CommPort com = CommPort.Instance;
s_ID01_c = ConvertEscapeSequences(s_ID01_c);
com.Send(s_ID01_c);
send_t = send_t + 1;
}
else
{
free1.Enabled = false;
timer_02.Enabled = true;
timer_01.Enabled = false;
}
}
#endregion
// After ends 01, chage to 02, to 03...........
ASKER
We had a problem of not receiving data, and receive duplicate data from the serial port with 6 devices RS485/USB, connected to the pc by a converter USB/RS485.
We solve the problem.
I used the code below.
Best Regards,
ocaccy.
// timer-10 interval= 10000ms
// timer-01 interval= 200ms
// timer-02 interval= 200ms
// timer-03 interval= 200ms
// timer-04 interval= 200ms
// timer-05 interval= 200ms
// timer-06 interval= 200ms
private void GetData_Click(object sender, EventArgs e)
{
timer_10.Enabled = true;
}
private void timer_10_Tick(object sender, EventArgs e)
{
timer_01.Enabled = true;
}
#region timer_01_Tick
private void timer_01_Tick(object sender, EventArgs e)
{
#region WORKING ID01
this.dataReceived = false;
send_t = 0;
free1.Enabled = true;
#endregion
}
private void free1_Tick(object sender, EventArgs e)
{
if (send_t == 3)
{
this.dataReceived = true;
}
if (this.dataReceived == false)
{
string s_ID01_c = "id01";
CommPort com = CommPort.Instance;
s_ID01_c = ConvertEscapeSequences(s_I D01_c);
com.Send(s_ID01_c);
send_t = send_t + 1;
}
else
{
free1.Enabled = false;
timer_02.Enabled = true;
timer_01.Enabled = false;
}
}
#endregion
// After ends 01, chage to 02, to 03...........
We solve the problem.
I used the code below.
Best Regards,
ocaccy.
// timer-10 interval= 10000ms
// timer-01 interval= 200ms
// timer-02 interval= 200ms
// timer-03 interval= 200ms
// timer-04 interval= 200ms
// timer-05 interval= 200ms
// timer-06 interval= 200ms
private void GetData_Click(object sender, EventArgs e)
{
timer_10.Enabled = true;
}
private void timer_10_Tick(object sender, EventArgs e)
{
timer_01.Enabled = true;
}
#region timer_01_Tick
private void timer_01_Tick(object sender, EventArgs e)
{
#region WORKING ID01
this.dataReceived = false;
send_t = 0;
free1.Enabled = true;
#endregion
}
private void free1_Tick(object sender, EventArgs e)
{
if (send_t == 3)
{
this.dataReceived = true;
}
if (this.dataReceived == false)
{
string s_ID01_c = "id01";
CommPort com = CommPort.Instance;
s_ID01_c = ConvertEscapeSequences(s_I
com.Send(s_ID01_c);
send_t = send_t + 1;
}
else
{
free1.Enabled = false;
timer_02.Enabled = true;
timer_01.Enabled = false;
}
}
#endregion
// After ends 01, chage to 02, to 03...........
ASKER
I have 6 RS485 devices connected to the computer through a converter RS485/USB.
To get the data I need to send a command to each device. id01, id02, id03, id04, id05, id06 twice.
XX and YY
Are defective, analyze and help me please.
In the twentieth sending twice the same data often return only once, but sometimes I get duplicate data and need to clean it.
The why of my question is as follows.
I have 6 RS485 devices connected to the computer through RS485/USB to convert.
To get the data I need to send a command to each device. id01, id02, id03, id04, id05, id06 twice.
The first time the sensor is ready.
The second time the device invoked responds.
Sometimes I get 2 times the same id return due to the fact that 2 times to send the same command.
But only want to get the data one time every 10 seconds. Hence my question to reset the buffer.
I have two buttons that do the work sending commands.
XX and YY
Are defective, analyze and help me please.
In the twentieth sending twice the same data often return only once, but sometimes I get duplicate data and need to clean it.
How to fix this?
Open in new window
Open in new window