I Have created some code for communicating with a device over the serialport. By sending certain command with serialPort1.WriteLine
I should receive answer with serialPort1.ReadExisting()
. Well I'm able to detect the device but I need to read some other information but to get this information correct I only get it when I place the code in a button_Click
function. The funny thing is that All is written in a function and I wish to get the information after the device is detected immediately. When I call the function after the device has been detected it doesn't work and when I call the function after the button is pressed I get the correct information. I do not understand why this is so.
The function for detecting the device is like this:
private void detectVM25ToolStripMenuItem_Click(object sender, EventArgs e)
{
// Detect VM25 and show connection is established
String device;
//Search all portnames
String[] ports = SerialPort.GetPortNames();
int totalPorts = ports.Length;
int count = 0 ;
//Test which enabled port is the VM25.
foreach (string port in ports)
{
count = count 1;
serialPort1.PortName = port;
serialPort1.Open();
if (serialPort1.IsOpen)
{
serialPort1.WriteLine("#S" Environment.NewLine);
answer = serialPort1.ReadExisting();
if (answer != "")
{
device = answer.Substring(0, 4);
if (device == "VM25")
{
getRecordings();
statusLblDevice.ForeColor = Color.LawnGreen;
statusLblDevice.Text = port " - " device " - Connected";
VM25Port = port;
}
}
else if (answer == "")
{
serialPort1.Close();
if (count == totalPorts)
{
MessageBox.Show("No device found");
}
}
}
}
}
The function getRecordings()
should give me data. If I place this function in my form and get called after a button is pressed I get the correct info but when it is inside the above function it doesn't do anything.
private void getRecordings()
{
if (serialPort1.IsOpen)
{
serialPort1.WriteLine("#H" Environment.NewLine);
memoryInfo = serialPort1.ReadExisting();
label1.Text = memoryInfo;
}
}
Does anybody knows why this is the case? I would like not to have press a button and get this information after it has detected the device. I also tried to create a delay with `Task.Delay()' unfortunately this did not help
CodePudding user response:
It's surely because you have no synchronization whatsoever. .ReadExisting()
does not get an entire response, it gets only what's already been received. So calling it right after .WriteLine(...)
... well your data hasn't even reached the device yet, so there definitely won't be an answer ready to read.
Since you know the length of your expected answer (or at least the prefix you're interested in), set the read timeout and then call .Read()
(or better, .BaseStream.ReadAsync()
) with that length.
Even that is only going to mostly work when the port is freshly opened... for subsequent commands you risk getting data in your buffer from the tail end of a reply to an earlier command. Correct use of a serial port really requires the two ends to agree on some sort of framing, whether that is "a message contains only ASCII and ends with CR LF" or "a message starts with the length of its payload" or some less common scheme.
CodePudding user response:
with the point out of @Ben Voigt I discovered I should tackle this issue different.
I have use the method serialPort1.ReadTo()
because I know that each message end with "/a".
therefore I fixed the function as follows
private void detectVM25ToolStripMenuItem_Click(object sender, EventArgs e)
{
// Detect VM25 and show connection is established
String device;
//Search all portnames
String[] ports = SerialPort.GetPortNames();
int totalPorts = ports.Length;
int count = 0 ;
//Test which enabled port is the VM25.
foreach (string port in ports)
{
count = count 1;
serialPort1.PortName = port;
serialPort1.Open();
if (serialPort1.IsOpen)
{
serialPort1.WriteLine("#S" Environment.NewLine);
answer = serialPort1.ReadExisting();
if (answer != "")
{
device = answer.Substring(0, 4);
if (device == "VM25")
{
statusLblDevice.ForeColor = Color.LawnGreen;
statusLblDevice.Text = port " - " device " - Connected";
VM25Port = port;
serialPort1.WriteLine("#H" Environment.NewLine);
string input = serialPort1.ReadTo("/a");
label1.Text = input;
string totalMeasurements = input.Substring(0, 11);
string totalFFT = input.Substring(11, 11);
statusLblMeas.Text = totalMeasurements;
statusLblFFT.Text = totalFFT;
}
}
else if (answer == "")
{
serialPort1.Close();
if (count == totalPorts)
{
MessageBox.Show("No device found");
}
}
}
}
}
Note the changes of reading the serialport where I stated that it should read up to "/a"