GalaxySmartDeviceCore 1.0.56
dotnet add package GalaxySmartDeviceCore --version 1.0.56
NuGet\Install-Package GalaxySmartDeviceCore -Version 1.0.56
<PackageReference Include="GalaxySmartDeviceCore" Version="1.0.56" />
<PackageVersion Include="GalaxySmartDeviceCore" Version="1.0.56" />
<PackageReference Include="GalaxySmartDeviceCore" />
paket add GalaxySmartDeviceCore --version 1.0.56
#r "nuget: GalaxySmartDeviceCore, 1.0.56"
#:package GalaxySmartDeviceCore@1.0.56
#addin nuget:?package=GalaxySmartDeviceCore&version=1.0.56
#tool nuget:?package=GalaxySmartDeviceCore&version=1.0.56
GalaxySmartDeviceCore
银河 IoT 智能设备核心库,为串口、TCP 客户端、TCP 服务端和蓝牙设备提供统一的配置、连接、收发、分包与业务命令处理入口。
调用者负责设备协议、连接参数和业务逻辑;库负责将通讯数据接入设备事件、接收过滤器和命令分发流程。
目录
引用与运行环境
核心项目提供 net4.8、netstandard2.0、net8.0、net9.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 必须匹配。 自定义解析配置的构造函数会设置 CustomR 或 QueueSCustomR;使用其他现有配置时,应在初始化中显式填写对应的 PortMode。通道基础配置负责设置 CommMode,通常无须手动覆盖。
常用分包参数:
| 配置类别 | 主要参数 |
|---|---|
| TrigR / QSTrigR | UseNoParser、可选 ParserFactory、ParserInterval(默认 20 毫秒);选择规则见下文 |
| HeadFootR | Head、Foot:按设备协议填写的字节数组 |
| FootR | Foot:按设备协议填写的结束标记 |
| HeadLengthR | Head、Foot、LengthMode、IsLengthReverse、IsLengthContainHead、IsLengthContainLength、IsLengthContainFoot |
| CustomR | ParserFactory:创建独立分包解析器 |
| SRBind | 可选 ParserFactory;未设置时使用 ParserInterval 时间分包;Timeout、SendInterval |
长度类配置中,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 }
};
ServerIP 和 ServerPort 是远端地址。基础配置还提供 KeepAlive、KeepAliveTime、KeepAliveInterval、KeepAliveRetryCount、NoDelay。
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.IP 和 DeviceIPList。如需限制重复连接,一对一模式使用 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)
};
BTName 和 PhysicalPort 不能为空。物理口实现负责打开/关闭连接、发送数据,以及提供接收数据的 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 时,单次事件数据不保证是一条完整业务消息。
ConnectEvent、DisconnectEvent、ConnectInfoUpdateEvent 均携带会话 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不参与分包;Timeout和SendInterval继续沿用原有请求/响应流程。 - 单连接通道每次创建通讯对象时调用工厂,应用应返回独立的新解析器实例。应在连接前配置,不支持运行中替换;修改配置后需重新创建通讯对象,底层自动重连不保证重新调用工厂。
- 自定义解析器负责分包,SRBind 负责现有请求/响应绑定。RTU 回复没有事务号,读寄存器回复也不包含起始地址;自定义分包不能排除超时后迟到回复与下一条请求错配的风险,应用仍需处理超时恢复。
CustomR / QueueSCustomR 和普通 Top 分包模式不提供 SRBind 的请求绑定能力,应使用 SendAsync 与 ReceiveEvent。在 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 自定义配置,例如 CustomRPortDeviceConfig、QSCustomRTCPServerDeviceConfig。配置 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只支持 MEI0E;08按八字节帧处理,不覆盖其他可变长度诊断格式。- 最大帧长由构造参数
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 与 ModbusRTUMasterParser;LaserReceiveFilter 按 tag 分发到命令。其 TCP 服务端配置仍受 SRBind 限制 |
VEDevice |
TrigR 配置自定义 ModbusRTUSlaveParser,通过事件接收 |
VOCsDevice |
QSTrigR 配置自定义 ModbusRTUSlaveParser,按发送间隔发送并通过事件接收 |
示例中的端口号、站号、寄存器地址和业务数据应按实际设备修改;主站或从站解析器由本应用接收的帧类型决定。
源码入口:
- 核心库:
GalaxySmartDeviceCore/GalaxySmartDeviceCore - 使用示例项目:
GalaxySmartDeviceCore/GalaxySmartDeviceCoreDemo - RTU 解析器:
GalaxySmartDeviceCore/GalaxySmartDeviceCore/Parser/Modbus/RTU
| Product | Versions 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. |
-
.NETFramework 4.8
- BreezyWuAttribute (>= 1.0.4)
- CSoft.Communication.Builder (>= 10.6.2)
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.12)
-
.NETStandard 2.0
- BreezyWuAttribute (>= 1.0.4)
- CSoft.Communication.Builder (>= 10.6.2)
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.12)
-
net10.0
- BreezyWuAttribute (>= 1.0.4)
- CSoft.Communication.Builder (>= 10.6.2)
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.12)
-
net8.0
- BreezyWuAttribute (>= 1.0.4)
- CSoft.Communication.Builder (>= 10.6.2)
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.12)
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 |
更新内容:
设备类增加发送事件功能。