I'm trying to realize a program that sends data to a TCP-server and then receives the same message by COM-port. I have the following code but it sends the data but doesn't receive any data.
When I monitor the serial port I can't see that the data is received.
How do I fix this? Do I have to switch to a multi threading system or is there a other way to sync this? Because I can see that the COM-port is opened but not read out.
And when I test this with Putty I can get it to work.
public class Variables
{
private static int v_VarI = 0;
public static int VarI
{
get { return v_VarI; }
set { v_VarI = value; }
}
private static int v_VarJ = 0;
public static int VarJ
{
get { return v_VarJ; }
set { v_VarJ = value; }
}
}
class Program
{
public class TcpTimeClient
{
private const int portNum = 6666;
private const string hostName = "192.168.1.51";
private const string data = "test";
public static int Main(String[] args)
{
new SerialPortProgram();
while (Variables.VarI < 10)
{
Byte[] bytesSent = Encoding.ASCII.GetBytes(data);
try
{
TcpClient client = new TcpClient(hostName, portNum);
NetworkStream ns = client.GetStream();
byte[] bytes = new byte[1024];
ns.Write(bytesSent, 0, bytesSent.Length);
int bytesRead = ns.Read(bytes, 0, bytes.Length);
client.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Variables.VarI++;
while (Variables.VarJ < Variables.VarI)
{
}
}
Console.ReadLine();
return 0;
}
}
public class SerialPortProgram
{
public SerialPort receiveport = new SerialPort("COM3", 115200, Parity.None, 8, StopBits.One);
public SerialPortProgram()
{
receiveport.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
receiveport.Open();
}
public void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// Show all the incoming data in the port's buffer
string rec_data = receiveport.ReadExisting();
Console.WriteLine(rec_data);
Variables.VarJ++;
}
}
}
Update
I've found that the program I wrote and putty and an other program named Serial Port Monitor differ in the IOCTL_SERIAL_SET_WAIT_MASK.
Serial Port Monitor: 0x00 00 01 19
Putty: Unkown
Own program: 0x00 00 01 FB
Does anyone know how to change this mask? Because it's not in the System.IO.Ports.SerialPort class.
you can use this :
public void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int length = receiveport.BytesToRead;
byte[] buf = new byte[length];
SerialPort2.Read(buf, 0, length);
}
buf array is your answer but in decimal mode . and you can changed it to want.
The wait mask is not your problem. Your wait mask enables the serial port for RXCHAR RXFLAG CTS DSR RLSD BRK ERR RING and has everything except ERR turned on.
This is correct for the way .Net wraps serial ports, and anyway it is not exposed in the .NET serial port class. Don't waste time pursuing that difference; your problem lies elsewhere.
Your serial port code ran perfectly on my system and printed all the data received from an external serial source, so I suspect your problem is with the TCP server whose code you did not post, or with your serial ports. Perhaps your configuration requires that you transmit something before the port begins sending? Try something like:
receiveport.Open();
receiveport.WriteLine("?");
Then if you still have problems, try connecting to another serial device to see if you can prove your receive code is working for you as it is for me. If you still can't figure it out, post more information about what's happening on the serial source end.
Related
I am working on a C# application. My application has to do serial communication with a hardware device. The device is connected with my system on "COM4" com port. Code:
serialPort = new SerialPort("COM4", 2400, Parity.Odd, 8, StopBits.One);
serialPort.WriteTimeout = 5000;
serialPort.ReadTimeout = 5000;
serialPort.Open();
serialPort.Handshake = Handshake.None;
serialPort.DtrEnable = true;
serialPort.RtsEnable = true;
After that i do a write operation, this works fine. Code:
private void WriteMessage(byte[] busMsg)
{
BinaryWriter writer = new BinaryWriter(serialPort.BaseStream);
writer.Write(busMsg);
writer.Flush();
}
After write, when i do ReadByte operation, i get the timeout exception. Code:
private byte ReadAEBusMessageResponse()
{
BinaryReader reader = new BinaryReader(serialPort.BaseStream);
return reader.ReadByte();
}
I read somewhere on google that BaseStream might cause issue, so i tried the below code for reading but, still no luck and i am still getting the timeout exception.
private byte ReadAEBusMessageResponse()
{
SerialPort currentPort = serialPort;
return Convert.ToByte(currentPort.ReadByte());
}
I do get the response when i try communication with Hercules, so i assume there is no issue with response from device. What am i doing wrong with serial communication ? any help would be much appreciated.
I have only found the async event to work. I have created my own byte receive buffer and then I handle the event:
static byte[] RXbuffer = new byte[512]; //"static" so it can be used all over
public void SerialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
Byte_Size = SerialPort.BytesToRead;
SerialPort.Read(RXbuffer, 0, Byte_Size);
/* Return to UI thread */
this.Invoke(new EventHandler(DisplayText));
}
the DisplayText is a method to print the buffer in a textbox.
private void DisplayText(object sender, EventArgs e)
{
int i = 0;
byte[] Received_Bytes = new byte[Byte_Size];
while (i < Byte_Size)
{
Received_Bytes[i] = RXbuffer[i];
i++;
}
TB_Info.AppendText("\r\nBytes Received: ");
TB_Info.AppendText(Byte_Size.ToString());
TB_Info.AppendText("\r\n--> ");
TB_Info.AppendText(BitConverter.ToString(Received_Bytes));
TB_Info.AppendText("\r\n");
//Array.Copy(RXbuffer,Full_RX_Buff,)
}
You can then read/manipulate the values later.
***Don't forget that in the SerialPort object that put on your form, you have to go into the properties/events dialog and assign the function that handles the receivedata event!
Have a trouble with smart card reader. Reader is connect to pc through Usb-to-Serial converter. Can't read anything from reader.
...
static void Main(string[] args)
{
byte[] data = new byte[256];
byte[] recived = new byte[256];
data[0] = 0x00;
data[1] = 0xA4;
data[2] = 0x04;
data[3] = 0x00;
data[4] = 0x00;
data[5] = 0x00;
data[6] = 0x00;
System.IO.Ports.SerialPort sp = new System.IO.Ports.SerialPort("COM4", 38400, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One);
sp.WriteTimeout = 300;
sp.ReadTimeout = 300;
sp.DataReceived += Sp_DataReceived;
sp.ErrorReceived += Sp_ErrorReceived;
if (sp.IsOpen)
{sp.Close();}
sp.Open();
try {
sp.Write(data, 0, 7);
int bt = sp.ReceivedBytesThreshold;
sp.Read(recived, 0, bt);
if (bt != 0)
{ Console.WriteLine(bt.ToString());
Console.ReadKey();}
} catch (Exception ex){
Console.WriteLine(ex.Message);
Console.ReadKey();}
}
private static void Sp_ErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
{Console.ReadKey();}
private static void Sp_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{Console.ReadKey();}
}
}
Code doesn't do anything as if there isn't card reader in the system.
Well, first of all you're attaching the event handlers after you send something to the reader. That's not good. I recommend initializing the SerialPort instance completely (set it up, attach events, etc) and only after that, open the connection and communicate.
Also your application doesn't wait for anything. If you use the asynchronous communication (by defining the DataReceived event) you need to make sure your application actually loops and waits.
Your console application doesn't do that. It writes something to the serial port and then quits as it steps out of the Main method. If you expect an answer you need to decide:
Use the synchronous way calling the methods to actually block/read from the serial port.
Use the asynchronous way as you started doing, but then make your application run without blocking any threads.
And please: Don't mix the two! I see a lot of code where people in DataReceived write a loop because they don't get all the information in one go. Don't do that. Instead build a buffer and check it for complete transmissions. No Read in DataReceived!
The following code might work. It will not implement the asynchronous variant, but the blocking, synchronous approach:
static void Main(string[] args)
{
byte[] data = new byte[256];
byte[] recived = new byte[256];
data[0] = 0x00;
data[1] = 0xA4;
data[2] = 0x04;
data[3] = 0x00;
data[4] = 0x00;
data[5] = 0x00;
data[6] = 0x00;
using (System.IO.Ports.SerialPort sp = new System.IO.Ports.SerialPort("COM4", 38400, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One))
{
try
{
sp.Open();
sp.Write(data, 0, 7);
int bytesRead = sp.Read(recived, 0, received.Length);
if (bytesRead != 0)
{
string s = Encoding.ASCII.GetString(received, 0, bytesRead);
Console.WriteLine(s);
Console.ReadKey();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadKey();
}
}
}
If that doesn't show any result on the console, then there might be several causes of error, including:
Wrong COM configuration (is BAUD rate, etc. correct?)
Wrong serial port (do you have more than one?)
Device doesn't communicate the way you think (are you sending the correct command?)
etc..
I am trying to create TCP IP Client in WPF GUI / C#.NET for a Ubunu Server.
Problem: I am able to connect to the server machine , the connection work correctly, send the message correctly and the ubuntu console show as well , Client Connected and sent this command like Start Video Feed on the server but When it comes to Read the Response nothing happens - It does not read the byte array that should be returned by the Ubuntu Server. Actually on message - 102 it should start the video feed on the server and return back the video feed byte array which should be read further and display the video. No code written yet to display the video feed as I am unable to read the feed from the server however, the client sends the commands(messages) to the server correctly as mentioned can view it on a console of the Ubuntu server machine. Please suggest thanks !!
Below is the code please have a look and suggest me what I am doing wrong :
namespace POC_TCP_Listener
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private int WhichEventFired = 0;
private void Button_Click_1(object sender, RoutedEventArgs e)
{
try
{
// string message = "{Site: 1}";
WhichEventFired = 1; //Start Video Feed
Thread ClientThread = new Thread(new ThreadStart(ConnectToServerAndRetrieveBytes));
ClientThread.Start();
}
catch (Exception ex)
{
string st = ex.Message;
}
}
private void ConnectToServerAndRetrieveBytes()
{
TcpClient TCP = new TcpClient();
TCP.Connect("IPAddress", 5001);
byte[] packet;
var size = 9;
var header = 102;
var siteId = 1;
var state = 1;
if (WhichEventFired == 1)
{
header = 102; // Start Video Feed
}
else if (WhichEventFired == 2)
{
header = 114; // Stop Video Feed
}
else
{
header = 115; // query Temperature
}
// <8> <115> <1>
packet = BitConverter.GetBytes(size).Reverse().Concat(BitConverter.GetBytes(header).Reverse()).Concat(BitConverter.GetBytes(siteId).Reverse()).Concat(BitConverter.GetBytes(state).Reverse()).ToArray();
// Translate the passed message into ASCII and store it as a Byte array.
Byte[] data = packet;
// Get a client stream for reading and writing.
NetworkStream stream = TCP.GetStream();
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
byte[] buffer = new byte[64 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
// In the below line - it stops and nothing happens after it - Please Suggest
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
// return ms.ToArray();
}
stream.Close();
TCP.Close();
}
}
}
strong text
Please suggest why it stops working or let me know if I am doing anything wrong.
I think the problem is that if there are no more packages left, it escapes the while-loop. If you want to check it endlessly you should try using a for. But i am not sure.
Yeah that should be it. If there are no Packages in the moment the while-loop is starting, it terminates itself because there is nothing to read. So you could check if the Ubuntu Server returns you something.
I have set up a C# server which at present serves up one test mp3 file over TCP. The code to send the file is as follows
public void RunStreamer()
{
log.MakeLog("Starting streamer");
Run = true;
//Need to look into how to thread this to not block the main window
TcpListener listen = new TcpListener(localAddr, _port);
listen.Start(); //startlistening to client requests
//blocks until a client request comes in
for (; ; )
{
Socket socket = listen.AcceptSocket();
if (socket.Connected)
{
SendFileToClient(socket);
socket.Disconnect(false);
}
}
}
void SendFileToClient(Socket socket)
{
log.MakeLog("Connection made");
NetworkStream netStream = new NetworkStream(socket);
StreamWriter writer = new StreamWriter(netStream);
//Todo - set specfified file - this file just for test
FileStream filestream = File.Open(#"C:\MusicTest\Test.mp3", FileMode.Open, FileAccess.Read, FileShare.Read);
filestream.CopyTo(netStream);
netStream.Flush();
netStream.Close();
}
In my test android set up I am making a call to the server on a button click:
public void btngo_click(View v)
{
final TcpClient client = new TcpClient();
new Thread(new Runnable(){
#Override
public void run() {
final MediaPlayer mediaPlayer = new MediaPlayer();
client.GetStream();
runOnUiThread(new Runnable(){
public void run()
{
int length = client.GetLength();
if(length > 0)
{
byte[] result = client.GetResult();
try {
// create temp file that will hold byte array
File tempMp3 = File.createTempFile("test", "mp3", getCacheDir());
tempMp3.deleteOnExit();
FileOutputStream fos = new FileOutputStream(tempMp3);
fos.write(result);
fos.close();
mediaPlayer.reset();
FileInputStream fis = new FileInputStream(tempMp3);
mediaPlayer.setDataSource(fis.getFD());
mediaPlayer.prepare();
mediaPlayer.start();
} catch (IOException ex) {
String s = ex.toString();
ex.printStackTrace();
}
}
}
});
}
}).start();
}
the stream is received in the TcpClient class which is as follows:
public class TcpClient {
public final static String SERVER_ADDRESS = "127.0.0.1";
public final static int SERVER_PORT = 65000;
public String TotalResult;
public int Length;
byte[] result = new byte[21000000];
public TcpClient()
{
}
public int GetLength()
{
return Length;
}
public byte[] GetResult()
{
return result;
}
public void GetStream()
{
try
{
final Socket socket = new Socket("192.0.0.5", 85000);
final InputStream input = new BufferedInputStream(socket.getInputStream());
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nread;
while((nread = input.read(result, 0, result.length)) != -1)
{
buffer.write(result, 0, nread);
}
buffer.flush();
//input.read(result);
Length = result.length;
input.close();
socket.close();
} catch (UnknownHostException e) {
String exc = e.getMessage();
e.printStackTrace();
} catch (IOException e) {
String exc2 = e.getMessage();
e.printStackTrace();
}
}
}
With apologies for all the code here is my problem.
I am receiving the stream. The temp MP3 file is created and the media player starts. I then only get a short snippet of the test MP3 file (which is a full song). It also jumps about a bit. The length is not the same and the section of the song played is different each time.
How do I receive the full file in a ordered way such that it will provide full play back of the song.
I have tried to route around for this and have an idea that I need to tell my client what file size it should suspect and then perform some loop until all data is received although I have no idea how to successfully implement this if that is the correct solution.
Any pointers on where I am going wrong or what I can do to rectify would be greatly appreciated!!
Having received no answers on this I dug around a bit more. Two things were wrong:
Firstly I had not included the size of the stream as a int sized header in my stream. I understand that for smaller files this will not be a problem but as file sizes grow it is necessary to make sure that the whole stream has been received.
This in turn raised another issue. The int I was sending as byte[] form c# was not returning the correct value in Java. Turns out Java uses sbytes -128 to 127 range as opposed to byte. This then involved a bit of code to convert to an int. then I could instruct the reader to readfully passing in the byte[] buffer with the actual size of the expected stream = voila it worked. MP3 files is received and plays just fine.
i need to read data from my virtual com port and detect the message "Dreq". Once i press the connect button, it connects to my COM8 port and begins reading in a new thread. I also have a disconnect button in which i wish to close the reading and disconnect from the COM8 port. However, i have problems closing the BeginRead.
public partial class Form1 : Form
{
SerialPort sp;
Stream stream;
IAsyncResult recv_result;
private void button1_Click(object sender, EventArgs e)
{
sp = new SerialPort("COM8", 9600);
sp.Open();
sp.ReadTimeout = 50000;
sp.NewLine = "\n\r\0";
stream = sp.BaseStream;
recv_result = stream.BeginRead(new byte[1], 0, 0, new
AsyncCallback(ReadCallBack), stream);
}
private void ReadCallBack(IAsyncResult ar)
{
Stream stream = (Stream)ar.AsyncState;
string temp;
while (stream.CanRead)
{
temp = sp.ReadLine();
// ... do something with temp
}
}
private void disconnectButton_Click(object sender, EventArgs e)
{
stream.EndRead(recv_result);
sp.Close();
}
}
You can try calling sp.DiscardOutBuffer(). It will call your read callback and you can then use stream.EndRead().
private void disconnectButton_Click(object sender, EventArgs e)
{
sp.DiscardOutBuffer();
stream.EndRead(recv_result);
sp.Close();
}
You can try this program.
using System;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
using System.IO;
using System.Text;
public class clsState {
private const int BUFFER_SIZE = 1024;
public byte[] BytesBuffer = new byte[BUFFER_SIZE];
public SerialPort sp;
public Stream stream;
}
public partial class Form1 : Form {
SerialPort sp;
Stream stream;
IAsyncResult recv_result;
bool endLoop = false;
Thread _readThread;
private ManualResetEvent _readDone = new ManualResetEvent(false);
private void button1_Click(object sender, EventArgs e) {
sp = new SerialPort("COM8", 9600);
sp.Open();
sp.ReadTimeout = 50000;
sp.NewLine = "\n\r\0";
stream = sp.BaseStream;
// save serial port and stream to state object
clsState state = new clsState();
state.sp = sp;
state.stream = stream;
// create worker thread
endLoop = false;
_readThread = new Thread(() => ReadThreadProc(state))
_readThread.IsBackground = true;
_readThread.Start();
}
private void ReadThreadProc(clsState state) {
while (endLoop == false){
// open and then close the gate as soon as after one thread passed
_readDone.Reset();
// starting ascynchronous read
recv_result = state.stream.BeginRead(state.BytesBuffer, 0, state.BytesBuffer.Length, new AsyncCallback(ReadCallBack), state.stream);
// worker thread block in here (waiting for... _readDone.Set())
_readDone.WaitOne();
}
}
private void ReadCallBack(IAsyncResult ar) {
string temp;
int bytesRead = 0;
// read serial port and stream from IAsyncResult
clsState state = (clsState) ar.AsyncState;
// if port serial is open and..
if (state.sp.IsOpen) {
// the stream can read then..
if(state.stream.CanRead) {
// wait for asynchronous read to completed
bytesRead = state.stream.EndRead(ar);
}
}
if(bytesRead > 0) {
// convert data in state.BytesBuffer from bytes array to string and save to temp variable
temp = Encoding.ASCII.GetString(state.BytesBuffer);
// open gate for next data
_readDone.Set();
}
}
private void disconnectButton_Click(object sender, EventArgs e) {
// ending loop and will kill worker thread...
endLoop = true;
// release begin read
_readDone.Set();
if (_readThread != null){
if (_readThread.IsAlive){ // if worker thread still live
_readThread.Join(); // wait thread off in here..
}
}
// close serial port
if (sp.IsOpen) sp.Close();
// close stream and dispose it
if (stream.CanRead || stream.CanWrite) {
stream.Close();
stream.Dispose();
}
}
}
It's an old post, but I think this solution can help people with the same problem.
I was using legacy code for an application and I found that the problem with BeginRead and EndRead is that there is no way to cancel the asynchronous operation. Therefore, when you close the port, your call to BeginRead stays there forever until another byte is received in the port, then your call to EndRead will free up the port. If it does not happen this way, then your application may hang and not even task manager can close it until you unplug the serial port cable!
Fortunately the TPL library can fix this problem in a very simple and elegant way. The CancelToken is what you need:
On port open:
while (x)
var myTask = _serialPort.BaseStream.ReadAsync(_serialBuffer, 0, _bufferLength, cancelToken.Token);
var bytesRead = await myTask;
... your business logic here...
if ((myTask.IsCanceled) || (myTask.IsFaulted)) break;
}
On port close:
cancelToken.Cancel(false);
Please note a while loop is better than recursive call because when port is broadcasting lots of information, a stack overflow exception is thrown after 15 minutes.
It's a very simple implementation. I hope it helps