Merge commit '9e85419e35233598ba347f4af7da6f5ec033d1d2' into V2
This commit is contained in:
commit
d3e12c16f2
@ -42,7 +42,7 @@ DOXYFILE_ENCODING = UTF-8
|
||||
# title of most generated pages and in a few other places.
|
||||
# The default value is: My Project.
|
||||
|
||||
PROJECT_NAME = "Control Core for C#"
|
||||
PROJECT_NAME = "Roboid Control for C#"
|
||||
|
||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
@ -68,7 +68,7 @@ PROJECT_LOGO = //intranet/home/Afbeeldingen/PasserVR/Logos/Logo3NameRi
|
||||
# entered, it will be relative to the location where doxygen was started. If
|
||||
# left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY = //intranet/web/passer_life/apis/ControlCore/Csharp/
|
||||
OUTPUT_DIRECTORY = //intranet/web/roboidcontrol_doc/Csharp/
|
||||
|
||||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
|
||||
# sub-directories (in 2 levels) under the output directory of each output format
|
||||
@ -777,7 +777,7 @@ MAX_INITIALIZER_LINES = 30
|
||||
# list will mention the files that were used to generate the documentation.
|
||||
# The default value is: YES.
|
||||
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_USED_FILES = NO
|
||||
|
||||
# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
|
||||
# will remove the Files entry from the Quick Index and from the Folder Tree View
|
||||
|
175
EchoStream.cs
175
EchoStream.cs
@ -1,175 +0,0 @@
|
||||
/*
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
public class EchoStream : Stream {
|
||||
public override bool CanTimeout { get; } = true;
|
||||
public override int ReadTimeout { get; set; } = Timeout.Infinite;
|
||||
public override int WriteTimeout { get; set; } = Timeout.Infinite;
|
||||
public override bool CanRead { get; } = true;
|
||||
public override bool CanSeek { get; } = false;
|
||||
public override bool CanWrite { get; } = true;
|
||||
|
||||
public bool CopyBufferOnWrite { get; set; } = false;
|
||||
|
||||
private readonly object _lock = new object();
|
||||
|
||||
// Default underlying mechanism for BlockingCollection is ConcurrentQueue<T>, which is what we want
|
||||
private readonly BlockingCollection<byte[]> _Buffers;
|
||||
private int _maxQueueDepth = 10;
|
||||
|
||||
private byte[] m_buffer = null;
|
||||
private int m_offset = 0;
|
||||
private int m_count = 0;
|
||||
|
||||
private bool m_Closed = false;
|
||||
private bool m_FinalZero = false; //after the stream is closed, set to true after returning a 0 for read()
|
||||
public override void Close() {
|
||||
m_Closed = true;
|
||||
|
||||
// release any waiting writes
|
||||
_Buffers.CompleteAdding();
|
||||
}
|
||||
|
||||
public bool DataAvailable {
|
||||
get {
|
||||
return _Buffers.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
private long _Length = 0L;
|
||||
public override long Length {
|
||||
get {
|
||||
return _Length;
|
||||
}
|
||||
}
|
||||
|
||||
private long _Position = 0L;
|
||||
public override long Position {
|
||||
get {
|
||||
return _Position;
|
||||
}
|
||||
set {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public EchoStream() : this(10) {
|
||||
}
|
||||
|
||||
public EchoStream(int maxQueueDepth) {
|
||||
_maxQueueDepth = maxQueueDepth;
|
||||
_Buffers = new BlockingCollection<byte[]>(_maxQueueDepth);
|
||||
}
|
||||
|
||||
// we override the xxxxAsync functions because the default base class shares state between ReadAsync and WriteAsync, which causes a hang if both are called at once
|
||||
public new Task WriteAsync(byte[] buffer, int offset, int count) {
|
||||
return Task.Run(() => Write(buffer, offset, count));
|
||||
}
|
||||
|
||||
// we override the xxxxAsync functions because the default base class shares state between ReadAsync and WriteAsync, which causes a hang if both are called at once
|
||||
public new Task<int> ReadAsync(byte[] buffer, int offset, int count) {
|
||||
return Task.Run(() => {
|
||||
return Read(buffer, offset, count);
|
||||
});
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count) {
|
||||
if (m_Closed || buffer.Length - offset < count || count <= 0)
|
||||
return;
|
||||
|
||||
byte[] newBuffer;
|
||||
if (!CopyBufferOnWrite && offset == 0 && count == buffer.Length)
|
||||
newBuffer = buffer;
|
||||
else {
|
||||
newBuffer = new byte[count];
|
||||
System.Buffer.BlockCopy(buffer, offset, newBuffer, 0, count);
|
||||
}
|
||||
if (!_Buffers.TryAdd(newBuffer, WriteTimeout))
|
||||
throw new TimeoutException("EchoStream Write() Timeout");
|
||||
|
||||
_Length += count;
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) {
|
||||
if (count == 0)
|
||||
return 0;
|
||||
lock (_lock) {
|
||||
if (m_count == 0 && _Buffers.Count == 0) {
|
||||
if (m_Closed) {
|
||||
if (!m_FinalZero) {
|
||||
m_FinalZero = true;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (_Buffers.TryTake(out m_buffer, ReadTimeout)) {
|
||||
m_offset = 0;
|
||||
m_count = m_buffer.Length;
|
||||
}
|
||||
else {
|
||||
if (m_Closed) {
|
||||
if (!m_FinalZero) {
|
||||
m_FinalZero = true;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int returnBytes = 0;
|
||||
while (count > 0) {
|
||||
if (m_count == 0) {
|
||||
if (_Buffers.TryTake(out m_buffer, 0)) {
|
||||
m_offset = 0;
|
||||
m_count = m_buffer.Length;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
var bytesToCopy = (count < m_count) ? count : m_count;
|
||||
System.Buffer.BlockCopy(m_buffer, m_offset, buffer, offset, bytesToCopy);
|
||||
m_offset += bytesToCopy;
|
||||
m_count -= bytesToCopy;
|
||||
offset += bytesToCopy;
|
||||
count -= bytesToCopy;
|
||||
|
||||
returnBytes += bytesToCopy;
|
||||
}
|
||||
|
||||
_Position += returnBytes;
|
||||
|
||||
return returnBytes;
|
||||
}
|
||||
}
|
||||
|
||||
public override int ReadByte() {
|
||||
byte[] returnValue = new byte[1];
|
||||
return (Read(returnValue, 0, 1) <= 0 ? -1 : (int)returnValue[0]);
|
||||
}
|
||||
|
||||
public override void Flush() {
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
*/
|
84
Messages/BinaryMsg.cs
Normal file
84
Messages/BinaryMsg.cs
Normal file
@ -0,0 +1,84 @@
|
||||
namespace Passer.RoboidControl {
|
||||
|
||||
/// <summary>
|
||||
/// A message containing binary data for custom communication
|
||||
/// </summary>
|
||||
public class BinaryMsg : IMessage {
|
||||
/// <summary>
|
||||
/// The message ID
|
||||
/// </summary>
|
||||
public const byte Id = 0xB1;
|
||||
/// <summary>
|
||||
/// The length of the message, excluding the binary data
|
||||
/// </summary>
|
||||
/// For the total size of the message this.bytes.Length should be added to this value.
|
||||
public const byte length = 2;
|
||||
/// <summary>
|
||||
/// The network ID identifying the thing
|
||||
/// </summary>
|
||||
public byte networkId;
|
||||
/// <summary>
|
||||
/// The ID of the thing
|
||||
/// </summary>
|
||||
public byte thingId;
|
||||
/// <summary>
|
||||
/// The binary data
|
||||
/// </summary>
|
||||
public byte[] bytes;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new message for sending
|
||||
/// </summary>
|
||||
/// <param name="networkId">The netowork ID of the thing</param>
|
||||
/// <param name="thingId">The ID of the thing</param>
|
||||
/// <param name="bytes">The binary data for the thing</param>
|
||||
public BinaryMsg(byte networkId, byte thingId, byte[] bytes) : base() {
|
||||
this.networkId = networkId;
|
||||
this.thingId = thingId;
|
||||
this.bytes = bytes;
|
||||
}
|
||||
/// <summary>
|
||||
/// Create an empty message for sending
|
||||
/// </summary>
|
||||
/// <param name="networkId">The netowork ID of the thing</param>
|
||||
/// <param name="thingId">The ID of the thing</param>
|
||||
public BinaryMsg(byte networkId, Thing thing) : base() {
|
||||
this.networkId = networkId;
|
||||
this.thingId = thing.id;
|
||||
this.bytes = System.Array.Empty<byte>();
|
||||
}
|
||||
/// <summary>
|
||||
/// Create the message for receiving
|
||||
/// </summary>
|
||||
/// <param name="buffer">The byte array to parse</param>
|
||||
public BinaryMsg(byte[] buffer) {
|
||||
byte ix = 1;
|
||||
this.networkId = buffer[ix++];
|
||||
this.thingId = buffer[ix++];
|
||||
byte length = (byte)(buffer.Length - ix);
|
||||
this.bytes = new byte[length];
|
||||
for (uint bytesIx = 0; bytesIx < length; bytesIx++)
|
||||
this.bytes[bytesIx] = buffer[ix++];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serialize the message into a byte array for sending
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to serilize into</param>
|
||||
/// <returns>The length of the message in the buffer</returns>
|
||||
public override byte Serialize(ref byte[] buffer) {
|
||||
if (buffer.Length < BinaryMsg.length + buffer.Length || bytes.Length == 0)
|
||||
return 0;
|
||||
|
||||
byte ix = 0;
|
||||
buffer[ix++] = BinaryMsg.Id;
|
||||
buffer[ix++] = this.networkId;
|
||||
buffer[ix++] = this.thingId;
|
||||
foreach (byte b in bytes)
|
||||
buffer[ix++] = b;
|
||||
|
||||
return ix;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
namespace Passer.Control.Core {
|
||||
|
||||
public class ClientMsg : IMessage {
|
||||
public const byte Id = 0xA0;
|
||||
public const byte length = 2;
|
||||
public byte networkId;
|
||||
|
||||
public ClientMsg(byte networkId) {
|
||||
this.networkId = networkId;
|
||||
}
|
||||
|
||||
public ClientMsg(byte[] buffer) {
|
||||
this.networkId = buffer[1];
|
||||
}
|
||||
|
||||
public override byte Serialize(ref byte[] buffer) {
|
||||
byte ix = 0;
|
||||
buffer[ix++] = ClientMsg.Id;
|
||||
buffer[ix++] = networkId;
|
||||
return ClientMsg.length;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
namespace Passer.Control.Core {
|
||||
|
||||
public class CustomMsg : IMessage {
|
||||
public const byte Id = 0xB1;
|
||||
public byte networkId;
|
||||
public byte thingId;
|
||||
public byte[] bytes;
|
||||
|
||||
public CustomMsg(byte[] buffer) {
|
||||
byte ix = 1;
|
||||
this.networkId = buffer[ix++];
|
||||
this.thingId = buffer[ix++];
|
||||
byte length = (byte)(buffer.Length - ix);
|
||||
this.bytes = new byte[length];
|
||||
for (uint bytesIx = 0; bytesIx < length; bytesIx++)
|
||||
this.bytes[bytesIx] = buffer[ix++];
|
||||
}
|
||||
public CustomMsg(byte networkId, byte thingId, byte[] bytes) : base() {
|
||||
this.networkId = networkId;
|
||||
this.thingId = thingId;
|
||||
this.bytes = bytes;
|
||||
}
|
||||
public CustomMsg(byte networkId, Thing thing) : base() {
|
||||
this.networkId = networkId;
|
||||
this.thingId = thing.id;
|
||||
this.bytes = new byte[0];
|
||||
}
|
||||
|
||||
public override byte Serialize(ref byte[] buffer) {
|
||||
if (bytes.Length == 0)
|
||||
return 0;
|
||||
|
||||
byte ix = 0;
|
||||
buffer[ix++] = CustomMsg.Id;
|
||||
buffer[ix++] = this.networkId;
|
||||
buffer[ix++] = this.thingId;
|
||||
//buffer[ix++] = (byte)bytes.Length;
|
||||
foreach (byte b in bytes)
|
||||
buffer[ix++] = b;
|
||||
|
||||
return ix;
|
||||
}
|
||||
|
||||
//public static async Task<bool> Receive(Stream dataStream, Participant client, byte packetSize) {
|
||||
// byte[] buffer = await Receive(dataStream, packetSize);
|
||||
|
||||
// CustomMsg msg = new(buffer);
|
||||
// client.messageQueue.Enqueue(msg);
|
||||
// return true;
|
||||
//}
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Passer.Control.Core {
|
||||
namespace Passer.RoboidControl {
|
||||
|
||||
public class DestroyMsg : IMessage {
|
||||
public const byte Id = 0x20;
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Passer.Control.Core {
|
||||
namespace Passer.RoboidControl {
|
||||
|
||||
public class InvestigateMsg : IMessage {
|
||||
public const byte Id = 0x81;
|
||||
|
@ -1,6 +1,6 @@
|
||||
using Passer.LinearAlgebra;
|
||||
|
||||
namespace Passer.Control.Core
|
||||
namespace Passer.RoboidControl
|
||||
{
|
||||
public class LowLevelMessages
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
|
||||
namespace Passer.Control.Core {
|
||||
namespace Passer.RoboidControl {
|
||||
|
||||
public class IMessage {
|
||||
public IMessage() { }
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace Passer.Control.Core {
|
||||
namespace Passer.RoboidControl {
|
||||
|
||||
public class NameMsg : IMessage {
|
||||
public const byte Id = 0x91; // 145
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace Passer.Control.Core {
|
||||
namespace Passer.RoboidControl {
|
||||
|
||||
public class NetworkIdMsg : IMessage {
|
||||
public const byte Id = 0xA1;
|
||||
|
51
Messages/ParticipantMsg.cs
Normal file
51
Messages/ParticipantMsg.cs
Normal file
@ -0,0 +1,51 @@
|
||||
namespace Passer.RoboidControl {
|
||||
|
||||
/// <summary>
|
||||
/// A participant messages notifies other participants of its presence
|
||||
/// </summary>
|
||||
public class ParticipantMsg : IMessage {
|
||||
/// <summary>
|
||||
/// The message ID
|
||||
/// </summary>
|
||||
public const byte Id = 0xA0;
|
||||
/// <summary>
|
||||
/// The length of the message
|
||||
/// </summary>
|
||||
public const byte length = 2;
|
||||
/// <summary>
|
||||
/// The network ID known by the participant
|
||||
/// </summary>
|
||||
public byte networkId;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new message for sending
|
||||
/// </summary>
|
||||
/// <param name="networkId"></param>
|
||||
public ParticipantMsg(byte networkId) {
|
||||
this.networkId = networkId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a message for receiving
|
||||
/// </summary>
|
||||
/// <param name="buffer">The byte array to parse</param>
|
||||
public ParticipantMsg(byte[] buffer) {
|
||||
this.networkId = buffer[1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serialize the message into a byte array
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to serialize into</param>
|
||||
/// <returns>The length of the message in the buffer</returns>
|
||||
public override byte Serialize(ref byte[] buffer) {
|
||||
if (buffer.Length < ParticipantMsg.length)
|
||||
return 0;
|
||||
|
||||
byte ix = 0;
|
||||
buffer[ix++] = ParticipantMsg.Id;
|
||||
buffer[ix++] = networkId;
|
||||
return ParticipantMsg.length;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Passer.LinearAlgebra;
|
||||
|
||||
namespace Passer.Control.Core {
|
||||
namespace Passer.RoboidControl {
|
||||
|
||||
public class PoseMsg : IMessage {
|
||||
public const byte Id = 0x10;
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Passer.Control.Core {
|
||||
namespace Passer.RoboidControl {
|
||||
|
||||
public class TextMsg : IMessage {
|
||||
public TextMsg(byte[] buffer) : base(buffer) {}
|
||||
|
90
Messages/ThingMsg.cs
Normal file
90
Messages/ThingMsg.cs
Normal file
@ -0,0 +1,90 @@
|
||||
namespace Passer.RoboidControl {
|
||||
|
||||
/// <summary>
|
||||
/// Message providing generic information about a Thing
|
||||
/// </summary>
|
||||
public class ThingMsg : IMessage {
|
||||
/// <summary>
|
||||
/// The message ID
|
||||
/// </summary>
|
||||
public const byte id = 0x80;
|
||||
/// <summary>
|
||||
/// The length of the message
|
||||
/// </summary>
|
||||
public const byte length = 5;
|
||||
/// <summary>
|
||||
/// The network ID of the thing
|
||||
/// </summary>
|
||||
public byte networkId;
|
||||
/// <summary>
|
||||
/// The ID of the thing
|
||||
/// </summary>
|
||||
public byte thingId;
|
||||
/// <summary>
|
||||
/// The Thing.Type of the thing
|
||||
/// </summary>
|
||||
public byte thingType;
|
||||
/// <summary>
|
||||
/// The parent of the thing in the hierarachy. This is null for root Things
|
||||
/// </summary>
|
||||
public byte parentId;
|
||||
|
||||
/// <summary>
|
||||
/// Create a message for sending
|
||||
/// </summary>
|
||||
/// <param name="networkId">The network ID of the thing</param>
|
||||
/// <param name="thing">The thing</param>
|
||||
public ThingMsg(byte networkId, Thing thing) {
|
||||
this.networkId = networkId;
|
||||
this.thingId = thing.id;
|
||||
this.thingType = thing.type;
|
||||
if (thing.parent != null)
|
||||
this.parentId = thing.parent.id;
|
||||
else
|
||||
this.parentId = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Create a message for sending
|
||||
/// </summary>
|
||||
/// <param name="networkId">The network ID of the thing</param>
|
||||
/// <param name="thingId">The ID of the thing</param>
|
||||
/// <param name="thingType">The type of thing</param>
|
||||
/// <param name="parentId">The parent of the thing</param>
|
||||
public ThingMsg(byte networkId, byte thingId, byte thingType, byte parentId) {
|
||||
this.networkId = networkId;
|
||||
this.thingId = thingId;
|
||||
this.thingType = thingType;
|
||||
this.parentId = parentId;
|
||||
}
|
||||
/// <summary>
|
||||
/// Create a message for receiving
|
||||
/// </summary>
|
||||
/// <param name="buffer">The byte array to parse</param>
|
||||
public ThingMsg(byte[] buffer) {
|
||||
uint ix = 1;
|
||||
this.networkId = buffer[ix++];
|
||||
this.thingId = buffer[ix++];
|
||||
this.thingType = buffer[ix++];
|
||||
this.parentId = buffer[ix];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serialize the message into a byte array
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to serialize into</param>
|
||||
/// <returns>The length of the message in the bufer. 0 when the buffer was too small</returns>
|
||||
public override byte Serialize(ref byte[] buffer) {
|
||||
if (buffer.Length < ThingMsg.length)
|
||||
return 0;
|
||||
|
||||
byte ix = 0;
|
||||
buffer[ix++] = ThingMsg.id;
|
||||
buffer[ix++] = this.networkId;
|
||||
buffer[ix++] = this.thingId;
|
||||
buffer[ix++] = this.thingType;
|
||||
buffer[ix++] = this.parentId;
|
||||
return ThingMsg.length;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
namespace Passer.Control.Core {
|
||||
namespace Passer.RoboidControl {
|
||||
|
||||
public class ModelUrlMsg : IMessage {
|
||||
public const byte Id = 0x90; // (144) Model URL
|
||||
|
@ -4,13 +4,15 @@ using System.Collections.Concurrent;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace Passer.Control.Core {
|
||||
namespace Passer.RoboidControl {
|
||||
|
||||
/// <summary>
|
||||
/// A participant is used for communcation between things
|
||||
/// </summary>
|
||||
public class Participant : RemoteParticipant {
|
||||
public byte[] buffer = new byte[1024];
|
||||
public ulong publishInterval = 3000; // = 3 seconds
|
||||
|
||||
//public byte networkId = 0;
|
||||
public string name = "Participant";
|
||||
|
||||
public IPEndPoint endPoint = null;
|
||||
@ -148,7 +150,7 @@ namespace Passer.Control.Core {
|
||||
}
|
||||
|
||||
public virtual void Publish() {
|
||||
this.Publish(new ClientMsg(this.networkId));
|
||||
this.Publish(new ParticipantMsg(this.networkId));
|
||||
}
|
||||
|
||||
#endregion Update
|
||||
@ -160,7 +162,7 @@ namespace Passer.Control.Core {
|
||||
this.Send(remoteParticipant, new ThingMsg(this.networkId, thing));
|
||||
this.Send(remoteParticipant, new NameMsg(this.networkId, thing));
|
||||
this.Send(remoteParticipant, new ModelUrlMsg(this.networkId, thing));
|
||||
this.Send(remoteParticipant, new CustomMsg(this.networkId, thing));
|
||||
this.Send(remoteParticipant, new BinaryMsg(this.networkId, thing));
|
||||
}
|
||||
|
||||
public bool Send(IMessage msg) {
|
||||
@ -189,7 +191,7 @@ namespace Passer.Control.Core {
|
||||
this.Publish(new ThingMsg(this.networkId, thing));
|
||||
this.Publish(new NameMsg(this.networkId, thing));
|
||||
this.Publish(new ModelUrlMsg(this.networkId, thing));
|
||||
this.Publish(new CustomMsg(this.networkId, thing));
|
||||
this.Publish(new BinaryMsg(this.networkId, thing));
|
||||
}
|
||||
|
||||
public bool Publish(IMessage msg) {
|
||||
@ -232,8 +234,8 @@ namespace Passer.Control.Core {
|
||||
}
|
||||
|
||||
switch (msgId) {
|
||||
case ClientMsg.Id: // 0xA0 / 160
|
||||
this.Process(remoteParticipant, new ClientMsg(data));
|
||||
case ParticipantMsg.Id: // 0xA0 / 160
|
||||
this.Process(remoteParticipant, new ParticipantMsg(data));
|
||||
break;
|
||||
case NetworkIdMsg.Id: // 0xA1 / 161
|
||||
this.Process(remoteParticipant, new NetworkIdMsg(data));
|
||||
@ -253,8 +255,8 @@ namespace Passer.Control.Core {
|
||||
case PoseMsg.Id: // 0x10 / 16
|
||||
// result = await PoseMsg.Receive(dataStream, client, packetSize);
|
||||
break;
|
||||
case CustomMsg.Id: // 0xB1 / 177
|
||||
this.Process(remoteParticipant, new CustomMsg(data));
|
||||
case BinaryMsg.Id: // 0xB1 / 177
|
||||
this.Process(remoteParticipant, new BinaryMsg(data));
|
||||
break;
|
||||
case TextMsg.Id: // 0xB0 / 176
|
||||
// result = await TextMsg.Receive(dataStream, client, packetSize);
|
||||
@ -271,7 +273,7 @@ namespace Passer.Control.Core {
|
||||
|
||||
#region Process
|
||||
|
||||
protected virtual void Process(RemoteParticipant sender, ClientMsg msg) { }
|
||||
protected virtual void Process(RemoteParticipant sender, ParticipantMsg msg) { }
|
||||
|
||||
protected virtual void Process(RemoteParticipant sender, NetworkIdMsg msg) {
|
||||
Console.WriteLine($"{this.name} receive network id {this.networkId} {msg.networkId}");
|
||||
@ -301,7 +303,7 @@ namespace Passer.Control.Core {
|
||||
|
||||
protected virtual void Process(PoseMsg msg) { }
|
||||
|
||||
protected virtual void Process(RemoteParticipant sender, CustomMsg msg) {
|
||||
protected virtual void Process(RemoteParticipant sender, BinaryMsg msg) {
|
||||
// Console.WriteLine($"Participant: Process binary [{msg.networkId}/{msg.thingId}]");
|
||||
Thing thing = sender.Get(msg.networkId, msg.thingId);
|
||||
thing?.ProcessBinary(msg.bytes);
|
||||
|
@ -2,32 +2,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Passer.Control.Core {
|
||||
namespace Passer.RoboidControl {
|
||||
|
||||
/// <summary>
|
||||
/// A reference to a participant, possible on a remote location
|
||||
/// </summary>
|
||||
public class RemoteParticipant {
|
||||
/// <summary>
|
||||
/// The internet address of the participant
|
||||
/// </summary>
|
||||
public string ipAddress = "0.0.0.0";
|
||||
/// <summary>
|
||||
/// The UDP port on which the participant can be reached
|
||||
/// </summary>
|
||||
public int port = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The network ID of the participant
|
||||
/// </summary>
|
||||
public byte networkId;
|
||||
|
||||
public RemoteParticipant() {
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public RemoteParticipant() {}
|
||||
/// <summary>
|
||||
/// Create a new remote participant
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">The ip address of the participant</param>
|
||||
/// <param name="port">The UDP port of the participant</param>
|
||||
public RemoteParticipant(string ipAddress, int port) {
|
||||
this.ipAddress = ipAddress;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The things reported by this participant
|
||||
/// </summary>
|
||||
protected readonly List<Thing> things = new List<Thing>();
|
||||
|
||||
/// <summary>
|
||||
/// Get a thing with the given ids
|
||||
/// </summary>
|
||||
/// <param name="networkId">The networkId of the thing</param>
|
||||
/// <param name="thingId">The ID of the thing</param>
|
||||
/// <returns>The thing when it is found, null in other cases.</returns>
|
||||
public Thing Get(byte networkId, byte thingId) {
|
||||
Thing thing = things.Find(aThing => Thing.IsThing(aThing, networkId, thingId));
|
||||
// if (thing == null)
|
||||
// Console.WriteLine($"Could not find thing {ipAddress}:{port}[{networkId}/{thingId}]");
|
||||
return thing;
|
||||
}
|
||||
|
||||
// if (thing == null)
|
||||
// Console.WriteLine($"Could not find thing {ipAddress}:{port}[{networkId}/{thingId}]");
|
||||
|
||||
/// <summary>
|
||||
/// Add a new thing for this participant
|
||||
/// </summary>
|
||||
/// <param name="thing">The thing to add</param>
|
||||
/// <param name="invokeEvent">Invoke an notification event when the thing has been added</param>
|
||||
public void Add(Thing thing, bool invokeEvent = true) {
|
||||
// Console.WriteLine($"added thing [{thing.networkId}/{thing.id}]");
|
||||
Thing foundThing = Get(thing.networkId, thing.id);
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Passer.Control.Core {
|
||||
namespace Passer.RoboidControl.Core {
|
||||
|
||||
public class DistanceSensor : Thing {
|
||||
public float distance = 0;
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Passer.Control.Core {
|
||||
namespace Passer.RoboidControl.Core {
|
||||
|
||||
public class TemperatureSensor : Thing {
|
||||
public float temp = 0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace Passer.Control.Core {
|
||||
namespace Passer.RoboidControl.Core {
|
||||
public class TouchSensor : Thing {
|
||||
public bool touchedSomething = false;
|
||||
|
||||
|
@ -3,10 +3,17 @@ using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace Passer.Control.Core {
|
||||
namespace Passer.RoboidControl {
|
||||
|
||||
/// <summary>
|
||||
/// A site server is a participant which provides a shared simulated environment
|
||||
/// </summary>
|
||||
public class SiteServer : Participant {
|
||||
|
||||
/// <summary>
|
||||
/// Create a new site server
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
public SiteServer(int port = 7681) {
|
||||
this.name = "Site Server";
|
||||
|
||||
@ -22,6 +29,9 @@ namespace Passer.Control.Core {
|
||||
new Tuple<UdpClient, IPEndPoint>(this.udpClient, new IPEndPoint(IPAddress.Any, port)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the site
|
||||
/// </summary>
|
||||
public void Close() {
|
||||
this.udpClient?.Close();
|
||||
}
|
||||
@ -29,7 +39,7 @@ namespace Passer.Control.Core {
|
||||
public override void Publish() {
|
||||
}
|
||||
|
||||
protected override void Process(RemoteParticipant sender, ClientMsg msg) {
|
||||
protected override void Process(RemoteParticipant sender, ParticipantMsg msg) {
|
||||
if (msg.networkId == 0) {
|
||||
Console.WriteLine($"{this.name} received New Client -> {sender.networkId}");
|
||||
this.Send(sender, new NetworkIdMsg(sender.networkId));
|
||||
|
9
Thing.cs
9
Thing.cs
@ -2,18 +2,21 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Passer.LinearAlgebra;
|
||||
|
||||
namespace Passer.Control.Core {
|
||||
namespace Passer.RoboidControl {
|
||||
|
||||
/// <summary>
|
||||
/// A thing is the basic building block
|
||||
/// A thing is the primitive building block
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Thing {
|
||||
|
||||
#region Types
|
||||
|
||||
/// <summary>
|
||||
/// Predefined thing types
|
||||
/// </summary>
|
||||
public enum Type {
|
||||
Undeterment,
|
||||
Undetermined,
|
||||
// Sensor
|
||||
Switch,
|
||||
DistanceSensor,
|
||||
|
45
ThingMsg.cs
45
ThingMsg.cs
@ -1,45 +0,0 @@
|
||||
namespace Passer.Control.Core {
|
||||
|
||||
public class ThingMsg : IMessage {
|
||||
public const byte length = 5;
|
||||
public const byte id = 0x80;
|
||||
public byte networkId;
|
||||
public byte thingId;
|
||||
public byte thingType;
|
||||
public byte parentId;
|
||||
|
||||
public ThingMsg(byte networkId, Thing thing) {
|
||||
this.networkId = networkId;
|
||||
this.thingId = thing.id;
|
||||
this.thingType = thing.type;
|
||||
if (thing.parent != null)
|
||||
this.parentId = thing.parent.id;
|
||||
else
|
||||
this.parentId = 0;
|
||||
}
|
||||
public ThingMsg(byte networkId, byte thingId, byte thingType, byte parentId) {
|
||||
this.networkId = networkId;
|
||||
this.thingId = thingId;
|
||||
this.thingType = thingType;
|
||||
this.parentId = parentId;
|
||||
}
|
||||
public ThingMsg(byte[] buffer) {
|
||||
uint ix = 1;
|
||||
this.networkId = buffer[ix++];
|
||||
this.thingId = buffer[ix++];
|
||||
this.thingType = buffer[ix++];
|
||||
this.parentId = buffer[ix];
|
||||
}
|
||||
|
||||
public override byte Serialize(ref byte[] buffer) {
|
||||
byte ix = 0;
|
||||
buffer[ix++] = ThingMsg.id;
|
||||
buffer[ix++] = this.networkId;
|
||||
buffer[ix++] = this.thingId;
|
||||
buffer[ix++] = this.thingType;
|
||||
buffer[ix++] = this.parentId;
|
||||
return ThingMsg.length;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 620fef383ba64a44995a234a71b2f189
|
@ -3,7 +3,7 @@ using System;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
|
||||
using Passer.Control.Core;
|
||||
using Passer.RoboidControl;
|
||||
|
||||
namespace ControlCore.test {
|
||||
public class Tests {
|
||||
|
Loading…
x
Reference in New Issue
Block a user