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
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!
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.
I have created TCP Client application and wanted to read and write to TCP server through my code. For reading from TCP Server I have created thread but it is not continuously firing the code of reading When I send the text from TCP server twice at the second time it gets fired and I am getting the data at the second time. Below is my code of reading and writing the data Please help me to resolve this
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
namespace TCPClient
{
public partial class Form1 : Form
{
int i;
StreamWriter streamWriter;
StreamReader streamReader;
TcpClient client; // Creates a TCP Client
NetworkStream stream; //Creats a NetworkStream (used for sending and receiving data)
byte[] datalength = new byte[256]; // creates a new byte with length 4 ( used for receivng data's lenght)
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
try
{
client = new TcpClient("127.0.0.1", 747); //Trys to Connect
ClientReceive(); //Starts Receiving When Connected
// timer1.Enabled = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message); // Error handler :D
}
}
public void ClientReceive()
{
stream = client.GetStream(); //Gets The Stream of The Connection
new Thread(() => // Thread (like Timer)
{
//MessageBox.Show(stream.Read(datalength, 0, 256).ToString());
while ((i = stream.Read(datalength, 0, 256)) != 0)//Keeps Trying to Receive the Size of the Message or Data
{
// how to make a byte E.X byte[] examlpe = new byte[the size of the byte here] , i used BitConverter.ToInt32(datalength,0) cuz i received the length of the data in byte called datalength :D
// byte[] data = BitConverter.GetBytes(1000); // Creates a Byte for the data to be Received On
byte[] data = new byte[1000];
stream.Read(data, 0, data.Length); //Receives The Real Data not the Size
this.Invoke((MethodInvoker)delegate // To Write the Received data
{
txtLog.Text += System.Environment.NewLine + "Server : " + Encoding.Default.GetString(data); // Encoding.Default.GetString(data); Converts Bytes Received to String
});
}
}).Start(); // Start the Thread
}
public void ClientSend(string msg)
{
stream = client.GetStream(); //Gets The Stream of The Connection
byte[] data; // creates a new byte without mentioning the size of it cuz its a byte used for sending
data = Encoding.Default.GetBytes(msg); // put the msg in the byte ( it automaticly uses the size of the msg )
int length = data.Length; // Gets the length of the byte data
byte[] datalength = new byte[4]; // Creates a new byte with length of 4
datalength = BitConverter.GetBytes(length); //put the length in a byte to send it
stream.Write(datalength, 0, 4); // sends the data's length
stream.Write(data, 0, data.Length); //Sends the real data
}
private void btnSend_Click(object sender, EventArgs e)
{
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
if (client.Connected) // if the client is connected
{
ClientSend(textBox1.Text); // uses the Function ClientSend and the msg as txtSend.Text
}
}
}
}
I'm attempting to write an application that can read and write to a device that accepts ordinary serial communication through a serial com port. I'm using a bluetooth to serial device. The bluetooth to serial device is a bolutek BK-MD-BC04-B_DEMO. It's basically a bluetooth device with a serial port on it.
I am able to connect to the device using my Android phone, and I can send data to it. With my computer connected to the serial port on the bluetooth device using PuTTY on COM5 with USB to serial, I can see the data I'm sending using my Android phone. I cannot seem to be able to get the serial commands to work properly when I connect the bluetooth adapter to my serial device, however. I am also unable to read anything back from the bluetooth adapter.
I have verified that all of the serial settings seem to be correct. The baud rate, data bits, stop bits, and parity are all set correctly on the bluetooth device.
I tried to contact bolutek via email, but they are very slow to respond. Here are some things I found on the device I'm trying to use:
http://www.electrodragon.com/w/index.php?title=BC04
http://docs.teguna.ro/BC04-electrondragon-2013-01-17.pdf
http://diwo.bq.com/wp-content/uploads/2014/11/BLK-MD-BC04-B_AT-COMMANDS.pdf
Here is my code:
using System;
using System.Linq;
using System.IO;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Bluetooth;
//...
public class MainActivity : Activity
{
private BluetoothSocket socket;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
Button button = FindViewById<Button>(Resource.Id.MyButton);
EditText text = FindViewById<EditText>(Resource.Id.editText);
button.Click += delegate
{
BluetoothAdapter adapter = BluetoothAdapter.DefaultAdapter;
Action finish = new Action(async delegate
{
if (socket == null)
{
BluetoothDevice device = (from bd in adapter.BondedDevices where bd.Name == "BOLUTEK" select bd).FirstOrDefault();
if (device == null)
{
AndroidMethods.message("Error", "BOLUTEK device not found. Please make sure you are paired with the BOLUTEK device.",
"OK", this);
return;
}
socket = device.CreateRfcommSocketToServiceRecord(Java.Util.UUID.FromString("00001101-0000-1000-8000-00805f9b34fb"));
}
if (!socket.IsConnected)
await socket.ConnectAsync();
string outString = text.Text + "\r";
string wakeString = "\t\r";
byte[] output = charsToBytes(outString.ToCharArray());
byte[] wakeUp = charsToBytes(wakeString.ToCharArray());
await socket.OutputStream.WriteAsync(wakeUp, 0, wakeUp.Length);
await socket.OutputStream.WriteAsync(wakeUp, 0, wakeUp.Length);
await socket.OutputStream.WriteAsync(wakeUp, 0, wakeUp.Length);
await socket.OutputStream.WriteAsync(output, 0, output.Length);
byte[] output2 = stringToBytes(outString);
byte[] wakeUp2 = stringToBytes(wakeString);
await socket.OutputStream.WriteAsync(wakeUp2, 0, wakeUp.Length);
await socket.OutputStream.WriteAsync(wakeUp2, 0, wakeUp.Length);
await socket.OutputStream.WriteAsync(wakeUp2, 0, wakeUp.Length);
await socket.OutputStream.WriteAsync(output2, 0, output.Length);
});
if (socket != null)
finish();
else if (adapter == null)
{
AndroidMethods.message("Error", "No bluetooth adapter found.", "OK", this);
return;
}
else if (!adapter.IsEnabled)
{
DialogBuilder.createConfirmDialog(this, "Error", "Bluetooth adapter is not enabled. Would you like to enable it now?",
"No", "Yes", delegate
{
adapter.Enable();
finish();
});
}
else
finish();
};
}
public static byte[] stringToBytes(string value)
{
byte[] bytes = new byte[value.Length * sizeof(char)];
System.Buffer.BlockCopy(value.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
public static string bytesToString(byte[] bytes)
{
char[] chars = new char[bytes.Length / sizeof(char)];
System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
public static byte[] charsToBytes(char[] chars)
{
int length = chars.Length;
byte[] returnVal = new byte[length];
for (int x = 0; x < length; x++)
returnVal[x] = (byte)chars[x];
return returnVal;
}
}
You'll notice I'm using two different methods of converting the string to a byte array. One of them just creates a char array and converts it to a byte array while the other converts a string array to a byte array and each byte is separated by a 0. Either method SEEMS to work when I am watching the incoming bluetooth to serial communication on my computer.
To communicate with the serial device, I would normally use PuTTY and hit tab then enter on my keyboard. This puts the serial device in command mode. You can do this multiple times. Thus the "\t\r". After you send a "\t\r", you should be able to enter a command followed by a "\r". So in PuTTY, I would enter on my keyboard something like "(tab)(enter)commandstring(enter)". The command I'm sending should change some settings on the serial device, yet when I connect to it through PuTTY, the settings are unchanged.
Is there anything I may be overlooking that could be causing this issue? I have spent a lot of time trying to figure this out and have yet to come up with a solution.
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