AVR32 UC3 USB data loss in cdc device mode - c#

I need to transfer data from AT32 UC3 microcontroller ADC to PC via USB. I check work of ADC and PDCA in MCU of filling the buffer, and it works was perfect without data loosing. But when I send data from USB some bytes are lost. I do not know, why this happens.
I write simple programms to send some data from MCU to PC and check this data. In MCU I fill buffer with numbers from 0,1,2.. to 255 continuously, then send buffer via USB to PC, and check content of this buffer. So, some numbers are different from original data. Some bytes are lost. I using EVK1100 in CDC device mode.
AVR code:
#include <asf.h>
#include "conf_usb.h"
#define BUF_SIZE 32
int main(void){
irq_initialize_vectors();
cpu_irq_enable();
sysclk_init();
udc_start();
udc_attach();
char pbuf[BUF_SIZE];
for(int i=0; i<BUF_SIZE; i++){
pbuf[i] = (char)i;
}
while (true) {
udi_cdc_write_buf(pbuf, BUF_SIZE);
}
}
C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
namespace acc_tester
{
class Program
{
static void Main(string[] args) {
Console.WriteLine("Start");
int N = 32;
SerialPort serialPort = new SerialPort();
serialPort.PortName = "COM6";
serialPort.Open();
byte[] buf = new byte [N];
for (int n = 0; n < 10000; n++) {
serialPort.Read(buf, 0, N);
for (int i = 0; i < N; i++) {
if (buf[i] != (byte)(buf[0] + i)) {
Console.WriteLine("Data Lost. n =" + n.ToString() + " i=" + i.ToString());
return;
}
}
}
serialPort.Close();
Console.WriteLine("Stop");
return;
}
}
}
The output of my C# program is:
Data Lost. n =257 i=31
Data Lost. n =385 i=31
Data Lost. n =641 i=31
Data Lost. n =257 i=31
and etc.
Please, help me solve the problem.

SerialPort.Read reads at most N (32) bytes, it depends on how many bytes are in the input buffer (docs). Read returns the amount of bytes read.
To read chunk of data of length N you should buffer yourself the data and only check the content when you reach N bytes. Eg.
while (true) {
var bytesInBuffer = 0;
bytesInBuffer += serialPort.Read(buf, bytesInBuffer, N - bytesInBuffer);
if (bytesInBuffer == N) {
// Here the buffer is ready
bytesInBuffer = 0; // reset the counter
}
}

Related

.Net Calling NetworkStream.Read() twice caused about 100ms overhead, what's the cause?

I am writing a simple Tcp communication programs using TcpListener and TcpClient , .Net 4.7.1
I designed my own protocol to be:
For each "data unit", the first 4 bytes is an int, indicating the length of data body. Once a complete "data unit" is received, the data body (as a byte[]) is passed to upper level.
My read and write functions are:
public static byte[] ReadBytes(Stream SocketStream)
{
int numBytesToRead = 4, numBytesRead = 0, n;
byte[] Length = new byte[4];
do
{
n = SocketStream.Read(Length, numBytesRead, numBytesToRead);
numBytesRead += n;
numBytesToRead -= n;
} while (numBytesToRead > 0 && n != 0);
if (n == 0) return null; //network error
if (!BitConverter.IsLittleEndian) Array.Reverse(Length);
numBytesToRead = BitConverter.ToInt32(Length, 0); //get the data body length
numBytesRead = 0;
byte[] Data = new byte[numBytesToRead];
do
{
n = SocketStream.Read(Data, numBytesRead, numBytesToRead);
numBytesRead += n;
numBytesToRead -= n;
} while (numBytesToRead > 0 && n != 0);
if (n == 0) return null; //network error
return Data;
}
public static void SendBytes(Stream SocketStream, byte[] Data)
{
byte[] Length = BitConverter.GetBytes(Data.Length);
if (!BitConverter.IsLittleEndian) Array.Reverse(Length);
SocketStream.Write(Length, 0, Length.Length);
SocketStream.Write(Data, 0, Data.Length);
SocketStream.Flush();
}
And I made a simple echo program to test the RTT:
private void EchoServer()
{
var Listener = new TcpListener(System.Net.IPAddress.Any, 23456);
Listener.Start();
var ClientSocket = Listener.AcceptTcpClient();
var SW = new System.Diagnostics.Stopwatch();
var S = ClientSocket.GetStream();
var Data = new byte[1];
Data[0] = 0x01;
Thread.Sleep(2000);
SW.Restart();
SendBytes(S, Data); //send the PING signal
ReadBytes(S); //this method blocks until signal received from client
//System.Diagnostics.Debug.WriteLine("Ping: " + SW.ElapsedMilliseconds);
Text = "Ping: " + SW.ElapsedMilliseconds;
SW.Stop();
}
private void EchoClient()
{
var ClientSocket = new TcpClient();
ClientSocket.Connect("serverIP.com", 23456);
var S = ClientSocket.GetStream();
var R = ReadBytes(S); //wait for PING signal from server
SendBytes(S, R); //response immediately
}
In "ReadBytes", I have to read 4 bytes from the NetworkStream first in order to know how many bytes I have to read next. So in total I have to call NetworkStream.Read twice, as shown in above codes.
The problem is: I discovered that calling it twice resulted in around 110ms RTT. While calling it once(regardless of data completeness) is only around 2~10ms(put a "return Length;" immediately after the first do-while loop, or comment out the first do-while loop and hard-code the data length, or read as much as it can in one call to "Read").
If I go for the "read as much as it can in one call" method, it may result in "over-read" of data and I have to write more lines to handle the over-read data to assemble next "data unit" correctly.
Anyone knows what's the cause of the almost 50 times overhead?
As I read from Micrisoft
Microsoft improved the performance of all streams in the .NET Framework by including a built-in buffer.
so even if I call .Read twice, it's only reading from memory, am I correct?
(if you want to test the codes, please do it on a real server and connect from your home PC maybe, do it in localhost always returns 0ms)
Thanks for Jeroen Mostert's comment reminder. I added:
ClientSocket.NoDelay = true;
ClientSocket.Client.NoDelay = true;
to both the client and server side and the annoying delay is gone, the RTT is back to expected.
TcpClient.NoDelay Property
Further tests showed that both sides(client and server) contributed around 50ms delay without modifying "NoDelay" option, so in total around 100ms RTT "overhead".

Send Image Frames from C++ Server to C# Client using Named Pipe

I am noobie in IPC. I am trying to send the Image Frame from my C++ Server to C# Client. I have start learning about that and make a small Client and Server that In which my C++ Server sends Hello. I saw a related question and someone told to first convert the Image into Byte Array and then send that in same way as Hello Message but I am not able to do that.
My Basic Client Server Code
C++ Code:
Mat image = imread("IMG_0_10_34_45_2018_1.bmp");
uchar buffer[500][500];
for (int i = 0; i < image.rows; i++)
{
for (int j = 0; j < image.cols; j++)
{
buffer[i][j] = image.at<unsigned char>(i, j);
}
}
cout << "Server Creating Pipe\n";
HANDLE hPipe = ::CreateNamedPipe(_T("\\\\.\\pipe\\HyperPipe"),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
PIPE_UNLIMITED_INSTANCES,
4096,
4096,
0,
NULL);
cout << "Server Created Succesfully";
ConnectNamedPipe(hPipe, NULL);
cout << "Sending Message to Client";
DWORD bytesWritten = 0;
WriteFile(hPipe, buffer, sizeof(buffer) * sizeof(uchar), &bytesWritten, NULL);
CloseHandle(hPipe);
return 0;
And C# Code:
static void Main(string[] args)
{
Console.WriteLine("Creating Client Pipe");
NamedPipeClientStream pipe = new NamedPipeClientStream(".", "HyperPipe", PipeDirection.InOut);
Console.WriteLine("Pipe Created Successfully, Connecting to Server");
pipe.Connect();
Console.WriteLine("Successfully, Connected to Server");
using (StreamReader rdr = new StreamReader(pipe, Encoding.Unicode))
{
System.Console.WriteLine("Message from Server: " + rdr.ReadToEnd());
}
Console.ReadKey();
}
I also noticed that in my C++ Server I have to change the PIPE_TYPE to BYTE and also READMODE to BYTE. I am using OpenCV library for Image Processing so I can easily make Byte Array no issue with that.
So, Can Anyone Please tell me how to send that Byte Array from C++ to C#.
Or if possible that anyone can provide me the code for that
Thanks in Advance
Update:
No error is coming but at the client side i.e C# Side the the output of Message from Server is ????? .
To Send the Byte Array from Server to Client i.e the buffer just small changes in the WriteFile function is required.
WriteFile(hPipe, buffer, sizeof(buffer) * sizeof(uchar), &bytesWritten, NULL);
This method will send whole Byte Array to the Client
And also changing the buffer
int _count = 0;
UINT8 _imageBuffer[110592];
for (int _imageRow = 0; _imageRow < _image.rows; _imageRow++)
{
for (int _imageCol = 0; _imageCol < _image.cols; _imageCol++)
{
buffer[_count] = image.at<uchar>(_imageRow, _imageCol);
_count++;
}
}
I have hardCode the buffer Array because I known that my camera will only send 110592 byte to create one frame.
And On the Client Side just use Read function.
int _imageRowSize = 288;
int _imageColSize = 384;
int _count = 0;
byte[] buffer = new byte[_imageColSize * _imageRowSize];
Image<Gray, UInt16> image = new Image<Gray, UInt16>(_imageColSize,_imageRowSize);
Console.WriteLine("Creating Client Pipe");
NamedPipeClientStream pipe = new NamedPipeClientStream(".", "HyperPipe", PipeDirection.InOut);
Console.WriteLine("Pipe Created Successfully, Connecting to Server");
pipe.Connect();
Console.WriteLine("Successfully, Connected to Server");
using (MemoryStream ms = new MemoryStream())
{
while (true)
{
_count = 0;
int read = pipe.Read(buffer, 0, buffer.Length);
for (int _imageRow = 0; _imageRow < 288; _imageRow++)
{
for (int _imageCol = 0; _imageCol < 384; _imageCol++)
{
try
{
image.Data[_imageRow, _imageCol, 0] = (UInt16)(buffer[_count] * 255);
}catch(Exception exception)
{
Console.WriteLine(exception);
}
_count++;
}
}
if (read <= 0)
break;
ms.Write(buffer, 0, read);
}
}
CvInvoke.Imshow("Image", image);
}

Ho to read data from COM-port in asynchronous mode using await async in C# .NET?

My application works with some peripheral device. I must receive array of bytes from COM-port. Below are the snippets of code executing synchronously from my application:
// COM-port used.
private SerialPort _serialPort;
// Buffer for bytes received from COM-port.
private Byte[] _inputOutputBuffer;
// Buffer for instances of Point.
private List<Point> _linePoints = new List<Point>();
This method prepairs COM-port to work.
// Prepaires COM-port.
void PrepareComPort()
{
if (this._serialPort == null)
this._serialPort = new SerialPort(this.SelectedAvailableComPortsName);
this._serialPort.BaudRate = 115200;
this._serialPort.Parity = Parity.None;
this._serialPort.DataBits = 8;
this._serialPort.StopBits = StopBits.One;
this._serialPort.Handshake = Handshake.None;
this._serialPort.ReadTimeout = SerialPort.InfiniteTimeout
this._serialPort.WriteTimeout = 1000;
if (!this._serialPort.IsOpen)
this._serialPort.Open();
}
This method gets array of bytes via COM-port.
// Gets bytes from device via COM-port.
void recieveBytesFromDevice()
{
// Get bytes array at whole from COM-port.
while (this._serialPort.BytesToRead < 4006) { ; }
this._inputOutputBuffer = new Byte[this._serialPort.BytesToRead];
this._serialPort.Read(this._inputOutputBuffer, offset: 0, count: this._serialPort.BytesToRead);
}
This method fills the list of instances of Point.
// Fills list of instances of Point.
void FillPointsList()
{
for (int i = 0, j = 0; i <= this._inputOutputBuffer.Length - 8; i++)
{
Int16 shortValue = 0;
if (i % 2 == 0)
{
Byte[] bytes = new Byte[] { this._inputOutputBuffer[i], this._inputOutputBuffer[i + 1] };
Array.Reverse(bytes);
shortValue = BitConverter.ToInt16(bytes, startIndex: 0);
_linePoints.Add(new Point(j, shortValue));
j++;
}
}
}
My application sends data request via COM-port to the peripheral device and the peripheral device always send just 4006 bytes as a reply which my application must receive. If the peripheral device sends 4006 bytes without any delay than the application works good. But when the peripheral device has some delay before sending of 4006 bytes than my application hangs. How to realize aforementioned PrepareComPort and FillPointsList methods as one method for asynchronous work using await async?

Modbus Communication

I am using C# to communicate via modbus rs485 rs232 to 2 phase meters that among other log the power voltage.
I have to send data over the bus so that i can receive the readings.
I have connected a normal wire and shorted the send and receive.
The data is recieved and this event is fired:
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
byte[] buff = new byte[sp.BytesToRead];
//Read the Serial Buffer
sp.Read(buff, 0, buff.Length);
string data= sp.ReadExisting();
foreach (byte b in buff)
{
AddBuffer(b); //Add byte to buffer
}
}
Then this buffer is sent to another function which is this one:
private void AddBuffer(byte b)
{
buffer.Add(b);
byte[] msg = buffer.ToArray();
//Make sure that the message integrity is correct
if (this.CheckDataIntegrity(msg))
{
if (DataReceived != null)
{
ModbusEventArgs args = new ModbusEventArgs();
GetValue(msg, args);
DataReceived(this, args);
}
buffer.RemoveRange(0, buffer.Count);
}
}
I think that the problem lies at the data integrity check:
public bool CheckDataIntegrity(byte[] data)
{
if (data.Length < 6)
return false;
//Perform a basic CRC check:
byte[] CRC = new byte[2];
GetCRC(data, ref CRC);
if (CRC[0] == data[data.Length - 2] && CRC[1] == data[data.Length - 1])
return true;
else
return false;
}
There is a CRC check and what is strange is that it never becomes true. The CRC calculation:
private void GetCRC(byte[] message, ref byte[] CRC)
{
ushort CRCFull = 0xFFFF;
byte CRCHigh = 0xFF, CRCLow = 0xFF;
char CRCLSB;
for (int i = 0; i < (message.Length) - 2; i++)
{
CRCFull = (ushort)(CRCFull ^ message[i]);
for (int j = 0; j < 8; j++)
{
CRCLSB = (char)(CRCFull & 0x0001);
CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF);
if (CRCLSB == 1)
CRCFull = (ushort)(CRCFull ^ 0xA001);
}
}
CRC[1] = CRCHigh = (byte)((CRCFull >> 8) & 0xFF);
CRC[0] = CRCLow = (byte)(CRCFull & 0xFF);
}
The problem is the use of ReadExisting(). It was not to be used in that manner as the buffer was being filled with useless data from the serial port. This problem was identified by #glace in the comments!
You first need to establish communication with your meters through some existing MODBUS master application like MODPOLL. Then, once you have communication working and having valid replies from your device, then and only then start testing your code. This way you make sure that problem can be only in your code and nothing else.
For example, to connect to two slave devices at the same time RS485 must be used instead of RS232, and this requests different wiring and RS485 to RS232 convertor on PC side.
Having RX and TX connected in RS232 for simulation purpose is not a good idea since each MODBUS message from a master (except broadcast messages) needs a reply which is different from just message echo. Also, each MODBUS message from a master has MODBUS client address embedded in it and only single client should reply to it (MODBUS is single master multiple slaves protocol).
As for a CRC calculation, this might help for MODBUS RTU protocol (ASCII is different):
function mb_CalcCRC16(ptr: pointer to byte; ByteCount: byte): word;
var
crc: word;
b, i, n: byte;
begin
crc := $FFFF;
for i := 0 to ByteCount do
if i = 0 then // device id is 1st byte in message, and it is not in the buffer
b := mb_GetMessageID; // so we have to calculate it and put it as 1st crc byte
else
b := ptr^;
Inc(ptr);
endif;
crc := crc xor word(b);
for n := 1 to 8 do
if (crc and 1) = 1 then
crc := (crc shr 1) xor $A001;
else
crc := crc shr 1;
endif;
endfor;
endfor;
Return(crc);
end;
function mb_CalcCRC: word; // Calculate CRC for message in mb_pdu
begin // this message can be one that is just received, or in a reply we have just composed
Return(mb_CalcCRC16(#mb_pdu[1], mb_GetEndOfData));
end;
That's a quote from a working embedded AVR device with implemented MODBUS RTU slave protocol.

Using COM port in C# and not getting all sent data

Just to explain, I have a dev board that is, on command, shooting out 4 chars (Bytes). The terminal program (RealTerm) i'm using to debug this sees all 4 bytes. I've now moved on to writing the desktop software, and my program is only paying attention to 1 out of 4 bytes sent. TO clarify, i don't know which 1 of 4 bytes (first , last, middle two) but i can find out if its really necessary.
At first I thought the SerialPort.DataReceived event would fire for each byte that was received. This isn't true, I don't know what causes it to fire but its not the receiving of a singular Byte.
So I tried looping over SerialPort.BytesToRead, but this also only gets the first byte, even though it recognizes there are 3 bytes to read (why not 4??)
Its not essential for me to receive this data at the exact time it hits the port, but obviously I dot want to be loosing 3/4 of my data. However it wont always be 4 bytes, that's just what its doing now. I just want to get all bytes that are ready to be read.
Event Handler:
private void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
while (comPort.BytesToRead > 0)
{
RxString = comPort.ReadExisting();
RxByte = comPort.ReadByte();
byte[] myByte = new byte[6];
for (int i = 0; i < 6; i++)
{
myByte[i] = 0000000;
}
comPort.Read(myByte, 0, comPort.BytesToRead);
for (int i=0;i<6;i++)
{
if (myByte[i] != null)
{
thisBytes.Add(myByte[i]);
}
}
RxString = RxByte + "";
try
{
this.Invoke(new EventHandler(dealWithByte));
}
catch
{
}
}
}
private void dealWithByte(object sender, EventArgs e)
{
foreach (byte item in thisBytes)
{
RxByte = Convert.ToInt16(item);
string binary = Convert.ToString(RxByte, 2).PadLeft(8, '0');
//processTime(binary);
}
}
I am not a C# person but the code is pretty simple, pseudo code
numBytes As Int = SerialPort1.BytesToRead 'get # of bytes available
buf(numBytes - 1) As Byte 'allocate a buffer
br As Int = SerialPort1.Read(buf, 0, numBytes) 'read the bytes
If br <> numBytes {
Resize(buf, br) 'resize the buffer
}
at this point store the bytes into a list. This list can then be processed for messages.

Categories