Simulartion env setup (WIP)
This commit is contained in:
parent
b2591ca5cc
commit
246a2b9a3a
142
Participant.cs
142
Participant.cs
@ -1,5 +1,3 @@
|
|||||||
#nullable enable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
@ -8,63 +6,96 @@ using System.Net.Sockets;
|
|||||||
|
|
||||||
namespace Passer.Control.Core {
|
namespace Passer.Control.Core {
|
||||||
|
|
||||||
public class Participant {
|
public class Participant : RemoteParticipant {
|
||||||
//public ConnectionMethod connection;
|
public byte[] buffer = new byte[1024];
|
||||||
public IPEndPoint? endPoint = null;
|
public ulong publishInterval = 3000; // = 3 seconds
|
||||||
public UdpClient? udpClient = null;
|
|
||||||
public string ipAddress = "0.0.0.0";
|
|
||||||
public string broadcastIpAddress = "255.255.255.255";
|
|
||||||
public int port;
|
|
||||||
|
|
||||||
public byte[] buffer = new byte[256];
|
//public byte networkId = 0;
|
||||||
|
|
||||||
public byte networkId = 0;
|
|
||||||
public string name = "Participant";
|
public string name = "Participant";
|
||||||
|
|
||||||
|
public IPEndPoint endPoint = null;
|
||||||
|
public UdpClient udpClient = null;
|
||||||
|
public string broadcastIpAddress = "255.255.255.255";
|
||||||
|
|
||||||
public readonly ConcurrentQueue<IMessage> messageQueue = new();
|
public readonly ConcurrentQueue<IMessage> messageQueue = new();
|
||||||
|
|
||||||
public List<Participant> others = new List<Participant>();
|
|
||||||
|
|
||||||
public Participant? GetParticipant(string ipAddress, int port) {
|
|
||||||
foreach (Participant c in others) {
|
|
||||||
if (c.ipAddress == ipAddress && c.port == port)
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
public Participant AddParticipant(string ipAddress, int port) {
|
|
||||||
Participant participant = new Participant(ipAddress, port);
|
|
||||||
participant.networkId = (byte)this.others.Count;
|
|
||||||
//others.Add();
|
|
||||||
return participant;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Init
|
#region Init
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a porticiapnt
|
||||||
|
/// </summary>
|
||||||
public Participant() {
|
public Participant() {
|
||||||
others.Add(this);
|
others.Add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new participant
|
/// Create a participant with the give UDP port
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="port">The port number on which to communicate</param>
|
||||||
|
public Participant(int port) : this() {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new participant for a site at the given address and port
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ipAddress">The ip address of the site server</param>
|
/// <param name="ipAddress">The ip address of the site server</param>
|
||||||
/// <param name="port">The port number of the site server</param>
|
/// <param name="port">The port number of the site server</param>
|
||||||
public Participant(string ipAddress = "0.0.0.0", int port = 7681) : this() {
|
public Participant(string ipAddress = "0.0.0.0", int port = 7681) : this() {
|
||||||
this.ipAddress = ipAddress;
|
this.ipAddress = ipAddress;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
|
|
||||||
this.endPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port); // for sending
|
this.endPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port); // for sending
|
||||||
this.udpClient = new UdpClient(); // for receiving
|
|
||||||
this.udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, 0));
|
this.udpClient = new UdpClient(port); // for receiving
|
||||||
|
this.udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, port));
|
||||||
this.udpClient.BeginReceive(new AsyncCallback(result => ReceiveUDP(result)), null);
|
this.udpClient.BeginReceive(new AsyncCallback(result => ReceiveUDP(result)), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a participant using the given udp client
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="udpClient">UDP client to use for communication</param>
|
||||||
|
/// <param name="port">The port number on which to communicate</param>
|
||||||
public Participant(UdpClient udpClient, int port) : this() {
|
public Participant(UdpClient udpClient, int port) : this() {
|
||||||
this.udpClient = udpClient;
|
this.udpClient = udpClient;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
//clients.Add(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<RemoteParticipant> others = new List<RemoteParticipant>();
|
||||||
|
|
||||||
|
public RemoteParticipant GetParticipant(string ipAddress, int port) {
|
||||||
|
foreach (RemoteParticipant c in others) {
|
||||||
|
if (c.ipAddress == ipAddress && c.port == port)
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public RemoteParticipant AddParticipant(string ipAddress, int port) {
|
||||||
|
RemoteParticipant participant = new(ipAddress, port);
|
||||||
|
participant.networkId = (byte)this.others.Count;
|
||||||
|
//others.Add();
|
||||||
|
return participant;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected readonly Dictionary<byte, Func<byte, byte, Thing>> thingMsgProcessors = new();
|
||||||
|
|
||||||
|
public delegate Thing ThingConstructor(byte networkId, byte thingId);
|
||||||
|
public void Register(byte thingType, ThingConstructor constr) {
|
||||||
|
thingMsgProcessors[thingType] = new Func<byte, byte, Thing>(constr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Register<ThingClass>(Thing.Type thingType) where ThingClass : Thing {
|
||||||
|
Register<ThingClass>((byte)thingType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Register<ThingClass>(byte thingType) where ThingClass : Thing {
|
||||||
|
thingMsgProcessors[thingType] = (byte networkId, byte thingId) =>
|
||||||
|
Activator.CreateInstance(typeof(ThingClass), networkId, thingId) as ThingClass;
|
||||||
|
Console.WriteLine($"Registering {typeof(ThingClass)} for thing type {thingType}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion Init
|
#endregion Init
|
||||||
|
|
||||||
#region Update
|
#region Update
|
||||||
@ -76,24 +107,29 @@ namespace Passer.Control.Core {
|
|||||||
byte[] data = udpClient.EndReceive(result, ref this.endPoint);
|
byte[] data = udpClient.EndReceive(result, ref this.endPoint);
|
||||||
// This does not yet take multi-packet messages into account!
|
// This does not yet take multi-packet messages into account!
|
||||||
|
|
||||||
Participant? remoteParticipant = this.GetParticipant(endPoint.Address.ToString(), endPoint.Port);
|
RemoteParticipant remoteParticipant = this.GetParticipant(endPoint.Address.ToString(), endPoint.Port);
|
||||||
if (remoteParticipant == null) {
|
if (remoteParticipant == null)
|
||||||
remoteParticipant = this.AddParticipant(endPoint.Address.ToString(), endPoint.Port);
|
remoteParticipant = this.AddParticipant(endPoint.Address.ToString(), endPoint.Port);
|
||||||
}
|
|
||||||
ReceiveData(data, remoteParticipant);
|
ReceiveData(data, remoteParticipant);
|
||||||
|
|
||||||
udpClient.BeginReceive(new AsyncCallback(result => ReceiveUDP(result)), null);
|
udpClient.BeginReceive(new AsyncCallback(result => ReceiveUDP(result)), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly ulong publishInterval = 3000;
|
|
||||||
private ulong nextPublishMe = 0;
|
private ulong nextPublishMe = 0;
|
||||||
|
|
||||||
|
|
||||||
public virtual void Update(ulong currentTimeMs) {
|
public virtual void Update(ulong currentTimeMs = 0) {
|
||||||
if (currentTimeMs > this.nextPublishMe) {
|
if (currentTimeMs == 0) {
|
||||||
|
#if UNITY_5_3_OR_NEWER
|
||||||
|
currentTimeMs = (ulong)(UnityEngine.Time.time * 1000);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.publishInterval > 0 && currentTimeMs > this.nextPublishMe) {
|
||||||
this.Publish(new ClientMsg(this.networkId));
|
this.Publish(new ClientMsg(this.networkId));
|
||||||
// Console.WriteLine($"{this.name} Sent ClientMsg {this.networkId}");
|
// Console.WriteLine($"{this.name} Sent ClientMsg {this.networkId}");
|
||||||
this.nextPublishMe = currentTimeMs + Participant.publishInterval;
|
this.nextPublishMe = currentTimeMs + this.publishInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for (int ix = 0; ix < this.others.Count; ix++) {
|
// for (int ix = 0; ix < this.others.Count; ix++) {
|
||||||
@ -110,11 +146,11 @@ namespace Passer.Control.Core {
|
|||||||
|
|
||||||
#region Send
|
#region Send
|
||||||
|
|
||||||
public void SendThingInfo(Thing thing) {
|
public void SendThingInfo(RemoteParticipant remoteParticipant, Thing thing) {
|
||||||
Console.WriteLine("Send thing info");
|
Console.WriteLine("Send thing info");
|
||||||
this.Send(new ThingMsg(this.networkId, thing));
|
this.Send(remoteParticipant, new ThingMsg(this.networkId, thing));
|
||||||
this.Send(new NameMsg(this.networkId, thing));
|
this.Send(remoteParticipant, new NameMsg(this.networkId, thing));
|
||||||
this.Send(new ModelUrlMsg(this.networkId, thing));
|
this.Send(remoteParticipant, new ModelUrlMsg(this.networkId, thing));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Send(IMessage msg) {
|
public bool Send(IMessage msg) {
|
||||||
@ -127,6 +163,17 @@ namespace Passer.Control.Core {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Send(RemoteParticipant remoteParticipant, IMessage msg) {
|
||||||
|
int bufferSize = msg.Serialize(ref this.buffer);
|
||||||
|
if (bufferSize <= 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
IPEndPoint participantEndpoint = new(IPAddress.Parse(remoteParticipant.ipAddress), remoteParticipant.port);
|
||||||
|
Console.WriteLine($"msg to {participantEndpoint.Address.ToString()} {participantEndpoint.Port}");
|
||||||
|
this.udpClient?.Send(this.buffer, bufferSize, participantEndpoint);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool Publish(IMessage msg) {
|
public bool Publish(IMessage msg) {
|
||||||
int bufferSize = msg.Serialize(ref this.buffer);
|
int bufferSize = msg.Serialize(ref this.buffer);
|
||||||
if (bufferSize <= 0)
|
if (bufferSize <= 0)
|
||||||
@ -159,8 +206,9 @@ namespace Passer.Control.Core {
|
|||||||
|
|
||||||
#region Receive
|
#region Receive
|
||||||
|
|
||||||
public void ReceiveData(byte[] data, Participant remoteParticipant) {
|
public void ReceiveData(byte[] data, RemoteParticipant remoteParticipant) {
|
||||||
byte msgId = data[0];
|
byte msgId = data[0];
|
||||||
|
Console.Write($"received msg {msgId}");
|
||||||
if (msgId == 0xFF) {
|
if (msgId == 0xFF) {
|
||||||
// Timeout
|
// Timeout
|
||||||
return;
|
return;
|
||||||
@ -206,14 +254,14 @@ namespace Passer.Control.Core {
|
|||||||
|
|
||||||
#region Process
|
#region Process
|
||||||
|
|
||||||
protected virtual void Process(Participant sender, ClientMsg msg) { }
|
protected virtual void Process(RemoteParticipant sender, ClientMsg msg) { }
|
||||||
|
|
||||||
protected virtual void Process(Participant sender, NetworkIdMsg msg) {
|
protected virtual void Process(RemoteParticipant sender, NetworkIdMsg msg) {
|
||||||
Console.WriteLine($"{this.name} receive network id {this.networkId} {msg.networkId}");
|
Console.WriteLine($"{this.name} receive network id {this.networkId} {msg.networkId}");
|
||||||
if (this.networkId != msg.networkId) {
|
if (this.networkId != msg.networkId) {
|
||||||
this.networkId = msg.networkId;
|
this.networkId = msg.networkId;
|
||||||
foreach (Thing thing in Thing.GetAllThings())
|
foreach (Thing thing in Thing.GetAllThings())
|
||||||
sender.SendThingInfo(thing);
|
this.SendThingInfo(sender, thing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
RemoteParticipant.cs
Normal file
18
RemoteParticipant.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
namespace Passer.Control.Core {
|
||||||
|
|
||||||
|
public class RemoteParticipant {
|
||||||
|
public string ipAddress = "0.0.0.0";
|
||||||
|
public int port = 0;
|
||||||
|
|
||||||
|
public byte networkId;
|
||||||
|
|
||||||
|
public RemoteParticipant() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public RemoteParticipant(string ipAddress, int port) {
|
||||||
|
this.ipAddress = ipAddress;
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,6 +3,8 @@ using System;
|
|||||||
namespace Passer.Control.Core {
|
namespace Passer.Control.Core {
|
||||||
|
|
||||||
public class TemperatureSensor : Thing {
|
public class TemperatureSensor : Thing {
|
||||||
|
public float temp = 0;
|
||||||
|
|
||||||
public TemperatureSensor(byte networkId, byte thingId) : base(null, networkId, thingId, (byte)Type.TemperatureSensor) {
|
public TemperatureSensor(byte networkId, byte thingId) : base(null, networkId, thingId, (byte)Type.TemperatureSensor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,50 +8,41 @@ namespace Passer.Control.Core {
|
|||||||
public class SiteServer : Participant {
|
public class SiteServer : Participant {
|
||||||
|
|
||||||
public SiteServer(int port = 7681) {
|
public SiteServer(int port = 7681) {
|
||||||
|
this.name = "Site Server";
|
||||||
|
this.publishInterval = 0;
|
||||||
|
|
||||||
this.ipAddress = "0.0.0.0";
|
this.ipAddress = "0.0.0.0";
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.endPoint = new IPEndPoint(IPAddress.Parse(ipAddress), 0); // for sending, but should not be used really...
|
|
||||||
this.udpClient = new UdpClient(); // for receiving
|
|
||||||
this.udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, port));
|
|
||||||
this.udpClient.BeginReceive(new AsyncCallback(result => ReceiveUDP(result)), null);
|
|
||||||
this.name = "Site Server";
|
|
||||||
|
|
||||||
Register<TemperatureSensor>((byte)Thing.Type.TemperatureSensor);
|
this.endPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port); // for sending
|
||||||
|
|
||||||
|
Console.Write($"Prepare receive on port {port}");
|
||||||
|
this.udpClient = new UdpClient(port); // for receiving
|
||||||
|
//this.udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, port));
|
||||||
|
IPEndPoint receiveEndpoint = new(IPAddress.Any, port);
|
||||||
|
this.udpClient.BeginReceive(
|
||||||
|
new AsyncCallback(result => ReceiveUDP(result)),
|
||||||
|
new Tuple<UdpClient, IPEndPoint>(this.udpClient, receiveEndpoint));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(ulong currentTimeMs) {
|
protected override void Process(RemoteParticipant sender, ClientMsg msg) {
|
||||||
Thing.UpdateAll(currentTimeMs);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Process(Participant sender, ClientMsg msg) {
|
|
||||||
if (msg.networkId == 0) {
|
if (msg.networkId == 0) {
|
||||||
Console.WriteLine($"{this.name} received New Client -> {sender.networkId}");
|
Console.WriteLine($"{this.name} received New Client -> {sender.networkId}");
|
||||||
sender.Send(new NetworkIdMsg(sender.networkId));
|
this.Send(sender, new NetworkIdMsg(sender.networkId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Process(Participant sender, NetworkIdMsg msg) {
|
protected override void Process(RemoteParticipant sender, NetworkIdMsg msg) { }
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
delegate Thing ThingConstructor(byte networkId, byte thingId);
|
|
||||||
readonly Dictionary<byte, ThingConstructor> thingMsgProcessors = new();
|
|
||||||
|
|
||||||
public void Register<ThingClass>(byte thingType) where ThingClass : Thing {
|
|
||||||
thingMsgProcessors[thingType] = (byte networkId, byte thingId) => {
|
|
||||||
if (Activator.CreateInstance(typeof(Thing), networkId, thingId) is not ThingClass instance)
|
|
||||||
throw new InvalidOperationException($"Could not created an instance of {(typeof(ThingClass))}.");
|
|
||||||
return instance;
|
|
||||||
};
|
|
||||||
Console.WriteLine($"Registering {typeof(ThingClass)} for thing type {thingType}");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Process(ThingMsg msg) {
|
protected override void Process(ThingMsg msg) {
|
||||||
|
Console.Write("SiteServer: Processing thing msg");
|
||||||
Thing thing = Thing.Get(msg.networkId, msg.thingId);
|
Thing thing = Thing.Get(msg.networkId, msg.thingId);
|
||||||
if (thing == null) {
|
if (thing == null) {
|
||||||
if (thingMsgProcessors.TryGetValue(msg.thingType, out ThingConstructor thingConstructor)) {
|
if (thingMsgProcessors.ContainsKey(msg.thingType))
|
||||||
thingConstructor(msg.networkId, msg.thingId);
|
thingMsgProcessors[msg.thingType](msg.networkId, msg.thingId);
|
||||||
}
|
// if (thingMsgProcessors.TryGetValue(msg.thingType, out ThingConstructor thingConstructor)) {
|
||||||
|
// thingConstructor(msg.networkId, msg.thingId);
|
||||||
|
// }
|
||||||
else {
|
else {
|
||||||
new Thing(this, msg.networkId, msg.thingId, msg.thingType);
|
new Thing(this, msg.networkId, msg.thingId, msg.thingType);
|
||||||
}
|
}
|
||||||
|
2
Thing.cs
2
Thing.cs
@ -75,7 +75,7 @@ namespace Passer.Control.Core {
|
|||||||
|
|
||||||
public event ChangeHandler OnNameChanged;
|
public event ChangeHandler OnNameChanged;
|
||||||
private string _name;
|
private string _name;
|
||||||
public string name {
|
public virtual string name {
|
||||||
get => _name;
|
get => _name;
|
||||||
set {
|
set {
|
||||||
if (_name != value) {
|
if (_name != value) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user