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!
Related
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.
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'm working on a C# project in visual studio 2015. For this project I have to read/write data to a hi-co Magnetic ID card. The model of writer I'm using is the IDTECH IDWA-336133B reader/writer.
The company gives you a set of commands to send to the unit through an emulated rs232 port (physical USB port). So far I have sent commands to turn the LEDs on and off on the unit with System.IO.Ports, but I have yet to figure out how I am supposed to receive data from the swipe, or write data on the swipe.
I'm attaching the frmMain.cs file I have, and the manual for the unit. You can see the commands on that manual that I'm using (Sending the hex code as bytes).
So what I was wondering: is there a way someone can show me the correct syntax / way to write a command to read the data from the card swipe back in?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
namespace SerialPortCommunication
{
public partial class Form1 : Form
{
static SerialPort _serialPort;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
_serialPort = new SerialPort();
byte[] command = new byte[] { 0x1B, 0x81 };
_serialPort.PortName = "COM4";
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
_serialPort.Open();
_serialPort.Write(command, 0, command.Length);
_serialPort.Close();
_serialPort.Dispose();
}
private void btnLedon_Click(object sender, EventArgs e)
{
_serialPort = new SerialPort();
byte[] command = new byte[] { 0x1B, 0x84};
_serialPort.PortName = "COM4";
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
_serialPort.Open();
_serialPort.Write(command, 0, command.Length);
_serialPort.Close();
_serialPort.Dispose();
}
private void btnRead_Click(object sender, EventArgs e)
{
_serialPort = new SerialPort();
byte[] command = new byte[] { 0x1B, 0x52 };
byte[] hico = new byte[] {0x1B, 0x78 };
_serialPort.PortName = "COM4";
_serialPort.ReadTimeout = 10000;
_serialPort.WriteTimeout = 500;
byte[] answer = new byte[] { };
_serialPort.Open();
// setting it to hico cards just incase
_serialPort.Write(hico, 0, hico.Length);
//sends command to read data
_serialPort.Write(command, 0, command.Length);
// I don't know if this is even remotely right
String response =_serialPort.ReadExisting();
lblReadData.Text = response;
_serialPort.Close();
_serialPort.Dispose();
}
}
}
I know this is sloppy code, but I'm just trying to get it working so I can migrate it to the real program and do it correctly.
Here is part of the manual that has all the hex codes and responses etc.:
Command & Response Introduction
The EzWriter supports the following commands. The responses are
provided.
Command: Reset Buffer Command code: <ESC> a Hex code: 1B
61 Response: none Description: This command reset the EzWriter
buffer to initial state. Encoding settings are not affected by this
command.
Command: Read Command code: <ESC> r Hex code: 1B 72
Response: [data block] <ESC> [status byte] Description: This
command requests the EzWriter to read a card swiped and respond with
the data read.
Command: Write Command code: <ESC> w [data block] Hex
code: 1B 77 [data block] Response: <ESC> [status byte]
Description: This command requests the EzWriter to write the data
block into the card swiped.
Command: Communication test Command code: <ESC> e Hex
code: 1B 65 Response: <ESC> y [1B] [79] Description:
This command is used to verify that the communication link between
computer and the EzWriter is up and good.
The serial port class fires the DataReceived event when data is sent to it. Keep in mind that this event fires on its own thread, separate from the main thread running the UI of your form. In order to receive data you need to implement this event. I did a quick example but have not tested it.
class Program
{
private static SerialPort _SerialPort;
private const int baudRate = 9600;
private const string PortName = "Com4";
static void Main(string[] args)
{
_SerialPort = new SerialPort(PortName, baudRate);
_SerialPort.DataReceived += _readSerialPort_DataReceived;
_SerialPort.Open();
var command = new byte[] { 0x1B, 0x81 };
Console.WriteLine("Sending {0} to device", command);
sendData(command);
Console.WriteLine("Press any key to continue...");
Console.WriteLine();
Console.ReadKey();
_SerialPort.Close();
}
static void sendData(byte[] command)
{
_SerialPort.Write(command,0,command.Length);
}
static void _readSerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var sp = (SerialPort) sender;
// Edited following line. See comment
var data = sp.ReadLine();
Console.WriteLine("Data Received: {0}", data);
//you may be able to do something like this as well but I am not sure if this is a blocking call
var messageLength = 10;
var buffer = new byte[messageLength];
sp.Read(buffer, 0, buffer.Length);
//if you are going to update the UI you need to invoke a delegate method on the main thread
}
}
There are a few options on how to read the data as well if you want to read it into a byte array or only take a snip-it of the data returned.
More info on Serial port class: Here
Info on updating UI elements from another thread: Here
MSDN example of Serial port DataReceived event: Here
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