I have a scale that connect to PC through RS232, I send "W" to receive the weight. The scale sends the weight all the time as it's read. How do I catch the weight that is being read?
Can i get any C# sample code?
Sending a W? Sounds like the Mettler Toledo scale that FedEx gives businesses. I happen to have some code that reads from such a scale:
// where this.port is an instance of SerialPort, ie
// this.port = new SerialPort(
// portName,
// 1200,
// Parity.None,
// 8,
// StopBits.One);
// this.port.Open();
protected override bool GetWeight(out decimal weightLB, out bool stable)
{
stable = false;
weightLB = 0;
try
{
string data;
this.port.Write("W\r\n");
Thread.Sleep(500);
data = this.port.ReadExisting();
if (data == null || data.Length < 12 || data.Substring(8, 2) != "LB")
{
return false;
}
if (decimal.TryParse(data.Substring(1, 7), out weightLB))
{
stable = (data[11] == '0');
return true;
}
}
catch (TimeoutException)
{
return false;
}
return false;
}
You need to use SerialPort component of .NET. The full description and examples are available on MSDN site: http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.aspx
Related
My dotnet/c# server is running very well for my Unity game on my local machine.
But when I host it on an online cloud server (AWS EC2 instance) it will result in not all TCP messages arriving at the client side.
Server side method:
git: github.com/IRiViI/TCPmreServer
public void SendData(Packet _packet)
{
try
{
if (socket != null)
{
stream.BeginWrite(_packet.ToArray(), 0, _packet.Length(), null, null);
}
}
catch (Exception _ex)
{
Console.WriteLine($"Error sending data to player {id} via TCP: {_ex}");
}
}
Client side method:git: github.com/IRiViI/TCPmreClient
private void ReceiveCallback(IAsyncResult _result){
try {
int _byteLength = stream.EndRead(_result);
if (_byteLength <= 0){
client.Disconnect();
return;
}
byte[] _data = new byte[_byteLength];
Array.Copy(receiveBuffer, _data, _byteLength);
receivedData.Reset(HandleData(_data));
stream.BeginRead(receiveBuffer, 0, dataBufferSize, ReceiveCallback, null);
} catch(Exception _ex) {
Disconnect();
Debug.Log(_ex);
}
}
private bool HandleData(byte[] _data){
int _packetLength = 0;
receivedData.SetBytes(_data);
if(receivedData.UnreadLength() >= 4){
_packetLength = receivedData.ReadInt();
if (_packetLength <= 0){
return true;
}
}
while (_packetLength > 0 && _packetLength <= receivedData.UnreadLength()){
byte[] _packetBytes = receivedData.ReadBytes(_packetLength);
ThreadManager.ExecuteOnMainThread(() => {
using (Packet _packet = new Packet(_packetBytes)){
int _packetId = _packet.ReadInt();
client.packetHandlers[_packetId](_packet);
}
});
_packetLength = 0;
if(receivedData.UnreadLength() >= 4){
_packetLength = receivedData.ReadInt();
if (_packetLength <= 0){
return true;
}
}
}
if (_packetLength <= 1){
return true;
}
return false;
}
It only happens when I send many (100+) messages at the same time. below 100 it usally goes well.
I think the issue might be AWS related (firewall and such). But I would expect to get some error messages when a TCP message could not be send. I'm not able to find any errors. I would have expect this behaviour of UDP but not of TCP.
My question is: How can I increase the amount of messages that can be send or have some message not received callback inorder to handle failed TCP messages.
Update --
The problem seems to be on the client side. I tested my server code on my server at home and the same problem occures as when running my server code on an EC2 AWS instance.
The problem occures when there are multiple tcp packets handled.
At the moment when the tcp handler breaks, I get a packetsLength of 16777216 (which equals 2^24).
if(receivedData.UnreadLength() >= 4){
_packetLength = receivedData.ReadInt();
if (_packetLength <= 0){
return true;
}
Console.WriteLine($"_{_packetLength}");
}
I have a system in which I read the serial port from a X,Y,Z motion stage, meaning that I send a signal (via usb) to a function which reads the signal, moves a stepper motor accordingly, then reads the next stepper motor signal and so on. At the moment, this function looks like this:
public void SCPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
string sCurString = "";
//Loop to receive the data from serial port
System.Threading.Thread.Sleep(150);
sCurString = SCPort.ReadExisting();
if (sCurString != "")
StrReceiver = sCurString;
if (BlnSet == true)
{
if (StrReceiver.Length == 3)
{
if (StrReceiver.Substring(StrReceiver.Length - 3) == "OK\n")
BlnReadCom = true;
}
else if (StrReceiver.Length == 4)
{
if (StrReceiver.Substring(StrReceiver.Length - 3) == "OK\n" || StrReceiver.Substring(StrReceiver.Length - 4) == "OK\nS")
BlnReadCom = true;
}
else
{
if (StrReceiver.Substring(StrReceiver.Length - 3) == "OK\n" || StrReceiver.Substring(StrReceiver.Length - 4) == "OK\nS" ||
StrReceiver.Substring(StrReceiver.Length - 5) == "ERR1\n" || StrReceiver.Substring(StrReceiver.Length - 5) == "ERR3\n" ||
StrReceiver.Substring(StrReceiver.Length - 5) == "ERR4\n" || StrReceiver.Substring(StrReceiver.Length - 5) == "ERR5\n")
BlnReadCom = true;
}
}
else
{
if (StrReceiver.Substring(StrReceiver.Length - 1, 1) == "\n")
BlnReadCom = true;
}
}
catch (Exception ex)
{
MessageBox.Show("Failed to receive data", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
This function reads the serialport SCPort, every 150ms indicated by the Thread.Sleep. If I try to read the data any faster, I get the exception (which is likely an indication of the limitation of my system). Fine. However, this exception is not thrown immediately, but every once in a while. What I would like to do instead of waiting a fixed time between reading the signal, is to each time wait until the serialport is ready and then read it. This should speed up my system, as instead of waiting 150ms between every movement, I could wait exactly the amount of time the system requires.
The question is: how do I implement this behavior in the function?
I have not tried to solve it on my own, because I really have no idea about how to do this. Will be happy to implement this into my function, but at a bare minimum I need to be pointed in the right direction.
This function handles connection to the port SCPort.
public void ConnectPort(short sPort)
{
if (SCPort.IsOpen == true)
{
ClosePort();
buttonConnectStage.Text = "Connect stage";
}
else if (SCPort.IsOpen == false)
{
SCPort.PortName = comStage.SelectedItem.ToString(); //Set the serial port number
SCPort.BaudRate = 9600; //Set the bit rate
SCPort.DataBits = 8; //Set the data bits
SCPort.StopBits = StopBits.One; //Set the stop bit
SCPort.Parity = Parity.None; //Set the Parity
SCPort.ReadBufferSize = 2048;
SCPort.WriteBufferSize = 1024;
SCPort.DtrEnable = true;
SCPort.Handshake = Handshake.None;
SCPort.ReceivedBytesThreshold = 1;
SCPort.RtsEnable = false;
//This delegate should be a trigger event for fetching data asynchronously, it will be triggered when there is data passed from serial port.
SCPort.DataReceived += new SerialDataReceivedEventHandler(SCPort_DataReceived); //DataReceivedEvent delegate
try
{
SCPort.Open(); //Open serial port
if (SCPort.IsOpen)
{
StrReceiver = "";
BlnBusy = true;
BlnSet = false;
SendCommand("?R\r"); //Connect to the controller
Delay(250);
BlnBusy = false;
if (StrReceiver == "?R\rOK\n")
{
displayValues();
BlnConnect = true; //Connected successfully
ShrPort = sPort; //Setial port number
buttonConnectStage.Text = "Disconnect stage";
SendCommand("V" + sSpeed.ToString() + "\r"); //Set speed
}
else
{
BlnBusy = false;
BlnConnect = false;
buttonConnectStage.Text = "Failed to connect";
MessageBox.Show("Failed to connect", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
}
}
catch (Exception ex)
{
}
}
}
I have a method which opens a serial port, reads some data into an array, and then closes the port again. This method can be called up to 20 times per second but I feel this may be ineffective.
The method can be called from multiple windows forms and locations.
class COMPortStream
{
private static readonly string COM = Properties.Settings.Default.COMPort;
public static SerialPort ForcePort = new SerialPort(COM, 19200, Parity.None, 8, StopBits.One);
public double N2P(double N)
{
double lbf = N * 0.224809;
return lbf;
}
public string[] GetLoads()
{
try
{
if (!ForcePort.IsOpen) { ForcePort.Open(); }
string buffer = ForcePort.ReadTo("\r") ;
string message = ForcePort.ReadTo("\r");
string[] arr = message.Split('N');
ForcePort.Close();
for( int i =0;i<2;i++)
{
double ld = N2P(Convert.ToDouble(arr[i]));
arr[i] = ld.ToString("N1");
}
return arr;
}
catch (TimeoutException)
{
ForcePort.Close();
return null;
}
catch(InvalidOperationException ex)
{
ForcePort.Close();
return null;
}
catch(SystemException)
{
ForcePort.Close();
return null;
}
}
The above works but I feel it is inefficient. What I would like is a method / function which is continually reading the stream regardless of which form is showing - almost like a background worker for the entire program. This would save the numbers into a public array and other forms/functions would query this instead.
Maybe I am a little bad at telling whats going on but I will try my best (sorry about my english).
Arduino code:
//Setup message bytes
byte inputByte_0;
byte inputByte_1;
byte inputByte_2;
int pin = 9;
void setup()
{
Serial.begin(9600);
}
void loop() {
if (Serial.available()> 2)
{
inputByte_0 = Serial.read();delay(10);
inputByte_1 = Serial.read();delay(10);
inputByte_2 = Serial.read();delay(10);
}
//Check for start of Message
if(inputByte_0 == 4)
{
//Detect Command type
switch (inputByte_1)
{
case 8://Set Port Identification Number, this case is only to find the correct port in order to connect.
switch (inputByte_2)
{
case 16:
Serial.print("I'M ARDUINO");
break;
case 32:
Serial.print(digitalRead(x)); // Here I send via serial the value of x pin. 1/0 and receive in C# as a String. The "receiving" is handled by a class named "communicator" which I show it below.
break;
}
}
//Clear Message bytes
inputByte_0 = 0;
inputByte_1 = 0;
inputByte_2 = 0;
}
}
So here is the class "communicator" which gets the messages from Arduino.
namespace testtemp
{
public class communicator
{
public string port = "";
static SerialPort currentPort;
public Boolean connect(int baud, string recognizeText, byte paramone, byte paramtwo, byte paramthree)
{
try
{
byte[] buffer = new byte[3];
buffer[0] = Convert.ToByte(paramone);
buffer[1] = Convert.ToByte(paramtwo);
buffer[2] = Convert.ToByte(paramthree);
int intReturnASCII = 0;
char charReturnValue = (Char)intReturnASCII;
string[] ports = SerialPort.GetPortNames();
foreach (string newport in ports)
{
currentPort = new SerialPort(newport, baud);
currentPort.Open();
currentPort.Write(buffer, 0, 3);
Thread.Sleep(200);
int count = currentPort.BytesToRead;
string returnMessage = ""; // Here I see that the message is a STRING so I wonder what is wrong.
while (count > 0)
{
intReturnASCII = currentPort.ReadByte();
returnMessage = returnMessage + Convert.ToChar(intReturnASCII);
count--;
}
currentPort.Close();
port = newport;
if (returnMessage.Contains(recognizeText))
{
return true;
}
}
return false;
}
catch (Exception e)
{
return false;
}
}
public string message(byte paramone, byte paramtwo, byte paramthree)
{
try
{
byte[] buffer = new byte[3];
buffer[0] = Convert.ToByte(paramone);
buffer[1] = Convert.ToByte(paramtwo);
buffer[2] = Convert.ToByte(paramthree);
currentPort.Open();
currentPort.Write(buffer, 0, 3);
int intReturnASCII = 0;
char charReturnValue = (Char)intReturnASCII;
Thread.Sleep(200);
int count = currentPort.BytesToRead;
string returnMessage = "";
while (count > 0)
{
intReturnASCII = currentPort.ReadByte();
returnMessage = returnMessage + Convert.ToChar(intReturnASCII);
count--;
}
currentPort.Close();
return returnMessage;
}
catch (Exception e)
{
return "Error";
}}}}
And now I have the main class where I want to use that value from Arduino, the value from x pin. That value is provided by a call of the function: comport.message(4,8,32);
This is the code:
namespace testtemp
{
public partial class tempreaderform : Form
{
public tempreaderform()
{
InitializeComponent();
}
communicator comport = new communicator();
Boolean portConnection = false;
Int32 red_light1;
private void button1_Click(object sender, EventArgs e)
{
if (comport.connect(9600, "I'M ARDUINO", 4, 8, 16))
{
label1.Text = "Connection Successful - Connected to "+comport.port;
portConnection = true;
tempreader.Start();
}
else
{
label1.Text = "Not connected . . . ";
portConnection = false;
tempreader.Stop();
}
}
private void tempreader_Tick(object sender, EventArgs e)// Here I have a timer that is called every 100ms to read that
{
red_light1 = Convert.ToInt32(comport.message(4, 8, 32));// Here I get this error:"when converting a string to datetime parse the string to take the date before putting each variable"
I have nothing to do with datetime type. I don't understand why I get this error.
label3.Text = comport.message(4, 8, 32); When I put that value in a label everything works fine. I see that value oscilating from 0 to 1 and viceversa.
// Here I have a timer that is called every 100ms to read that value.
}
private void groupBox1_Paint(object sender, PaintEventArgs e)
{
Graphics rectangle1 = groupBox1.CreateGraphics();
Graphics ellipse1 = groupBox1.CreateGraphics();
Brush color = new SolidBrush(Color.DimGray);
Brush red_on = new SolidBrush(Color.Red);
Brush red_off = new SolidBrush(Color.DarkRed);
Pen pen = new Pen(Color.Black, 3);
if (label3.Text == "1")
{
ellipse1.FillEllipse(red_on, 123, 78, 24, 24);
}
else ellipse1.FillEllipse(red_off, 123, 78, 24, 24);
// Here I want to color an ellipse depending on the value of red_light1 and doesn't work because I never see "red_light1" as true.
}}}
I am sorry for long question and maybe is not the best explained question. I reply as fast as I can if somebody doesn't understand something in my question/code.
In
red_light1 = Convert.ToInt32(comport.message(4, 8, 32));
method comport.message() returns a string which is then converted into an integer. This works when the string is e.g. "123", but your Arduino sketch is passing binary data (see Convert.ToChar(intReturnASCII)). Byte codes 48 to 57 map to the decimal numbers 0 to 9 and can be converted. Other byte codes however cannot be converted to an integer.
In other words, Convert.ToInt32("123") works, but Convert.ToInt32("abc") does not work.
When you are looking for an easy way to communicate with Arduino boards from Windows devices, I suggest taking a look at SolidSoils4Arduino. It's a library supporting serial, Firmata and I2C communication. It also offers methods to automatically find serial port connections and it has support for Mono too.
I am beginning to suspect that the error lies here:
returnMessage = returnMessage + Convert.ToChar(intReturnASCII);
Why do you convert To char here? That can have side effects if intReturnAscII is not what you'd expect. Also, your returnMessage is a string, so treat it as one. Use
returnMessage = returnMessage + intReturnASCII.ToString();
instead.
Also this:
int intReturnASCII = 0;
char charReturnValue = (Char)intReturnASCII;
is completely unnecessary as you never do a thing with charReturnValue. You just assign NULL and then let it linger.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
I have developed one application in which i am polling the serial port(sending request and getting response) every after 5 sec. everything was working very fine and i tested it thoroughly.
but when i introduced threading i get the blue screen error regarding physical memory or something as attached below in threading i just separated GUI updating task and polling task.
can anyone suggest me what should i do to remove the same, just stuck and not understanding what to do.
This is happening every time i run the application, i am using profic driver serial to usb driver.
MAIN APPLICATION CODE
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
PollingAllMeters();
}
public void PollingAllMeters()
{
int isdbError = 0;
PollingUtility.MeterClass mData = new PollingUtility.MeterClass();
for (int index = 0; index < m_slaveID.Length; index++)
{
try
{
mData = poll.MeterOne(m_slaveID[index]);
Thread processData = new Thread(() => this.updateData(data));
processData.Start();
}
catch { MessageBox.Show("Inside polling box");
}
}
private void updateData(MeterValues data)
{
mainFormRef.updateData(data);
}
DLL CODE IN WHICH ACTUAL REQUEST AND RESPONSE ARE HAPPENING
enter code here
public MeterClass MeterOne(byte meterID)
{
MeterClass data1 = new MeterClass();
//Voltage
mb.SendFc3(meterID, startAdd, register, ref value_meter); //modbus call is made here for sending and receiving response at serial port
if (mb.modbusStatus == "Read successful")
{
//do some calculation
}
else
{
// error handling code to create log file
if (mb.modbusStatus == "Error in read event")
{
isPollError = 21;
}
else if (mb.modbusStatus == "CRC error")
{
isPollError = 22;
}
else if (mb.modbusStatus == "Serial port not open")
{
isPollError = 23;
}
}
startAdd = 360;
register = 2;
value_meter = new byte[register * 2];
meterData = new byte[register * 2];
//Max demand
mb.SendFc3(meterID, startAdd, register, ref value_meter);
if (mb.modbusStatus == "Read successful")
{
//do some calculation
}
else
{
// error handling code to create log file
if (mb.modbusStatus == "Error in read event")
{
isPollError = 21;
}
else if (mb.modbusStatus == "CRC error")
{
isPollError = 22;
}
else if (mb.modbusStatus == "Serial port not open")
{
isPollError = 23;
}
}
startAdd = 496;
register = 16;
value_meter = new byte[register * 2];
meterData = new byte[register * 2];
mb.SendFc3(meterID, startAdd, register, ref value_meter);
if (mb.modbusStatus == "Read successful")
{
//do some calcualtion
}
else
{
// error handling code to create log file
if (mb.modbusStatus == "Error in read event")
{
isPollError = 21;
}
else if (mb.modbusStatus == "CRC error")
{
isPollError = 22;
}
else if (mb.modbusStatus == "Serial port not open")
{
isPollError = 23;
}
}
data1.date = DateTime.Now;
data1.Status = isPollError;
return data1; // return result to the main program
}
USB and BlueTooth device drivers that emulate a serial port are notoriously unreliable. It is a cut-throat business that doesn't leave a lot money to pay a good programmer a decent wage, I guess. The only thing you can do about it if you can't get a driver update is to destroy the thing so it stops making your life miserable. Take it out to the parking lot and run over it with your car a couple of times.
Do take a good look at your code before you spin up the engine. "Multi-threading" is a red flag, the driver is oblivious to your program using more than one thread. Avoid a scenario where you can call Read or Write simultaneously from more than one thread. A driver should always be resilient to that but this doesn't get put to the test very often. Rejigger the code if necessary so only a single thread ever reads or writes or use the lock statement.