bugfix: 修复已知bug
This commit is contained in:
@@ -5,65 +5,95 @@
|
||||
---
|
||||
|
||||
## 1. 日志格式
|
||||
|
||||
**格式:** `FOD-> (1) X X X (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13)`
|
||||
|
||||
**示例:** `FOD-> 4 2 1 127 10690 12013 35377 9904 1213 -2882 750 0 0 1 500 1`
|
||||
|
||||
> 括号数字表示有效字段编号,X 表示忽略该位置数据
|
||||
```
|
||||
pow_loss = 3053, delta_p = 1950
|
||||
FOD-> (1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 字段定义
|
||||
|
||||
### 2.1 第一行字段
|
||||
|
||||
| 编号 | 字段名称 | 数据类型 | 说明 |
|
||||
|------|----------|----------|------|
|
||||
| (1) | RxType | byte | 接收端类型标识 |
|
||||
| (2) | RxPower | short | 接收端功率(mW) |
|
||||
| (3) | TxPower | short | 发射端功率(mW) |
|
||||
| (4) | Vcoil | short | 发射线圈电压 |
|
||||
| (5) | Vin | short | 输入电压 |
|
||||
| (6) | Isns | short | 输入电流采样值 |
|
||||
| (7) | Ploss | int | **核心值**:计算损耗(负数表示安全) |
|
||||
| (8) | Threshold | int | **安全红线**:当前功率段阈值 |
|
||||
| (9) | TriggerCount | short | 触发计数器 |
|
||||
| (10) | FodResult | short | FOD判定结果状态 |
|
||||
| (11) | ProtocolType | byte | 充电协议类型 |
|
||||
| (12) | PwmDuty | short | PWM控制占空比 |
|
||||
| (13) | CoilIndex | byte | 充电线圈索引 |
|
||||
| (A) | PowLoss | int | 功率损耗值 |
|
||||
| (B) | DeltaP | int | 功率差值 |
|
||||
|
||||
### 2.2 第二行字段 (FOD->)
|
||||
|
||||
| 编号 | 字段名称 | 数据类型 | 说明 |
|
||||
|------|----------|----------|------|
|
||||
| (1) | Field1 | int | 待定义 |
|
||||
| (2) | Field2 | int | 待定义 |
|
||||
| (3) | Field3 | int | 待定义 |
|
||||
| (4) | Field4 | int | 待定义 |
|
||||
| (5) | Field5 | int | 待定义 |
|
||||
| (6) | Field6 | int | 待定义 |
|
||||
| (7) | Field7 | int | 待定义 |
|
||||
| (8) | Field8 | int | 待定义 |
|
||||
| (9) | Field9 | int | 待定义 |
|
||||
| (10) | Field10 | int | 待定义 |
|
||||
| (11) | Field11 | int | 待定义 |
|
||||
| (12) | Field12 | int | 待定义 |
|
||||
| (13) | Field13 | int | 待定义 |
|
||||
| (14) | Field14 | int | 待定义 |
|
||||
| (15) | Field15 | int | 待定义 |
|
||||
| (16) | Field16 | int | 待定义 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 正则表达式
|
||||
|
||||
> **修正说明**:原设计稿正则只有2个忽略字段,实际格式有3个X(忽略字段),已修正。
|
||||
日志由两行组成,需要分别匹配:
|
||||
|
||||
```csharp
|
||||
// Parsers/PlossParser.cs
|
||||
// 格式: FOD-> (1) X X X (2) (3) ... (13),其中3个X需要3个 \d+ 忽略
|
||||
private static readonly Regex PlossPattern = new(
|
||||
@"^FOD->\s+(\d+)\s+\d+\s+\d+\s+\d+\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(-?\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$",
|
||||
// 第一行格式: pow_loss = 3053, delta_p = 1950
|
||||
private static readonly Regex HeaderPattern = new(
|
||||
@"^pow_loss\s*=\s*(\d+),\s*delta_p\s*=\s*(\d+)$",
|
||||
RegexOptions.Compiled
|
||||
);
|
||||
|
||||
// 第二行格式: FOD-> 后跟16个数字(均支持负数)
|
||||
private static readonly Regex FodPattern = new(
|
||||
@"^FOD->\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)$",
|
||||
RegexOptions.Compiled
|
||||
);
|
||||
```
|
||||
|
||||
> **说明**:所有16个字段均支持负数,使用 `-?\d+` 匹配。
|
||||
|
||||
**捕获组映射:**
|
||||
|
||||
**第一行 (HeaderPattern):**
|
||||
|
||||
| 捕获组 | 字段 | 类型转换 |
|
||||
|--------|------|----------|
|
||||
| Group 1 | RxType | byte.Parse() |
|
||||
| Group 2 | RxPower | short.Parse() |
|
||||
| Group 3 | TxPower | short.Parse() |
|
||||
| Group 4 | Vcoil | short.Parse() |
|
||||
| Group 5 | Vin | short.Parse() |
|
||||
| Group 6 | Isns | short.Parse() |
|
||||
| Group 7 | Ploss | int.Parse() |
|
||||
| Group 8 | Threshold | int.Parse() |
|
||||
| Group 9 | TriggerCount | short.Parse() |
|
||||
| Group 10 | FodResult | short.Parse() |
|
||||
| Group 11 | ProtocolType | byte.Parse() |
|
||||
| Group 12 | PwmDuty | short.Parse() |
|
||||
| Group 13 | CoilIndex | byte.Parse() |
|
||||
| Group 1 | PowLoss | int.Parse() |
|
||||
| Group 2 | DeltaP | int.Parse() |
|
||||
|
||||
**第二行 (FodPattern):**
|
||||
|
||||
| 捕获组 | 字段 | 类型转换 |
|
||||
|--------|------|----------|
|
||||
| Group 1 | Field1 | int.Parse() |
|
||||
| Group 2 | Field2 | int.Parse() |
|
||||
| Group 3 | Field3 | int.Parse() |
|
||||
| Group 4 | Field4 | int.Parse() |
|
||||
| Group 5 | Field5 | int.Parse() |
|
||||
| Group 6 | Field6 | int.Parse() |
|
||||
| Group 7 | Field7 | int.Parse() |
|
||||
| Group 8 | Field8 | int.Parse() |
|
||||
| Group 9 | Field9 | int.Parse() |
|
||||
| Group 10 | Field10 | int.Parse() |
|
||||
| Group 11 | Field11 | int.Parse() |
|
||||
| Group 12 | Field12 | int.Parse() |
|
||||
| Group 13 | Field13 | int.Parse() |
|
||||
| Group 14 | Field14 | int.Parse() |
|
||||
| Group 15 | Field15 | int.Parse() |
|
||||
| Group 16 | Field16 | int.Parse() |
|
||||
|
||||
---
|
||||
|
||||
@@ -78,57 +108,102 @@ namespace WCTDataMiner.Parsers;
|
||||
|
||||
public class PlossParser : IParser<PlossRecord>
|
||||
{
|
||||
private static readonly Regex PlossPattern = new(
|
||||
@"^FOD->\s+(\d+)\s+\d+\s+\d+\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(-?\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$",
|
||||
private static readonly Regex HeaderPattern = new(
|
||||
@"^pow_loss\s*=\s*(\d+),\s*delta_p\s*=\s*(\d+)$",
|
||||
RegexOptions.Compiled
|
||||
);
|
||||
|
||||
public bool CanParse(string line) => PlossPattern.IsMatch(line);
|
||||
private static readonly Regex FodPattern = new(
|
||||
@"^FOD->\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)$",
|
||||
RegexOptions.Compiled
|
||||
);
|
||||
|
||||
public bool CanParse(string line) => HeaderPattern.IsMatch(line) || FodPattern.IsMatch(line);
|
||||
|
||||
public ParseResult<PlossRecord> Parse(string line, Guid scenarioId)
|
||||
{
|
||||
var match = PlossPattern.Match(line);
|
||||
if (!match.Success)
|
||||
// 尝试匹配第一行
|
||||
var headerMatch = HeaderPattern.Match(line);
|
||||
if (headerMatch.Success)
|
||||
{
|
||||
return ParseResult<PlossRecord>.Failure(
|
||||
"FORMAT_MISMATCH",
|
||||
"Line does not match Ploss pattern"
|
||||
);
|
||||
return ParseHeaderLine(headerMatch, scenarioId);
|
||||
}
|
||||
|
||||
// 尝试匹配第二行
|
||||
var fodMatch = FodPattern.Match(line);
|
||||
if (fodMatch.Success)
|
||||
{
|
||||
return ParseFodLine(fodMatch, scenarioId);
|
||||
}
|
||||
|
||||
return ParseResult<PlossRecord>.Failure(
|
||||
"FORMAT_MISMATCH",
|
||||
"Line does not match Ploss pattern"
|
||||
);
|
||||
}
|
||||
|
||||
private ParseResult<PlossRecord> ParseHeaderLine(Match match, Guid scenarioId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var record = new PlossRecord
|
||||
{
|
||||
ScenarioId = scenarioId,
|
||||
RxType = byte.Parse(match.Groups[1].Value),
|
||||
RxPower = short.Parse(match.Groups[2].Value),
|
||||
TxPower = short.Parse(match.Groups[3].Value),
|
||||
Vcoil = short.Parse(match.Groups[4].Value),
|
||||
Vin = short.Parse(match.Groups[5].Value),
|
||||
Isns = short.Parse(match.Groups[6].Value),
|
||||
Ploss = int.Parse(match.Groups[7].Value),
|
||||
Threshold = int.Parse(match.Groups[8].Value),
|
||||
TriggerCount = short.Parse(match.Groups[9].Value),
|
||||
FodResult = short.Parse(match.Groups[10].Value),
|
||||
ProtocolType = byte.Parse(match.Groups[11].Value),
|
||||
PwmDuty = short.Parse(match.Groups[12].Value),
|
||||
CoilIndex = byte.Parse(match.Groups[13].Value)
|
||||
PowLoss = int.Parse(match.Groups[1].Value),
|
||||
DeltaP = int.Parse(match.Groups[2].Value),
|
||||
IsHeaderLine = true
|
||||
};
|
||||
|
||||
return ParseResult<PlossRecord>.Success(record);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ParseResult<PlossRecord>.Failure(
|
||||
"TYPE_CONVERSION",
|
||||
$"Failed to convert field: {ex.Message}"
|
||||
$"Failed to convert header field: {ex.Message}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private ParseResult<PlossRecord> ParseFodLine(Match match, Guid scenarioId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var record = new PlossRecord
|
||||
{
|
||||
ScenarioId = scenarioId,
|
||||
Field1 = int.Parse(match.Groups[1].Value),
|
||||
Field2 = int.Parse(match.Groups[2].Value),
|
||||
Field3 = int.Parse(match.Groups[3].Value),
|
||||
Field4 = int.Parse(match.Groups[4].Value),
|
||||
Field5 = int.Parse(match.Groups[5].Value),
|
||||
Field6 = int.Parse(match.Groups[6].Value),
|
||||
Field7 = int.Parse(match.Groups[7].Value),
|
||||
Field8 = int.Parse(match.Groups[8].Value),
|
||||
Field9 = int.Parse(match.Groups[9].Value),
|
||||
Field10 = int.Parse(match.Groups[10].Value),
|
||||
Field11 = int.Parse(match.Groups[11].Value),
|
||||
Field12 = int.Parse(match.Groups[12].Value),
|
||||
Field13 = int.Parse(match.Groups[13].Value),
|
||||
Field14 = int.Parse(match.Groups[14].Value),
|
||||
Field15 = int.Parse(match.Groups[15].Value),
|
||||
Field16 = int.Parse(match.Groups[16].Value),
|
||||
IsHeaderLine = false
|
||||
};
|
||||
return ParseResult<PlossRecord>.Success(record);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ParseResult<PlossRecord>.Failure(
|
||||
"TYPE_CONVERSION",
|
||||
$"Failed to convert FOD field: {ex.Message}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> **注意**:实际实现中,两行日志需要合并为一条完整记录。可以使用 `PlossRecordMerger` 或在业务逻辑层处理合并。
|
||||
|
||||
---
|
||||
|
||||
## 5. 核心判定逻辑
|
||||
|
||||
Reference in New Issue
Block a user