Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save smdn/48cbacb2c9553f7183a4e61facfc2926 to your computer and use it in GitHub Desktop.
Save smdn/48cbacb2c9553f7183a4e61facfc2926 to your computer and use it in GitHub Desktop.
Smdn.Net.EchonetLite.RouteB.SkStackIP 2.0.0-preview1 Release Notes

main/Smdn.Net.EchonetLite.RouteB.SkStackIP-2.0.0-preview1

diff --git a/doc/api-list/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP-net6.0.apilist.cs b/doc/api-list/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP-net6.0.apilist.cs
new file mode 100644
index 0000000..b635de6
--- /dev/null
+++ b/doc/api-list/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP-net6.0.apilist.cs
@@ -0,0 +1,101 @@
+// Smdn.Net.EchonetLite.RouteB.SkStackIP.dll (Smdn.Net.EchonetLite.RouteB.SkStackIP-2.0.0-preview1)
+// Name: Smdn.Net.EchonetLite.RouteB.SkStackIP
+// AssemblyVersion: 2.0.0.0
+// InformationalVersion: 2.0.0-preview1+93509882219e05b5d6a8c897a8bdfee251761d59
+// TargetFramework: .NETCoreApp,Version=v6.0
+// Configuration: Release
+// Referenced assemblies:
+// Microsoft.Extensions.DependencyInjection, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
+// Microsoft.Extensions.DependencyInjection.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
+// Microsoft.Extensions.Logging.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
+// Polly.Core, Version=8.0.0.0, Culture=neutral, PublicKeyToken=c8a3ffc3f8f825cc
+// Smdn.Net.EchonetLite.RouteB, Version=2.0.0.0, Culture=neutral
+// Smdn.Net.EchonetLite.Transport, Version=2.0.0.0, Culture=neutral
+// Smdn.Net.SkStackIP, Version=1.0.0.0, Culture=neutral
+// System.ComponentModel, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.ComponentModel.Primitives, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.Memory, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
+// System.Net.NetworkInformation, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.Net.Primitives, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.Runtime, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.Threading, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+#nullable enable annotations
+
+using System;
+using System.Buffers;
+using System.ComponentModel;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
+using Smdn.Net.EchonetLite.RouteB.Credentials;
+using Smdn.Net.EchonetLite.RouteB.Transport;
+using Smdn.Net.EchonetLite.RouteB.Transport.SkStackIP;
+using Smdn.Net.SkStackIP;
+
+namespace Smdn.Net.EchonetLite.RouteB.Transport.SkStackIP {
+ public interface ISkStackRouteBEchonetLiteHandlerFactory : IRouteBEchonetLiteHandlerFactory {
+ Action<SkStackRouteBSessionConfiguration>? ConfigureRouteBSessionConfiguration { get; set; }
+ }
+
+ public enum SkStackRouteBTransportProtocol : int {
+ Tcp = 0,
+ Udp = 1,
+ }
+
+ public abstract class SkStackRouteBEchonetLiteHandler : RouteBEchonetLiteHandler {
+ public static readonly string ResiliencePipelineKeyForSend = "SkStackRouteBEchonetLiteHandler.resiliencePipelineSend";
+
+ public override IPAddress? LocalAddress { get; }
+ public override IPAddress? PeerAddress { get; }
+ public override ISynchronizeInvoke? SynchronizingObject { get; set; }
+
+ protected override ValueTask ConnectAsyncCore(IRouteBCredential credential, CancellationToken cancellationToken) {}
+ protected override async ValueTask DisconnectAsyncCore(CancellationToken cancellationToken) {}
+ protected override void Dispose(bool disposing) {}
+ protected override async ValueTask DisposeAsyncCore() {}
+ protected override ValueTask<IPAddress> ReceiveAsyncCore(IBufferWriter<byte> buffer, CancellationToken cancellationToken) {}
+ protected override ValueTask SendAsyncCore(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken) {}
+ protected override ValueTask SendToAsyncCore(IPAddress remoteAddress, ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken) {}
+ [MemberNotNull("client")]
+ protected override void ThrowIfDisposed() {}
+ }
+
+ public static class SkStackRouteBEchonetLiteHandlerBuilderExtensions {
+ public static ISkStackRouteBEchonetLiteHandlerFactory ConfigureSession(this ISkStackRouteBEchonetLiteHandlerFactory factory, Action<SkStackRouteBSessionConfiguration> configureRouteBSessionConfiguration) {}
+ }
+
+ public abstract class SkStackRouteBEchonetLiteHandlerFactory : ISkStackRouteBEchonetLiteHandlerFactory {
+ protected SkStackRouteBEchonetLiteHandlerFactory(IServiceCollection services) {}
+
+ public Action<SkStackRouteBSessionConfiguration>? ConfigureRouteBSessionConfiguration { get; set; }
+ protected abstract SkStackRouteBTransportProtocol TransportProtocol { get; }
+
+ public virtual async ValueTask<RouteBEchonetLiteHandler> CreateAsync(CancellationToken cancellationToken) {}
+ protected abstract ValueTask<SkStackClient> CreateClientAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken);
+ }
+
+ public sealed class SkStackRouteBSessionConfiguration : ICloneable {
+ public SkStackRouteBSessionConfiguration() {}
+
+ public SkStackActiveScanOptions? ActiveScanOptions { get; set; }
+ public SkStackChannel? Channel { get; set; }
+ public IPAddress? PaaAddress { get; set; }
+ public PhysicalAddress? PaaMacAddress { get; set; }
+ public int? PanId { get; set; }
+
+ public SkStackRouteBSessionConfiguration Clone() {}
+ object ICloneable.Clone() {}
+ }
+
+ public sealed class SkStackRouteBTcpEchonetLiteHandler : SkStackRouteBEchonetLiteHandler {
+ public SkStackRouteBTcpEchonetLiteHandler(SkStackClient client, SkStackRouteBSessionConfiguration sessionConfiguration, bool shouldDisposeClient = false, IServiceProvider? serviceProvider = null) {}
+ }
+
+ public sealed class SkStackRouteBUdpEchonetLiteHandler : SkStackRouteBEchonetLiteHandler {
+ public SkStackRouteBUdpEchonetLiteHandler(SkStackClient client, SkStackRouteBSessionConfiguration sessionConfiguration, bool shouldDisposeClient = false, IServiceProvider? serviceProvider = null) {}
+ }
+}
+// API list generated by Smdn.Reflection.ReverseGenerating.ListApi.MSBuild.Tasks v1.4.1.0.
+// Smdn.Reflection.ReverseGenerating.ListApi.Core v1.3.1.0 (https://github.com/smdn/Smdn.Reflection.ReverseGenerating)
diff --git a/doc/api-list/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP-net8.0.apilist.cs b/doc/api-list/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP-net8.0.apilist.cs
new file mode 100644
index 0000000..6e971f0
--- /dev/null
+++ b/doc/api-list/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP-net8.0.apilist.cs
@@ -0,0 +1,101 @@
+// Smdn.Net.EchonetLite.RouteB.SkStackIP.dll (Smdn.Net.EchonetLite.RouteB.SkStackIP-2.0.0-preview1)
+// Name: Smdn.Net.EchonetLite.RouteB.SkStackIP
+// AssemblyVersion: 2.0.0.0
+// InformationalVersion: 2.0.0-preview1+93509882219e05b5d6a8c897a8bdfee251761d59
+// TargetFramework: .NETCoreApp,Version=v8.0
+// Configuration: Release
+// Referenced assemblies:
+// Microsoft.Extensions.DependencyInjection, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
+// Microsoft.Extensions.DependencyInjection.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
+// Microsoft.Extensions.Logging.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
+// Polly.Core, Version=8.0.0.0, Culture=neutral, PublicKeyToken=c8a3ffc3f8f825cc
+// Smdn.Net.EchonetLite.RouteB, Version=2.0.0.0, Culture=neutral
+// Smdn.Net.EchonetLite.Transport, Version=2.0.0.0, Culture=neutral
+// Smdn.Net.SkStackIP, Version=1.0.0.0, Culture=neutral
+// System.ComponentModel, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.ComponentModel.Primitives, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.Memory, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
+// System.Net.NetworkInformation, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.Net.Primitives, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.Threading, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+#nullable enable annotations
+
+using System;
+using System.Buffers;
+using System.ComponentModel;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
+using Smdn.Net.EchonetLite.RouteB.Credentials;
+using Smdn.Net.EchonetLite.RouteB.Transport;
+using Smdn.Net.EchonetLite.RouteB.Transport.SkStackIP;
+using Smdn.Net.SkStackIP;
+
+namespace Smdn.Net.EchonetLite.RouteB.Transport.SkStackIP {
+ public interface ISkStackRouteBEchonetLiteHandlerFactory : IRouteBEchonetLiteHandlerFactory {
+ Action<SkStackRouteBSessionConfiguration>? ConfigureRouteBSessionConfiguration { get; set; }
+ }
+
+ public enum SkStackRouteBTransportProtocol : int {
+ Tcp = 0,
+ Udp = 1,
+ }
+
+ public abstract class SkStackRouteBEchonetLiteHandler : RouteBEchonetLiteHandler {
+ public static readonly string ResiliencePipelineKeyForSend = "SkStackRouteBEchonetLiteHandler.resiliencePipelineSend";
+
+ public override IPAddress? LocalAddress { get; }
+ public override IPAddress? PeerAddress { get; }
+ public override ISynchronizeInvoke? SynchronizingObject { get; set; }
+
+ protected override ValueTask ConnectAsyncCore(IRouteBCredential credential, CancellationToken cancellationToken) {}
+ protected override async ValueTask DisconnectAsyncCore(CancellationToken cancellationToken) {}
+ protected override void Dispose(bool disposing) {}
+ protected override async ValueTask DisposeAsyncCore() {}
+ protected override ValueTask<IPAddress> ReceiveAsyncCore(IBufferWriter<byte> buffer, CancellationToken cancellationToken) {}
+ protected override ValueTask SendAsyncCore(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken) {}
+ protected override ValueTask SendToAsyncCore(IPAddress remoteAddress, ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken) {}
+ [MemberNotNull("client")]
+ protected override void ThrowIfDisposed() {}
+ }
+
+ public static class SkStackRouteBEchonetLiteHandlerBuilderExtensions {
+ public static ISkStackRouteBEchonetLiteHandlerFactory ConfigureSession(this ISkStackRouteBEchonetLiteHandlerFactory factory, Action<SkStackRouteBSessionConfiguration> configureRouteBSessionConfiguration) {}
+ }
+
+ public abstract class SkStackRouteBEchonetLiteHandlerFactory : ISkStackRouteBEchonetLiteHandlerFactory {
+ protected SkStackRouteBEchonetLiteHandlerFactory(IServiceCollection services) {}
+
+ public Action<SkStackRouteBSessionConfiguration>? ConfigureRouteBSessionConfiguration { get; set; }
+ protected abstract SkStackRouteBTransportProtocol TransportProtocol { get; }
+
+ public virtual async ValueTask<RouteBEchonetLiteHandler> CreateAsync(CancellationToken cancellationToken) {}
+ protected abstract ValueTask<SkStackClient> CreateClientAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken);
+ }
+
+ public sealed class SkStackRouteBSessionConfiguration : ICloneable {
+ public SkStackRouteBSessionConfiguration() {}
+
+ public SkStackActiveScanOptions? ActiveScanOptions { get; set; }
+ public SkStackChannel? Channel { get; set; }
+ public IPAddress? PaaAddress { get; set; }
+ public PhysicalAddress? PaaMacAddress { get; set; }
+ public int? PanId { get; set; }
+
+ public SkStackRouteBSessionConfiguration Clone() {}
+ object ICloneable.Clone() {}
+ }
+
+ public sealed class SkStackRouteBTcpEchonetLiteHandler : SkStackRouteBEchonetLiteHandler {
+ public SkStackRouteBTcpEchonetLiteHandler(SkStackClient client, SkStackRouteBSessionConfiguration sessionConfiguration, bool shouldDisposeClient = false, IServiceProvider? serviceProvider = null) {}
+ }
+
+ public sealed class SkStackRouteBUdpEchonetLiteHandler : SkStackRouteBEchonetLiteHandler {
+ public SkStackRouteBUdpEchonetLiteHandler(SkStackClient client, SkStackRouteBSessionConfiguration sessionConfiguration, bool shouldDisposeClient = false, IServiceProvider? serviceProvider = null) {}
+ }
+}
+// API list generated by Smdn.Reflection.ReverseGenerating.ListApi.MSBuild.Tasks v1.4.1.0.
+// Smdn.Reflection.ReverseGenerating.ListApi.Core v1.3.1.0 (https://github.com/smdn/Smdn.Reflection.ReverseGenerating)
diff --git a/doc/api-list/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP-netstandard2.1.apilist.cs b/doc/api-list/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP-netstandard2.1.apilist.cs
new file mode 100644
index 0000000..f638d45
--- /dev/null
+++ b/doc/api-list/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP-netstandard2.1.apilist.cs
@@ -0,0 +1,94 @@
+// Smdn.Net.EchonetLite.RouteB.SkStackIP.dll (Smdn.Net.EchonetLite.RouteB.SkStackIP-2.0.0-preview1)
+// Name: Smdn.Net.EchonetLite.RouteB.SkStackIP
+// AssemblyVersion: 2.0.0.0
+// InformationalVersion: 2.0.0-preview1+93509882219e05b5d6a8c897a8bdfee251761d59
+// TargetFramework: .NETStandard,Version=v2.1
+// Configuration: Release
+// Referenced assemblies:
+// Microsoft.Extensions.DependencyInjection, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
+// Microsoft.Extensions.DependencyInjection.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
+// Microsoft.Extensions.Logging.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
+// Polly.Core, Version=8.0.0.0, Culture=neutral, PublicKeyToken=c8a3ffc3f8f825cc
+// Smdn.Net.EchonetLite.RouteB, Version=2.0.0.0, Culture=neutral
+// Smdn.Net.EchonetLite.Transport, Version=2.0.0.0, Culture=neutral
+// Smdn.Net.SkStackIP, Version=1.0.0.0, Culture=neutral
+// netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
+#nullable enable annotations
+
+using System;
+using System.Buffers;
+using System.ComponentModel;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
+using Smdn.Net.EchonetLite.RouteB.Credentials;
+using Smdn.Net.EchonetLite.RouteB.Transport;
+using Smdn.Net.EchonetLite.RouteB.Transport.SkStackIP;
+using Smdn.Net.SkStackIP;
+
+namespace Smdn.Net.EchonetLite.RouteB.Transport.SkStackIP {
+ public interface ISkStackRouteBEchonetLiteHandlerFactory : IRouteBEchonetLiteHandlerFactory {
+ Action<SkStackRouteBSessionConfiguration>? ConfigureRouteBSessionConfiguration { get; set; }
+ }
+
+ public enum SkStackRouteBTransportProtocol : int {
+ Tcp = 0,
+ Udp = 1,
+ }
+
+ public abstract class SkStackRouteBEchonetLiteHandler : RouteBEchonetLiteHandler {
+ public static readonly string ResiliencePipelineKeyForSend = "SkStackRouteBEchonetLiteHandler.resiliencePipelineSend";
+
+ public override IPAddress? LocalAddress { get; }
+ public override IPAddress? PeerAddress { get; }
+ public override ISynchronizeInvoke? SynchronizingObject { get; set; }
+
+ protected override ValueTask ConnectAsyncCore(IRouteBCredential credential, CancellationToken cancellationToken) {}
+ protected override async ValueTask DisconnectAsyncCore(CancellationToken cancellationToken) {}
+ protected override void Dispose(bool disposing) {}
+ protected override async ValueTask DisposeAsyncCore() {}
+ protected override ValueTask<IPAddress> ReceiveAsyncCore(IBufferWriter<byte> buffer, CancellationToken cancellationToken) {}
+ protected override ValueTask SendAsyncCore(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken) {}
+ protected override ValueTask SendToAsyncCore(IPAddress remoteAddress, ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken) {}
+ protected override void ThrowIfDisposed() {}
+ }
+
+ public static class SkStackRouteBEchonetLiteHandlerBuilderExtensions {
+ public static ISkStackRouteBEchonetLiteHandlerFactory ConfigureSession(this ISkStackRouteBEchonetLiteHandlerFactory factory, Action<SkStackRouteBSessionConfiguration> configureRouteBSessionConfiguration) {}
+ }
+
+ public abstract class SkStackRouteBEchonetLiteHandlerFactory : ISkStackRouteBEchonetLiteHandlerFactory {
+ protected SkStackRouteBEchonetLiteHandlerFactory(IServiceCollection services) {}
+
+ public Action<SkStackRouteBSessionConfiguration>? ConfigureRouteBSessionConfiguration { get; set; }
+ protected abstract SkStackRouteBTransportProtocol TransportProtocol { get; }
+
+ public virtual async ValueTask<RouteBEchonetLiteHandler> CreateAsync(CancellationToken cancellationToken) {}
+ protected abstract ValueTask<SkStackClient> CreateClientAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken);
+ }
+
+ public sealed class SkStackRouteBSessionConfiguration : ICloneable {
+ public SkStackRouteBSessionConfiguration() {}
+
+ public SkStackActiveScanOptions? ActiveScanOptions { get; set; }
+ public SkStackChannel? Channel { get; set; }
+ public IPAddress? PaaAddress { get; set; }
+ public PhysicalAddress? PaaMacAddress { get; set; }
+ public int? PanId { get; set; }
+
+ public SkStackRouteBSessionConfiguration Clone() {}
+ object ICloneable.Clone() {}
+ }
+
+ public sealed class SkStackRouteBTcpEchonetLiteHandler : SkStackRouteBEchonetLiteHandler {
+ public SkStackRouteBTcpEchonetLiteHandler(SkStackClient client, SkStackRouteBSessionConfiguration sessionConfiguration, bool shouldDisposeClient = false, IServiceProvider? serviceProvider = null) {}
+ }
+
+ public sealed class SkStackRouteBUdpEchonetLiteHandler : SkStackRouteBEchonetLiteHandler {
+ public SkStackRouteBUdpEchonetLiteHandler(SkStackClient client, SkStackRouteBSessionConfiguration sessionConfiguration, bool shouldDisposeClient = false, IServiceProvider? serviceProvider = null) {}
+ }
+}
+// API list generated by Smdn.Reflection.ReverseGenerating.ListApi.MSBuild.Tasks v1.4.1.0.
+// Smdn.Reflection.ReverseGenerating.ListApi.Core v1.3.1.0 (https://github.com/smdn/Smdn.Reflection.ReverseGenerating)
diff --git a/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP.csproj b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP.csproj
new file mode 100644
index 0000000..b3ba9ab
--- /dev/null
+++ b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP.csproj
@@ -0,0 +1,46 @@
+<!--
+SPDX-FileCopyrightText: 2024 smdn <smdn@smdn.jp>
+SPDX-License-Identifier: MIT
+-->
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <TargetFrameworks>net8.0;net6.0;netstandard2.1</TargetFrameworks>
+ <VersionPrefix>2.0.0</VersionPrefix>
+ <VersionSuffix>preview1</VersionSuffix>
+ <!-- <PackageValidationBaselineVersion>2.0.0</PackageValidationBaselineVersion> -->
+ <Nullable>enable</Nullable>
+ <RootNamespace/> <!-- empty the root namespace so that the namespace is determined only by the directory name, for code style rule IDE0030 -->
+ <NoWarn>CS1591;$(NoWarn)</NoWarn> <!-- CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member' -->
+ </PropertyGroup>
+
+ <PropertyGroup Label="metadata">
+ <Description>
+<![CDATA[Skyley Networksの[SKSTACK IP](https://www.skyley.com/wiki/?SKSTACK+IP+for+HAN)を使用して、 スマート電力量メータとの情報伝達手段である「Bルート」を介したECHONET Lite規格の通信を扱うためのAPIを提供します。
+ECHONET Lite規格における下位通信層に相当する実装である`SkStackRouteBUdpEchonetLiteHandler`クラスをはじめとするAPIを提供します。
+]]>
+ </Description>
+ <CopyrightYear>2024</CopyrightYear>
+ </PropertyGroup>
+
+ <PropertyGroup Label="package properties">
+ <PackageTags>SKSTACK;SKSTACK-IP;Route-B;B-Route;smart-meter;smart-energy-meter;$(PackageTags)</PackageTags>
+ <GenerateNupkgReadmeFileDependsOnTargets>$(GenerateNupkgReadmeFileDependsOnTargets);GenerateReadmeFileContent</GenerateNupkgReadmeFileDependsOnTargets>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Microsoft.Extensions.DependencyInjection" />
+ <PackageReference Include="Smdn.Net.SkStackIP" />
+ <ProjectOrPackageReference Include="$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Smdn.Net.EchonetLite.RouteB\Smdn.Net.EchonetLite.RouteB.csproj'))" />
+ </ItemGroup>
+
+ <Target Name="GenerateReadmeFileContent">
+ <PropertyGroup>
+ <PackageReadmeFileContent><![CDATA[# $(PackageId) $(PackageVersion)
+$(Description)
+
+## Contributing
+This project welcomes contributions, feedbacks and suggestions. You can contribute to this project by submitting [Issues]($(RepositoryUrl)/issues/new/choose) or [Pull Requests]($(RepositoryUrl)/pulls/) on the [GitHub repository]($(RepositoryUrl)).
+]]></PackageReadmeFileContent>
+ </PropertyGroup>
+ </Target>
+</Project>
diff --git a/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/ISkStackRouteBEchonetLiteHandlerFactory.cs b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/ISkStackRouteBEchonetLiteHandlerFactory.cs
new file mode 100644
index 0000000..a254ec2
--- /dev/null
+++ b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/ISkStackRouteBEchonetLiteHandlerFactory.cs
@@ -0,0 +1,9 @@
+// SPDX-FileCopyrightText: 2023 smdn <smdn@smdn.jp>
+// SPDX-License-Identifier: MIT
+using System;
+
+namespace Smdn.Net.EchonetLite.RouteB.Transport.SkStackIP;
+
+public interface ISkStackRouteBEchonetLiteHandlerFactory : IRouteBEchonetLiteHandlerFactory {
+ Action<SkStackRouteBSessionConfiguration>? ConfigureRouteBSessionConfiguration { get; set; }
+}
diff --git a/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBEchonetLiteHandler.cs b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBEchonetLiteHandler.cs
new file mode 100644
index 0000000..c1cb411
--- /dev/null
+++ b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBEchonetLiteHandler.cs
@@ -0,0 +1,312 @@
+// SPDX-FileCopyrightText: 2023 smdn <smdn@smdn.jp>
+// SPDX-License-Identifier: MIT
+
+using System;
+using System.Buffers;
+using System.ComponentModel;
+#if SYSTEM_DIAGNOSTICS_CODEANALYSIS_MEMBERNOTNULLATTRIBUTE
+using System.Diagnostics.CodeAnalysis;
+#endif
+using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+
+using Polly;
+using Polly.Registry;
+
+using Smdn.Net.EchonetLite.RouteB.Credentials;
+using Smdn.Net.SkStackIP;
+
+namespace Smdn.Net.EchonetLite.RouteB.Transport.SkStackIP;
+
+public abstract class SkStackRouteBEchonetLiteHandler : RouteBEchonetLiteHandler {
+ public static readonly string ResiliencePipelineKeyForSend = nameof(SkStackRouteBEchonetLiteHandler) + "." + nameof(resiliencePipelineSend);
+
+ private SkStackClient? client;
+ private readonly bool shouldDisposeClient;
+ private readonly SkStackRouteBSessionConfiguration sessionConfiguration;
+ private readonly ResiliencePipeline? resiliencePipelineSend;
+ private SkStackPanaSessionInfo? panaSessionInfo;
+ private SemaphoreSlim semaphore = new(initialCount: 1, maxCount: 1);
+
+ /// <inheritdoc/>
+ public override ISynchronizeInvoke? SynchronizingObject {
+#if !SYSTEM_DIAGNOSTICS_CODEANALYSIS_MEMBERNOTNULLATTRIBUTE
+#pragma warning disable CS8602
+#endif
+ get { ThrowIfDisposed(); return client.SynchronizingObject; }
+ set { ThrowIfDisposed(); client.SynchronizingObject = value; }
+#pragma warning restore CS8602
+ }
+
+ /// <inheritdoc/>
+ public override IPAddress? LocalAddress => panaSessionInfo?.LocalAddress;
+
+ /// <inheritdoc/>
+ public override IPAddress? PeerAddress => panaSessionInfo?.PeerAddress;
+
+ private protected SkStackClient Client {
+ get {
+ ThrowIfDisposed();
+
+#if !SYSTEM_DIAGNOSTICS_CODEANALYSIS_MEMBERNOTNULLATTRIBUTE
+#pragma warning disable CS8603
+#endif
+ return client;
+#pragma warning restore CS8603
+ }
+ }
+
+ private protected SkStackRouteBEchonetLiteHandler(
+ SkStackClient client,
+ SkStackRouteBSessionConfiguration sessionConfiguration,
+ bool shouldDisposeClient = false,
+ IServiceProvider? serviceProvider = null // TODO: logger
+ )
+ {
+ this.client = client ?? throw new ArgumentNullException(nameof(client));
+ this.sessionConfiguration = (sessionConfiguration ?? throw new ArgumentNullException(nameof(sessionConfiguration))).Clone(); // holds the clone to avoid being affected from the changes to the original
+ this.shouldDisposeClient = shouldDisposeClient;
+
+ _ = serviceProvider?.GetService<ILoggerFactory>(); // TODO
+
+ var resiliencePipelineProvider = serviceProvider?.GetService<ResiliencePipelineProvider<string>>();
+
+ _ = resiliencePipelineProvider?.TryGetPipeline(ResiliencePipelineKeyForSend, out resiliencePipelineSend);
+ }
+
+ /// <inheritdoc/>
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+
+ DisposeCore();
+ }
+
+ /// <inheritdoc/>
+ protected override async ValueTask DisposeAsyncCore()
+ {
+ await base.DisposeAsyncCore().ConfigureAwait(false);
+
+ DisposeCore();
+ }
+
+ private void DisposeCore()
+ {
+ if (shouldDisposeClient)
+ client?.Dispose();
+
+ client = null;
+
+ panaSessionInfo = null;
+
+ semaphore?.Dispose();
+ semaphore = null!;
+ }
+
+#if SYSTEM_DIAGNOSTICS_CODEANALYSIS_MEMBERNOTNULLATTRIBUTE
+ [MemberNotNull(nameof(client))]
+#endif
+ protected override void ThrowIfDisposed()
+ {
+#pragma warning disable CA1513
+ if (client is null)
+ throw new ObjectDisposedException(GetType().FullName);
+#pragma warning restore CA1513
+
+ base.ThrowIfDisposed();
+ }
+
+ protected override ValueTask ConnectAsyncCore(
+ IRouteBCredential credential,
+ CancellationToken cancellationToken
+ )
+ {
+#pragma warning disable CA1510
+ if (credential is null)
+ throw new ArgumentNullException(nameof(credential));
+#pragma warning restore CA1510
+
+ ThrowIfDisposed();
+ ThrowIfReceiving();
+
+ var shouldPerformActiveScan =
+ !sessionConfiguration.Channel.HasValue ||
+ !sessionConfiguration.PanId.HasValue ||
+ (
+ sessionConfiguration.PaaMacAddress is null &&
+ sessionConfiguration.PaaAddress is null
+ );
+
+ // TODO: reduce allocation
+ var rbidBufferWriter = new ArrayBufferWriter<byte>(initialCapacity: RouteBCredentials.AuthenticationIdLength);
+ var passwordBufferWriter = new ArrayBufferWriter<byte>(initialCapacity: RouteBCredentials.PasswordLength);
+
+ credential.WriteIdTo(rbidBufferWriter);
+ credential.WritePasswordTo(passwordBufferWriter);
+
+ if (shouldPerformActiveScan) {
+ // obtain PAN information by active scan prior to initialization
+ return Core(
+ authenticateAsPanaClientAsync: (device, ct) => device.AuthenticateAsPanaClientAsync(
+ rbid: rbidBufferWriter.WrittenMemory,
+ password: passwordBufferWriter.WrittenMemory,
+ scanOptions: sessionConfiguration.ActiveScanOptions,
+ cancellationToken: ct
+ )
+ );
+ }
+ else {
+ var shouldResolvePaaAddress = sessionConfiguration.PaaAddress is null;
+
+ if (shouldResolvePaaAddress) {
+ return Core(
+ authenticateAsPanaClientAsync: (device, ct) => device.AuthenticateAsPanaClientAsync(
+ rbid: rbidBufferWriter.WrittenMemory,
+ password: passwordBufferWriter.WrittenMemory,
+ paaMacAddress: sessionConfiguration.PaaMacAddress!,
+ channel: sessionConfiguration.Channel!.Value,
+ panId: sessionConfiguration.PanId!.Value,
+ cancellationToken: ct
+ )
+ );
+ }
+ else {
+ return Core(
+ authenticateAsPanaClientAsync: (device, ct) => device.AuthenticateAsPanaClientAsync(
+ rbid: rbidBufferWriter.WrittenMemory,
+ password: passwordBufferWriter.WrittenMemory,
+ paaAddress: sessionConfiguration.PaaAddress!,
+ channel: sessionConfiguration.Channel!.Value,
+ panId: sessionConfiguration.PanId!.Value,
+ cancellationToken: ct
+ )
+ );
+ }
+ }
+
+#if !SYSTEM_DIAGNOSTICS_CODEANALYSIS_MEMBERNOTNULLATTRIBUTE
+#pragma warning disable CS8604
+#endif
+ async ValueTask Core(
+ Func<SkStackClient, CancellationToken, ValueTask<SkStackPanaSessionInfo>> authenticateAsPanaClientAsync
+ )
+ {
+ await PrepareConnectionAsync(cancellationToken).ConfigureAwait(false);
+
+ panaSessionInfo = await authenticateAsPanaClientAsync(
+ client,
+ cancellationToken
+ ).ConfigureAwait(false);
+ }
+#pragma warning restore CS8604
+ }
+
+ private protected abstract ValueTask PrepareConnectionAsync(CancellationToken cancellationToken);
+
+ protected override async ValueTask DisconnectAsyncCore(
+ CancellationToken cancellationToken
+ )
+ {
+ if (client is null)
+ return;
+ if (!client.IsPanaSessionAlive)
+ return;
+
+ _ = await client.TerminatePanaSessionAsync(cancellationToken: default).ConfigureAwait(false);
+ }
+
+ /// <inheritdoc/>
+ protected override ValueTask<IPAddress> ReceiveAsyncCore(
+ IBufferWriter<byte> buffer,
+ CancellationToken cancellationToken
+ )
+ {
+ ThrowIfDisposed();
+
+ return ReceiveEchonetLiteAsync(
+ buffer: buffer,
+ cancellationToken: cancellationToken
+ );
+ }
+
+ private protected abstract ValueTask<IPAddress> ReceiveEchonetLiteAsync(
+ IBufferWriter<byte> buffer,
+ CancellationToken cancellationToken
+ );
+
+ /// <inheritdoc/>
+ protected override ValueTask SendAsyncCore(
+ ReadOnlyMemory<byte> buffer,
+ CancellationToken cancellationToken
+ )
+ {
+ ThrowIfDisposed();
+
+#if !SYSTEM_DIAGNOSTICS_CODEANALYSIS_MEMBERNOTNULLATTRIBUTE
+#pragma warning disable CS8602, CS8604
+#endif
+ if (!client.IsPanaSessionAlive)
+ throw new InvalidOperationException("pana session terminated or expired");
+
+ return SendToAsyncCore(
+ remoteAddress: client.PanaSessionPeerAddress, // TODO: multicast
+ buffer: buffer,
+ cancellationToken: cancellationToken
+ );
+#pragma warning restore CS8602, CS8604
+ }
+
+ /// <inheritdoc/>
+ protected override ValueTask SendToAsyncCore(
+ IPAddress remoteAddress,
+ ReadOnlyMemory<byte> buffer,
+ CancellationToken cancellationToken
+ )
+ {
+#pragma warning disable CA1510
+ if (remoteAddress is null)
+ throw new ArgumentNullException(nameof(remoteAddress));
+#pragma warning restore CA1510
+
+ ThrowIfDisposed();
+
+#if !SYSTEM_DIAGNOSTICS_CODEANALYSIS_MEMBERNOTNULLATTRIBUTE
+#pragma warning disable CS8602
+#endif
+ if (!client.IsPanaSessionAlive)
+ throw new InvalidOperationException("pana session terminated or expired");
+ if (!client.PanaSessionPeerAddress.Equals(remoteAddress))
+ throw new NotSupportedException($"Sending to a specified remote address {remoteAddress} is not supported.");
+
+ return Core();
+
+ async ValueTask Core()
+ {
+ await semaphore.WaitAsync(
+ cancellationToken: cancellationToken
+ ).ConfigureAwait(false);
+
+ try {
+ await SendEchonetLiteAsync(
+ buffer: buffer,
+ resiliencePipeline: resiliencePipelineSend,
+ cancellationToken: cancellationToken
+ ).ConfigureAwait(false);
+ }
+ finally {
+ semaphore.Release();
+ }
+ }
+#pragma warning restore CS8602
+ }
+
+ private protected abstract ValueTask SendEchonetLiteAsync(
+ ReadOnlyMemory<byte> buffer,
+ ResiliencePipeline? resiliencePipeline,
+ CancellationToken cancellationToken
+ );
+}
diff --git a/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBEchonetLiteHandlerBuilderExtensions.cs b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBEchonetLiteHandlerBuilderExtensions.cs
new file mode 100644
index 0000000..1d8c973
--- /dev/null
+++ b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBEchonetLiteHandlerBuilderExtensions.cs
@@ -0,0 +1,24 @@
+// SPDX-FileCopyrightText: 2023 smdn <smdn@smdn.jp>
+// SPDX-License-Identifier: MIT
+using System;
+
+namespace Smdn.Net.EchonetLite.RouteB.Transport.SkStackIP;
+
+public static class SkStackRouteBEchonetLiteHandlerBuilderExtensions {
+ public static ISkStackRouteBEchonetLiteHandlerFactory ConfigureSession(
+ this ISkStackRouteBEchonetLiteHandlerFactory factory,
+ Action<SkStackRouteBSessionConfiguration> configureRouteBSessionConfiguration
+ )
+ {
+#pragma warning disable CA1510
+ if (factory is null)
+ throw new ArgumentNullException(nameof(factory));
+ if (configureRouteBSessionConfiguration is null)
+ throw new ArgumentNullException(nameof(configureRouteBSessionConfiguration));
+#pragma warning restore CA1510
+
+ factory.ConfigureRouteBSessionConfiguration = configureRouteBSessionConfiguration;
+
+ return factory;
+ }
+}
diff --git a/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBEchonetLiteHandlerFactory.cs b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBEchonetLiteHandlerFactory.cs
new file mode 100644
index 0000000..23c78e5
--- /dev/null
+++ b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBEchonetLiteHandlerFactory.cs
@@ -0,0 +1,64 @@
+// SPDX-FileCopyrightText: 2023 smdn <smdn@smdn.jp>
+// SPDX-License-Identifier: MIT
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Microsoft.Extensions.DependencyInjection;
+
+using Smdn.Net.SkStackIP;
+
+namespace Smdn.Net.EchonetLite.RouteB.Transport.SkStackIP;
+
+public abstract class SkStackRouteBEchonetLiteHandlerFactory(IServiceCollection services) : ISkStackRouteBEchonetLiteHandlerFactory {
+ private readonly IServiceCollection services = services;
+
+ public Action<SkStackRouteBSessionConfiguration>? ConfigureRouteBSessionConfiguration { get; set; }
+
+ /// <summary>
+ /// Gets the value specifying the transport protocol to be used by the handler which this factory creates.
+ /// </summary>
+ protected abstract SkStackRouteBTransportProtocol TransportProtocol { get; }
+
+ protected abstract ValueTask<SkStackClient> CreateClientAsync(
+ IServiceProvider serviceProvider,
+ CancellationToken cancellationToken
+ );
+
+ public virtual async ValueTask<RouteBEchonetLiteHandler> CreateAsync(
+ CancellationToken cancellationToken
+ )
+ {
+ var sessionConfiguration = new SkStackRouteBSessionConfiguration();
+
+ ConfigureRouteBSessionConfiguration?.Invoke(sessionConfiguration);
+
+ var serviceProvider = services.BuildServiceProvider();
+
+ var client = await CreateClientAsync(
+ serviceProvider: serviceProvider,
+ cancellationToken: cancellationToken
+ ).ConfigureAwait(false);
+
+ client.ReceiveResponseDelay = TimeSpan.FromMilliseconds(20); // TODO: make configurable
+ client.ReceiveUdpPollingInterval = TimeSpan.FromMilliseconds(50); // TODO: make configurable
+
+ return TransportProtocol switch {
+ SkStackRouteBTransportProtocol.Tcp => new SkStackRouteBTcpEchonetLiteHandler(
+ client: client,
+ sessionConfiguration: sessionConfiguration,
+ shouldDisposeClient: true,
+ serviceProvider: serviceProvider
+ ),
+
+ SkStackRouteBTransportProtocol.Udp => new SkStackRouteBUdpEchonetLiteHandler(
+ client: client,
+ sessionConfiguration: sessionConfiguration,
+ shouldDisposeClient: true,
+ serviceProvider: serviceProvider
+ ),
+
+ _ => throw new InvalidOperationException($"There is no hanlder that supports '{TransportProtocol}' for the transport protocol."),
+ };
+ }
+}
diff --git a/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBSessionConfiguration.cs b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBSessionConfiguration.cs
new file mode 100644
index 0000000..f80d27e
--- /dev/null
+++ b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBSessionConfiguration.cs
@@ -0,0 +1,59 @@
+// SPDX-FileCopyrightText: 2023 smdn <smdn@smdn.jp>
+// SPDX-License-Identifier: MIT
+
+using System;
+using System.Net;
+using System.Net.NetworkInformation;
+
+using Smdn.Net.SkStackIP;
+
+namespace Smdn.Net.EchonetLite.RouteB.Transport.SkStackIP;
+
+/// <summary>
+/// A class representing the Route B session configurations.
+/// </summary>
+public sealed class SkStackRouteBSessionConfiguration : ICloneable {
+ /// <summary>
+ /// Gets or sets the <see cref="IPAddress"/> representing the IP address of the PANA Authentication Agent (PAA), or Personal Area Network (PAN) coordinator.
+ /// </summary>
+ /// <remarks>
+ /// The PANA Authentication Agent (PAA) can also be specified with the MAC address by setting <see cref="PaaMacAddress"/>.
+ /// </remarks>
+ /// <seealso cref="PaaMacAddress"/>
+ public IPAddress? PaaAddress { get; set; }
+
+ /// <summary>
+ /// Gets or sets the <see cref="PhysicalAddress"/> representing the MAC address of the PANA Authentication Agent (PAA), or Personal Area Network (PAN) coordinator.
+ /// </summary>
+ /// <remarks>
+ /// The PANA Authentication Agent (PAA) can also be specified with the IP address by setting <see cref="PaaAddress"/>.
+ /// </remarks>
+ /// <seealso cref="PaaAddress"/>
+ public PhysicalAddress? PaaMacAddress { get; set; }
+
+ /// <summary>
+ /// Gets or sets the <see cref="SkStackChannel"/> representing the logical channel number used by this session.
+ /// </summary>
+ public SkStackChannel? Channel { get; set; }
+
+ /// <summary>
+ /// Gets or sets the value representing the Personal Area Network (PAN) ID used by this session.
+ /// </summary>
+ public int? PanId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the <see cref="SkStackActiveScanOptions"/> which specifying options for performing an active scan.
+ /// </summary>
+ public SkStackActiveScanOptions? ActiveScanOptions { get; set; }
+
+ public SkStackRouteBSessionConfiguration Clone()
+ => new() {
+ PaaAddress = this.PaaAddress,
+ PaaMacAddress = this.PaaMacAddress,
+ Channel = this.Channel,
+ PanId = this.PanId,
+ ActiveScanOptions = this.ActiveScanOptions?.Clone(),
+ };
+
+ object ICloneable.Clone() => Clone();
+}
diff --git a/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBTcpEchonetLiteHandler.cs b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBTcpEchonetLiteHandler.cs
new file mode 100644
index 0000000..779fa83
--- /dev/null
+++ b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBTcpEchonetLiteHandler.cs
@@ -0,0 +1,48 @@
+// SPDX-FileCopyrightText: 2024 smdn <smdn@smdn.jp>
+// SPDX-License-Identifier: MIT
+
+using System;
+using System.Buffers;
+using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Polly;
+
+using Smdn.Net.SkStackIP;
+
+namespace Smdn.Net.EchonetLite.RouteB.Transport.SkStackIP;
+
+public sealed class SkStackRouteBTcpEchonetLiteHandler : SkStackRouteBEchonetLiteHandler {
+ public SkStackRouteBTcpEchonetLiteHandler(
+ SkStackClient client,
+ SkStackRouteBSessionConfiguration sessionConfiguration,
+ bool shouldDisposeClient = false,
+ IServiceProvider? serviceProvider = null
+ )
+ : base(
+ client: client,
+ sessionConfiguration: sessionConfiguration,
+ shouldDisposeClient: shouldDisposeClient,
+ serviceProvider: serviceProvider
+ )
+ {
+ throw new NotImplementedException();
+ }
+
+ private protected override ValueTask PrepareConnectionAsync(CancellationToken cancellationToken)
+ => throw new NotImplementedException();
+
+ private protected override ValueTask<IPAddress> ReceiveEchonetLiteAsync(
+ IBufferWriter<byte> buffer,
+ CancellationToken cancellationToken
+ )
+ => throw new NotImplementedException();
+
+ private protected override ValueTask SendEchonetLiteAsync(
+ ReadOnlyMemory<byte> buffer,
+ ResiliencePipeline? resiliencePipeline,
+ CancellationToken cancellationToken
+ )
+ => throw new NotImplementedException();
+}
diff --git a/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBTransportProtocol.cs b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBTransportProtocol.cs
new file mode 100644
index 0000000..e4638e3
--- /dev/null
+++ b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBTransportProtocol.cs
@@ -0,0 +1,11 @@
+// SPDX-FileCopyrightText: 2024 smdn <smdn@smdn.jp>
+// SPDX-License-Identifier: MIT
+namespace Smdn.Net.EchonetLite.RouteB.Transport.SkStackIP;
+
+/// <summary>
+/// An enumeration type that defines the values representing the transport protocol.
+/// </summary>
+public enum SkStackRouteBTransportProtocol {
+ Tcp,
+ Udp,
+}
diff --git a/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBUdpEchonetLiteHandler.cs b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBUdpEchonetLiteHandler.cs
new file mode 100644
index 0000000..4f48213
--- /dev/null
+++ b/src/Smdn.Net.EchonetLite.RouteB.SkStackIP/Smdn.Net.EchonetLite.RouteB.SkStackIP/SkStackRouteBUdpEchonetLiteHandler.cs
@@ -0,0 +1,64 @@
+// SPDX-FileCopyrightText: 2024 smdn <smdn@smdn.jp>
+// SPDX-License-Identifier: MIT
+
+using System;
+using System.Buffers;
+using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Polly;
+
+using Smdn.Net.SkStackIP;
+
+namespace Smdn.Net.EchonetLite.RouteB.Transport.SkStackIP;
+
+public sealed class SkStackRouteBUdpEchonetLiteHandler : SkStackRouteBEchonetLiteHandler {
+ public SkStackRouteBUdpEchonetLiteHandler(
+ SkStackClient client,
+ SkStackRouteBSessionConfiguration sessionConfiguration,
+ bool shouldDisposeClient = false,
+ IServiceProvider? serviceProvider = null
+ )
+ : base(
+ client: client,
+ sessionConfiguration: sessionConfiguration,
+ shouldDisposeClient: shouldDisposeClient,
+ serviceProvider: serviceProvider
+ )
+ {
+ }
+
+ private protected override async ValueTask PrepareConnectionAsync(CancellationToken cancellationToken)
+ {
+ _ = await Client.PrepareUdpPortAsync(
+ port: SkStackKnownPortNumbers.Pana,
+ cancellationToken: cancellationToken
+ ).ConfigureAwait(false);
+
+ _ = await Client.PrepareUdpPortAsync(
+ port: SkStackKnownPortNumbers.EchonetLite,
+ cancellationToken: cancellationToken
+ ).ConfigureAwait(false);
+ }
+
+ private protected override ValueTask<IPAddress> ReceiveEchonetLiteAsync(
+ IBufferWriter<byte> buffer,
+ CancellationToken cancellationToken
+ )
+ => Client.ReceiveUdpEchonetLiteAsync(
+ buffer: buffer,
+ cancellationToken: cancellationToken
+ );
+
+ private protected override ValueTask SendEchonetLiteAsync(
+ ReadOnlyMemory<byte> buffer,
+ ResiliencePipeline? resiliencePipeline,
+ CancellationToken cancellationToken
+ )
+ => Client.SendUdpEchonetLiteAsync(
+ buffer: buffer,
+ resiliencePipeline: resiliencePipeline,
+ cancellationToken: cancellationToken
+ );
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment