State_SEER.cs
4.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using Rcs.Domain.Attributes;
namespace Rcs.Domain.Models.VDA5050.SEER;
/// <summary>
/// SEER(仙工)状态消息扩展。
/// 通过自定义转换器兼容 information 中的动态对象/数组字段。
/// </summary>
[ProtocolInfo("SEER", "2.0.0", nameof(State))]
[JsonConverter(typeof(StateSeerJsonConverter))]
public class State_SEER : State
{
/// <summary>
/// 货叉机构状态(SEER扩展字段)
/// </summary>
[JsonPropertyName("forkState")]
public SeerForkState? ForkState { get; set; }
/// <summary>
/// 是否等待交互区释放(SEER扩展字段,可忽略)
/// </summary>
[JsonPropertyName("waitingForInteractionZoneRelease")]
public bool? WaitingForInteractionZoneRelease { get; set; }
}
/// <summary>
/// SEER货叉状态
/// </summary>
public class SeerForkState
{
/// <summary>
/// 货叉高度
/// </summary>
[JsonPropertyName("forkHeight")]
public double? ForkHeight { get; set; }
}
internal sealed class StateSeerJsonConverter : JsonConverter<State_SEER>
{
public override State_SEER? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var rootNode = JsonNode.Parse(ref reader) as JsonObject
?? throw new JsonException("SEER state payload is not a JSON object.");
// SEER 的 information.infoReferences.referenceValue 可能是对象/数组,
// 先移除该字段后按基础 State 反序列化,避免 string 类型转换错误。
var baseNode = rootNode.DeepClone() as JsonObject ?? new JsonObject();
baseNode.Remove("information");
var baseState = baseNode.Deserialize<State>(options) ?? new State();
var seerState = new State_SEER();
CopyState(baseState, seerState);
if (rootNode.TryGetPropertyValue("forkState", out var forkNode) && forkNode is not null)
{
seerState.ForkState = forkNode.Deserialize<SeerForkState>(options);
}
if (rootNode.TryGetPropertyValue("waitingForInteractionZoneRelease", out var waitNode)
&& waitNode is JsonValue waitValue
&& waitValue.TryGetValue<bool>(out var waiting))
{
seerState.WaitingForInteractionZoneRelease = waiting;
}
return seerState;
}
public override void Write(Utf8JsonWriter writer, State_SEER value, JsonSerializerOptions options)
{
var baseNode = JsonSerializer.SerializeToNode((State)value, options)?.AsObject() ?? new JsonObject();
if (value.ForkState is not null)
{
baseNode["forkState"] = JsonSerializer.SerializeToNode(value.ForkState, options);
}
if (value.WaitingForInteractionZoneRelease.HasValue)
{
baseNode["waitingForInteractionZoneRelease"] = value.WaitingForInteractionZoneRelease.Value;
}
baseNode.WriteTo(writer, options);
}
private static void CopyState(State source, State target)
{
target.HeaderId = source.HeaderId;
target.Timestamp = source.Timestamp;
target.Version = source.Version;
target.Manufacturer = source.Manufacturer;
target.SerialNumber = source.SerialNumber;
target.Maps = source.Maps;
target.OrderId = source.OrderId;
target.OrderUpdateId = source.OrderUpdateId;
target.ZoneSetId = source.ZoneSetId;
target.LastNodeId = source.LastNodeId;
target.LastNodeSequenceId = source.LastNodeSequenceId;
target.NodeStates = source.NodeStates;
target.EdgeStates = source.EdgeStates;
target.AgvPosition = source.AgvPosition;
target.Velocity = source.Velocity;
target.Loads = source.Loads;
target.Driving = source.Driving;
target.Paused = source.Paused;
target.NewBaseRequest = source.NewBaseRequest;
target.DistanceSinceLastNode = source.DistanceSinceLastNode;
target.ActionStates = source.ActionStates;
target.BatteryState = source.BatteryState;
target.OperatingMode = source.OperatingMode;
target.Errors = source.Errors;
target.Information = source.Information;
target.SafetyState = source.SafetyState;
}
}