0

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

  • The following may be helpful: https://stackoverflow.com/questions/65957066/serial-to-usb-cable-from-a-scale-to-pc-some-values-are-just-question-marks/65971845#65971845 – Tu deschizi eu inchid Dec 21 '21 at 23:19
  • I tried converting to ascii and sending the write command one byte at a time as suggested in the link provided above and that did not resolve the issue. – Michael Hunsaker Dec 22 '21 at 00:02
  • Having the correct serial port settings is important. I haven't looked for the documentation for your serial port device, but did you try the serial port settings that were used in the post? – Tu deschizi eu inchid Dec 22 '21 at 00:08
  • Is there a model number for the scale? – Tu deschizi eu inchid Dec 22 '21 at 00:27
  • 1
    The following may be helpful: https://www.mt.com/us/en/home/applications/industrial_weighing/data_communication.html#publications – Tu deschizi eu inchid Dec 22 '21 at 00:29
  • I have added an image of the print head although the default settings in putty are working so I do not think it is an issue of compatibility. – Michael Hunsaker Jan 04 '22 at 16:50
  • I have also submitted a request to Mettler Toledo through the link @user9938 suggested. – Michael Hunsaker Jan 04 '22 at 16:58
  • Looks like some resources for the 420 Plus are [here](https://www.ricelake.com/products/420-plus-digital-weight-indicator-discontinued/) and the manual: [420 Plus HMI Digital Weight Indicator Installation Manual](https://www.ricelake.com/media/3ewalrag/m_us_85127_420plus_install_revc.pdf) – Tu deschizi eu inchid Jan 04 '22 at 17:30
  • I used that documentation to get the correct command "KPRINT" for the scale head already I have unfortunately not gotten much else from it. Mostly all I need to know is what Putty is doing and I am not to obtain a response where I am not. – Michael Hunsaker Jan 04 '22 at 18:34
  • If you haven't already done so, I suggest reading the entire manual. You'll need to ensure that the cables are connected properly. Then check/set the appropriate settings as outlined in the documentation. Also according to the manual, for `TERMIN` (termination character) there are two choices `CRLF` (default) or `CR`. See this [post](https://stackoverflow.com/questions/1552749/difference-between-cr-lf-lf-and-cr-line-break-types) for more information on what those mean. – Tu deschizi eu inchid Jan 04 '22 at 19:04
  • You'll want to set [SerialPort.NewLine](https://learn.microsoft.com/en-us/dotnet/api/system.io.ports.serialport.newline?view=netframework-4.8) to the appropriate value `CRLF` or `CR` - _the default is a line feed ("\n" in C#)_ – Tu deschizi eu inchid Jan 04 '22 at 19:05
  • Right I am now getting a ?? back in response which means something is wrong with how I am sending the command A mettler Toledo rep told me that I should try sending the ASCII character P instead of kprint is that different than doing a port.writeline("P")? – Michael Hunsaker Jan 05 '22 at 17:29
  • I have also tried it in the hexval conversion way now as suggested earlier it is also not working displays the same as before. – Michael Hunsaker Jan 05 '22 at 17:34

1 Answers1

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-CimInstance -Namespace Root\Cimv2 -Query "Select * From Win32_SerialPort Where Name like '%COM%'"
  • Get-CimInstance -Namespace Root\Cimv2 -Query "Select * From Win32_SerialPortConfiguration"
  • Get-CimInstance -Namespace Root\Cimv2 -Query "Select * From Win32_PnPEntity where PnPClass = 'Ports' and Name like '%COM%'"
  • mode

Resources:

Tu deschizi eu inchid
  • 4,117
  • 3
  • 13
  • 24
  • All of the `data == ` comparisons are wrong, the newline can be read together with other data in a single `ReadExisting` call. There are numerous other issues with this code and the `SerialPort` methods it uses which may cause it to behave erratically. Do away with the events and use `await` and async reads from the `BaseStream` member of `SerialPort`. – Ben Voigt Jan 07 '22 at 20:23
  • @BenVoigt: Thanks for the feedback. I've modified some of the code, but I'm not sure what you mean by _Do away with the events and use await and async reads from the BaseStream member of SerialPort_ or if I know how to do that. – Tu deschizi eu inchid Jan 07 '22 at 21:27
  • Changing all other setting other than dtr or flow control seems to prevent it from sending properly other than when on the settings you and I are both using. However the dtr and flow control settings don't appear to be having an effect on input or output. – Michael Hunsaker Jan 11 '22 at 20:40
  • I just found some information [here](https://batchloaf.wordpress.com/2013/02/12/simple-trick-for-sending-characters-to-a-serial-port-in-windows/). It looks like one can find the settings that were last used on the serial port by doing the following: Connect to your device using PuTTY. Then disconnect. Then open a "cmd" window and type "mode". It will show the settings last used for the COM port. – Tu deschizi eu inchid Jan 11 '22 at 21:44
  • I've updated, "SerialCmdSend", you can give it a try and see if it makes any difference. – Tu deschizi eu inchid Jan 11 '22 at 23:14
  • The following may be helpful: https://www.aggsoft.com/scale-balance/mettler-toledo-scale.htm – Tu deschizi eu inchid Jan 12 '22 at 16:26
  • I tried the modified section and have had no change in what I recieve. – Michael Hunsaker Jan 12 '22 at 18:32
  • Try subscribing to the SerialPort `PinChanged` event and see if the event is triggered by placing `Debug.WriteLine("ScalePort_PinChanged - " + e.EventType.ToString());` in the event handler. – Tu deschizi eu inchid Jan 12 '22 at 19:07
  • The command may be case-sensitive. According to page 39 (35 in lower right corner of page), _"If the command is unrecognized or cannot be executed, the indicator responds with `??`"_. Therefore, it seems that the command is probably be received. However, it doesn't understand the command because it wasn't properly sent (ie: the wrong command was sent or the format was incorrect). – Tu deschizi eu inchid Jan 12 '22 at 20:00
  • Try the following: `byte[] bytesToSend = new byte[] { 0x16, 0x50, 0x0D }; ScalePort.Write(bytesToSend, 0, bytesToSend.Length);` – Tu deschizi eu inchid Jan 13 '22 at 02:49
  • The following may be helpful [Bidirectional Data Interface](http://www.dragon.lv/exafs/equipment/704018_2_12.pdf) - starting on p. 74 it discusses the varying Handshake protocols and the associated control characters. – Tu deschizi eu inchid Jan 13 '22 at 15:46
  • I am now getting one good reply every time I open putty first get a good reply from them which is after one bad. Then I open the port in my software and it will work once and only once. That is while using the simple send command ScalePort.WriteLine(settings[19]); – Michael Hunsaker Feb 17 '22 at 18:43
  • It appears setting this is making it work consistently: ScalePort.NewLine = "\r"; – Michael Hunsaker Feb 17 '22 at 18:53