I'm trying to convert TCL code, used to communicate with a serial port to a "robot", to C#. But for some reason my commands are not getting responses.
This is the serial com init in TCL:
proc openUart {} {
set robot::fd_ [open COM${robot::port_num}: w+]
fconfigure $robot::fd_ -mode 9600,e,7,1
fconfigure $robot::fd_ -blocking 0
fconfigure $robot::fd_ -buffering none
fileevent $robot::fd_ readable ""
}
A "command" is sent like this:
proc SendCmd {command} {
set commandlen [string length $command]
for {set i 0} {$i < $commandlen} {incr i} {
set letter [string index $command $i]
after 10
puts -nonewline $robot::fd_ $letter
}
after [expr 2 * 10]
puts -nonewline $robot::fd_ "\n"
flush $robot::fd_
}
This is how I translated this to C#. Opening the port:
private void Initialize(string com)
{
_comPort = new SerialPort(com,9600,Parity.Even,7,StopBits.One)
{
Encoding = Encoding.ASCII,
NewLine = "\n"
};
_comPort.Open();
}
And sending a command:
private string SendCommand(Commands cmd)
{
string commandToWrite = Command(cmd);
for (int i = 0; i < CommandLen; i++)
{
Thread.Sleep(10);
_comPort.Write(commandToWrite.ToCharArray(), i, 1);
}
Thread.Sleep(10 * 2);
_comPort.Write("\n");
_comPort.BaseStream.Flush();
}
I connected my PC to the robot with a serial to USB cable and ran both TCL and C# programs -
The TCL script turns on a LED on the robot.
My C# code doesn't turn the LED on, meaning the robot did not recognize the command.
I'm using the same com port, so I believe the problem is one of these:
I did not initialize the com port correctly in C#. How do you set the blocking and buffering?
Could there be an encoding issue in C#? isn't ASCII the default encoding in TCL?
Could there be a timing difference in how I'm sending the command letter-by-letter between the two languages?
Issue resolved!
I finally looped back the cable into my PC using another serial cable and 2 blue wires, crossing the RX\TX (thanks don_q for the idea!).
Using a simple serial monitor, "UART Terminal", I sniffed the commands, and to my surprise the TCL script was adding a '\r' before the '\n'!
So in fact the robot was expecting this command format -
:010508010000F1\r\n
I changed the NewLine property in C# to be "\r\n", and now I finish a command by using -
_comPort.WriteLine("");
And now everything works.
Related
I'm trying to get a tow-way communication between a c# application and a python script that c# will call.
I have some input channels in c# that changes constantly at high frequency (5000-1000 data/s) for let's say a minute. On every change of those inputs,results are calculated and assigned to output variables. What i'm trying to do is to move the logic to a python script. For instance:
Inputs: double x,y
Output: double z
So the pyhton script should be capable of read the inputs, perform the logic and write the results at a symilar frequency.
Any recomendations? Has anyone did anything similar before?
First I tried to call the script on every change and read the console output. But the code in the script is not as simple as z=x*y and variables that store values are required in the pyhon script. For example, the script mught want to save the maximum value of x and y reached.
I had a look to ZeroMQ library for the communication, not sure how to use it though.
Here is a solution:
Simple C# program: client which sends data and receive
using System;
using ZeroMQ;
namespace ZeroMQ_Client
{
class Program
{
static void Main(string[] args)
{
using (var requester = new ZSocket(ZSocketType.REQ))
{
// Connect
requester.Connect("tcp://127.0.0.1:5555");
for (int n = 0; n < 10; ++n)
{
string requestText = "Hello";
Console.Write("Sending {0}...", requestText);
// Send
requester.Send(new ZFrame(requestText));
// Receive
using (ZFrame reply = requester.ReceiveFrame())
{
Console.WriteLine(" Received: {0} {1}!", requestText, reply.ReadString());
}
}
}
}
}
}
python program, you have to install pyzmq:
#
# Hello World server in Python
# Binds REP socket to tcp://*:5555
# Expects b"Hello" from client, replies with b"World"
#
import time
import zmq
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:5555")
while True:
# Wait for next request from client
message = socket.recv()
print("Received request: %s" % message)
# Do some 'work'
time.sleep(1)
# Send reply back to client
socket.send(b"World")
I´d like to stream a text file containing G-Code to an Arduino UNO via the serialPort.
The Arduino receives all bytes with the SerialEvent and adds it to a char array named buffer. If the buffer is full it is supposed to send an "!;" over the serial port to C#.
This works fine as I have tested it with the Serial Montior application of the Arduino IDE. But I can´t type text as fast as C# can send it :)
The C# program reads the G-Code file linewise and then sends each char in a line to the arduino. After each char I want to check if the Arduino tells me if the buffer is full. Otherwise keep streaming.
Somehow c# never notices the "!;" or even gets any Bytes to read from the Arduino while streaming. I have the feeling that the serialPort.Write() function blocks the port.
This is the Arduino Code:
void serialEvent()
{
// wenn im Puffer noch platz ist
if (buffercount < MAX_BUF)
{
char c = (char)Serial.read();
buffer[buffercount++] = c;
}
else
{
Serial.print("!;");
}
}
The serialEvent is fired every time the Arduino receives bytes on the port.
Max_BUF has a value of 64.
This is the C# Code:
private void startStreaming(string Text)
{
string[] stringSeparators;
string Text2Stream;
if (Text == "")
{
Text2Stream = File.ReadAllText(textBoxSelectFile.Text);
stringSeparators = new string[] { "\n" };
}
else
{
stringSeparators = new string[] { "\r\n" };
Text2Stream = Text;
}
string[] t2s = Text2Stream.Split(stringSeparators, StringSplitOptions.None);
foreach (string zeile in t2s)
{
if (zeile.Contains(")") || zeile.Contains("("))
{
continue;
}
// Code schicken
foreach (char c in zeile)
{
if (c == ' ') continue;
serialPort.Write(c.ToString());
if (serialPort.BytesToRead > 0)
{
if(serialPort.ReadExisting() == "!;")
{
**wait and do smth.**
}
}
}
serialPort.Write(";");
addTextToLog(zeile);
}
}
serialPort.ReadExisiting() never happens because there are never BytesToRead.
The ";" is for both the sign for the end of a line.
startStreaming is started in an asynchronous thread as BackGroundWorker.
Somehow c# never notices the "!;" or even gets any Bytes to read from the Arduino while streaming. I have the feeling that the serialPort.Write() function blocks the port.
The Write command is not blocking the port. The arduino is just much slower then your computer. So between these two lines:
serialPort.Write(c.ToString());
if (serialPort.BytesToRead > 0)
the arduino is occupied and no data is received yet. Therefore BytesToRead is 0. Two possibilities to solve that come right away to my mind.
1) Use the serialPort.DataReceived event for asynchronous processing. This will be triggered every time you receive data. Then you can react upon the received data in that event or
2) Just give the arduino some time with System.Threading.Thread.Sleep(1000);
serialPort.Write(c.ToString());
System.Threading.Thread.Sleep(1000);
if (serialPort.BytesToRead > 0)
You need to find out which is the minimum timespan to wait.
I have a very strange issue, which has been driving me mad for the last two days.
I have a serial device (LS 100 Photometer) which I am trying to control. Using a terminal (termite) set up with the correct parameters, I can send the command ("MES"), followed by the delimeter (CR LF), and I get back some measurement data as expected.
The problem is, from Qt, I do not get any data returned. Using a sniffer program, I have confirmed that I am sending the exact same 5 bytes (MES CR LF) as the terminal is sending, and with the same port setup.
If I change the flow control to "NoFlowControl" then I can get some data back, but it appears to be meaningless and is just one random byte. In any case the device documentation says to use RTS/CTS and that is what the terminal (termite) is set up to use.
Also, if I use the Qt serialport example terminal, I get the same issue where I can't get the device to return data. I have also tried using C# and have had the exact same issue. The only thing that seems capable of communicating with the instrument is the Termite terminal.
Qt Code:
port.setPortName(ui->cmbPort->currentText());
port.setBaudRate(QSerialPort::Baud4800);
port.setDataBits(QSerialPort::Data7);
port.setParity(QSerialPort::EvenParity);
port.setStopBits(QSerialPort::TwoStop);
port.setFlowControl(QSerialPort::HardwareControl);
if (!port.open(QIODevice::ReadWrite))
{
connected = false;
QMessageBox::information(this, "Failed To Open", "Failed to open the serial port");
ui->statusBar->showMessage("Connection to " + ui->cmbPort->currentText() + " failed...");
}
else
{
connected = true;
ui->statusBar->showMessage("Connected to " + ui->cmbPort->currentText() + "...");
}
QByteArray cmdB;
cmdB[0] = 0x4d;
cmdB[1] = 0x45;
cmdB[2] = 0x53;
cmdB[3] = 0x0d;
cmdB[4] = 0x0a;
qint64 r = port.write(cmdB.data(), cmdB.size());
qDebug() << "Written: " << r;
Then the ReadData function which is called on ReadyRead or every 100ms:
QByteArray data = port.readAll();
if (data.count() != 0)
{
qDebug() << "Read " << data.size() << " bytes";
QString str = QString(data);
ui->txtOutput->append(str);
}
Any help would be much appreciated, I'm running out of hair to pull out...
Finally worked it out.
Even though the documentation says to use RTS/CTS, and the terminal program (termite) uses RTS/CTS, the solution was to turn off flow control in the Qt application (i.e. NoFlowControl), then turn on the RTS line manually just before sending data, like this:
port.setRequestToSend(true);
qint64 r = port.write(cmdB.data(), cmdB.size());
port.waitForBytesWritten(5000);
qDebug() << "Written: " << r;
I developed an in-browser Silverlight application that consist in a button. When it pressed it open a Socket to send ZPL commands to a Zebra Printer (model RZ400).
I made all the required actions to allow in-browser app to open connection to other hosts.
The printer works well except that it print only a limited number of labels (27) even if the socket send right all the data to the printer (that consist in 48 labels, about 440 bytes each).
To be sure, I check the buffer size of the socket that is 65536 bytes. The amount of data that I send to the printer through the socket is only 21282 bytes.
foreach (Label l in args.Labels)
{
saea = new SocketAsyncEventArgs();
printCommand = GetPrintCommandFromLabelAndPRN(l, args.SelectedPrinter.prn);
buffer = Encoding.UTF8.GetBytes(printCommand);
saea.SetBuffer(buffer, 0, buffer.Length);
willRaiseEvent = args.ConnectionSocket.SendAsync(saea);
totBytes += buffer.Length;
Log("Pack " + l.data + " inviato al socket di stampa");
}
The method GetPrintCommandFromLabelAndPRN build the PRN command for a single label:
private string GetPrintCommandFromLabelAndPRN(Label l, string prn)
{
// Codice e RFID
string aux = prn.Replace("{code}", l.code).Replace("{epc}", l.data);
// Meta
foreach (labelMeta meta in l.meta)
{
if (meta.key != null && !meta.key.Equals(String.Empty))
{
aux = aux.Replace("{" + meta.key + "}", meta.value);
}
}
return aux;
}
And this is the PRN template:
^XA
~SD25
^FO10,70^XGE:LOGO.GRF,1,1^FS
^FT275,65^A0N,29,28^FH\^FDArticolo:^FS
^FT375,65^A0N,29,28^FH\^FD{code}^FS
^FT509,65^A0N,25,24^FH\^FD{description1}^FS
^FT275,99^A0N,25,24^FH\^FD{description2}^FS
^BY2,3,57^FT275,166^BCN,50,Y,N,N^FD>:{code}^FS
^FT50,225^A0N,29,28^FH\^FDLotto:^FS
^BY2,3,35^FT130,225^BCN,30,Y,N,N^FD>:{lotCode}^FS
^PQ1,0,1,Y
^RR2
^RS8,300,50,2,N
^RW20,20
^RFW,H
^FD{epc}^FS
~RVE
^XZ
I try to do the same in Java, with the same PRN, using PrintWriter and it works correctly. So I exclude that is a printer issue.
I would bet that the printer is queuing up your labels and that is what causes it to stop at 27. Have you tried sending one at a time just to test to see if you might need to let the printer 'catch up' with the print jobs you are sending? We used to have an issue similar to this - when we slowed down the loop to the printer it allowed the printer to work at it's own rate just fine, but labels came out at a slower rate.
I am trying to run a treadmill using the serial port, I was able to do it using matlab however I am having a few probelms when I ported the same code to C#. I am sure that the port is open there is probably something wrong with the message format. Would be great if someone can tell me what mistake I am making.The matlab code (which works) and the C# code (which doesn't work) are given below.
MATLAB CODE :
ctr = char(12); %control character
rel = char(169); %release
set_speed = char(163);
set_dir = char (184);
%initializing the ports
R = serial('COM4');
set(R, 'BaudRate', 4800, 'Parity', 'none', 'DataBits', 8, 'StopBits', 1, 'Terminator', 'CR');
set(R, 'InputBufferSize', 128, 'OutputBufferSize', 128);
fopen(R);
if R.status == 'open'
fprintf(R, [rel ctr]);
disp('port for R belt open and released');
else
disp('error with R port-- COM3');
end;
%initial direction to FORWARD
fprintf(R, [set_dir '0' char(12)]);
%set speed to
fprintf(R, [set_speed '0005' ctr]);
My C# version of the matlab code above
char ctr = (char)12;
char rel = (char)169; //release
char set_speed = (char)163;
char set_dir = (char)184;
void Start () {
try{
SerialPort R = new SerialPort();
R.BaudRate = 4800;
R.Parity = Parity.None;
R.DataBits = 8;
R.StopBits = StopBits.One;
R.ReadBufferSize = 128;
R.WriteBufferSize = 128;
R.Open();
if(R.IsOpen){
//Release
R.Write(rel+""+ctr);
print ("Serial port is open");
}
else print ("Serial port is close");
R.Write(set_dir+""+"0"+""+ctr);
R.Write(set_speed+""+"0005"+""+ctr);
}
catch(UnityException e){
print ("Exception");
print (e);
}
}
I'm not really familiar with C#, but I'll try to guess that you should also send terminator character in your C# code.
Check the fprintf (serial) documentation in MatLab:
fprintf(obj,'cmd') writes the string cmd to the device connected to the serial port object, obj. The default format is %s\n. The write operation is synchronous and blocks the command-line until execution completes.
fprintf(obj,'format','cmd') writes the string using the format specified by format.
In your calls you are using 1st syntax so your call
fprintf(R, [rel ctr]);
is actually
fprintf(R, '%s\n', [rel ctr]);
Usually, serial devices read input data until the terminator character is found. This means that transmission of the command string or data is completed and the device now can execute the command. This is much like hitting ENTER in MatLab command window: command is executed only after you do this.
Which terminator character to use should be specified in your device programming manual.
Seems that CR is OK since your MatLab code works.
In your MatLAb code you set the terminator to be CR character (ASCII code 13). I do not see this in your C# code so your device waits for CR which is not sent so there should be no reaction from your device.
I do not think that C# will send the terminator character for you, you should take care of it by yourself.
My guess is that
R.Write(rel+""+ctr + "\r");
should solve the problem (thanks dodald for reminding me that I missed the proper conclusion).
See also Terminator property of SERIAL object and Rules for Writing the Terminator.