using System.Runtime.InteropServices; namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS; /// /// P/Invoke surface for Fanuc FWLIB (Fwlib32.dll). Declarations extracted from /// fwlib32.h in the strangesast/fwlib repo; the licensed DLL itself is NOT shipped /// with OtOpcUa — the deployment places Fwlib32.dll next to the server executable /// or on PATH. /// /// /// Deliberately narrow — only the calls actually makes. /// FOCAS has 800+ functions in fwlib32.h; pulling in every one would bloat the /// P/Invoke surface + signal more coverage than this driver provides. Expand as capabilities /// are added. /// internal static class FwlibNative { private const string Library = "Fwlib32.dll"; // ---- Handle lifetime ---- /// Open an Ethernet FWLIB handle. Returns EW_OK (0) on success; handle written out. [DllImport(Library, EntryPoint = "cnc_allclibhndl3", CharSet = CharSet.Ansi, ExactSpelling = true)] public static extern short AllcLibHndl3( [MarshalAs(UnmanagedType.LPStr)] string ipaddr, ushort port, int timeout, out ushort handle); [DllImport(Library, EntryPoint = "cnc_freelibhndl", ExactSpelling = true)] public static extern short FreeLibHndl(ushort handle); // ---- PMC ---- /// PMC range read. is the ADR_* enum; is 0 byte / 1 word / 2 long. [DllImport(Library, EntryPoint = "pmc_rdpmcrng", ExactSpelling = true)] public static extern short PmcRdPmcRng( ushort handle, short addrType, short dataType, ushort startNumber, ushort endNumber, ushort length, ref IODBPMC buffer); [DllImport(Library, EntryPoint = "pmc_wrpmcrng", ExactSpelling = true)] public static extern short PmcWrPmcRng( ushort handle, ushort length, ref IODBPMC buffer); // ---- Parameters ---- [DllImport(Library, EntryPoint = "cnc_rdparam", ExactSpelling = true)] public static extern short RdParam( ushort handle, ushort number, short axis, short length, ref IODBPSD buffer); [DllImport(Library, EntryPoint = "cnc_wrparam", ExactSpelling = true)] public static extern short WrParam( ushort handle, short length, ref IODBPSD buffer); // ---- Macro variables ---- [DllImport(Library, EntryPoint = "cnc_rdmacro", ExactSpelling = true)] public static extern short RdMacro( ushort handle, short number, short length, ref ODBM buffer); [DllImport(Library, EntryPoint = "cnc_wrmacro", ExactSpelling = true)] public static extern short WrMacro( ushort handle, short number, short length, int macroValue, short decimalPointCount); // ---- Status ---- [DllImport(Library, EntryPoint = "cnc_statinfo", ExactSpelling = true)] public static extern short StatInfo(ushort handle, ref ODBST buffer); // ---- Structs ---- /// /// IODBPMC — PMC range I/O buffer. 8-byte header + 40-byte union. We marshal the union /// as a fixed byte buffer + interpret per on the managed side. /// [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct IODBPMC { public short TypeA; public short TypeD; public ushort DatanoS; public ushort DatanoE; // 40-byte union: cdata[5] / idata[5] / ldata[5] / fdata[5] / dbdata[5] — dbdata is the widest. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] public byte[] Data; } /// /// IODBPSD — CNC parameter I/O buffer. Axis-aware; for non-axis parameters pass axis=0. /// Union payload is bytes / shorts / longs — we marshal 32 bytes as the widest slot. /// [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct IODBPSD { public short Datano; public short Type; // axis index (0 for non-axis) [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] Data; } /// ODBM — macro variable read buffer. Value = McrVal / 10^DecVal. [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct ODBM { public short Datano; public short Dummy; public int McrVal; // long in C; 32-bit signed public short DecVal; // decimal-point count } /// ODBST — CNC status info. Machine state, alarm flags, automatic / edit mode. [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct ODBST { public short Dummy; public short TmMode; public short Aut; public short Run; public short Motion; public short Mstb; public short Emergency; public short Alarm; public short Edit; } } /// /// PMC address-letter → FOCAS ADR_* numeric code. Per Fanuc FOCAS/2 spec the codes /// are: G=0, F=1, Y=2, X=3, A=4, R=5, T=6, K=7, C=8, D=9, E=10. Exposed internally + /// tested so the FwlibFocasClient translation is verifiable without the DLL loaded. /// internal static class FocasPmcAddrType { public static short? FromLetter(string letter) => letter.ToUpperInvariant() switch { "G" => 0, "F" => 1, "Y" => 2, "X" => 3, "A" => 4, "R" => 5, "T" => 6, "K" => 7, "C" => 8, "D" => 9, "E" => 10, _ => null, }; } /// PMC data-type numeric codes per FOCAS/2: 0 = byte, 1 = word, 2 = long, 4 = float, 5 = double. internal static class FocasPmcDataType { public const short Byte = 0; public const short Word = 1; public const short Long = 2; public const short Float = 4; public const short Double = 5; public static short FromFocasDataType(FocasDataType t) => t switch { FocasDataType.Bit or FocasDataType.Byte => Byte, FocasDataType.Int16 => Word, FocasDataType.Int32 => Long, FocasDataType.Float32 => Float, FocasDataType.Float64 => Double, _ => Byte, }; }