This repository has been archived by the owner on Nov 9, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New Logix: LogiX/Network/ART-NET ArtNetChannelDataExtractor ArtNetReceiverConnect ArtNetUniverseDataReceiver New Component: Network ArtNetReceiver
- Loading branch information
Showing
7 changed files
with
321 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
using System; | ||
using System.Net; | ||
using System.Net.Sockets; | ||
using System.Threading.Tasks; | ||
using BaseX; | ||
using FrooxEngine; | ||
|
||
[Category("Network")] | ||
public class ArtNetReceiver : Component | ||
{ | ||
public readonly Sync<Uri> URL; | ||
public readonly UserRef HandlingUser; | ||
public readonly Sync<string> AccessReason; | ||
public readonly Sync<float> ConnectRetryInterval; | ||
public readonly Sync<bool> IsConnected; | ||
|
||
private Uri _currentURL; | ||
private UdpClient _udpClient; | ||
|
||
public event Action<ArtNetReceiver> Connected; | ||
public event Action<ArtNetReceiver> Closed; | ||
public event Action<ArtNetReceiver, string> Error; | ||
public event Action<ArtNetReceiver, byte[]> PacketReceived; | ||
|
||
protected override void OnAwake() | ||
{ | ||
base.OnAwake(); | ||
ConnectRetryInterval.Value = 10f; | ||
} | ||
|
||
protected override void OnChanges() | ||
{ | ||
Uri uri = (Enabled ? URL.Value : null); | ||
if (HandlingUser.Target != LocalUser) | ||
{ | ||
uri = null; | ||
} | ||
if (uri != _currentURL) | ||
{ | ||
_currentURL = uri; | ||
CloseCurrent(); | ||
IsConnected.Value = false; | ||
if (_currentURL != null) | ||
{ | ||
StartTask(async () => | ||
{ | ||
await ConnectTo(_currentURL); | ||
}); | ||
} | ||
} | ||
} | ||
|
||
private async Task ConnectTo(Uri target) | ||
{ | ||
if (target.Scheme != "artnet") | ||
{ | ||
throw new ArgumentException("Invalid URL scheme. Expected 'artnet://'."); | ||
} | ||
|
||
if (await Engine.Security.RequestAccessPermission(target.Host, target.Port, AccessReason.Value ?? "Art-Net Receiver") == HostAccessPermission.Allowed && target == _currentURL && !IsRemoved) | ||
{ | ||
_udpClient = new UdpClient(target.Port); | ||
IsConnected.Value = true; | ||
Connected?.Invoke(this); | ||
StartTask(ReceiveLoop); | ||
} | ||
} | ||
|
||
private async Task ReceiveLoop() | ||
{ | ||
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); | ||
while (IsConnected.Value) | ||
{ | ||
UdpReceiveResult result = await _udpClient.ReceiveAsync(); | ||
byte[] receivedData = result.Buffer; | ||
|
||
PacketReceived?.Invoke(this, receivedData); | ||
} | ||
} | ||
|
||
protected override void OnDispose() | ||
{ | ||
CloseCurrent(); | ||
base.OnDispose(); | ||
} | ||
|
||
private void CloseCurrent() | ||
{ | ||
if (_udpClient != null) | ||
{ | ||
UdpClient udpClient = _udpClient; | ||
_udpClient = null; | ||
try | ||
{ | ||
Closed?.Invoke(this); | ||
} | ||
catch (Exception ex) | ||
{ | ||
UniLog.Error($"Exception in running Closed event on ArtNetReceiver:\n{ex}"); | ||
} | ||
udpClient.Close(); | ||
} | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
NEOSPlus/Logix/Network/ART-NET/ArtNetChannelDataExtractor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using FrooxEngine; | ||
using FrooxEngine.LogiX; | ||
|
||
[Category("LogiX/Network/ART-NET")] | ||
public class ArtNetChannelDataExtractor : LogixNode | ||
{ | ||
public readonly Input<byte[]> Data; | ||
public readonly Input<int> Channel; | ||
public readonly Input<int> StartIndex; | ||
public readonly Output<byte> Output; | ||
|
||
public readonly Impulse OnEvaluationComplete; | ||
|
||
[ImpulseTarget] | ||
public void EvaluateData() | ||
{ | ||
byte[] data = Data.Evaluate(); | ||
int channel = Channel.Evaluate(); | ||
int startIndex = StartIndex.Evaluate(); | ||
|
||
if (data != null && data.Length > startIndex + channel - 1) | ||
{ | ||
Output.Value = data[startIndex + channel - 1]; | ||
} | ||
else | ||
{ | ||
Output.Value = 0; | ||
} | ||
|
||
// Triggering output impulse when data evaluation is complete | ||
OnEvaluationComplete.Trigger(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
using FrooxEngine; | ||
using FrooxEngine.LogiX; | ||
|
||
public abstract class ArtNetReceiverBaseNode : LogixNode | ||
{ | ||
public readonly Input<ArtNetReceiver> Receiver; | ||
|
||
private ArtNetReceiver _registered; | ||
|
||
protected override void OnChanges() | ||
{ | ||
base.OnChanges(); | ||
ArtNetReceiver artNetReceiver = Receiver.Evaluate(); | ||
if (artNetReceiver != _registered) | ||
{ | ||
Unregister(); | ||
if (artNetReceiver != null) | ||
{ | ||
Register(artNetReceiver); | ||
} | ||
_registered = artNetReceiver; | ||
} | ||
} | ||
|
||
protected abstract void Register(ArtNetReceiver receiver); | ||
|
||
protected abstract void Unregister(ArtNetReceiver receiver); | ||
|
||
private void Unregister() | ||
{ | ||
if (_registered != null) | ||
{ | ||
Unregister(_registered); | ||
} | ||
_registered = null; | ||
} | ||
|
||
protected override void OnDispose() | ||
{ | ||
Unregister(); | ||
base.OnDispose(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using System; | ||
using FrooxEngine; | ||
using FrooxEngine.LogiX; | ||
|
||
[Category(new string[] { "LogiX/Network/ART-NET" })] | ||
public class ArtNetReceiverConnect : LogixNode | ||
{ | ||
public readonly Input<ArtNetReceiver> Receiver; | ||
public readonly Input<Uri> URL; | ||
public readonly Input<User> HandlingUser; | ||
public readonly Impulse OnConnectStart; | ||
|
||
[ImpulseTarget] | ||
public void Connect() | ||
{ | ||
ArtNetReceiver artNetReceiver = Receiver.Evaluate(); | ||
if (artNetReceiver != null) | ||
{ | ||
Uri value = URL.Evaluate(artNetReceiver.URL.Value); | ||
User target = HandlingUser.Evaluate(base.LocalUser); | ||
artNetReceiver.URL.Value = value; | ||
artNetReceiver.HandlingUser.Target = target; | ||
OnConnectStart.Trigger(); | ||
} | ||
} | ||
} |
104 changes: 104 additions & 0 deletions
104
NEOSPlus/Logix/Network/ART-NET/ArtNetUniverseDataReceiver.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
using FrooxEngine; | ||
using FrooxEngine.LogiX; | ||
using System; | ||
using BaseX; | ||
|
||
[Category(new string[] { "LogiX/Network/ART-NET" })] | ||
|
||
public class ArtNetUniverseDataReceiver : ArtNetReceiverBaseNode | ||
{ | ||
public readonly Input<int> UniverseID; | ||
public readonly Impulse Received; | ||
public readonly Output<byte[]> Data; | ||
|
||
protected override void Register(ArtNetReceiver receiver) | ||
{ | ||
receiver.PacketReceived += OnArtNetPacketReceived; | ||
} | ||
|
||
protected override void Unregister(ArtNetReceiver receiver) | ||
{ | ||
receiver.PacketReceived -= OnArtNetPacketReceived; | ||
} | ||
|
||
private void OnArtNetPacketReceived(ArtNetReceiver receiver, byte[] data) | ||
{ | ||
// UniLog.Log("Packet received. Data length: " + data.Length); | ||
|
||
if (IsValidArtNetPacket(data)) | ||
{ | ||
// UniLog.Log("Data is a valid Art-Net packet"); | ||
|
||
int receivedUniverseID = ParseUniverseID(data); | ||
// UniLog.Log("Parsed Universe ID: " + receivedUniverseID); | ||
|
||
if (receivedUniverseID == UniverseID.Evaluate()) | ||
{ | ||
RunSynchronously(delegate | ||
{ | ||
byte[] dmxData = ExtractDMXData(data); | ||
Data.Value = dmxData; | ||
Received.Trigger(); | ||
}); | ||
} | ||
} | ||
else if (IsValidDMXPacket(data)) | ||
{ | ||
UniLog.Log("Data is a valid DMX packet"); | ||
|
||
RunSynchronously(delegate | ||
{ | ||
byte[] dmxData = ExtractDMXData(data); | ||
Data.Value = dmxData; | ||
Received.Trigger(); | ||
}); | ||
} | ||
else | ||
{ | ||
UniLog.Log("Received data is not a valid Art-Net or DMX packet."); | ||
} | ||
} | ||
|
||
private bool IsValidArtNetPacket(byte[] data) | ||
{ | ||
return data.Length >= 8 && System.Text.Encoding.ASCII.GetString(data, 0, 7) == "Art-Net"; | ||
} | ||
|
||
private bool IsValidDMXPacket(byte[] data) | ||
{ | ||
return data.Length >= 1 && data[0] == 0; | ||
} | ||
|
||
private int ParseUniverseID(byte[] data) | ||
{ | ||
// According to the Art-Net protocol, the Universe ID is stored as a 16-bit integer (2 bytes) with the Low Byte at offset 14 and High Byte at offset 15. | ||
int universeIDOffsetLowByte = 14; | ||
int universeIDOffsetHighByte = 15; | ||
|
||
int universeID = (data[universeIDOffsetHighByte] << 8) | data[universeIDOffsetLowByte]; | ||
|
||
// Additional logging details | ||
byte subuni = data[14]; | ||
string subnet = Convert.ToString(subuni >> 4); | ||
string universe = Convert.ToString(subuni & 0x0F); | ||
|
||
//UniLog.Log("Subnet: " + subnet); | ||
//UniLog.Log("Universe: " + universe); | ||
|
||
return universeID; | ||
} | ||
|
||
private byte[] ExtractDMXData(byte[] data) | ||
{ | ||
int dmxDataOffset = 18; | ||
int dmxDataLength = 512; // fixed size of DMX data | ||
|
||
byte[] dmxData = new byte[dmxDataLength]; | ||
Array.Copy(data, dmxDataOffset, dmxData, 0, dmxDataLength); | ||
|
||
string dmx = BitConverter.ToString(dmxData); | ||
UniLog.Log("DMX Data: " + dmx); | ||
|
||
return dmxData; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters