I recently got a sas expander card.
The one who gave card to me said:
It has a firmware on the chip and it can show sensor's temperature.
He wants me to develop a C# Console app to execute the firmware.
I didn't know the firmware source code looks like.
But it could be executed by PuTTy and it's connection was via RS232 Serial Port.
PuTTy connection setting:
After I click Open,press Enter and type command sys:
What I try in my C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.Threading;
namespace SerialPortExample
{
class SerialPortProgram
{
// Create the serial port with basic settings
[STAThread]
static void Main()
{
SerialPort mySerialPort = new SerialPort("COM5");
mySerialPort.BaudRate = 115200;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.RtsEnable = true;
mySerialPort.DtrEnable = true;
mySerialPort.ReadTimeout = 2000;
mySerialPort.WriteTimeout = 1000;
mySerialPort.Open();
if(mySerialPort.IsOpen)
{
string str= "Enter";
mySerialPort.Write(str);
}
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
Console.ReadLine();
}
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.WriteLine("Data Received:");
Console.Write(indata);
}
}
}
What my code execute:
What is the problem with my code?
How can I execute firmware via RS232 and interact like PuTTy have done?
My Console app is using .Net Framework 4.7.2.
You are sending the string Enter (like typing ⇧E, N, T, E, R). You should probably send the ⏎ Enter key, which is represented on a terminal with the ASCII code 13, i.e. \r in a C# string.
Also you don't yet send any actual command. Try something like counters\r or sys\r.
(You currently receive the Enter back as response because that's what you sent out, and the card echoes any incoming characters so it can be used like a shell without blind typing. There is no other response yet because from the card's perspective you basically started typing the (invalid) command Enter but haven't yet submitted it with the ⏎ Enter key.)
Also I'd suggest adding the event listener for received data before sending any data, otherwise there would be a race condition in which the card could be responding before you even set up your listener and you would lose part of the data.
Additional note: Using the DataRecieved event may not even be desirable in your case.
According to docs:
The DataReceived event is not guaranteed to be raised for every byte received. Use the BytesToRead property to determine how much data is left to be read in the buffer.
This means that your DataReceived event may not even fire at all if there wasn't enough data sent in total yet (it may fire some time later with all the data at once) - but if you quit your program before that, you will never see.
As suggested here (emphasis mine):
Here is my general approach:
Use event-driven (DataReceived) code for streaming data. That is, where data is delivered at regular intervals, without specific associated commands that originate from your application.
Use polling for Command/Response protocols. These might involve a thread the you create to poll, but more frequently would be simple loops that may or may not block other operations until they complete.
So, it would be recommended to use one of the Read methods instead (see docs). There is also ReadTo and ReadLine which you may find useful. You may choose to use ReadTo(" bp1 >") for instance.
Related
I am trying to read data from a device connected via USB.
For creating the trigger the code looks like:
private SerialPort realTimePort;
realTimePort = new SerialPort();
realTimePort.BaudRate = 9600;
realTimePort.PortName = "COM4";
realTimePort.ReadTimeout = 5000;
realTimePort.ReadBufferSize = 32768;
realTimePort.ReceivedBytesThreshold = 1;
realTimePort.BaudRate = 9600;
realTimePort.ReadBufferSize = 4096;
realTimePort.ParityReplace = 63;
realTimePort.Parity = Parity.None;
realTimePort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(realTimePort_DataReceived);
realTimePort.Open();
To read the data, which was sent, the code looks like:
public void realTimePort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// Do something with the data
}
With one version of the device everything works fine and the trigger starts, when data was sent, but with a newer software-version of the device realTimePort_DataReceived is never triggered.
At first i thought, that the problem might be, that the device never sends data, but then i tried to read the data with "Tera Term" and there i can see exactly, what i am expecting. I also compared the data with "Tera Term", which was sent of the devices with the different software-versions, but it is exactly the same string.
Do you have any ideas, why the event is triggered with the older software-version and not with the newer one?
An employee of the manufacturer of the device already gave me the specification of the SerialPort, because i had this problem, but it didn't help me.
It is hard to reproduce the issue as i am not aware what type of device you are using and what type of data is sends here are some tips you can evaluate a quick check list to ensure the correct data receiving.
1. Play with RTS or DTR port flags for new version device
Basically some new versions of hardware uses flags of SerialPort e.g. DTR (Data Terminal Ready) indicates that your code is ready to receive, and RTS (Request to Send) a request to device to actually send data. for older hardware types it was not mandatory to use these flags although in modern devices its still not but just a standard practice so you should experiment & try enabling these by your code e.g.
realTimePort.RtsEnable = true; //enable this mode
realTimePort.DtrEnable = true; //and also this one
2. Try to read device error stream
It is possible that your new version hardware is sendind data over error stream, the tool you was using utilizes both streams for data read so you can subscrive to error event like.
realTimePort.ErrorReceived += new SerialErrorReceivedEventHandler(sPort_ErrorReceived);
private static void sPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
{
//process your error, it will give you further hint about why part of your question.
}
I'm working on writing a simple program to move a stepper motor in C#. I have some past experience in C++, but have decided to transition over, as I'd have to reteach myself a bit of C++.
Previously, I've controlled the motor (using an Applied Motion ST5 Stepper Controller) with serial commands via PuTTY. My thought is that I could just send the same commands using C# by opening the correct COM Port (which works fine, as it crashes when I feed in a nonworking port number), and sending a string over. However, when I send a string of the same command that I had been using via serial terminal (FL1000, followed by a carriage return, it tells the motor to move 1000 steps clockwise), the motor does nothing. WriteLine should be the correct thing to use here, as it sends the string then a return, correct?
Does anybody see any glaring mistakes that would make my string not make it to the controller?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
namespace ConsoleApp3
{
class Program
{
static SerialPort comPort;
static void Main()
{
//These values in the declared serial port match what my device manager says.
comPort = new SerialPort("COM6", 9600, Parity.None, 8, StopBits.One);
comPort.ReadTimeout = 5000;
comPort.WriteTimeout = 5000;
comPort.Open();
//Pauses for a moment so that I can see the console otuput.
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(3));
string command = "FL1000";
Console.WriteLine("Moving Motor...");
//Tells the controller to move the motor 1000 steps clockwise
comPort.WriteLine(command);
//confirms that the code made it past the comPort writeline
Console.Write("Command Sent");
//Pauses for a moment so that I can see the console output.
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(3));
}
}
}
I expect that this would move the motor 1000 steps. The only results I see are that my "markers" appear on the console. The program exits without error.
Thank you in advance!
Your command does not contain a carriage return or newline. The motor is looking for one of these to know that the command is complete.
I haven't worked with their ST5 line of motors, but other products they carry require the command to be terminated with a carriage return. Try changing your message to:
string command = "FL1000\r";
Excuse me, quick question:
I have this hardware setup:
Same machine: "Com3" -> USB -> To Serial -> To USB -> "Com4"
And I followed MSDN SerialPort Class and MSDN SerialPort.ReadLine() to build this routine:
SerialPort SendSerialPort = new SerialPort("Com3", 9600);
SerialPort ReceiveSerialPort = new SerialPort("Com4", 9600);
SendSerialPort.Open();
ReceiveSerialPort.Open();
SendSerialPort.WriteLine("Test");
var message = ReceiveSerialPort.ReadLine(); // control stops here
SendSerialPort.Close();
ReceiveSerialPort.Close();
Console.WriteLine(message);
However, when I tend to ReadLine(), my control stops and just waits. I did not expect that.
I am expecting to receive the string Test and assign it to my var message. Could you please tell me what am I doing wrong here?
EDIT:
I tested my hardware using the Serial Port Utility Application and it worked just fine.
I've altered from the example you linked:
To actually have both ports running to read and write back and forth you will actually need to implement threading for reading and writing for both.
It can be a good idea to use a timer.
public static void Main()
{
SerialPort SendSerialPort = new SerialPort("Com3", 9600);
SerialPort ReceiveSerialPort = new SerialPort("Com4", 9600);
StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;
Thread readThread = new Thread(Read);
// Set the read/write timeouts
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
SendSerialPort.Open();
ReceiveSerialPort.Open();
bool _continue = true;
readThread.Start();
Console.Write("Name: ");
name = Console.ReadLine();
Console.WriteLine("Type QUIT to exit");
while (_continue)
{
message = Console.ReadLine();
if (stringComparer.Equals("quit", message))
_continue = false;
else
SendSerialPort.WriteLine(String.Format("<{0}>: {1}", name, message));
}
readThread.Join();
SendSerialPort.Close();
}
public static void Read()
{
while (_continue)
{
try
{
string message = ReceiveSerialPort.ReadLine();
Console.WriteLine(message);
}
catch (TimeoutException) { }
}
}
Usually there will be a beginning and end value within the written data to tell the other port that the message is finished and also for the ports to validate that they are reading data they should be, usually with commands of what to do with that data. (out of scope for this question).
Also lacking and important is the intialisation of your ports.
I prefer to use the default constructor (preference only)
SerialPort Constructor ()
And then set any values like so:
_serialPort.BaudRate = SetPortBaudRate(_serialPort.BaudRate);
_serialPort.Parity = SetPortParity(_serialPort.Parity);
_serialPort.DataBits = SetPortDataBits(_serialPort.DataBits);
_serialPort.StopBits = SetPortStopBits(_serialPort.StopBits);
_serialPort.Handshake = SetPortHandshake(_serialPort.Handshake);
All the constructors will give these values:
This constructor uses default property values when none are specified. For example, the DataBits property defaults to 8, the Parity property defaults to the None enumeration value, the StopBits property defaults to 1, and a default port name of COM1.
Even the handshake has a default value. If you look at the source code.
private const Handshake defaultHandshake = Handshake.None;
The problem with your code is in this line
var message = ReceiveSerialPort.ReadLine();
You block your code to wait for a line, if the line never arrives it will remain here forever or the value set to ReadTimeout
So why does the line never arrive?
The problem can be an error in WriteLine("Test");, you should handle errors, or it can be that your in are blocking your code ReadLine() before the WriteLine("Test") manage to come through, you could insert a Thread.Sleep(100) between, but this is not really improving the code.
Note: Your code will also work as is sometimes, depending on these race conditions.
This synchronized / blocking reading from serial ports seems simple in code just one line; but it creates a lot of negative side effects in your communication protocol's.
A much better solution (considering that you like to Read / Write data from a microcontroller) is to either use a thread as Yvette suggested or use asynchronously reading Stream.BeginRead (Byte[], Int32, Int32, AsyncCallback, Object) which I would prefer.
The asynchronously reading will throw an event when something is incoming on the serial port. The basic idea of this programming strategy is to not do step programming but expecting what ever result and then handle it correctly.
In communications protocol with asynchronously reading the AutoResetEvent is very useful, hence you send something, then you start the AutoResetEvent, if asynchronously the expected result is arriving you will set this event and your code can continue, if it does not arrive the AutoResetEvent will timeout and you can handle this.
It cannot block when there is data available. What you sent either got stuck in the transmit buffer, got lost due to a wiring mistake, triggered an error or was ignored. If it works with another program then a wiring mistake can't be the problem.
Do keep in mind that just setting the Baudrate is not enough, you must also use set the DataBits, Parity and Stopbits properties to match the device settings. A mismatch can trigger an error, the kind you can only see when you write an event handler for the ErrorReceived event. Never skip that event, confounding problems can occur if you never check.
And above all the Handshake property must be set correctly. The proper value depends on how the ports are wired together, it is too common to not connect them. Start by setting it to Handshake.None so a wrong state for the DSR and CTS signals can't block reception and a wrong state for the DTR and RTS signals can't block transmission. Beware that it is common for another program to enable hardware handshaking, a mismatch is guaranteed to cause communications to stall.
If you use synchronous reads instead of the DataReceived event then you should in general deal with the possibility that a device is not responding. Either because it is powered off, not connected at all or malfunctioning. Use the ReadTimeout property for that so your program cannot hang. Aim high, 10000 milliseconds is a reasonable choice.
Beware the randomness of this problem, putzing around with another program can easily get the port configured correctly and now it will suddenly work. And beware that starting a thread accomplishes nothing, it will now be that thread that gets stuck and the Join() call will deadlock.
Background: we are developing an application (or windows service) that will listen for communications from various devices connected via virtual serial ports. Each device's information will be captured manually, so I know device 1 will be on COM5, Device 2 is on COM6, etc. Any time a device transmits data, I need to capture it and write in somewhere else (basically a log file).
With that in mind, is it possible to monitor more than one serial port on a single thread, or should I spawn a new thread for each port (keep in mind that I know exactly which ports to monitor)?
Or what would you guys think is a good approach?
My working prototype code looks like this (only reads one port though):
class Program
{
public static void Main()
{
SerialPort mySerialPort = new SerialPort("COM5");
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
mySerialPort.Open();
Console.WriteLine("Press any key to continue...");
Console.WriteLine();
Console.ReadKey();
mySerialPort.Close();
}
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.WriteLine(indata);
Debug.Print("Data Received:");
Debug.Print(indata);
}
}
I'm basically wondering if I should create a class for each port that contains the code in the console application, or if I should go old-school and write a giant procedural app that monitors all of them at once.
If the COM port devices are all similar, one class to handle retrieving their data with an instance for each device seems like the way to go. If separate functionality is needed you can always inherit from a base class. If you go down the rout of 'writing a giant procedural app' it will be much more difficult to maintain and modify in future.
As for multiple threads, the event handler you are using should allow multiple ports to be read without affecting other operations in your program. They can be considered their own thread, operations between them need to be handled as cross thread operations (such as changing form properties).
The DataReceived events tend to occur on a background thread created by SerialPort anyway.
This means:
a. You don't need to create multiple threads yourself to monitor multiple ports
b. You need to be careful what you do in the event handler, because you're probably not on your app's main thread, which can be a problem if, for example, you interact directly with a window. Your console stuff will be fine, however.
I am starting from the ground up and trying to write a simple console to interface with a serial port on a windows 7 computer.
I am using:
Visual Studio 2010 Ultimate
C# console project
Code: http://pastebin.com/0ADaEiSY
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
namespace ConsoleApplication1
{
class Program
{
public static void Main()
{
SerialPort mySerialPort = new SerialPort("COM5");
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
mySerialPort.Open();
mySerialPort.Write("This is a test");
Console.WriteLine("Press any key to continue...");
Console.WriteLine();
Console.ReadKey();
mySerialPort.Close();
}
private static void DataReceivedHandler(
object sender,
SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Console.Write(indata);
}
}
}
So far i have ran this code and interfaced with a xbee module connected to my computer. That xbee module sent the serial data to another xbee connected to a msp430. The msp430 is programmed to take whatever it receives and echo it back. This works with the code I have. In my console I will get "This is a test" echoed back onto the console window.
The problem I am having is when I use a virtual serial connection to a putty window. I am using this to try to ease development and not have to use hardware all of the time. I will use HHD Free Virtual Serial Ports to create a bridged connection between two serial ports. I will connect one to the putty terminal and the other will be for my console program. When running the program I recieve the error.
"A first chance exception of type 'System.TimeoutException' occurred in System.dll"
on the line
mySerialPort.Write("This is a test");
But the "This is a test" will appear on the Putty terminal.
If I remove the "mySerialPort.Write("This is a test");" line and attempt to send data from the Putty window to the console window, nothing appears.
Again this works with my hardware solution just fine.
Please help and i will try to clarify any questions. Thank you again.
I guess the problem is in virtual utility you are using. It seems it sets pin states incorrect. If I use 2 putty instances and connect to bridged ports I see infinite sending of symbol I entered. So I think your code is fine.
When I was working on such tasks I used a special cable for connecting 2 hardware com ports (com1 and com2, if you don't have them you can try usb-to-com converters) and it worked fine.
I'm has the very same problem with HHD Free Virtual Serial Ports, but this work great with asynchronous write operation.
Also you can replace
mySerialPort.Write("This is a test");
with (for example)
var buffer = Encoding.ASCII.GetBytes("This is a test");
mySerialPort.BaseStream.BeginWrite(buffer, 0, buffer.Length, ar => mySerialPort.BaseStream.EndWrite(ar), new object());