Serial port in .Net (C#) - c#

what should i do to wait until all the data sent to serial port
to test this condition assume the code bellow:
Console.WriteLine("Baud is:" + SerialPortObj.BaudRate);
Console.WriteLine(DateTime.Now.Millisecond);
string tmpStr="";
for (int i = 0; i < 100; i++)
{
tmpStr += "A";
}
SerialPortObj.Write(tmpStr.ToCharArray(),0,99);
Console.WriteLine(DateTime.Now.Millisecond);
example output is:
Baud is:300
97
97
And it indicate that .Net is not waiting until all chars to be send!
just to mention the code below does not work:
Console.WriteLine("Baud is:" + SerialPortObj.BaudRate);
Console.WriteLine(DateTime.Now.Millisecond);
string tmpStr="";
for (int i = 0; i < 100; i++)
{
tmpStr += "A";
}
SerialPortObj.Write(tmpStr.ToCharArray(),0,99);
while (SerialPortObj.BytesToWrite>0)
{
Thread.Sleep(1);
Console.WriteLine(SerialPortObj.BytesToWrite);
};
Console.WriteLine(DateTime.Now.Millisecond);
example output is:
Baud is:300
97
97
i am working on an special protocol that is depends on baud rate change over and use some thing like the follow:
->[Send Some Bytes (Baud300)]
<-[Receive Another Bytes (Baud9600)]
so i want to send some chars by write method and wait until it finish and right after finishing i try to change baud , so i could understand the received bytes
is there any idea?

In the first place the serial port is stateless. So you can never really by sure when the right point in time is reached for a baud rate change. Due to the fact that you are going to implement your own special protocol you must have control of both sides of the communication (sender/receiver). So in that case i strongly recommend to also set the Handshake property to RequestToSend and checking of the DtrEnable property.
Also you should use two buffers (received/outgoing) on each site of the communication which are watched by their own task/thread. If you push something into the outgoing buffer, the task check if sending is possible (CtsHolding, DsrHolding) and if yes, change the baudrate and push that data onto the wire. Wait till the holding properties are set back and then change the baudrate to the other value. The incoming thread is quite simple in this case. It simply waits for the DataReceived event cause the change of the baudrate is done by the outgoing task.
If you use hardware handshake (which i strongly recommend in your case), then be sure that your serial port supports it correctly. Most of the USB-to-Serial-Adapters don't work very well with anything else then 19200-8-N-1. So before you think you didn't code it right or the SerialPort class is buggy try to find two machines with a real serial port (or one machine with two ports for testing).

Try to store your data in a variable and when a specific condition apear (can be set by you), send the value of the variable to the serial port

Do it in hardware?
You might try to use two serial adaptors, configured as 300/9600. Tx on one and rx on the other. You would need a 'funny cable' with pins 2/3 split out to different D-types, but that should work.

Related

Can't get data out of FTDI FT201X using i2c

I have a project using the FTDI FT201X as a USB to i2c slave and the i2c master is an AVR microcontroller. I'm using WPF Core 3.1 C# on a Windows 10 machine. Basically, everything with the FTDI chip works fine except I can't successfully get data sent from the PC to the FTDI chip no matter what I try. The D2XX Write function says it was successful and returns no error, but there is never any data in the buffer when I try to read.
I've since written a small test program in an attempt to isolate the issue but the problem remains. Basically, when a button is clicked we open the device by serial number, we write a command to the device's buffers, handshake with the AVR to let it know to read and then wait for the AVR to drive a handshake pin low meaning it has received the data.
public class USBLibrary
{
byte targetDeviceCount = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
public FTDI connectedUSBDevice;
// Called from button click event
public void ConnectUSB()
{
bool isOK = true;
byte numOfBytes = 1;
uint bytesWritten = 0;
bool usbInPinIsHigh = false; // Tracks USB In Pin
byte lowMask = 0b00010000; // CBUS 0 is output (4-7), all pins low (0-3) (Default Setting)
byte highMask = 0b00010001; // CBUS 0 is output (4-7), CBUS 3 is high
byte inPinMask = 0b00001000; // AND with pin states to get input pin value (Bus3)
byte pinStates = 0; // Used to get the current pin values
double timeout = 0;
// Create new instance of the FTDI device class
connectedUSBDevice = new FTDI();
// Determine the number of FTDI devices connected to the machine
ftStatus = connectedUSBDevice.OpenBySerialNumber("P00001");
/*** Write to Device ***/
byte[] firmwareCmd = new byte[numOfBytes];
firmwareCmd[0] = 128; // 128 is Get Firmware Command
// firmwareCmd[1] = 61; // Just Testing
// Write Firmware Command to Tx buffer
ftStatus = connectedUSBDevice.Write(firmwareCmd, numOfBytes, ref bytesWritten);
Trace.WriteLine(bytesWritten);
// Handshake with Device
isOK = DeviceHandshake(lowMask, highMask, inPinMask);
// Check if handshake failed
if (isOK == false)
{
return;
}
Task.Delay(10);
// Wait until message is sent
while ((usbInPinIsHigh == false) && (timeout <= 1000))
{
Task.Delay(1);
// Check for USB In pin to go high. Signals FW transfer is complete and to retrieve.
ftStatus = connectedUSBDevice.GetPinStates(ref pinStates);
// Is input pin high or low?
if ((pinStates & inPinMask) == inPinMask) // In pin high
{
usbInPinIsHigh = true; // Means uC finished sending data
}
timeout++;
}
// TEST: displays timeout amount for testing
Trace.WriteLine("Timeout=" + timeout);
ftStatus = connectedUSBDevice.Close();
}
}
NOTE: For this code, I've taken out a lot of the error checking code for clarity. Also, the handshake code is not shown because it shouldn't be relevant: raise output pin, listen for AVR to raise output pin, lower output pin, listen for AVR to lower output pin.
On the AVR side, we simply poll for the FT201X's pin to go high and then handshake with the chip. Then we simply read. The read function always returns 0.
I doubt the problem is with i2c as there are 3 IO Expander chips controlling LEDs and buttons and we can read and write to those fine. Further, the FT chip has a function called Get USB State where you can check to see the device's status by sending the command and reading the result via i2c. When I do this, I always get back the correct 0x03 "Configured" state. So we can read from the chip via i2c.
There's also a function that will return the # of bytes in the buffer waiting to be read...when I do this, it always says 0 bytes.
And for good measure I replaced the chip with a new one in case it was bad and again we had the same results.
Is there anything I'm missing in terms of setting up the chip beyond using FT_Prog, like an initialization procedure or setting registers or something? Or do I need to somehow push the byte I write to the front of the queue or something before it can be read? Anybody seen anything like this before?
Given that I haven't affected the results, I'm either missing a key part in the process or something is wrong with their driver/version of the chip. It's been 3 weeks, I'm out of ideas, and my hair is patchy from ripping out large chunks. Please save my hair.
Check by oscilloscope that your I2C master gives clock for your slave (FT201x). Try to control only I2C (rip off GPIO controls) and check if you can isolate problem that way. I suppose you are very familiar with FT201X datasheet. Good luck!
Check the latency timer setting. It’s described in this document, https://www.ftdichip.com/Support/Documents/AppNotes/AN232B-04_DataLatencyFlow.pdf. In section 3.3, you’ll find a section describing a scenario in which no data will be made available to the app.
“While the host controller is waiting for one of the above conditions to occur, NO data is received by our driver and hence the user's application. The data, if there is any, is only finally transferred after one of the above conditions has occurred.”
You can use the latency timer to work around it, if you’re hitting this. Try setting it to 1ms, its lowest value. If your data has a delimiter character, consider setting that as an event character and you might get even better results.
Did this issue ever get resolved?
Experiencing the same issues with an FT200X except the function "bytes available" (0x0C) returns the correct byte count sent from the host PC, but can't read the actual bytes using the read procedure mentioned in the datasheet.
I have also several other I2C devices on the bus, working fine.

How solid is the Mono SerialPort class?

I have an application that, among other things, uses the SerialPort to communicate with a Digi XBee coordinator radio.
The code for this works rock solid on the desktop under .NET.
Under Mono running on a Quark board and WindRiver Linux, I get about a 99% failure rate when attempting to receive and decode messages from other radios in the network due to checksum validation errors.
Things I have tested:
I'm using polling for the serial port, not events, since event-driven serial is not supported in Mono. So the problem is not event related.
The default USB Coordinator uses an FTDI chipset, but I swapped out to use a proto board and a Prolific USB to serial converter and I see the same failure rate. I think this eliminates the FTDI driver as the problem.
I changed the code to never try duplex communication. It's either sending or receiving. Same errors.
I changed the code to read one byte at a time instead of in blocks sized by the size identifier in the incoming packet. Same errors.
I see this with a variety of remote devices (smart plug, wall router, LTH), so it's not remote-device specific.
The error occurs with solicited or unsolicited messages coming from other devices.
I looked at some of the raw packets that fail a checksum and manual calculation gets the same result, so the checksum calculation itself is right.
Looking at the data I see what appear to be packet headers mid-packet (i.e. inside the length indicated in the packet header). This makes me think that I'm "missing" some bytes, causing subsequent packet data to be getting read into earlier packets.
Again, this works fine on the desktop, but for completeness, this is the core of the receiver code (with error checking removed for brevity):
do
{
byte[] buffer;
// find the packet start
byte #byte = 0;
do
{
#byte = (byte)m_port.ReadByte();
} while (#byte != PACKET_DELIMITER);
int read = 0;
while(read < 2)
{
read += m_port.Read(lengthBuffer, read, 2 - read);
}
var length = lengthBuffer.NetworkToHostUShort(0);
// get the packet data
buffer = new byte[length + 4];
buffer[0] = PACKET_DELIMITER;
buffer[1] = lengthBuffer[0];
buffer[2] = lengthBuffer[1];
do
{
read += m_port.Read(buffer, 3 + read, (buffer.Length - 3) - read);
} while (read < (length + 1));
m_frameQueue.Enqueue(buffer);
m_frameReadyEvent.Set();
} while (m_port.BytesToRead > 0);
I can only think of two places where the failure might be happening - the Mono SerialPort implementation or the WindRiver serial port driver that's sitting above the USB stack. I'm inclined to think that WindRiver has a good driver.
To add to the confusion, we're running Modbus Serial on the same device (in a different application) via Mono and that works fine for days, which somewhat vindicates Mono.
Has anyone else got any experience with the Mono SerialPort? Is it solid? Flaky? Any ideas on what could be going on here?
m_port.Read(lengthBuffer, 0, 2);
That's a bug, you have no guarantee whatsoever that you'll actually read two bytes. Getting just one is very common, serial ports are slow. You must use the return value of Read() to check. Note how you did it right in your second usage. Beyond looping, the simple alternative is to just call ReadByte() twice.

My RS232 Serial Port Splits the input I send it

I have a USB to RS232 adapter and I was using it to get a long input (28 chars) from a barcode reader.
Everything works fine in my computer.
I installed my c# application on other computer that has RS232 Serial Port connected to its PCI-E and when I'm receiving the input from the barcode reader, it splits it into two parts!
How do I know that? Because I have an event handler for DataReceived on my c# application, and it's being called 2 times, and each time I get a part of the input.
The RS232 PCI-E ports are manufacturer by Oxford Semiconductor Inc.
OS is Windows 7.
I'm assuming it's a hardware issue and not a problem in my application.. Maybe some settings to change, a buffer size or something like that but I could't find something like that.
Thanks in advanced!
No, it is your application. You shouldn't expect all of the data to be immediately available; you were getting lucky on the first machine. You need to call Read() until you get everything you expect.
Differences in the UARTs, drivers, etc. can cause windows to raise that event multiple times, depending on timing and other factors.
Something along these lines:
char buf[28];
int offset = 0;
int nread;
while (offset < buf.Length) {
nread = comPort.Read(buf, offset, buf.Length - offset);
offset += nread;
}

Serial port read string

I have a serial port app that read weighing machine.
public void Read()
{
while (Puerto.BytesToRead > 0)
{
try
{
string inputData = Puerto.ReadExisting();
dataReceived = inputData;
}
catch (TimeoutException) { }
}
}
the return string is like this
It has other extrange chars in it, how can i do to parse or get a clean data from it? all I need is 0.52lb
I have no idea what weighing machine is it and what the serial port specs on it but, if it is black box to you too then, check the following:
- check if you have a technical spec that explains what comes out of RS232 port
- do several (10?) samples with one sample weight and see if the number of bytes are delivered each time
- if you see the number of bytes being constant (barring discrepancy in the 0.52lb text changing to 0.5lb once in a while), it is likely that garbage following the weight is additional binary data.
- if not, and you see the weight (text) with exact offset each time, you just can scrape the output
this is complete reverse engineering, I suggest going after technical spec and doing more insightful data handling though.
This could be anything - a bug in the weighing machine, some sort of hardware issue, or a problem in how the serial port is configured. I would suspect a configuration problem. Make sure all the settings are correct (BaudRate, Handshake, Parity, StopBits). Also, try connecting to the same serial port device using another program (e.g. see http://helpdeskgeek.com/windows-7/windows-7-hyperterminal/ ) and see if you see the same garbage data.

Detecting when SerialPort is ready for next command

I have a piece of hardware that I'm connecting to using the .NET SerialPort class over RS232.
According to its documentation it doesn't support any type of flow control.
I can write queries and commands to the device, for the queries it'll respond immediately to a read, and if echo is on for the device and I have to do a read after writing a command then the command writes work fine too. The commands and responses are a maximum of 7 characters.
However if echo is off and I write 2 commands in quick succession the second one isn't carried out, unless I put in a Thread.Sleep(15) between the writes, presumably replicating the time it takes to do the ReadLine when echo is on.
I can't necessarily guarantee that echo will be on, and explicitly turning it on isn't really an option either, so I basically need to handle the behaviour as I find it.
The SerialPort is set up as follows:
SerialPort _serialPort = new SerialPort
{
PortName = "COM1",
BaudRate = 9600,
Parity = Parity.None,
DataBits = 8,
ReadTimeout = 5000,
WriteTimeout = 5000,
NewLine = "\x0D"
};
And I'm using WriteLine and ReadLine to communicate with it.
Sleeping the thread feels like a hack, and I haven't found an alternative with all my googling.
So, have I missed something, is there some way I can check when the next command write to a serialport can be carried out or is Thread.Sleep pretty much my lot?
http://msmvps.com/blogs/coad/archive/2005/03/23/SerialPort-_2800_RS_2D00_232-Serial-COM-Port_2900_-in-C_2300_-.NET.aspx
Set handshake property to RTSCTS and handle the PinChanged event when CTS becomes true?
Lines marked ‘Output’ in the table can be set by the serial port to a high or low state (True or > > False) and the ‘Input’ lines can be read as high or low. You can use the PinChanged event to be > > notified when one of the input pins changes. The Handshake property can be set to use RTS/CTS > > > (uses hardware control lines) or XON/XOFF (uses software) or both.
Control Line Name DB9 Pin SerialPort Property I/O
DTR Data Terminal Ready 4 DtrEnable Output
RTS Request to Send 7 RtsEnable Output
CTS Clear to Send 8 CtsHolding Input
DSR Data Set Ready 6 DsrHolding Input
CD (or DCD) Data Carrier Detect 1 CDHolding Input
Unfortunately due to the lack of support in my system for flow control Thread.Sleep seems to be the solution.
I've set up my code so that it checks to see if echo is on and then if it is it just uses the ReadLine, and if it's off then it uses a Thread.Sleep(15).
It feels nasty, but it works reliably, so I'm just having to go with that.
I was just having a similar problem. Using a low baud rate I was attempting to write commands to the port too fast (apparently the "write" command returns before the write is finished).
I solved this by modifying the "Serial Port Ready?" function I call before each command. I added a while loop to sleep for 5ms while the "BytesToWrite" property was greater than zero. Worked fine after that.

Categories