using System.Runtime.InteropServices; using System.Text; namespace B24SiemensEmulator; [StructLayout(LayoutKind.Explicit, Size = 19)] public struct PLCPacket { [FieldOffset(0)] private byte LifebitAndKamera; [FieldOffset(2)] public int Materialnummer; [FieldOffset(6)] public int ArtikelnummerBall; [FieldOffset(10)] public int MaterialnummerFoil; [FieldOffset(14)] private byte Chargennummer0; [FieldOffset(15)] private byte Chargennummer1; [FieldOffset(16)] private byte Chargennummer2; [FieldOffset(17)] private byte Chargennummer3; [FieldOffset(18)] private byte Chargennummer4; public string Chargennummer { get => Encoding.ASCII.GetString(new[] {Chargennummer0, Chargennummer1, Chargennummer2, Chargennummer3, Chargennummer4}); set { var bytes = Encoding.ASCII.GetBytes(value); var fill = new byte[5]; for (int i = 0; i < bytes.Length; i++) { fill[i] = bytes[i]; } Chargennummer0 = fill[0]; Chargennummer1 = fill[1]; Chargennummer2 = fill[2]; Chargennummer3 = fill[3]; Chargennummer4 = fill[4]; } } public bool Lifebit { get => (LifebitAndKamera & 1) > 0; set { if (value) LifebitAndKamera |= 1; else LifebitAndKamera &= 0xFE; } } public bool KameraStart { get => (LifebitAndKamera & 2) > 0; set { if (value) LifebitAndKamera |= 2; else LifebitAndKamera &= 0xFD; } } public byte[] Serialize() { int size = Marshal.SizeOf(this); byte[] arr = new byte[size]; IntPtr ptr = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(this, ptr, true); Marshal.Copy(ptr, arr, 0, size); Marshal.FreeHGlobal(ptr); if (BitConverter.IsLittleEndian) { Array.Reverse(arr, 2, 4); // Materialnummer Array.Reverse(arr, 6, 4); // ArtikelnummerBall Array.Reverse(arr, 10, 4); // MaterialnummerFoil } return arr; } public static PLCPacket Deserialize(byte[] arr) { if (BitConverter.IsLittleEndian) { Array.Reverse(arr, 2, 4); // Materialnummer Array.Reverse(arr, 6, 4); // ArtikelnummerBall Array.Reverse(arr, 10, 4); // MaterialnummerFoil } PLCPacket ds; int size = Marshal.SizeOf(typeof(PLCPacket)); IntPtr ptr = Marshal.AllocHGlobal(size); Marshal.Copy(arr, 0, ptr, size); ds = (PLCPacket)Marshal.PtrToStructure(ptr, typeof(PLCPacket)); Marshal.FreeHGlobal(ptr); return ds; } override public string ToString() { return $"Lifebit: {(Lifebit?'1':'0')}, KameraStart: {KameraStart}, Materialnummer: {Materialnummer}, ArtikelnummerBall: {ArtikelnummerBall}, MaterialnummerFoil: {MaterialnummerFoil}, Chargennummer: {Chargennummer}"; } public static bool IsValidChargennummer(string chargennummer) { if (string.IsNullOrEmpty(chargennummer)) return true; // Empty is valid if (chargennummer.Length > 5) return false; // Too long // Check if all characters are ASCII return chargennummer.All(c => c >= 0 && c <= 127); } public static string ValidateAndTrimChargennummer(string chargennummer) { if (string.IsNullOrEmpty(chargennummer)) return string.Empty; // Trim to max 5 characters and ensure ASCII var trimmed = chargennummer.Substring(0, Math.Min(chargennummer.Length, 5)); return new string(trimmed.Where(c => c >= 0 && c <= 127).ToArray()); } public bool IsValid() { return IsValidChargennummer(Chargennummer); } }