Hi to all i am new here and i have heard a lot about this website that it really helps you out. Hope you will be able to help me out!.
I have a very simple program which its only aim is to read from a serial port and prints it on the console window in C# for 2000 times.
I am just turning a variable resistor on a micro-controller that's all
Here below is the code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
namespace Testing_serial_v3._0
{
class Program
{
static void Main(string[] args)
{
string buff;
SerialPort port = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
port.Open();
for (int i = 0; i < 2000; i++)
{
buff = port.ReadLine();
Console.WriteLine(buff);
//Console.ReadLine();
}
}
}
}
But there is a funny thing happening in this code. When the console readline is commented as shown in the code above the value from the port changes as i turn the knob of the variable resistor. So this means it is working good.
On the other hand if i make the readline happen so that after each value i have to press a key the port reads the current value and even though i change the knob and press enter again the value will remain the first as if it is not resetting at all?
Do you have to include any other command lines so that the port will reset?
Hope you understand my problem and any other questions you need to know please don't hesitate i really need this problem fixed ASAP.
Many thanks and regards
The data coming through the port is a stream - when you read, you are gradually consuming the stream. You are not seeing "the most recent value", you are seeing "the next value in the stream". When you add the read-line, you add a delay which means there is a large backlog of data. It isn't that "it stayed the same"... Simply that you haven't read to the end (and the more recent values) yet.
In many cases, it would be preferable to deal with the network IO via an async callback so that reading values from the stream is not tied into delays like human data entry. That may involve some knowledge of threading, though.
You could also use a Task to read it in a separate thread and observe it there, kind of what #Marc Gravel mentions. You just have to wait until the task is finished or press enter to cancel it manually. Just another example of offloading the task to another thread.
Here's an example:
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ReadStreamAsyncTask
{
internal class Program
{
private static CancellationToken _cancelTaskSignal;
private static byte[] _serialPortBytes;
private static MemoryStream _streamOfBytesFromPort;
private static CancellationTokenSource _cancelTaskSignalSource;
private static void Main()
{
_serialPortBytes = Encoding.ASCII.GetBytes("Mimic a bunch of bytes from the serial port");
_streamOfBytesFromPort = new MemoryStream(_serialPortBytes);
_streamOfBytesFromPort.Position = 0;
_cancelTaskSignalSource = new CancellationTokenSource();
_cancelTaskSignal = _cancelTaskSignalSource.Token; // Used to request cancel the task if needed.
var readFromSerialPort = Task.Factory.StartNew(ReadStream, _cancelTaskSignal);
readFromSerialPort.Wait(3000); // wait until task is complete(or errors) OR 3 seconds
Console.WriteLine("Press enter to cancel the task");
_cancelTaskSignalSource.Cancel();
Console.ReadLine();
}
private static void ReadStream()
{
// start your loop here to read from the port and print to console
Console.WriteLine("Port read task started");
int bytesToReadCount = Buffer.ByteLength(_serialPortBytes);
var localBuffer = new byte[bytesToReadCount];
int bytesRead = 0;
bool finishedReading = false;
try
{
while (!finishedReading)
{
_cancelTaskSignal.ThrowIfCancellationRequested();
bytesRead += _streamOfBytesFromPort.Read(localBuffer, 0, bytesToReadCount);
finishedReading = (bytesRead - bytesToReadCount == 0);
}
}
catch (TaskCanceledException)
{
Console.WriteLine("You cancelled the task");
}
Console.WriteLine(Encoding.ASCII.GetString(localBuffer));
Console.WriteLine("Done reading stream");
}
}
}
You are sending thousands of data from micro-controller to the serial port (with delay of 1ms for ex.), which makes the buffer of the serial port filled with same values! If you read it one by one by pressing enter key, you are reading the first received ones...
I think if you want to read your data in computer by "Enter" key, you should send the date from micro-controller by a push button! It means you set the value by resistor, press the push button, the micro sends "One Byte" to the computer. You press the enter on the computer and let your computer read just "One Byte" from the serial port!
Also some modification to your code:
static void Main(string[] args)
{
int buff; // string to int
SerialPort port = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
port.Open();
for (int i = 0; i < 2000; i++)
{
Console.ReadLine(); // wait for the Enter key
buff = port.ReadByte(); // read a byte
Console.WriteLine(buff);
}
}
I hope this will work for you! :)
Related
I am using C# Console app to interact with firmware on sas Expander card.
It was connected by RS232 Serial Port.
Here is the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.Threading;
namespace SerialPortExample
{
class SerialPortProgram
{
// Create the serial port with basic settings
[STAThread]
static void Main()
{
SerialPort mySerialPort = new SerialPort("COM5");
mySerialPort.BaudRate = 115200;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.RtsEnable = true;
mySerialPort.DtrEnable = true;
mySerialPort.ReadTimeout = 2000;
mySerialPort.WriteTimeout = 1000;
mySerialPort.Open();
if(mySerialPort.IsOpen)
{
mySerialPort.Write("\r");
}
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
while (true)
{
string userResponse = Console.ReadLine();
if (userResponse == "sys")
{
mySerialPort.Write("sys\r");
}
else if (userResponse == "counters")
{
mySerialPort.Write("counters\r");
}
else if (userResponse == "phyinfo")
{
mySerialPort.Write("phyinfo\r");
}
else if (userResponse == "? -a")
{
mySerialPort.Write("? -a\r");
}
else
{
mySerialPort.Write("\r");
}
}
}
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.Write(indata);
}
}
}
What the app execute command counters result:
Using PuTTy by sending command counters result:
You can see counters will show up on the app page
and counters won't show up in PuTTY's page.
What should I do to let my code result just like PuTTY does?
How to hide some return data from Serial Port?
My C# Console app is using .Net Framwork 4.7.2.
.....................................................
Update:
After I add mySerialPort.ReadChar(); in code,
the code looks like:
string userResponse = Console.ReadLine();
if (userResponse == "sys")
{
mySerialPort.Write("sys\r");
mySerialPort.ReadChar();
mySerialPort.ReadChar();
mySerialPort.ReadChar();
}
and the result is:
I am not satisfied with this result
because there are at least twenty command in firmware.
I don't want keep adding mySerialPort.ReadChar() in every condition.
Is there another way to fullfill my goal?
.......................................................
Update Part2:
After adding string echocancel = sp.ReadLine(); in DataReceivedHandler,
the code looks like:
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string echocancel = sp.ReadLine();
string indata = sp.ReadExisting();
Console.Write(indata);
}
and the result looks like:
After product identity :'s word should have default
and between product Identity and <<Alarm status>>
should have space, it should show up.
At least, sys , this three character won't show up again.
Did someone has some solution about it?
Seems like a situation of double echo of keyboard input.
By default the typical terminal emulation program (e.g. minicom) disables local echo for keyboard input; apparent putty does the same.
So when the attached device does echo the typed input, you only see one copy of the input displayed.
(Because of this default mode, you will not see what you type when the attached device also has its echo inhibited.)
With your program, characters typed as input on keyboard are echoed locally to your display, and when transmitted that line is echoed by the attached device and then displayed (by your program) as part of the response.
You can verify this hypothesis by changing your code to accept a foo command instead of counters:
...
else if (userResponse == "foo")
{
mySerialPort.Write("counters\r");
}
...
The expected display should then be something like
bp1 >foo
counters
...
Possible solutions are:
a. disable echo from the device (preferred), or
b. disable local echo, or
c. echo cancellation.
Echo cancellation can be simplified in your program because each command transmitted seems to be a line terminated by a carriage return. So instead of absorbing individual characters as you did for an individual command, you only need a single read of a line to absorb the echoed line:
while (true)
{
string userResponse = Console.ReadLine();
if (userResponse == "sys")
...
else
{
mySerialPort.Write("\r");
}
/*
* might need a delay here allow serial output to drain/complete
* and give device time to respond
*/
string echocancel = mySerialPort.Readline();
}
However such echo cancellation would also require proper setting of the line-terminator character, i.e. mySerialPort.NewLine = "\r";
See
https://learn.microsoft.com/en-us/dotnet/api/system.io.ports.serialport.newline?redirectedfrom=MSDN&view=dotnet-plat-ext-5.0#System_IO_Ports_SerialPort_NewLine
Note that disabling echo from the device is the standard mode for (serial) communication with a device by software (i.e. machine to machine). This simply reduces the amount of data transferred. Echo is only enabled for the convenience of humans.
What is the local echo in my code? Console.ReadLine()?
For Linux, minicom disables local echo by configuring termios flags for stdin (aka the keyboard).
Seems like you're using Windows, so I don't know the equivalent operation.
Yes, the local echo should be occurring during the Console.ReadLine().
Addendum in response to Update Part2
My suggestion for echo cancellation guarantees that only one line of input would be discarded per command sent.
Your modification differs from my suggestion in order to keep all serial port reads within a single procedure/handler.
However that could introduce a synchronization issue, because now you have to ensure that DataReceivedHandler() is performed only once per iteration of the while loop that receives userResponse.
But there seems to be absolutely nothing in that while loop that could enforce any synchronization with DataReceivedHandler().
Prior to this echo cancellation modification, your program really didn't have to rely on any synchronization. Since DataReceivedHandler() simply displayed whatever it received, this data transfer seems flawless, and you weren't concerned about how indata aligned with the text of the response.
To test this synchronization hypothesis, report the line(s) that is/are being discarded for echo cancellation, e.g.
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string echocancel = sp.ReadLine();
Console.WriteLine($"DEBUG: {echocancel}");
string indata = sp.ReadExisting();
Console.Write(indata);
}
In practice echo cancellation is probably the method of last choice in comparison to simply avoiding the generation of the echo. Some schemes validate the received data prior to discarding (e.g. using a FIFO of expected echo data) to ensure the cancellation is accurate.
I'm doing a TCP Messenger Programm ATM with TCPClient and TCPListener. Everything is working fine. I've had both of these in separate programs and now I'm basically trying to make it one Program. I'm stuck with the fact that it is always WAITING till I have something written to send it before it goes to checking the receive. I'm new to C# and learning. So I need a way to check "is something written? If no, then skip this" basically a bool to ask if something is written.
I've tried to make it like "if the line in storage right now is the same as the was the last time, skip it" so it doesnt stuck infinitly in the Send sector of the program. But still it ALWAYS waits until I wrote something before it even checks/ skips it.
This is the write and send loop code:
nachricht = Console.ReadLine();
if (nachrichtcheck != nachricht)
{
Console.WriteLine("test1");
TcpClient clientnachricht = new TcpClient(zielip, port);
NetworkStream streamnachricht = clientnachricht.GetStream();
sendnachricht = Encoding.ASCII.GetBytes(nachricht);
streamnachricht.Write(sendnachricht, 0, sendnachricht.Length);
streamnachricht.Close();
clientnachricht.Close();
nachrichtcheck = nachricht;
Console.WriteLine("test2");
}
else
{
if (empfangstream.CanRead)
{
Console.WriteLine("test3");
byte[] receivedBuffer2 = new byte[100];
NetworkStream stream = empfangclient.GetStream();
stream.Read(receivedBuffer, 0, receivedBuffer.Length);
StringBuilder msg2 = new StringBuilder();
foreach (byte b in receivedBuffer)
{
if (b.Equals(00))
{
break;
}
else
msg2.Append(Convert.ToChar(b).ToString());
}
Console.WriteLine("test4");
empfangscheck2 = msg2.ToString();
if (empfangscheck2 != empfangscheck)
{
Console.WriteLine(msg2.ToString());
empfangscheck = msg2.ToString();
Console.WriteLine("receive");
}
}
}
So if someone can help me just getting a way to get a bool to check if something is written -> then use it. Except of wait until something is written -> use it it would help me miles.
I've got an alternative to solve your problem. You can use a thread to wait for an user input instead of your actual code.
(I've also considered your german language)
Code Example:
using System;
using System.Threading;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
string nachricht = "";
double AndereTätigkeitBeweis = 0;
Thread NachrichtenEinleser = new Thread(()=> {
Console.Write("Gib diene zu sendende Nachricht ein: ");//Type in the message you'd like to send
nachricht = Console.ReadLine();//Read the user Input without stopping the actual code because it's another process
});
NachrichtenEinleser.Start();
//do somewhat activity until you get a user input
while (nachricht == ""){
AndereTätigkeitBeweis++;
}
//Write out the user input
Console.WriteLine($"User Input: {nachricht}|AndereTätigkeitBeweis: {AndereTätigkeitBeweis}");
Console.ReadLine();
}
}
}
Output example:
Gib diene zu sendende Nachricht ein: hallo
User Input: hallo|AndereTätigkeitBeweis: 560075647
Hope this helps.
I'm having a very peculiar issue with the serial port class in C# (using .NET 4.5 as a target). Our application needs the ability to switch between (close then open another) serial COM ports which are all USB 1.1 virtual COM port devices. The problem I'm having has two symptoms that may be related. First, we can only connect to our device after having already read from it using another terminal emulator or similar application and even then only once. After one successful connection all other attempts after closing and re-opening the port will never receive data (DataReceivedEvent never fires). The only workaround I have found to this is to manually drive the RTS signal as shown below (even though every other serial library or emulation program requires no handshaking to talk to this device, including TerraTerm, Java, and PySerial).
Second, even then, while the port may be freely opened and closed successful, occasionally (1/30 ish) the Open() or Close() functions take precisely 30 seconds to finish (30008 ms measured via a diagnostic Stopwatch) where it would normally take a mere 5-8 ms. There seems to be no explanation for this. Any thoughts?
Measures already used to try eliminating or mitigating the problem:
Attempts to Open or Close the port are executed as separate tasks in the thread pool so that they can be terminated or aborted cleanly after a specified period of time if unsuccessful (I use 60 seconds for this value in testing)
I've added various time delays both short (100 ms) and extreme (5000 ms) in every conceivable place with no effect (between port close and reopen, between open and close, and between open/close and RTS true/false
Double triple and quadruple checked the designed port parameters for our USB serial device
I've looked at this article by bvoigt and this article by Zach Saw which both seem to suggest that there are deeply rooted issues with .NET SerialPort class. This has left me with the impression that a third party library might be the best option (there are some good candidates on NuGet). Ultimately this will be used as the serial port within a WPF application.
Before anyone asks, no, simply opening the port and leaving it open is not an option in our application and, frankly, this is something that works seamlessly 100% of the time with the same device from the same hosts with the same driver in other languages' standard serial implementations (see above).
Please see the simple exemplary application below which I have been using to successfully reproduce this problem. Any pointers in the right direction are greatly appreciated!!!
SerialTestApplication.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.Diagnostics;
using System.Threading;
namespace SerialTestApplication
{
class Program
{
private SerialPort S = new SerialPort();
private bool S_active = false;
private int succeed = 0;
private int fail = 0;
static void Main(string[] args)
{
Program P = new Program();
System.Threading.Thread.Sleep(1000);
var test_timer = new Stopwatch();
test_timer.Start();
for (int a = 0; a < 100; a++)
{
P.ConnectSerial(P);
P.CloseSerial(P);
}
Console.WriteLine("EXIT");
System.Threading.Thread.Sleep(1000);
Console.ReadLine();
}
private bool ConnectSerial(Program P)
{
if (S.IsOpen)
{
fail++;
Console.WriteLine("PORT NOT CLOSED YET");
return false;
}
// Setup The Serial COMM Port
S.PortName = "COM1";
S.BaudRate = 115200;
S.Handshake = System.IO.Ports.Handshake.None;
S.Parity = Parity.None;
S.DataBits = 8;
S.StopBits = StopBits.One;
// Write Properties
S.WriteBufferSize = 2048;
S.WriteTimeout = 500;
// Read Properties
S.ReceivedBytesThreshold = 1;
S.ReadBufferSize = 2048;
S.ReadTimeout = 500;
try
{
S_active = false;
if (!P.OpenSerial(P))
{
fail++;
return false;
}
var connection_timer = new Stopwatch();
connection_timer.Start();
while (S.IsOpen && !S_active)
{
if (connection_timer.ElapsedMilliseconds > 1000)
{
fail++;
CloseSerial(this);
Console.WriteLine("Succeed/Fail: " + succeed + " " + fail);
return false;
}
}
succeed++;
Console.WriteLine("Succeed/Fail: " + succeed + " " + fail);
Console.WriteLine(S.BytesToWrite + " " + S.BytesToRead);
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
private void Receive(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (S.IsOpen)
{
S_active = true;
S.ReadExisting();
}
}
private bool OpenSerial(Program P)
{
Task OpenAttempt = Task.Factory.StartNew(() =>
{
try
{
if (S.IsOpen)
{
Console.WriteLine("PORT STILL OPEN!");
return;
}
S.Open();
S.DiscardInBuffer();
S.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(Receive);
S.RtsEnable = true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
});
var open_timer = new Stopwatch();
open_timer.Start();
OpenAttempt.Wait(60000);
Console.WriteLine("Opened In: " + open_timer.ElapsedMilliseconds);
return S.IsOpen;
}
private void CloseSerial(Program P)
{
Task CloseAttempt = Task.Factory.StartNew(() =>
{
try
{
S.RtsEnable = false;
S.Close();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
});
var close_timer = new Stopwatch();
close_timer.Start();
CloseAttempt.Wait(60000);
Console.WriteLine("Closed In: " + close_timer.ElapsedMilliseconds);
}
}
}
EDIT 1
I've found one issue with this but unfortunately it doesn't solve the core "takes 30 seconds to finish the Open() or Close() method" problem. The way I am recycling (closing and reopening) the SerialPort object in this test application adds a new DataReceived event handler every time the port is reopened. Basically after closing/opening the port 10 times there will be ten DataReceived handlers associated with the object. To correct that I'm now letting Close() Dispose() the SerialPort object then setting the reference to null and creating a completely new instance of SerialPort on the next open. That seems to ensure that the serial port is properly released so long as the USB cable is not physically pulled out of the computer.
I am new to netduino so I have a simple question (or, it should be simple).
What I want to do is to send an integer (string) via rs232 from my winform app to my netduino plus 2, and then, my netduino should read that integer and blink an onboard led that many times.
I have read online tutorial on that topic and found some examples that should provide communication between my PC and Netduino.
Yes, I did got an echo from it. I am getting an echo even if I disconnect my netduino and hide it in my pocket :).
So much for my understanding of that gadget.
How can I send an info to my Netduino via rs232 cabel that he can read, understand and act accordingly?
There is a code straight from the the web:
For NETDUINO:
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
using System.IO.Ports;
namespace NetduinoApplication1
{
public class Program
{
static SerialPort serial;
public static void Main()
{
// initialize the serial port for COM1 (using D0 & D1)
serial = new SerialPort(SerialPorts.COM1, 9600, Parity.None, 8, StopBits.One);
// open the serial-port, so we can send & receive data
serial.Open();
// add an event-handler for handling incoming data
serial.DataReceived += new SerialDataReceivedEventHandler(serial_DataReceived);
OutputPort led = new OutputPort(Pins.ONBOARD_LED, false);
for (int i = 0; i < 3; i++)
{
led.Write(true); // turn on the LED
Thread.Sleep(250); // sleep for 250ms
led.Write(false); // turn off the LED
Thread.Sleep(250); // sleep for 250ms
}
// wait forever...
Thread.Sleep(Timeout.Infinite);
}
static void serial_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// create a single byte array
byte[] bytes = new byte[1];
// as long as there is data waiting to be read
while (serial.BytesToRead > 0)
{
// read a single byte
serial.Read(bytes, 0, bytes.Length);
// send the same byte back
serial.Write(bytes, 0, bytes.Length);
OutputPort led1 = new OutputPort(Pins.ONBOARD_LED, false);
led1.Write(true); // turn on the LED
Thread.Sleep(250); // sleep for 250ms
led1.Write(false); // turn off the LED
Thread.Sleep(250); // sleep for 250ms
}
}
}
}
And the code for my console:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
namespace ConsoleRSS
{
class Program
{
static SerialPort serial;
static void Main(string[] args)
{
// provide some usage information
System.Console.WriteLine("enter some text and hit ENTER.");
System.Console.WriteLine("enter 'x' and hit ENTER to exit.");
System.Console.WriteLine();
// initialize the serial port for COM3 (could be other port, depends on system)
serial = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
// open the serial-port, so we can send & receive data
serial.Open();
// add an event-handler for handling incoming data
serial.DataReceived += new SerialDataReceivedEventHandler(serial_DataReceived);
// this will hold each line entered
string line = string.Empty;
// as long as an x is not entered
while (line.ToLowerInvariant() != "x")
{
// read a single line from the console
line = System.Console.ReadLine();
// convert the line to bytes
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(line);
// send the bytes over the serial-port
serial.Write(utf8Bytes, 0, utf8Bytes.Length);
}
}
static void serial_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// wait a little for the buffer to fill
System.Threading.Thread.Sleep(100);
// create an array for the incoming bytes
byte[] bytes = new byte[serial.BytesToRead];
// read the bytes
serial.Read(bytes, 0, bytes.Length);
// convert the bytes into a string
string line = System.Text.Encoding.UTF8.GetString(bytes);
// write the received bytes, as a string, to the console
System.Console.WriteLine("echo: " + line);
System.Console.WriteLine();
}
}
}
I'm not sure what problem you are actually getting with this? Your code at first glance looks correct.
I would try checking your hardware first, so is the usb cable actually set as COM 1 in device manager on your pc? Is the cable connected to the correct ports in the netduino?
I'm trying to write a small application that simply reads data from a socket, extracts some information (two integers) from the data and sends the extracted information off on a serial port.
The idea is that it should start and just keep going. In short, it works, but not for long. After a consistently short period I start to receive IOExceptions and socket receive buffer is swamped.
The thread framework has been taken from the MSDN serial port example.
The delay in send(), readThread.Join(), is an effort to delay read() in order to allow serial port interrupt processing a chance to occur, but I think I've misinterpreted the join function. I either need to sync the processes more effectively or throw some data away as it comes in off the socket, which would be fine. The integer data is controlling a pan tilt unit and I'm sure four times a second would be acceptable, but not sure on how to best acheive either, any ideas would be greatly appreciated, cheers.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static bool _continue;
static SerialPort _serialPort;
static Thread readThread;
static Thread sendThread;
static String sendString;
static Socket s;
static int byteCount;
static Byte[] bytesReceived;
// synchronise send and receive threads
static bool dataReceived;
const int FIONREAD = 0x4004667F;
static void Main(string[] args)
{
dataReceived = false;
readThread = new Thread(Read);
sendThread = new Thread(Send);
bytesReceived = new Byte[16384];
// Create a new SerialPort object with default settings.
_serialPort = new SerialPort("COM4", 38400, Parity.None, 8, StopBits.One);
// Set the read/write timeouts
_serialPort.WriteTimeout = 500;
_serialPort.Open();
string moveMode = "CV ";
_serialPort.WriteLine(moveMode);
s = null;
IPHostEntry hostEntry = Dns.GetHostEntry("localhost");
foreach (IPAddress address in hostEntry.AddressList)
{
IPEndPoint ipe = new IPEndPoint(address, 10001);
Socket tempSocket =
new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
tempSocket.Connect(ipe);
if (tempSocket.Connected)
{
s = tempSocket;
s.ReceiveBufferSize = 16384;
break;
}
else
{
continue;
}
}
readThread.Start();
sendThread.Start();
while (_continue)
{
Thread.Sleep(10);
;// Console.WriteLine("main...");
}
readThread.Join();
_serialPort.Close();
s.Close();
}
public static void Read()
{
while (_continue)
{
try
{
//Console.WriteLine("Read");
if (!dataReceived)
{
byte[] outValue = BitConverter.GetBytes(0);
// Check how many bytes have been received.
s.IOControl(FIONREAD, null, outValue);
uint bytesAvailable = BitConverter.ToUInt32(outValue, 0);
if (bytesAvailable > 0)
{
Console.WriteLine("Read thread..." + bytesAvailable);
byteCount = s.Receive(bytesReceived);
string str = Encoding.ASCII.GetString(bytesReceived);
//str = Encoding::UTF8->GetString( bytesReceived );
string[] split = str.Split(new Char[] { '\t', '\r', '\n' });
string filteredX = (split.GetValue(7)).ToString();
string filteredY = (split.GetValue(8)).ToString();
string[] AzSplit = filteredX.Split(new Char[] { '.' });
filteredX = (AzSplit.GetValue(0)).ToString();
string[] ElSplit = filteredY.Split(new Char[] { '.' });
filteredY = (ElSplit.GetValue(0)).ToString();
// scale values
int x = (int)(Convert.ToInt32(filteredX) * 1.9);
string scaledAz = x.ToString();
int y = (int)(Convert.ToInt32(filteredY) * 1.9);
string scaledEl = y.ToString();
String moveAz = "PS" + scaledAz + " ";
String moveEl = "TS" + scaledEl + " ";
sendString = moveAz + moveEl;
dataReceived = true;
}
}
}
catch (TimeoutException) {Console.WriteLine("timeout exception");}
catch (NullReferenceException) {Console.WriteLine("Read NULL reference exception");}
}
}
public static void Send()
{
while (_continue)
{
try
{
if (dataReceived)
{
// sleep Read() thread to allow serial port interrupt processing
readThread.Join(100);
// send command to PTU
dataReceived = false;
Console.WriteLine(sendString);
_serialPort.WriteLine(sendString);
}
}
catch (TimeoutException) { Console.WriteLine("Timeout exception"); }
catch (IOException) { Console.WriteLine("IOException exception"); }
catch (NullReferenceException) { Console.WriteLine("Send NULL reference exception"); }
}
}
}
}
UPDATE:
Thanks for the response Jon.
What I'm attempting to do is poll a socket for data, if its there process it and send it to the serial port, else keep polling the socket , repeating this whole process ad nauseum.
My initial attempt used a single thread and I was getting the same problem, which led me to believe that I need to give the serial port some more time to allow it to send the data before giving it more data on the next loop, because once I've sent data to the serial port I'm back polling the socket very hard. Having said that IOExceptions occur after approximately 30 seconds of operation, possibly with what I'm saying is I should see IOExceptions immediately?
My interpretation of the join function, I think, is incorrect, ideally calling readThread.Join from send() would allow read() to sleep while still pumping the COM port, but where I have it seems to put the send() to sleep, which I guess is the calling function?? and not producing the desired result.
I've encountered this problem recently as well (and a lot of others have too) - and it's basically a problem with Microsoft's serial port initialization code. I've written a very detailed explanation here if you wish to find out more. I've also suggested a workaround. Hopefully there's enough fuss about this issue such that Microsoft would take notice and fix it asap - perhaps a .NET 4.0 hotfix. This issue has been going on long enough starting .NET 2.0 (first time System.IO.Ports namespace was introduced).
It looks like what you're trying to do is send some data, then wait for a response, then repeat. You're using two threads for this and trying to sync them. I think you only need one thread. First send, then wait for a response, then repeat. This will eliminate your thread sync problems.