├── Fanuc.RobotInterface ├── SRTP │ ├── IRequestPacket.cs │ ├── IResponsePacket.cs │ ├── MessageType.cs │ ├── IPacket.cs │ ├── ExtendedResponsePacket.cs │ ├── PacketType.cs │ ├── ExtendedRequestPacket.cs │ ├── ShortPacketBase.cs │ ├── SegmentSelector.cs │ ├── ExtendedPacketBase.cs │ ├── ShortResponsePacket.cs │ ├── ShortRequestPacket.cs │ ├── ServiceRequestCode.cs │ └── PacketBase.cs ├── Collections │ ├── IRobotDataDictionary.cs │ ├── RobotDataDictionary.NotifyPropertyBase.cs │ └── RobotDataDictionary.cs ├── IValueHolder.cs ├── Fanuc.RobotInterface.csproj ├── IRobotIF.cs ├── RobotTaskStatus.cs ├── ExRobotIF.IRobotInterface.cs ├── NotifyPropertyBase.cs ├── IExRobotIF.cs ├── ExRobotIF.StatusData.cs ├── ExRobotIF.Registers.cs ├── ExRobotIF.SystemVariables.cs ├── ExRobotIF.DigitalSignals.cs ├── RobotAlarm.cs ├── ExRobotIF.Data.cs ├── ParallelExtensionExtras │ ├── LimitedConcurrencyLevelTaskScheduler.cs │ └── ObservableConcurrentDictionary.cs ├── IRobotIFExtension.cs ├── ExRobotIF.cs └── IPosition.cs ├── README.md ├── FANUCRobotTest ├── AssemblyInfo.cs ├── UI │ ├── RobotAlarmIsHistoryConverter.cs │ ├── RobotTaskTypeToSymbolConverter.cs │ ├── Dialogs │ │ ├── SetPositionDialog.xaml.cs │ │ └── SetPositionDialog.xaml │ ├── TypeToDataTemplateSelector.cs │ ├── RobotKeyDataDisplayControl.xaml │ ├── RobotIndexDataDisplayControl.xaml │ ├── RobotKeyDataDisplayControl.xaml.cs │ ├── RobotIndexDataDisplayControl.xaml.cs │ ├── PositionConverter.cs │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ └── RobotDisplayExtended.xaml.cs ├── Converters │ ├── BooleanInvertConverter.cs │ └── BooleanToObjectConverter.cs ├── kl │ ├── SE_MOVETO.LS │ └── dhm_abort.kl ├── App.xaml ├── FANUCRobotTest.csproj ├── SettingsBase.cs ├── NotifyPropertyBase.cs ├── App.xaml.cs └── OfficialIF.cs ├── FANUCRobotTest.sln └── .gitignore /Fanuc.RobotInterface/SRTP/IRequestPacket.cs: -------------------------------------------------------------------------------- 1 | namespace Fanuc.RobotInterface.SRTP 2 | { 3 | public interface IRequestPacket : IPacket 4 | { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/SRTP/IResponsePacket.cs: -------------------------------------------------------------------------------- 1 | namespace Fanuc.RobotInterface.SRTP 2 | { 3 | public interface IResponsePacket : IPacket 4 | { 5 | byte[] ActualPayload { get; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/SRTP/MessageType.cs: -------------------------------------------------------------------------------- 1 | namespace Fanuc.RobotInterface.SRTP 2 | { 3 | public enum MessageType : byte 4 | { 5 | SHORT = 0xc0, 6 | SHORT_ACK = 0xd4, 7 | LONG = 0x80, 8 | LONG_ACK = 0x94, 9 | 10 | SHORT_FAILED = 0xd1, 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/SRTP/IPacket.cs: -------------------------------------------------------------------------------- 1 | namespace Fanuc.RobotInterface.SRTP 2 | { 3 | public interface IPacket 4 | { 5 | MessageType MessageType { get; } 6 | 7 | byte[] Header { get; } 8 | byte[] ExtraPayload { get; } 9 | 10 | byte[] GetBytes(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/Collections/IRobotDataDictionary.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Fanuc.RobotInterface.Collections 4 | { 5 | public interface IRobotDataDictionary : IReadOnlyDictionary 6 | { 7 | TValue GetOrAdd(TKey key); 8 | bool Remove(TKey key); 9 | void Clear(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/SRTP/ExtendedResponsePacket.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | namespace Fanuc.RobotInterface.SRTP 4 | { 5 | public class ExtendedResponsePacket : ExtendedPacketBase, IResponsePacket 6 | { 7 | public ExtendedResponsePacket(byte[] buffer) 8 | { 9 | Header = buffer.Take(56).ToArray(); 10 | ExtraPayload = buffer.Skip(56).ToArray(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/SRTP/PacketType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Fanuc.RobotInterface.SRTP 10 | { 11 | public enum PacketType : ushort 12 | { 13 | INIT = 0x00, 14 | 15 | REQUEST = 0x02, 16 | ACK = 0x03, 17 | 18 | UNKNOWN_8 = 0x08, 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/IValueHolder.cs: -------------------------------------------------------------------------------- 1 | namespace Fanuc.RobotInterface 2 | { 3 | public interface IValueHolder 4 | { 5 | object Value { get; } 6 | } 7 | 8 | public interface IWritableValueHolder : IValueHolder 9 | { 10 | new object Value { get; set; } 11 | } 12 | 13 | public interface IValueHolder : IValueHolder 14 | { 15 | new T Value { get; } 16 | } 17 | 18 | public interface IWritableValueHolder : IValueHolder, IWritableValueHolder 19 | { 20 | new T Value { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FANUC.RobotInterface 2 | 3 | v3.0.3 4 | 5 | # Overview 6 | 7 | A library that allows you to connect to FANUC industrial robot arm. 8 | Tested with R-30iB. 9 | 10 | # Disclaimer 11 | 12 | **The authohr of this software is not affiliated with GE or FANUC Corporation in any way. All trademarks and registered trademarks are property of their respective owners, and company, product and service names mentioned in this readme or appearing in source code or other artifacts in this repository are used for identification purposes only.** 13 | 14 | **Use of these names does not imply endorsement by either GE nor FANUC Corporation.** -------------------------------------------------------------------------------- /Fanuc.RobotInterface/SRTP/ExtendedRequestPacket.cs: -------------------------------------------------------------------------------- 1 | namespace Fanuc.RobotInterface.SRTP 2 | { 3 | public class ExtendedRequestPacket : ExtendedPacketBase, IRequestPacket 4 | { 5 | public ushort Index { get => _ToUInt16(Header[53], Header[52]); set => (Header[53], Header[52]) = _ToBytes(value); } 6 | public ushort Count { get => _ToUInt16(Header[55], Header[54]); set => (Header[55], Header[54]) = _ToBytes(base.ExtraLength = value); } 7 | 8 | public ExtendedRequestPacket() 9 | { 10 | PacketType = PacketType.REQUEST; 11 | MessageType = MessageType.LONG; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /FANUCRobotTest/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] 11 | -------------------------------------------------------------------------------- /FANUCRobotTest/UI/RobotAlarmIsHistoryConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace FANUCRobotTest.UI 6 | { 7 | public class RobotAlarmIsHistoryConverter : IValueConverter 8 | { 9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => 10 | (bool)value switch 11 | { 12 | true => "E", 13 | false => "", 14 | }; 15 | 16 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => 17 | throw new NotImplementedException(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/SRTP/ShortPacketBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Fanuc.RobotInterface.SRTP 4 | { 5 | public abstract class ShortPacketBase : PacketBase 6 | { 7 | public ServiceRequestCode ServiceRequestCode { get => (ServiceRequestCode)Header[42]; set => Header[42] = (byte)value; } 8 | public SegmentSelector SegmentSelector { get => (SegmentSelector)Header[43]; set => Header[43] = (byte)value; } 9 | 10 | public override byte[] ActualPayload => Payload; 11 | 12 | public ShortPacketBase() 13 | { 14 | Unknown_8 = 0x0100; 15 | Unknown_16 = 0x0100; 16 | 17 | ExtraPayload = Array.Empty(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /FANUCRobotTest/Converters/BooleanInvertConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | 5 | namespace FANUCRobotTest.Converters 6 | { 7 | public class BooleanInvertConverter : IValueConverter 8 | { 9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 10 | { 11 | if (value is bool b) 12 | return !b; 13 | return null; 14 | } 15 | 16 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 17 | { 18 | if (value is bool b) 19 | return !b; 20 | return null; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/SRTP/SegmentSelector.cs: -------------------------------------------------------------------------------- 1 | namespace Fanuc.RobotInterface.SRTP 2 | { 3 | public enum SegmentSelector : byte 4 | { 5 | BIT_I = 0x46, 6 | BIT_Q = 0x48, 7 | BIT_T = 0x4a, 8 | BIT_M = 0x4c, 9 | BIT_SA = 0x4e, 10 | BIT_SB = 0x50, 11 | BIT_SC = 0x52, 12 | BIT_S = 0x54, 13 | BIT_G = 0x56, 14 | 15 | BYTE_I = 0x10, 16 | BYTE_Q = 0x12, 17 | BYTE_T = 0x14, 18 | BYTE_M = 0x16, 19 | BYTE_SA = 0x1a, 20 | BYTE_SB = 0x1c, 21 | BYTE_SC = 0x1e, 22 | BYTE_G = 0x38, 23 | 24 | WORD_R = 0x08, 25 | WORD_AI = 0x0a, 26 | WORD_AQ = 0x0c, 27 | 28 | INIT = 0x01, // unknown selector used in init 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /FANUCRobotTest/UI/RobotTaskTypeToSymbolConverter.cs: -------------------------------------------------------------------------------- 1 | using Fanuc.RobotInterface; 2 | using System; 3 | using System.Globalization; 4 | using System.Windows.Data; 5 | 6 | namespace FANUCRobotTest.UI 7 | { 8 | public class RobotTaskTypeToSymbolConverter : IValueConverter 9 | { 10 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => 11 | (RobotTaskType)value switch 12 | { 13 | RobotTaskType.All => "", 14 | RobotTaskType.IgnoreMacro => "M", 15 | RobotTaskType.IgnoreKarel => "K", 16 | RobotTaskType.IgnoreMacroKarel => "MK", 17 | _ => throw new NotImplementedException(), 18 | }; 19 | 20 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => 21 | throw new NotImplementedException(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /FANUCRobotTest/kl/SE_MOVETO.LS: -------------------------------------------------------------------------------- 1 | /PROG SE_MOVETO 2 | /ATTR 3 | OWNER = MNEDITOR; 4 | COMMENT = ""; 5 | PROG_SIZE = 314; 6 | CREATE = DATE 22-05-15 TIME 03:43:10; 7 | MODIFIED = DATE 22-05-15 TIME 04:01:54; 8 | FILE_NAME = ; 9 | VERSION = 0; 10 | LINE_COUNT = 13; 11 | MEMORY_SIZE = 766; 12 | PROTECT = READ_WRITE; 13 | TCD: STACK_SIZE = 0, 14 | TASK_PRIORITY = 50, 15 | TIME_SLICE = 0, 16 | BUSY_LAMP_OFF = 0, 17 | ABORT_REQUEST = 0, 18 | PAUSE_REQUEST = 0; 19 | DEFAULT_GROUP = 1,*,*,*,*; 20 | CONTROL_CODE = 00000000 00000000; 21 | /APPL 22 | /MN 23 | 1: SELECT R[1]=1,JMP LBL[1] ; 24 | 2: =2,JMP LBL[2] ; 25 | 3: ELSE,JMP LBL[99] ; 26 | 4: ; 27 | 5: LBL[1] ; 28 | 6:J PR[1] 100% FINE ; 29 | 7: JMP LBL[99] ; 30 | 8: ; 31 | 9: LBL[2] ; 32 | 10:L PR[1] 4000mm/sec FINE ; 33 | 11: JMP LBL[99] ; 34 | 12: ; 35 | 13: LBL[99] ; 36 | /POS 37 | /END 38 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/SRTP/ExtendedPacketBase.cs: -------------------------------------------------------------------------------- 1 | namespace Fanuc.RobotInterface.SRTP 2 | { 3 | public abstract class ExtendedPacketBase : PacketBase 4 | { 5 | public override byte PacketNumber { get => base.PacketNumber; set => Header[48] = base.PacketNumber = value; } 6 | public override byte TotalPacketNumber { get => base.TotalPacketNumber; set => Header[49] = base.TotalPacketNumber = value; } 7 | 8 | public ServiceRequestCode ServiceRequestCode { get => (ServiceRequestCode)Header[50]; set => Header[50] = (byte)value; } 9 | public SegmentSelector SegmentSelector { get => (SegmentSelector)Header[51]; set => Header[51] = (byte)value; } 10 | 11 | public override byte[] Payload { get => ExtraPayload; set => ExtraPayload = value; } 12 | 13 | public override byte[] ActualPayload => ExtraPayload; 14 | 15 | public ExtendedPacketBase() 16 | { 17 | Unknown_8 = 0x0200; 18 | Unknown_16 = 0x0200; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /FANUCRobotTest/Converters/BooleanToObjectConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Data; 8 | 9 | namespace FANUCRobotTest.Converters 10 | { 11 | public class BooleanToObjectConverter : IValueConverter 12 | { 13 | public object TrueValue { get; init; } 14 | public object FalseValue { get; init; } 15 | public object NullValue { get; init; } 16 | 17 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 18 | { 19 | if (value is bool b) 20 | return b ? TrueValue : FalseValue; 21 | return NullValue; 22 | } 23 | 24 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 25 | { 26 | if (Equals(value, TrueValue)) 27 | return true; 28 | if (Equals(value, FalseValue)) 29 | return false; 30 | return null; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/Fanuc.RobotInterface.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net48;net6.0 5 | disable 6 | disable 7 | False 8 | AnyCPU 9 | True 10 | Fanuc RobotInterface 11 | Victor Tseng 12 | Open source implentation for Fanuc RobotInterface. 13 | https://github.com/Palatis/Fanuc.RobotInterface 14 | BSD-3-Clause 15 | False 16 | 3.0.3 17 | $(Version).0 18 | $(Version).0 19 | https://github.com/Palatis/FANUC.RobotInterface 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/SRTP/ShortResponsePacket.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | namespace Fanuc.RobotInterface.SRTP 4 | { 5 | public class ShortResponsePacket : ShortPacketBase, IResponsePacket 6 | { 7 | //[FieldOffset(42)] public ushort Unknown_42; 8 | 9 | public override byte[] Payload 10 | { 11 | get => new byte[] { Header[44], Header[45], Header[46], Header[47], Header[48], Header[49] }; 12 | set 13 | { 14 | if (value.Length > 0) Header[44] = value[0]; 15 | if (value.Length > 1) Header[45] = value[1]; 16 | if (value.Length > 2) Header[46] = value[2]; 17 | if (value.Length > 3) Header[47] = value[3]; 18 | if (value.Length > 4) Header[48] = value[4]; 19 | if (value.Length > 5) Header[49] = value[5]; 20 | } 21 | } 22 | 23 | //[FieldOffset(50)] public uint Unknown_50; 24 | //[FieldOffset(54)] public ushort Unknown_54; 25 | 26 | public ShortResponsePacket(byte[] buffer) 27 | { 28 | Header = buffer.Take(56).ToArray(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/IRobotIF.cs: -------------------------------------------------------------------------------- 1 | namespace Fanuc.RobotInterface 2 | { 3 | public interface IRobotIF 4 | { 5 | bool IsConnected { get; } 6 | 7 | void Connect(string host, ushort port, int timeout); 8 | void Disconnect(); 9 | 10 | void ClearAlarm(); 11 | void ResetAlarm(); 12 | 13 | #region IO 14 | bool[] ReadDI(int index, ushort count); 15 | bool[] ReadDO(int index, ushort count); 16 | void WriteDI(int index, params bool[] values); 17 | void WriteDO(int index, params bool[] values); 18 | 19 | ushort[] ReadGI(int index, ushort count); 20 | ushort[] ReadGO(int index, ushort count); 21 | void WriteGI(int index, params ushort[] values); 22 | void WriteGO(int index, params ushort[] values); 23 | #endregion 24 | 25 | #region DataTable 26 | void WriteCommand(string command); 27 | void WriteSNPX(int index, params byte[] values); 28 | byte[] ReadSNPX(int index, ushort count); 29 | #endregion 30 | 31 | #region KCL & Karel 32 | string ExecuteKCL(string command); 33 | string ExecuteKarel(string program); 34 | #endregion 35 | } 36 | } -------------------------------------------------------------------------------- /Fanuc.RobotInterface/SRTP/ShortRequestPacket.cs: -------------------------------------------------------------------------------- 1 | namespace Fanuc.RobotInterface.SRTP 2 | { 3 | public class ShortRequestPacket : ShortPacketBase, IRequestPacket 4 | { 5 | public ushort Index { get => _ToUInt16(Header[45], Header[44]); set => (Header[45], Header[44]) = _ToBytes(value); } 6 | public ushort Count { get => _ToUInt16(Header[47], Header[46]); set => (Header[47], Header[46]) = _ToBytes(value); } 7 | 8 | public override byte[] Payload 9 | { 10 | get => new byte[] { Header[48], Header[49], Header[50], Header[51], Header[52], Header[53] }; 11 | set 12 | { 13 | if (value.Length > 0) Header[48] = value[0]; 14 | if (value.Length > 1) Header[49] = value[1]; 15 | if (value.Length > 2) Header[50] = value[2]; 16 | if (value.Length > 3) Header[51] = value[3]; 17 | if (value.Length > 4) Header[52] = value[4]; 18 | if (value.Length > 5) Header[53] = value[5]; 19 | } 20 | } 21 | 22 | //[FieldOffset(54)] public ushort Unknown_54; 23 | 24 | public override byte[] ActualPayload => Payload; 25 | 26 | public ShortRequestPacket() 27 | { 28 | PacketType = PacketType.REQUEST; 29 | MessageType = MessageType.SHORT; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /FANUCRobotTest/UI/Dialogs/SetPositionDialog.xaml.cs: -------------------------------------------------------------------------------- 1 | using Fanuc.RobotInterface; 2 | using ModernWpf.Controls; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using System.Windows.Controls; 10 | using System.Windows.Data; 11 | using System.Windows.Documents; 12 | using System.Windows.Input; 13 | using System.Windows.Media; 14 | using System.Windows.Media.Imaging; 15 | using System.Windows.Navigation; 16 | using System.Windows.Shapes; 17 | 18 | namespace FANUCRobotTest.UI 19 | { 20 | /// 21 | /// SetPositionDialog.xaml 的互動邏輯 22 | /// 23 | public partial class SetPositionDialog : ContentDialog 24 | { 25 | public static readonly DependencyProperty PositionProperty = 26 | DependencyProperty.Register(nameof(Position), typeof(Position), typeof(SetPositionDialog), new PropertyMetadata(null)); 27 | 28 | public Position Position { get => (Position)GetValue(PositionProperty); set => SetValue(PositionProperty, value); } 29 | 30 | public SetPositionDialog() 31 | { 32 | InitializeComponent(); 33 | } 34 | 35 | private void ContentDialog_CloseButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs e) 36 | { 37 | e.GetDeferral().Complete(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /FANUCRobotTest/UI/TypeToDataTemplateSelector.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | using System.Windows.Markup; 4 | 5 | namespace FANUCRobotTest.UI 6 | { 7 | public class TypeToDataTemplateSelector : DataTemplateSelector 8 | { 9 | public ResourceDictionary Resources { get; set; } 10 | public DataTemplate UnknownTypeTemplate { get; set; } 11 | public DataTemplate NullTypeTemplate { get; set; } 12 | 13 | public override DataTemplate SelectTemplate(object item, DependencyObject container) 14 | { 15 | if (item == null || Resources == null) 16 | { 17 | if (NullTypeTemplate != null) 18 | return NullTypeTemplate; 19 | return UnknownTypeTemplate; 20 | } 21 | 22 | var type = item.GetType(); 23 | if (type == null) 24 | return NullTypeTemplate; 25 | if (Resources.Contains(type) || Resources.Contains(type.FullName)) 26 | { 27 | var res = Resources[type] ?? Resources[type.FullName]; 28 | if (res is BindableDataTemplate bt) 29 | return bt.Template; 30 | return res as DataTemplate; 31 | } 32 | return UnknownTypeTemplate; 33 | } 34 | } 35 | 36 | [ContentProperty(nameof(Template))] 37 | public sealed class BindableDataTemplate 38 | { 39 | public DataTemplate Template { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /FANUCRobotTest/App.xaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/SRTP/ServiceRequestCode.cs: -------------------------------------------------------------------------------- 1 | namespace Fanuc.RobotInterface.SRTP 2 | { 3 | public enum ServiceRequestCode : byte 4 | { 5 | PLC_SHORT_STATUS = 0x00, // PLC short status request 6 | GET_PROGNAME = 0x03, // get control program names 7 | READ_SYS_MEM = 0x04, // read system memory 8 | READ_TASK_MEM = 0x05, // read task memroy 9 | READ_PROG_MEM = 0x06, // read program memory 10 | WRITE_SYS_MEM = 0x07, // write system memory 11 | WRITE_TASK_MEM = 0x08, // write task memory 12 | WRITE_PROG_MEM = 0x09, // write program block memory 13 | PROG_LOGON = 0x20, // programmer logon 14 | CHANGE_PRIV = 0x21, // change PLC CPU privilege level 15 | SET_CPU_ID = 0x22, // set control ID (CPU ID) 16 | SET_PLC_RUN = 0x23, // set PLC (run vs stop) 17 | SET_PLC_TIME = 0x24, // set PLC time / date 18 | GET_PKC_TIME = 0x25, // get PLC time / data 19 | GET_FAULT = 0x38, // get fault table 20 | CLR_FAULT = 0x39, // clear fault table 21 | PROG_STORE = 0x3f, // program store (upload from PLC) 22 | PROG_LOAD = 0x40, // program load (download to PLC) 23 | GET_INFO = 0x43, // get controller type and id information 24 | TOGGLE_FORCE_SYS_MEM = 0x44, // toggle force system memory 25 | 26 | INIT = 0x4f, // Unknown request used in init 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /FANUCRobotTest/FANUCRobotTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | net6.0-windows10.0.18362.0 6 | disable 7 | true 8 | AnyCPU;x86;x64 9 | True 10 | 11 | 12 | 13 | 14 | tlbimp 15 | 15 16 | 42 17 | 347ae5e2-b639-4527-b2ec-9d4f4dc4e7a9 18 | 0 19 | false 20 | true 21 | 22 | 23 | tlbimp 24 | 0 25 | 1 26 | e84cc822-360d-4712-90ff-ee4c8c1e0b19 27 | 0 28 | false 29 | true 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /FANUCRobotTest/SettingsBase.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.IO; 4 | using System.Reflection; 5 | 6 | namespace FANUCRobotTest 7 | { 8 | public class SettingsBase : NotifyPropertyBase 9 | { 10 | private static JsonSerializerSettings _SerializerSettings = new JsonSerializerSettings() 11 | { 12 | Formatting = Formatting.Indented, 13 | DefaultValueHandling = DefaultValueHandling.Populate, 14 | TypeNameHandling = TypeNameHandling.All, 15 | }; 16 | 17 | private readonly string _FilePath; 18 | 19 | public SettingsBase(string filename) 20 | { 21 | _FilePath = Path.Combine( 22 | Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), 23 | "FANUCRobotTest", 24 | filename 25 | ); 26 | Load(); 27 | } 28 | 29 | public void Load() 30 | { 31 | string json; 32 | try 33 | { 34 | json = File.ReadAllText(_FilePath); 35 | } 36 | catch 37 | { 38 | json = "{}"; 39 | } 40 | JsonConvert.PopulateObject(json, this, _SerializerSettings); 41 | } 42 | 43 | public void Save() 44 | { 45 | Directory.CreateDirectory(Path.GetDirectoryName(_FilePath)); 46 | 47 | if (File.Exists($"{_FilePath}.new")) 48 | File.Delete($"{_FilePath}.new"); 49 | 50 | File.WriteAllText($"{_FilePath}.new", JsonConvert.SerializeObject(this, _SerializerSettings)); 51 | 52 | if (File.Exists($"{_FilePath}.bak")) 53 | File.Delete($"{_FilePath}.bak"); 54 | if (File.Exists(_FilePath)) 55 | File.Move(_FilePath, $"{_FilePath}.bak"); 56 | File.Move($"{_FilePath}.new", _FilePath); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/Collections/RobotDataDictionary.NotifyPropertyBase.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Collections.Generic; 3 | using System.Collections.Specialized; 4 | using System.ComponentModel; 5 | using System.Runtime.CompilerServices; 6 | 7 | namespace Fanuc.RobotInterface.Collections 8 | { 9 | internal partial class RobotDataDictionary : INotifyPropertyChanged, INotifyCollectionChanged 10 | { 11 | private static readonly ObservableConcurrentDictionary _ChangedEventArgsCache = 12 | new ObservableConcurrentDictionary(); 13 | 14 | private static PropertyChangedEventArgs _GetChangedEventArgs(string name) 15 | { 16 | var e = _ChangedEventArgsCache.ContainsKey(name) ? _ChangedEventArgsCache[name] : null; 17 | if (e == null) 18 | { 19 | e = new PropertyChangedEventArgs(name); 20 | _ChangedEventArgsCache.Add(name, e); 21 | } 22 | return e; 23 | } 24 | 25 | public event PropertyChangedEventHandler PropertyChanged; 26 | 27 | protected void RaisePropertyChanged([CallerMemberName] string name = "") => PropertyChanged?.Invoke(this, _GetChangedEventArgs(name)); 28 | protected void RaisePropertyChanged(PropertyChangedEventArgs e) => PropertyChanged?.Invoke(this, e); 29 | 30 | protected bool SetField(ref T field, T value, [CallerMemberName] string name = "") 31 | { 32 | if (EqualityComparer.Default.Equals(field, value)) 33 | return false; 34 | field = value; 35 | RaisePropertyChanged(name); 36 | return true; 37 | } 38 | 39 | public event NotifyCollectionChangedEventHandler CollectionChanged; 40 | 41 | protected void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e) => CollectionChanged?.Invoke(this, e); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/RobotTaskStatus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace Fanuc.RobotInterface 5 | { 6 | public enum RobotTaskType 7 | { 8 | All = 0, 9 | IgnoreMacro = 1, 10 | IgnoreKarel = 2, 11 | IgnoreMacroKarel = 3, 12 | } 13 | 14 | public enum RobotTaskState 15 | { 16 | Stopped = 0, 17 | Paused = 1, 18 | Running = 2, 19 | } 20 | 21 | public class RobotTaskStatus : IEquatable 22 | { 23 | public string ProgramName { get; set; } 24 | public short LineNumber { get; set; } 25 | public RobotTaskState State { get; set; } 26 | public string Caller { get; set; } 27 | 28 | public bool Equals(RobotTaskStatus other) 29 | { 30 | if (other == null) 31 | return false; 32 | if (LineNumber != other.LineNumber) 33 | return false; 34 | if (State != other.State) 35 | return false; 36 | if (!string.Equals(ProgramName, other.ProgramName)) 37 | return false; 38 | if (!string.Equals(Caller, other.Caller)) 39 | return false; 40 | return true; 41 | } 42 | 43 | public static RobotTaskStatus FromBytes(byte[] bytes, int start = 0) 44 | { 45 | if (bytes == null) 46 | return null; 47 | if (bytes.Length < start + 36) 48 | throw new ArgumentException("need 36 bytes for task state", nameof(bytes)); 49 | 50 | return new RobotTaskStatus() 51 | { 52 | ProgramName = Encoding.ASCII.GetString(bytes, start + 0, 16), 53 | LineNumber = BitConverter.ToInt16(bytes, start + 16), 54 | State = (RobotTaskState)BitConverter.ToInt16(bytes, start + 18), 55 | Caller = Encoding.ASCII.GetString(bytes, start + 20, 16), 56 | }; 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /FANUCRobotTest/UI/Dialogs/SetPositionDialog.xaml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 33 | 34 | 37 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /FANUCRobotTest/NotifyPropertyBase.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace FANUCRobotTest 6 | { 7 | public abstract class NotifyPropertyBase : INotifyPropertyChanging, INotifyPropertyChanged 8 | { 9 | private static readonly Dictionary _ChangedEventArgsCache = new Dictionary(); 10 | private static readonly Dictionary _ChangingEventArgsCache = new Dictionary(); 11 | 12 | private static PropertyChangedEventArgs _GetChangedEventArgs(string name) 13 | { 14 | var e = _ChangedEventArgsCache.GetValueOrDefault(name, null); 15 | if (e == null) 16 | { 17 | e = new PropertyChangedEventArgs(name); 18 | _ChangedEventArgsCache.Add(name, e); 19 | } 20 | return e; 21 | } 22 | private static PropertyChangingEventArgs _GetChangingEventArgs(string name) 23 | { 24 | var e = _ChangingEventArgsCache.GetValueOrDefault(name, null); 25 | if (e == null) 26 | { 27 | e = new PropertyChangingEventArgs(name); 28 | _ChangingEventArgsCache.Add(name, e); 29 | } 30 | return e; 31 | } 32 | 33 | public event PropertyChangingEventHandler PropertyChanging; 34 | public event PropertyChangedEventHandler PropertyChanged; 35 | 36 | protected void RaisePropertyChanged([CallerMemberName] string name = "") => PropertyChanged?.Invoke(this, _GetChangedEventArgs(name)); 37 | protected void RaisePropertyChanging([CallerMemberName] string name = "") => PropertyChanging?.Invoke(this, _GetChangingEventArgs(name)); 38 | 39 | protected bool SetField(ref T field, T value, [CallerMemberName] string name = "") 40 | { 41 | if (EqualityComparer.Default.Equals(field, value)) 42 | return false; 43 | RaisePropertyChanging(name); 44 | field = value; 45 | RaisePropertyChanged(name); 46 | return true; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Fanuc.RobotInterface/ExRobotIF.IRobotInterface.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks.Schedulers; 2 | 3 | namespace Fanuc.RobotInterface 4 | { 5 | public partial class ExRobotIF : IRobotIF 6 | { 7 | public bool IsConnected => _Robot.IsConnected; 8 | 9 | public void Connect(string host, ushort port = RobotIF.DEFAULT_PORT, int timeout = RobotIF.DEFAULT_TIMEOUT) 10 | => ConnectAsync(host, port, timeout).Wait(); 11 | 12 | public void Disconnect() 13 | { 14 | if (IsConnected) 15 | { 16 | _TaskFactory?.StartNew(() => _Robot.Disconnect())?.Wait(); 17 | _CancellationTokenSource?.Cancel(); 18 | 19 | _TaskFactory = null; 20 | 21 | RaisePropertyChanged(nameof(IsConnected)); 22 | } 23 | } 24 | 25 | public void ClearAlarm() => _InvokeIfConnected(() => _Robot.ClearAlarm()).Wait(); 26 | public void ResetAlarm() => _InvokeIfConnected(() => _Robot.ResetAlarm()).Wait(); 27 | 28 | public bool[] ReadDI(int index, ushort count) => AsyncReadDI(index, count).Result; 29 | public bool[] ReadDO(int index, ushort count) => AsyncReadDO(index, count).Result; 30 | public ushort[] ReadGI(int index, ushort count) => AsyncReadGI(index, count).Result; 31 | public ushort[] ReadGO(int index, ushort count) => AsyncReadGO(index, count).Result; 32 | public void WriteDI(int index, params bool[] values) => AsyncWriteDI(index, values).Wait(); 33 | public void WriteDO(int index, params bool[] values) => AsyncWriteDO(index, values).Wait(); 34 | public void WriteGI(int index, params ushort[] values) => AsyncWriteGI(index, values).Wait(); 35 | public void WriteGO(int index, params ushort[] values) => AsyncWriteGO(index, values).Wait(); 36 | 37 | public byte[] ReadSNPX(int index, ushort count) => AsyncReadSNPX(index, count).Result; 38 | public void WriteSNPX(int index, params byte[] values) => AsyncWriteSNPX(index, values).Wait(); 39 | public void WriteCommand(string command) => AsyncWriteCommand(command).Wait(); 40 | 41 | public string ExecuteKCL(string command) => AsyncExecuteKCL(command).Result; 42 | public string ExecuteKarel(string program) => AsyncExecuteKarel(program).Result; 43 | } 44 | } -------------------------------------------------------------------------------- /Fanuc.RobotInterface/NotifyPropertyBase.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Runtime.CompilerServices; 5 | 6 | namespace Fanuc.RobotInterface 7 | { 8 | public abstract class NotifyPropertyBase : INotifyPropertyChanged, INotifyPropertyChanging 9 | { 10 | private static readonly ObservableConcurrentDictionary _ChangedEventArgsCache = new ObservableConcurrentDictionary(); 11 | private static readonly ObservableConcurrentDictionary _ChangingEventArgsCache = new ObservableConcurrentDictionary(); 12 | 13 | private static PropertyChangedEventArgs _GetChangedEventArgs(string name) 14 | { 15 | var e = _ChangedEventArgsCache.ContainsKey(name) ? _ChangedEventArgsCache[name] : null; 16 | if (e == null) 17 | { 18 | e = new PropertyChangedEventArgs(name); 19 | _ChangedEventArgsCache.Add(name, e); 20 | } 21 | return e; 22 | } 23 | private static PropertyChangingEventArgs _GetChangingEventArgs(string name) 24 | { 25 | var e = _ChangingEventArgsCache.ContainsKey(name) ? _ChangingEventArgsCache[name] : null; 26 | if (e == null) 27 | { 28 | e = new PropertyChangingEventArgs(name); 29 | _ChangingEventArgsCache.Add(name, e); 30 | } 31 | return e; 32 | } 33 | 34 | public event PropertyChangingEventHandler PropertyChanging; 35 | public event PropertyChangedEventHandler PropertyChanged; 36 | 37 | protected void RaisePropertyChanged([CallerMemberName] string name = "") => PropertyChanged?.Invoke(this, _GetChangedEventArgs(name)); 38 | protected void RaisePropertyChanging([CallerMemberName] string name = "") => PropertyChanging?.Invoke(this, _GetChangingEventArgs(name)); 39 | 40 | protected bool SetField(ref T field, T value, [CallerMemberName] string name = "") 41 | { 42 | if (EqualityComparer.Default.Equals(field, value)) 43 | return false; 44 | RaisePropertyChanging(name); 45 | field = value; 46 | RaisePropertyChanged(name); 47 | return true; 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /FANUCRobotTest/UI/RobotKeyDataDisplayControl.xaml: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | 16 | 17 | : 18 | 19 | 23 |