We are trying to connect to a truck weighing scale on a custom developed form that reads weight from scale and shows on screen in a continuous manner.
Before I attempted implementation in X++, I did a proof of concept (poc) with a normal C# project. The basic code of connection and reading data is as follows:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO.Ports; using Microsoft.VisualBasic; using System.Text.RegularExpressions; namespace WeightScaleReader { public partial class Form1 : Form { // Temp Strings String stor; String stor2; // String used to receive Com port data String buffer; private SerialPort _serialPort; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { } private void startButton_Click(object sender, EventArgs e) { //Check if Serial Port is already open if (_serialPort != null && _serialPort.IsOpen) _serialPort.Close(); if (_serialPort != null) _serialPort.Dispose(); //Initialize serial port with hard coded settings. Later settings will be transfered to settings file _serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One); // Add event handler when ever data is received in COM port _serialPort.DataReceived += SerialPortOnDataReceived; _serialPort.Open(); messageBox.Text = "Listening on " + _serialPort.PortName + "...\r\n"; } private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs) { try { this.buffer = this._serialPort.ReadLine(); // printing reading to text box to see nature of data. useful for parsing received data messageBox.Text += buffer+"\r\n"; this.Invoke((Delegate)new MethodInvoker(this.Display)); } catch (Exception ex) { messageBox.Text += "Error " + ex.Message; MessageBox.Show(ex.Message); } } private void Display() { try { this.stor = buffer; buffer = ""; // Parsing recieved data to extract the weight this.stor2 = Regex.Replace(this.stor.Trim(), "[^0-9]", ""); comData.Text += stor2; } catch (Exception e) { messageBox.Text += " ... ERROR ... \r\n"; } } } }
The above code is working fine.
Next step I transferred the code with logic to a AX form as follows.
private void initilaizeComPort() { try{ if(serialPort!=null && serialPort.get_IsOpen()) { serialPort.Close(); } if(serialPort!=null) { serialPort.Dispose(); } serialPort = new System.IO.Ports.SerialPort("COM1",9600,System.IO.Ports.Parity::None,8,System.IO.Ports.StopBits::One); portEventHandler = new ManagedEventHandler(this,"serialPortEventHandler"); serialPort.add_DataReceived(portEventHandler); serialPort.Open(); comPortConnected = true; } catch { comPortConnected = false; } if(comPortConnected){ info("Com Connection Successful"); } else{ info("Com Connection Failed"); } }
public void serialPortEventHandler(Object object, System.IO.Ports.SerialDataReceivedEventArgs e) { System.String buffer = null; info("Data Received"); buffer = serialPort.ReadLine(); info(buffer); scaleReading = System.Text.RegularExpressions.Regex::Replace(buffer.Trim(),"[^0-9]",""); info(scaleReading); // Setting scale reading to gauge control digiG.set_Text(scaleReading); }
The initilaizeComPort method is called in the init method of the form. The connection is successful, however when data is received the AX client crashes. The code within the handler never runs.
Just to make sure that com port is sending data and I can read and parse I did the following
private void tickTime() { buffer = null; buffer = serialPort.ReadLine(); info(buffer); scaleReading = System.Text.RegularExpressions.Regex::Replace(buffer.Trim(),"[^0-9]",""); info(scaleReading); digiG.set_Text(scaleReading); timerHandler = this.setTimeOut(identifierstr(tickTime),200,false);*/ }
I placed the code in a ticktime method which calls it self after a time out. The first call to this method is made right after the initilaizeComPort method in init method
public void init() { super(); this.initilaizeComPort(); this.tickTime(); }
Once form was run, the reading started to come on screen changing continuously, how ever the values were delayed and sometimes in correct. This is due to the frequency in which our code is reading the data and the actual throw-put of COM port is different. This is why I feel that event handler must be used.
After some searching I understood that I have to use a delegate which will take the event hanlder as a parameter, but I do not quite understand how to do that. Also if I create a delegate in AOT how will I pass that delegate to add_DataRecieved method in serial port.
I feel the solution is simple but cannot wrap my head around it.
*This post is locked for comments