diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 700537b..037c5f2 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -1,32 +1,32 @@
-name: push_nuget
-
-# on push on main
-on:
- push:
- branches:
- - main
- paths-ignore:
- - README.md
-
-jobs:
- build:
- runs-on: windows-latest
- steps:
- - name: Git Checkout
+name: push_nuget
+
+# on push on main
+on:
+ push:
+ branches:
+ - main
+ paths-ignore:
+ - README.md
+
+jobs:
+ build:
+ runs-on: windows-latest
+ steps:
+ - name: Git Checkout
uses: actions/checkout@master
with:
- lfs: 'true'
-
- - name: Setup MSBuild.exe
- uses: microsoft/setup-msbuild@v2
-
- - name: Setup Nuget.exe
- uses: nuget/setup-nuget@v2.0.0
-
- - name: Publish VL Nuget
- uses: vvvv/PublishVLNuget@1.0.43
- with:
- nuspec: deployment\VL.Devices.RPLidar.nuspec
- icon-src: https://raw.githubusercontent.com/vvvv/PublicContent/master/nugeticon.png
- icon-dst: ./deployment/nugeticon.png
- nuget-key: ${{ secrets.VVVV_ORG_NUGET_KEY }}
+ lfs: 'true'
+
+ - name: Setup MSBuild.exe
+ uses: microsoft/setup-msbuild@v2
+
+ - name: Setup Nuget.exe
+ uses: nuget/setup-nuget@v2.0.0
+
+ - name: Publish VL Nuget
+ uses: vvvv/PublishVLNuget@1.0.43
+ with:
+ nuspec: deployment\VL.Devices.RPLidar.nuspec
+ icon-src: https://raw.githubusercontent.com/vvvv/PublicContent/master/nugeticon.png
+ icon-dst: ./deployment/nugeticon.png
+ nuget-key: ${{ secrets.VVVV_ORG_NUGET_KEY }}
diff --git a/Directory.Packages.props b/Directory.Packages.props
new file mode 100644
index 0000000..4ee6eb2
--- /dev/null
+++ b/Directory.Packages.props
@@ -0,0 +1,6 @@
+
+
+ 2025.7.1
+ 0.5.0
+
+
diff --git a/VL.Devices.RPLidar.slnx b/VL.Devices.RPLidar.slnx
new file mode 100644
index 0000000..485e74f
--- /dev/null
+++ b/VL.Devices.RPLidar.slnx
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/VL.Devices.RPLidar.vl b/VL.Devices.RPLidar.vl
index 96f5efb..3bc3b55 100644
--- a/VL.Devices.RPLidar.vl
+++ b/VL.Devices.RPLidar.vl
@@ -1,5 +1,5 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Toggle
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Bang
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Bang
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Bang
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Properties/AsseblyInfo.cs b/src/Properties/AsseblyInfo.cs
new file mode 100644
index 0000000..05aee89
--- /dev/null
+++ b/src/Properties/AsseblyInfo.cs
@@ -0,0 +1,3 @@
+using VL.Core.Import;
+
+[assembly: ImportAsIs(Namespace = "VL.Devices.RPLidar.Advanced", Category = "Devices.RPLidar.Advanced")]
diff --git a/src/Properties/launchSettings.json b/src/Properties/launchSettings.json
new file mode 100644
index 0000000..eb43916
--- /dev/null
+++ b/src/Properties/launchSettings.json
@@ -0,0 +1,13 @@
+{
+ "profiles": {
+ "VL.Devices.RPLidar.Advanced": {
+ "commandName": "Project"
+ },
+ "dev/antokhio": {
+ "commandName": "Executable",
+ "executablePath": "C:\\Program Files\\vvvv\\vvvv_gamma_7.1-win-x64\\vvvv.exe",
+ "commandLineArgs": " --allow-multiple --package-repositories ..\\..\\; --editable-packages VL.Devices.RPLidar*;",
+ "workingDirectory": "$(ProjectDir)"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/RPLidarUDPSocketNode.cs b/src/RPLidarUDPSocketNode.cs
new file mode 100644
index 0000000..225f1fa
--- /dev/null
+++ b/src/RPLidarUDPSocketNode.cs
@@ -0,0 +1,178 @@
+using RPLidar4Net.Api.Data;
+using RPLidar4Net.Api.Helpers;
+using System.Net;
+using System.Net.Sockets;
+using VL.Core.Import;
+using VL.Lib.Basics.Resources;
+using VL.Lib.Collections;
+using NetSocket = System.Net.Sockets.Socket;
+
+namespace VL.Devices.RPLidar.Advanced
+{
+ public enum RPLidarUDPState
+ {
+ Idle,
+ ScanSimple,
+ ScanDense,
+ ScanHighQuality,
+ NextPacketIsInfo,
+ }
+
+ public enum RPLidarUDPWorkMode
+ {
+ Legacy = 0x0,
+ Unknown1 = 0x1,
+ Unknown2 = 0x2,
+ }
+
+ public static class RPLidarUDPSocketHelper
+ {
+ public static bool IPEndPointEquals(IPEndPoint? input, IPEndPoint? input2)
+ {
+ if (ReferenceEquals(input, input2))
+ return true;
+ if (ReferenceEquals(input, null))
+ return false;
+ return input.Equals(input2);
+ }
+
+ public static byte[] FormatCommand(Command command, byte[] payload, bool includePayloadSize)
+ {
+ byte commandByte = CommandHelper.GetByte(command);
+
+ var packetBytes = new List();
+ packetBytes.Add(Constants.SYNC_BYTE);
+ packetBytes.Add(commandByte);
+
+ //Add payload
+ if (payload != null)
+ {
+ if (includePayloadSize)
+ packetBytes.Add((byte)payload.Length);
+ packetBytes.AddRange(payload);
+ byte checksum = 0;
+ foreach (var b in packetBytes)
+ checksum ^= b;
+ packetBytes.Add(checksum);
+ }
+
+ var packet = packetBytes.ToArray();
+
+ return packet;
+ }
+
+ public static byte[] RESPONSE_DESCRIPTOR_GET_INFO = new byte[]
+ {
+ 0xA5,
+ 0x5A,
+ 0x14,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x4,
+ };
+
+ public static bool IsGetInfoResponse(Spread bytes) =>
+ bytes.ToArray().SequenceEqual(RESPONSE_DESCRIPTOR_GET_INFO);
+
+ public static InfoDataResponse ReadInfoDataResponse(byte[] bytes) =>
+ InfoDataResponseHelper.ToInfoDataResponse(bytes);
+
+ public static byte[] RESPONSE_DESCRIPTOR_SCAN_SCAN = new byte[]
+ {
+ 0xA5,
+ 0x5A,
+ 0x05,
+ 0x0,
+ 0x0,
+ 0x40,
+ 0x81,
+ };
+ public static byte[] RESPONSE_DESCRIPTOR_SCAN_DENSE = new byte[]
+ {
+ 0xA5,
+ 0x5A,
+ 0x54,
+ 0x00,
+ 0x00,
+ 0x40,
+ 0x85,
+ };
+ public static byte[] RESPONSE_DESCRIPTOR_SCAN_HIGHQL = new byte[]
+ {
+ 0xA5,
+ 0x5A,
+ 0x0D,
+ 0x03,
+ 0x0,
+ 0x40,
+ 0x83,
+ };
+
+ public static bool IsScanResponse(byte[] bytes) =>
+ bytes.SequenceEqual(RESPONSE_DESCRIPTOR_SCAN_SCAN);
+
+ public static bool IsScanDenseResponse(byte[] bytes) =>
+ bytes.SequenceEqual(RESPONSE_DESCRIPTOR_SCAN_DENSE);
+
+ public static bool IsScanHightQlResponse(byte[] bytes) =>
+ bytes.SequenceEqual(RESPONSE_DESCRIPTOR_SCAN_HIGHQL);
+
+ public static byte[] FormattedExpressScanCommand(
+ RPLidarUDPWorkMode wm = RPLidarUDPWorkMode.Legacy
+ ) =>
+ //FormatCommand(Command.ExpressScan, CommandHelper.GetExpressScanPayload((byte)wm), true);
+ RPLidarUDPSocketHelper.FormatCommand(
+ Command.ExpressScan,
+ new byte[] { (byte)wm, 0x0, 0x0, 0x0, 0x0 },
+ true
+ );
+ }
+
+ [ProcessNode(Name = "RPLidar", Category = "RPLidar.UDPSocket")]
+ public class RPLidarUDPSocketNode
+ {
+ ResourceProviderMonitor? _provider;
+ private bool _connect = false;
+ private IPEndPoint? _remoteEndpoint;
+
+ public IResourceProvider Update(
+ IPEndPoint remoteEndpoint,
+ bool connect,
+ bool enabled = true
+ )
+ {
+ if (
+ !RPLidarUDPSocketHelper.IPEndPointEquals(_remoteEndpoint, remoteEndpoint)
+ || _connect != connect
+ )
+ {
+ _connect = connect;
+ _remoteEndpoint = remoteEndpoint;
+
+ _provider = ResourceProvider
+ .New(() =>
+ {
+ var socket = new NetSocket(SocketType.Dgram, ProtocolType.Udp);
+ socket.ExclusiveAddressUse = false;
+ socket.SetSocketOption(
+ SocketOptionLevel.Socket,
+ SocketOptionName.ReuseAddress,
+ true
+ );
+ if (connect && remoteEndpoint != null)
+ socket.Connect(remoteEndpoint);
+ return socket;
+ })
+ .ShareInParallel()
+ .Monitor();
+ }
+
+ if (enabled)
+ return _provider;
+ return null;
+ }
+
+ public bool IsOpen => _provider?.SinkCount > 0;
+ }
+}
diff --git a/src/VL.Devices.RPLidar.Advanced.csproj b/src/VL.Devices.RPLidar.Advanced.csproj
new file mode 100644
index 0000000..861c664
--- /dev/null
+++ b/src/VL.Devices.RPLidar.Advanced.csproj
@@ -0,0 +1,14 @@
+
+
+ net8.0
+ enable
+ enable
+ ..\lib\
+
+
+
+
+
+
+
+
diff --git a/src/VL.Devices.RPLidar.Advanced.csproj.user b/src/VL.Devices.RPLidar.Advanced.csproj.user
new file mode 100644
index 0000000..f470b28
--- /dev/null
+++ b/src/VL.Devices.RPLidar.Advanced.csproj.user
@@ -0,0 +1,9 @@
+
+
+
+ ProjectDebugger
+
+
+ dev/antokhio
+
+
\ No newline at end of file