I have a null terminated serial port listener and I want it to pass on all data and pin events from the in port to the out port. The data is working well however I want to pass on all the pin events as well. I've added a listener using:
in_port.PinChanged += new SerialPinChangedEventHandler(port_PinChanged);
and then handle it with:
static void port_PinChanged(object sender, SerialPinChangedEventArgs e)
{
if (e.EventType == SerialPinChange.Break)
{
out_port.BreakState = in_port.BreakState;
}
else if (e.EventType == SerialPinChange.CDChanged)
{
}
else if (e.EventType == SerialPinChange.CtsChanged)
{
}
else if (e.EventType == SerialPinChange.DsrChanged)
{
}
else if (e.EventType == SerialPinChange.Ring)
{
}
}
How can I pass these changes in pin state to the out port?
This isn't going to work. CD and Ring are modem signals, they are wired as inputs on your PC. You don't have spare outputs that you could use to drive these signals. CTS and DSR are handshake signals that are wired to RTS and DTR on the other end. You need to use them yourself to implement handshaking, on both ports. Break cannot work well either, you don't know when it turns off, although you could simulate it with a timer. Don't bother, that signal dates from the stone age.
RS-232 just isn't made for this. Instead wire it directly and tap the signals. TxD+Gnd to one port, RxD+Gnd to another so you can snoop on the traffic. Not the greatest for noise, keep the cables short or baudrate low. Soldering iron required.
The CtsChanged and DsrChanged pin states are reactions to other things happening, you should not try to pass them on in this way. They relate to the dataflow.
I'm not sure about the other signals.
Related
What I try to do: Processing 3 is receiving a sort of QR code via my webcam --> it reads the value and sends it to my Arduino, Arduino successfully receives it and can now do stuff with it. Now I want to add another communication channel, Unity. I want the Arduino to send the value from the Processing to Unity.
It is easy to communicate between Arduino and Unity, but I need Processing for the webcam value.
The problem: Both Processing 3 and Unity make use of the same port (COM4, 9600). This will cause an IO exception in Unity saying "Access Denied" followed by errors of the Serial port isn't open.
Processing 3 code
...
//Open port
String portName = Serial.list()[0];
myPort = new Serial(this, portName, 9600);
myPort.write(1);
...
Arduino code
void setup() {
// put your setup code here, to run once:
...
Serial.begin(9600); // Start serial communication at 9600 bps
...
}
void loop() {
if (Serial.available()) { // If data is available to read,
val = Serial.read(); // read it and store it in val
}
//val contains now the data that was sent from Processing 3
//Send this data to Unity:
Serial.flush();
Serial.println(val);
}
Unity code
...
SerialPort stream = new SerialPort ("COM4", 9600); //We obviously can't open this port since its already in use by Processing 3. How to fix this?
...
// Use this for initialization
void Start () {
stream.Open(); //Throws IO exception: Access Denied error
}
// Update is called once per frame
void Update () {
string value = stream.ReadLine();
val = int.Parse(value);
if (val == 1) {
//Links van arduino
goLeft();
}else if (val == 2) {
//Rechts van arduino
goRight();
}
}
We obviously can't open the port in Unity since its already in use by Processing 3. How to fix this?
Communication stream:
Processing 3 --> Arduino --> Unity
Eventually Unity needs to know whether you have to go Left or Right based on the QR code input on the webcam.
You can't use the same serial port in two concurrent applications (why do you want to use an Arduino at all?) A solution is to establish alink between applications. A network connection, using a 127.0.0.1 loopback connection, is a tried and tested way of creating that link.
As far as protocols go, you have endless options, my personal preference is to use OSC - both processing (via OSCP5) and Unity (various plugins, including my own I should really make public at some point) have decent support for messaging, but you can use many other types of links (ie. websockets)
For the people who would like to know how to solve this problem.
You can't. We have to think in another way.
Options were:
Close port while done processing and then open port in Unity (was not practical since we need a constant stream of instructions)
Leave out the Arduino and communicate between Processing and Unity (was not practical either since we need the Arduino in this case for blinkers)
Find another communication form between the Arduino/Processing and Unity without any ports. (Thanks to #kaj)
I've implemented the last option
Output Processing results to a "data.txt" file
Unity opens this file in C# with ReadAccess FileStream and reads the output and uses this
In this way we can still use the Arduino and Unity directly reads output from the Processing without a middleman.
I am trying to communicate with an Industrial weight bridge using a serial port. I know how to write the code code (c#). The problem is when I connect the bridge to the Indicator the weight is displayed. However when I connect the bridge to my PC and run the program all that is returned is "\0"(NULL). When I connect my PC to the indicator and run the program I get continuous "\0". I am using xk3190-a9 indicator. here is sample program
namespace SerialPort
{
class Program
{
private static string dev = "";
static void Main(string[] args)
{
System.IO.Ports.SerialPort mySerialPort = new System.IO.Ports.SerialPort("COM15")
{
BaudRate = 2400,
Parity = Parity.None,
StopBits = StopBits.Two,
DataBits = 8,
RtsEnable = true,
};
mySerialPort.DataReceived += DataReceivedHandler;
mySerialPort.Open();
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
mySerialPort.Close();
}
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
System.IO.Ports.SerialPort sp = (System.IO.Ports.SerialPort) sender;
dev += sp.ReadExisting();
Console.WriteLine(dev);
}
}
}
My question is whether the bridge needs "special" commands to send back the weight or what can I do to get the weight. Any other data from the port would be progress. Also I have tried different port settings all same result.
After searching online and not finding a solution that would fit my case I gave up the digital chase and consulted a weight bridge 'specialist'. In case you are pulling out your hair too, here are a few things to note:
Most weight bridges(trucks and vehicles) will send the weight as an analogue signal. So even though they have a serial port your computer will definately not "get it" hence the \0 return.
To get any weight to your software you will have to go through an indicator which has converters on it's motherboard which read the analogue signal and can convert it to a digital signal
As much as indicators get it, some of them have very low BaudRates and the rate might be set at a weird number(see 4) so you might want to try from as low as 100 to 9600. In my case the BaudRate was 600 which I never tried hence the continuous \0
Know how to configure your indicator - A simple google search using the indicator number should yield a good English language manual, it might be confusing at first but that is the only way you will be able to change the BaudRate(among other settings) and avoid all the guessing.
Simple indicators return GrossWeight and most times this is sufficient but incase you need weight per axle or you want weight on each load cell you might need an advanced indicator like Avery Weigh-Tronix E1310
This notes should guide you to a viable solution, I got mine from 1,3 & 4.
I am working with a codec and am trying to poll the state of RS232 serial pin 1 (CD high/low).
The code I have I think is right but I am second guessing myself and was hoping someone could confirm or correct me.
According to the the data sheet of the codec Pin 1 should be High when a call is active. I suspect i have done something wrong because while in a call I get a return of false (low).
This is a Windows Forms application and I am using System.IO.Ports
private void button4_Click(object sender, EventArgs e)
{
if (!serialPort1.IsOpen)
{
serialPort1.Open();
}
bool test = serialPort1.CDHolding;
if (test == false)
{
MessageBox.Show("Pin low");
}
else
{
MessageBox.Show("Pin high");
}
}
Also is there an easy way to show the actual voltage on the pin?
There really isn't much here we can tell you that you don't already know. Yes SerialPort.CDHolding "Gets the state of the Carrier Detect line for the port." I would first verify (electrically) the state of the pin, and then check that against what this property tells you. I'm guessing it is telling you the correct state.
When it comes to serial ports, I would always double check your pin-out; depending on the hardware and connector, they can be incredibly non-standard, and are easy to mess up.
You ask about showing the voltage on the pin. Do you mean programattically? No, that is impossible. That is a digital input line; once it hits the UART it is a digital signal, you cannot know the analog voltage.
Just as an additional tidbit, this property is actually just a wrapper that calls the Win32 GetCommModemStatus function, and returns true if bit 7 (decimal 128) is set.
Can you use the .PinChanged event instead? Or do you need to only poll on button press?
Ok, this should be dirt simple. I'm trying to read charactes from a serial device. It's such that if I send a space character, it echos back a string of numbers and EOL. That's it.
I'm using Unity 3.3 (.Net 2.0 support), and the 'serial port' is a Prolific serial-to-USB adaptor. BTW: Using Hyperterminal, it all works perfectly, so I know it's not driver nor hardware.
I can open the port ok. It seems I can send my space with port.Write(" "); But if I even TRY to call ReadChar, ReadByte, or ReadLine (like polling), it freezes up until I unplug the USB, and my console output shows nothing (exceptions were caught).
So instead I set up a DataReceviedHandler, but it's never called.
I've read some posts where people have done just this type of thing with Arduinos etc. (this is not an Arduino but hey), using nothing more than ReadLine. Their code does not work for me (and no answers thus far from those authors).
So, any tips? Do I need to use a different thread? If you know any Unity (Mono) coding, any tips along those lines greatly appreciated.
This code a mashup from http://plikker.com/?p=163 and http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx#Y537
using UnityEngine;
using System.Collections;
using System.IO.Ports;
using System;
public class SerialTest : MonoBehaviour {
SerialPort stream;
void Start () {
try {
stream = new SerialPort("COM3", 9600);
stream.Parity = Parity.None;
stream.StopBits = StopBits.One;
stream.DataBits = 8;
stream.Handshake = Handshake.None;
stream.DataReceived += new SerialDataReceivedEventHandler(DataReceviedHandler);
stream.Open();
Debug.Log("opened ok"); // it DOES open ok!
} catch (Exception e){
Debug.Log("Error opening port "+e.ToString()); // I never see this message
}
}
void Update () { // called about 60 times/second
try {
// Read serialinput from COM3
// if this next line is here, it will hang, I don't even see the startup message
Debug.Log(stream.ReadLine());
// Note: I've also tried ReadByte and ReadChar and the same problem, it hangs
} catch (Exception e){
Debug.Log("Error reading input "+e.ToString());
}
}
private static void DataReceviedHandler(
object sender,
SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender; // It never gets here!
string indata = sp.ReadExisting();
Debug.Log("Data Received:");
Debug.Log(indata);
}
void OnGUI() // simple GUI
{
// Create a button that, when pressed, sends the 'ping'
if (GUI.Button (new Rect(10,10,100,20), "Send"))
stream.Write(" ");
}
}
Events are not implemented in Mono SerialPort class, so you won't get any notifications, you have to perform (blocking) read explicitly. Other possible problem - I'm not sure how Unity Behaviours work, are you certain all methods accessing the SerialPort are invoked on the same thread? And you are not disposing you port object, this will also cause problems.
Make sure that you are opening the right port, using correct settings. Here is an example of how you could configure it:
serial = new SerialPort();
serial.ReadBufferSize = 8192;
serial.WriteBufferSize = 128;
serial.PortName = "COM1";
serial.BaudRate = 115200;
serial.Parity = Parity.None;
serial.StopBits = StopBits.One;
// attach handlers
// (appears to be broken in some Mono versions?)
serial.DataReceived += SerialPort_DataReceived;
serial.Disposed += SerialPort_Disposed;
serial.Open();
I recommend the open source RealTerm terminal, it has a rich set of features and can help you debug. Try writing a byte manually using such software, and if it works, then the problem is in your program. Otherwise it might be a driver problem (but more likely it isn't).
[Edit]
Calling SerialPort.ReadLine is actually supposed to block the thread until SerialPort.NewLine is received. Also ReadChar and ReadByte will hang until at least one byte is received. You need to make sure that you are actually receiving characters from the other side, and you won't be receiving them if your app is stuck and cannot send the space.
Since I never used Unity, I am not sure how Update is called, but I am presuming it's fired on a foreground thread in regular intervals (otherwise your app wouldn't freeze).
The example that you linked (Arduino and Unity example) shows that Arduino is sending the data continuously, and that is why their Update method is constantly receiving data (no space character needs to be sent towards the device). If they unplug the device, their app will hang just as well.
Well, maybe not, because in .NET 1.1, default value for ReadTimeout was not infinite, like it is in .NET 2.0.
So, what you can do is:
a. Set the ReadTimeout property to a reasonable value. Default in .NET 2.0 is InfiniteTimeout, which doesn't suit your needs. Cons: your update method will still hang for a while on each call, but not infinitely.
b. Someone said that events are not implemented in MONO SerialPort, so I guess using DataReceived only is not an option.
c. Move your sending logic to the Update method also, so that you don't read data at all, until it's time to read it:
private volatile bool _shouldCommunicate = false;
void Update ()
{
if (_shouldCommunicate) // this is a flag you set in "OnGui"
{
try {
stream.Write(" ");
Debug.Log(stream.ReadLine());
} catch (Exception e){
Debug.Log("Error reading input "+e.ToString());
}
}
}
void OnGUI() // simple GUI
{
if (GUI.Button (new Rect(10,10,100,20), "Send"))
_shouldCommunicate = true;
}
Note that, if your device is not sending data, it will also block at stream.ReadLine(), so make sure your ReadTimeout is set to a reasonable value. You will also want to stop sending at some point, but I leave that to you.
d. Send the space in OnGui like you are doing now, but always check if there is data in your buffer before reading it:
void Update () { // called about 60 times/second
try {
// call our new method
Debug.Log(ReadLineNonBlocking());
} catch (Exception e){
Debug.Log("Error reading input "+e.ToString());
}
}
private StringBuilder sb = new StringBuilder();
string ReadLineNonBlocking()
{
int len = stream.BytesToRead;
if (len == 0)
return "";
// read the buffer
byte[] buffer = new byte[len];
stream.Read(buffer, 0, len);
sb.Append(ASCIIEncoding.ASCII.GetString(buffer));
// got EOL?
if (sb.Length < 2 ||
sb[sb.Length-2] != '\r' ||
sb[sb.Length-1] != '\n')
return "";
// if we are here, we got both EOL chars
string entireLine = sb.ToString();
sb.Length = 0;
return entireLine;
}
Disclaimer: this is directly out of my head, untested, so there may be some syntax errors which I am sure you will handle.
Maybe your problem is the configuration of the serial port. It is important not only to check for BaudRate or StopBits. Also you should configure DTR, RTS, Handshake, everything. This is important cause maybe another program set some ugly values and the configuration must be explicitly set at every start or some settings of the old connection can run you into trouble.
Also maybe take a look into one of these tools:
com0com
Serial Port Monitor
They can help you to stub your serial interface or to take a deeper look into the connection. Also maybe try to talk to your serial device by using HyperTerminal or some similar tool that's proven to work.
Had similar problem with Mono, upgrading to 2.6.7 helped.
Do not mix data event and blocking read. What do you expect to happen if data arrives? That both the read method and the event should get the same received data?
You should also read about:
CTS: http://en.wikipedia.org/wiki/RS-232_RTS/CTS#RTS.2FCTS_handshaking
DTR: http://en.wikipedia.org/wiki/Data_Terminal_Ready
Small serial port tutorial describing all states: http://www.wcscnet.com/Tutorials/SerialComm/Page1.htm
The standard c# System.IO.Pots.SerialPort sucks big time. I suggest to give RJCP.DLL.SerialPortStream library a try. Synchronous read/write is super easy with this delightful library too, no need to jump through the loops with delegate and listeners.
I have a C# code which communicates with three different COM ports. The COM ports are actually three serial port to USB converters.
The code each time switches 'off' and 'on' the devices to which it is communicating, then initializes the three com ports, tries to send and read data and then closes the com port. This keeps continuing for a pre-defined number of loops.
My problem is that after about 8 or 9 iterations, the COM port communication stops working. Sometime it throws an error saying the port is closed, sometime it does not throw any exception but it is actually not reading or writing anything from the com port. Some point it was only writing but not reading back the data.
What might be the reason and any tips to debug this problem?
EDIT:
The port abruptly closes or stops working even in the middle of the program as shown below:
SerialPort.Write("ss");
SerialPort.Read("ss"); // FAILS!!
Some part of the code I am using
public string Read(string readCommand)
{
string str = "";
_port.WriteLine("\r");
_port.WriteLine(readCommand + "\r");
Thread.Sleep(0x3e8);
str = _port.ReadExisting();
return str;
}
public void Write(string command)
{
_port.WriteLine(command + "\r");
Thread.Sleep(100);
if (_port.ReadExisting() == string.Empty)
{
throw new IOException("Error writing to COM");
}
}
public void Initialize()
{
if (_port == null)
{
_port = new SerialPort(this.PortName.ToString(), this.BaudRate, this.Parity, this.DataBits, this.StopBits);
_port.Handshake = this.Handshake;
}
try
{
if (!_port.IsOpen)
{
_port.Open();
if (Read("") == string.Empty)
{
throw new IOException("Device not connected or powered on");
}
}
}
catch (Exception)
{
this.Close();
}
}
Thanks...
_port.WriteLine(command + "\r");
Thread.Sleep(100);
if (_port.ReadExisting() == string.Empty)
{
throw new IOException("Error writing to COM");
}
That's evil code and bound to throw sooner or later. Windows cannot provide a service guarantee like that. Or for that matter the device itself, especially when you power it on and off. Use SerialPort.ReadTimeout, set it to at least 2 seconds. And make a blocking call, like ReadLine().
catch (Exception)
{
this.Close();
}
That's tops the previous snippet. You have no idea what's going wrong when that runs. And your code will try to use a closed port. Just delete the statements, it does nothing but harm.
Do not close the ports until your program ends. SerialPort uses a background thread to watch for events on the port, that thread needs to shutdown after the Close() call before you can open the port again. How long it takes to shutdown is unpredictable, it could be seconds worst case. There's no point in closing the port, it isn't going to be useful to anything else.
You need to use SetCommTimeouts (not sure what the .NET wrapper is, I gave up on the .NET serial classes long ago and call the Win32 API directly) to force the USB/serial converter to send the data back to your program.
By default it may try to collect a block equal in size to a USB transfer block, for efficiency.
Its tough to tell exactly what the problem might be without see some of the code. My guess would be that you are not waiting long enough for the COM port to close after reopening it. Note from the SerialPort.Close page, that:
The best practice for any application is to wait for some amount of time after calling the Close method before attempting to call the Open method, as the port may not be closed instantly.
Can you just open the COM ports and leave them open until you are done? For example from this post:
using (SerialPort serialPort = new SerialPort("COM1", 9600))
{
serialPort.Open();
while (true)
{
Thread.Sleep(1000);
// serialPort.Write();
Thread.Sleep(1000);
// serialPort.Read();
// break at some point to end
}
serialPort.Close();
}