Closed amit-tomar-github closed 3 years ago
I think this is off-topic issue because source of this issue is not related to this project. Anyway, your problem is you are trying to process asynchronous data synchronously. Sample is sufficient for 1 controller but no for 3.
Btw, your modifications like in OpenProtocolDriver constructor:
typeof(Mid0002), //Added by me
are not necessary because this list of MIDs to parse. MID 0002 (EDIT: sorry, I mean MID 0001, MID 0002 is response and this change is ok) is "your" MID meaning this is something you sent to controller and in this case it's not necassary parse it.
I sligtly modified your code to work with 3 controllers: (sorry, I can't attach it to this comment because " Something went really wrong, and we can’t process that file." and I don't know why)
using OpenProtocolInterpreter.Sample.Driver;
using OpenProtocolInterpreter.Sample.Driver.Events;
using System;
using System.Windows.Forms;
using OpenProtocolInterpreter.Sample.Driver.Helpers;
using OpenProtocolInterpreter.KeepAlive;
using System.Drawing;
using OpenProtocolInterpreter.Tightening;
using OpenProtocolInterpreter.Communication;
using OpenProtocolInterpreter.Job;
using OpenProtocolInterpreter.Sample.Driver.Commands;
using System.Threading.Tasks;
using OpenProtocolInterpreter.Sample.Ethernet;
using Timer = System.Threading.Timer;
namespace OpenProtocolInterpreter.Sample
{
public partial class DriverForm : Form
{
private Timer keepAliveTimerPort1, keepAliveTimerPort2, keepAliveTimerPort3;
private OpenProtocolDriver driverPort1, driverPort2, driverPort3;
private string IP1, IP2, IP3;
private int port1, port2, port3;
public DriverForm()
{
InitializeComponent();
keepAliveTimerPort1 = new System.Threading.Timer(KeepAliveTimerPort1_Elapsed, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
keepAliveTimerPort2 = new System.Threading.Timer(KeepAliveTimerPort2_Elapsed, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
keepAliveTimerPort3 = new System.Threading.Timer(KeepAliveTimerPort3_Elapsed, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
}
private void KeepAliveTimerPort1_Elapsed(object sender)
{
if (driverPort1.KeepAlive.ElapsedMilliseconds > 10000) //10 sec
{
Log.Information($"Sending Keep Alive For Port 9001...");
var pack = driverPort1.SendAndWaitForResponse(new Mid9999().Pack(), TimeSpan.FromSeconds(10));
if (pack != null && pack.HeaderData.Mid == Mid9999.MID)
{
lastMessageArrived.Text = Mid9999.MID.ToString();
Log.Information($"Keep Alive Received For Port 9001 - Pack {pack}");
}
else
{
Log.Information($"Keep Alive Not Received For Port 9001");
}
}
}
private void KeepAliveTimerPort2_Elapsed(object sender)
{
if (driverPort2.KeepAlive.ElapsedMilliseconds > 10000) //10 sec
{
Log.Information($"Sending Keep Alive For Port 9002...");
var pack = driverPort2.SendAndWaitForResponse(new Mid9999().Pack(), TimeSpan.FromSeconds(10));
if (pack != null && pack.HeaderData.Mid == Mid9999.MID)
{
lastMessageArrived.Text = Mid9999.MID.ToString();
Log.Information($"Keep Alive Received For Port 9002- Pack {pack}");
}
else
{
Log.Information($"Keep Alive Not Received For Port 9002");
}
}
}
private void KeepAliveTimerPort3_Elapsed(object sender)
{
if (driverPort3.KeepAlive.ElapsedMilliseconds > 10000) //10 sec
{
Log.Information($"Sending Keep Alive For Port 9003...");
var pack = driverPort3.SendAndWaitForResponse(new Mid9999().Pack(), TimeSpan.FromSeconds(10));
if (pack != null && pack.HeaderData.Mid == Mid9999.MID)
{
lastMessageArrived.Text = Mid9999.MID.ToString();
Log.Information($"Keep Alive Received For Port 9003 - Pack {pack}");
}
else
{
Log.Information($"Keep Alive Not Received For Port 9003");
}
}
}
private void BtnConnection_Click(object sender, EventArgs e)
{
//Added list of mids i want to use in my interpreter, every another will be desconsidered
driverPort1 = new OpenProtocolDriver(new Type[]
{
typeof(Mid0001),
typeof(Mid0002), //Added by me
typeof(Mid0005),
typeof(Mid0004),
typeof(Mid0003),
typeof(ParameterSet.Mid0010), //Added by me
typeof(ParameterSet.Mid0011),
typeof(ParameterSet.Mid0013),
typeof(Mid0035),
typeof(Mid0031),
typeof(Alarm.Mid0071),
typeof(Alarm.Mid0074),
typeof(Alarm.Mid0076),
typeof(Vin.Mid0052),
typeof(Mid0061),
typeof(Mid0062),//added by me
typeof(Mid0065),
typeof(Time.Mid0081),
typeof(Mid9999)
});
Log.Information($"Communicating to Port 9001");
SimpleTcpClient client1 = null;
Task.Run(() =>
{
client1 = new Ethernet.SimpleTcpClient().Connect(IP1, port1);
if (driverPort1.BeginCommunication(client1))
{
keepAliveTimerPort1.Change(2000, 2000);
this.Invoke(new Action(() =>
{
connectionStatus.Text = "Connected!";
connectionStatus.BackColor = Color.Green;
}));
Log.Information($"Connected to Port 9001");
}
else
{
driverPort1 = null;
this.Invoke(new Action(() =>
{
connectionStatus.Text = "Disconnected!";
connectionStatus.BackColor = Color.Red;
}));
Log.Information($"DisConnected to Port 9001");
}
});
//for Port 2
driverPort2 = new OpenProtocolDriver(new Type[]
{
typeof(Mid0001),
typeof(Mid0002), //Added by me
typeof(Mid0005),
typeof(Mid0004),
typeof(Mid0003),
typeof(ParameterSet.Mid0010), //Added by me
typeof(ParameterSet.Mid0011),
typeof(ParameterSet.Mid0013),
typeof(Mid0035),
typeof(Mid0031),
typeof(Alarm.Mid0071),
typeof(Alarm.Mid0074),
typeof(Alarm.Mid0076),
typeof(Vin.Mid0052),
typeof(Mid0061),
typeof(Mid0062),//added by me
typeof(Mid0065),
typeof(Time.Mid0081),
typeof(Mid9999)
});
Log.Information($"Communicating to Port 9002");
SimpleTcpClient client2 = null;
Task.Run(() =>
{
client2 = new Ethernet.SimpleTcpClient().Connect(IP2, port2);
if (driverPort2.BeginCommunication(client2))
{
keepAliveTimerPort2.Change(2000, 2000);
//connectionStatus.Text = "Connected!";
//connectionStatus.BackColor = Color.Green;
Log.Information($"Connected to Port 9002");
}
else
{
driverPort2 = null;
//connectionStatus.Text = "Disconnected!";
//connectionStatus.BackColor = Color.Red;
Log.Information($"DisConnected to Port 9002");
}
});
//for Port 3
driverPort3 = new OpenProtocolDriver(new Type[]
{
typeof(Mid0001),
typeof(Mid0002), //Added by me
typeof(Mid0005),
typeof(Mid0004),
typeof(Mid0003),
typeof(ParameterSet.Mid0010), //Added by me
typeof(ParameterSet.Mid0011),
typeof(ParameterSet.Mid0013),
typeof(Mid0035),
typeof(Mid0031),
typeof(Alarm.Mid0071),
typeof(Alarm.Mid0074),
typeof(Alarm.Mid0076),
typeof(Vin.Mid0052),
typeof(Mid0061),
typeof(Mid0062),//added by me
typeof(Mid0065),
typeof(Time.Mid0081),
typeof(Mid9999)
});
Log.Information($"Communicating to Port 9003");
SimpleTcpClient client3 = null;
Task.Run(() =>
{
client3 = new Ethernet.SimpleTcpClient().Connect(IP3, port3);
if (driverPort3.BeginCommunication(client3))
{
keepAliveTimerPort3.Change(2000, 2000);
//connectionStatus.Text = "Connected!";
//connectionStatus.BackColor = Color.Green;
Log.Information($"Connected to Port 9003");
}
else
{
driverPort3 = null;
//connectionStatus.Text = "Disconnected!";
//connectionStatus.BackColor = Color.Red;
Log.Information($"DisConnected to Port 9003");
}
});
}
/// <summary>
/// Job info subscribe
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnJobInfoSubscribe_Click(object sender, EventArgs e)
{
Log.Information($"Sending Job Info Subscribe...");
var pack = driverPort1.SendAndWaitForResponse(new Mid0034().Pack(), TimeSpan.FromSeconds(10));
if (pack != null)
{
if (pack.HeaderData.Mid == Mid0004.MID)
{
var mid04 = pack as Mid0004;
Log.Information($@"Error while subscribing (MID 0004):
Error Code: <{mid04.ErrorCode}>
Failed MID: <{mid04.FailedMid}>");
}
else
Log.Information($"Job Info Subscribe accepted!");
}
driverPort1.AddUpdateOnReceivedCommand(typeof(Mid0035), OnJobInfoReceived);
}
/// <summary>
/// Tightening subscribe
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnTighteningSubscribe_Click(object sender, EventArgs e)
{
Log.Information($"Sending Tightening Subscribe For Port 9001...");
// var pack = driver.SendAndWaitForResponse(new Mid0060().Pack(), TimeSpan.FromSeconds(10));
/*changing default revision no from 7 to 1*/
int Revision = txtRevision.Text.Trim() == "" ? 1 : int.Parse(txtRevision.Text.Trim());
var pack = driverPort1.SendAndWaitForResponse(new Mid0060(Revision).Pack(), TimeSpan.FromSeconds(10));
if (pack != null)
{
if (pack.HeaderData.Mid == Mid0004.MID)
{
var mid04 = pack as Mid0004;
Log.Information($@"Error while subscribing (MID 0004):
Error Code: <{mid04.ErrorCode}>
Failed MID: <{mid04.FailedMid}>");
}
else
{
Log.Information($"Tightening Subscribe accepted!");
lblManualMidResult.Text = $"Tightening Response:{pack.HeaderData}";
}
}
//register command
driverPort1.AddUpdateOnReceivedCommand(typeof(Mid0061), OnTighteningReceived1);
//Port2
Log.Information($"Sending Tightening Subscribe For Port 9002...");
// var pack = driver.SendAndWaitForResponse(new Mid0060().Pack(), TimeSpan.FromSeconds(10));
/*changing default revision no from 7 to 1*/
var pack2 = driverPort2.SendAndWaitForResponse(new Mid0060(1).Pack(), TimeSpan.FromSeconds(10));
// var pack = driver.SendAndWaitForResponse(new ParameterSet.Mid0010(Revision).Pack(), TimeSpan.FromSeconds(10));
if (pack2 != null)
{
if (pack2.HeaderData.Mid == Mid0004.MID)
{
var mid04 = pack2 as Mid0004;
Log.Information($@"Error while subscribing (MID 0004):
Error Code: <{mid04.ErrorCode}>
Failed MID: <{mid04.FailedMid}>");
}
else
{
Log.Information($"Tightening Subscribe accepted!");
lblManualMidResult.Text = $"Tightening Response:{pack.HeaderData}";
}
}
//register command
driverPort2.AddUpdateOnReceivedCommand(typeof(Mid0061), OnTighteningReceived2);
//Port3
Log.Information($"Sending Tightening Subscribe For Port 9003...");
// var pack = driver.SendAndWaitForResponse(new Mid0060().Pack(), TimeSpan.FromSeconds(10));
/*changing default revision no from 7 to 1*/
var pack3 = driverPort3.SendAndWaitForResponse(new Mid0060(1).Pack(), TimeSpan.FromSeconds(10));
// var pack = driver.SendAndWaitForResponse(new ParameterSet.Mid0010(Revision).Pack(), TimeSpan.FromSeconds(10));
if (pack3 != null)
{
if (pack3.HeaderData.Mid == Mid0004.MID)
{
var mid04 = pack3 as Mid0004;
Log.Information($@"Error while subscribing (MID 0004):
Error Code: <{mid04.ErrorCode}>
Failed MID: <{mid04.FailedMid}>");
}
else
{
Log.Information($"Tightening Subscribe accepted!");
lblManualMidResult.Text = $"Tightening Response:{pack.HeaderData}";
}
}
//register command
driverPort3.AddUpdateOnReceivedCommand(typeof(Mid0061), OnTighteningReceived3);
}
private void BtnSendJob_Click(object sender, EventArgs e)
{
new SendJobCommand(driverPort1).Execute((int)numericJob.Value);
}
/// <summary>
/// Async method from controller, MID 0035 (Job Info)
/// </summary>
/// <param name="e"></param>
private void OnJobInfoReceived(MIDIncome e)
{
driverPort1.SendMessage(e.Mid.BuildAckPackage());
var jobInfo = e.Mid as Mid0035;
lastMessageArrived.Text = Mid0035.MID.ToString();
Log.Information($@"JOB INFO RECEIVED (MID 0035):
Job ID: <{jobInfo.JobId}>
Job Status: <{(int)jobInfo.JobStatus}> ({jobInfo.JobStatus.ToString()})
Job Batch Mode: <{(int)jobInfo.JobBatchMode}> ({jobInfo.JobBatchMode.ToString()})
Job Batch Size: <{jobInfo.JobBatchSize}>
Job Batch Counter: <{jobInfo.JobBatchCounter}>
TimeStamp: <{jobInfo.TimeStamp.ToString("yyyy-MM-dd:HH:mm:ss")}>");
}
/// <summary>
/// Async method from controller, MID 0061 (Last Tightening)
/// Basically, on every tightening this method will be called!
/// </summary>
/// <param name="e"></param>
private void OnTighteningReceived1(MIDIncome e)
{
Log.Information("Tightening Data Received For Port 9001");
// lblManualMidResult.Text = "Tightening Data Received";
driverPort1.SendMessage(e.Mid.BuildAckPackage());
var tighteningMid = e.Mid as Mid0061;
lastMessageArrived.Text = Mid0061.MID.ToString();
Log.Information($@"TIGHTENING RECEIVED For Port 9001 (MID 0061):
Cell ID: <{tighteningMid.CellId}>
Channel ID: <{tighteningMid.ChannelId}>
Torque Controller Name: <{tighteningMid.TorqueControllerName}>
VIN Number: <{tighteningMid.VinNumber}>
Job ID: <{tighteningMid.JobId}>
Parameter Set ID: <{tighteningMid.ParameterSetId}>
Batch Size: <{tighteningMid.BatchSize}>
Batch Counter: <{tighteningMid.BatchCounter}>
Tightening Status: <{tighteningMid.TighteningStatus}>
Torque Status: <{(int)tighteningMid.TorqueStatus}> ({tighteningMid.TorqueStatus.ToString()})
Angle Status: <{(int)tighteningMid.AngleStatus}> ({tighteningMid.AngleStatus.ToString()})
Torque Min Limit: <{tighteningMid.TorqueMinLimit}>
Torque Max Limit: <{tighteningMid.TorqueMaxLimit}>
Torque Final Target: <{tighteningMid.TorqueFinalTarget}>
Torque: <{tighteningMid.Torque}>
Angle Min Limit: <{tighteningMid.AngleMinLimit}>
Angle Max Limit: <{tighteningMid.AngleMaxLimit}>
Final Angle Target: <{tighteningMid.AngleFinalTarget}>
Angle: <{tighteningMid.Angle}>
TimeStamp: <{tighteningMid.Timestamp.ToString("yyyy-MM-dd:HH:mm:ss")}>
Last Change In Parameter Set: <{tighteningMid.LastChangeInParameterSet.ToString("yyyy-MM-dd:HH:mm:ss")}>
Batch Status: <{(int)tighteningMid.BatchStatus}> ({tighteningMid.BatchStatus.ToString()})
TighteningID: <{tighteningMid.TighteningId}>");
}
private void OnTighteningReceived2(MIDIncome e)
{
Log.Information("Tightening Data Received For Port 9002");
// lblManualMidResult.Text = "Tightening Data Received";
driverPort2.SendMessage(e.Mid.BuildAckPackage());
var tighteningMid = e.Mid as Mid0061;
lastMessageArrived.Text = Mid0061.MID.ToString();
Log.Information($@"TIGHTENING RECEIVED For Port 9002 (MID 0061):
Cell ID: <{tighteningMid.CellId}>
Channel ID: <{tighteningMid.ChannelId}>
Torque Controller Name: <{tighteningMid.TorqueControllerName}>
VIN Number: <{tighteningMid.VinNumber}>
Job ID: <{tighteningMid.JobId}>
Parameter Set ID: <{tighteningMid.ParameterSetId}>
Batch Size: <{tighteningMid.BatchSize}>
Batch Counter: <{tighteningMid.BatchCounter}>
Tightening Status: <{tighteningMid.TighteningStatus}>
Torque Status: <{(int)tighteningMid.TorqueStatus}> ({tighteningMid.TorqueStatus.ToString()})
Angle Status: <{(int)tighteningMid.AngleStatus}> ({tighteningMid.AngleStatus.ToString()})
Torque Min Limit: <{tighteningMid.TorqueMinLimit}>
Torque Max Limit: <{tighteningMid.TorqueMaxLimit}>
Torque Final Target: <{tighteningMid.TorqueFinalTarget}>
Torque: <{tighteningMid.Torque}>
Angle Min Limit: <{tighteningMid.AngleMinLimit}>
Angle Max Limit: <{tighteningMid.AngleMaxLimit}>
Final Angle Target: <{tighteningMid.AngleFinalTarget}>
Angle: <{tighteningMid.Angle}>
TimeStamp: <{tighteningMid.Timestamp.ToString("yyyy-MM-dd:HH:mm:ss")}>
Last Change In Parameter Set: <{tighteningMid.LastChangeInParameterSet.ToString("yyyy-MM-dd:HH:mm:ss")}>
Batch Status: <{(int)tighteningMid.BatchStatus}> ({tighteningMid.BatchStatus.ToString()})
TighteningID: <{tighteningMid.TighteningId}>");
}
private void OnTighteningReceived3(MIDIncome e)
{
Log.Information("Tightening Data Received For Port 9003");
// lblManualMidResult.Text = "Tightening Data Received";
driverPort3.SendMessage(e.Mid.BuildAckPackage());
var tighteningMid = e.Mid as Mid0061;
lastMessageArrived.Text = Mid0061.MID.ToString();
Log.Information($@"TIGHTENING RECEIVED For Port 9003 (MID 0061):
Cell ID: <{tighteningMid.CellId}>
Channel ID: <{tighteningMid.ChannelId}>
Torque Controller Name: <{tighteningMid.TorqueControllerName}>
VIN Number: <{tighteningMid.VinNumber}>
Job ID: <{tighteningMid.JobId}>
Parameter Set ID: <{tighteningMid.ParameterSetId}>
Batch Size: <{tighteningMid.BatchSize}>
Batch Counter: <{tighteningMid.BatchCounter}>
Tightening Status: <{tighteningMid.TighteningStatus}>
Torque Status: <{(int)tighteningMid.TorqueStatus}> ({tighteningMid.TorqueStatus.ToString()})
Angle Status: <{(int)tighteningMid.AngleStatus}> ({tighteningMid.AngleStatus.ToString()})
Torque Min Limit: <{tighteningMid.TorqueMinLimit}>
Torque Max Limit: <{tighteningMid.TorqueMaxLimit}>
Torque Final Target: <{tighteningMid.TorqueFinalTarget}>
Torque: <{tighteningMid.Torque}>
Angle Min Limit: <{tighteningMid.AngleMinLimit}>
Angle Max Limit: <{tighteningMid.AngleMaxLimit}>
Final Angle Target: <{tighteningMid.AngleFinalTarget}>
Angle: <{tighteningMid.Angle}>
TimeStamp: <{tighteningMid.Timestamp.ToString("yyyy-MM-dd:HH:mm:ss")}>
Last Change In Parameter Set: <{tighteningMid.LastChangeInParameterSet.ToString("yyyy-MM-dd:HH:mm:ss")}>
Batch Status: <{(int)tighteningMid.BatchStatus}> ({tighteningMid.BatchStatus.ToString()})
TighteningID: <{tighteningMid.TighteningId}>");
}
private void BtnSendProduct_Click(object sender, EventArgs e)
{
new DownloadProductCommand(driverPort1).Execute(txtProduct.Text);
}
private void BtnAbortJob_Click(object sender, EventArgs e)
{
new AbortJobCommand(driverPort1).Execute();
}
private void DriverForm_Load(object sender, EventArgs e)
{
Log.Information("App started");
}
private void btnManualMid_Click(object sender, EventArgs e)
{
Log.Information($"Sending Manual Mid...");
lblManualMidResult.Text = $"Sending {txtManualMid.Text}";
var pack = driverPort1.SendAndWaitForResponse(txtManualMid.Text.Trim(), TimeSpan.FromSeconds(10));
lblManualMidResult.Text = $"Response {pack}";
if (pack != null)
{
if (pack.HeaderData.Mid == Mid0004.MID)
{
var mid04 = pack as Mid0004;
Log.Information($@"Error while subscribing (MID 0004):
Error Code: <{mid04.ErrorCode}>
Failed MID: <{mid04.FailedMid}>");
}
else
Log.Information($"Manual Mid Response Without error {pack} && Mid {pack.HeaderData.Mid}");
}
else
Log.Information($"Manual Mid Response {pack}-null");
}
private void DriverForm_FormClosing(object sender, FormClosingEventArgs e)
{
Log.Information("Closing App");
}
}
}
Hi, Thank you for your time and feedback. I will use this code, But I was short on time for this project so I figured out there is MID0100 and MID0101 for multispindle so I am using this MID in my project. But I am having one problem with that sometimes I am getting a message in the log that keep alive not received and then I never got the data again. So what I am doing on keepalive timer I am reconnecting to the controller(calling btnConnect) event. I don't know why this happening. Even though I will change in that code too according to this code then will see how it will work..BY THE WAY, THANK YOU AGAIN
You are welcome, let me know result :) There is bug in MID 0100 and I forgot to report it. Constant LAST_REVISION has value 4 but this revision isn't defined and flag "sendOnlyNewData" wasn't implemented at all. Anyway, "Send only new data" is for revision 3+ and I can test MID 0100 on 2 PF4000 controllers and one PF6000 and each controller can use only MID 0100 with revision 1 so I think this flag is useless (for now).
Here is modified code:
using OpenProtocolInterpreter.Converters;
using System.Collections.Generic;
namespace OpenProtocolInterpreter.MultiSpindle
{
/// <summary>
/// Multi-spindle result subscribe
/// <para>
/// A subscription for the multi-spindle status. For Power Focus, the subscription must
/// be addressed to a sync Master.
/// </para>
/// <para>
/// This telegram is also used for a PowerMACS 4000 system
/// running a press instead of a spindle. A press system only supports revision 4 and higher
/// of the telegram and will answer with <see cref="Communication.Mid0004"/>, MID revision unsupported if a subscription
/// is made with a lower revision.
/// </para>
/// <para>Message sent by: Integrator</para>
/// <para>
/// Answer: <see cref="Communication.Mid0005"/> Command accepted or
/// <see cref="Communication.Mid0004"/> Command error, Controller is not a sync master/station controller,
/// Multi-spindle result subscription already exists or MID revision unsupported
/// </para>
/// </summary>
public class Mid0100 : Mid, IMultiSpindle, IIntegrator
{
private readonly IValueConverter<long> _longConverter;
private readonly IValueConverter<bool> _boolConverter;
private const int LAST_REVISION = 4;
public const int MID = 100;
public long DataNumberSystem
{
get => GetField(2, (int)DataFields.DATA_NUMBER_SYSTEM).GetValue(_longConverter.Convert);
set => GetField(2, (int)DataFields.DATA_NUMBER_SYSTEM).SetValue(_longConverter.Convert, value);
}
public bool SendOnlyNewData
{
get => GetField(3, (int)DataFields.SEND_ONLY_NEW_DATA).GetValue(_boolConverter.Convert);
set => GetField(3, (int)DataFields.SEND_ONLY_NEW_DATA).SetValue(_boolConverter.Convert, value);
}
public Mid0100() : this(LAST_REVISION)
{
}
public Mid0100(int revision = LAST_REVISION) : base(MID, revision)
{
_longConverter = new Int64Converter();
_boolConverter = new BoolConverter();
}
public Mid0100(int revision, bool sendOnlyNewData) : this(revision)
{
SendOnlyNewData = sendOnlyNewData;
}
public Mid0100(int revision, int dataNumberSysten, bool sendOnlyNewData) : this(revision)
{
DataNumberSystem = dataNumberSysten;
SendOnlyNewData = sendOnlyNewData;
}
protected override Dictionary<int, List<DataField>> RegisterDatafields()
{
return new Dictionary<int, List<DataField>>()
{
{ 1, new List<DataField>() },
{
2, new List<DataField>()
{
new DataField((int)DataFields.DATA_NUMBER_SYSTEM, 20, 10, '0', DataField.PaddingOrientations.LEFT_PADDED, false),
}
},
{
3, new List<DataField>()
{
new DataField((int)DataFields.SEND_ONLY_NEW_DATA, 30, 1, '0', DataField.PaddingOrientations.LEFT_PADDED, false),
}
},
{
4, new List<DataField>()
}
};
}
public enum DataFields
{
DATA_NUMBER_SYSTEM,
SEND_ONLY_NEW_DATA
}
}
}
Sorry for the late reply and thanks for posting this code. I was busy with this controller thing where I am getting data more than one time even the controller is sending only one time but I am getting some times 3-4 times. I am using Revision 1 for 0100 but now I will test your code too. I have found one more problem with Mid0101 when parsing data then during conversion there is a problem with the substring variable
Yes, I found this bug too but I forgot it in my last comment :) I fixed it this way (I deleted extra "* 18"):
public override IEnumerable<SpindleOrPressStatus> Convert(string value)
{
for (int i = 0; i < value.Length; i += 18)
{
// var spindleValue = value.Substring(i * 18, 18);
var spindleValue = value.Substring(i, 18);
yield return new SpindleOrPressStatus()
{
SpindleOrPressNumber = _intConverter.Convert(spindleValue.Substring(0, 2)),
ChannelId = _intConverter.Convert(spindleValue.Substring(2, 2)),
OverallStatus = _boolConverter.Convert(spindleValue.Substring(4, 1)),
TorqueOrForceStatus = (TighteningValueStatus)_intConverter.Convert(spindleValue.Substring(5,1)),
TorqueOrForce = _decimalConverter.Convert(spindleValue.Substring(6, 6)),
AngleOrStrokeStatus = _boolConverter.Convert(spindleValue.Substring(12, 1)),
AngleOrStroke = _intConverter.Convert(spindleValue.Substring(13,5))
};
}
}
Hi, Thanks for your feedback. Now I am having one strange problem some data is missing. When I checked the log then When I received the tightening data then if before sending confirmation MID, keep alive mid sent then the connection is lost and then I am reconnecting to the controller but till then I have lost the data. This happens mostly in the case of first data NG then connection lost then I only had NG data because reconnection to the controller will take some time and till then the operator has passed the operation to the next process.
I think you didn't sent some ACK or didn't sent it in right order. I checked if keepalive (MID 9999) can drop connection and I sent keepalive before ack on purpose and connection was unaffected. I had similar issues when I forgot to send ack. You can find this in Open Protocol specification:
4.3.3 Subscribed data message acknowledge Depending on the subscription message” No Acknowledge Flag” settings in the message header the integrator is acknowledging or not acknowledging. If the flag is NOT set the integrator shall acknowledge the data event messages by sending the corresponding acknowledge MID, otherwise not. If no acknowledge is received before the response timeout, the controller will re-send the message up to three times. After three attempts the controller will consider the connection as lost.
You can try to subscribe with NoAck option (byte 12 in message header) to test this possibility. "No ack" option is considered as unreliable so you should restore this option after testing.
I am sending the ACK but I feel so while checking log I noticed I am getting message keep alive not received if just before ACK I am sending keep alive MID and after that code enter to reconnect method which will take some time and till then I have lost some OK data. I am send ACK in the following way
private void OnTighteningReceived3(MIDIncome e)
{
Log.Information("Tightening Data Received For Port 9003");
// lblManualMidResult.Text = "Tightening Data Received";
driverPort3.SendMessage(e.Mid.BuildAckPackage());
}
I have 3 controller for multispindle and one controller with single tool. In both the cases I am having problem..Can you help me what wrong I am doing and where ? Can controller handle multiple operation like when controller is waiting for some ACK and we are sending MID9999 for keep alive ?
I tried to send keepalive before ACK on purpose and this is result:
15.10 05:02:59.371 ... DEBUG: READ << 00420015 0042015-05-26:08:56:56
15.10 05:02:59.380 ... >> KeepAliveAtlas >> (00209999 )
15.10 05:02:59.383 ... << Parameter set selected - 4 (2015-05-26 08:56:56)
15.10 05:02:59.385 ... DEBUG: WRITE >> PsetNo_Acknowledge >> (00200016001 )
15.10 05:02:59.408 ... >> PsetNo_Acknowledge >> (00200016001 )
15.10 05:02:59.410 ... Parameter set ID: 4
15.10 05:02:59.428 ... DEBUG: READ << 00209999
So, I received response from controller 48ms later and no connection lost error or something like this.
It's hard to tell where is problem when I have only fragments of your code. I don't see try-catch block so I can guess if you're trying to log different events in same time you can get "file is in use" exception. Try to run logger in different thread and add semaphore (SemaphoreSlim) to control "traffic" (if you don't do it already) or try to swap lines like this:
private void OnTighteningReceived3(MIDIncome e)
{
driverPort3.SendMessage(e.Mid.BuildAckPackage());
// lblManualMidResult.Text = "Tightening Data Received";
Log.Information("Tightening Data Received For Port 9003");
}
Thanks for your reply.. Yes, i am using the try-catch block and not getting error message. But I will try to change as you have suggested. Thanks again for your help.
I tried to modify sample to work with multi-spindle tightening and I found problem is probable in SimpleTcpClient not your code. This TCP client is synchronous, it's good for sample but not for production. I lost connection to controller when I receive tightening result and in same time keepalive MID was sent and client waiting for response. Check this code:
public void WriteLine(string data)
{
if (string.IsNullOrEmpty(data)) { return; }
while (this.waitingForResponse)
Thread.Sleep(10);
if (data.LastOrDefault() != Delimiter)
{
Write(data);
}
else
{
Write(data);
}
}
You can see You can't send ACK MID when other MID was sent with request for response and client is waiting for requested response.
Thanks for your time again..this is exactly happening with me..Now what should I do and where and what should I change to run this code in production? I am not that good to work in Asynchronous way
I tried to change TCP class to SimpleTcp [1] (NuGet name is SuperSimpleTcp) and got no connection lost during one and half hour. I want to share this multi-spindle sample with this project but I don't when it will be ready.
Hi I think i had a similar issue . To improve the process don't send keep alive if you already send another command. Use keep alive only you have nothing to communicate. This will not fix your error but will decrease the chance of getting error.
@xGusu Thanks for your reply. I tried to do so by creating one flag which will check if the controller is not waiting for ACK then only keepalive will send the data. But as you said it does not fix the error and due to critical data I can not say to the client that you have to manage like this only. @yanick76 Thanks for sharing the class reference link I will try to use this class and hoping the issue will be resolved. Thanks again for your time and help @yanick76 @xGusu
Modified sample is included in different issue https://github.com/Rickedb/OpenProtocolInterpreter/issues/34
I left this sample running for 24 hours and i got no connection lost (and no crash or memory/resources leak) so you can use this sample I think it's stable enough. I hope this helps you.
Thank you so much for your help & time. I will use this sample in my production application. Thank you again
Closing issue due to inactivity and it seems that was solved. If problem persists, just reopen it.
I was communicating to one Open protocol controller with 3 tool. So first we try to use MID0100 but for that we are getting parsing error while receiving the response from the controller. So vendor of controller suggest that we can use 3 different port for 3 tool of the controller so we changed accordingly. We are testing everthing with the sample app in the repo. So we connected successfully but we are getting the response from all the 3 tool multple times. Even controller is sending one time but we are receiving multiple times. This is the first problem we faced but after some time we are having another big problem , controller is sending the data of all the 3 tool but we are receiving only for either 1 or 2 tool. When we restart the app then we again receive the data from all the 3 tool for 2-3 times but again then we received the data only for 1 or 2 tool. Here I am attaching code and log file as well. Log_20201001.log
Code.txt