Get scale weight over serial from Mettler Toledo Rice Lake scale

Trying to recieve weight when requested via command over serial from a Mettler Toledo Rice Lake scale. Before anything else it works fine if I use putty to send the command; it returns properly the currently displayed weight on the print head this is in essence all I want to accomplish from these functions.

Here is my code at the moment although I have tried quite a lot of variations:

On form load it will fix variables associated with the port to follow settings that are set elsewhere in the software. This appears to work properly and does in many other parts of the software.

settings: 12: COM1 13: 9600 16: none 17: 8 18: One 19: kprint

private void Get_Weight_Load(object sender, EventArgs e)
        {
            string path11 = File.ReadAllText(Application.StartupPath + @"\ConfigurationPathFile.txt") + @"\GeneralSettings.txt";
            path11 = path11.Replace("\r", "").Replace("\n", "");
            string[] settings = File.ReadAllText(path11).Split(',');

            LoadResources();
            #region Scale
            ScalePort.PortName = settings[12];
            ScalePort.BaudRate = Int32.Parse(settings[13]);
            ScalePort.Handshake = Handshake.RequestToSend; // This is one thing I have been changing in order to try and fix the problem.
            switch (settings[16])
            {
                case "None":
                    ScalePort.Parity = System.IO.Ports.Parity.None;
                    break;
                case "Odd":
                    ScalePort.Parity = System.IO.Ports.Parity.Odd;
                    break;
                case "Even":
                    ScalePort.Parity = System.IO.Ports.Parity.Even;
                    break;
                case "Mark":
                    ScalePort.Parity = System.IO.Ports.Parity.Mark;
                    break;
                case "Space":
                    ScalePort.Parity = System.IO.Ports.Parity.Space;
                    break;
            }
            ScalePort.DataBits = Int32.Parse(settings[17]);
            switch (settings[18])
            {
                case "None":
                    ScalePort.StopBits = System.IO.Ports.StopBits.None;
                    break;
                case "One":
                    ScalePort.StopBits = System.IO.Ports.StopBits.One;
                    break;
                case "Two":
                    ScalePort.StopBits = System.IO.Ports.StopBits.Two;
                    break;
                case "OnePointFive":
                    ScalePort.StopBits = System.IO.Ports.StopBits.OnePointFive;
                    break;
            }
            try
            {
                ScalePort.Open();
                ScalePort.WriteLine(settings[19]);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Contact your system admin if you are seeing this message" + System.Environment.NewLine + ex.ToString());
            }
            #endregion
        }

On form close:

private void Get_Weight_FormClosed(object sender, FormClosedEventArgs 
{
     if (ScalePort.IsOpen)
        { ScalePort.Close(); }
}

and the ScalePort Data received event handler:

 private void ScalePort_DataReceived(object sender, SerialDataReceivedEventArgs e)
 {
      Thread.Sleep(30);
      SerialPort sp = (SerialPort)sender;
      string indata = sp.ReadExisting();
      textBox1.AppendText(indata + System.Environment.NewLine);
      //MessageBox.Show(indata);
 }

When this runs all I recieve in the textbox1 is the command I send which in this case is kprint.

So to make it clear what my question is; What am I doing wrong that is preventing me from receiving the weight or, am I sending the command wrong and if so how do I do it properly?

This is an image of the print head:enter image description here

I got the inline serial port reader and this is the logs i generated my software on the left putty on the right. Each of the tests on my software are separate attempts with the port opened and closed between each attempt. enter image description here

I adjusted my settings based on the mode cmd command suggested below afterward I used the mode command again I only have one thing I can not seem to change which is the timeout to off, which is set to infinite -1 on both read and wright. There was no change in result after doing this. Here is the two images After Putty right side after software left side: enter image description here


Solution 1:

According to the documentation, there are two choices for the termination character: CRLF (default) or CR, so you'll need to set the SerialPort.NewLine value as appropriate. It's also important that the other SerialPort properties are set to the same values that they are on the serial port device that you're using. The procedure to get/set the values can be found in the documentation.

The code below has been tested using a serial port device I have (not a scale). However, it's usefulness with your scale may vary and depends upon the serial port properties matching the properties set for the scale. I've also set some of the serial port property values based on information from the documentation for your scale.

Try the following:

Add the following using statements:

using System.IO.Ports;
using System.Diagnostics;

Enums:

public enum TerminationCharacterType
{
    CRLF,
    CR
};

public enum PortBaudRate : int
{
    Baud300 = 300,
    Baud600 = 600,
    Baud1200 = 1200,
    Baud2400 = 2400,
    Baud4800 = 4800,
    Baud9600 = 9600,
    Baud19200 = 19200,
    Baud38400 = 38400
};

Note: You stated that you had used PuTTY, and that it seemed to work. After installing PuTTY, I noticed that the following values are set:

  • Baud: 9600
  • Data bits: 8
  • Stop bits: 1
  • Parity: None
  • Flow control: XON/XOFF

In the code below, I've used the following settings:

  • ScalePort.Handshake = Handshake.XOnXOff;
  • ScalePort.DtrEnable = true;

If the settings don't work, you might try:

  • ScalePort.Handshake = Handshake.None;
  • ScalePort.DtrEnable = false;

Connect:

public System.IO.Ports.SerialPort ScalePort { get; private set; } = null;
private string _dataReceived = string.Empty;
private TerminationCharacterType _termin = TerminationCharacterType.CRLF;

public string Connect(string comPort, TerminationCharacterType termin = TerminationCharacterType.CRLF, PortBaudRate baudRate = PortBaudRate.Baud9600)
{
    //create new instance
    ScalePort = new SerialPort(comPort);

    //set properties
    ScalePort.BaudRate = (int)baudRate;
    ScalePort.Handshake = Handshake.XOnXOff; //Handshake.None or Handshake.XOnXOff 
    ScalePort.DtrEnable = true; //enable Data Terminal Ready - set true for Handshake.RequestToSend, Handshake.RequestToSendXOnXOff, or Handshake.XOnXOff
    ScalePort.RtsEnable = false; //enable Request to send - set true for Handshake.RequestToSend or Handshake.RequestToSendXOnXOff

    //if Parity.None is used, then use DataBits = 8
    //if Parity.Even or Parity.Odd is used, then use DataBits = 7
    ScalePort.Parity = Parity.None; //Even,None,Odd supported; default: Parity.None
    ScalePort.DataBits = 8; //default: 8

    //set value
    _termin = termin;

    if (termin == TerminationCharacterType.CR)
        ScalePort.NewLine = "\r"; //CR: \r
    else
        ScalePort.NewLine = "\r\n"; // CRLF: \r\n; this is the default

    ScalePort.StopBits = StopBits.One; //1 or 2 supported; default: 1
    ScalePort.ReadTimeout = 200; //num ms before a time-out occurs
    ScalePort.ReadBufferSize = 4096; //default is 4096; max value is 2147483647
    ScalePort.ReceivedBytesThreshold = 1; //default is 1; num bytes before DataReceived event occurs
    ScalePort.WriteBufferSize = 2048; //default is 2048
    ScalePort.WriteTimeout = 50; //num ms before a time-out occurs

    //subscribe to events
    ScalePort.DataReceived += ScalePort_DataReceived;
    ScalePort.ErrorReceived += ScalePort_ErrorReceived;

    //open port
    ScalePort.Open();
}

private void ScalePort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    SerialPort sp = (SerialPort)sender;

    if (e.EventType != SerialData.Chars)
        return;

    //read data
    //string data = sp.ReadExisting();

    //System.Threading.Thread.Sleep(25);
    string data = sp.ReadLine();

    Debug.WriteLine("data: " + data);
}

private void ScalePort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
{
    Debug.WriteLine("Error - " + e.ToString());
}

Note: SerialPort.ReadLine may also work. If you use it, this post may be useful.

To send data:

public void SerialCmdSend(string data, bool sendAsString = true)
{
    if (ScalePort.IsOpen && !String.IsNullOrEmpty(data))
    {
        //ToDo: see if the following works, if not comment it out
        //For testing, try to prepend STX (hex: 02; Ctrl-B)
        data = "\x02" + data.Trim();

        if (_termin == TerminationCharacterType.CRLF)
            data = data.Trim() + "\r\n"; //append CRLF
        else if (_termin == TerminationCharacterType.CR)
            data = data.Trim() + "\r"; //append CR

        if (sendAsString)
        {
            //ScalePort.WriteLine(data);
            ScalePort.Write(data);
        }
        else
        {
            // Send the binary data out the port
            byte[] hexstring = Encoding.ASCII.GetBytes(data);

            foreach (byte hexval in hexstring)
            {
                byte[] _hexval = new byte[] { hexval }; // need to convert byte to byte[] to write
                ScalePort.Write(_hexval, 0, 1);
                //System.Threading.Thread.Sleep(1);
            }
        }
    }
}

Since I don't have the scale that you're using, the following is untested:

Write Displayed Weight:

//write current displayed weight with units identifier
//SerialCmdSend("P", false);
SerialCmdSend("P", true);

List all parameter values:

//list all parameter values
SerialCmdSend("DUMPALL");

Transmit Net Weight:

//transmit net weight in displayed units
SerialCmdSend("XN");

According to the documentation, "An EOL may be required for continuous transmission at slower baud rates to ensure the receiving buffer is empty before another string is transmitted.".

You may also want to look at the STREAM setting options which "...selects the serial port used for continuous transmission".

Update:

Here's some additional info that may be useful:

Open PowerShell and run the following:

  • Get-WmiObject -Class Win32_SerialPort
  • Get-WmiObject -Class Win32_SerialPortConfiguration
  • Get-WmiObject -Class Win32_PnPEntity -filter "Name LIKE '%(com%)%'"
  • mode

Resources:

  • 420 Plus HMI Digital Weight Indicator Installation Manual
  • System.IO.Ports Namespace
  • SerialPort Class
  • SerialPort.NewLine
  • SerialPort.ReadExisting
  • SerialPort.ReadLine
  • DTREnable
  • Handshake
  • Handshake Enum
  • How to update a RichTextBox from BackgroundWorker using BeginInvoke
  • Serial port communication issue in WPF using VSPE
  • I need SerialPort event on NewLine received
  • C# Async Serial Port Read
  • Communicating With Serial Port In C#
  • PowerShell - Get-WmiObject
  • PowerShell - LIKE operator