//替換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 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 VID_Val_Dict = new Dictionary(); 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 } } 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 > // { // 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 ""; 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; }