GalaxySmartDeviceCore 1.0.56

dotnet add package GalaxySmartDeviceCore --version 1.0.56
                    
NuGet\Install-Package GalaxySmartDeviceCore -Version 1.0.56
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GalaxySmartDeviceCore" Version="1.0.56" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="GalaxySmartDeviceCore" Version="1.0.56" />
                    
Directory.Packages.props
<PackageReference Include="GalaxySmartDeviceCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add GalaxySmartDeviceCore --version 1.0.56
                    
#r "nuget: GalaxySmartDeviceCore, 1.0.56"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package GalaxySmartDeviceCore@1.0.56
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=GalaxySmartDeviceCore&version=1.0.56
                    
Install as a Cake Addin
#tool nuget:?package=GalaxySmartDeviceCore&version=1.0.56
                    
Install as a Cake Tool

GalaxySmartDeviceCore

银河 IoT 智能设备核心库,为串口、TCP 客户端、TCP 服务端和蓝牙设备提供统一的配置、连接、收发、分包与业务命令处理入口。

调用者负责设备协议、连接参数和业务逻辑;库负责将通讯数据接入设备事件、接收过滤器和命令分发流程。

目录

引用与运行环境

核心项目提供 net4.8netstandard2.0net8.0net9.0 目标,主要公开类型位于 GalaxySmartDeviceCore 命名空间。具体通讯能力还取决于操作系统、物理设备及底层实现。

引用仓库源码时,在应用项目中添加项目引用,路径按实际目录调整:

<ItemGroup>
  <ProjectReference Include="..\GalaxySmartDeviceCore\GalaxySmartDeviceCore\GalaxySmartDeviceCore.csproj" />
</ItemGroup>

使用已发布的 NuGet 包时:

dotnet add package GalaxySmartDeviceCore

本文对应当前仓库源码。自定义解析配置、Modbus RTU 主从解析器是否可用,取决于所安装包是否包含这些源码;如安装后找不到类型,请引用当前源码或包含这些功能的构建包。项目版本字段不等同于功能已经发布。

核心项目已声明 CSoft.Communication.Builder 10.6.2 等依赖,由项目引用或包引用传递。蓝牙通道还需应用提供 IBluetoothPhysicalPort 实现。

快速开始

下面是可放入控制台项目的完整示例:通过串口发送一条 Modbus RTU 读取请求,并监听从站响应。修改串口号和波特率后运行;设备协议须与示例请求一致。

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

// 仅使用接收事件时,仍需提供满足泛型约束的请求类型。
public sealed class RawRequest : IRequestInfo
{
    public string Key => "Raw";
}

public static class Program
{
    public static async Task Main()
    {
        var device = new Device<RawRequest>();
        device.Config = new CustomRPortDeviceConfig(device)
        {
            PortName = "COM3",
            BaudRate = 9600,
            ParserFactory = () => new ModbusRTUMasterParser(slaveAddress: 1)
        };

        device.ReceiveEvent += (data, sessionID) =>
        {
            Console.WriteLine("接收:" + BitConverter.ToString(data));
            return Task.CompletedTask;
        };

        try
        {
            int result = await device.ConnectAsync();
            if (result != 0)
            {
                Console.WriteLine("连接失败,返回码:" + result);
                return;
            }

            // 从站 1,功能码 03,起始地址 0,读取 10 个寄存器;末尾已包含 CRC。
            byte[] request = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x0A, 0xC5, 0xCD };
            int sendResult = await device.SendAsync(request);
            Console.WriteLine("发送返回码:" + sendResult);

            Console.WriteLine("按回车停止接收并断开连接。");
            Console.ReadLine();
        }
        catch (Exception ex)
        {
            // 配置错误、解析器创建等异常不一定会转换成返回码。
            Console.WriteLine(ex.Message);
        }
        finally
        {
            await device.DisconnectAsync();
        }
    }
}

这里的 SendAsync 只发送数据,响应通过 ReceiveEvent 到达。它不等待响应,也不自动生成协议字段或 CRC。只订阅接收事件时可以不设置 ReceiveFilter

选择通讯模式

先选择分包方式,再选择即时发送或队列发送。队列配置以 QS 开头,使用 SendInterval 指定发送间隔,默认 50 毫秒;发送间隔不代表响应超时。

接收方式 即时发送 PortMode 队列发送 PortMode 配置类前缀
触发式 / 时间或自定义分包 TrigR QueueSTrigR TrigR / QSTrigR
包头 + 包尾 HeadFootR QueueSHeadFootR HeadFootR / QSHeadFootR
包尾 FootR QueueSFootR FootR / QSFootR
包头 + 长度 HeadLengthR QueueSHeadLengthR HeadLengthR / QSHeadLengthR
自定义解析器 CustomR QueueSCustomR CustomR / QSCustomR
发送与响应绑定 SRBind 使用自身配置的发送间隔 SRBind

表中的模式均属于 TransferMode。完整配置类名由“前缀 + 通道后缀”组成:

通道 配置类后缀 示例
串口 PortDeviceConfig HeadFootRPortDeviceConfig
TCP 客户端 TCPClientDeviceConfig QSHeadFootRTCPClientDeviceConfig
TCP 服务端 TCPServerDeviceConfig CustomRTCPServerDeviceConfig
蓝牙 BluetoothDeviceConfig QSCustomRBluetoothDeviceConfig

配置类和 PortMode 必须匹配。 自定义解析配置的构造函数会设置 CustomRQueueSCustomR;使用其他现有配置时,应在初始化中显式填写对应的 PortMode。通道基础配置负责设置 CommMode,通常无须手动覆盖。

常用分包参数:

配置类别 主要参数
TrigR / QSTrigR UseNoParser、可选 ParserFactoryParserInterval(默认 20 毫秒);选择规则见下文
HeadFootR HeadFoot:按设备协议填写的字节数组
FootR Foot:按设备协议填写的结束标记
HeadLengthR HeadFootLengthModeIsLengthReverseIsLengthContainHeadIsLengthContainLengthIsLengthContainFoot
CustomR ParserFactory:创建独立分包解析器
SRBind 可选 ParserFactory;未设置时使用 ParserInterval 时间分包;TimeoutSendInterval

长度类配置中,Foot 还参与长度计算,不能将它理解为所有长度模式都会再次校验包尾。按实际帧结构设置各个长度包含标志;复杂协议可以改用自定义解析器。

TrigR / QSTrigR 的解析器选择

四类通道的 TrigR 和 QSTrigR 配置均支持可选的 ParserFactory。实际接收使用的解析器按以下顺序选择:

条件 接收行为
UseNoParser = true 使用 NoParser,不按业务协议分帧
UseNoParser = false 且设置了 ParserFactory 使用工厂返回的自定义解析器
UseNoParser = false 且未设置工厂 使用时间解析器,间隔由 ParserInterval 指定

UseNoParser 默认是 false。选择自定义解析器时,ParserInterval 不参与分包。蓝牙当前实现在选择 NoParser 前仍会调用已设置的工厂,因此使用原始接收时应不设置工厂。

例如,保留触发式接收模式,改用 RTU 主站解析器:

device.Config = new TrigRPortDeviceConfig(device)
{
    PortName = "COM3",
    BaudRate = 9600,
    PortMode = TransferMode.TrigR,
    UseNoParser = false,
    ParserFactory = () => new ModbusRTUMasterParser(1)
};

需要队列发送时,使用 QSTrigRPortDeviceConfig,将 PortMode 设为 TransferMode.QueueSTrigR,并设置 SendInterval。这两种模式都通过 SendAsync 发送、ReceiveEvent 接收,不会因为使用自定义解析器而获得请求/响应绑定能力。

CustomR / QueueSCustomR 也保留可用,适合明确要求应用提供解析器的配置;与 TrigR 不同,它们没有缺省时间解析器。

配置不同通讯通道

以下片段中的 device 是已经创建的设备对象。先完成配置、订阅事件,再调用 ConnectAsync;切换配置前先停止当前通讯。

串口

device.Config = new HeadFootRPortDeviceConfig(device)
{
    PortName = "COM3",
    BaudRate = 115200,
    PortMode = TransferMode.HeadFootR,
    Head = new byte[] { 0xAA, 0x55 },
    Foot = new byte[] { 0x0D, 0x0A }
};

当前串口基础配置公开串口号和波特率,波特率默认 9600。不要假设配置支持未公开的数据位、校验位或停止位设置。

TCP 客户端

device.Config = new QSHeadFootRTCPClientDeviceConfig(device)
{
    ServerIP = "192.168.1.100",
    ServerPort = 40000,
    PortMode = TransferMode.QueueSHeadFootR,
    SendInterval = 50,
    Head = new byte[] { 0xAA, 0x55 },
    Foot = new byte[] { 0x0D, 0x0A }
};

ServerIPServerPort 是远端地址。基础配置还提供 KeepAliveKeepAliveTimeKeepAliveIntervalKeepAliveRetryCountNoDelay

TCP 服务端

device.Config = new QSCustomRTCPServerDeviceConfig(device)
{
    ServerIP = "127.0.0.1",
    ServerPort = 40000,
    DeviceMode = TCPServerDeviceMode.ONE_TO_MORE,
    SendInterval = 50,
    ParserFactory = () => new FixedLengthParser(4)
};

ServerIP 是本机监听地址;127.0.0.1 只用于本机访问,需要远程连接时请改为合适的本机地址。示例中的 FixedLengthParser 实现在下文。

DeviceMode 默认 ONE_TO_ONE,多设备场景使用 ONE_TO_MORE。IP 过滤使用 FilterMode = TCPServerFilterMode.IPDeviceIPList。如需限制重复连接,一对一模式使用 ConnectMode = Only_One,一对多模式使用 Only_One_By_IP;枚举类型为 TCPServerConnectMode,默认 None

蓝牙

应用先实现并创建 IBluetoothPhysicalPort,再配置:

// physicalPort 是应用提供的 IBluetoothPhysicalPort 实例。
device.Config = new CustomRBluetoothDeviceConfig(device)
{
    ID = "device-01",
    BTName = "MyDevice",
    BTMAC = "00:11:22:33:44:55",
    PhysicalPort = physicalPort,
    ParserFactory = () => new FixedLengthParser(4)
};

BTNamePhysicalPort 不能为空。物理口实现负责打开/关闭连接、发送数据,以及提供接收数据的 PipeReader

收发与连接管理

API 用法与返回值
ConnectAsync() 创建通讯口并连接;TCP 服务端为开始监听。约定 0 为成功,非 0 为失败
ConnectAsync(true) 请求首次连接失败后重连;TCP 服务端不适用,具体执行取决于所选通讯适配器
SendAsync(data, sessionID) 发送字节数组;约定 0 为成功,非 0 为失败,不表示对端业务已处理
SendWithRespAsync(tag, data, sessionID, timeout) 用于 SRBind 的请求/响应流程,返回响应字节数组;失败时可能返回 null
DisconnectAsync() 断开设备连接或停止整个 TCP 服务端

ConnectAsync 返回 1 通常表示未创建出通讯口;检查配置类型、模式及该配置要求的参数;CustomR / QueueSCustomR 需要提供 ParserFactory,TrigR 和 SRBind 的工厂则是可选项。打开通讯口失败可能返回 -1。仍须处理异常:配置为空、构造通讯对象或调用解析器工厂的异常可能直接抛出。

设备连接状态属性的实际名称是 IsConnnected(三个连续的 n),请按现有 API 拼写使用。TCP 服务端开始监听不代表已有客户端连接,不能只用该属性判断监听状态。

非服务端处于离线状态时,设备级 DisconnectAsync() 会直接返回;重新连接时也仅在在线状态下关闭旧通讯口。应用切换配置或结束重连任务时,应根据需要管理旧 DataPort 的生命周期。

接收事件

ReceiveEvent 的签名是 Task Handler(byte[] data, Guid sessionID)。分包模式下的 data 为解析器输出;使用 UseNoParser 时,单次事件数据不保证是一条完整业务消息。

ConnectEventDisconnectEventConnectInfoUpdateEvent 均携带会话 ID 和连接信息。TCP 服务端新增客户端不一定每次触发 ConnectEvent,后续连接可能通过 ConnectInfoUpdateEvent 通知。收包时以当前事件的 sessionID 识别来源。

事件处理返回 Task,避免 async void。UI 更新应由应用切回 UI 线程;事件回调中的异常应在应用内处理,避免影响后续数据处理。

TCP 服务端的定向发送与断开

向某个连接发送时,传入该连接接收事件携带的会话 ID:

await device.SendAsync(replyBytes, sessionID);

普通即时/队列发送的服务端适配器在未指定 sessionID 时向当前客户端发送;需要定向响应时务必传入 ID。

仅断开一个客户端时,调用服务端通讯接口:

if (device.DataPort is IDeviceCommunicationServer server)
{
    await server.DisconnectAsync(sessionID);
}

当前设备级 device.DisconnectAsync(sessionID) 在处理指定连接后还会继续断开整个通讯口,不应将它用于“只踢出单个客户端”。

SRBind 请求与响应

当前限制:TCP 服务端的 SRBind 适配器尚未实现请求/响应绑定,不应将其用于等待请求回复。该路径会为每个客户端创建解析器,但这不等于支持请求/响应绑定。服务端业务可使用普通/自定义分包模式,通过接收事件处理。

以下示例未设置 ParserFactory,继续使用默认时间分包。配置与调用配套使用,requestBytes 由应用按设备协议组装:

device.Config = new SRBindPortDeviceConfig(device)
{
    PortName = "COM3",
    BaudRate = 9600,
    PortMode = TransferMode.SRBind,
    ParserInterval = 20,
    Timeout = 1000,
    SendInterval = 50
};

// 配置完成后先连接,再调用:
byte[] response = await device.SendWithRespAsync(
    "ReadStatus", requestBytes, timeout: 1000);

tag 是应用自己的业务标记,会交给带 tag 参数的接收过滤器,不会作为协议字段自动添加到发送数据。示例显式指定调用超时,单位为毫秒。设备级方法的 timeout 默认值是 0,并非自动采用配置的 Timeout;使用正数指定本次超时,或传入 -1 使用 SRBind 底层配置的默认超时。

串口、TCP 客户端和蓝牙的 SRBind 配置均支持可选的 ParserFactory。以下为使用 Modbus RTU 主站解析器的串口配置:

device.Config = new SRBindPortDeviceConfig(device)
{
    CommMode = CommunicationMode.SERIAL_PORT,
    PortName = "COM3",
    BaudRate = 9600,
    PortMode = TransferMode.SRBind,
    Timeout = 1000,
    SendInterval = 50,
    ParserFactory = () => new ModbusRTUMasterParser(1)
};

// 配置完成后先连接;requestBytes 为应用组装的完整 RTU 请求(含 CRC)。
byte[] response = await device.SendWithRespAsync(
    "ReadTemperature", requestBytes, timeout: 1000);
  • 未设置工厂时,串口使用 WithTimeParser(config.ParserInterval);TCP 客户端和蓝牙使用 new TimeParser(config.ParserInterval),保留原有行为。
  • 设置工厂后使用其返回的解析器,ParserInterval 不参与分包;TimeoutSendInterval 继续沿用原有请求/响应流程。
  • 单连接通道每次创建通讯对象时调用工厂,应用应返回独立的新解析器实例。应在连接前配置,不支持运行中替换;修改配置后需重新创建通讯对象,底层自动重连不保证重新调用工厂。
  • 自定义解析器负责分包,SRBind 负责现有请求/响应绑定。RTU 回复没有事务号,读寄存器回复也不包含起始地址;自定义分包不能排除超时后迟到回复与下一条请求错配的风险,应用仍需处理超时恢复。

CustomR / QueueSCustomR 和普通 Top 分包模式不提供 SRBind 的请求绑定能力,应使用 SendAsyncReceiveEvent。在 SRBind 配置中指定自定义解析器仍然属于 SRBind 模式,可以使用 SendWithRespAsync

SRBind 收到回复时仍会触发 ReceiveEvent 和不带 tag 的过滤器;SendWithRespAsync 取得回复后还会调用带 tag 的过滤器。若按请求标记分发业务,建议让不带 tag 的重载返回 null,只在带 tag 的重载中设置 IRequestInfo.Key = tag,避免同一回复重复执行业务。当前 Demo 的 LaserReceiveFilter 即采用此方式。

业务解析与命令分发

分包与业务解析是两个阶段:

通讯字节流 → IParser 分包 → ReceiveEvent
                         → IReceiveFilter<TRequestInfo>
                         → IRequestInfo.Key → 对应命令

IParser 负责找出完整帧;IReceiveFilter<TRequestInfo> 将帧转换成业务请求。过滤器返回 null 表示不分发命令,不影响此前已经触发的接收事件。

若需要命令分发,定义具体设备类、请求类型和接收过滤器:

using System;
using GalaxySmartDeviceCore;

namespace MyApp
{
    public sealed class SampleRequest : IRequestInfo
    {
        public string Key => "HandleFrame";
        public byte[] Data { get; }

        public SampleRequest(byte[] data)
        {
            Data = data;
        }
    }

    public sealed class SampleReceiveFilter : IReceiveFilter<SampleRequest>
    {
        public SampleRequest ResolveRequestInfo(byte[] data, Guid sessionID)
        {
            if (data == null || data.Length == 0)
                return null;

            // 示例将完整帧交给同一命令;实际项目在这里按功能码等字段设置 Key。
            return new SampleRequest(data);
        }

        public SampleRequest ResolveRequestInfo(string tag, byte[] data, Guid sessionID)
        {
            return ResolveRequestInfo(data, sessionID);
        }
    }

    public sealed class SampleDevice : Device<SampleRequest>
    {
        public SampleDevice()
        {
            ReceiveFilter = new SampleReceiveFilter();
            Config = new CustomRPortDeviceConfig(this)
            {
                PortName = "COM3",
                BaudRate = 9600,
                ParserFactory = () => new ModbusRTUMasterParser(1)
            };
        }
    }
}

在同一程序集添加命令:

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

namespace MyApp.SampleDeviceCommand
{
    public sealed class HandleFrame : CommandBase<MyApp.SampleRequest>
    {
        public override Task ExecuteCommand(
            MyApp.SampleRequest requestInfo, Guid sessionID)
        {
            Console.WriteLine(BitConverter.ToString(requestInfo.Data));
            return Task.CompletedTask;
        }
    }
}

调用 new MyApp.SampleDevice() 并连接后,框架会发现并加载命令。默认发现规则:

  • 扫描具体设备类型所在的程序集。
  • 命令命名空间以“具体设备类名 + Command”结尾,示例为 SampleDeviceCommand
  • 命令为非抽象类,实现匹配请求类型的命令接口,提供可用的公共无参构造函数。
  • IRequestInfo.Key 匹配命令的 Name,默认名称为命令类名;匹配不区分大小写,命令名称不能重复。

单纯使用 Device<RawRequest> 加接收事件即可完成收发;需要自动发现应用命令时,使用上面这样的具体设备子类。

自定义分包解析器

自定义解析器可用于 TrigR / QSTrigR、CustomR / QueueSCustomR,以及 SRBind 配置。前两种触发式配置和 SRBind 允许不设置工厂;CustomR 配置要求提供工厂。TCP 服务端 SRBind 的限制见前文。

所有四类通道都提供普通和 QS 自定义配置,例如 CustomRPortDeviceConfigQSCustomRTCPServerDeviceConfig。配置 ParserFactory = () => new MyParser() 即可,无须自行创建通讯口或修改工厂。

解析器实现 Parser.Interfaces.IParser,或继承 Parser.Parsers.BaseParser。下面是可直接放入应用的定长分包示例:

using System;
using System.Buffers;
using Parser.Parsers;

public sealed class FixedLengthParser : BaseParser
{
    private readonly int length;

    public FixedLengthParser(int length) : base(false)
    {
        if (length <= 0)
            throw new ArgumentOutOfRangeException(nameof(length));

        this.length = length;
    }

    protected override SequencePosition? FindStartPosition(
        ReadOnlySequence<byte> sequence)
    {
        return sequence.Start;
    }

    protected override SequencePosition? FindEndPosition(
        ReadOnlySequence<byte> sequence, SequencePosition startPosition)
    {
        var remaining = sequence.Slice(startPosition);
        return remaining.Length >= length
            ? remaining.GetPosition(length)
            : (SequencePosition?)null;
    }
}

此示例每 length 字节输出一帧,适合说明扩展方式;它不验证帧头或校验码。返回空结束位置时,由基类保留数据等待后续字节。构造中的 base(false) 不启用额外的解析结果处理队列。

以下约定适用于 CustomR / QueueSCustomR 配置;SRBind 的可选工厂及默认时间分包行为见“SRBind 请求与响应”:

  • 每次调用工厂必须返回独立、非空的新实例,不使用 () => sharedParser。TCP 服务端可能并发调用工厂。
  • 单连接通道在创建通讯对象时创建解析器;TCP 服务端在每个客户端接入时创建解析器,分别维护分包缓存。
  • 实际收包调用 RunAsync(PipeReader, CancellationToken)。直接实现接口时,仅实现 ReceiveOriginalDataAsync 不足以接入实际通讯。
  • 配置应在连接前完成。通讯对象捕获当时的工厂委托,替换配置委托不会热更新已有通讯对象;委托捕获的外部可变状态由应用管理。
  • 底层自动重连沿用原有生命周期,不保证每次自动重连重新调用工厂。
  • CustomR / QueueSCustomR 缺少工厂时无法通过创建校验。应用负责返回可用的解析器;当前辅助方法直接调用工厂,不统一检查返回值或规定空返回值的异常类型。工厂自身异常不回退为时间解析器;服务端工厂在客户端接入时调用。
  • 工厂是运行时 C# 委托,不能直接作为 JSON/XML 配置保存;应用加载连接配置后再赋值。TrigR / QSTrigR 与 SRBind 的可选工厂同样遵循此约定。

Modbus RTU 主站与从站

库内提供两个分离的解析器,均位于 GalaxySmartDeviceCore 命名空间:

解析器 使用方 / 接收内容 地址规则
ModbusRTUMasterParser(byte? slaveAddress = null, int maxAduLength = 256) 主站接收从站响应 指定时只接收该从站;null 接收 1~247;不接收地址 0
ModbusRTUSlaveParser(byte? stationAddress = null, int maxAduLength = 256) 从站接收主站请求 指定时接收本站及地址 0;null 接收 0~247

显式指定的地址必须为 1~247。主站与从站表示当前应用在协议中的角色,不表示 TCP 客户端或服务端角色。

// 主站:读取地址为 1 的从站响应。
var masterConfig = new CustomRPortDeviceConfig(device)
{
    PortName = "COM3",
    BaudRate = 9600,
    ParserFactory = () => new ModbusRTUMasterParser(slaveAddress: 1)
};

// 从站:接收发给本站 1 的请求,以及广播请求。
var slaveConfig = new CustomRPortDeviceConfig(device)
{
    PortName = "COM4",
    BaudRate = 9600,
    ParserFactory = () => new ModbusRTUSlaveParser(stationAddress: 1)
};

按当前应用角色选择一个配置赋给 device.Config,再连接。完整主站收发流程见“快速开始”。

两个解析器都会保留并输出完整 RTU 帧(地址、功能码、数据、CRC),支持半包、粘包、CRC 校验和前导噪声恢复。大批粘包分批处理,不按固定输入总长度截断合法帧。

当前支持的功能码长度规则(十六进制):

01 / 02 / 03 / 04 / 05 / 06 / 07 / 08 / 0B / 0C / 0F / 10 / 11 / 14 / 15 / 16 / 17 / 18 / 2B

  • 主站额外识别功能码高位为 1 的五字节异常响应。
  • 2B 只支持 MEI 0E08 按八字节帧处理,不覆盖其他可变长度诊断格式。
  • 最大帧长由构造参数 maxAduLength 指定,默认 256 字节;不支持的功能码、非法长度候选和 CRC 错误候选会被跳过。
  • 分帧依据是功能码长度与 CRC,不实现串口静默时间分帧;这不是完整的协议业务校验器。
  • 分包优先等待最早的合法半包候选,不提前提取其内部看似有效的帧。若噪声恰好构成合法帧头/长度,也会等待数据补齐后再校验;当前不设置半包等待超时。
  • 解析器不会自动生成 CRC、发送响应、执行寄存器读写、匹配请求或重试。相关逻辑由应用实现。
  • 解析器只处理 RTU 帧。若通过 TCP 传输使用它,输入也必须是 RTU 帧格式。

常见问题

现象 检查方向
找不到 CustomR 或 ModbusRTU 类型 所引用包可能未包含当前源码功能,确认引用来源
连接返回 1 检查配置类型与 PortMode 是否匹配,以及对应配置所需的端口名、服务端地址、蓝牙物理口;CustomR / QueueSCustomR 还需设置 ParserFactory
已连接但无完整帧回调 检查所选解析器、帧结构、站号、CRC、长度定义;排除只实现 ReceiveOriginalDataAsync 而遗漏 RunAsync
收到数据但命令没执行 检查 ReceiveFilter 是否返回非空请求,以及 Key、命令名称、命名空间后缀和程序集
自定义模式调用 SendWithRespAsync 没得到响应 改用 SendAsync 与接收事件;需要请求/响应绑定时使用 SRBind 并匹配其分包方式
多客户端数据混在一起 确保 ParserFactory 每次返回新实例,并按 sessionID 区分设备
服务端定向回复发给了其他客户端 SendAsync 未传 sessionID 时可能发送到多个连接,应传入原接收事件的会话 ID
服务端监听后 IsConnnected 仍为 false 该属性与客户端连接状态有关,开始监听不等于客户端已接入
UI 事件处理报跨线程错误 将 UI 更新切回 UI 线程

构建与示例

以下命令在仓库根目录运行:

# 构建核心库全部目标框架,不生成 NuGet 包。
dotnet build GalaxySmartDeviceCore/GalaxySmartDeviceCore/GalaxySmartDeviceCore.csproj -p:GeneratePackageOnBuild=false

全目标构建需要对应的 .NET SDK / 目标框架支持。核心库可以单独构建,无须先构建 WPF Demo。

Demo 是 Windows WPF / .NET Framework 4.8 项目。使用安装了 .NET 桌面开发工作负载和对应目标包的 Visual Studio 打开 GalaxySmartDeviceCore/GalaxySmartDeviceCore.sln,还原依赖后,将 GalaxySmartDeviceCoreDemo 设为启动项目。也可在 Visual Studio Developer PowerShell 中构建:

msbuild GalaxySmartDeviceCore/GalaxySmartDeviceCoreDemo/GalaxySmartDeviceCoreDemo.csproj /t:Build /p:Configuration=Debug /p:GeneratePackageOnBuild=false

当前仓库未保留 CustomParserAcceptance 控制台验收项目,不能使用旧文档中的验收命令。编译通过不代表真实串口、蓝牙或设备协议已完成联调。

现有 Demo 可参考:

示例 当前用法
LaserDevice 串口/TCP 客户端使用 SRBind 与 ModbusRTUMasterParserLaserReceiveFilter 按 tag 分发到命令。其 TCP 服务端配置仍受 SRBind 限制
VEDevice TrigR 配置自定义 ModbusRTUSlaveParser,通过事件接收
VOCsDevice QSTrigR 配置自定义 ModbusRTUSlaveParser,按发送间隔发送并通过事件接收

示例中的端口号、站号、寄存器地址和业务数据应按实际设备修改;主站或从站解析器由本应用接收的帧类型决定。

源码入口:

  • 核心库:GalaxySmartDeviceCore/GalaxySmartDeviceCore
  • 使用示例项目:GalaxySmartDeviceCore/GalaxySmartDeviceCoreDemo
  • RTU 解析器:GalaxySmartDeviceCore/GalaxySmartDeviceCore/Parser/Modbus/RTU
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 is compatible.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (7)

Showing the top 5 NuGet packages that depend on GalaxySmartDeviceCore:

Package Downloads
MeteorPushVOCs

流星般地快速、即时地向第三方平台/设备推送数据与消息【春来色谱VOCs产品平台】

BWBluetoothLowEnergy

低功耗蓝牙(Bluetooth Low Energy)技术是专门针对基于物联网(IoT)设备构建的无线应用功能,最大特点是降低成本和功耗。它可满足小型电池供电的设备进行低功耗无线连接的要求,极大地延长电池寿命。目前,蓝牙低功耗技术已被广泛使用,可用的应用场景:资产跟踪,运动及健身传感器,医疗传感器,智能手表,遥控器,玩具等。因此,开发该低功耗蓝牙(BLE,Bluetooth Low Energy)设备功能库以简化运行在10.0.17763.0(1809)版本及更高版本的Windows 10以上系统的低功耗蓝牙设备进行数据传输。

FTIRSpectrometerBusiness

傅里叶红外光谱商用库是为傅里叶红外光谱产品服务的配套模块,基于设备私有网络应用层通信协议开发。它提供了一组功能强大的接口和工具,方便用户对傅里叶红外光谱产品进行操作和控制,具有高度可定制、高效稳定、易于使用、灵活可扩展等特点。

FTIRFunctionBoardCore

傅里叶红外光谱仪(FTIR)功能板核心库,通过统一的API接口为开发者可便捷地完成功能板的功能控制。该核心库采用模块化架构,降低FTIR系统集成复杂度,加速产品开发周期。

GBHJ2122017Transfer

HJ212-2017《污染源在线自动监控(监测)系统数据传输标准》传输中心库,旨在为设备提供更便利、更简洁的开发模式以更快捷地对接智能工业设备数据。

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.56 0 9/17/2026
1.0.55 3 9/17/2026
1.0.54 740 7/8/2026
1.0.53 431 6/7/2026
1.0.52 120 6/7/2026
1.0.51 134 6/3/2026
1.0.50 216 5/27/2026
1.0.49 172 5/25/2026
1.0.48 159 5/25/2026
1.0.47 164 5/21/2026
1.0.46 338 4/28/2026
1.0.45 126 4/17/2026
1.0.44 142 3/26/2026
1.0.43 299 1/14/2026
1.0.42 153 1/13/2026
1.0.41 234 1/8/2026
1.0.40 926 12/11/2025
1.0.39 632 11/17/2025
1.0.38 341 10/30/2025
1.0.37 822 9/9/2025
Loading failed

更新内容:
设备类增加发送事件功能。