-
-
Notifications
You must be signed in to change notification settings - Fork 7
feat(ModbusCrc16): add modbus crc-16 algorithm #560
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 13 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
48e30ef
refactor: 更改回调名称
ArgoZhang 07af0a8
refactor: 恢复缓存变量
ArgoZhang 417d179
test: 提高 TryConvertTo 方法代码覆盖率
ArgoZhang 47fc252
test: 提高 HexConverter 代码覆盖率
ArgoZhang f0fcb7f
refactor: 优化代码
ArgoZhang 57996ce
refactor: 增加异常保护
ArgoZhang d8fd55e
test: 增加 SocketLogging 单元测试
ArgoZhang cf3c830
test: 增加 CreateInstance 扩展方法单元测试
ArgoZhang 1f8ad3f
feat: 增加 Modbus CRC-16 算法
ArgoZhang 0f43203
refactor: 更改参数类型
ArgoZhang 5eb4cc9
feat: 增加重载方法
ArgoZhang 4d6c4a5
chore: bump version 9.0.7
ArgoZhang 5509b62
test: 增加单元测试
ArgoZhang 7657c33
refactor: 更改命名空间
ArgoZhang edca3d4
chore: bump version 9.0.8
ArgoZhang File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
2 changes: 1 addition & 1 deletion
2
src/extensions/BootstrapBlazor.Socket/BootstrapBlazor.Socket.csproj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
src/extensions/BootstrapBlazor.Socket/Utility/ModbusCrc16.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| // Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved. | ||
| // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
| // Website: https://www.blazor.zone or https://argozhang.github.io/ | ||
|
|
||
| namespace BootstrapBlazor.Components.Utility; | ||
|
|
||
| /// <summary> | ||
| /// Modubs CRC-16 查表算法 | ||
| /// </summary> | ||
| public static class ModbusCrc16 | ||
| { | ||
| // 预计算的CRC表(256个条目) | ||
| private static readonly ushort[] CrcTable = | ||
| [ | ||
| 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, | ||
| 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, | ||
| 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, | ||
| 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, | ||
| 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, | ||
| 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, | ||
| 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, | ||
| 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, | ||
| 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, | ||
| 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, | ||
| 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, | ||
| 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, | ||
| 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, | ||
| 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, | ||
| 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, | ||
| 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, | ||
| 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, | ||
| 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, | ||
| 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, | ||
| 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, | ||
| 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, | ||
| 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, | ||
| 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, | ||
| 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, | ||
| 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, | ||
| 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, | ||
| 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, | ||
| 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, | ||
| 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, | ||
| 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, | ||
| 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, | ||
| 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 | ||
| ]; | ||
|
|
||
| /// <summary> | ||
| /// 计算 Modbus CRC-16 校验码 | ||
| /// </summary> | ||
| /// <param name="data">要计算的数据字节数组</param> | ||
| /// <returns>CRC校验码(低字节在前)</returns> | ||
| public static ushort Compute(ReadOnlySpan<byte> data) | ||
| { | ||
| ushort crc = 0xFFFF; | ||
| foreach (var b in data) | ||
| { | ||
| crc = (ushort)((crc >> 8) ^ CrcTable[(crc ^ b) & 0xFF]); | ||
| } | ||
| return crc; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// 计算 CRC 并将结果添加到消息末尾(Modbus格式) | ||
| /// </summary> | ||
| /// <param name="data">原始数据</param> | ||
| /// <returns>带 CRC 校验码的数据</returns> | ||
| public static ReadOnlySpan<byte> Append(ReadOnlySpan<byte> data) | ||
| { | ||
| ushort crc = Compute(data); | ||
|
|
||
| // 使用 stackalloc 避免堆分配(小数据时) | ||
| if (data.Length <= 256) | ||
|
ArgoZhang marked this conversation as resolved.
|
||
| { | ||
| Span<byte> result = stackalloc byte[data.Length + 2]; | ||
| data.CopyTo(result); | ||
| result[data.Length] = (byte)(crc & 0xFF); | ||
|
ArgoZhang marked this conversation as resolved.
|
||
| result[data.Length + 1] = (byte)(crc >> 8); | ||
| return result.ToArray(); | ||
| } | ||
| else | ||
| { | ||
| // 大数据使用常规数组 | ||
| byte[] result = new byte[data.Length + 2]; | ||
| data.CopyTo(result); | ||
| result[data.Length] = (byte)(crc & 0xFF); | ||
| result[data.Length + 1] = (byte)(crc >> 8); | ||
| return result; | ||
| } | ||
|
ArgoZhang marked this conversation as resolved.
|
||
| } | ||
|
|
||
| /// <summary> | ||
| /// 验证带 CRC 的数据是否有效 | ||
| /// </summary> | ||
| /// <param name="dataWithCrc">包含 CRC 校验码的数据</param> | ||
| /// <returns>验证结果</returns> | ||
| public static bool Validate(ReadOnlySpan<byte> dataWithCrc) | ||
| { | ||
| if (dataWithCrc.Length < 2) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| ushort receivedCrc = (ushort)(dataWithCrc[^1] << 8 | dataWithCrc[^2]); | ||
|
ArgoZhang marked this conversation as resolved.
|
||
| ushort calculatedCrc = Compute(dataWithCrc[..^2]); | ||
| return receivedCrc == calculatedCrc; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| // Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved. | ||
| // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
| // Website: https://www.blazor.zone or https://argozhang.github.io/ | ||
|
|
||
| namespace UnitTestTcpSocket; | ||
|
|
||
| public class ActivationExtensionsTest | ||
| { | ||
| [Fact] | ||
| public void Activation_Ok() | ||
| { | ||
| var type = typeof(Foo); | ||
| var o = type.CreateInstance(); | ||
| Assert.NotNull(o); | ||
|
|
||
| var foo = o as Foo; | ||
| Assert.NotNull(foo); | ||
|
|
||
| var foo1 = type.CreateInstance<Foo>(); | ||
| Assert.NotNull(foo1); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void Activation_Nest() | ||
| { | ||
| var o = typeof(MockNestEntity).CreateInstance<MockNestEntity>([0.01f]); | ||
| Assert.Equal(0.01f, o?.Rate); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void Activation_Fail() | ||
| { | ||
| var type = typeof(string); | ||
| var o = type.CreateInstance([123]); | ||
| Assert.Null(o); | ||
|
|
||
| var foo = type.CreateInstance<Foo>(); | ||
| Assert.Null(foo); | ||
| } | ||
|
|
||
| class MockNestEntity(float rate) | ||
| { | ||
| public float Rate { get; } = rate; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| // Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved. | ||
| // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
| // Website: https://www.blazor.zone or https://argozhang.github.io/ | ||
|
|
||
| using BootstrapBlazor.Components.Utility; | ||
|
|
||
| namespace UnitTestTcpSocket; | ||
|
|
||
| public class ModbusCrcTest | ||
| { | ||
| [Fact] | ||
| public void Computer_Ok() | ||
| { | ||
| // 06 00 00 01 7F C9 BA | ||
| var data = new byte[] { 0x01, 0x06, 0x00, 0x00, 0x01, 0x7F }; | ||
|
|
||
| var crc = ModbusCrc16.Compute(data); | ||
| Assert.Equal("BAC9", crc.ToString("X4")); | ||
| Assert.Equal("01060000017FC9BA", HexConverter.ToString(ModbusCrc16.Append(data), "")); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void Validate_Ok() | ||
| { | ||
| var result = ModbusCrc16.Validate([0x01]); | ||
| Assert.False(result); | ||
|
|
||
| result = ModbusCrc16.Validate([0x01, 0x06, 0x00, 0x00, 0x01, 0x7F, 0xC9, 0xBA]); | ||
| Assert.True(result); | ||
|
|
||
| result = false; | ||
|
ArgoZhang marked this conversation as resolved.
|
||
| var data = Enumerable.Range(0, 300).Select(i => (byte)Random.Shared.Next(0, 255)); | ||
| result = ModbusCrc16.Validate(ModbusCrc16.Append(data.ToArray())); | ||
| Assert.True(result); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| // Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved. | ||
| // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
| // Website: https://www.blazor.zone or https://argozhang.github.io/ | ||
|
|
||
| using BootstrapBlazor.Socket.Logging; | ||
|
|
||
| namespace UnitTestTcpSocket; | ||
|
|
||
| public class SocketLoggingTest | ||
| { | ||
| [Fact] | ||
| public void Logger_Ok() | ||
| { | ||
| SocketLogging.LogError(new Exception()); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.