I am trying to create a RS232 application that reads incoming data and stores it in a buffer. I found the following code in an RS232 example but I am not sure how to use it
*RS232 Example port_DataReceived*
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (!comport.IsOpen) return;
if (CurrentDataMode == DataMode.Text)
{
string data = comport.ReadExisting();
LogIncoming(LogMsgType.Incoming, data + "\n");
}
else
{
int bytes = comport.BytesToRead;
byte[] buffer = new byte[bytes];
comport.Read(buffer, 0, bytes);
LogIncoming(LogMsgType.Incoming, ByteArrayToHexString(buffer) + "\n");
}
}
I am trying to write another method that takes an incoming byte array and combines it with another array ... see below:
private void ReadStoreArray()
{
//Read response and store in buffer
int bytes = comport.BytesToRead;
byte[] respBuffer = new byte[bytes];
comport.Read(respBuffer, 0, bytes);
//I want to take what is in the buffer and combine it with another array
byte AddOn = {0x01, 0x02}
byte Combo = {AddOn[1], AddOn[2], respBuffer[0], ...};
}
I currently have both methods in my code as I am confused how to read and store the incoming bytes to the port. Can I use the "port_DataReceived" method in my "ReadStoreArray" method? Do I need to modify my "ReadStoreArray" method? Or should I just start over?
When you create your SerialPort:
SerialPort comport = new SerialPort("COM1");
comport.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// Shortened and error checking removed for brevity...
if (!comport.IsOpen) return;
int bytes = comport.BytesToRead;
byte[] buffer = new byte[bytes];
comport.Read(buffer, 0, bytes);
HandleSerialData(buffer);
}
//private void ReadStoreArray(byte[] respBuffer)
private void HandleSerialData(byte[] respBuffer)
{
//I want to take what is in the buffer and combine it with another array
byte [] AddOn = {0x01, 0x02}
byte [] Combo = {AddOn[1], AddOn[2], respBuffer[0], ...};
}
Don't bother with using the DataRecieve handler, it's horribly inaccurate, you're better off to start a thread which constantly reads the serial port and grabs every byte which comes across it.
You can't read the same data from the port twice. You'll need to read it once into a buffer, then either share the buffer (pass as a function parameter) or clone it to give each function its own copy.
Related
I am new to c# and I try to read the serial port, but it results in some strange characters. I do not know what encoding shall I use.
I tried to use GetEncoding("utf-8") which results in some strange characters and using BitConverter.ToString I can see the hex output.
Can some one point me out in the right direction, where I am doing the mistake?
Using GetEncoding("utf-8")
private void port_DataRecieved(object sender, SerialDataReceivedEventArgs e)
{
SerialPort port = (SerialPort)sender;
byte[] data = new byte[port.BytesToRead];
port.Read(data, 0, data.Length);
TextBox.Text += "'Rx:'"+Encoding.GetEncoding("utf-8").GetString(data)+"\n";
}
Output is as follows:
Using BitConverter.ToString
private void port_DataRecieved(object sender, SerialDataReceivedEventArgs e)
{
SerialPort port = (SerialPort)sender;
int bytes = port.BytesToRead;
byte[] buffer = new byte[bytes];
port.Read(buffer, 0, bytes);
if (BitConverter.ToString(buffer).Replace("-", " ").Length > 1)
{
TextBox.Text += "'Rx:'"+BitConverter.ToString(buffer).Replace("-", " ")+"'\n";
}
}
Output is as follows:
I'm currently working on a project that involves me taking a picture with my laptop camera on a given command. I'm using my webcam as a security camera right now due to the fact that I have not gotten the time to buy a real one yet so my laptop will have to do.
The project is structured like this:
I have my Server (this runs on my laptop) and I have my Client (which runs on my PC which will later be on my phone - but thats not relevant). I send a command to the server using my client (in this case it's "Webcam") and the server receives it, takes a picture using the webcam, gets the bytes and then sends the bytes over a network stream to the client.
However when I download the stream with my client, it downloads 0 bytes. To clarify, it does save the image in my folder but I can't open it because it's 0 bytes.
Server
while (true)
{
if (nwStream.DataAvailable)
{
//Create a byte array (a buffer). This will hold the byte size that we recieve from the client in memory.
byte[] buffer = new byte[client.ReceiveBufferSize];
//Now we need to read the bytes and store the bytes we read in a int, we do this by using our nwStream.Read function and pass it the correct parameters.
//1. [Buffer] - an array of type byte, and we declared that above [buffer] <- This is what we are reading from.
//2. [Offset] - Now we need to set the offset, where we want to start reading in the buffer. so since its an array we start at 0.
//3. [Size] - The number of bytes we want to read from the NetworkStream.
int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize);
//Now we need to decode the message we recieved by using the Encoding.ASCII.GetString to get the string and passing the correct parameters.
//1. [Bytes] - What we want to decode, this is where we give it a byte array
//2. [Index] - We need to give it the first index of the array that we want to decode so it knows where to start, we do this bya dding 0 since its an array.
//3. [Count] - The number of bytes we want to decode and we created an int to hold that number above so let's pass it as a parameter.
string dataRecieved = Encoding.Default.GetString(buffer, 0, bytesRead);
if (dataRecieved == "webcam")
{
Console.WriteLine("Starting the webcam feature..");
CameraFeature();
}
}
}
}
private static void CameraFeature()
{
VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo Device in VideoCaptureDevices)
{
Devices.Add(Device.Name);
Console.WriteLine("Device: " + Device.Name);
}
FinalVideo = new VideoCaptureDevice(VideoCaptureDevices[0].MonikerString);
FinalVideo.NewFrame += new NewFrameEventHandler(FinalVideo_NewFrame);
FinalVideo.Start();
}
private static void exitcamera()
{
FinalVideo.SignalToStop();
// FinalVideo.WaitForStop(); << marking out that one solved it
FinalVideo.NewFrame -= new NewFrameEventHandler(FinalVideo_NewFrame); // as sugested
FinalVideo = null;
}
static void FinalVideo_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Bitmap video = (Bitmap)eventArgs.Frame.Clone();
//video.Save($"image{imgCount}.png");
Console.WriteLine("Picture taken!");
Connection(video);
exitcamera();
imgCount++;
}
public static void Connection(Bitmap tImage)
{
Console.WriteLine("Starting the transfer..");
byte[] bStream = ImageToByte(tImage);
try
{
nwStream.Write(bStream, 0, bStream.Length);
Console.WriteLine("Done..");
}
catch (SocketException e1)
{
Console.WriteLine("SocketException: " + e1);
}
}
static byte[] ImageToByte(Bitmap iImage)
{
MemoryStream mMemoryStream = new MemoryStream();
iImage.Save(mMemoryStream, System.Drawing.Imaging.ImageFormat.Png);
return mMemoryStream.ToArray();
}
}
Client
private static void SendCommand()
{
while (true)
{
Console.WriteLine("Please enter a command: ");
string userInput = Console.ReadLine();
//Convert out string message to a byteArray because we will send it as a buffer later.
byte[] bytesToSend = Encoding.Default.GetBytes(userInput);
//Write out to the console what we are sending.
Console.WriteLine("Sending: " + userInput);
//Use the networkstream to send the byteArray we just declared above, start at the offset of zero, and the size of the packet we are sending is the size of the messages length.
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
//RecieveBuffer();
//Recieve the bytes that are coming from the other end (server) through the client and store them in an array.
byte[] bytesToRead = new byte[client.ReceiveBufferSize];
//byte[] bitmap = GetYourImage();
//read the bytes, starting from the offset 0, and the size is what ever the client has recieved.
int bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize);
//Decode the bytes we just recieved using the Encoding.ASCII.GetString function and give it the correct parameters
//1. What it should decode
//2. Starting to decode from what offset
//3. How much do we want to decode?
Bitmap bmp;
using (var ms = new MemoryStream(bytesToRead))
{
bmp = new Bitmap(ms);
bmp.Save("Image.png");
}
//Console.WriteLine("Recieved: " + Encoding.ASCII.GetString(bytesToRead, 0, bytesRead));
}
Try MemoryStream.Seek(0, SeekOrigin.Begin) before sending stream to client. You may download 0 bytes, because stream at its end when you receive it.
I am having a problem receiving data (a string of text) from an Arduino via a C# Winform app. The sketch on the Arduino basically reply with whatever I send. I am able to send data. What is strange is that if I telnet the device and type any text it responds correctly so it appears the problem is my C# code, however, I can't seem to figure out where I am incorrect.
Here is what I have
public partial class Form1 : Form
{
System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient();
NetworkStream serverStream = default(NetworkStream);
string readData = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
byte[] outStream = System.Text.Encoding.ASCII.GetBytes(textBox2.Text);
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
}
private void button2_Click(object sender, EventArgs e)
{
clientSocket.Connect("192.168.1.177", 5223);
readData = "Conected Arduino ...";
msg();
serverStream = clientSocket.GetStream();
byte[] outStream = System.Text.Encoding.ASCII.GetBytes(textBox2.Text);
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
Thread ctThread = new Thread(getData);
ctThread.Start();
}
private void getData()
{
while (true)
{
while (true)
{
serverStream = clientSocket.GetStream();
int buffSize = clientSocket.ReceiveBufferSize;
byte[] inStream = new byte[10025];
serverStream.Read(inStream, 0, buffSize);
string returndata = System.Text.Encoding.ASCII.GetString(inStream);
readData = "" + returndata;
msg();
}
}
}
private void msg()
{
this.BeginInvoke(new Action(() =>
{
textBox1.Text = String.Format("{0}{1} >> {2}", textBox1.Text, Environment.NewLine, readData);
}
));
}
}
Here is part of the Arduino sketch
void loop() {
// wait for a new client:
EthernetClient client = server.available();
// when the client sends the first byte, say hello:
if (client) {
if (!alreadyConnected) {
// clead out the input buffer:
client.flush();
Serial.println("We have a new client");
client.println("Hello, client!");
alreadyConnected = true;
}
if (client.available() > 0) {
// read the bytes incoming from the client:
char thisChar = client.read();
// echo the bytes back to the client:
//server.write(thisChar);
// echo the bytes to the server as well:
//Serial.write(thisChar);
if (inputPos < maxLength-1)
{
if (thisChar == '\n')
{
inputString[inputPos] = 0;
server.write(inputString);
Serial.write(inputString);
inputPos = 0;
} else {
// add it to the inputString:
inputString[inputPos] = thisChar;
inputPos++;
}
} else {
inputPos = 0;
}
}
}
}
Your code has a number of things wrong with it, including what has to be the most common novice error I've seen in any context: you fail to take into account the number of bytes actually read. Plus you have another common variation on the theme, which is that you process the entire receive buffer array as if the whole thing had valid data in it.
Without a way to test, it's hard to know for sure. But at the very least, you should change your receive method to look like this:
private void getData()
{
serverStream = clientSocket.GetStream();
while (true)
{
byte[] inStream = new byte[10025];
int bytesRead = serverStream.Read(inStream, 0, inStream.Length);
readData = System.Text.Encoding.ASCII.GetString(inStream, 0, bytesRead);
msg();
}
}
DON'T pointlessly nest a while (true) loop inside another while (true) loop
DON'T create a new NetworkStream every time you want to read
DON'T concern yourself with the Socket.ReceiveBufferSize property value
DO capture and use the return value from the read operation
DON'T concatenate the empty string with other strings (even in an iterated scenario, one should be using StringBuilder instead, and here you're not even iterating the concatenation!)
Of course, not all of those flaws are fatal. The biggest issues are the new NetworkStream on each read and the mismanagement of the receive buffer and result value. But really, you should strive for all of the code to be good.
Note that the above merely improves the code. Even the above still has a variation on "the most common novice error I've seen in any context": while it does use the return value from the read operation, it does not do everything with it that it should. In particular:
You are not actually guaranteed that you will receive all of the bytes that were sent to you in one read operation. This means your application protocol really should have some way for you to identify within the stream of bytes you're reading where one message ends and the next one starts.
When the connection is gracefully closed, the read operation will return 0 as the byte count, at which point your own code is supposed to respond by finishing up whatever writes to the socket you need to (if any) and then gracefully closing your own socket by calling Socket.Shutdown(SocketShutdown.Both) and finally Socket.Close().
But the above should at least help you make forward progress in your project.
One other thing you really should change IMHO which I didn't bother in the above, is that you should not use an instance field (i.e. readData) to pass data when simply passing it as a method parameter would suffice. You should avoid side-effects in your code as much as possible. It will make the code much easier to comprehend and thus to write correctly, among other things.
I am communicating with a machine by serial port connected through RS232 cable. After passing the credentials I am able to get the data from the machine as client if the buffer storage of the machine is empty (clean). As soon as I close my application, the data comes into the buffer storage of the machine as machine is in continuous running mode. After this if I try to get the data with the same way by starting my application and passing credentials I do not get buffer as well as live data from the machine.
Now again when I try to log in by passing credentials into hyperterminal.exe and after I am able to get the buffer as well as live data..
So my question is why am I not getting the buffer data from program when data is there in the buffer as we are getting from Hyperterminal.exe
I have struggled a lot searching for the solution for this but no luck ..
I request to please guide me on this.. any suggestion will be like a life savior for me..
Here is the code that I am using..
port1.RtsEnable = true;
port1.DtrEnable = true;
port1.PortName = "COM1";
port1.BaudRate = 9600;
port1.DataBits = 8;
port1.Parity = System.IO.Ports.Parity.None;
port1.StopBits = System.IO.Ports.StopBits.One;
port1.Handshake = Handshake.RequestToSend;
port1.Handshake = Handshake.RequestToSendXOnXOff;
port1.Handshake = Handshake.None;
port1.Handshake = Handshake.XOnXOff;
port1.Open();
port1.Write("Username\r\n");
port1.Write("Password\r\n");
port1.Write("Command\r\n");
port1.DataReceived += new SerialDataReceivedEventHandler(port1_DataReceived);
}
public void port1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(500);
while (port1.IsOpen)
{
//string s = port1.ReadExisting();
string s = port1.ReadLine();
}
}
I have used ReadLine() as well as ReadExisting() but with no luck..
I/O Code..
public void getData() {
byte[] buffersize = new byte[port1.ReadBufferSize];
int bytesRead = port1.Read(buffersize, 0, buffersize.Length);
byte[] buffer = new byte[bytesRead];
File.AppendAllText(text, "Inside 1\r\n");
Action kickoffRead = delegate
{
port1.BaseStream.BeginRead(buffer, 0, buffer.Length, delegate(IAsyncResult ar)
{
try
{
File.AppendAllText(text, "Inside 2\r\n");
int actualLength = port1.BaseStream.EndRead(ar);
byte[] received = new byte[actualLength];
Buffer.BlockCopy(buffer, 0, received, 0, actualLength);
string mybuffer = "";
//ASCII data.
mybuffer += Encoding.ASCII.GetString(received, 0, bytesRead);
}
I have invoked this method just after the login credentials...Still have no luck in receiving the data ...
public void port1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//Initialize a buffer to hold the received data
byte[] buffer = new byte[port1.ReadBufferSize];
//get the number of bytes read
int bytesRead = port1.Read(buffer, 0, buffer.Length);
//ASCII data.
mybuffer += Encoding.ASCII.GetString(buffer, 0, bytesRead);
if(mybuffer.IndexOf('\r') > -1)
{
//Found a carriage return, do something with buffer?
}
}
you are going to get bits and pieces, so you might want to buffer it all up and look for a return character (or whatever terminator you are getting from the other side) to extract the packet.
I need to save whole incoming serial port data into a file. Some people suggest to use File.WriteAllBytes but it takes the all empty indexes of created byte array.
Array.Resize(ref Read_Data2, Read_Data2.Length + incoming.Length);
public void SaveData(byte[] incoming)
{
for (int i = 0; i < incoming.Length; i++)
{
Read_Data2[x] = incoming[i];
++x;
}
File.WriteAllBytes("C:\\Test3.text", Read_Data2);
}
I use that method to save all incoming bytes into Read_Data2 but i think something is wrong. It saves the empty indexes of byte array as i said before. How can i improve this or is there any better way to save the incoming serial port data into file?
private void mySerialPort_DataReceived(System.Object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
SerialPort spL = (SerialPort)sender;
byte[] bytesToRec = new byte[spL.byteToRead];
Int64 bytes = spL.Read(bytesToRec, 0, bytesToRec.Length);
navSerialPort.DiscardInBuffer();
navSerialPort.DiscardOutBuffer();
string filepath = #"" + textBox1.Text + "\\" + "KMTU_" +DateTime.Now.ToString("MMM-d-yyyy") + ".hex";
FileStream LogFile = new FileStream(filepath, FileMode.Create);
LogFile.Write(bytesToRec, 0, bytesToRec.Length);
LogFile.Close();
}