666
This commit is contained in:
237
CSharp调用说明.md
Normal file
237
CSharp调用说明.md
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
# XYParser 的 C# 调用说明
|
||||||
|
|
||||||
|
## 1. 项目现状
|
||||||
|
|
||||||
|
当前工程已经是一个 **C++ 原生 DLL**,不是 .NET DLL。
|
||||||
|
C# 调用它的推荐方式是使用 **P/Invoke**。
|
||||||
|
|
||||||
|
相关接口定义见:
|
||||||
|
|
||||||
|
- [XYParserApi.h](file:///c:/Users/xyyl666/Desktop/XYParser/XYParser/XYParserApi.h#L12-L40)
|
||||||
|
- [XYParserApi.cpp](file:///c:/Users/xyyl666/Desktop/XYParser/XYParser/XYParserApi.cpp#L59-L154)
|
||||||
|
|
||||||
|
当前主要导出函数:
|
||||||
|
|
||||||
|
- `XYParser_CreateParser`
|
||||||
|
- `XYParser_DestroyParser`
|
||||||
|
- `XYParser_SetAdcParams`
|
||||||
|
- `XYParser_SetBypassChecksum`
|
||||||
|
- `XYParser_Feed`
|
||||||
|
- `XYParser_GetLastError`
|
||||||
|
|
||||||
|
## 2. 使用方式
|
||||||
|
|
||||||
|
### 2.1 先编译 DLL
|
||||||
|
|
||||||
|
在 Visual Studio 中打开:
|
||||||
|
|
||||||
|
- [XYParser.sln](file:///c:/Users/xyyl666/Desktop/XYParser/XYParser/XYParser.sln)
|
||||||
|
|
||||||
|
建议编译配置:
|
||||||
|
|
||||||
|
- `Release | x64`
|
||||||
|
|
||||||
|
编译后得到:
|
||||||
|
|
||||||
|
- `XYParser.dll`
|
||||||
|
|
||||||
|
运行 C# 程序时,需要把 `XYParser.dll` 放到:
|
||||||
|
|
||||||
|
- C# 可执行程序同目录
|
||||||
|
- 或系统可搜索到的 DLL 路径中
|
||||||
|
|
||||||
|
## 3. C# P/Invoke 声明
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
internal static class NativeMethods
|
||||||
|
{
|
||||||
|
private const string DllName = "XYParser.dll";
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr XYParser_CreateParser(byte channel_count);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void XYParser_DestroyParser(IntPtr handle);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void XYParser_SetAdcParams(IntPtr handle, double vref, double gain);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void XYParser_SetBypassChecksum(IntPtr handle, int bypass);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int XYParser_Feed(
|
||||||
|
IntPtr handle,
|
||||||
|
byte[] data,
|
||||||
|
UIntPtr size,
|
||||||
|
[Out] XYParserFrameSummary[] outSummaries,
|
||||||
|
int maxSummaries);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr XYParser_GetLastError(IntPtr handle);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 结构体定义
|
||||||
|
|
||||||
|
C++ 中的结构体定义见:
|
||||||
|
|
||||||
|
- [XYParserFrameSummary](file:///c:/Users/xyyl666/Desktop/XYParser/XYParser/XYParserApi.h#L21-L29)
|
||||||
|
|
||||||
|
对应的 C# 写法:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct XYParserFrameSummary
|
||||||
|
{
|
||||||
|
public uint frame_index;
|
||||||
|
public byte channel_count;
|
||||||
|
public byte battery;
|
||||||
|
public byte sample_count;
|
||||||
|
|
||||||
|
// C++: double channel_values_uv[5][64]
|
||||||
|
// C#: 按一维数组接收,总长度 = 5 * 64
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5 * 64)]
|
||||||
|
public double[] channel_values_uv;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
|
||||||
|
public byte[] trigger_types;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
|
||||||
|
public byte[] trigger_indices;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. 调用示例
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main()
|
||||||
|
{
|
||||||
|
IntPtr handle = NativeMethods.XYParser_CreateParser(8);
|
||||||
|
if (handle == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
throw new Exception("创建解析器失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
NativeMethods.XYParser_SetAdcParams(handle, 4.5, 6.0);
|
||||||
|
NativeMethods.XYParser_SetBypassChecksum(handle, 1);
|
||||||
|
|
||||||
|
byte[] input = File.ReadAllBytes("test.bin");
|
||||||
|
|
||||||
|
XYParserFrameSummary[] summaries = new XYParserFrameSummary[8];
|
||||||
|
for (int i = 0; i < summaries.Length; i++)
|
||||||
|
{
|
||||||
|
summaries[i].channel_values_uv = new double[5 * 64];
|
||||||
|
summaries[i].trigger_types = new byte[5];
|
||||||
|
summaries[i].trigger_indices = new byte[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = NativeMethods.XYParser_Feed(
|
||||||
|
handle,
|
||||||
|
input,
|
||||||
|
(UIntPtr)input.Length,
|
||||||
|
summaries,
|
||||||
|
summaries.Length);
|
||||||
|
|
||||||
|
string lastError = Marshal.PtrToStringAnsi(
|
||||||
|
NativeMethods.XYParser_GetLastError(handle)) ?? "";
|
||||||
|
|
||||||
|
Console.WriteLine($"解析出的帧数: {count}");
|
||||||
|
Console.WriteLine($"最后错误: {lastError}");
|
||||||
|
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
double firstValue = summaries[0].channel_values_uv[0];
|
||||||
|
Console.WriteLine($"第一帧第一个采样点第一个通道值: {firstValue}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
NativeMethods.XYParser_DestroyParser(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 二维数组取值说明
|
||||||
|
|
||||||
|
C++ 中:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
double channel_values_uv[5][64];
|
||||||
|
```
|
||||||
|
|
||||||
|
C# 中按一维数组接收后,索引方式为:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
double value = summary.channel_values_uv[sampleIndex * 64 + channelIndex];
|
||||||
|
```
|
||||||
|
|
||||||
|
例如:
|
||||||
|
|
||||||
|
- 第 `0` 个采样点,第 `0` 个通道:`[0 * 64 + 0]`
|
||||||
|
- 第 `1` 个采样点,第 `3` 个通道:`[1 * 64 + 3]`
|
||||||
|
|
||||||
|
## 7. 注意事项
|
||||||
|
|
||||||
|
- `CallingConvention` 要使用 `Cdecl`
|
||||||
|
- `XYParser_GetLastError` 返回的是 `const char*`,需用 `Marshal.PtrToStringAnsi`
|
||||||
|
- C# 程序位数必须和 DLL 一致
|
||||||
|
- 你当前更适合使用 `x64`
|
||||||
|
- `channel_count` 当前只支持 `8` 和 `64`
|
||||||
|
|
||||||
|
## 8. 推荐封装方式
|
||||||
|
|
||||||
|
如果后续要长期在 C# 中使用,建议再包一层托管类,例如:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public sealed class XYParser : IDisposable
|
||||||
|
{
|
||||||
|
private IntPtr _handle;
|
||||||
|
|
||||||
|
public XYParser(byte channelCount)
|
||||||
|
{
|
||||||
|
_handle = NativeMethods.XYParser_CreateParser(channelCount);
|
||||||
|
if (_handle == IntPtr.Zero)
|
||||||
|
throw new InvalidOperationException("创建解析器失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAdcParams(double vref, double gain)
|
||||||
|
{
|
||||||
|
NativeMethods.XYParser_SetAdcParams(_handle, vref, gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBypassChecksum(bool enabled)
|
||||||
|
{
|
||||||
|
NativeMethods.XYParser_SetBypassChecksum(_handle, enabled ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_handle != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
NativeMethods.XYParser_DestroyParser(_handle);
|
||||||
|
_handle = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. 总结
|
||||||
|
|
||||||
|
- 当前工程已经能生成原生 `XYParser.dll`
|
||||||
|
- C# 不需要重写解析逻辑,直接用 `DllImport` 即可调用
|
||||||
|
- 最关键的是函数声明匹配、结构体布局匹配、位数一致
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
XYParser/.vs/XYParser/v17/.suo
Normal file
BIN
XYParser/.vs/XYParser/v17/.suo
Normal file
Binary file not shown.
BIN
XYParser/.vs/XYParser/v17/Browse.VC.db
Normal file
BIN
XYParser/.vs/XYParser/v17/Browse.VC.db
Normal file
Binary file not shown.
BIN
XYParser/.vs/XYParser/v17/Browse.VC.db-shm
Normal file
BIN
XYParser/.vs/XYParser/v17/Browse.VC.db-shm
Normal file
Binary file not shown.
0
XYParser/.vs/XYParser/v17/Browse.VC.db-wal
Normal file
0
XYParser/.vs/XYParser/v17/Browse.VC.db-wal
Normal file
BIN
XYParser/.vs/XYParser/v17/Browse.VC.opendb
Normal file
BIN
XYParser/.vs/XYParser/v17/Browse.VC.opendb
Normal file
Binary file not shown.
171
XYParser/.vs/XYParser/v17/DocumentLayout.backup.json
Normal file
171
XYParser/.vs/XYParser/v17/DocumentLayout.backup.json
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
{
|
||||||
|
"Version": 1,
|
||||||
|
"WorkspaceRootPath": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\",
|
||||||
|
"Documents": [
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYParserApi.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYParserApi.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYParserApi.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYParserApi.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParserExample.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYEegParserExample.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser64.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYEegParser64.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParserCommon.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYEegParserCommon.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser8.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYEegParser8.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser64.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYEegParser64.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser8.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYEegParser8.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\dllmain.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:dllmain.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"DocumentGroupContainers": [
|
||||||
|
{
|
||||||
|
"Orientation": 0,
|
||||||
|
"VerticalTabListWidth": 256,
|
||||||
|
"DocumentGroups": [
|
||||||
|
{
|
||||||
|
"DockedWidth": 200,
|
||||||
|
"SelectedChildIndex": 0,
|
||||||
|
"Children": [
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 0,
|
||||||
|
"Title": "XYParserApi.h",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYParserApi.h",
|
||||||
|
"RelativeDocumentMoniker": "XYParserApi.h",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYParserApi.h",
|
||||||
|
"RelativeToolTip": "XYParserApi.h",
|
||||||
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAA0AAAAUAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||||
|
"WhenOpened": "2026-06-04T06:13:17.908Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 1,
|
||||||
|
"Title": "XYParserApi.cpp",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYParserApi.cpp",
|
||||||
|
"RelativeDocumentMoniker": "XYParserApi.cpp",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYParserApi.cpp",
|
||||||
|
"RelativeToolTip": "XYParserApi.cpp",
|
||||||
|
"ViewState": "AgIAAH4AAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
|
||||||
|
"WhenOpened": "2026-06-04T06:13:04.173Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Bookmark",
|
||||||
|
"Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 2,
|
||||||
|
"Title": "XYEegParserExample.cpp",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParserExample.cpp",
|
||||||
|
"RelativeDocumentMoniker": "XYEegParserExample.cpp",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParserExample.cpp",
|
||||||
|
"RelativeToolTip": "XYEegParserExample.cpp",
|
||||||
|
"ViewState": "AgIAAFwAAAAAAAAAAAAAAFAAAAADAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
|
||||||
|
"WhenOpened": "2026-06-04T05:55:44.898Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 3,
|
||||||
|
"Title": "XYEegParser64.h",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser64.h",
|
||||||
|
"RelativeDocumentMoniker": "XYEegParser64.h",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser64.h",
|
||||||
|
"RelativeToolTip": "XYEegParser64.h",
|
||||||
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAQAAAAkAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||||
|
"WhenOpened": "2026-06-04T05:51:57.408Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 4,
|
||||||
|
"Title": "XYEegParserCommon.h",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParserCommon.h",
|
||||||
|
"RelativeDocumentMoniker": "XYEegParserCommon.h",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParserCommon.h",
|
||||||
|
"RelativeToolTip": "XYEegParserCommon.h",
|
||||||
|
"ViewState": "AgIAAMkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||||
|
"WhenOpened": "2026-06-04T05:50:06.166Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 7,
|
||||||
|
"Title": "XYEegParser8.h",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser8.h",
|
||||||
|
"RelativeDocumentMoniker": "XYEegParser8.h",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser8.h",
|
||||||
|
"RelativeToolTip": "XYEegParser8.h",
|
||||||
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||||
|
"WhenOpened": "2026-06-04T05:49:55.73Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 6,
|
||||||
|
"Title": "XYEegParser64.cpp",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser64.cpp",
|
||||||
|
"RelativeDocumentMoniker": "XYEegParser64.cpp",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser64.cpp",
|
||||||
|
"RelativeToolTip": "XYEegParser64.cpp",
|
||||||
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
|
||||||
|
"WhenOpened": "2026-06-04T05:49:51.523Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 5,
|
||||||
|
"Title": "XYEegParser8.cpp",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser8.cpp",
|
||||||
|
"RelativeDocumentMoniker": "XYEegParser8.cpp",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser8.cpp",
|
||||||
|
"RelativeToolTip": "XYEegParser8.cpp",
|
||||||
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
|
||||||
|
"WhenOpened": "2026-06-04T05:49:48.717Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 8,
|
||||||
|
"Title": "dllmain.cpp",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\dllmain.cpp",
|
||||||
|
"RelativeDocumentMoniker": "dllmain.cpp",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\dllmain.cpp",
|
||||||
|
"RelativeToolTip": "dllmain.cpp",
|
||||||
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
|
||||||
|
"WhenOpened": "2026-06-04T03:55:05.048Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
171
XYParser/.vs/XYParser/v17/DocumentLayout.json
Normal file
171
XYParser/.vs/XYParser/v17/DocumentLayout.json
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
{
|
||||||
|
"Version": 1,
|
||||||
|
"WorkspaceRootPath": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\",
|
||||||
|
"Documents": [
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYParserApi.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYParserApi.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYParserApi.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYParserApi.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParserExample.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYEegParserExample.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser64.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYEegParser64.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParserCommon.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYEegParserCommon.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser8.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYEegParser8.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser64.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYEegParser64.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser8.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:XYEegParser8.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\dllmain.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
|
||||||
|
"RelativeMoniker": "D:0:0:{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}|XYParser.vcxproj|solutionrelative:dllmain.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"DocumentGroupContainers": [
|
||||||
|
{
|
||||||
|
"Orientation": 0,
|
||||||
|
"VerticalTabListWidth": 256,
|
||||||
|
"DocumentGroups": [
|
||||||
|
{
|
||||||
|
"DockedWidth": 200,
|
||||||
|
"SelectedChildIndex": 0,
|
||||||
|
"Children": [
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 0,
|
||||||
|
"Title": "XYParserApi.h",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYParserApi.h",
|
||||||
|
"RelativeDocumentMoniker": "XYParserApi.h",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYParserApi.h",
|
||||||
|
"RelativeToolTip": "XYParserApi.h",
|
||||||
|
"ViewState": "AgIAABsAAAAAAAAAAAAAACMAAAA4AAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||||
|
"WhenOpened": "2026-06-04T06:13:17.908Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 1,
|
||||||
|
"Title": "XYParserApi.cpp",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYParserApi.cpp",
|
||||||
|
"RelativeDocumentMoniker": "XYParserApi.cpp",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYParserApi.cpp",
|
||||||
|
"RelativeToolTip": "XYParserApi.cpp",
|
||||||
|
"ViewState": "AgIAAI4AAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
|
||||||
|
"WhenOpened": "2026-06-04T06:13:04.173Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Bookmark",
|
||||||
|
"Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 2,
|
||||||
|
"Title": "XYEegParserExample.cpp",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParserExample.cpp",
|
||||||
|
"RelativeDocumentMoniker": "XYEegParserExample.cpp",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParserExample.cpp",
|
||||||
|
"RelativeToolTip": "XYEegParserExample.cpp",
|
||||||
|
"ViewState": "AgIAAFwAAAAAAAAAAAAAAFAAAAADAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
|
||||||
|
"WhenOpened": "2026-06-04T05:55:44.898Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 3,
|
||||||
|
"Title": "XYEegParser64.h",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser64.h",
|
||||||
|
"RelativeDocumentMoniker": "XYEegParser64.h",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser64.h",
|
||||||
|
"RelativeToolTip": "XYEegParser64.h",
|
||||||
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAQAAAAkAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||||
|
"WhenOpened": "2026-06-04T05:51:57.408Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 4,
|
||||||
|
"Title": "XYEegParserCommon.h",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParserCommon.h",
|
||||||
|
"RelativeDocumentMoniker": "XYEegParserCommon.h",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParserCommon.h",
|
||||||
|
"RelativeToolTip": "XYEegParserCommon.h",
|
||||||
|
"ViewState": "AgIAAMkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||||
|
"WhenOpened": "2026-06-04T05:50:06.166Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 7,
|
||||||
|
"Title": "XYEegParser8.h",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser8.h",
|
||||||
|
"RelativeDocumentMoniker": "XYEegParser8.h",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser8.h",
|
||||||
|
"RelativeToolTip": "XYEegParser8.h",
|
||||||
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
|
||||||
|
"WhenOpened": "2026-06-04T05:49:55.73Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 6,
|
||||||
|
"Title": "XYEegParser64.cpp",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser64.cpp",
|
||||||
|
"RelativeDocumentMoniker": "XYEegParser64.cpp",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser64.cpp",
|
||||||
|
"RelativeToolTip": "XYEegParser64.cpp",
|
||||||
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
|
||||||
|
"WhenOpened": "2026-06-04T05:49:51.523Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 5,
|
||||||
|
"Title": "XYEegParser8.cpp",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser8.cpp",
|
||||||
|
"RelativeDocumentMoniker": "XYEegParser8.cpp",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\XYEegParser8.cpp",
|
||||||
|
"RelativeToolTip": "XYEegParser8.cpp",
|
||||||
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
|
||||||
|
"WhenOpened": "2026-06-04T05:49:48.717Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 8,
|
||||||
|
"Title": "dllmain.cpp",
|
||||||
|
"DocumentMoniker": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\dllmain.cpp",
|
||||||
|
"RelativeDocumentMoniker": "dllmain.cpp",
|
||||||
|
"ToolTip": "C:\\Users\\xyyl666\\Desktop\\XYParser\\XYParser\\dllmain.cpp",
|
||||||
|
"RelativeToolTip": "dllmain.cpp",
|
||||||
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
|
||||||
|
"WhenOpened": "2026-06-04T03:55:05.048Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
XYParser/.vs/XYParser/v17/Solution.VC.db
Normal file
BIN
XYParser/.vs/XYParser/v17/Solution.VC.db
Normal file
Binary file not shown.
BIN
XYParser/.vs/XYParser/v17/ipch/da131652d6dd7f4a.ipch
Normal file
BIN
XYParser/.vs/XYParser/v17/ipch/da131652d6dd7f4a.ipch
Normal file
Binary file not shown.
2
XYParser/XYEegParser64.cpp
Normal file
2
XYParser/XYEegParser64.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "XYEegParser64.h"
|
||||||
10
XYParser/XYEegParser64.h
Normal file
10
XYParser/XYEegParser64.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "XYEegParserCommon.h"
|
||||||
|
|
||||||
|
using XYEegFrame64 = xyparser::XYEegFrame<64>;
|
||||||
|
|
||||||
|
class XYEegParser64 final : public xyparser::XYEegTcpParserCommon<64> {
|
||||||
|
public:
|
||||||
|
using Frame = XYEegFrame64;
|
||||||
|
};
|
||||||
2
XYParser/XYEegParser8.cpp
Normal file
2
XYParser/XYEegParser8.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "XYEegParser8.h"
|
||||||
10
XYParser/XYEegParser8.h
Normal file
10
XYParser/XYEegParser8.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "XYEegParserCommon.h"
|
||||||
|
|
||||||
|
using XYEegFrame8 = xyparser::XYEegFrame<8>;
|
||||||
|
|
||||||
|
class XYEegParser8 final : public xyparser::XYEegTcpParserCommon<8> {
|
||||||
|
public:
|
||||||
|
using Frame = XYEegFrame8;
|
||||||
|
};
|
||||||
266
XYParser/XYEegParserCommon.h
Normal file
266
XYParser/XYEegParserCommon.h
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace xyparser {
|
||||||
|
|
||||||
|
template <std::size_t ChannelCount>
|
||||||
|
struct XYEegSample {
|
||||||
|
std::array<double, ChannelCount> channel_values_uv{};
|
||||||
|
std::uint8_t trigger_type = 0;
|
||||||
|
std::uint8_t trigger_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <std::size_t ChannelCount>
|
||||||
|
struct XYEegFrame {
|
||||||
|
static constexpr std::size_t kSamplesPerFrame = 5;
|
||||||
|
|
||||||
|
std::uint8_t header = 0;
|
||||||
|
std::uint32_t index = 0;
|
||||||
|
std::uint16_t payload_length = 0;
|
||||||
|
std::uint8_t battery = 0;
|
||||||
|
std::uint8_t channel_count = 0;
|
||||||
|
std::int16_t elevation_angle = 0;
|
||||||
|
std::int16_t rolling_angle = 0;
|
||||||
|
std::int16_t yaw_angle = 0;
|
||||||
|
std::int16_t ecg = 0;
|
||||||
|
std::int16_t blood_oxygen = 0;
|
||||||
|
std::array<std::uint8_t, 6> reserved{};
|
||||||
|
std::array<XYEegSample<ChannelCount>, kSamplesPerFrame> samples{};
|
||||||
|
std::uint8_t crc = 0;
|
||||||
|
std::array<std::uint8_t, 2> tails{};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <std::size_t ChannelCount>
|
||||||
|
class XYEegTcpParserCommon {
|
||||||
|
public:
|
||||||
|
using Frame = XYEegFrame<ChannelCount>;
|
||||||
|
|
||||||
|
static constexpr std::uint8_t kFrameHeader = 0xAA;
|
||||||
|
static constexpr std::uint8_t kFrameTail = 0x55;
|
||||||
|
static constexpr std::size_t kSamplesPerFrame = 5;
|
||||||
|
static constexpr std::size_t kFrameHeaderLen = 1;
|
||||||
|
static constexpr std::size_t kFrameTailLen = 2;
|
||||||
|
static constexpr std::size_t kFrameTagLen = 25;
|
||||||
|
|
||||||
|
void SetAdcParams(double vref, double gain) noexcept
|
||||||
|
{
|
||||||
|
if (vref > 0.0) {
|
||||||
|
vref_ = vref;
|
||||||
|
}
|
||||||
|
if (gain > 0.0) {
|
||||||
|
gain_ = gain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBypassChecksum(bool bypass) noexcept
|
||||||
|
{
|
||||||
|
bypass_checksum_ = bypass;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BypassChecksum() const noexcept
|
||||||
|
{
|
||||||
|
return bypass_checksum_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
buffer_.clear();
|
||||||
|
last_error_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &LastError() const noexcept
|
||||||
|
{
|
||||||
|
return last_error_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Frame> Feed(const std::vector<std::uint8_t> &bytes)
|
||||||
|
{
|
||||||
|
return Feed(bytes.data(), bytes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Frame> Feed(const std::uint8_t *data, std::size_t size)
|
||||||
|
{
|
||||||
|
std::vector<Frame> frames;
|
||||||
|
if (data == nullptr || size == 0) {
|
||||||
|
return frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_.insert(buffer_.end(), data, data + size);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const auto header_it = std::find(buffer_.begin(), buffer_.end(), kFrameHeader);
|
||||||
|
if (header_it == buffer_.end()) {
|
||||||
|
buffer_.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t header_index = static_cast<std::size_t>(std::distance(buffer_.begin(), header_it));
|
||||||
|
if (buffer_.size() < header_index + 7) {
|
||||||
|
if (header_index > 0) {
|
||||||
|
buffer_.erase(buffer_.begin(), buffer_.begin() + static_cast<std::ptrdiff_t>(header_index));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::uint16_t payload_length = ReadBE16(buffer_, header_index + 5);
|
||||||
|
const std::size_t total_frame_len = payload_length + kFrameTagLen + kFrameTailLen + kFrameHeaderLen;
|
||||||
|
if (buffer_.size() - header_index < total_frame_len) {
|
||||||
|
if (header_index > 0) {
|
||||||
|
buffer_.erase(buffer_.begin(), buffer_.begin() + static_cast<std::ptrdiff_t>(header_index));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t tail_index = header_index + payload_length + kFrameTagLen + kFrameHeaderLen;
|
||||||
|
if (tail_index + 1 >= buffer_.size() || buffer_[tail_index] != kFrameTail || buffer_[tail_index + 1] != kFrameTail) {
|
||||||
|
buffer_.erase(buffer_.begin(), buffer_.begin() + static_cast<std::ptrdiff_t>(header_index + 1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::uint8_t> frame_bytes(
|
||||||
|
buffer_.begin() + static_cast<std::ptrdiff_t>(header_index),
|
||||||
|
buffer_.begin() + static_cast<std::ptrdiff_t>(tail_index + 2));
|
||||||
|
buffer_.erase(buffer_.begin(), buffer_.begin() + static_cast<std::ptrdiff_t>(tail_index + 2));
|
||||||
|
|
||||||
|
Frame frame;
|
||||||
|
if (TryParseFrame(frame_bytes, frame)) {
|
||||||
|
frames.push_back(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::uint16_t ReadBE16(const std::vector<std::uint8_t> &bytes, std::size_t offset) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<std::uint16_t>((static_cast<std::uint16_t>(bytes[offset]) << 8) |
|
||||||
|
static_cast<std::uint16_t>(bytes[offset + 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::uint16_t ReadLE16(const std::vector<std::uint8_t> &bytes, std::size_t offset) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<std::uint16_t>(static_cast<std::uint16_t>(bytes[offset]) |
|
||||||
|
(static_cast<std::uint16_t>(bytes[offset + 1]) << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::uint32_t ReadLE32(const std::vector<std::uint8_t> &bytes, std::size_t offset) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<std::uint32_t>(bytes[offset]) |
|
||||||
|
(static_cast<std::uint32_t>(bytes[offset + 1]) << 8) |
|
||||||
|
(static_cast<std::uint32_t>(bytes[offset + 2]) << 16) |
|
||||||
|
(static_cast<std::uint32_t>(bytes[offset + 3]) << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
double ConvertAdcToUv(const std::uint8_t raw0, const std::uint8_t raw1, const std::uint8_t raw2) const noexcept
|
||||||
|
{
|
||||||
|
double value = static_cast<double>(raw0) * 65536.0 +
|
||||||
|
static_cast<double>(raw1) * 256.0 +
|
||||||
|
static_cast<double>(raw2);
|
||||||
|
const double factor = vref_ / gain_ / 8388608.0 * 1000000.0;
|
||||||
|
if (value < 8388608.0) {
|
||||||
|
return value * factor;
|
||||||
|
}
|
||||||
|
return -(16777216.0 - value) * factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckChecksum(const std::vector<std::uint8_t> &frame_bytes) const noexcept
|
||||||
|
{
|
||||||
|
if (frame_bytes.size() < 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t crc_index = frame_bytes.size() - 3;
|
||||||
|
std::uint8_t checksum = 0;
|
||||||
|
for (std::size_t i = 0; i < crc_index; ++i) {
|
||||||
|
checksum = static_cast<std::uint8_t>(checksum + frame_bytes[i]);
|
||||||
|
}
|
||||||
|
return checksum == frame_bytes[crc_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryParseFrame(const std::vector<std::uint8_t> &frame_bytes, Frame &frame)
|
||||||
|
{
|
||||||
|
if (!bypass_checksum_ && !CheckChecksum(frame_bytes)) {
|
||||||
|
last_error_ = "checksum failed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t min_frame_len = kFrameHeaderLen + kFrameTagLen + kFrameTailLen;
|
||||||
|
if (frame_bytes.size() < min_frame_len) {
|
||||||
|
last_error_ = "frame too short";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t channel_count_offset = kFrameHeaderLen + 4 + 2 + 1;
|
||||||
|
const std::uint8_t channel_count = frame_bytes[channel_count_offset];
|
||||||
|
if (channel_count != ChannelCount) {
|
||||||
|
last_error_ = "unexpected channel count";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t sample_bytes = ChannelCount * 3 + 2;
|
||||||
|
const std::size_t expected_frame_len = kFrameHeaderLen + kFrameTagLen +
|
||||||
|
kSamplesPerFrame * sample_bytes + kFrameTailLen;
|
||||||
|
if (frame_bytes.size() != expected_frame_len) {
|
||||||
|
last_error_ = "frame length mismatch";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t offset = 0;
|
||||||
|
frame.header = frame_bytes[offset++];
|
||||||
|
frame.index = ReadLE32(frame_bytes, offset);
|
||||||
|
offset += 4;
|
||||||
|
frame.payload_length = ReadBE16(frame_bytes, offset);
|
||||||
|
offset += 2;
|
||||||
|
frame.battery = frame_bytes[offset++];
|
||||||
|
frame.channel_count = frame_bytes[offset++];
|
||||||
|
frame.elevation_angle = static_cast<std::int16_t>(ReadLE16(frame_bytes, offset));
|
||||||
|
offset += 2;
|
||||||
|
frame.rolling_angle = static_cast<std::int16_t>(ReadLE16(frame_bytes, offset));
|
||||||
|
offset += 2;
|
||||||
|
frame.yaw_angle = static_cast<std::int16_t>(ReadLE16(frame_bytes, offset));
|
||||||
|
offset += 2;
|
||||||
|
frame.ecg = static_cast<std::int16_t>(ReadLE16(frame_bytes, offset));
|
||||||
|
offset += 2;
|
||||||
|
frame.blood_oxygen = static_cast<std::int16_t>(ReadLE16(frame_bytes, offset));
|
||||||
|
offset += 2;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < frame.reserved.size(); ++i) {
|
||||||
|
frame.reserved[i] = frame_bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &sample : frame.samples) {
|
||||||
|
for (std::size_t channel = 0; channel < ChannelCount; ++channel) {
|
||||||
|
sample.channel_values_uv[channel] = ConvertAdcToUv(
|
||||||
|
frame_bytes[offset],
|
||||||
|
frame_bytes[offset + 1],
|
||||||
|
frame_bytes[offset + 2]);
|
||||||
|
offset += 3;
|
||||||
|
}
|
||||||
|
sample.trigger_type = frame_bytes[offset++];
|
||||||
|
sample.trigger_index = frame_bytes[offset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.crc = frame_bytes[offset++];
|
||||||
|
frame.tails[0] = frame_bytes[offset++];
|
||||||
|
frame.tails[1] = frame_bytes[offset++];
|
||||||
|
|
||||||
|
last_error_.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::uint8_t> buffer_;
|
||||||
|
std::string last_error_;
|
||||||
|
double vref_ = 4.5;
|
||||||
|
double gain_ = 6.0;
|
||||||
|
bool bypass_checksum_ = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xyparser
|
||||||
112
XYParser/XYEegParserExample.cpp
Normal file
112
XYParser/XYEegParserExample.cpp
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "XYParserApi.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::vector<std::uint8_t> BuildMinimalFrame(std::uint8_t channel_count)
|
||||||
|
{
|
||||||
|
constexpr std::size_t kSamplesPerFrame = 5;
|
||||||
|
constexpr std::uint8_t kHeader = 0xAA;
|
||||||
|
constexpr std::uint8_t kTail = 0x55;
|
||||||
|
constexpr std::size_t kTagLen = 25;
|
||||||
|
|
||||||
|
const std::size_t sample_bytes = static_cast<std::size_t>(channel_count) * 3 + 2;
|
||||||
|
const std::uint16_t payload_length = static_cast<std::uint16_t>(sample_bytes * kSamplesPerFrame);
|
||||||
|
const std::size_t frame_size = 1 + kTagLen + payload_length + 2;
|
||||||
|
|
||||||
|
std::vector<std::uint8_t> frame(frame_size, 0);
|
||||||
|
std::size_t offset = 0;
|
||||||
|
|
||||||
|
frame[offset++] = kHeader;
|
||||||
|
|
||||||
|
// index, little endian
|
||||||
|
frame[offset++] = 0x01;
|
||||||
|
frame[offset++] = 0x00;
|
||||||
|
frame[offset++] = 0x00;
|
||||||
|
frame[offset++] = 0x00;
|
||||||
|
|
||||||
|
// payload length, big endian
|
||||||
|
frame[offset++] = static_cast<std::uint8_t>((payload_length >> 8) & 0xFF);
|
||||||
|
frame[offset++] = static_cast<std::uint8_t>(payload_length & 0xFF);
|
||||||
|
|
||||||
|
frame[offset++] = 95; // battery
|
||||||
|
frame[offset++] = channel_count; // channelCount
|
||||||
|
|
||||||
|
// elevation / roll / yaw / ecg / spo2 / reserved[6]
|
||||||
|
offset += 2 + 2 + 2 + 2 + 2 + 6;
|
||||||
|
|
||||||
|
// Build 5 samples. Each channel uses 3 ADC bytes, followed by trigger fields.
|
||||||
|
for (std::size_t sample = 0; sample < kSamplesPerFrame; ++sample) {
|
||||||
|
for (std::size_t channel = 0; channel < channel_count; ++channel) {
|
||||||
|
frame[offset++] = 0x00;
|
||||||
|
frame[offset++] = 0x00;
|
||||||
|
frame[offset++] = static_cast<std::uint8_t>(sample + channel + 1);
|
||||||
|
}
|
||||||
|
frame[offset++] = 0x00; // triggerType
|
||||||
|
frame[offset++] = 0x00; // triggerIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
frame[offset++] = 0x00; // crc, ignored when bypass checksum is enabled
|
||||||
|
frame[offset++] = kTail;
|
||||||
|
frame[offset++] = kTail;
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void MinimalExampleFor8ChParser()
|
||||||
|
{
|
||||||
|
XYParserHandle parser = XYParser_CreateParser(8);
|
||||||
|
if (parser == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
XYParser_SetAdcParams(parser, 4.5, 6.0);
|
||||||
|
XYParser_SetBypassChecksum(parser, 1);
|
||||||
|
|
||||||
|
const std::vector<std::uint8_t> raw_bytes = BuildMinimalFrame(8);
|
||||||
|
std::array<XYParserFrameSummary, 1> summaries{};
|
||||||
|
const int frame_count = XYParser_Feed(parser,
|
||||||
|
raw_bytes.data(),
|
||||||
|
raw_bytes.size(),
|
||||||
|
summaries.data(),
|
||||||
|
static_cast<int>(summaries.size()));
|
||||||
|
|
||||||
|
if (frame_count > 0) {
|
||||||
|
const XYParserFrameSummary& frame = summaries.front();
|
||||||
|
const double first_channel_uv = frame.channel_values_uv[0][0];
|
||||||
|
(void)first_channel_uv;
|
||||||
|
}
|
||||||
|
|
||||||
|
XYParser_DestroyParser(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MinimalExampleFor64ChParser()
|
||||||
|
{
|
||||||
|
XYParserHandle parser = XYParser_CreateParser(64);
|
||||||
|
if (parser == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
XYParser_SetAdcParams(parser, 4.5, 6.0);
|
||||||
|
XYParser_SetBypassChecksum(parser, 1);
|
||||||
|
|
||||||
|
const std::vector<std::uint8_t> raw_bytes = BuildMinimalFrame(64);
|
||||||
|
std::array<XYParserFrameSummary, 1> summaries{};
|
||||||
|
const int frame_count = XYParser_Feed(parser,
|
||||||
|
raw_bytes.data(),
|
||||||
|
raw_bytes.size(),
|
||||||
|
summaries.data(),
|
||||||
|
static_cast<int>(summaries.size()));
|
||||||
|
|
||||||
|
if (frame_count > 0) {
|
||||||
|
const XYParserFrameSummary& frame = summaries.front();
|
||||||
|
const std::uint8_t battery = frame.battery;
|
||||||
|
(void)battery;
|
||||||
|
}
|
||||||
|
|
||||||
|
XYParser_DestroyParser(parser);
|
||||||
|
}
|
||||||
31
XYParser/XYParser.sln
Normal file
31
XYParser/XYParser.sln
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.14.36429.23 d17.14
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XYParser", "XYParser.vcxproj", "{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}.Release|x64.Build.0 = Release|x64
|
||||||
|
{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{CB1FF804-BB1F-41C8-92FA-7B15F6B86347}.Release|x86.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {F6206831-0432-4ABB-B939-97EC2B8EAB79}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
161
XYParser/XYParser.vcxproj
Normal file
161
XYParser/XYParser.vcxproj
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>17.0</VCProjectVersion>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<ProjectGuid>{cb1ff804-bb1f-41c8-92fa-7b15f6b86347}</ProjectGuid>
|
||||||
|
<RootNamespace>XYParser</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;XYPARSER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableUAC>false</EnableUAC>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;XYPARSER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableUAC>false</EnableUAC>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;XYPARSER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableUAC>false</EnableUAC>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;XYPARSER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableUAC>false</EnableUAC>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="framework.h" />
|
||||||
|
<ClInclude Include="pch.h" />
|
||||||
|
<ClInclude Include="XYParserApi.h" />
|
||||||
|
<ClInclude Include="XYEegParser8.h" />
|
||||||
|
<ClInclude Include="XYEegParser64.h" />
|
||||||
|
<ClInclude Include="XYEegParserCommon.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="dllmain.cpp" />
|
||||||
|
<ClCompile Include="pch.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="XYParserApi.cpp" />
|
||||||
|
<ClCompile Include="XYEegParser8.cpp" />
|
||||||
|
<ClCompile Include="XYEegParser64.cpp" />
|
||||||
|
<ClCompile Include="XYEegParserExample.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
57
XYParser/XYParser.vcxproj.filters
Normal file
57
XYParser/XYParser.vcxproj.filters
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="源文件">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="头文件">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="资源文件">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="framework.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="pch.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="XYParserApi.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="XYEegParser8.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="XYEegParser64.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="XYEegParserCommon.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="dllmain.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="pch.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="XYParserApi.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="XYEegParser8.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="XYEegParser64.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="XYEegParserExample.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
BIN
XYParser/XYParser/x64/Debug/XYEegParser64.obj
Normal file
BIN
XYParser/XYParser/x64/Debug/XYEegParser64.obj
Normal file
Binary file not shown.
BIN
XYParser/XYParser/x64/Debug/XYEegParser8.obj
Normal file
BIN
XYParser/XYParser/x64/Debug/XYEegParser8.obj
Normal file
Binary file not shown.
BIN
XYParser/XYParser/x64/Debug/XYEegParserExample.obj
Normal file
BIN
XYParser/XYParser/x64/Debug/XYEegParserExample.obj
Normal file
Binary file not shown.
11
XYParser/XYParser/x64/Debug/XYParser.dll.recipe
Normal file
11
XYParser/XYParser/x64/Debug/XYParser.dll.recipe
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project>
|
||||||
|
<ProjectOutputs>
|
||||||
|
<ProjectOutput>
|
||||||
|
<FullPath>C:\Users\xyyl666\Desktop\XYParser\XYParser\x64\Debug\XYParser.dll</FullPath>
|
||||||
|
</ProjectOutput>
|
||||||
|
</ProjectOutputs>
|
||||||
|
<ContentFiles />
|
||||||
|
<SatelliteDlls />
|
||||||
|
<NonRecipeFileRefs />
|
||||||
|
</Project>
|
||||||
BIN
XYParser/XYParser/x64/Debug/XYParser.ilk
Normal file
BIN
XYParser/XYParser/x64/Debug/XYParser.ilk
Normal file
Binary file not shown.
9
XYParser/XYParser/x64/Debug/XYParser.log
Normal file
9
XYParser/XYParser/x64/Debug/XYParser.log
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
pch.cpp
|
||||||
|
dllmain.cpp
|
||||||
|
XYParserApi.cpp
|
||||||
|
XYEegParser8.cpp
|
||||||
|
XYEegParser64.cpp
|
||||||
|
XYEegParserExample.cpp
|
||||||
|
正在生成代码...
|
||||||
|
正在创建库 C:\Users\xyyl666\Desktop\XYParser\XYParser\x64\Debug\XYParser.lib 和对象 C:\Users\xyyl666\Desktop\XYParser\XYParser\x64\Debug\XYParser.exp
|
||||||
|
XYParser.vcxproj -> C:\Users\xyyl666\Desktop\XYParser\XYParser\x64\Debug\XYParser.dll
|
||||||
BIN
XYParser/XYParser/x64/Debug/XYParser.pch
Normal file
BIN
XYParser/XYParser/x64/Debug/XYParser.pch
Normal file
Binary file not shown.
BIN
XYParser/XYParser/x64/Debug/XYParser.tlog/CL.command.1.tlog
Normal file
BIN
XYParser/XYParser/x64/Debug/XYParser.tlog/CL.command.1.tlog
Normal file
Binary file not shown.
BIN
XYParser/XYParser/x64/Debug/XYParser.tlog/CL.read.1.tlog
Normal file
BIN
XYParser/XYParser/x64/Debug/XYParser.tlog/CL.read.1.tlog
Normal file
Binary file not shown.
BIN
XYParser/XYParser/x64/Debug/XYParser.tlog/CL.write.1.tlog
Normal file
BIN
XYParser/XYParser/x64/Debug/XYParser.tlog/CL.write.1.tlog
Normal file
Binary file not shown.
6
XYParser/XYParser/x64/Debug/XYParser.tlog/Cl.items.tlog
Normal file
6
XYParser/XYParser/x64/Debug/XYParser.tlog/Cl.items.tlog
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
C:\Users\xyyl666\Desktop\XYParser\XYParser\dllmain.cpp;C:\Users\xyyl666\Desktop\XYParser\XYParser\XYParser\x64\Debug\dllmain.obj
|
||||||
|
C:\Users\xyyl666\Desktop\XYParser\XYParser\pch.cpp;C:\Users\xyyl666\Desktop\XYParser\XYParser\XYParser\x64\Debug\pch.obj
|
||||||
|
C:\Users\xyyl666\Desktop\XYParser\XYParser\XYParserApi.cpp;C:\Users\xyyl666\Desktop\XYParser\XYParser\XYParser\x64\Debug\XYParserApi.obj
|
||||||
|
C:\Users\xyyl666\Desktop\XYParser\XYParser\XYEegParser8.cpp;C:\Users\xyyl666\Desktop\XYParser\XYParser\XYParser\x64\Debug\XYEegParser8.obj
|
||||||
|
C:\Users\xyyl666\Desktop\XYParser\XYParser\XYEegParser64.cpp;C:\Users\xyyl666\Desktop\XYParser\XYParser\XYParser\x64\Debug\XYEegParser64.obj
|
||||||
|
C:\Users\xyyl666\Desktop\XYParser\XYParser\XYEegParserExample.cpp;C:\Users\xyyl666\Desktop\XYParser\XYParser\XYParser\x64\Debug\XYEegParserExample.obj
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
PlatformToolSet=v143:VCToolArchitecture=Native32Bit:VCToolsVersion=14.44.35207:TargetPlatformVersion=10.0.26100.0:
|
||||||
|
Debug|x64|C:\Users\xyyl666\Desktop\XYParser\XYParser\|
|
||||||
BIN
XYParser/XYParser/x64/Debug/XYParser.tlog/link.command.1.tlog
Normal file
BIN
XYParser/XYParser/x64/Debug/XYParser.tlog/link.command.1.tlog
Normal file
Binary file not shown.
BIN
XYParser/XYParser/x64/Debug/XYParser.tlog/link.read.1.tlog
Normal file
BIN
XYParser/XYParser/x64/Debug/XYParser.tlog/link.read.1.tlog
Normal file
Binary file not shown.
@@ -0,0 +1,4 @@
|
|||||||
|
^C:\USERS\XYYL666\DESKTOP\XYPARSER\XYPARSER\XYPARSER\X64\DEBUG\DLLMAIN.OBJ|C:\USERS\XYYL666\DESKTOP\XYPARSER\XYPARSER\XYPARSER\X64\DEBUG\PCH.OBJ|C:\USERS\XYYL666\DESKTOP\XYPARSER\XYPARSER\XYPARSER\X64\DEBUG\XYEEGPARSER64.OBJ|C:\USERS\XYYL666\DESKTOP\XYPARSER\XYPARSER\XYPARSER\X64\DEBUG\XYEEGPARSER8.OBJ|C:\USERS\XYYL666\DESKTOP\XYPARSER\XYPARSER\XYPARSER\X64\DEBUG\XYEEGPARSEREXAMPLE.OBJ|C:\USERS\XYYL666\DESKTOP\XYPARSER\XYPARSER\XYPARSER\X64\DEBUG\XYPARSERAPI.OBJ
|
||||||
|
C:\Users\xyyl666\Desktop\XYParser\XYParser\x64\Debug\XYParser.lib
|
||||||
|
C:\Users\xyyl666\Desktop\XYParser\XYParser\x64\Debug\XYParser.EXP
|
||||||
|
C:\Users\xyyl666\Desktop\XYParser\XYParser\XYParser\x64\Debug\XYParser.ilk
|
||||||
BIN
XYParser/XYParser/x64/Debug/XYParser.tlog/link.write.1.tlog
Normal file
BIN
XYParser/XYParser/x64/Debug/XYParser.tlog/link.write.1.tlog
Normal file
Binary file not shown.
BIN
XYParser/XYParser/x64/Debug/XYParserApi.obj
Normal file
BIN
XYParser/XYParser/x64/Debug/XYParserApi.obj
Normal file
Binary file not shown.
BIN
XYParser/XYParser/x64/Debug/dllmain.obj
Normal file
BIN
XYParser/XYParser/x64/Debug/dllmain.obj
Normal file
Binary file not shown.
BIN
XYParser/XYParser/x64/Debug/pch.obj
Normal file
BIN
XYParser/XYParser/x64/Debug/pch.obj
Normal file
Binary file not shown.
BIN
XYParser/XYParser/x64/Debug/vc143.idb
Normal file
BIN
XYParser/XYParser/x64/Debug/vc143.idb
Normal file
Binary file not shown.
BIN
XYParser/XYParser/x64/Debug/vc143.pdb
Normal file
BIN
XYParser/XYParser/x64/Debug/vc143.pdb
Normal file
Binary file not shown.
154
XYParser/XYParserApi.cpp
Normal file
154
XYParser/XYParserApi.cpp
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "XYParserApi.h"
|
||||||
|
|
||||||
|
#include "XYEegParser8.h"
|
||||||
|
#include "XYEegParser64.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <new>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct ParserContext {
|
||||||
|
std::uint8_t channel_count = 0;
|
||||||
|
XYEegParser8 parser8;
|
||||||
|
XYEegParser64 parser64;
|
||||||
|
std::string last_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
void FillSummary(const XYEegFrame8& frame, XYParserFrameSummary& summary)
|
||||||
|
{
|
||||||
|
summary.frame_index = frame.index;
|
||||||
|
summary.channel_count = frame.channel_count;
|
||||||
|
summary.battery = frame.battery;
|
||||||
|
summary.sample_count = static_cast<std::uint8_t>(frame.samples.size());
|
||||||
|
for (std::size_t sample_index = 0; sample_index < XYPARSER_SAMPLES_PER_FRAME; ++sample_index) {
|
||||||
|
summary.trigger_types[sample_index] = frame.samples[sample_index].trigger_type;
|
||||||
|
summary.trigger_indices[sample_index] = frame.samples[sample_index].trigger_index;
|
||||||
|
for (std::size_t channel_index = 0; channel_index < XYPARSER_MAX_CHANNELS; ++channel_index) {
|
||||||
|
summary.channel_values_uv[sample_index][channel_index] =
|
||||||
|
channel_index < frame.channel_count
|
||||||
|
? frame.samples[sample_index].channel_values_uv[channel_index]
|
||||||
|
: 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FillSummary(const XYEegFrame64& frame, XYParserFrameSummary& summary)
|
||||||
|
{
|
||||||
|
summary.frame_index = frame.index;
|
||||||
|
summary.channel_count = frame.channel_count;
|
||||||
|
summary.battery = frame.battery;
|
||||||
|
summary.sample_count = static_cast<std::uint8_t>(frame.samples.size());
|
||||||
|
for (std::size_t sample_index = 0; sample_index < XYPARSER_SAMPLES_PER_FRAME; ++sample_index) {
|
||||||
|
summary.trigger_types[sample_index] = frame.samples[sample_index].trigger_type;
|
||||||
|
summary.trigger_indices[sample_index] = frame.samples[sample_index].trigger_index;
|
||||||
|
for (std::size_t channel_index = 0; channel_index < XYPARSER_MAX_CHANNELS; ++channel_index) {
|
||||||
|
summary.channel_values_uv[sample_index][channel_index] =
|
||||||
|
channel_index < frame.channel_count
|
||||||
|
? frame.samples[sample_index].channel_values_uv[channel_index]
|
||||||
|
: 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
XYParserHandle XYParser_CreateParser(std::uint8_t channel_count)
|
||||||
|
{
|
||||||
|
if (channel_count != 8 && channel_count != 64) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParserContext* context = new (std::nothrow) ParserContext();
|
||||||
|
if (context == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->channel_count = channel_count;
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XYParser_DestroyParser(XYParserHandle handle)
|
||||||
|
{
|
||||||
|
ParserContext* context = static_cast<ParserContext*>(handle);
|
||||||
|
delete context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XYParser_SetAdcParams(XYParserHandle handle, double vref, double gain)
|
||||||
|
{
|
||||||
|
ParserContext* context = static_cast<ParserContext*>(handle);
|
||||||
|
if (context == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->channel_count == 8) {
|
||||||
|
context->parser8.SetAdcParams(vref, gain);
|
||||||
|
} else {
|
||||||
|
context->parser64.SetAdcParams(vref, gain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void XYParser_SetBypassChecksum(XYParserHandle handle, int bypass)
|
||||||
|
{
|
||||||
|
ParserContext* context = static_cast<ParserContext*>(handle);
|
||||||
|
if (context == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool enabled = bypass != 0;
|
||||||
|
if (context->channel_count == 8) {
|
||||||
|
context->parser8.SetBypassChecksum(enabled);
|
||||||
|
} else {
|
||||||
|
context->parser64.SetBypassChecksum(enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int XYParser_Feed(XYParserHandle handle,
|
||||||
|
const std::uint8_t* data,
|
||||||
|
std::size_t size,
|
||||||
|
XYParserFrameSummary* out_summaries,
|
||||||
|
int max_summaries)
|
||||||
|
{
|
||||||
|
ParserContext* context = static_cast<ParserContext*>(handle);
|
||||||
|
if (context == nullptr || data == nullptr || size == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_summaries < 0) {
|
||||||
|
max_summaries = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context->channel_count == 8) {
|
||||||
|
const std::vector<XYEegFrame8> frames = context->parser8.Feed(data, size);
|
||||||
|
context->last_error = context->parser8.LastError();
|
||||||
|
const int write_count = std::min<int>(static_cast<int>(frames.size()), max_summaries);
|
||||||
|
for (int i = 0; i < write_count; ++i) {
|
||||||
|
FillSummary(frames[static_cast<std::size_t>(i)], out_summaries[i]);
|
||||||
|
}
|
||||||
|
return write_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<XYEegFrame64> frames = context->parser64.Feed(data, size);
|
||||||
|
context->last_error = context->parser64.LastError();
|
||||||
|
const int write_count = std::min<int>(static_cast<int>(frames.size()), max_summaries);
|
||||||
|
for (int i = 0; i < write_count; ++i) {
|
||||||
|
FillSummary(frames[static_cast<std::size_t>(i)], out_summaries[i]);
|
||||||
|
}
|
||||||
|
return write_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* XYParser_GetLastError(XYParserHandle handle)
|
||||||
|
{
|
||||||
|
ParserContext* context = static_cast<ParserContext*>(handle);
|
||||||
|
if (context == nullptr) {
|
||||||
|
return "invalid parser handle";
|
||||||
|
}
|
||||||
|
return context->last_error.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
42
XYParser/XYParserApi.h
Normal file
42
XYParser/XYParserApi.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#ifdef XYPARSER_EXPORTS
|
||||||
|
#define XYPARSER_API __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define XYPARSER_API __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
typedef void* XYParserHandle;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
XYPARSER_MAX_CHANNELS = 64,
|
||||||
|
XYPARSER_SAMPLES_PER_FRAME = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
struct XYParserFrameSummary {
|
||||||
|
std::uint32_t frame_index;
|
||||||
|
std::uint8_t channel_count;
|
||||||
|
std::uint8_t battery;
|
||||||
|
std::uint8_t sample_count;
|
||||||
|
double channel_values_uv[XYPARSER_SAMPLES_PER_FRAME][XYPARSER_MAX_CHANNELS];
|
||||||
|
std::uint8_t trigger_types[XYPARSER_SAMPLES_PER_FRAME];
|
||||||
|
std::uint8_t trigger_indices[XYPARSER_SAMPLES_PER_FRAME];
|
||||||
|
};
|
||||||
|
|
||||||
|
XYPARSER_API XYParserHandle XYParser_CreateParser(std::uint8_t channel_count);
|
||||||
|
XYPARSER_API void XYParser_DestroyParser(XYParserHandle handle);
|
||||||
|
XYPARSER_API void XYParser_SetAdcParams(XYParserHandle handle, double vref, double gain);
|
||||||
|
XYPARSER_API void XYParser_SetBypassChecksum(XYParserHandle handle, int bypass);
|
||||||
|
XYPARSER_API int XYParser_Feed(XYParserHandle handle,
|
||||||
|
const std::uint8_t* data,
|
||||||
|
std::size_t size,
|
||||||
|
XYParserFrameSummary* out_summaries,
|
||||||
|
int max_summaries);
|
||||||
|
XYPARSER_API const char* XYParser_GetLastError(XYParserHandle handle);
|
||||||
|
|
||||||
|
}
|
||||||
19
XYParser/dllmain.cpp
Normal file
19
XYParser/dllmain.cpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// dllmain.cpp : 定义 DLL 应用程序的入口点。
|
||||||
|
#include "pch.h"
|
||||||
|
|
||||||
|
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||||
|
DWORD ul_reason_for_call,
|
||||||
|
LPVOID lpReserved
|
||||||
|
)
|
||||||
|
{
|
||||||
|
switch (ul_reason_for_call)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
5
XYParser/framework.h
Normal file
5
XYParser/framework.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
|
||||||
|
// Windows 头文件
|
||||||
|
#include <windows.h>
|
||||||
5
XYParser/pch.cpp
Normal file
5
XYParser/pch.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// pch.cpp: 与预编译标头对应的源文件
|
||||||
|
|
||||||
|
#include "pch.h"
|
||||||
|
|
||||||
|
// 当使用预编译的头时,需要使用此源文件,编译才能成功。
|
||||||
13
XYParser/pch.h
Normal file
13
XYParser/pch.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// pch.h: 这是预编译标头文件。
|
||||||
|
// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
|
||||||
|
// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
|
||||||
|
// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
|
||||||
|
// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。
|
||||||
|
|
||||||
|
#ifndef PCH_H
|
||||||
|
#define PCH_H
|
||||||
|
|
||||||
|
// 添加要在此处预编译的标头
|
||||||
|
#include "framework.h"
|
||||||
|
|
||||||
|
#endif //PCH_H
|
||||||
BIN
XYParser/x64/Debug/XYParser.dll
Normal file
BIN
XYParser/x64/Debug/XYParser.dll
Normal file
Binary file not shown.
BIN
XYParser/x64/Debug/XYParser.exp
Normal file
BIN
XYParser/x64/Debug/XYParser.exp
Normal file
Binary file not shown.
BIN
XYParser/x64/Debug/XYParser.lib
Normal file
BIN
XYParser/x64/Debug/XYParser.lib
Normal file
Binary file not shown.
BIN
XYParser/x64/Debug/XYParser.pdb
Normal file
BIN
XYParser/x64/Debug/XYParser.pdb
Normal file
Binary file not shown.
Reference in New Issue
Block a user