Hi i have create a program in C# to receive a string of ASCII the string is an XML markup.
The computer i receive the data from i have no control over and does not accept a response it sends out data on the COM port about every 10 mins
The Console app i have collects and stores this data but it does not always work i would say about 50% of the time data is missing like a packet or byte was lost and the XML string wont read into XmlDocument
I have been trying for about a week now to make this more stable but this is my first time in C# and would like some help is there anyway to improve this.
CODE
class SerialPortProgram : IDisposable
{
// Create the serial port with basic settings
private SerialPort port = new SerialPort("COM1",
115200, Parity.None, 8, StopBits.One);
string sBuffer = null;
string filePath1 = @"C:\Data\data1.xml";
string filePath2 = @"C:\Data\data2.xml";
[STAThread]
static void Main(string[] args)
{
// Instatiate this class
new SerialPortProgram();
}
private SerialPortProgram()
{
Console.WriteLine("Started Data Monitoring:");
//Attach a method to be called when there
//is data waiting in the port's buffer
port.ReadBufferSize = 20971520;
port.ReceivedBytesThreshold = 1;
port.DataReceived += new SerialDataReceivedEventHandler(Port_DataReceived);
//Begin communications
port.Open();
//Enter an application loop to keep this thread alive
Application.Run();
}
private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//Show all the incoming data in the port's buffer
SerialPort sp = (SerialPort)sender;
sBuffer += sp.ReadExisting();
if (sBuffer.Length > 26000) // check the file size
{
if (sBuffer.Substring(sBuffer.Length - 6) == "</xml>") // check for end of file
{
Console.WriteLine("Found: Processing...");
//Thread.Sleep(1000);
ProcessXML();
sBuffer = null;
Console.WriteLine("Done!");
DateTime now = DateTime.Now;
Console.WriteLine(now);
Console.WriteLine("Monitoring...");
}
else
{
Console.WriteLine("Still Receiving Data: " + sBuffer.Length);
}
}
else
{
Console.WriteLine("Receiving Data: " + sBuffer.Length);
}
}
private void ProcessXML()
{
XmlDocument xmlDoc = new XmlDocument();
try
{
xmlDoc.LoadXml("<wrapper>" + sBuffer + "</wrapper>");
int index = 0;
XmlNodeList xnl = xmlDoc.SelectNodes("wrapper/xml");
foreach (XmlNode node in xnl)
{
// Console.WriteLine(index.ToString());
if (index == 0)// xml file 1
{
using (XmlReader r = new XmlNodeReader(node))
{
DataSet ds = new DataSet();
ds.ReadXml(r);
ds.WriteXml(filePath1);
Console.WriteLine("NEW Data1");
ds.Dispose();
var db = new Database();
db.SaveMetersToDatabase(ds);
}
}
else if (index == 1)// xml file 2
{
using (XmlReader r1 = new XmlNodeReader(node))
{
DataSet dst = new DataSet();
dst.ReadXml(r1);
dst.WriteXml(filePath2);
Console.WriteLine("NEW Data2");
dst.Dispose();
}
}
index++;
}
}
catch
{
Console.WriteLine("Error: in data");
try
{
string now = DateTime.Now.ToString("yyyyMMddHHmmss");
System.IO.File.WriteAllText(@"C:\Data\log" + now + ".xml", "<wrapper>" + sBuffer + "</wrapper>");
}
catch
{
Console.WriteLine("Failed to write to log");
}
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing && port != null)
{
port.Dispose();
port = null;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
UPDATED CODE:
private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//Show all the incoming data in the port's buffer
SerialPort sp = (SerialPort)sender;
sBuffer += sp.ReadExisting();
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
if (sBuffer.Length > 25000) // check the file size
{
if (sBuffer.Substring(sBuffer.Length - 6) == "</xml>") // check for end of file
{
Console.WriteLine("Found: Processing...");
Task.Run(() =>
{
ProcessXML();
sBuffer = null;
Console.WriteLine("Done!");
DateTime now = DateTime.Now;
Console.WriteLine(now);
Console.WriteLine("Monitoring...");
});
}
else
{
Console.WriteLine("Still Receiving Data: " + sBuffer.Length);
}
}
else
{
Console.WriteLine("Receiving Data: " + sBuffer.Length);
}
}).Start();
}
UPDATE
still having this issue could it be possible that the sending computer sometimes does not send all the data or there is packet loss i have tried everything i have tried this new code below using Serial Port BaseStream BeginRead
private SerialPortProgram()
{
Console.WriteLine("Started Data Monitoring:");
//Attach a method to be called when there
try
{
Port.BaudRate = 115200;
Port.DataBits = 8;
Port.Parity = Parity.None;
Port.StopBits = StopBits.One;
Port.Handshake = Handshake.None;
Port.DtrEnable = true;
Port.NewLine = Environment.NewLine;
Port.ReceivedBytesThreshold = 2048;
Port.Open();
byte[] buffer = new byte[35000];
Action StartRead = null;
StartRead = () => {
Port.BaseStream.BeginRead(buffer, 0, buffer.Length, async (IAsyncResult ar) =>
{
try
{
int actualLength = Port.BaseStream.EndRead(ar);
byte[] received = new byte[actualLength];
Buffer.BlockCopy(buffer, 0, received, 0, actualLength);
await Task.Run(() =>
{
sBuffer += Encoding.ASCII.GetString(received);
CheckBuffer();
});
}
catch (Exception exc)
{
Console.WriteLine(exc);
}
StartRead();
}, null);
};
StartRead();
}
catch (Exception ex)
{
Console.WriteLine("Error accessing port." + ex);
Port.Dispose();
Application.Exit();
}
//Enter an application loop to keep this thread alive
Application.Run();
}
private void CheckBuffer()
{
if (sBuffer != null && sBuffer.Length > 26000) // check the file size
{
if (sBuffer.Substring(sBuffer.Length - 6) == "</xml>") // check for end of file
{
new Thread(async () =>
{
Console.WriteLine("Found: Processing...");
await Task.Run(() => ProcessXML());
sBuffer = null;
Console.WriteLine("Done!");
DateTime now = DateTime.Now;
Console.WriteLine(now);
Console.WriteLine("Monitoring...");
}).Start();
}
else
{
Console.WriteLine("Still Receiving Data: " + sBuffer.Length);
}
}
else if (sBuffer != null && sBuffer.Length > 0)
{
Console.WriteLine("Receiving Data: " + sBuffer.Length);
}
}