using DTS.Common.Enums; using DTS.Common.Enums.DASFactory; using DTS.Common.Interface.DASFactory; using DTS.Common.Interface.DASFactory.Config; using System; namespace DTS.Common.Classes.TMAT { /// /// these are all the patterns that represent global keys /// public enum TMTGlobalKeys { [TMTKey("{NAME OF PROGRAM}")] NameOfProgram, [TMTKey("{TEST ID}")] TestId, [TMTKey("{DAS SERIAL NUMBER}")] DASSerialNumber, [TMTKey("{DAS INDEX}")] DASIndex, [TMTKey("{DAS SAMPLE RATE}")] DASSampleRate, [TMTKey("{TEST TIMESTAMP}")] TestTimeStamp, [TMTKey("{DAS BIT RATE}")] DASBitRate, [TMTKey("{STREAM TIME FORMAT}")] StreamTimeFormat, //FB 26736 Keys for time & data channel Id [TMTKey("{UDP STREAM TIME CHANNEL ID}")] UdpStreamTimeChannelId, [TMTKey("{UDP STREAM DATA CHANNEL ID}")] UdpStreamDataChannelId, //FB 43761 [TMTKey("{UDP STREAM UART CHANNEL ID}")] UdpStreamUartChannelId, [TMTKey("{UDP STREAM UART CHANNEL ID ENABLED}")] UdpStreamUartChannelIdEnabled, //FB 29996 Key for file creation date [TMTKey("{CREATE DATE}")] CreateDate, //http://manuscript.dts.local/f/cases/37929/Implement-TSRAIR-module-on-off-selection-via-Max-Slice-Enable-system-attribute [TMTKey("{NUMBER OF STREAMED CHANNELS}")] NumberOfStreamedChannels, [TMTKey("{NUMBER OF CHANNELS PLUS TIME}")] NumberOfChannelsPlusTime, [TMTKey("{NUMBER OF BITS PER MINOR FRAME}")] NumberOfBitsPerMinorFrame } /// /// these are all the patterns that represent channel keys when channels are all part of 1 template /// public enum TMTChannelKeys { [TMTKey("{{CHANNEL {0} HARDWARE CHANNEL NUMBER}}")] HardwareChannelNumber, [TMTKey("{{CHANNEL {0} NAME}}")] ChannelName, [TMTKey("{{CHANNEL {0} COUPLING MODE}}")] CouplingMode, [TMTKey("{{CHANNEL {0} BRIDGE RESISTANCE}}")] BridgeResistance, [TMTKey("{{CHANNEL {0} AAF}}")] AAF, [TMTKey("{{CHANNEL {0} OFFSET mV}}")] OffsetMV, [TMTKey("{{CHANNEL {0} INPUT RANGE}}")] InputRangeMV, [TMTKey("{{CHANNEL {0} MAX RANGE EU}}")] MaxRangeEU, [TMTKey("{{CHANNEL {0} MIN RANGE EU}}")] MinRangeEU, [TMTKey("{{CHANNEL {0} EU}}")] EU, [TMTKey("{{CHANNEL {0} SCALEFACTOR EU}}")] ScaleFactorEU, [TMTKey("{{CHANNEL {0} OFFSET EU}}")] OffsetEU, } /// /// these are patterns for channel keys when channels are split into a separate template /// public enum TMTChannelKeysEx { [TMTKey("{CHANNEL NUMBER}")]ChannelNumber, [TMTKey("{CHANNEL NAME}")]ChannelName, [TMTKey("{CHANNEL OFFSET EU}")]ChannelOffsetEU, [TMTKey("{CHANNEL SCALEFACTOR EU}")]ChannelScaleFactorEU, [TMTKey("{CHANNEL EU}")]ChannelEU, [TMTKey("{CHANNEL MAX RANGE EU}")]ChannelMaxRangeEU, [TMTKey("{CHANNEL MIN RANGE EU}")]ChannelMinRangeEU, [TMTKey("{BYTE FORMAT}")]ByteFormat, [TMTKey("{BYTE FORMAT2}")]ByteFormat2, [TMTKey("{CHANNEL MIDPOINT}")]ChannelMidPoint } /// /// Helper attribute, allows us to associate patterns to enums to make processing file easier /// [System.AttributeUsage(System.AttributeTargets.Field)] public class TMTKey : System.Attribute { /// /// the pattern to look for in a line to replace /// public string Key { get; set; } public TMTKey(string key) { Key = key; } /// /// returns the pattern to look for in a line for a given property /// /// /// public static string GetKey(TMTGlobalKeys o) { var mi = o.GetType().GetMember(o.ToString()); if (mi.Length <= 0) return string.Empty; return GetCustomAttribute(mi[0], typeof(TMTKey)) is TMTKey attr ? attr.Key : string.Empty; } /// /// returns the pattern to look for in a line for a given property /// /// /// public static string GetKey(TMTChannelKeysEx o) { var mi = o.GetType().GetMember(o.ToString()); if (mi.Length <= 0) return string.Empty; return GetCustomAttribute(mi[0], typeof(TMTKey)) is TMTKey attr ? attr.Key : string.Empty; } /// /// returns the pattern to look for in a line for a given channel property /// /// /// /// public static string GetKey(TMTChannelKeys o, int channelNumber) { var mi = o.GetType().GetMember(o.ToString()); if (mi.Length <= 0) return string.Empty; if (GetCustomAttribute(mi[0], typeof(TMTKey)) is TMTKey attr) { return string.Format(attr.Key, channelNumber); } else { return string.Empty; } } } [System.Diagnostics.CodeAnalysis.SuppressMessage("Minor Code Smell", "S101:Types should be named in Acronym", Justification = "")] public interface ITMTTemplate { /// /// updates the fields in the file with a given value /// /// /// void UpdateValue(TMTChannelKeysEx key, string value, int channelNumber); /// /// updates the fields in the file with a given value /// /// /// void UpdateValue(TMTGlobalKeys key, string value); /// /// updates the files in the file with the given value /// /// /// /// void UpdateValue(TMTChannelKeys key, string value, int channelNumber); /// /// returns all lines in the TMT file /// /// string[] GetAllLines(); } public abstract class TmtBase : ITMTTemplate { /// /// this is the max length of the channel name in a TMT file, /// this was done in an effort to keep TMT file length below 4k bytes /// 2019-10-10 - DTM increased this to 200 as TMT file length was increased to 16k /// private const int TMT_MAX_CHANNEL_LENGTH = 200; /// /// does the work to ensure string is of MAX_LENGTH or shorter /// /// /// public static string TMT_LimitString(string s) { return s.Substring(0, Math.Min(s.Length, TMT_MAX_CHANNEL_LENGTH)); } private static string ScaleFactorOrOffsetToString(double d) { return $"{d:0.0##########}";//F11, but strip trailing zeros } /// /// updates the given field in the template with a value /// public static void UpdateChannelField(TMTChannelKeysEx key, ITMTTemplate template, int channelIndex, float [] ranges, double minEU, double maxEU, string eu, float [] scaleFactors, double adcToEUScalingFactor, string channelName2, string offsetEU, bool bSigned) { switch (key) { case TMTChannelKeysEx.ChannelNumber: template.UpdateValue(key, $"{1 + channelIndex}", channelIndex); break; case TMTChannelKeysEx.ChannelName: template.UpdateValue(key, TMT_LimitString(channelName2), channelIndex); break; case TMTChannelKeysEx.ChannelOffsetEU: template.UpdateValue(key, TMT_LimitString(offsetEU), channelIndex); break; case TMTChannelKeysEx.ChannelScaleFactorEU: if (scaleFactors != null) { template.UpdateValue(key, ScaleFactorOrOffsetToString(scaleFactors[channelIndex]), channelIndex); } else { template.UpdateValue(key, RunTestVariables.MaskEUMetaData ? "1" : ScaleFactorOrOffsetToString(adcToEUScalingFactor), channelIndex); } break; case TMTChannelKeysEx.ByteFormat: template.UpdateValue(key, bSigned?"TWO":"OFF", channelIndex); break; case TMTChannelKeysEx.ByteFormat2: template.UpdateValue(key, bSigned?"2":"B", channelIndex); break; case TMTChannelKeysEx.ChannelMidPoint: template.UpdateValue(key, bSigned?"0":"2500", channelIndex); break; case TMTChannelKeysEx.ChannelEU: template.UpdateValue(key, RunTestVariables.MaskEUMetaData ? "---" : eu?.Trim() ?? "", channelIndex); break; case TMTChannelKeysEx.ChannelMaxRangeEU: { if ( ranges != null) { template.UpdateValue(key, ranges[channelIndex].ToString("F0"), channelIndex); } else { template.UpdateValue(key, RunTestVariables.MaskEUMetaData ? "1" : maxEU.ToString("F0"), channelIndex); } } break; case TMTChannelKeysEx.ChannelMinRangeEU: { if (ranges != null) { template.UpdateValue(key, (-1 * ranges[channelIndex]).ToString("F0"), channelIndex); } else { template.UpdateValue(key, RunTestVariables.MaskEUMetaData ? "1" : minEU.ToString("F0"), channelIndex); } } break; } } public static void UpdateGlobalField(IDASCommunication das, TMTGlobalKeys key, ITMTTemplate template, IConfigurationData ConfigData, String serialNumber, ushort? timeChannelId, ushort? dataChannelId, ushort? uartChannelId, int dasIndex, int bitsPerFrame) { switch (key) { case TMTGlobalKeys.NameOfProgram: template.UpdateValue(key, TMT_LimitString(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name)); break; case TMTGlobalKeys.TestId: template.UpdateValue(key, TMT_LimitString(ConfigData.TestID)); break; case TMTGlobalKeys.CreateDate: //FB 29996 used the same date format from the template template.UpdateValue(key, DateTime.Now.ToString("MM-dd-yyyy")); break; case TMTGlobalKeys.DASSerialNumber: template.UpdateValue(key, serialNumber); break; // FB 26736 replace time & data channel Ids in template case TMTGlobalKeys.UdpStreamDataChannelId: if (dataChannelId.HasValue) { template.UpdateValue(key, dataChannelId.Value.ToString()); } break; case TMTGlobalKeys.UdpStreamTimeChannelId: if (timeChannelId.HasValue) { template.UpdateValue(key, timeChannelId.Value.ToString()); } break; //FB 43761 update tmat file with uart channel id & enable/disable T/F case TMTGlobalKeys.UdpStreamUartChannelId: if (uartChannelId.HasValue) { template.UpdateValue(key, uartChannelId.Value.ToString()); } break; case TMTGlobalKeys.UdpStreamUartChannelIdEnabled: if (uartChannelId.HasValue) { template.UpdateValue(key, uartChannelId.Value > 0 ? "T" : "F"); } else { template.UpdateValue(key, "F"); } break; case TMTGlobalKeys.DASIndex: template.UpdateValue(key, dasIndex.ToString()); break; case TMTGlobalKeys.DASSampleRate: template.UpdateValue(key, ConfigData.Modules[0].SampleRateHz.ToString()); break; case TMTGlobalKeys.DASBitRate: template.UpdateValue(key, (ConfigData.Modules[0].SampleRateHz * bitsPerFrame).ToString()); break; case TMTGlobalKeys.StreamTimeFormat: // FB15388 Add line "R-1\TTF-1:{TIME FORMAT};" to detail either time format 1 or 2 // FB 30035 Get stream time format from StreamOut module var streamOutModule = Array.Find(ConfigData.Modules, m => m.ModuleType() == DFConstantsAndEnums.ModuleType.StreamOut); if (streamOutModule != null) { template.UpdateValue(key, streamOutModule.StreamProfile.ToString().Contains(Constants.UDP_STREAM_CH10_TF2) ? "2" : "1"); } break; case TMTGlobalKeys.TestTimeStamp: var now = DateTime.Now; var timeStamp = $"{now.Month:00}-{now.Day:00}-{now.Year:0000}-{now.Hour:00}-{now.Minute:00}-{now.Second:00}"; template.UpdateValue(key, timeStamp); break; case TMTGlobalKeys.NumberOfStreamedChannels: template.UpdateValue(key, GetNumberOfStreamedChannels(das).ToString()); break; case TMTGlobalKeys.NumberOfChannelsPlusTime: template.UpdateValue(key, (1 + GetNumberOfStreamedChannels(das)).ToString()); break; case TMTGlobalKeys.NumberOfBitsPerMinorFrame: template.UpdateValue(key, (32 + 16 * GetNumberOfStreamedChannels(das)).ToString()); break; } } public static int GetNumberOfStreamedChannels(IDASCommunication das) { if (das is IDASReconfigure reconfigure) { if (das.GetHardwareType() == Enums.Hardware.HardwareTypes.SLICE6_AIR_TC) { return 24; } return GetNumberOfStreamedChannelsReconfigurable(das); } else { return 6; } } private static int GetNumberOfStreamedChannelsReconfigurable(IDASCommunication das) { //for now the TSR AIR is the only reconfigurable streaming devices? we may need to fix this in the future switch (das.DASInfo.Modules.Length) { case 3: return 3; //TSR AIR Lowg only (low g + stream output + UART) case 4: return 6; //TSR AIR LowG & High G (low g + high g + stream output + UART) case 5: return 9; //TSR AIR LowG, HighG, ARS default: return 18; //ALL } } public abstract void UpdateValue(TMTChannelKeysEx key, string value, int channelNumber); public abstract void UpdateValue(TMTGlobalKeys key, string value); public abstract void UpdateValue(TMTChannelKeys key, string value, int channelNumber); public abstract string[] GetAllLines(); } }