|
//替換MESDefaultMapAction.cs 裡的
|
|
public void Receive_S1F3W(SecsMessage msg, UInt32 SystemByte)
|
|
{
|
|
UInt32 currentVID = 0; // Used to log VID in case of an error during SetValue
|
|
object currentValue = null; // Used to log the original value in case of an error
|
|
string currentVidName = "UNKNOWN"; // Used to log VID name
|
|
SecsItem.SecsIndexType currentSecsType = default(SecsItem.SecsIndexType); // Used to log SECS type
|
|
|
|
try
|
|
{
|
|
SCUtility.jsecsActionRecordMsg(jSecs, true, msg, SystemByte);
|
|
|
|
Int32 SVID_Count = new Int32();
|
|
// Get_List returns the count, ensure it's not an error code itself
|
|
if (msg.Body().Get_List(ref SVID_Count) < 0 || SVID_Count < 0)
|
|
{
|
|
logger_SystemError.Error($"[Receive_S1F3W] Invalid SVID_Count ({SVID_Count}) from S1F3 message. SystemByte: {SystemByte}");
|
|
jSecs.UnrecognizedError(UnrecognizedErrorType.InvalidData, ref SystemByte);
|
|
return;
|
|
}
|
|
|
|
SecsMessage S1F4 = BodyCreator.Create_S1F4();
|
|
S1F4.Body().Set_List(SVID_Count);
|
|
|
|
Dictionary<int, VID> vidDefinitions = null;
|
|
try
|
|
{
|
|
vidDefinitions = jSecs.Read_VID();
|
|
if (vidDefinitions == null)
|
|
{
|
|
throw new InvalidOperationException("jSecs.Read_VID() returned null.");
|
|
}
|
|
}
|
|
catch (Exception exReadVid)
|
|
{
|
|
logger_SystemError.Error(exReadVid, $"[Receive_S1F3W] Failed to read VID definitions (jSecs.Read_VID()). SystemByte: {SystemByte}. Exception: {exReadVid.Message}");
|
|
//jSecs.UnrecognizedError(UnrecognizedErrorType.SystemError, ref SystemByte);
|
|
jSecs.UnrecognizedError(UnrecognizedErrorType.InvalidData, ref SystemByte);
|
|
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < SVID_Count; i++)
|
|
{
|
|
UInt32[] Request_VID_Array = new UInt32[1]; // SECS U4 is an array of 1 item
|
|
if (msg.Body().I((uint)i).Get_U4(ref Request_VID_Array) == -1)
|
|
{
|
|
logger_SystemError.Error($"[Receive_S1F3W] Failed to get U4 VID at S1F3 body index {i}. SystemByte: {SystemByte}");
|
|
jSecs.UnrecognizedError(UnrecognizedErrorType.InvalidData, ref SystemByte);
|
|
return;
|
|
}
|
|
currentVID = Request_VID_Array[0];
|
|
currentVidName = vidDefinitions.ContainsKey((int)currentVID) ? vidDefinitions[(int)currentVID].Name : "UNKNOWN_VID_NAME";
|
|
|
|
logger.Debug($"[Receive_S1F3W] Processing S1F3 item {(i + 1)}/{SVID_Count} - VID: {currentVID} ({currentVidName})");
|
|
|
|
Dictionary<SecsItem.SecsIndexType, object> VID_Val_Dict = new Dictionary<SecsItem.SecsIndexType, object>();
|
|
|
|
int queryStatus = -1;
|
|
try
|
|
{
|
|
// Assuming QueryCurrentVID is defined elsewhere in this class or a base class
|
|
queryStatus = QueryCurrentVID((int)currentVID, ref VID_Val_Dict);
|
|
}
|
|
catch (Exception exQuery)
|
|
{
|
|
logger_SystemError.Error(exQuery, $"[Receive_S1F3W] Exception during QueryCurrentVID for VID: {currentVID} ({currentVidName}). SystemByte: {SystemByte}. Exception: {exQuery.Message}");
|
|
//jSecs.UnrecognizedError(UnrecognizedErrorType.SystemError, ref SystemByte);
|
|
jSecs.UnrecognizedError(UnrecognizedErrorType.InvalidData, ref SystemByte);
|
|
return;
|
|
}
|
|
|
|
if (queryStatus != 0)
|
|
{
|
|
logger.Warn($"[Receive_S1F3W] QueryCurrentVID failed (returned {queryStatus}) for VID: {currentVID} ({currentVidName}). SystemByte: {SystemByte}");
|
|
jSecs.UnrecognizedError(UnrecognizedErrorType.InvalidData, ref SystemByte);
|
|
return;
|
|
}
|
|
|
|
if (VID_Val_Dict.Count > 0)
|
|
{
|
|
foreach (var vobj in VID_Val_Dict)
|
|
{
|
|
currentValue = vobj.Value;
|
|
currentSecsType = vobj.Key;
|
|
try
|
|
{
|
|
logger.Debug($"[Receive_S1F3W] VID: {currentVID} ({currentVidName}), QueryResult Value: '{TruncateValueForLog(currentValue)}' (Type: {currentValue?.GetType().FullName}), TargetSECSDataType: {currentSecsType}");
|
|
|
|
if (currentSecsType == SecsItem.SecsIndexType.List)
|
|
{
|
|
if (currentValue is System.Collections.IList listData)
|
|
{
|
|
int listSize = listData.Count;
|
|
S1F4.Body().I((uint)i).Set_List(listSize);
|
|
for (int listItemIndex = 0; listItemIndex < listSize; listItemIndex++)
|
|
{
|
|
object listItem = listData[listItemIndex];
|
|
SecsItem.SecsIndexType listItemSecsType = DetermineListItemSecsType(currentVID, listItem, listItemIndex);
|
|
|
|
if (listItemSecsType == default(SecsItem.SecsIndexType))
|
|
{
|
|
logger_SystemError.Error($"[Receive_S1F3W] VID: {currentVID} ({currentVidName}), List item at index {listItemIndex} has undetermined SECS type. Value: '{TruncateValueForLog(listItem)}' (Type: {listItem?.GetType().FullName}).");
|
|
throw new InvalidOperationException($"Could not determine SECS type for list item of VID {currentVID} at index {listItemIndex}.");
|
|
}
|
|
S1F4.Body().I((uint)i).I((uint)listItemIndex).SetValue(listItemSecsType, listItem);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
logger_SystemError.Error($"[Receive_S1F3W] VID: {currentVID} ({currentVidName}), queried value for List type is not an IList. Actual type: {currentValue?.GetType().FullName}. Value: '{TruncateValueForLog(currentValue)}'");
|
|
// Potentially set an empty list or error for this item in S1F4
|
|
S1F4.Body().I((uint)i).Set_List(0); // Example: send <L 0>
|
|
}
|
|
}
|
|
else
|
|
{
|
|
S1F4.Body().I((uint)i).SetValue(currentSecsType, currentValue);
|
|
}
|
|
}
|
|
catch (ArgumentException exSetValue)
|
|
{
|
|
logger_SystemError.Error(exSetValue, $"[Receive_S1F3W] SetValue ArgumentException for VID: {currentVID} ({currentVidName}). OriginalValue: '{TruncateValueForLog(currentValue)}', OriginalValueType: {currentValue?.GetType().FullName}, TargetSECSDataType: {currentSecsType}. Exception: {exSetValue.Message}");
|
|
// Handle error for this specific item - e.g., skip or try to set an error if S1F4 allows
|
|
// If you skip, S1F4 might be malformed if SVID_Count doesn't match actual items.
|
|
// Consider if the entire S1F4 should be aborted.
|
|
}
|
|
catch (NotSupportedException exNotSupported)
|
|
{
|
|
logger_SystemError.Error(exNotSupported, $"[Receive_S1F3W] SetValue NotSupportedException for VID: {currentVID} ({currentVidName}). OriginalValue: '{TruncateValueForLog(currentValue)}', OriginalValueType: {currentValue?.GetType().FullName}, TargetSECSDataType: {currentSecsType}. Exception: {exNotSupported.Message}");
|
|
}
|
|
catch (Exception exGenericSetValue) // Other exceptions during SetValue or list processing
|
|
{
|
|
logger_SystemError.Error(exGenericSetValue, $"[Receive_S1F3W] SetValue Generic Exception for VID: {currentVID} ({currentVidName}). OriginalValue: '{TruncateValueForLog(currentValue)}', OriginalValueType: {currentValue?.GetType().FullName}, TargetSECSDataType: {currentSecsType}. Exception: {exGenericSetValue.Message}");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
logger.Warn($"[Receive_S1F3W] QueryCurrentVID for VID: {currentVID} ({currentVidName}) returned no data (empty dictionary). SystemByte: {SystemByte}");
|
|
// Handle in S1F4: e.g. S1F4.Body().I((uint)i).Set_List(0); if it's supposed to be a list but is empty,
|
|
// or set to a default/error value if a single item was expected.
|
|
// This depends heavily on your SECS spec for the specific VID.
|
|
}
|
|
}
|
|
|
|
if (jSecs.Reply(S1F4, SystemByte) != SendReturnCode.Normal)
|
|
{
|
|
// Assuming scApp and SCAppConstants are available
|
|
// scApp.AlarmBLL.onMainAlarm(SCAppConstants.MainAlarmCode.EAP_REPLY_MSG_ERROR_1, "S1F4", SystemByte.ToString());
|
|
logger_SystemError.Error($"[Receive_S1F3W] Failed to send S1F4 reply. SystemByte: {SystemByte}");
|
|
}
|
|
SCUtility.jsecsActionRecordMsg(jSecs, false, S1F4, SystemByte);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger_SystemError.Error(ex, $"[Receive_S1F3W] Unhandled Exception. SystemByte: {SystemByte}. Last attempted VID: {currentVID} ({currentVidName}). Last Value: '{TruncateValueForLog(currentValue)}'. TargetSECSDataType: {currentSecsType}. Exception: {ex.ToString()}");
|
|
// Consider sending a generic error reply to host if appropriate (e.g., SxF0)
|
|
// jSecs.UnrecognizedError(UnrecognizedErrorType.SystemError, ref SystemByte); // Example
|
|
}
|
|
}
|
|
// THIS IS A PLACEHOLDER AND MUST BE IMPLEMENTED BASED ON YOUR EQUIPMENT'S SECS SPECIFICATION.
|
|
private SecsItem.SecsIndexType DetermineListItemSecsType(UInt32 parentVid, object listItem, int itemIndex)
|
|
{
|
|
// --- Your specific logic here ---
|
|
// This function needs to know, based on 'parentVid' (and potentially 'itemIndex' if the list has a fixed structure),
|
|
// what the SECS data type of 'listItem' should be.
|
|
|
|
// Example:
|
|
// if (parentVid == 12345) // VID 12345 is a List of U2 values
|
|
// {
|
|
// return SecsItem.SecsIndexType.U2;
|
|
// }
|
|
// else if (parentVid == 67890) // VID 67890 is <L[2] <A string1> <U4 number1>>
|
|
// {
|
|
// if (itemIndex == 0) return SecsItem.SecsIndexType.A;
|
|
// if (itemIndex == 1) return SecsItem.SecsIndexType.U4;
|
|
// }
|
|
|
|
// Fallback or error if type cannot be determined
|
|
logger_SystemError.Warn($"[DetermineListItemSecsType] Undetermined SECS type for Parent VID: {parentVid}, Item Index: {itemIndex}, Item Value: '{TruncateValueForLog(listItem)}', Item Type: {listItem?.GetType().FullName}. Implement specific logic.");
|
|
|
|
// A very generic attempt (likely insufficient for robust SECS implementation)
|
|
if (listItem is string) return SecsItem.SecsIndexType.A;
|
|
if (listItem is byte || listItem is sbyte) return SecsItem.SecsIndexType.U1; // Or I1 if signed
|
|
if (listItem is ushort || listItem is short) return SecsItem.SecsIndexType.U2; // Or I2
|
|
if (listItem is uint || listItem is int) return SecsItem.SecsIndexType.U4; // Or I4
|
|
if (listItem is ulong || listItem is long) return SecsItem.SecsIndexType.U8; // Or I8
|
|
if (listItem is float) return SecsItem.SecsIndexType.F4;
|
|
if (listItem is double) return SecsItem.SecsIndexType.F8;
|
|
if (listItem is bool) return SecsItem.SecsIndexType.Boolean;
|
|
if (listItem is byte[]) return SecsItem.SecsIndexType.B; // Or U1 if it's a single byte conceptually
|
|
|
|
return default(SecsItem.SecsIndexType); // Indicates type could not be determined
|
|
}
|
|
|
|
private string TruncateValueForLog(object value, int maxLength = 100)
|
|
{
|
|
if (value == null) return "<null>";
|
|
|
|
string sValue;
|
|
if (value is byte[] bytes)
|
|
{
|
|
// For byte arrays, show a snippet if too long
|
|
if (bytes.Length > (maxLength / 2 - 5)) // Approximation: 2 chars per byte + "0x" + "..."
|
|
{
|
|
sValue = "0x" + BitConverter.ToString(bytes, 0, Math.Min(bytes.Length, maxLength / 2 - 10)).Replace("-", "") + "...";
|
|
}
|
|
else
|
|
{
|
|
sValue = "0x" + BitConverter.ToString(bytes).Replace("-", "");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sValue = value.ToString();
|
|
}
|
|
|
|
if (sValue.Length > maxLength)
|
|
{
|
|
return sValue.Substring(0, maxLength - 3) + "...";
|
|
}
|
|
return sValue;
|
|
}
|