I have three class, main, serial, meter.
main is create new instance of meter and add list for management, when user clicked button.
// main.cs
MeterPanel meter = new MeterPanel(meterid);
list_Meters.Add(meter);
And each meter has an instance of a serial class and control it.
// meter.cs
SerialClass serialclass = new SerialClass();
...
serialclass.SetMeterID("00001");
serialclass.OpenSerial("COM12", 9600);
And serial class work for serial open, close, read, write.
// SerialClass.cs
SerialPort serial = new SerialPort();
string meterid = "";
public bool OpenSerial(string port, int baud)
{
...
serial.DataReceived += new SerialDataReceivedEventHandler(Serial_DataReceived);
serial.Open();
}
private void Serial_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
...
}
private void SerialWrite(string str)
{
serial.Write(str);
}
public void SetMeterID(string meterid)
{
this.meterid = meterid;
}
It work well if meter has own port.
But I want the meter to share one port. The serial class does not respond if its meter id does not match the packet's meter id.
How can meter to share one port?
first, I tried serial open on main class, and each meter class do deep copy serial class.
public object DeepCopy(object obj)
{
if (ReferenceEquals(obj, null)) return null;
Type type = obj.GetType();
if (type.IsValueType || type == typeof(string))
return obj;
else if (type.IsArray)
{
var array = obj as Array;
var arrayType = Type.GetType(type.FullName.Replace("[]", string.Empty));
var arrayInstance = Array.CreateInstance(arrayType, array.Length);
for (int i = 0; i < array.Length; i++)
arrayInstance.SetValue(DeepCopy(array.GetValue(i)), i);
return Convert.ChangeType(arrayInstance, type);
}
else if (type.IsClass)
{
var instance = Activator.CreateInstance(obj.GetType());
var fields = type.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var field in fields)
{
var fieldValue = field.GetValue(obj);
if (ReferenceEquals(fieldValue, null)) continue;
field.SetValue(instance, DeepCopy(fieldValue));
}
return instance;
}
else
return null;
}
But it ocuur System.MissingMethodException when Activator.CreateInstance, because System.Text.DecoderNLS and System.IO.Ports.SerialStream not defined parameterless constructor.
so I do deep copy like that
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, this);
ms.Position = 0;
return formatter.Deserialize(ms);
}
It occurr error again...
The type 'System.IO.Ports.SerialPort' is not marked as serializable.'
Second, I make simple serial class for serial open only.
//SimpleSerial
...
public SerialPort OpenSerial(string port, int baud)
{
...
serial.Open();
return serial;
}
And other class change like that.
// main.cs
SimpleSerial simple = new SimpleSerial()
SerialPort serial = simple.OpenSerial("COM12", 9600);
list_Meters[i].SetSerialPort(serial);
// meter.cs
public void SetSerialPort(SerialPort serial)
{
serialclass.Set(serial);
}
// SerialClass.cs
public void Set(SerialPort serial)
{
this.serial = serial;
serial.DataReceived += new SerialDataReceivedEventHandler(Serial_DataReceived);
}
I intended the received event of each meter's serial class to work. However, only the received event of the first generated meter fired.
I guess this is because each meter shares one serial port instance.
But SerialPort fails with deep copy.
How can I deepcopy a SerialPort?
Or is there any other way to use one serial port in multiple classes?
Only one serial port instance at a time can be open for a particular physical port, so it does not make sense to attempt to make copies.
Instead, what you could do is have one instance of a custom class, e.g. PortManager, which owns the serial port instance, and then provides a subscription mechanism where multiple client classes can register with a callback delegate, subscribing to incoming data, perhaps based off of a key that the port manager then filters incoming data on and figures out, which client(s) should receive this particular piece of incoming data.
Presumably, the port manager will also have a public Send method, which allows clients to send data out through the port.