Skip to content

Commit

Permalink
import Smdn.Devices.BP35XX
Browse files Browse the repository at this point in the history
  • Loading branch information
smdn committed Apr 6, 2024
1 parent 2fdbe43 commit f8f5d71
Show file tree
Hide file tree
Showing 21 changed files with 1,379 additions and 0 deletions.
29 changes: 29 additions & 0 deletions src/Smdn.Devices.BP35XX/Smdn.Devices.BP35XX.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!--
SPDX-FileCopyrightText: 2021 smdn <smdn@smdn.jp>
SPDX-License-Identifier: MIT
-->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0;net6.0;netstandard2.1</TargetFrameworks>
<VersionPrefix>1.0.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
<!-- <PackageValidationBaselineVersion>1.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>Provides APIs to operate ROHM BP35A1 and other ROHM Wi-SUN modules using the SKSTACK-IP command.</Description>
<CopyrightYear>2021</CopyrightYear>
</PropertyGroup>

<PropertyGroup Label="package properties">
<PackageTags>SKSTACK,SKSTACK-IP,BP35A1,ROHM-BP35A1,Wi-SUN</PackageTags>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.IO.Ports" Version="8.0.0" />
<ProjectOrPackageReference ReferencePackageVersion="[1.0.0,2.0.0)" Include="..\Smdn.Net.SkStackIP\Smdn.Net.SkStackIP.csproj" />
</ItemGroup>
</Project>
63 changes: 63 additions & 0 deletions src/Smdn.Devices.BP35XX/Smdn.Devices.BP35XX/BP35A1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-FileCopyrightText: 2021 smdn <smdn@smdn.jp>
// SPDX-License-Identifier: MIT

using System;
using System.Threading;
using System.Threading.Tasks;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Smdn.Devices.BP35XX;

public class BP35A1 : BP35Base {
/// <summary>
/// Refer to the initial value of baud rate for UART setting in the BP35A1.
/// </summary>
/// <remarks>
/// See 'BP35A1コマンドリファレンス 3.32. WUART (プロダクト設定コマンド)' for detailed specifications.
/// </remarks>
internal const BP35UartBaudRate DefaultValueForBP35UartBaudRate = BP35UartBaudRate.Baud115200;

public static ValueTask<BP35A1> CreateAsync(
string? serialPortName,
IServiceProvider? serviceProvider = null,
CancellationToken cancellationToken = default
)
=> CreateAsync(
configurations: new BP35A1Configurations() {
SerialPortName = serialPortName,
},
serviceProvider: serviceProvider,
cancellationToken: cancellationToken
);

public static ValueTask<BP35A1> CreateAsync(
BP35A1Configurations configurations,
IServiceProvider? serviceProvider = null,
CancellationToken cancellationToken = default
)
=> InitializeAsync(
#pragma warning disable CA2000
device: new BP35A1(
configurations: configurations ?? throw new ArgumentNullException(nameof(configurations)),
serviceProvider: serviceProvider
),
#pragma warning restore CA2000
tryLoadFlashMemory: configurations.TryLoadFlashMemory,
serviceProvider: serviceProvider,
cancellationToken: cancellationToken
);

private BP35A1(
IBP35Configurations configurations,
IServiceProvider? serviceProvider = null
)
: base(
configurations: configurations,
serialPortStreamFactory: serviceProvider?.GetService<IBP35SerialPortStreamFactory>(),
logger: serviceProvider?.GetService<ILoggerFactory>()?.CreateLogger<BP35A1>()
)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: 2023 smdn <smdn@smdn.jp>
// SPDX-License-Identifier: MIT
using Smdn.Net.SkStackIP;

namespace Smdn.Devices.BP35XX;

public sealed class BP35A1Configurations : IBP35Configurations {
/// <inheritdoc cref="IBP35Configurations.SerialPortName"/>
public string? SerialPortName { get; set; }

/// <inheritdoc cref="IBP35Configurations.BaudRate"/>
public BP35UartBaudRate BaudRate { get; set; } = BP35A1.DefaultValueForBP35UartBaudRate;

/// <inheritdoc cref="IBP35Configurations.TryLoadFlashMemory"/>
public bool TryLoadFlashMemory { get; set; } = BP35Base.DefaultValueForTryLoadFlashMemory;

SkStackERXUDPDataFormat IBP35Configurations.ERXUDPDataFormat => SkStackERXUDPDataFormat.Binary;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// SPDX-FileCopyrightText: 2021 smdn <smdn@smdn.jp>
// SPDX-License-Identifier: MIT

using System;
using System.IO;
using System.IO.Ports;

namespace Smdn.Devices.BP35XX;

#pragma warning disable IDE0040
partial class BP35Base {
#pragma warning restore IDE0040
private class DefaultSerialPortStreamFactory : IBP35SerialPortStreamFactory {
public static DefaultSerialPortStreamFactory Instance { get; } = new();

public Stream CreateSerialPortStream(IBP35Configurations configurations)
{
if (string.IsNullOrEmpty(configurations.SerialPortName)) {
throw new ArgumentException(
message: $"The {nameof(configurations.SerialPortName)} is not set for the {configurations.GetType().Name}",
paramName: nameof(configurations)
);
}

const string CRLF = "\r\n";

#pragma warning disable CA2000
var port = new SerialPort(
portName: configurations.SerialPortName,
baudRate: configurations.BaudRate switch {
BP35UartBaudRate.Baud2400 => 2_400,
BP35UartBaudRate.Baud4800 => 4_800,
BP35UartBaudRate.Baud9600 => 9_600,
BP35UartBaudRate.Baud19200 => 19_200,
BP35UartBaudRate.Baud38400 => 38_400,
BP35UartBaudRate.Baud57600 => 57_600,
BP35UartBaudRate.Baud115200 => 115_200,
_ => throw new ArgumentException(
message: $"A valid {nameof(BP35UartBaudRate)} value is not set for the {configurations.GetType().Name}",
paramName: nameof(configurations)
),
},
parity: Parity.None,
dataBits: 8,
stopBits: StopBits.One
) {
Handshake = Handshake.None, // TODO: RequestToSend
DtrEnable = false,
RtsEnable = false,
NewLine = CRLF,
};
#pragma warning restore CA2000

port.Open();

// discard input buffer to avoid reading previously received data
port.DiscardInBuffer();

return port.BaseStream;
}
}
}
71 changes: 71 additions & 0 deletions src/Smdn.Devices.BP35XX/Smdn.Devices.BP35XX/BP35Base.Functions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-FileCopyrightText: 2021 smdn <smdn@smdn.jp>
// SPDX-License-Identifier: MIT

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Smdn.Devices.BP35XX;

#pragma warning disable IDE0040
partial class BP35Base {
#pragma warning restore IDE0040
public ValueTask SetUdpDataFormatAsync(
BP35UdpReceiveDataFormat format,
CancellationToken cancellationToken = default
)
{
return SendWOPTAsync(
mode: format switch {
BP35UdpReceiveDataFormat.Binary => BP35ERXUDPFormatBinary,
BP35UdpReceiveDataFormat.HexAscii => BP35ERXUDPFormatHexAscii,
_ => throw new ArgumentException($"undefined value of {nameof(BP35UdpReceiveDataFormat)}", nameof(format)),
},
cancellationToken: cancellationToken
);
}

public async ValueTask<BP35UdpReceiveDataFormat> GetUdpDataFormatAsync(
CancellationToken cancellationToken = default
)
{
var mode = await SendROPTAsync(
cancellationToken: cancellationToken
).ConfigureAwait(false);

return (mode & BP35ERXUDPFormatMask) switch {
BP35ERXUDPFormatBinary => BP35UdpReceiveDataFormat.Binary,
BP35ERXUDPFormatHexAscii => BP35UdpReceiveDataFormat.HexAscii,
_ => BP35UdpReceiveDataFormat.Binary, // XXX
};
}

public ValueTask SetUartOptionsAsync(
BP35UartBaudRate baudRate,
BP35UartCharacterInterval characterInterval = default,
BP35UartFlowControl flowControl = default,
CancellationToken cancellationToken = default
)
=> SetUartOptionsAsync(
uartConfigurations: new(baudRate, characterInterval, flowControl),
cancellationToken: cancellationToken
);

public ValueTask SetUartOptionsAsync(
BP35UartConfigurations uartConfigurations,
CancellationToken cancellationToken = default
)
=> SendWUARTAsync(
mode: uartConfigurations.Mode,
cancellationToken: cancellationToken
);

public async ValueTask<BP35UartConfigurations> GetUartOptionsAsync(
CancellationToken cancellationToken = default
)
{
var mode = await SendRUARTAsync(cancellationToken: cancellationToken).ConfigureAwait(false);

return new(mode);
}
}
140 changes: 140 additions & 0 deletions src/Smdn.Devices.BP35XX/Smdn.Devices.BP35XX/BP35Base.SkStackIP.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// SPDX-FileCopyrightText: 2021 smdn <smdn@smdn.jp>
// SPDX-License-Identifier: MIT

using System;
using System.Buffers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using Smdn.Formats;
using Smdn.Net.SkStackIP.Protocol;

namespace Smdn.Devices.BP35XX;

#pragma warning disable IDE0040
partial class BP35Base {
#pragma warning restore IDE0040
private static readonly SkStackProtocolSyntax RMCommandSyntax = new BP35CommandSyntax();

/// <remarks>
/// <para>See 'BP35A1コマンドリファレンス 3.30. WOPT (プロダクト設定コマンド)' for detailed specifications.</para>
/// </remarks>
private const byte BP35ERXUDPFormatMask = 0b_0000000_1;

/// <remarks>
/// <para>See 'BP35A1コマンドリファレンス 3.30. WOPT (プロダクト設定コマンド)' for detailed specifications.</para>
/// </remarks>
private const byte BP35ERXUDPFormatBinary = 0b_0000000_0;

/// <remarks>
/// <para>See 'BP35A1コマンドリファレンス 3.30. WOPT (プロダクト設定コマンド)' for detailed specifications.</para>
/// </remarks>
private const byte BP35ERXUDPFormatHexAscii = 0b_0000000_1;

/// <summary>
/// <para>Sends a command <c>WOPT</c>.</para>
/// </summary>
/// <remarks>
/// <para>See 'BP35A1コマンドリファレンス 3.30. WOPT (プロダクト設定コマンド)' for detailed specifications.</para>
/// </remarks>
private protected async ValueTask SendWOPTAsync(
byte mode,
CancellationToken cancellationToken = default
)
{
byte[]? modeBytes = null;

try {
modeBytes = ArrayPool<byte>.Shared.Rent(2);

_ = Hexadecimal.TryEncodeUpperCase(mode, modeBytes.AsSpan(), out var lengthOfMODE);

_ = await SendCommandAsync(
command: BP35CommandNames.WOPT,
writeArguments: writer => writer.WriteToken(modeBytes.AsSpan(0, lengthOfMODE)),
syntax: RMCommandSyntax,
cancellationToken: cancellationToken,
throwIfErrorStatus: true
).ConfigureAwait(false);
}
finally {
if (modeBytes is not null)
ArrayPool<byte>.Shared.Return(modeBytes);
}
}

/// <summary>
/// <para>Sends a command <c>ROPT</c>.</para>
/// </summary>
/// <remarks>
/// <para>See 'BP35A1コマンドリファレンス 3.31. ROPT (プロダクト設定コマンド)' for detailed specifications.</para>
/// </remarks>
private protected async ValueTask<byte> SendROPTAsync(
CancellationToken cancellationToken = default
)
{
var resp = await SendCommandAsync(
command: BP35CommandNames.ROPT,
writeArguments: null,
syntax: RMCommandSyntax,
cancellationToken: cancellationToken,
throwIfErrorStatus: true
).ConfigureAwait(false);

return Convert.ToByte(Encoding.ASCII.GetString(resp.StatusText.Span), 16);
}

/// <summary>
/// <para>Sends a command <c>WUART</c>.</para>
/// </summary>
/// <remarks>
/// <para>See 'BP35A1コマンドリファレンス 3.32. WUART (プロダクト設定コマンド)' for detailed specifications.</para>
/// </remarks>
private protected async ValueTask SendWUARTAsync(
byte mode,
CancellationToken cancellationToken = default
)
{
byte[]? modeBytes = null;

try {
modeBytes = ArrayPool<byte>.Shared.Rent(2);

_ = Hexadecimal.TryEncodeUpperCase(mode, modeBytes.AsSpan(), out var lengthOfMODE);

_ = await SendCommandAsync(
command: BP35CommandNames.WUART,
writeArguments: writer => writer.WriteToken(modeBytes.AsSpan(0, lengthOfMODE)),
syntax: RMCommandSyntax,
cancellationToken: cancellationToken,
throwIfErrorStatus: true
).ConfigureAwait(false);
}
finally {
if (modeBytes is not null)
ArrayPool<byte>.Shared.Return(modeBytes);
}
}

/// <summary>
/// <para>Sends a command <c>RUART</c>.</para>
/// </summary>
/// <remarks>
/// <para>See 'BP35A1コマンドリファレンス 3.33. RUART (プロダクト設定コマンド)' for detailed specifications.</para>
/// </remarks>
private protected async ValueTask<byte> SendRUARTAsync(
CancellationToken cancellationToken = default
)
{
var resp = await SendCommandAsync(
command: BP35CommandNames.RUART,
writeArguments: null,
syntax: RMCommandSyntax,
cancellationToken: cancellationToken,
throwIfErrorStatus: true
).ConfigureAwait(false);

return Convert.ToByte(Encoding.ASCII.GetString(resp.StatusText.Span), 16);
}
}

0 comments on commit f8f5d71

Please sign in to comment.