I need to read continuously the bytestream from my Arduino board.
For this, I've created a method that is reading the Serialport in a loop and expose the ByteStream to the other classes:
public async void ReadSerialPort
{
dataReader = new DataReader(SerialPort.InputStream)
while (true) {
uint ReadBufferLength = 16;
Task < UInt32 > loadAsyncTask;
loadAsyncTask = dataReader.LoadAsync(ReadBufferLength).AsTask();
UInt32 rxbytes = await loadAsyncTask;
RxBytes = new byte[rxbytes];
if (rxbytes > 0) {
datareader.ReadBytes(ByteStream);
}
}
}
But I think this is not the most efficient method for reading the serialport continuously as this method needs a couple of milliseconds to get the bytestream.
Is there an alternative for reading the bytestream?
Use event to read data from SerialPort:
static void Main(string[] args)
{
SerialPort sp= new SerialPort();
sp.DataReceived += Sp_DataReceived;
}
private static void Sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
throw new NotImplementedException();
}
Related
public class AsynchronousClient
{
private const int port = 7777;
public static ManualResetEvent allDone = new ManualResetEvent(false);
public class AppServer
{
Socket serverSocket = null;
void accept()
{
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.Completed += new EventHandler<SocketAsyncEventArgs>(e_Completed);
bool raiseEvent = serverSocket.AcceptAsync(e);
while (true)
{
if (!raiseEvent)
AcceptCallback(e);
}
}
public void Start()
{
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(new IPEndPoint(IPAddress.Parse("0.0.0.0"), 7777));
serverSocket.Listen(100);
serverSocket.Blocking = false;
accept();
}
void e_Completed(object sender, SocketAsyncEventArgs e)
{
AcceptCallback(e);
}
Socket clientSocket;
private void AcceptCallback(SocketAsyncEventArgs e)
{
SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs();
byte[] buffer = new byte[1024];
readEventArgs.SetBuffer(buffer, 0, buffer.Length);
readEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(readEventArgs_Completed);
clientSocket = e.AcceptSocket;
while (true)
{
allDone.Reset();
bool raiseEvent = clientSocket.ReceiveAsync(readEventArgs); // <-- Error goes here
if (!raiseEvent)
ReceiveCallback(readEventArgs);
allDone.WaitOne();
}
}
void readEventArgs_Completed(object sender, SocketAsyncEventArgs e)
{
ReceiveCallback(e);
}
private void ReceiveCallback(SocketAsyncEventArgs e)
{
allDone.Set();
if (e.BytesTransferred > 0)
clientSocket.Send(e.Buffer);
else
{
accept(); }
}
private void SendCallback(SocketAsyncEventArgs e)
{
}
}
public static int Main(String[] args)
{
AppServer a = new AppServer();
a.Start();
return 0;
}
}
Hello. The idea of this code is to run the program, connect with netcat, and whatever i send from netcat, it needs to be echoed back to it. It works fine, until i close netcat, reopen it, connect to the server and when i send a message, it crashes on ReceievAsync. It says:"An asynchronous socket operation is already in progress using this SocketAsyncEventArgs instance.". I can't figure out why. Does anyone understand why?
You shouldn't use a loop in the AcceptCallback, instead you should call the serverSocket.AcceptAsync(e); at the end of the method.
At the end of ReceiveCallback you should call the clientSocket.ReceiveAsync(readEventArgs) again to continue receiving. (not loop needed)
while (true)
{
if (!raiseEvent)
AcceptCallback(e);
}
// ^^^^^^^^^^^^^^^^^^^^^
// Doesn't look right....
I never used the ReceiveAsync. The BeginReceive/EndReceive are much easier.
I've been trying to get a live updating chart to work with WPF using livecharts, my goal is to have a chart update as it reads a serial input from an Arduino that just gives some numbers.
Using this example: https://lvcharts.net/App/examples/v1/wpf/Constant%20Changes
Although the example includes a built in randomizer of numbers, I want to switch that out for the Arduino serial input.
I read the serial input like this:
private void Button_Serial_Click(object sender, EventArgs e)
{
Thread thread = new Thread(SerialThread);
thread.Start();
}
static SerialPort _serialPort;
private void SerialThread() //serial thread starts here
{
_serialPort = new SerialPort();
_serialPort.PortName = "COM3";//Set your board COM
_serialPort.BaudRate = 9600;
try
{
_serialPort.Open();
}
catch (Exception e)
{
Console.WriteLine("could not connect to serial");
}
while (true)
{
string serialMSG = _serialPort.ReadExisting();
Console.WriteLine(serialMSG);
Thread.Sleep(200);
}
}
My problem is that I don't know what code to switch out for it to read the serial instead of the built in randomizer the example uses. The example has no usable comments or explanation of how it works and my inexperience with coding makes me unable to understand it fully.
I've looked at similar issues, but most just say to read through livechart examples. Well I did, but I do not understand it enough still.
Any assistance is appreciated.
Instead of while(true), you should let c# you decided when data
class Program
{
private static SerialPort port = new SerialPort("COM3",
9600, Parity.None, 8, StopBits.One);
private static ChartValues<MeasureModel> _chartValues;
static void Main(string[] args)
{
SerialPortWorker();
Console.Read();
}
private static void SerialPortWorker()
{
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived); //called when the data waiting in the buffer
port.Open(); //// Begin communications
Console.ReadLine(); // keep console thread alive
}
private static void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if(port.BytesToWrite > 0)
{
var data = port.ReadExisting(); //read incoming data
_chartValues.Add(new MeasureModel
{
DateTime = DateTime.Now,
Value = data
});
SetAxisLimits(now);
//lets only use the last 150 values
if (ChartValues.Count > 150) ChartValues.RemoveAt(0);
}
}
}
class MeasureModel
{
public DateTime DateTime { get; set; }
public String Value { get; set; }
}
I need to wait for the user to input data to the serialport reader and then process the data. However, using this code blocks the UI which is not what I want. Any ideas on how to make sure that data is received or a timeout has occured before continuing?
The reason I use
do
{
Thread.Sleep(1);
} while (...)
is because without it the code return indata before the user has time to change it.
I call ReadFromSerial from the main function and process the data there. If anything goes wrong I want it to return an empty string.
public string ReadFromSerial()
{
try
{
System.IO.Ports.SerialPort Serial1 = new System.IO.Ports.SerialPort("COM1", 9600, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One);
var MessageBufferRequest = new byte[13] { ... };
int BufferLength = 13;
if (!Serial1.IsOpen)
{
Serial1.Open();
}
Serial1.Write(MessageBufferRequest, 0, BufferLength); //Activates the serialport reader
indata = "";
Stopwatch timer = new Stopwatch();
timer.Start();
Serial1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
do
{
Thread.Sleep(1);
} while (string.IsNullOrEmpty(indata) && timer.Elapsed.TotalSeconds < 10);
timer.Stop();
if (Serial1.IsOpen)
{
Serial1.Close();
}
return indata;
}
catch (Exception ex)
{
return "";
}
}
private static string indata;
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
try
{
SerialPort sp = (SerialPort)sender;
if (sp.BytesToRead > 0)
{
indata = sp.ReadExisting();
}
}
catch(InvalidOperationException)
{
;
}
}
This is where multi-threading, tasks, async programming and/or event handlers comes in handy. All of them offer something to help you get around stuff like this, depending on the types of objects you're using.
A good starting point in this case would be to run the whole receive loop as a separate thread, then send the received data back to the main thread in some fashion.
Here's the source of a form that does basically what yours does, but either as a Thread or a Task:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// Button: starts Task version
private void button1_Click(object sender, EventArgs e)
{
StartReceiveTask();
}
// Button: starts Thread version
private void button2_Click(object sender, EventArgs e)
{
StartReceiveThread();
}
// Start the Receive loop as a Task
public void StartReceiveTask()
{
System.Threading.Tasks.Task.Run(() => receiveThreadFunc());
}
// Start the Receive loop as a Thread
public void StartReceiveThread()
{
var thd = new System.Threading.Thread(receiveThreadFunc);
thd.Start();
}
// Called when the Receive loop finishes
public void DataReceived(string data)
{
// do something with the data here
}
// The Receive loop, used by both Thread and Task forms.
public void receiveThreadFunc()
{
using (var serial1 = new System.IO.Ports.SerialPort("COM1", 9600, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One))
{
// open serial port
if (!serial1.IsOpen)
serial1.Open();
// send init command
var initCommand = new byte[13];
serial1.Write(initCommand, 0, initCommand.Length);
// get start time
DateTime start = DateTime.Now;
// buffer for pushing received string data into
StringBuilder indata = new StringBuilder();
// loop until at most 10 seconds have passed
while ((DateTime.Now - start).TotalSeconds < 2)
{
if (serial1.BytesToRead > 0)
{
// allocate a buffer, up to 1K in length, to receive into
int blen = Math.Min(1024, serial1.BytesToRead);
byte[] buffer = new byte[blen];
// read chunks of data until none left
while (serial1.BytesToRead > 0)
{
int rc = serial1.Read(buffer, 0, blen);
// convert data from ASCII format to string and append to input buffer
indata.Append(Encoding.ASCII.GetString(buffer, 0, rc));
}
}
else
System.Threading.Thread.Sleep(25);
// check for EOL
if (indata.Length > 0 && indata.ToString().EndsWith("\r\n"))
break;
}
if (indata.Length > 0)
{
// post data to main thread, via Invoke if necessary:
string data = indata.ToString();
if (this.InvokeRequired)
this.Invoke(new Action(() => { DataReceived(data); }));
else
this.DataReceived(data);
}
}
}
}
I went with solution not to touch what I had already written. Instead I added these methods in my main function.
private void StartReceiveThread()
{
var thd = new System.Threading.Thread(receiveThreadFunc);
thd.Start();
}
private void receiveThreadFunc()
{
string str = Read.ReadFromSerial();
DataReceived(str);
}
private void DataReceived(string data)
{
//Process the data received
}
I have an application which connects with an external protocol
using serial communication.
I need know if the wakeup bit is set on each packet it sends to me (the 9 bit), and as communication rates must be below 40ms, and response must be sent under 20 ms.
The framework, encapsulates the bits read from the port, and only send back the 8 bits of data to me. Also, I cannot wait for the parity error event, because of timing issues.
I need to know how can I read the 9 bit, or if there is a free alternative to http://www.wcscnet.com/CdrvLBro.htm
Did you try to put your serial read function right in the parity error event handler? Depending on the driver, this might be fast enough.
This wouldn't happen to be for a certain slot machine protocol, would it? I did this for fun for you. Maybe it will work?
{
public Form1()
{
InitializeComponent();
}
SerialPort sp;
private void Form1_Load(object sender, EventArgs e)
{
sp = new SerialPort("COM1", 19200, Parity.Space, 8, StopBits.One);
sp.ParityReplace = 0;
sp.ErrorReceived += new SerialErrorReceivedEventHandler(sp_SerialErrorReceivedEventHandler);
sp.ReadTimeout = 5;
sp.ReadBufferSize = 256;
sp.Open();
}
object msgsLock = new object();
Queue<byte[]> msgs = new Queue<byte[]>();
public void sp_SerialErrorReceivedEventHandler(Object sender, SerialErrorReceivedEventArgs e)
{
if (e.EventType == SerialError.RXParity)
{
byte[] buffer = new byte[256];
try
{
int cnt = sp.Read(buffer, 0, 256);
byte[] msg = new byte[cnt];
Array.Copy(buffer, msg, cnt);
if (cnt > 0)
{
lock (msgsLock)
{
msgs.Enqueue(msg);
}
}
}
catch
{
}
}
}
private void timer1_Tick(object sender, EventArgs e)
{
if (msgs.Count > 0)
{
lock (msgsLock)
{
listBox1.Items.Insert(0, BitConverter.ToString(msgs.Dequeue()));
}
}
}
}
}
Anyways, for more control over the serial port I suggest using the win32 calls to get what you want.
http://msdn.microsoft.com/en-us/magazine/cc301786.aspx
i have a problem
i am writing a code in C#
i wanna receive a byte from serial port
but when i wanna receive data from port that sounds my program is hang
and doesnt work any more
SerialPort port = new SerialPort("COM3");
port.Open();
byte[] b = new byte[10];
port.Read(b, 0, 1);
port.Close();
please help me
This is because SerialPort reads data synchronously and blocks current thread until the data would be available.
You can use separate thread for this:
public class SerialPort : IDisposable
{
public SerialPort(byte comNum, int baudRate)
{
this.comNum = comNum;
serialPort = new System.IO.Ports.SerialPort("COM" + comNum.ToString(), baudRate);
serialPort.Open();
thread = new System.Threading.Thread(ThreadFn);
thread.Start();
}
public void Dispose()
{
if (thread != null)
thread.Abort();
if (serialPort != null)
serialPort.Dispose();
}
private void OnReceiveByte(byte b)
{
//handle received byte
}
private void ThreadFn(object obj)
{
Byte[] inputBuffer = new Byte[inputBufferSize];
while (true)
{
try
{
int availibleBytes = serialPort.BytesToRead;
if (availibleBytes > 0)
{
int bytesToRead = availibleBytes < inputBufferSize ? availibleBytes : inputBufferSize;
int readedBytes = serialPort.Read(inputBuffer, 0, bytesToRead);
for (int i = 0; i < readedBytes; i++)
OnReceiveByte(inputBuffer[i]);
}
System.Threading.Thread.Sleep(1);
}
catch (System.Threading.ThreadAbortException)
{
break;
}
catch (Exception e)
{
System.Diagnostics.Debug.Assert(false, e.Message);
}
}
}
private Byte comNum;
private System.IO.Ports.SerialPort serialPort;
private System.Threading.Thread thread;
private const int inputBufferSize = 1024;
}
Is there actually any data being sent over the serial port? The call to Read might just be waiting to receive some data before returning. Make sure that you have set a value for the ReadTimeout property. This will make the call to Read throw a TimeoutException if no data was read from the port.
Reference:
http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.readtimeout.aspx
Also make sure you set the serial speed right (if you're reading too fast you'll miss some data, etc)